import { _decorator, CCFloat, CCInteger, Color, Component, Node, Prefab, randomRangeInt, Vec3 } from 'cc'; import { BoosterBase } from '../Booster/BoosterBase'; import GameState from '../Enum/GameState'; import ScoreType from '../Enum/ScoreType'; import { ScoreObject } from '../Environments/ScoreObject'; import GameEvent from '../Events/GameEvent'; import { registerGizmos } from '../Gizmos/Decorator'; import Gizmos2D from '../Gizmos/Gizmos2D'; import ObjectPool from '../Pool/ObjectPool'; import { EventManger } from './EventManger'; const { ccclass, property } = _decorator; @ccclass('weightedObject') class weightedObject { @property(Prefab) public prefab: Prefab; @property(CCInteger) public readonly weight = 0; @property(CCInteger) public weightStepOnGoal = 0; @property(CCInteger) public maxWeight = 0; @property(CCInteger) public maxObjects = -1; @property({ type: CCInteger, readonly: true }) public currentWeight; } @registerGizmos @ccclass('SpawnObjectManager') export class SpawnObjectManager extends Component { @property({ type: weightedObject, visible: true }) private _objects: weightedObject[] = []; @property({ type: weightedObject, visible: true }) private _boosters: weightedObject[] = []; @property({ type: Node, visible: true }) private _spawnPoints: Node[] = []; @property({ type: CCFloat, visible: true }) private readonly _spawnTime; @property({ type: CCFloat, visible: true }) private readonly _spawnTimeWhenBoosterActive; @property({ type: CCFloat, visible: true }) private _spawnBoosterTime; private _pools: ObjectPool[] = []; private _boosterPools: ObjectPool[] = []; private _usedPoints: { [key: string]: Node } = {}; private _playing = false; private _timer = 0; private _timerBooster = 0; private _weights: number[] = []; private _boosterWeights: number[] = []; private _isReplay = false; private _boosterSpawned = false; private _spawnTimeObject = 0; onDrawGizmos(): void { Gizmos2D.beginColor(this.node, new Color(0, 255, 0, 180)); for (let i = 0; i < this._spawnPoints.length; i++) { Gizmos2D.drawSolidCircle(this.node, this._spawnPoints[i].worldPosition, 15); } } protected onLoad(): void { EventManger.instance.on(GameEvent.ObjectRelease, this.onObjectRelease, this); EventManger.instance.on(GameEvent.GameStateChange, this.onGameStateChange, this); EventManger.instance.on(GameEvent.Score, this.onScore, this); EventManger.instance.on(GameEvent.BoosterActive, this.onBoosterActive, this); EventManger.instance.on(GameEvent.BoosterDisable, this.onBoosterDisable, this); this._spawnTimeObject = this._spawnTime; for (let i = 0; i < this._objects.length; i++) { const prefab = this._objects[i].prefab; this._pools[i] = new ObjectPool(prefab, 10, true, ScoreObject); } for (let i = 0; i < this._boosters.length; i++) { const prefab = this._boosters[i].prefab; this._boosterPools[i] = new ObjectPool(prefab, 2, true, BoosterBase); } } protected update(dt: number): void { if (!this._playing) return; this._timer += dt; if (this._timer >= this._spawnTimeObject) { this._timer = 0; this.spawn(); } if (this._boosterSpawned) return; this._timerBooster += dt; if (this._timerBooster >= this._spawnBoosterTime) { this._timerBooster = 0; this.spawnBooster(); } } private spawn() { if (Object.keys(this._usedPoints).length == this._spawnPoints.length) return; do { var randomPool = this._pools.getRandom(this._weights); var index = this._pools.indexOf(randomPool); } while (this._objects[index].maxObjects != -1 && randomPool.countActive >= this._objects[index].maxObjects); do { var randomPoint = this._spawnPoints[randomRangeInt(0, this._spawnPoints.length)]; } while (Object.values(this._usedPoints).indexOf(randomPoint) != -1); const obj = randomPool.get(this.node); obj.setWorldPosition(randomPoint.worldPosition); this._usedPoints[obj.uuid] = randomPoint; } private spawnBooster() { if (Object.keys(this._usedPoints).length == this._spawnPoints.length) return; do { var randomPool = this._boosterPools.getRandom(this._boosterWeights); var index = this._boosterPools.indexOf(randomPool); } while (this._boosters[index].maxObjects != -1 && randomPool.countActive >= this._boosters[index].maxObjects); do { var randomPoint = this._spawnPoints[randomRangeInt(0, this._spawnPoints.length)]; } while (Object.values(this._usedPoints).indexOf(randomPoint) != -1); const obj = randomPool.get(this.node); obj.setWorldPosition(randomPoint.worldPosition); this._usedPoints[obj.uuid] = randomPoint; this._boosterSpawned = true; } private onObjectRelease(obj: Node) { delete this._usedPoints[obj.uuid]; } private onBoosterActive() { this._boosterSpawned = false; this._spawnTimeObject = this._spawnTimeWhenBoosterActive; } private onBoosterDisable() { this._spawnTimeObject = this._spawnTime; } private onScore(score: number, points: number, type: ScoreType) { if (type == ScoreType.Goal) { this._objects.forEach((object) => { if (object.currentWeight >= object.maxWeight) { object.currentWeight = object.maxWeight; return; } object.currentWeight += object.weightStepOnGoal; }); this._boosters.forEach((object) => { if (object.currentWeight >= object.maxWeight) { object.currentWeight = object.maxWeight; return; } object.currentWeight += object.weightStepOnGoal; }); this._weights = this._objects.map((obj) => obj.currentWeight); this._boosterWeights = this._boosters.map((obj) => obj.currentWeight); } } private onGameStateChange(state: GameState) { switch (state) { case GameState.Init: break; case GameState.Ready: break; case GameState.Playing: this._playing = true; if (this._isReplay) return; this._weights = this._objects.map((obj) => { obj.currentWeight = obj.weight; return obj.currentWeight; }); this._boosterWeights = this._boosters.map((obj) => { obj.currentWeight = obj.weight; return obj.currentWeight; }); for (let i = 0; i < randomRangeInt(5, 10); i++) { this.spawn(); } break; case GameState.GameOver: this._playing = false; break; case GameState.Relive: this._isReplay = true; break; case GameState.End: break; } } }