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": {
"__id__": 70
},
"rigidbody": {
"_rigidbody": {
"__id__": 67
},
"collider": {
"_collider": {
"__id__": 65
},
"_hitSound": {
"__uuid__": "6a432293-3852-4267-be19-c671f36fe9f0",
"__expectedType__": "cc.AudioClip"
},
"_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;

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 {
_decorator,
AudioClip,
CCFloat,
Collider2D,
Component,
@ -9,52 +10,64 @@ import {
EventTarget,
IPhysics2DContact,
RigidBody2D,
Vec2,
} from 'cc';
import IPoolable from '../Pool/IPoolable';
import Utilities from '../Utilities/Utilities';
import { SoundManager } from '../Manager/SoundManager';
const { ccclass, property } = _decorator;
@ccclass('Ball')
export class Ball extends Component implements IPoolable {
@property({ visible: true, type: CCFloat })
public maxSpeed: number;
@property({ visible: true, type: RigidBody2D })
public rigidbody: RigidBody2D;
@property(Collider2D)
public collider: Collider2D;
public isActive: boolean;
private hitted = false;
@property({ type: CCFloat, visible: true })
private _maxSpeed: number;
@property({ type: RigidBody2D, visible: true })
private _rigidbody: RigidBody2D;
@property({ type: Collider2D, visible: true })
private _collider: Collider2D;
@property({ type: AudioClip, visible: true })
private _hitSound: AudioClip;
private _hitted = false;
public eventHitObstacle = new EventTarget();
public eventGoal = new EventTarget();
protected onLoad(): void {
if (this.getComponent(Collider2D)) {
this.collider.on(Contact2DType.BEGIN_CONTACT, this.onBeginContact, this);
this.collider.on(Contact2DType.END_CONTACT, this.onEndContact, this);
if (this._collider) {
this._collider.on(Contact2DType.BEGIN_CONTACT, this.onBeginContact, this);
this._collider.on(Contact2DType.END_CONTACT, this.onEndContact, 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() {
if (this.rigidbody.linearVelocity.length() > this.maxSpeed) {
this.rigidbody.linearVelocity = this.rigidbody.linearVelocity.normalize().multiplyScalar(this.maxSpeed);
if (this._rigidbody.linearVelocity.length() > this._maxSpeed) {
this._rigidbody.linearVelocity = this._rigidbody.linearVelocity.normalize().multiplyScalar(this._maxSpeed);
}
}
private onEndContact(selfCollider: Collider2D, otherCollider: Collider2D, contact: IPhysics2DContact | null) {
// console.log(otherCollider.tag, otherCollider.node.name);
this.hitted = false;
this._hitted = false;
}
reuse() {
console.log('use');
public addFocre(force: Vec2) {
const point = this.node.getWorldPosition();
this._rigidbody.applyLinearImpulse(force, new Vec2(point.x, point.y), true);
}
reuse() {}
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 { GameEventArgMap, GameEventCallbackMap } from '../Interface/GameEventMap';
const { ccclass, property } = _decorator;
@ccclass('EventManger')
@ -21,15 +22,27 @@ export class EventManger extends Component {
}
}
public on(eventType: GameEvent, callback?: (...args: any[]) => void, thisArg?: any) {
this._eventTarget.on(eventType, callback, thisArg);
public on<K extends keyof GameEventCallbackMap>(
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) {
this._eventTarget.on(eventType, callback, thisArg);
public off<K extends keyof GameEventCallbackMap>(
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) {
this._eventTarget.emit(eventType, arg0, arg1, arg2, arg3, arg4);
public emit<K extends keyof GameEventArgMap>(eventType: K, arg: GameEventArgMap[K]) {
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 { 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;
@ccclass('GameManager')
@ -13,15 +17,54 @@ export class GameManager extends Component {
@property({ type: Prefab, visible: true })
private _ballPrefab: Prefab;
@property({ type: Vec3, visible: true })
private _ballSpawnPosition: Vec3;
@property({ type: CCInteger, visible: true })
private _balls = 3;
private _ballPool: ObjectPool;
private _gameState = GameState.Init;
public highestStreak: number;
public score = 0;
protected onLoad(): void {
GameManager._instance = this;
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() {
throw new Error('Method not implemented.');
}

View File

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

View File

@ -33,7 +33,6 @@ export default class ObjectPool {
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 | Node {
let obj: Node = null;
let p = parent || director.getScene();