feat: add sfx

main
tiendat3699 2024-04-03 16:43:18 +07:00
parent 15bb43a4ca
commit bbdb01ac87
74 changed files with 2535 additions and 1607 deletions

View File

@ -941,11 +941,11 @@
"__id__": 47
},
"_hitSound": {
"__uuid__": "6a432293-3852-4267-be19-c671f36fe9f0",
"__uuid__": "b122d38e-ecf1-42e2-8b26-c09d306d90d9",
"__expectedType__": "cc.AudioClip"
},
"_ballThrowSound": {
"__uuid__": "97c8a166-c717-41bd-837f-bd1733e2ee1c",
"_hitFlipperSound": {
"__uuid__": "a76cc94a-6331-47e7-b8aa-0caeea6a79eb",
"__expectedType__": "cc.AudioClip"
},
"_jumpCurve": {

View File

@ -1119,6 +1119,10 @@
"_animation": {
"__id__": 82
},
"_collectSound": {
"__uuid__": "1ac12acc-dde3-4d31-9106-dfc30c030d40",
"__expectedType__": "cc.AudioClip"
},
"time": 10,
"_id": ""
},

View File

@ -318,7 +318,7 @@
"__id__": 16
},
"_hitSound": {
"__uuid__": "1f602e14-2769-4903-b4d2-b0977eeaf36b",
"__uuid__": "65a023cb-b98f-4470-ba2d-4eba9fe184fe",
"__expectedType__": "cc.AudioClip"
},
"_score": 0,

View File

@ -318,7 +318,7 @@
"__id__": 16
},
"_hitSound": {
"__uuid__": "1f602e14-2769-4903-b4d2-b0977eeaf36b",
"__uuid__": "65a023cb-b98f-4470-ba2d-4eba9fe184fe",
"__expectedType__": "cc.AudioClip"
},
"_score": 5,

File diff suppressed because it is too large Load Diff

View File

@ -1,9 +1,10 @@
import { _decorator, CCFloat, Collider2D, Component, Contact2DType, Animation } from 'cc';
import { _decorator, CCFloat, Collider2D, Component, Contact2DType, Animation, AudioClip } from 'cc';
import ObjectPool from '../Pool/ObjectPool';
import { EventManger } from '../Manager/EventManger';
import GameEvent from '../Events/GameEvent';
import IPoolable from '../Pool/IPoolable';
import Utilities from '../Utilities';
import { SoundManager } from '../Manager/SoundManager';
const { ccclass, property } = _decorator;
@ccclass('BoosterBase')
@ -12,6 +13,9 @@ export class BoosterBase extends Component implements IPoolable {
protected _collider: Collider2D;
@property({ type: Animation, visible: true })
private _animation: Animation;
@property({ type: AudioClip, visible: true })
private _collectSound: AudioClip;
@property(CCFloat)
protected time: number = 10;
@ -22,6 +26,7 @@ export class BoosterBase extends Component implements IPoolable {
private onContactBegin(self: Collider2D, other: Collider2D) {
this.boosterActive();
EventManger.instance.emit(GameEvent.ObjectRelease, this.node);
SoundManager.instance.playSfx(this._collectSound);
ObjectPool.release(this.node);
}

View File

@ -1,5 +1,6 @@
enum GameState {
Init = 'Init',
Ready = 'Ready',
Playing = 'Playing',
GameOver = 'GameOver',
End = 'End',

View File

@ -5,7 +5,9 @@ enum PhysicsGroup {
TRIGGER = 1 << 1,
BALL = 1 << 2,
BALL_THROWING = 1 << 3,
ENEMY = 1 << 4,
BORDER = 1 << 4,
ENEMY = 1 << 5,
FLIPPER = 1 << 6,
}
export default Enum(PhysicsGroup);

View File

@ -1,4 +1,18 @@
import { _decorator, CCInteger, clamp, Component, lerp, Sprite, Node, tween, Prefab, Tween, Vec3, Label } from 'cc';
import {
_decorator,
CCInteger,
clamp,
Component,
lerp,
Sprite,
Node,
tween,
Prefab,
Tween,
Vec3,
Label,
AudioClip,
} from 'cc';
import { EventManger } from '../Manager/EventManger';
import GameEvent from '../Events/GameEvent';
import ScoreType from '../Enum/ScoreType';
@ -6,6 +20,7 @@ import Utilities from '../Utilities';
import { GameManager } from '../Manager/GameManager';
import BoosterType from '../Enum/BoosterType';
import ObjectPool from '../Pool/ObjectPool';
import { SoundManager } from '../Manager/SoundManager';
const { ccclass, property } = _decorator;
@ccclass('CumulativeBar')
@ -19,16 +34,20 @@ export class CumulativeBar extends Component {
@property({ type: Prefab, visible: true })
private _scoreObjectPrefab: Prefab;
@property({ type: AudioClip, visible: true })
private _soundFx;
private _pool: ObjectPool;
private _currentValue = 0;
private _fillValue = 0;
private _active = false;
private _goal = false;
private _timer = 0;
private _multiplier = 1;
protected onLoad(): void {
this._fillBar.fillRange = 0;
this._pool = new ObjectPool(this._scoreObjectPrefab, 100, true);
this._pool = new ObjectPool(this._scoreObjectPrefab, 50, true);
EventManger.instance.on(GameEvent.Score, this.onScore, this);
EventManger.instance.on(GameEvent.BoosterActive, this.onBoosterActive, this);
EventManger.instance.on(GameEvent.BoosterDisable, this.onBoosterDisable, this);
@ -39,7 +58,7 @@ export class CumulativeBar extends Component {
this._timer += dt;
if (this._timer >= 0.1) {
this._timer = 0;
this._currentValue -= 0.5;
this._currentValue -= 2;
if (this._currentValue < 0) {
this._currentValue = 0;
@ -57,14 +76,16 @@ export class CumulativeBar extends Component {
switch (type) {
case ScoreType.DestroyObject:
if (!this._active) return;
this._currentValue += points;
this._multiplier++;
this._currentValue += points * this._multiplier;
if (this._currentValue > this._maxValue) this._currentValue = this._maxValue;
break;
case ScoreType.Goal:
if (this._currentValue == 0) return;
this._multiplier = 0;
this._goal = true;
await Utilities.delay(1);
let items = Math.round(this._currentValue / 5);
GameManager.instance.addScore(
Math.round(this._currentValue),
ScoreType.Combo,
@ -75,16 +96,17 @@ export class CumulativeBar extends Component {
duration: 1,
},
);
this._currentValue = 0;
this._goal = false;
let items = Math.ceil(this._currentValue / 10);
this.playCollectEffect(items);
this._goal = false;
this._currentValue = 0;
break;
}
this._fillValue = -clamp(this._currentValue / 2 / this._maxValue, 0, 0.5);
}
private async playCollectEffect(items: number) {
const time = items < 10 ? 0.05 : 1.5 / items;
const time = 0.04;
while (items > 0) {
const obj = this._pool.get(this._scoreUI);
obj.setWorldPosition(this.node.worldPosition);
@ -101,6 +123,7 @@ export class CumulativeBar extends Component {
.call(() => ObjectPool.release(obj))
.start();
items--;
SoundManager.instance.playSfx(this._soundFx);
await Utilities.delay(time);
}
}
@ -109,6 +132,9 @@ export class CumulativeBar extends Component {
if (type == BoosterType.CumulativeBar) this._active = true;
}
private onBoosterDisable(type: BoosterType) {
if (type == BoosterType.CumulativeBar) this._active = false;
if (type == BoosterType.CumulativeBar) {
this._multiplier = 0;
this._active = false;
}
}
}

View File

@ -1,5 +1,6 @@
import { _decorator, Collider2D, Component, Contact2DType, Node, Animation, RigidBody2D } from 'cc';
import { _decorator, Collider2D, Component, Contact2DType, Node, Animation, RigidBody2D, AudioClip } from 'cc';
import { CameraController } from './CameraController';
import { SoundManager } from '../Manager/SoundManager';
const { ccclass, property } = _decorator;
@ccclass('SlingShot')
@ -9,6 +10,9 @@ export default class SlingShot extends Component {
@property({ type: Collider2D, visible: true })
private _collider: Collider2D;
@property({ type: AudioClip, visible: true })
private _soundFx: AudioClip;
protected onLoad(): void {
this._collider.on(Contact2DType.BEGIN_CONTACT, this.onBeginContact, this);
}
@ -16,6 +20,9 @@ export default class SlingShot extends Component {
onBeginContact(self: Collider2D, other: Collider2D) {
this._animation.play();
const velocity = other.getComponent(RigidBody2D).linearVelocity.length();
if (velocity >= 40) CameraController.instance.shake(0.08);
SoundManager.instance.playSfx(this._soundFx);
if (velocity >= 40) {
CameraController.instance.shake(0.08);
}
}
}

View File

@ -9,6 +9,7 @@ import {
Vec2,
Animation,
Vec3,
AudioClip,
} from 'cc';
import Utilities from '../Utilities';
import { Ball } from './Ball';
@ -16,6 +17,7 @@ import TimeConfig from '../Enum/TimeConfig';
import { EventManger } from '../Manager/EventManger';
import GameEvent from '../Events/GameEvent';
import { CameraController } from '../Environments/CameraController';
import { SoundManager } from '../Manager/SoundManager';
const { ccclass, property } = _decorator;
@ccclass('Cannon')
@ -26,6 +28,10 @@ export class Cannon extends Component {
private _animation: Animation;
@property({ type: CCInteger, visible: true })
private _force = 30;
@property({ type: AudioClip, visible: true })
private _soundFx: AudioClip;
@property({ type: EventHandler, visible: true })
private onDone: EventHandler[] = [];
@ -45,6 +51,7 @@ export class Cannon extends Component {
this._animation.play();
ball.setActiveRigi(true);
ball.throwBall(new Vec2(0, this._force));
SoundManager.instance.playSfx(this._soundFx);
await Utilities.delay(TimeConfig.DelayCannonDone);
tween(this._collider.node).to(0.5, { scale: Vec3.ZERO }, { easing: 'backIn' }).start();
EventHandler.emitEvents(this.onDone, ball);

View File

@ -11,11 +11,14 @@ import {
Collider2D,
Sprite,
Contact2DType,
AudioClip,
Tween,
} from 'cc';
import { EventManger } from '../Manager/EventManger';
import GameEvent from '../Events/GameEvent';
import ScoreType from '../Enum/ScoreType';
import GameState from '../Enum/GameState';
import { SoundManager } from '../Manager/SoundManager';
const { ccclass, property } = _decorator;
@ccclass('Enemy')
@ -38,6 +41,10 @@ export class Enemy extends Component {
private _patrolCurve: geometry.AnimationCurve = new geometry.AnimationCurve();
@property({ type: CCFloat, visible: true })
private _multiplierCurve = 100;
@property({ type: AudioClip, visible: true })
private _hitSound: AudioClip;
private x: number;
private y: number;
private _distance: number;
@ -100,8 +107,10 @@ export class Enemy extends Component {
}
private onBeginContact(self: Collider2D, other: Collider2D) {
this._sprite.node.setScale(Vec3.ONE);
SoundManager.instance.playSfx(this._hitSound);
Tween.stopAllByTarget(this._sprite.node.scale);
tween(this._sprite.node.scale)
.set(Vec3.ONE)
.to(0.1, new Vec3(1.2, 1.2), { easing: 'backInOut' })
.to(0.5, Vec3.ONE, { easing: 'backOut' })
.start();
@ -130,11 +139,17 @@ export class Enemy extends Component {
switch (state) {
case GameState.Init:
break;
case GameState.Ready:
break;
case GameState.Playing:
this.init();
break;
case GameState.GameOver:
break;
case GameState.Relive:
break;
case GameState.End:
break;
}
}
}

View File

@ -14,7 +14,6 @@ import Utilities from '../Utilities';
import ObjectPool from '../Pool/ObjectPool';
import { Ball } from './Ball';
import { SoundManager } from '../Manager/SoundManager';
import TimeConfig from '../Enum/TimeConfig';
import { CameraController } from '../Environments/CameraController';
const { ccclass, property } = _decorator;
@ -41,7 +40,7 @@ export class Goal extends Component {
if (ball) {
GameManager.instance.goal(this._score, ball.node.getWorldPosition());
ball.setActiveRigi(false);
const fx = this._goalFxPool.get(this.node, ParticleSystem);
const fx = this._goalFxPool.get(ParticleSystem, this.node);
const pos = ball.node.getWorldPosition();
pos.z = 10;
fx.node.setWorldPosition(pos);
@ -50,7 +49,7 @@ export class Goal extends Component {
ObjectPool.release(ball.node);
CameraController.instance.shake(0.5);
await Utilities.waitUntil(() => fx.isStopped);
this._goalFxPool.release(fx.node);
this._goalFxPool.release(fx);
}
}
}

View File

@ -1,10 +1,11 @@
import { _decorator, Collider2D, Component, Contact2DType, Vec2, Node, ParticleSystem, Prefab } from 'cc';
import { _decorator, Collider2D, Component, Contact2DType, Vec2, Node, ParticleSystem, Prefab, AudioClip } from 'cc';
import { GameManager } from '../Manager/GameManager';
import Utilities from '../Utilities';
import { Ball } from './Ball';
import TimeConfig from '../Enum/TimeConfig';
import ObjectPool from '../Pool/ObjectPool';
import { CameraController } from '../Environments/CameraController';
import { SoundManager } from '../Manager/SoundManager';
const { ccclass, property } = _decorator;
@ccclass('MultiBall')
@ -18,6 +19,9 @@ export class MultiBall extends Component {
@property({ type: Prefab, visible: true })
private _fx: Prefab;
@property({ type: AudioClip, visible: true })
private _soundFX: AudioClip;
private _originBall: Ball;
private _trigged = false;
private _fxPool: ObjectPool;
@ -32,7 +36,7 @@ export class MultiBall extends Component {
CameraController.instance.shake(0.2);
this._originBall.setActiveRigi(true);
const ball1 = this._originBall;
const ball2 = GameManager.instance.spawnBall(false);
const ball2 = GameManager.instance.spawnBall(false, false);
ball1.node.setWorldPosition(this._portRight.worldPosition);
ball1.addForce(new Vec2(20, 0));
@ -49,11 +53,12 @@ export class MultiBall extends Component {
this._originBall = otherCollider.getComponent(Ball);
this._originBall.setActiveRigi(false);
this._trigged = true;
const fx = this._fxPool.get(this.node, ParticleSystem);
const fx = this._fxPool.get(ParticleSystem, this.node);
fx.node.setWorldPosition(this.node.worldPosition);
SoundManager.instance.playSfx(this._soundFX);
await Utilities.delay(TimeConfig.DelayMultiBall);
this._collider.enabled = true;
await Utilities.waitUntil(() => fx.isStopped);
this._fxPool.release(fx.node);
this._fxPool.release(fx);
}
}

View File

@ -37,10 +37,12 @@ export class Ball extends Component implements IPoolable {
private _maxSpeed: number;
@property({ type: RigidBody2D, visible: true })
private _rigidBody: RigidBody2D;
@property({ type: Sprite, visible: true })
private _sprite: Sprite;
@property({ type: Sprite, visible: true })
private _spriteShadow: Sprite;
@property({ type: Animation, visible: true })
private _animation: Animation;
@property({ type: ParticleSystem, visible: true })
@ -51,10 +53,12 @@ export class Ball extends Component implements IPoolable {
private _boosterParticle: ParticleSystem;
@property({ type: CircleCollider2D, visible: true })
private _collider: CircleCollider2D;
@property({ type: AudioClip, visible: true })
private _hitSound: AudioClip;
@property({ type: AudioClip, visible: true })
private _ballThrowSound: AudioClip;
private _hitFlipperSound: AudioClip;
@property({ type: geometry.AnimationCurve, visible: true })
private _jumpCurve: geometry.AnimationCurve = new geometry.AnimationCurve();
@ -131,11 +135,13 @@ export class Ball extends Component implements IPoolable {
const point = selfCollider.node.getWorldPosition().add(dir);
hitPoint = new Vec2(point.x, point.y);
}
const hitFx = this._impactPool.get(this.node.parent, ParticleSystem);
const hitFx = this._impactPool.get(ParticleSystem, this.node.parent);
hitFx.node.setWorldPosition(new Vec3(hitPoint.x, hitPoint.y, 10));
SoundManager.instance.playSfx(this._hitSound);
SoundManager.instance.playSfx(
otherCollider.group == PhysicsGroup.FLIPPER ? this._hitFlipperSound : this._hitSound,
);
await Utilities.waitUntil(() => hitFx.isStopped, 0.1);
this._impactPool.release(hitFx.node);
this._impactPool.release(hitFx);
}
}
@ -162,7 +168,6 @@ export class Ball extends Component implements IPoolable {
}
public throwBall(force: Vec2) {
SoundManager.instance.playSfx(this._ballThrowSound);
this._collider.group = PhysicsGroup.BALL_THROWING;
this._rigidBody.group = PhysicsGroup.BALL_THROWING;
this._rigidBody.applyAngularImpulse(-5 * force.x || 2, true);

View File

@ -11,10 +11,12 @@ import {
Animation,
Vec3,
AnimationState,
AudioClip,
} from 'cc';
import { EventManger } from '../Manager/EventManger';
import GameEvent from '../Events/GameEvent';
import TimeConfig from '../Enum/TimeConfig';
import { SoundManager } from '../Manager/SoundManager';
const { ccclass, property } = _decorator;
export enum ControllerSide {
@ -37,6 +39,9 @@ export class Flipper extends Component {
@property({ visible: true, type: ControllerSide })
private side = ControllerSide.Left;
@property({ type: AudioClip, visible: true })
private _activeSound: AudioClip;
private _timer = 0;
private _isAnimationPlaying;
@ -119,6 +124,7 @@ export class Flipper extends Component {
//#endregion
private activeFlipper(): void {
SoundManager.instance.playSfx(this._activeSound, 0.5);
this._hingeJoint.motorSpeed = this._motorSpeedActive;
}
private deActiveFlipper(): void {

View File

@ -66,10 +66,17 @@ export class GameManager extends Singleton<GameManager>() {
private _ballSpawnPosition: Vec3;
@property({ type: CCInteger, visible: true })
private readonly _timePlay = 120;
@property({ type: AudioClip, visible: true })
private _boosterActiveSound: AudioClip;
@property({ type: AudioClip, visible: true })
private _startSound: AudioClip;
@property({ type: AudioClip, visible: true })
private _ballOutSound: AudioClip;
@property({ type: AudioClip, visible: true })
private _backgroundMusic: AudioClip;
@property({ type: AudioClip, visible: true })
private _gameOverMusic: AudioClip;
private _ballPool: ObjectPool;
private _FloatingScorePool: ObjectPool;
@ -127,6 +134,8 @@ export class GameManager extends Singleton<GameManager>() {
case GameState.Init:
BEConnector.instance.authenticate();
break;
case GameState.Ready:
break;
case GameState.Playing:
this.countTime();
BEConnector.instance.ticketMinus('auth');
@ -134,8 +143,6 @@ export class GameManager extends Singleton<GameManager>() {
case GameState.GameOver:
break;
case GameState.End:
await Utilities.delay(2.5);
BEConnector.instance.postScoreToServer(this.score);
break;
case GameState.Relive:
BEConnector.instance.ticketMinus('revive');
@ -152,7 +159,7 @@ export class GameManager extends Singleton<GameManager>() {
opts: { scaleMin: number; scaleMax: number; duration: number },
) {
this._score += score;
const floatingScore = this._FloatingScorePool.get(this._floatingTextContainer, FloatingText);
const floatingScore = this._FloatingScorePool.get(FloatingText, this._floatingTextContainer);
floatingScore.show(`+${score}`, position, score >= 100 ? opts.scaleMax : opts.scaleMin, opts.duration);
EventManger.instance.emit(GameEvent.Score, [this._score, score, type]);
}
@ -186,11 +193,11 @@ export class GameManager extends Singleton<GameManager>() {
}
}
public spawnBall(throwBall: boolean): Ball {
public spawnBall(throwBall: boolean, playStartSound: boolean = true): Ball {
if (this._gameState != GameState.Playing) return;
SoundManager.instance.playSfx(this._startSound);
if (playStartSound) SoundManager.instance.playSfx(this._startSound);
this.setCurrentBallInGame(1);
const ball = this._ballPool.get(this._ballHolder, Ball);
const ball = this._ballPool.get(Ball, this._ballHolder);
ball.init(this._boostersActive.length > 0);
ball.node.setRotation(Quat.IDENTITY);
ball.node.setPosition(this._ballSpawnPosition);
@ -208,6 +215,7 @@ export class GameManager extends Singleton<GameManager>() {
this.setCurrentBallInGame(-1);
if (this._currentBallInGame <= 0) {
EventManger.instance.emit(GameEvent.BallOut, null);
SoundManager.instance.playSfx(this._ballOutSound);
for (let i = 0; i < this._boostersActive.length; i++) {
const booster = this._boostersActive[i];
EventManger.instance.emit(GameEvent.BoosterDisable, booster.type);
@ -243,7 +251,7 @@ export class GameManager extends Singleton<GameManager>() {
}
if (bonusTime) {
this.addTime(bonusTime);
const floatingScore = this._FloatingScorePool.get(this._floatingTextContainer, FloatingText);
const floatingScore = this._FloatingScorePool.get(FloatingText, this._floatingTextContainer);
floatingScore.show(`+${bonusTime}`, position, 1.5);
}
}
@ -260,7 +268,7 @@ export class GameManager extends Singleton<GameManager>() {
EventManger.instance.emit(GameEvent.BoosterDisable, booster.type);
}
this._boostersActive = [];
SoundManager.instance.playBGM(this._gameOverMusic);
if (this.isReplayed) {
this.changeGameState(GameState.End);
return;
@ -270,12 +278,16 @@ export class GameManager extends Singleton<GameManager>() {
this.changeGameState(GameState.GameOver);
}
public Ready() {
SoundManager.instance.playBGM(this._backgroundMusic, 1);
this.changeGameState(GameState.Ready);
}
public async play() {
this._timer = this._timePlay + TimeConfig.DelayPLay;
this._score = 0;
this._currentBallInGame = 0;
this._isMultiBall = false;
SoundManager.instance.playBGM(this._backgroundMusic, 0.5);
this.changeGameState(GameState.Playing);
await Utilities.delay(TimeConfig.DelayPLay);
this.spawnBall(true);
@ -286,13 +298,13 @@ export class GameManager extends Singleton<GameManager>() {
this._timer = this._timePlay + TimeConfig.DelayPLay;
this._currentBallInGame = 0;
this._isMultiBall = false;
SoundManager.instance.playBGM(this._backgroundMusic, 0.5);
SoundManager.instance.playBGM(this._backgroundMusic, 1);
this.changeGameState(GameState.Playing);
await Utilities.delay(TimeConfig.DelayPLay);
this.spawnBall(true);
}
public ActiveBooster(type: BoosterType, time: number) {
public async ActiveBooster(type: BoosterType, time: number) {
//check booster already active
for (let i = 0; i < this._boostersActive.length; i++) {
const booster = this._boostersActive[i];
@ -300,5 +312,7 @@ export class GameManager extends Singleton<GameManager>() {
}
this._boostersActive.push(new Booster(type, time));
EventManger.instance.emit(GameEvent.BoosterActive, type);
await Utilities.delay(0.2);
SoundManager.instance.playSfx(this._boosterActiveSound);
}
}

View File

@ -23,9 +23,15 @@ class SoundSource {
} else {
this.source.volume = this.volume;
}
this._mute = value;
}
public play() {
if (this.source.playing) {
this.source.playOneShot(this.source.clip, this.mute ? 0 : this.volume);
return;
}
this.source.play();
}
@ -39,19 +45,19 @@ export class SoundManager extends Singleton<SoundManager>('SoundManager') {
private _audioSourcesSfx: { [key: string]: SoundSource } = {};
private _audioSourceBgm: SoundSource;
private isMute = false;
private _isMute = false;
public toggleMute(): boolean {
this.isMute = !this.isMute;
this.setMute(this.isMute);
return this.isMute;
this._isMute = !this._isMute;
this.setMute(this._isMute);
return this._isMute;
}
public setMute(mute: boolean) {
this.isMute = mute;
this._audioSourceBgm.mute = this.isMute;
this._isMute = mute;
this._audioSourceBgm.mute = this._isMute;
for (const key in this._audioSourcesSfx) {
this._audioSourcesSfx[key].mute = this.isMute;
this._audioSourcesSfx[key].mute = this._isMute;
}
}
@ -65,7 +71,7 @@ export class SoundManager extends Singleton<SoundManager>('SoundManager') {
this._audioSourceBgm.volume = volume;
this._audioSourceBgm.source.clip = audio;
this._audioSourceBgm.source.loop = loop;
this._audioSourceBgm.mute = this.isMute;
this._audioSourceBgm.mute = this._isMute;
this._audioSourceBgm.play();
}
@ -76,10 +82,6 @@ export class SoundManager extends Singleton<SoundManager>('SoundManager') {
soundSource.volume = volume;
soundSource.source.loop = loop;
if (loop) return;
if (soundSource.source.playing) {
soundSource.source.playOneShot(audioClip, this.isMute ? 0 : volume);
return;
}
soundSource.play();
return;
}
@ -90,7 +92,7 @@ export class SoundManager extends Singleton<SoundManager>('SoundManager') {
soundSource.source.clip = audioClip;
soundSource.source.loop = loop;
soundSource.source.volume = volume;
soundSource.mute = this.isMute;
soundSource.mute = this._isMute;
this._audioSourcesSfx[audioClip.uuid] = soundSource;
soundSource.play();
}

View File

@ -160,6 +160,8 @@ export class SpawnObjectManager extends Component {
switch (state) {
case GameState.Init:
break;
case GameState.Ready:
break;
case GameState.Playing:
this._playing = true;
if (this._isReplay) return;

View File

@ -1,6 +1,5 @@
import { Component, Node, Prefab, director, instantiate } from 'cc';
import IPoolable from './IPoolable';
import { error } from 'cc';
export default class ObjectPool {
private _inactive: Node[] = [];
@ -58,14 +57,24 @@ export default class ObjectPool {
//#endregion
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 {
public get<T extends Component>(classConstructor: new () => T): T;
public get<T extends Component>(classConstructor: new () => T, parent: Node): T;
public get<T extends Component>(a?: (new () => T) | Node, b?: Node): T | Node {
if (!!!this._prefab) {
console.error('prefab cant be null or undefine');
return;
}
let parent: Node;
let classConstructor: new () => T;
if (a instanceof Node) {
parent = a || director.getScene();
} else {
parent = b || director.getScene();
classConstructor = a;
}
let obj: Node = null;
let p = parent || director.getScene();
if (this._inactive.length > 0) {
// Pop the last object in pool
obj = this._inactive.pop();
@ -78,14 +87,13 @@ export default class ObjectPool {
obj.removeFromParent();
}
obj.setParent(p);
obj.setParent(parent);
this._actives.push(obj);
// Invoke pool handler
const handler = this._poolHandlerComp ? obj.getComponent(this._poolHandlerComp) : null;
if (handler) {
(handler as unknown as IPoolable)?.onGet();
}
if (classConstructor) {
return handler == classConstructor ? handler : obj.getComponent(classConstructor);
}

View File

@ -0,0 +1,17 @@
import { _decorator, Button, Component, Node } from 'cc';
import { SoundManager } from '../Manager/SoundManager';
const { ccclass, property } = _decorator;
@ccclass('ButonSound')
export class ButonSound extends Component {
@property({ type: Node, visible: true })
private _unMute: Node;
@property({ type: Node, visible: true })
private _mute: Node;
public clickBtn() {
const mute = SoundManager.instance.toggleMute();
this._mute.active = mute;
this._unMute.active = !mute;
}
}

View File

@ -0,0 +1,9 @@
{
"ver": "4.0.23",
"importer": "typescript",
"imported": true,
"uuid": "fe6191ed-117d-4e42-aee8-78008aac035d",
"files": [],
"subMetas": {},
"userData": {}
}

View File

@ -1,4 +1,4 @@
import { _decorator, Component, Label, Node, Prefab, Tween, tween, Vec3 } from 'cc';
import { _decorator, AudioClip, Component, Label, Node, Prefab, Tween, tween, Vec3 } from 'cc';
import BEConnector from '../API/BEConnector';
import { GameManager } from '../Manager/GameManager';
import ObjectPool from '../Pool/ObjectPool';
@ -6,6 +6,7 @@ import Utilities from '../Utilities';
import { EventManger } from '../Manager/EventManger';
import GameEvent from '../Events/GameEvent';
import GameState from '../Enum/GameState';
import { SoundManager } from '../Manager/SoundManager';
const { ccclass, property } = _decorator;
@ccclass('GameOverPanel')
@ -26,9 +27,13 @@ export class GameOverPanel extends Component {
@property({ type: Prefab, visible: true })
private _scorePrefab: Prefab;
@property({ type: AudioClip, visible: true })
private _soundCollectCoinFx: AudioClip;
private _pool: ObjectPool;
private _active = false;
private _clicked = false;
private _end = false;
protected onLoad(): void {
this._pool = new ObjectPool(this._scorePrefab, 100, true);
@ -48,13 +53,24 @@ export class GameOverPanel extends Component {
private async onGameStateChange(state: GameState) {
switch (state) {
case GameState.End:
this._buyTicketBtn.active = false;
this._quitBtn.active = false;
case GameState.Init:
break;
case GameState.Ready:
break;
case GameState.Playing:
break;
case GameState.GameOver:
break;
default:
case GameState.End:
this._buyTicketBtn.active = false;
this._quitBtn.active = false;
this._end = true;
if (this._active) {
await Utilities.delay(1);
BEConnector.instance.postScoreToServer(GameManager.instance.score);
}
break;
case GameState.Relive:
break;
}
}
@ -94,13 +110,13 @@ export class GameOverPanel extends Component {
private async playCollectEffect(gameScore: number, currentScore: number) {
if (!this._active) {
let items = Math.round(gameScore / 5);
let x = 5;
if (items >= 300) {
items = 300;
let x = 10;
let items = Math.ceil(gameScore / x);
if (items >= 50) {
items = 50;
x = Math.round(gameScore / items);
}
const time = items < 10 ? 0.1 : 2 / items;
const time = 0.04;
let score = currentScore;
for (let i = 0; i < items; i++) {
score += x;
@ -112,18 +128,23 @@ export class GameOverPanel extends Component {
Tween.stopAllByTarget(this.yourScore);
tween(this.yourScore.node)
.to(0.1, { scale: new Vec3(1.3, 1.3, 1.3) })
.call(() => {
this.yourScore.string =
items == 0
? (gameScore + BEConnector.instance.currentScore).toString()
: score.toString();
.call(async () => {
if (i == items - 1) {
this.yourScore.string = (gameScore + BEConnector.instance.currentScore).toString();
if (this._end) {
await Utilities.delay(1);
BEConnector.instance.postScoreToServer(gameScore);
}
} else {
this.yourScore.string = score.toString();
}
})
.set({ scale: Vec3.ONE })
.start();
})
.call(() => ObjectPool.release(obj))
.start();
items--;
SoundManager.instance.playSfx(this._soundCollectCoinFx);
await Utilities.delay(time);
}
}

View File

@ -79,8 +79,14 @@ export class UIController extends Component {
this._scoreLabel.string = '0';
this._timeLabel.string = this.secondsToTime(GameManager.instance.gameTime);
break;
case GameState.Ready:
this._tutorialPanel.active = true;
this._startPanel.active = false;
break;
case GameState.Playing:
this._overPanel.active = false;
this._ticketLabel.string = BEConnector.instance.numberTicket.toString();
break;
case GameState.GameOver:
this.showEventLabel('TIME UP!!!');
@ -95,6 +101,8 @@ export class UIController extends Component {
break;
case GameState.Relive:
this._overPanel.active = false;
this._ticketLabel.string = BEConnector.instance.numberTicket.toString();
break;
}
}
@ -115,8 +123,7 @@ export class UIController extends Component {
}
public starGame() {
this._tutorialPanel.active = true;
this._startPanel.active = false;
GameManager.instance.Ready();
}
private onTimeUpdate(time: number) {

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -1,14 +0,0 @@
{
"ver": "1.0.0",
"importer": "audio-clip",
"imported": true,
"uuid": "5318386a-c072-4982-b604-d79513736912",
"files": [
".json",
".mp3"
],
"subMetas": {},
"userData": {
"downloadMode": 0
}
}

Binary file not shown.

View File

@ -1,14 +0,0 @@
{
"ver": "1.0.0",
"importer": "audio-clip",
"imported": true,
"uuid": "1f602e14-2769-4903-b4d2-b0977eeaf36b",
"files": [
".json",
".mp3"
],
"subMetas": {},
"userData": {
"downloadMode": 0
}
}

Binary file not shown.

View File

@ -2,7 +2,7 @@
"ver": "1.0.0",
"importer": "audio-clip",
"imported": true,
"uuid": "b8e26fea-3d75-4254-8fe6-4a57c40d6121",
"uuid": "40b027bb-9e2f-40e5-85a7-cd32e2ad51af",
"files": [
".json",
".mp3"

Binary file not shown.

View File

@ -2,7 +2,7 @@
"ver": "1.0.0",
"importer": "audio-clip",
"imported": true,
"uuid": "6a432293-3852-4267-be19-c671f36fe9f0",
"uuid": "bab45dd0-83c3-45fe-958c-5a21a4c4a5bb",
"files": [
".json",
".mp3"

Binary file not shown.

View File

@ -2,7 +2,7 @@
"ver": "1.0.0",
"importer": "audio-clip",
"imported": true,
"uuid": "fc66df28-6c8c-4915-adbd-5a3da652cfc6",
"uuid": "a76cc94a-6331-47e7-b8aa-0caeea6a79eb",
"files": [
".json",
".mp3"

Binary file not shown.

View File

@ -2,7 +2,7 @@
"ver": "1.0.0",
"importer": "audio-clip",
"imported": true,
"uuid": "97c8a166-c717-41bd-837f-bd1733e2ee1c",
"uuid": "90fc5275-7ce7-4e86-a757-0674c4fe8f18",
"files": [
".json",
".mp3"

Binary file not shown.

View File

@ -0,0 +1,14 @@
{
"ver": "1.0.0",
"importer": "audio-clip",
"imported": true,
"uuid": "4dba398c-e777-4670-8b1b-76b3fbfb4625",
"files": [
".json",
".mp3"
],
"subMetas": {},
"userData": {
"downloadMode": 0
}
}

Binary file not shown.

View File

@ -0,0 +1,14 @@
{
"ver": "1.0.0",
"importer": "audio-clip",
"imported": true,
"uuid": "c4a1c16a-96e4-4e8a-9188-cf42b4f35f73",
"files": [
".json",
".mp3"
],
"subMetas": {},
"userData": {
"downloadMode": 0
}
}

Binary file not shown.

View File

@ -0,0 +1,14 @@
{
"ver": "1.0.0",
"importer": "audio-clip",
"imported": true,
"uuid": "65a023cb-b98f-4470-ba2d-4eba9fe184fe",
"files": [
".json",
".mp3"
],
"subMetas": {},
"userData": {
"downloadMode": 0
}
}

Binary file not shown.

View File

@ -0,0 +1,14 @@
{
"ver": "1.0.0",
"importer": "audio-clip",
"imported": true,
"uuid": "1ac12acc-dde3-4d31-9106-dfc30c030d40",
"files": [
".json",
".mp3"
],
"subMetas": {},
"userData": {
"downloadMode": 0
}
}

Binary file not shown.

View File

@ -0,0 +1,14 @@
{
"ver": "1.0.0",
"importer": "audio-clip",
"imported": true,
"uuid": "ac21d2c4-7749-4701-af6a-b4ac4b43e7a5",
"files": [
".json",
".mp3"
],
"subMetas": {},
"userData": {
"downloadMode": 0
}
}

Binary file not shown.

View File

@ -2,7 +2,7 @@
"ver": "1.0.0",
"importer": "audio-clip",
"imported": true,
"uuid": "d93b45ca-fea1-4d38-b460-170b6b65ae08",
"uuid": "4ce9d2c6-98c5-4d05-94af-70193bb795fe",
"files": [
".json",
".mp3"

Binary file not shown.

View File

@ -0,0 +1,14 @@
{
"ver": "1.0.0",
"importer": "audio-clip",
"imported": true,
"uuid": "ac267249-4228-4a86-b4d4-39f84a210668",
"files": [
".json",
".mp3"
],
"subMetas": {},
"userData": {
"downloadMode": 0
}
}

Binary file not shown.

View File

@ -0,0 +1,14 @@
{
"ver": "1.0.0",
"importer": "audio-clip",
"imported": true,
"uuid": "b122d38e-ecf1-42e2-8b26-c09d306d90d9",
"files": [
".json",
".mp3"
],
"subMetas": {},
"userData": {
"downloadMode": 0
}
}

Binary file not shown.

View File

@ -0,0 +1,14 @@
{
"ver": "1.0.0",
"importer": "audio-clip",
"imported": true,
"uuid": "d3b9a148-5c8e-41f4-9e87-c09175e20b2d",
"files": [
".json",
".mp3"
],
"subMetas": {},
"userData": {
"downloadMode": 0
}
}

Binary file not shown.

View File

@ -0,0 +1,14 @@
{
"ver": "1.0.0",
"importer": "audio-clip",
"imported": true,
"uuid": "87e078a9-1082-4700-bd78-e6d0a06a150d",
"files": [
".json",
".mp3"
],
"subMetas": {},
"userData": {
"downloadMode": 0
}
}

Binary file not shown.

View File

@ -0,0 +1,14 @@
{
"ver": "1.0.0",
"importer": "audio-clip",
"imported": true,
"uuid": "8602f38f-d976-4e2b-baa2-621a62f20261",
"files": [
".json",
".mp3"
],
"subMetas": {},
"userData": {
"downloadMode": 0
}
}

Binary file not shown.

View File

@ -0,0 +1,14 @@
{
"ver": "1.0.0",
"importer": "audio-clip",
"imported": true,
"uuid": "015d5eb5-b790-46d8-a580-b35ecb94caf3",
"files": [
".json",
".mp3"
],
"subMetas": {},
"userData": {
"downloadMode": 0
}
}

Binary file not shown.

View File

@ -1,14 +0,0 @@
{
"ver": "1.0.0",
"importer": "audio-clip",
"imported": true,
"uuid": "6452248b-259c-4844-b0e1-70f47d69955e",
"files": [
".json",
".mp3"
],
"subMetas": {},
"userData": {
"downloadMode": 0
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.1 KiB

View File

@ -2,7 +2,7 @@
"ver": "1.0.25",
"importer": "image",
"imported": true,
"uuid": "ff046972-01bd-4d20-b27d-92120e050ca3",
"uuid": "4bcfb3c4-ecab-48a0-8bd6-c2916fd3acb3",
"files": [
".json",
".png"
@ -10,14 +10,14 @@
"subMetas": {
"6c48a": {
"importer": "texture",
"uuid": "ff046972-01bd-4d20-b27d-92120e050ca3@6c48a",
"displayName": "Play_Button",
"uuid": "4bcfb3c4-ecab-48a0-8bd6-c2916fd3acb3@6c48a",
"displayName": "No_Sound",
"id": "6c48a",
"name": "texture",
"userData": {
"wrapModeS": "clamp-to-edge",
"wrapModeT": "clamp-to-edge",
"imageUuidOrDatabaseUri": "ff046972-01bd-4d20-b27d-92120e050ca3",
"imageUuidOrDatabaseUri": "4bcfb3c4-ecab-48a0-8bd6-c2916fd3acb3",
"isUuid": true,
"visible": false,
"minfilter": "linear",
@ -34,8 +34,8 @@
},
"f9941": {
"importer": "sprite-frame",
"uuid": "ff046972-01bd-4d20-b27d-92120e050ca3@f9941",
"displayName": "Play_Button",
"uuid": "4bcfb3c4-ecab-48a0-8bd6-c2916fd3acb3@f9941",
"displayName": "No_Sound",
"id": "f9941",
"name": "spriteFrame",
"userData": {
@ -46,10 +46,10 @@
"offsetY": 0,
"trimX": 0,
"trimY": 0,
"width": 478,
"height": 194,
"rawWidth": 478,
"rawHeight": 194,
"width": 203,
"height": 159,
"rawWidth": 203,
"rawHeight": 159,
"borderTop": 0,
"borderBottom": 0,
"borderLeft": 0,
@ -61,17 +61,17 @@
"meshType": 0,
"vertices": {
"rawPosition": [
-239,
-97,
-101.5,
-79.5,
0,
239,
-97,
101.5,
-79.5,
0,
-239,
97,
-101.5,
79.5,
0,
239,
97,
101.5,
79.5,
0
],
"indexes": [
@ -84,12 +84,12 @@
],
"uv": [
0,
194,
478,
194,
159,
203,
159,
0,
0,
478,
203,
0
],
"nuv": [
@ -103,18 +103,18 @@
1
],
"minPos": [
-239,
-97,
-101.5,
-79.5,
0
],
"maxPos": [
239,
97,
101.5,
79.5,
0
]
},
"isUuid": true,
"imageUuidOrDatabaseUri": "ff046972-01bd-4d20-b27d-92120e050ca3@6c48a",
"imageUuidOrDatabaseUri": "4bcfb3c4-ecab-48a0-8bd6-c2916fd3acb3@6c48a",
"atlasUuid": ""
},
"ver": "1.0.11",
@ -129,6 +129,6 @@
"type": "sprite-frame",
"fixAlphaTransparencyArtifacts": true,
"hasAlpha": true,
"redirect": "ff046972-01bd-4d20-b27d-92120e050ca3@f9941"
"redirect": "4bcfb3c4-ecab-48a0-8bd6-c2916fd3acb3@f9941"
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.9 KiB

View File

@ -2,7 +2,7 @@
"ver": "1.0.25",
"importer": "image",
"imported": true,
"uuid": "98ce9fe6-ed8c-477d-96ba-d283b6ac387a",
"uuid": "834b7b1a-0bf9-437a-b2ee-627c08bc87cc",
"files": [
".json",
".png"
@ -10,14 +10,14 @@
"subMetas": {
"6c48a": {
"importer": "texture",
"uuid": "98ce9fe6-ed8c-477d-96ba-d283b6ac387a@6c48a",
"displayName": "P4P_BG-01",
"uuid": "834b7b1a-0bf9-437a-b2ee-627c08bc87cc@6c48a",
"displayName": "Sound",
"id": "6c48a",
"name": "texture",
"userData": {
"wrapModeS": "clamp-to-edge",
"wrapModeT": "clamp-to-edge",
"imageUuidOrDatabaseUri": "98ce9fe6-ed8c-477d-96ba-d283b6ac387a",
"imageUuidOrDatabaseUri": "834b7b1a-0bf9-437a-b2ee-627c08bc87cc",
"isUuid": true,
"visible": false,
"minfilter": "linear",
@ -34,8 +34,8 @@
},
"f9941": {
"importer": "sprite-frame",
"uuid": "98ce9fe6-ed8c-477d-96ba-d283b6ac387a@f9941",
"displayName": "P4P_BG-01",
"uuid": "834b7b1a-0bf9-437a-b2ee-627c08bc87cc@f9941",
"displayName": "Sound",
"id": "f9941",
"name": "spriteFrame",
"userData": {
@ -46,10 +46,10 @@
"offsetY": 0,
"trimX": 0,
"trimY": 0,
"width": 512,
"height": 512,
"rawWidth": 512,
"rawHeight": 512,
"width": 209,
"height": 159,
"rawWidth": 209,
"rawHeight": 159,
"borderTop": 0,
"borderBottom": 0,
"borderLeft": 0,
@ -61,17 +61,17 @@
"meshType": 0,
"vertices": {
"rawPosition": [
-256,
-256,
-104.5,
-79.5,
0,
256,
-256,
104.5,
-79.5,
0,
-256,
256,
-104.5,
79.5,
0,
256,
256,
104.5,
79.5,
0
],
"indexes": [
@ -84,12 +84,12 @@
],
"uv": [
0,
512,
512,
512,
159,
209,
159,
0,
0,
512,
209,
0
],
"nuv": [
@ -103,18 +103,18 @@
1
],
"minPos": [
-256,
-256,
-104.5,
-79.5,
0
],
"maxPos": [
256,
256,
104.5,
79.5,
0
]
},
"isUuid": true,
"imageUuidOrDatabaseUri": "98ce9fe6-ed8c-477d-96ba-d283b6ac387a@6c48a",
"imageUuidOrDatabaseUri": "834b7b1a-0bf9-437a-b2ee-627c08bc87cc@6c48a",
"atlasUuid": ""
},
"ver": "1.0.11",
@ -129,6 +129,6 @@
"type": "sprite-frame",
"fixAlphaTransparencyArtifacts": true,
"hasAlpha": true,
"redirect": "98ce9fe6-ed8c-477d-96ba-d283b6ac387a@f9941"
"redirect": "834b7b1a-0bf9-437a-b2ee-627c08bc87cc@f9941"
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 24 KiB

View File

@ -1,134 +0,0 @@
{
"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"
}
}