feat: multi ball

main
tiendat3699 2024-03-03 15:23:29 +07:00
parent 9e8f73b417
commit 9bef92b7e7
11 changed files with 3655 additions and 5775 deletions

BIN
assets/Assets/goal.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 222 KiB

134
assets/Assets/goal.png.meta Normal file
View File

@ -0,0 +1,134 @@
{
"ver": "1.0.25",
"importer": "image",
"imported": true,
"uuid": "12b8f875-a7c7-4af5-91be-6aac2e7547be",
"files": [
".json",
".png"
],
"subMetas": {
"6c48a": {
"importer": "texture",
"uuid": "12b8f875-a7c7-4af5-91be-6aac2e7547be@6c48a",
"displayName": "goal",
"id": "6c48a",
"name": "texture",
"userData": {
"wrapModeS": "clamp-to-edge",
"wrapModeT": "clamp-to-edge",
"imageUuidOrDatabaseUri": "12b8f875-a7c7-4af5-91be-6aac2e7547be",
"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": "12b8f875-a7c7-4af5-91be-6aac2e7547be@f9941",
"displayName": "goal",
"id": "f9941",
"name": "spriteFrame",
"userData": {
"trimType": "auto",
"trimThreshold": 1,
"rotated": false,
"offsetX": 0,
"offsetY": 0,
"trimX": 0,
"trimY": 0,
"width": 2304,
"height": 1469,
"rawWidth": 2304,
"rawHeight": 1469,
"borderTop": 0,
"borderBottom": 0,
"borderLeft": 0,
"borderRight": 0,
"packable": true,
"pixelsToUnit": 100,
"pivotX": 0.5,
"pivotY": 0.5,
"meshType": 0,
"vertices": {
"rawPosition": [
-1152,
-734.5,
0,
1152,
-734.5,
0,
-1152,
734.5,
0,
1152,
734.5,
0
],
"indexes": [
0,
1,
2,
2,
1,
3
],
"uv": [
0,
1469,
2304,
1469,
0,
0,
2304,
0
],
"nuv": [
0,
0,
1,
0,
0,
1,
1,
1
],
"minPos": [
-1152,
-734.5,
0
],
"maxPos": [
1152,
734.5,
0
]
},
"isUuid": true,
"imageUuidOrDatabaseUri": "12b8f875-a7c7-4af5-91be-6aac2e7547be@6c48a",
"atlasUuid": ""
},
"ver": "1.0.11",
"imported": true,
"files": [
".json"
],
"subMetas": {}
}
},
"userData": {
"type": "sprite-frame",
"fixAlphaTransparencyArtifacts": true,
"hasAlpha": true,
"redirect": "12b8f875-a7c7-4af5-91be-6aac2e7547be@f9941"
}
}

File diff suppressed because it is too large Load Diff

View File

@ -26,8 +26,6 @@ export class Ball extends Component {
public rigidbody: RigidBody2D;
@property(Collider2D)
public collider: Collider2D;
@property(ParticleSystem)
private trail: ParticleSystem;
public isActive: boolean;
private hitted = false;
@ -43,20 +41,14 @@ export class Ball extends Component {
director.on(Director.EVENT_AFTER_PHYSICS, this.setMaxVelocity, this);
}
protected onEnable(): void {
let dir = randomRangeInt(-1, 2);
while (dir == 0) {
dir = randomRangeInt(-1, 2);
}
const force = new Vec2(dir, 1);
this.rigidbody.applyLinearImpulse(force.multiply2f(5, 50), Vec2.ZERO, true);
SoundManager.Instance().PlayOneShot(SoundManager.Instance().whistle);
protected onDestroy(): void {
GameplayController.Instance().updateCurrentBallsInGame(-1);
}
private onBeginContact(selfCollider: Collider2D, otherCollider: Collider2D, contact: IPhysics2DContact | null) {
// Hit boundary
if (otherCollider.tag == 1) {
this.node.active = false;
this.node.destroy();
// GameplayController.Instance().SpawnBallInTime(1);
GameplayController.Instance().LoseStreak();
SoundManager.Instance().PlayOneShot(SoundManager.Instance().hitGround);
@ -65,14 +57,12 @@ export class Ball extends Component {
// Hit goal
if (otherCollider.tag == 2) {
this.node.destroy();
otherCollider.getComponent(Animation)?.play();
this.node.active = false;
GameplayController.Instance().AddScore(1);
// GameplayController.Instance().SpawnBallInTime(1);
SoundManager.Instance().PlayOneShot(SoundManager.Instance().goal);
this.eventGoal.emit('Goal');
this.eventGoal.emit('Goal', this.node.getWorldPosition());
return;
}
@ -99,8 +89,4 @@ export class Ball extends Component {
// console.log(otherCollider.tag, otherCollider.node.name);
this.hitted = false;
}
public resetTrail() {
this.trail.clear();
}
}

View File

@ -18,10 +18,6 @@ export class FlipperController extends Component {
public lFlipper: Flipper;
@property(Flipper)
public rFlipper: Flipper;
@property(Flipper)
public lFlipper2: Flipper;
@property(Flipper)
public rFlipper2: Flipper;
protected onLoad(): void {
// Mouse input
@ -40,34 +36,26 @@ export class FlipperController extends Component {
private HandleFlipperActive(params: EventMouse): void {
if (params.getLocationX() > screen.width / 2) {
this.rFlipper.ActiveFlipper();
this.rFlipper2.ActiveFlipper();
} else {
this.lFlipper.ActiveFlipper();
this.lFlipper2.ActiveFlipper();
}
}
private HandleFlipperDeActive(params: EventMouse): void {
this.rFlipper.DeActiveFlipper();
this.lFlipper.DeActiveFlipper();
this.rFlipper2.DeActiveFlipper();
this.lFlipper2.DeActiveFlipper();
}
private HandleFlipperActiveTouch(params: EventTouch): void {
if (params.getLocationX() > Screen.windowSize.x / 2) {
console.log('right');
this.rFlipper.ActiveFlipper();
this.rFlipper2.ActiveFlipper();
} else {
console.log('left');
this.lFlipper.ActiveFlipper();
this.lFlipper2.ActiveFlipper();
}
}
private HandleFlipperDeActiveTouch(params: EventTouch): void {
this.rFlipper.DeActiveFlipper();
this.lFlipper.DeActiveFlipper();
this.rFlipper2.DeActiveFlipper();
this.lFlipper2.DeActiveFlipper();
}
//#endregion
@ -76,12 +64,10 @@ export class FlipperController extends Component {
case KeyCode.ARROW_LEFT:
case KeyCode.KEY_A:
this.lFlipper.ActiveFlipper();
this.lFlipper2.ActiveFlipper();
break;
case KeyCode.ARROW_RIGHT:
case KeyCode.KEY_D:
this.rFlipper.ActiveFlipper();
this.rFlipper2.ActiveFlipper();
break;
}
}
@ -90,12 +76,10 @@ export class FlipperController extends Component {
case KeyCode.ARROW_LEFT:
case KeyCode.KEY_A:
this.lFlipper.DeActiveFlipper();
this.lFlipper2.DeActiveFlipper();
break;
case KeyCode.ARROW_RIGHT:
case KeyCode.KEY_D:
this.rFlipper.DeActiveFlipper();
this.rFlipper2.DeActiveFlipper();
break;
}
}

View File

@ -11,6 +11,7 @@ import {
randomRangeInt,
RigidBody2D,
Vec2,
Vec3,
} from 'cc';
import { Ball } from './Ball';
import { EventType } from './Enums';
@ -58,8 +59,6 @@ export class GameplayController extends Component {
private ballPrefab: Prefab;
@property([Vec2])
private startPositions: Vec2[] = [];
@property({ readonly: true, type: Node })
private controllingBall: Node = null;
@property(UIController)
public uiController: UIController = null;
@property(LevelController)
@ -92,8 +91,8 @@ export class GameplayController extends Component {
//#endregion
private _currentRandomEnemies = 0;
public eventMenuGame = new EventTarget();
private _currentBallsInGame = 0;
public eventStartGame = new EventTarget();
public eventPlayGame = new EventTarget();
@ -112,41 +111,36 @@ export class GameplayController extends Component {
this.randomEnemies.forEach((enemy) => (enemy.active = false));
}
private SpawnBall(): void {
public SpawnBall(): Ball {
if (this.currentGameState == GameState.EndGame) return;
if (this.controllingBall == null) {
this.controllingBall = instantiate(this.ballPrefab);
this.controllingBall.parent = this.node;
let randonPos = randomRangeInt(0, this.startPositions.length);
this.controllingBall.setPosition(this.startPositions[randonPos].x, this.startPositions[randonPos].y, 0);
this.controllingBall.active = true;
const ball = this.controllingBall.getComponent(Ball);
ball.eventHitObstacle.on('HitObstacle', this.ObstacleHitControl, this);
ball.getComponent(Ball).eventGoal.on('Goal', this.GoalControl, this);
return;
} else {
const rigi = this.controllingBall.getComponent(RigidBody2D);
rigi.angularVelocity = 0;
rigi.linearVelocity = Vec2.ZERO.clone();
let randonPos = randomRangeInt(0, this.startPositions.length);
this.controllingBall.parent = this.node;
this.controllingBall.setPosition(this.startPositions[randonPos].x, this.startPositions[randonPos].y, 0);
this.controllingBall.active = true;
this.controllingBall.getComponent(Ball).resetTrail();
}
const ballClone = instantiate(this.ballPrefab);
ballClone.setParent(this.node);
let randonPos = randomRangeInt(0, this.startPositions.length);
ballClone.setPosition(this.startPositions[randonPos].x, this.startPositions[randonPos].y, 0);
const ball = ballClone.getComponent(Ball);
ball.eventHitObstacle.on('HitObstacle', this.ObstacleHitControl, this);
ball.eventGoal.on('Goal', this.GoalControl, this);
this._currentBallsInGame++;
return ball;
}
public SpawnBallInTime(time: number): void {
if (this.ball <= 0) return;
if (this.currentGameState == GameState.EndGame) return;
this.spawnEnemies();
//this.unscheduleAllCallbacks();
console.log(this.currentGameState.toString());
console.log(GameState[this.currentGameState]);
this.scheduleOnce(() => {
this.SpawnBall();
const ball = this.SpawnBall();
let dir = randomRangeInt(-1, 2);
while (dir == 0) {
dir = randomRangeInt(-1, 2);
}
const force = new Vec2(dir, 1);
ball.getComponent(RigidBody2D).applyLinearImpulse(force.multiply2f(3, 50), Vec2.ZERO, true);
SoundManager.Instance().PlayOneShot(SoundManager.Instance().whistle);
}, time);
this.SetupObstacle();
}
@ -166,8 +160,6 @@ export class GameplayController extends Component {
this.score += score;
this.streak++;
this.eventUpdateStreak.emit(EventType.UpdateStreak, this.streak);
this.ball--;
if (this.streak > 2) {
let addBall = this.streak - 2;
this.ball += addBall;
@ -182,24 +174,20 @@ export class GameplayController extends Component {
this.eventUpdateScore.emit(EventType.UpdateScore, this.score);
SoundManager.Instance().PlayOneShot(SoundManager.Instance().sfxGoal);
if (this.ball <= 0) this.ChangeGameState(GameState.EndGame);
else this.SpawnBallInTime(1);
}
public LoseStreak(): void {
this.streak = 0;
this.eventUpdateStreak.emit(EventType.UpdateStreak, this.streak);
this.ball--;
this.eventUpdateBall.emit(EventType.UpdateBall, this.ball);
if (this.ball <= 0) this.ChangeGameState(GameState.EndGame);
else this.SpawnBallInTime(1);
}
public ChangeGameState(newState: GameState): void {
if (this.currentGameState == newState) return;
this.currentGameState = newState;
this.StateChangeHandle();
}
private StateChangeHandle(): void {
switch (this.currentGameState) {
case GameState.MainMenu:
@ -241,10 +229,10 @@ export class GameplayController extends Component {
node.active = true;
}, 3);
}
private GoalControl(): void {
const pos = this.controllingBall.position.clone();
private GoalControl(positon: Vec3): void {
const pos = positon;
pos.z = this.particle.node.position.z;
this.particle.node.setPosition(pos);
this.particle.node.setWorldPosition(pos);
this.particle.play();
}
@ -254,4 +242,14 @@ export class GameplayController extends Component {
this.eventUpdateBall.emit(EventType.UpdateBall, this.ball);
this.SpawnBallInTime(1);
}
public updateCurrentBallsInGame(value: number) {
this._currentBallsInGame += value;
if (this._currentBallsInGame <= 0) {
this.ball--;
this.eventUpdateBall.emit(EventType.UpdateBall, this.ball);
if (this.ball <= 0) this.ChangeGameState(GameState.EndGame);
else this.SpawnBallInTime(1);
}
}
}

View File

@ -0,0 +1,40 @@
import { _decorator, Collider2D, Component, Contact2DType, RigidBody2D, Vec2, Node } from 'cc';
import { GameplayController } from './GameplayController';
import Utilities from './Utilities/Utilities';
const { ccclass, property } = _decorator;
@ccclass('MultiBall')
export class MultiBall extends Component {
@property(Collider2D)
private collider: Collider2D;
private trigged = false;
private originBall: Node;
protected onLoad(): void {
this.collider.on(Contact2DType.BEGIN_CONTACT, this.onBeginContact, this);
}
protected lateUpdate(dt: number): void {
if (this.trigged) {
const ballClone = GameplayController.Instance().SpawnBall();
ballClone.node.setWorldPosition(this.node.worldPosition);
this.originBall.setWorldPosition(this.node.worldPosition);
ballClone.getComponent(RigidBody2D).applyLinearImpulse(new Vec2(40, 0), Vec2.ZERO, true);
const rigiball = this.originBall.getComponent(RigidBody2D);
rigiball.linearVelocity = Vec2.ZERO.clone();
rigiball.angularVelocity = 0;
rigiball.applyLinearImpulse(new Vec2(-40, 0), Vec2.ZERO, true);
this.trigged = false;
}
}
private async onBeginContact(selfCollider: Collider2D, otherCollider: Collider2D) {
if (this.trigged) return;
this.collider.enabled = false;
this.originBall = otherCollider.node;
this.trigged = true;
await Utilities.delay(2000);
this.collider.enabled = true;
}
}

View File

@ -0,0 +1,9 @@
{
"ver": "4.0.23",
"importer": "typescript",
"imported": true,
"uuid": "d2d9b8f7-3e0b-430e-80bd-06ebb6be1050",
"files": [],
"subMetas": {},
"userData": {}
}

View File

@ -0,0 +1,9 @@
{
"ver": "4.0.23",
"importer": "typescript",
"imported": true,
"uuid": "028e4fbe-72a3-4608-8e16-08da0b137f94",
"files": [],
"subMetas": {},
"userData": {}
}

View File

@ -66,8 +66,9 @@ export class UIController extends Component {
protected update(dt: number): void {
if (!this.isGameStarted) return;
if (this.countdownTime < 0) {
if (GameplayController.Instance().currentGameState != GameState.PlayGame)
if (GameplayController.Instance().currentGameState != GameState.PlayGame) {
GameplayController.Instance().ChangeGameState(GameState.PlayGame);
}
return;
}

View File

@ -1,6 +1,11 @@
import { Vec3 } from 'cc';
export default class Utilities {
/**
*
* @param time (ms)
* @returns
*/
public static delay(time: number): Promise<any> {
return new Promise((resolve) => setTimeout(resolve, time));
}