feat: add tutorial

main
tiendat3699 2024-03-27 10:04:28 +07:00
parent a45a461a85
commit e5b6cb1e32
13 changed files with 1558 additions and 546 deletions

View File

@ -0,0 +1,372 @@
[
{
"__type__": "cc.Prefab",
"_name": "box-001",
"_objFlags": 0,
"_native": "",
"data": {
"__id__": 1
},
"optimizationPolicy": 0,
"persistent": false
},
{
"__type__": "cc.Node",
"_name": "box-001",
"_objFlags": 0,
"__editorExtras__": {},
"_parent": null,
"_children": [
{
"__id__": 2
}
],
"_active": true,
"_components": [
{
"__id__": 8
},
{
"__id__": 10
},
{
"__id__": 12
},
{
"__id__": 14
},
{
"__id__": 16
}
],
"_prefab": {
"__id__": 18
},
"_lpos": {
"__type__": "cc.Vec3",
"x": 0,
"y": 0,
"z": 0
},
"_lrot": {
"__type__": "cc.Quat",
"x": 0,
"y": 0,
"z": 0,
"w": 1
},
"_lscale": {
"__type__": "cc.Vec3",
"x": 1,
"y": 1,
"z": 1
},
"_mobility": 0,
"_layer": 33554432,
"_euler": {
"__type__": "cc.Vec3",
"x": 0,
"y": 0,
"z": 0
},
"_id": ""
},
{
"__type__": "cc.Node",
"_name": "Sprite",
"_objFlags": 0,
"_parent": {
"__id__": 1
},
"_children": [],
"_active": true,
"_components": [
{
"__id__": 3
},
{
"__id__": 5
}
],
"_prefab": {
"__id__": 7
},
"_lpos": {
"__type__": "cc.Vec3",
"x": 0,
"y": -50,
"z": 0
},
"_lrot": {
"__type__": "cc.Quat",
"x": 0,
"y": 0,
"z": 0,
"w": 1
},
"_lscale": {
"__type__": "cc.Vec3",
"x": 1,
"y": 1,
"z": 1
},
"_mobility": 0,
"_layer": 33554432,
"_euler": {
"__type__": "cc.Vec3",
"x": 0,
"y": 0,
"z": 0
},
"_id": ""
},
{
"__type__": "cc.UITransform",
"_name": "",
"_objFlags": 0,
"node": {
"__id__": 2
},
"_enabled": true,
"__prefab": {
"__id__": 4
},
"_contentSize": {
"__type__": "cc.Size",
"width": 60,
"height": 100
},
"_anchorPoint": {
"__type__": "cc.Vec2",
"x": 0.5,
"y": 0
},
"_id": ""
},
{
"__type__": "cc.CompPrefabInfo",
"fileId": "7eQbUjrCxCdqX0lbHJJf5m"
},
{
"__type__": "cc.Sprite",
"_name": "",
"_objFlags": 0,
"node": {
"__id__": 2
},
"_enabled": true,
"__prefab": {
"__id__": 6
},
"_customMaterial": null,
"_srcBlendFactor": 2,
"_dstBlendFactor": 4,
"_color": {
"__type__": "cc.Color",
"r": 61,
"g": 0,
"b": 255,
"a": 255
},
"_spriteFrame": {
"__uuid__": "483ec166-493b-43a4-885a-f5051af6a6c7@f9941",
"__expectedType__": "cc.SpriteFrame"
},
"_type": 0,
"_fillType": 0,
"_sizeMode": 0,
"_fillCenter": {
"__type__": "cc.Vec2",
"x": 0,
"y": 0
},
"_fillStart": 0,
"_fillRange": 0,
"_isTrimmedMode": true,
"_useGrayscale": false,
"_atlas": null,
"_id": ""
},
{
"__type__": "cc.CompPrefabInfo",
"fileId": "8f4n9BtRRP+4F8ppzXIOAb"
},
{
"__type__": "cc.PrefabInfo",
"root": {
"__id__": 1
},
"asset": {
"__id__": 0
},
"fileId": "58e2t45HZDcaGTymn9uf1N",
"instance": null,
"targetOverrides": null,
"nestedPrefabInstanceRoots": null
},
{
"__type__": "cc.UITransform",
"_name": "",
"_objFlags": 0,
"node": {
"__id__": 1
},
"_enabled": true,
"__prefab": {
"__id__": 9
},
"_contentSize": {
"__type__": "cc.Size",
"width": 60,
"height": 100
},
"_anchorPoint": {
"__type__": "cc.Vec2",
"x": 0.5,
"y": 0.5
},
"_id": ""
},
{
"__type__": "cc.CompPrefabInfo",
"fileId": "dd1k5yz/9Jw7Y3h/ln7e+D"
},
{
"__type__": "cc.BoxCollider2D",
"_name": "",
"_objFlags": 0,
"node": {
"__id__": 1
},
"_enabled": true,
"__prefab": {
"__id__": 11
},
"tag": 0,
"_group": 2,
"_density": 1,
"_sensor": true,
"_friction": 0.2,
"_restitution": 0,
"_offset": {
"__type__": "cc.Vec2",
"x": 0,
"y": 0
},
"_size": {
"__type__": "cc.Size",
"width": 60,
"height": 100
},
"_id": ""
},
{
"__type__": "cc.CompPrefabInfo",
"fileId": "e3xI5cN0VBUb2QzjmBNBDQ"
},
{
"__type__": "cc.RigidBody2D",
"_name": "",
"_objFlags": 0,
"node": {
"__id__": 1
},
"_enabled": true,
"__prefab": {
"__id__": 13
},
"enabledContactListener": true,
"bullet": false,
"awakeOnLoad": true,
"_group": 2,
"_type": 1,
"_allowSleep": true,
"_gravityScale": 1,
"_linearDamping": 0,
"_angularDamping": 0,
"_linearVelocity": {
"__type__": "cc.Vec2",
"x": 0,
"y": 0
},
"_angularVelocity": 0,
"_fixedRotation": false,
"_id": ""
},
{
"__type__": "cc.CompPrefabInfo",
"fileId": "bbOXJ9GJVHppWgt0OjwEBK"
},
{
"__type__": "3bd17tsjpdMZqOLOE4CWMkE",
"_name": "",
"_objFlags": 0,
"node": {
"__id__": 1
},
"_enabled": true,
"__prefab": {
"__id__": 15
},
"_collider": {
"__id__": 10
},
"_sprite": {
"__id__": 5
},
"_spawnAnimation": {
"__id__": 16
},
"_hitSound": {
"__uuid__": "1f602e14-2769-4903-b4d2-b0977eeaf36b",
"__expectedType__": "cc.AudioClip"
},
"_score": 2,
"_bonusTime": 0,
"_id": ""
},
{
"__type__": "cc.CompPrefabInfo",
"fileId": "f3W6S5U0BKM6/Fx3RiEC8W"
},
{
"__type__": "cc.Animation",
"_name": "",
"_objFlags": 0,
"node": {
"__id__": 1
},
"_enabled": true,
"__prefab": {
"__id__": 17
},
"playOnLoad": false,
"_clips": [
{
"__uuid__": "cfd9afd6-9345-446c-bf56-b7ac3dbf2c1e",
"__expectedType__": "cc.AnimationClip"
}
],
"_defaultClip": {
"__uuid__": "cfd9afd6-9345-446c-bf56-b7ac3dbf2c1e",
"__expectedType__": "cc.AnimationClip"
},
"_id": ""
},
{
"__type__": "cc.CompPrefabInfo",
"fileId": "9cExf3IzxEa53jorYVyMdR"
},
{
"__type__": "cc.PrefabInfo",
"root": {
"__id__": 1
},
"asset": {
"__id__": 0
},
"fileId": "31K2tUn39G47RitJdKcKW+",
"instance": null,
"targetOverrides": null
}
]

View File

@ -0,0 +1,13 @@
{
"ver": "1.1.43",
"importer": "prefab",
"imported": true,
"uuid": "ff8610cc-1c8d-46d4-9c92-88f14a09f366",
"files": [
".json"
],
"subMetas": {},
"userData": {
"syncNodeName": "box-001"
}
}

View File

@ -321,7 +321,7 @@
"__uuid__": "1f602e14-2769-4903-b4d2-b0977eeaf36b", "__uuid__": "1f602e14-2769-4903-b4d2-b0977eeaf36b",
"__expectedType__": "cc.AudioClip" "__expectedType__": "cc.AudioClip"
}, },
"_score": 5, "_score": 1,
"_bonusTime": 0, "_bonusTime": 0,
"_id": "" "_id": ""
}, },

File diff suppressed because it is too large Load Diff

View File

@ -146,6 +146,7 @@ export class Ball extends Component implements IPoolable {
SoundManager.instance.playSfx(this._ballThrowSound); SoundManager.instance.playSfx(this._ballThrowSound);
this._collider.group = PhysicsGroup.BALL_THROWING; this._collider.group = PhysicsGroup.BALL_THROWING;
this._rigidBody.group = PhysicsGroup.BALL_THROWING; this._rigidBody.group = PhysicsGroup.BALL_THROWING;
this._rigidBody.applyAngularImpulse(-5 * force.x || 2, true);
this._rigidBody.applyLinearImpulseToCenter(force, true); this._rigidBody.applyLinearImpulseToCenter(force, true);
this._isJumping = true; this._isJumping = true;
this._jumpTime = 0; this._jumpTime = 0;

View File

@ -1,17 +1,4 @@
import { import { _decorator, Component, Node, Prefab, Vec2, Vec3, randomRangeInt, CCInteger, AudioClip, Quat } from 'cc';
_decorator,
Component,
Node,
Prefab,
Vec2,
Vec3,
randomRangeInt,
CCInteger,
AudioClip,
PhysicsSystem2D,
EPhysics2DDrawFlags,
Quat,
} from 'cc';
import ObjectPool from '../Pool/ObjectPool'; import ObjectPool from '../Pool/ObjectPool';
import { Ball } from '../GamePlay/Ball'; import { Ball } from '../GamePlay/Ball';
import Utilities from '../Utilities'; import Utilities from '../Utilities';
@ -71,6 +58,7 @@ export class GameManager extends Component {
private isReplayed = false; private isReplayed = false;
private _isMultiBall = false; private _isMultiBall = false;
private _currentBallInGame = 0; private _currentBallInGame = 0;
private _multiplierScore = 0;
public get score() { public get score() {
return this._score; return this._score;
@ -123,10 +111,15 @@ export class GameManager extends Component {
} }
} }
private addScore(score: number, type: ScoreType, position: Vec3) { private addScore(
score: number,
type: ScoreType,
position: Vec3,
opts: { scaleMin: number; scaleMax: number; duration: number },
) {
this._score += score; this._score += score;
const floatingScore = this._FloatingScorePool.get(this._floatingTextContainer, FloatingText); const floatingScore = this._FloatingScorePool.get(this._floatingTextContainer, FloatingText);
floatingScore.show(`+${score}`, position, score >= 100 ? 3 : 1.5, score >= 100 ? 1 : 0.7); floatingScore.show(`+${score}`, position, score >= 100 ? opts.scaleMax : opts.scaleMin, opts.duration);
EventManger.instance.emit(GameEvent.Score, [this._score, type]); EventManger.instance.emit(GameEvent.Score, [this._score, type]);
} }
@ -167,6 +160,7 @@ export class GameManager extends Component {
public async ballOut() { public async ballOut() {
this.setCurrentBallInGame(-1); this.setCurrentBallInGame(-1);
if (this._currentBallInGame <= 0) { if (this._currentBallInGame <= 0) {
this._multiplierScore = 0;
EventManger.instance.emit(GameEvent.BallOut, null); EventManger.instance.emit(GameEvent.BallOut, null);
await Utilities.delay(TimeConfig.DelayPLay); await Utilities.delay(TimeConfig.DelayPLay);
this.spawnBall(true); this.spawnBall(true);
@ -174,9 +168,14 @@ export class GameManager extends Component {
} }
public async goal(bonusScore: number, position: Vec3) { public async goal(bonusScore: number, position: Vec3) {
this.addScore(this._isMultiBall ? bonusScore * 2 : bonusScore, ScoreType.Goal, position); this.addScore(this._isMultiBall ? bonusScore * 2 : bonusScore, ScoreType.Goal, position, {
scaleMin: 2,
scaleMax: 3,
duration: 1,
});
this.setCurrentBallInGame(-1); this.setCurrentBallInGame(-1);
if (this._currentBallInGame <= 0) { if (this._currentBallInGame <= 0) {
this._multiplierScore = 0;
await Utilities.delay(TimeConfig.DelayGoal); await Utilities.delay(TimeConfig.DelayGoal);
this.spawnBall(true); this.spawnBall(true);
} }
@ -184,7 +183,12 @@ export class GameManager extends Component {
public async destroyEnvironmentObject(bonusScore: number, position: Vec3, bonusTime?: number) { public async destroyEnvironmentObject(bonusScore: number, position: Vec3, bonusTime?: number) {
if (bonusScore) { if (bonusScore) {
this.addScore(bonusScore, ScoreType.DestroyObject, position); this._multiplierScore++;
this.addScore(bonusScore * this._multiplierScore, ScoreType.DestroyObject, position, {
scaleMin: 1.5,
scaleMax: 2,
duration: 0.7,
});
await Utilities.delay(0.3); await Utilities.delay(0.3);
} }
if (bonusTime) { if (bonusTime) {

View File

@ -45,6 +45,7 @@ export class SpawnObjectManager extends Component {
private _playing = false; private _playing = false;
private _timer = 0; private _timer = 0;
private _weights: number[] = []; private _weights: number[] = [];
private _isReplay = false;
protected onLoad(): void { protected onLoad(): void {
SpawnObjectManager._instance = this; SpawnObjectManager._instance = this;
@ -70,7 +71,8 @@ export class SpawnObjectManager extends Component {
private spawn() { private spawn() {
if (Object.keys(this._usedPoints).length == this._spawnPoints.length) return; if (Object.keys(this._usedPoints).length == this._spawnPoints.length) return;
do { do {
var [randomPool, index] = Utilities.weightedRandom(this._pools, this._weights); var randomPool = Utilities.weightedRandom(this._pools, this._weights);
var index = this._pools.indexOf(randomPool);
} while (this._objects[index].maxObjects != -1 && randomPool.countActive >= this._objects[index].maxObjects); } while (this._objects[index].maxObjects != -1 && randomPool.countActive >= this._objects[index].maxObjects);
do { do {
var randomPoint = this._spawnPoints[randomRangeInt(0, this._spawnPoints.length)]; var randomPoint = this._spawnPoints[randomRangeInt(0, this._spawnPoints.length)];
@ -101,6 +103,10 @@ export class SpawnObjectManager extends Component {
private onGameStateChange(state: GameState) { private onGameStateChange(state: GameState) {
switch (state) { switch (state) {
case GameState.Init: case GameState.Init:
break;
case GameState.Playing:
this._playing = true;
if (this._isReplay) return;
this._weights = this._objects.map((obj) => { this._weights = this._objects.map((obj) => {
obj.currentWeight = obj.weight; obj.currentWeight = obj.weight;
return obj.currentWeight; return obj.currentWeight;
@ -109,12 +115,14 @@ export class SpawnObjectManager extends Component {
this.spawn(); this.spawn();
} }
break; break;
case GameState.Playing:
this._playing = true;
break;
case GameState.GameOver: case GameState.GameOver:
this._playing = false; this._playing = false;
break; break;
case GameState.Relive:
this._isReplay = true;
break;
case GameState.End:
break;
} }
} }
} }

View File

@ -0,0 +1,38 @@
import { _decorator, Component, EventTouch, Input, Node, Tween, tween, Vec3 } from 'cc';
import { GameManager } from '../Manager/GameManager';
const { ccclass, property } = _decorator;
@ccclass('TutorialController')
export class TutorialController extends Component {
@property({ type: Node, visible: true })
private _tapL: Node;
@property({ type: Node, visible: true })
private _tapR: Node;
protected onLoad(): void {
this.node.on(Input.EventType.TOUCH_START, this.onTouch, this);
}
protected start() {
tween(this._tapL)
.by(0.5, { position: new Vec3(0, 50) }, { easing: 'quintOut' })
.by(0.5, { position: new Vec3(0, -50) }, { easing: 'sineOut' })
.union()
.repeatForever()
.start();
tween(this._tapR)
.delay(0.5)
.by(0.5, { position: new Vec3(0, 50) }, { easing: 'quintOut' })
.by(0.5, { position: new Vec3(0, -50) }, { easing: 'sineOut' })
.union()
.repeatForever()
.start();
}
private onTouch(event: EventTouch) {
Tween.stopAllByTarget(this._tapL);
Tween.stopAllByTarget(this._tapR);
this.node.active = false;
GameManager.instance.play();
}
}

View File

@ -0,0 +1,9 @@
{
"ver": "4.0.23",
"importer": "typescript",
"imported": true,
"uuid": "58a5a096-13c5-44a8-92be-d30ce758bdb8",
"files": [],
"subMetas": {},
"userData": {}
}

View File

@ -75,7 +75,6 @@ export class UIController extends Component {
break; break;
case GameState.Playing: case GameState.Playing:
this._scoreLabel.string = 'Score: 0'; this._scoreLabel.string = 'Score: 0';
this._startPanel.active = false;
this._overPanel.active = false; this._overPanel.active = false;
break; break;
case GameState.GameOver: case GameState.GameOver:
@ -106,6 +105,10 @@ export class UIController extends Component {
} }
} }
public starGame() {
this._startPanel.active = false;
}
private onTimeUpdate(time: number) { private onTimeUpdate(time: number) {
this._timeLabe.string = this.secondsToTime(time); this._timeLabe.string = this.secondsToTime(time);
} }

View File

@ -1,3 +1,5 @@
import { Vec2, Vec3 } from 'cc';
export default class Utilities { export default class Utilities {
/** /**
* *
@ -27,18 +29,29 @@ export default class Utilities {
} }
} }
public static weightedRandom<T>(items: T[], weights: number[]): [T, number] { public static Vec2ToVec3(Vec2: Vec2): Vec3 {
let i = 0; return new Vec3(Vec2.x, Vec2.y);
}
public static Vec3ToVec2(Vec3: Vec3): Vec2 {
return new Vec2(Vec3.x, Vec3.y);
}
public static weightedRandom<T>(items: T[], weights: number[]): T {
const weightsClone = [...weights]; const weightsClone = [...weights];
for (i = 1; i < weightsClone.length; i++) { const totalWeight = weightsClone.reduce((a, b) => a + b, 0);
weightsClone[i] += weights[i - 1]; let random = Math.random() * totalWeight;
} const item = items.find((_, i) => (random -= weightsClone[i]) <= 0);
return item;
// for (i = 1; i < weightsClone.length; i++) {
// weightsClone[i] += weights[i - 1];
// }
let random = Math.random() * weightsClone[weightsClone.length - 1]; // let random = Math.random() * weightsClone[weightsClone.length - 1];
for (i = 0; i < weightsClone.length; i++) { // for (i = 0; i < weightsClone.length; i++) {
if (weightsClone[i] > random) break; // if (weightsClone[i] > random) break;
} // }
return [items[i], i]; // return [items[i], i];
} }
} }

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

View File

@ -0,0 +1,134 @@
{
"ver": "1.0.25",
"importer": "image",
"imported": true,
"uuid": "6a5c564e-65a2-4dfc-89df-621f6e68ef2a",
"files": [
".json",
".png"
],
"subMetas": {
"6c48a": {
"importer": "texture",
"uuid": "6a5c564e-65a2-4dfc-89df-621f6e68ef2a@6c48a",
"displayName": "tap",
"id": "6c48a",
"name": "texture",
"userData": {
"wrapModeS": "clamp-to-edge",
"wrapModeT": "clamp-to-edge",
"imageUuidOrDatabaseUri": "6a5c564e-65a2-4dfc-89df-621f6e68ef2a",
"isUuid": true,
"visible": false,
"minfilter": "linear",
"magfilter": "linear",
"mipfilter": "none",
"anisotropy": 0
},
"ver": "1.0.22",
"imported": true,
"files": [
".json"
],
"subMetas": {}
},
"f9941": {
"importer": "sprite-frame",
"uuid": "6a5c564e-65a2-4dfc-89df-621f6e68ef2a@f9941",
"displayName": "tap",
"id": "f9941",
"name": "spriteFrame",
"userData": {
"trimType": "auto",
"trimThreshold": 1,
"rotated": false,
"offsetX": 0,
"offsetY": 0,
"trimX": 317,
"trimY": 175,
"width": 617,
"height": 900,
"rawWidth": 1251,
"rawHeight": 1250,
"borderTop": 0,
"borderBottom": 0,
"borderLeft": 0,
"borderRight": 0,
"packable": true,
"pixelsToUnit": 100,
"pivotX": 0.5,
"pivotY": 0.5,
"meshType": 0,
"vertices": {
"rawPosition": [
-308.5,
-450,
0,
308.5,
-450,
0,
-308.5,
450,
0,
308.5,
450,
0
],
"indexes": [
0,
1,
2,
2,
1,
3
],
"uv": [
317,
1075,
934,
1075,
317,
175,
934,
175
],
"nuv": [
0.2533972821742606,
0.14,
0.7466027178257394,
0.14,
0.2533972821742606,
0.86,
0.7466027178257394,
0.86
],
"minPos": [
-308.5,
-450,
0
],
"maxPos": [
308.5,
450,
0
]
},
"isUuid": true,
"imageUuidOrDatabaseUri": "6a5c564e-65a2-4dfc-89df-621f6e68ef2a@6c48a",
"atlasUuid": ""
},
"ver": "1.0.11",
"imported": true,
"files": [
".json"
],
"subMetas": {}
}
},
"userData": {
"type": "sprite-frame",
"fixAlphaTransparencyArtifacts": true,
"hasAlpha": true,
"redirect": "6a5c564e-65a2-4dfc-89df-621f6e68ef2a@f9941"
}
}