feat: update game event manager

main
tiendat3699 2024-03-07 01:08:30 +07:00
parent 4d97fc35ea
commit 136a898942
15 changed files with 428 additions and 341 deletions

View File

@ -962,12 +962,16 @@
"__prefab": { "__prefab": {
"__id__": 70 "__id__": 70
}, },
"rigidbody": { "_rigidbody": {
"__id__": 67 "__id__": 67
}, },
"collider": { "_collider": {
"__id__": 65 "__id__": 65
}, },
"_hitSound": {
"__uuid__": "6a432293-3852-4267-be19-c671f36fe9f0",
"__expectedType__": "cc.AudioClip"
},
"_id": "" "_id": ""
}, },
{ {

File diff suppressed because it is too large Load Diff

View File

@ -1,3 +1,6 @@
enum GameEvent {} enum GameEvent {
GameStateChange,
BallHit,
}
export default GameEvent; export default GameEvent;

View File

@ -0,0 +1,7 @@
enum GameState {
Init,
Playing,
GameOver,
}
export default GameState;

View File

@ -0,0 +1,9 @@
{
"ver": "4.0.23",
"importer": "typescript",
"imported": true,
"uuid": "cf53cc6f-2c88-4312-828e-6edf8bfc7583",
"files": [],
"subMetas": {},
"userData": {}
}

View File

@ -1,5 +1,6 @@
import { import {
_decorator, _decorator,
AudioClip,
CCFloat, CCFloat,
Collider2D, Collider2D,
Component, Component,
@ -9,52 +10,64 @@ import {
EventTarget, EventTarget,
IPhysics2DContact, IPhysics2DContact,
RigidBody2D, RigidBody2D,
Vec2,
} from 'cc'; } from 'cc';
import IPoolable from '../Pool/IPoolable'; import IPoolable from '../Pool/IPoolable';
import Utilities from '../Utilities/Utilities'; import { SoundManager } from '../Manager/SoundManager';
const { ccclass, property } = _decorator; const { ccclass, property } = _decorator;
@ccclass('Ball') @ccclass('Ball')
export class Ball extends Component implements IPoolable { export class Ball extends Component implements IPoolable {
@property({ visible: true, type: CCFloat }) @property({ type: CCFloat, visible: true })
public maxSpeed: number; private _maxSpeed: number;
@property({ visible: true, type: RigidBody2D }) @property({ type: RigidBody2D, visible: true })
public rigidbody: RigidBody2D; private _rigidbody: RigidBody2D;
@property(Collider2D) @property({ type: Collider2D, visible: true })
public collider: Collider2D; private _collider: Collider2D;
public isActive: boolean; @property({ type: AudioClip, visible: true })
private hitted = false; private _hitSound: AudioClip;
private _hitted = false;
public eventHitObstacle = new EventTarget(); public eventHitObstacle = new EventTarget();
public eventGoal = new EventTarget(); public eventGoal = new EventTarget();
protected onLoad(): void { protected onLoad(): void {
if (this.getComponent(Collider2D)) { if (this._collider) {
this.collider.on(Contact2DType.BEGIN_CONTACT, this.onBeginContact, this); this._collider.on(Contact2DType.BEGIN_CONTACT, this.onBeginContact, this);
this.collider.on(Contact2DType.END_CONTACT, this.onEndContact, this); this._collider.on(Contact2DType.END_CONTACT, this.onEndContact, this);
} }
director.on(Director.EVENT_AFTER_PHYSICS, this.setMaxVelocity, this); director.on(Director.EVENT_AFTER_PHYSICS, this.setMaxVelocity, this);
} }
private onBeginContact(selfCollider: Collider2D, otherCollider: Collider2D, contact: IPhysics2DContact | null) {} private onBeginContact(selfCollider: Collider2D, otherCollider: Collider2D, contact: IPhysics2DContact | null) {
if (this._hitted) return;
this._hitted = true;
if (this._rigidbody.linearVelocity.length() >= 3) {
SoundManager.instance.playSfx(this._hitSound);
}
}
private setMaxVelocity() { private setMaxVelocity() {
if (this.rigidbody.linearVelocity.length() > this.maxSpeed) { if (this._rigidbody.linearVelocity.length() > this._maxSpeed) {
this.rigidbody.linearVelocity = this.rigidbody.linearVelocity.normalize().multiplyScalar(this.maxSpeed); this._rigidbody.linearVelocity = this._rigidbody.linearVelocity.normalize().multiplyScalar(this._maxSpeed);
} }
} }
private onEndContact(selfCollider: Collider2D, otherCollider: Collider2D, contact: IPhysics2DContact | null) { private onEndContact(selfCollider: Collider2D, otherCollider: Collider2D, contact: IPhysics2DContact | null) {
// console.log(otherCollider.tag, otherCollider.node.name); // console.log(otherCollider.tag, otherCollider.node.name);
this.hitted = false; this._hitted = false;
} }
reuse() { public addFocre(force: Vec2) {
console.log('use'); const point = this.node.getWorldPosition();
this._rigidbody.applyLinearImpulse(force, new Vec2(point.x, point.y), true);
} }
reuse() {}
unuse() { unuse() {
console.log('unuse'); this._rigidbody.linearVelocity = Vec2.ZERO.clone();
this._rigidbody.angularVelocity = 0;
} }
} }

View File

@ -0,0 +1,17 @@
import { _decorator, Collider2D, Component, Contact2DType, Node } from 'cc';
import { GameManager } from '../Manager/GameManager';
const { ccclass, property } = _decorator;
@ccclass('Outer')
export class Outer extends Component {
@property({ type: Collider2D, visible: true })
private _collider: Collider2D;
protected start(): void {
this._collider.on(Contact2DType.BEGIN_CONTACT, this.onBeginContact, this);
}
private onBeginContact(selfCollider: Collider2D, otherCollider: Collider2D) {
GameManager.instance.ballOut(otherCollider.node);
}
}

View File

@ -0,0 +1,9 @@
{
"ver": "4.0.23",
"importer": "typescript",
"imported": true,
"uuid": "dabd58dc-7708-4931-ad63-cd7875b7b5df",
"files": [],
"subMetas": {},
"userData": {}
}

View File

@ -0,0 +1,12 @@
{
"ver": "1.1.0",
"importer": "directory",
"imported": true,
"uuid": "29983e40-308b-4f9e-9e19-104e958a083b",
"files": [],
"subMetas": {},
"userData": {
"compressionType": {},
"isRemoteBundle": {}
}
}

View File

@ -0,0 +1,12 @@
import GameEvent from '../Enum/GameEvent';
import GameState from '../Enum/GameState';
export interface GameEventCallbackMap {
[GameEvent.GameStateChange]: (state: GameState) => void;
[GameEvent.BallHit]: () => void;
}
export interface GameEventArgMap {
[GameEvent.GameStateChange]: GameState;
[GameEvent.BallHit]: null;
}

View File

@ -0,0 +1,9 @@
{
"ver": "4.0.23",
"importer": "typescript",
"imported": true,
"uuid": "b1eecaf3-413b-4baa-b963-ac905620d203",
"files": [],
"subMetas": {},
"userData": {}
}

View File

@ -1,5 +1,6 @@
import { _decorator, Component, EventTarget, Node } from 'cc'; import { __private, _decorator, Component, EventTarget, Node } from 'cc';
import GameEvent from '../Enum/GameEvent'; import GameEvent from '../Enum/GameEvent';
import { GameEventArgMap, GameEventCallbackMap } from '../Interface/GameEventMap';
const { ccclass, property } = _decorator; const { ccclass, property } = _decorator;
@ccclass('EventManger') @ccclass('EventManger')
@ -21,15 +22,27 @@ export class EventManger extends Component {
} }
} }
public on(eventType: GameEvent, callback?: (...args: any[]) => void, thisArg?: any) { public on<K extends keyof GameEventCallbackMap>(
this._eventTarget.on(eventType, callback, thisArg); eventType: K,
callback: GameEventCallbackMap[K],
target?: any,
): GameEventCallbackMap[K] {
return this._eventTarget.on(eventType, callback, target);
} }
public off(eventType: GameEvent, callback?: (...args: any[]) => void, thisArg?: any) { public off<K extends keyof GameEventCallbackMap>(
this._eventTarget.on(eventType, callback, thisArg); eventType: K,
callback: GameEventCallbackMap[K],
thisArg?: any,
): GameEventCallbackMap[K] {
return this._eventTarget.on(eventType, callback, thisArg);
} }
public emit(eventType: GameEvent, arg0?: any, arg1?: any, arg2?: any, arg3?: any, arg4?: any) { public emit<K extends keyof GameEventArgMap>(eventType: K, arg: GameEventArgMap[K]) {
this._eventTarget.emit(eventType, arg0, arg1, arg2, arg3, arg4); if (Array.isArray(arg)) {
this._eventTarget.emit(eventType, ...arg);
} else {
this._eventTarget.emit(eventType, arg);
}
} }
} }

View File

@ -1,6 +1,10 @@
import { _decorator, Component, Prefab, Node } from 'cc'; import { _decorator, Component, Prefab, Node, Vec2, Vec3, randomRangeInt, CCInteger, Input } 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/Utilities';
import GameState from '../Enum/GameState';
import { EventManger } from './EventManger';
import GameEvent from '../Enum/GameEvent';
const { ccclass, property } = _decorator; const { ccclass, property } = _decorator;
@ccclass('GameManager') @ccclass('GameManager')
@ -13,15 +17,54 @@ export class GameManager extends Component {
@property({ type: Prefab, visible: true }) @property({ type: Prefab, visible: true })
private _ballPrefab: Prefab; private _ballPrefab: Prefab;
@property({ type: Vec3, visible: true })
private _ballSpawnPosition: Vec3;
@property({ type: CCInteger, visible: true })
private _balls = 3;
private _ballPool: ObjectPool; private _ballPool: ObjectPool;
private _gameState = GameState.Init;
public highestStreak: number; public highestStreak: number;
public score = 0; public score = 0;
protected onLoad(): void { protected onLoad(): void {
GameManager._instance = this;
this._ballPool = new ObjectPool(this._ballPrefab, 10, false, Ball); this._ballPool = new ObjectPool(this._ballPrefab, 10, false, Ball);
} }
protected async start() {
// this.spawnBall();
const a = [1, 4, 4, 5];
}
private changeGameState(state: GameState) {
this._gameState = state;
EventManger.instance.emit(GameEvent.GameStateChange, this._gameState);
}
public spawnBall(): Ball {
const ball = this._ballPool.get(this.node, Ball);
ball.node.setPosition(this._ballSpawnPosition);
let dir = randomRangeInt(-1, 2);
while (dir == 0) {
dir = randomRangeInt(-1, 2);
}
const force = new Vec2(dir, 1);
ball.addFocre(force.multiply2f(1, 50));
return ball;
}
public async ballOut(ball: Node) {
this._balls--;
if (this._balls === 0) {
return;
}
this._ballPool.release(ball);
await Utilities.delay(1000);
// this.spawnBall();
}
public onRevive() { public onRevive() {
throw new Error('Method not implemented.'); throw new Error('Method not implemented.');
} }

View File

@ -38,10 +38,10 @@ export class SoundManager extends Component {
//singleton //singleton
private static _instance: SoundManager; private static _instance: SoundManager;
public static get instance(): SoundManager { public static get instance(): SoundManager {
if (SoundManager._instance) { if (!SoundManager._instance) {
SoundManager._instance = new SoundManager('SoundManager'); SoundManager._instance = new SoundManager('SoundManager');
} }
return SoundManager.instance; return SoundManager._instance;
} }
private _audioSourcesSfx: { [key: string]: SoundSource } = {}; private _audioSourcesSfx: { [key: string]: SoundSource } = {};

View File

@ -33,7 +33,6 @@ export default class ObjectPool {
public get(parent?: Node): Node; public get(parent?: Node): Node;
public get<T extends Component>(parent?: Node, classConstructor?: new () => T): T; public get<T extends Component>(parent?: Node, classConstructor?: new () => T): T;
public get<T extends Component>(parent?: Node, classConstructor?: new () => T): T | Node { public get<T extends Component>(parent?: Node, classConstructor?: new () => T): T | Node {
let obj: Node = null; let obj: Node = null;
let p = parent || director.getScene(); let p = parent || director.getScene();