feat: update multi ball

main
tiendat3699 2024-03-10 17:12:55 +07:00
parent d94082f019
commit cedd082852
39 changed files with 9061 additions and 1060 deletions

View File

@ -1130,7 +1130,7 @@
"fileId": "9crXsAtjdEQIcD0a2IceFl" "fileId": "9crXsAtjdEQIcD0a2IceFl"
}, },
{ {
"__type__": "b14f8NWzRJDNL9eRfPhDx3G", "__type__": "4630aSZqwlFqb6BUtrii+tV",
"_name": "", "_name": "",
"_objFlags": 0, "_objFlags": 0,
"node": { "node": {
@ -1145,7 +1145,7 @@
"__expectedType__": "cc.Prefab" "__expectedType__": "cc.Prefab"
}, },
"_maxSpeed": 100, "_maxSpeed": 100,
"_rigidbody": { "_rigidBody": {
"__id__": 75 "__id__": 75
}, },
"_sprite": { "_sprite": {
@ -1168,7 +1168,7 @@
}, },
{ {
"__type__": "cc.CompPrefabInfo", "__type__": "cc.CompPrefabInfo",
"fileId": "69msKyk8NLHqP+rm4QOaXF" "fileId": "43eN1N3HRBEa/ox7tb7ZPo"
}, },
{ {
"__type__": "cc.AnimationCurve", "__type__": "cc.AnimationCurve",
@ -1180,8 +1180,6 @@
"__type__": "cc.RealCurve", "__type__": "cc.RealCurve",
"_times": [ "_times": [
0, 0,
0.2,
0.4,
1 1
], ],
"_values": [ "_values": [
@ -1190,34 +1188,10 @@
"interpolationMode": 2, "interpolationMode": 2,
"tangentWeightMode": 0, "tangentWeightMode": 0,
"value": 0, "value": 0,
"rightTangent": 5.777777777777779, "rightTangent": 5.537037037037036,
"rightTangentWeight": 0, "rightTangentWeight": 1,
"leftTangent": 5.777777777777779, "leftTangent": 5.537037037037036,
"leftTangentWeight": 0, "leftTangentWeight": 1,
"easingMethod": 0,
"__editorExtras__": null
},
{
"__type__": "cc.RealKeyframeValue",
"interpolationMode": 2,
"tangentWeightMode": 0,
"value": 1,
"rightTangent": 0.37707337523039497,
"rightTangentWeight": 0,
"leftTangent": 0.37707337523039497,
"leftTangentWeight": 0,
"easingMethod": 0,
"__editorExtras__": null
},
{
"__type__": "cc.RealKeyframeValue",
"interpolationMode": 2,
"tangentWeightMode": 0,
"value": 1,
"rightTangent": -0.5622495861888999,
"rightTangentWeight": 0,
"leftTangent": -0.5622495861888999,
"leftTangentWeight": 0,
"easingMethod": 0, "easingMethod": 0,
"__editorExtras__": null "__editorExtras__": null
}, },
@ -1226,9 +1200,9 @@
"interpolationMode": 2, "interpolationMode": 2,
"tangentWeightMode": 0, "tangentWeightMode": 0,
"value": 0, "value": 0,
"rightTangent": -1.877436291594456, "rightTangent": -2.148148148148149,
"rightTangentWeight": 1, "rightTangentWeight": 1,
"leftTangent": -1.877436291594456, "leftTangent": -2.148148148148149,
"leftTangentWeight": 1, "leftTangentWeight": 1,
"easingMethod": 0, "easingMethod": 0,
"__editorExtras__": null "__editorExtras__": null

View File

@ -146,7 +146,7 @@
"__prefab": { "__prefab": {
"__id__": 7 "__id__": 7
}, },
"_lable": { "_label": {
"__id__": 4 "__id__": 4
}, },
"_moveSpeed": 50, "_moveSpeed": 50,

File diff suppressed because it is too large Load Diff

View File

@ -4,7 +4,8 @@ enum PhysicsGroup {
DEFAULT = 1 << 0, DEFAULT = 1 << 0,
TRIGGER = 1 << 1, TRIGGER = 1 << 1,
BALL = 1 << 2, BALL = 1 << 2,
BALLTHROWING = 1 << 3, BALL_THROWING = 1 << 3,
ENEMY = 1 << 4,
} }
export default Enum(PhysicsGroup); export default Enum(PhysicsGroup);

View File

@ -4,7 +4,7 @@ const { ccclass, property } = _decorator;
@ccclass('FloatingText') @ccclass('FloatingText')
export class FloatingText extends Component { export class FloatingText extends Component {
@property({ type: Label, visible: true }) @property({ type: Label, visible: true })
private _lable: Label; private _label: Label;
@property({ type: CCFloat, visible: true }) @property({ type: CCFloat, visible: true })
private _moveSpeed = 1; private _moveSpeed = 1;
@property({ type: geometry.AnimationCurve, visible: true }) @property({ type: geometry.AnimationCurve, visible: true })
@ -24,7 +24,7 @@ export class FloatingText extends Component {
this._moveDuration = duration - (this._scaleUpDuration + this._scaleDownDuration); this._moveDuration = duration - (this._scaleUpDuration + this._scaleDownDuration);
this.node.setWorldPosition(position); this.node.setWorldPosition(position);
this.node.setScale(Vec3.ZERO); this.node.setScale(Vec3.ZERO);
this._lable.string = text; this._label.string = text;
tween(this.node) tween(this.node)
.to(this._scaleUpDuration, { scale: new Vec3(scale, scale, 1) }, { easing: 'backOut' }) .to(this._scaleUpDuration, { scale: new Vec3(scale, scale, 1) }, { easing: 'backOut' })
.by( .by(
@ -45,7 +45,6 @@ export class FloatingText extends Component {
}, },
{ easing: 'backIn' }, { easing: 'backIn' },
) )
.sequence()
.start(); .start();
} }
} }

View File

@ -15,7 +15,7 @@ import {
import { GameManager } from '../Manager/GameManager'; import { GameManager } from '../Manager/GameManager';
import IPoolable from '../Pool/IPoolable'; import IPoolable from '../Pool/IPoolable';
import ObjectPool from '../Pool/ObjectPool'; import ObjectPool from '../Pool/ObjectPool';
import Utilities from '../Utilities/Utilities'; import Utilities from '../Utilities';
import { EventManger } from '../Manager/EventManger'; import { EventManger } from '../Manager/EventManger';
import GameEvent from '../Events/GameEvent'; import GameEvent from '../Events/GameEvent';
const { ccclass, property, float } = _decorator; const { ccclass, property, float } = _decorator;
@ -35,7 +35,7 @@ export class ScoreObject extends Component implements IPoolable {
private _flyDirection: Vec3; private _flyDirection: Vec3;
private _targetColor: Color; private _targetColor: Color;
private _originColor: Color; private _originColor: Color;
private _hitted = false; private _isHit = false;
protected onLoad(): void { protected onLoad(): void {
this._collider.on(Contact2DType.BEGIN_CONTACT, this.onContactBegin, this); this._collider.on(Contact2DType.BEGIN_CONTACT, this.onContactBegin, this);
@ -43,7 +43,7 @@ export class ScoreObject extends Component implements IPoolable {
} }
protected update(dt: number): void { protected update(dt: number): void {
if (this._hitted) { if (this._isHit) {
const pos = new Vec3(); const pos = new Vec3();
const flySpeed = math.clamp(this._flySpeed * 10, 500, 1000); const flySpeed = math.clamp(this._flySpeed * 10, 500, 1000);
@ -66,13 +66,13 @@ export class ScoreObject extends Component implements IPoolable {
} }
private onContactBegin(selfCollider: Collider2D, otherCollider: Collider2D) { private onContactBegin(selfCollider: Collider2D, otherCollider: Collider2D) {
if (this._hitted) return; if (this._isHit) return;
this._collider.enabled = false; this._collider.enabled = false;
let center = this.node.getWorldPosition(); let center = this.node.getWorldPosition();
let other = otherCollider.node.getWorldPosition(); let other = otherCollider.node.getWorldPosition();
this._flyDirection = center.subtract(other); this._flyDirection = center.subtract(other);
this._flyDirection.normalize(); this._flyDirection.normalize();
this._hitted = true; this._isHit = true;
this._targetColor = this._sprite.color.clone(); this._targetColor = this._sprite.color.clone();
this._targetColor.a = 0; this._targetColor.a = 0;
this._flySpeed = otherCollider.getComponent(RigidBody2D).linearVelocity.length(); this._flySpeed = otherCollider.getComponent(RigidBody2D).linearVelocity.length();
@ -82,14 +82,14 @@ export class ScoreObject extends Component implements IPoolable {
} }
} }
public async reuse() { public async onGet() {
this._spawnAnimation.play(); this._spawnAnimation.play();
await Utilities.delay(this._spawnAnimation.defaultClip.duration * 1000); await Utilities.delay(this._spawnAnimation.defaultClip.duration * 1000);
this._collider.enabled = true; this._collider.enabled = true;
} }
public unuse() { public onRelease() {
this._hitted = false; this._isHit = false;
this.node.angle = 0; this.node.angle = 0;
this.node.setScale(Vec3.ONE); this.node.setScale(Vec3.ONE);
this._sprite.color = this._originColor; this._sprite.color = this._originColor;

View File

@ -5,20 +5,23 @@ import ScoreType from '../Enum/ScoreType';
enum GameEvent { enum GameEvent {
Score, Score,
BallOut, BallOut,
MultiBall,
GameStateChange, GameStateChange,
ScoreObjectRelease, ScoreObjectRelease,
} }
export interface GameEventCallbackMap { export interface GameEventCallbackMap {
[GameEvent.Score]: (type: ScoreType, score: number) => void; [GameEvent.Score]: (score: number, type?: ScoreType) => void;
[GameEvent.BallOut]: () => void; [GameEvent.BallOut]: () => void;
[GameEvent.MultiBall]: (active: boolean) => void;
[GameEvent.GameStateChange]: (state: GameState) => void; [GameEvent.GameStateChange]: (state: GameState) => void;
[GameEvent.ScoreObjectRelease]: (obj: Node) => void; [GameEvent.ScoreObjectRelease]: (obj: Node) => void;
} }
export interface GameEventArgMap { export interface GameEventArgMap {
[GameEvent.Score]: [ScoreType, number]; [GameEvent.Score]: [number, ScoreType];
[GameEvent.BallOut]: null; [GameEvent.BallOut]: null;
[GameEvent.MultiBall]: boolean;
[GameEvent.GameStateChange]: GameState; [GameEvent.GameStateChange]: GameState;
[GameEvent.ScoreObjectRelease]: Node; [GameEvent.ScoreObjectRelease]: Node;
} }

View File

@ -1,6 +1,6 @@
import { _decorator, CCInteger, Collider2D, Component, Contact2DType, EventHandler, tween, Vec2 } from 'cc'; import { _decorator, CCInteger, Collider2D, Component, Contact2DType, EventHandler, tween, Vec2 } from 'cc';
import { Ball } from '../Gameplay/Ball'; import { Ball } from './Ball';
import Utilities from '../Utilities/Utilities'; import Utilities from '../Utilities';
const { ccclass, property } = _decorator; const { ccclass, property } = _decorator;
@ccclass('Cannon') @ccclass('Cannon')

View File

@ -2,7 +2,7 @@
"ver": "4.0.23", "ver": "4.0.23",
"importer": "typescript", "importer": "typescript",
"imported": true, "imported": true,
"uuid": "bbe59da3-d216-484e-8c9e-de512aca245a", "uuid": "ba9083ce-8b19-4c6c-98bd-de3a9c918c2e",
"files": [], "files": [],
"subMetas": {}, "subMetas": {},
"userData": {} "userData": {}

View File

@ -0,0 +1,118 @@
import {
_decorator,
CCFloat,
CCInteger,
Component,
geometry,
math,
Node,
Vec3,
tween,
Collider2D,
Sprite,
Contact2DType,
} from 'cc';
import { EventManger } from '../Manager/EventManger';
import GameEvent from '../Events/GameEvent';
import ScoreType from '../Enum/ScoreType';
const { ccclass, property } = _decorator;
@ccclass('Enemy')
export class Enemy extends Component {
@property({ type: Collider2D, visible: true })
private _collider: Collider2D;
@property({ type: Sprite, visible: true })
private _sprite: Sprite;
@property({ type: Node, visible: true })
private _patrolPoint1: Node;
@property({ type: Node, visible: true })
private _patrolPoint2: Node;
@property({ type: CCFloat, visible: true })
private _speed = 100;
@property({ type: CCInteger, visible: true })
private _requireGoal = 1;
@property({ visible: true })
private _curveY = false;
@property({ type: geometry.AnimationCurve, visible: true })
private _patrolCurve: geometry.AnimationCurve = new geometry.AnimationCurve();
@property({ type: CCFloat, visible: true })
private _multiplierCurve = 100;
private x: number;
private y: number;
private _distance: number;
private _processDistance = 0;
private _direction = 1;
private _isActive = false;
private _currentGoal = 0;
protected onLoad(): void {
EventManger.instance.on(GameEvent.Score, this.onScore, this);
this._collider.on(Contact2DType.BEGIN_CONTACT, this.onBeginContact, this);
}
protected async start() {
this._collider.node.setWorldPosition(this._patrolPoint1.worldPosition);
const pos = this._patrolPoint1.getWorldPosition();
this.x = pos.x;
this.y = pos.y;
this._distance = Math.abs(this._patrolPoint2.worldPosition.x - this.x);
this._direction = this._patrolPoint1.worldPosition.x < this._patrolPoint2.worldPosition.x ? 1 : -1;
this._collider.node.active = false;
}
protected update(dt: number): void {
if (!this._isActive) return;
if (this._curveY) {
this._processDistance += this._speed * dt;
this._processDistance = math.clamp(this._processDistance, 0, this._distance);
const process = math.clamp01(this._processDistance / this._distance);
this.x += this._speed * dt * this._direction;
this.y = this._patrolPoint1.worldPosition.y + this._patrolCurve.evaluate(process) * this._multiplierCurve;
} else {
const dir = new Vec3();
Vec3.subtract(dir, this._patrolPoint2.worldPosition, this._patrolPoint1.worldPosition);
dir.multiplyScalar(this._direction).normalize();
this._processDistance += dir.x * this._speed * dt * this._direction;
this._processDistance = math.clamp(this._processDistance, 0, this._distance);
this.x += dir.x * this._speed * dt;
this.y += dir.y * this._speed * dt;
this.y = math.clamp(this.y, this._patrolPoint1.worldPosition.y, this._patrolPoint2.worldPosition.y);
}
this.x = math.clamp(this.x, this._patrolPoint1.worldPosition.x, this._patrolPoint2.worldPosition.x);
this._collider.node.setWorldPosition(new Vec3(this.x, this.y));
if (this._processDistance == this._distance) {
this._direction *= -1;
this._processDistance = 0;
}
}
private onBeginContact(self: Collider2D, other: Collider2D) {
this._sprite.node.setScale(Vec3.ONE);
tween(this._sprite.node.scale)
.to(0.1, new Vec3(1.2, 1.2), { easing: 'backInOut' })
.to(0.5, Vec3.ONE, { easing: 'backOut' })
.start();
}
private onScore(score: number, type: ScoreType) {
if (type == ScoreType.Goal) {
this._currentGoal++;
if (this._currentGoal == this._requireGoal) {
this._sprite.node.setScale(Vec3.ZERO);
this._collider.node.active = true;
tween(this._sprite.node.scale)
.delay(1)
.to(0.5, Vec3.ONE, {
easing: 'backOut',
onComplete: () => {
this._isActive = true;
},
})
.start();
}
}
}
}

View File

@ -2,7 +2,7 @@
"ver": "4.0.23", "ver": "4.0.23",
"importer": "typescript", "importer": "typescript",
"imported": true, "imported": true,
"uuid": "73cbd9b6-9959-43b8-8ee3-35c54f5fac3f", "uuid": "c394b738-05e4-418d-a047-2b3df4d486aa",
"files": [], "files": [],
"subMetas": {}, "subMetas": {},
"userData": {} "userData": {}

View File

@ -2,7 +2,7 @@
"ver": "4.0.23", "ver": "4.0.23",
"importer": "typescript", "importer": "typescript",
"imported": true, "imported": true,
"uuid": "2162ade9-5adb-492a-8bef-92f81aef908c", "uuid": "db6268f6-8d6d-4e9f-a908-f0c63885d157",
"files": [], "files": [],
"subMetas": {}, "subMetas": {},
"userData": {} "userData": {}

View File

@ -1,8 +1,8 @@
import { _decorator, CCInteger, Collider2D, Component, Contact2DType, Node, RigidBody2D } from 'cc'; import { _decorator, CCInteger, Collider2D, Component, Contact2DType, Node, RigidBody2D } from 'cc';
import { GameManager } from '../Manager/GameManager'; import { GameManager } from '../Manager/GameManager';
import Utilities from '../Utilities';
import ObjectPool from '../Pool/ObjectPool'; import ObjectPool from '../Pool/ObjectPool';
import Utilities from '../Utilities/Utilities'; import { Ball } from './Ball';
import { Ball } from '../Gameplay/Ball';
const { ccclass, property, float } = _decorator; const { ccclass, property, float } = _decorator;
@ccclass('Goal') @ccclass('Goal')
@ -19,10 +19,10 @@ export class Goal extends Component {
private async onContactBegin(selfCollider: Collider2D, otherCollider: Collider2D) { private async onContactBegin(selfCollider: Collider2D, otherCollider: Collider2D) {
const ball = otherCollider.getComponent(Ball); const ball = otherCollider.getComponent(Ball);
if (ball) { if (ball) {
GameManager.instance.goal(this._score, otherCollider.node.getWorldPosition()); GameManager.instance.goal(this._score, ball.node.getWorldPosition());
ball.setActiveRigi(false); ball.setActiveRigi(false);
await Utilities.delay(1000); await Utilities.delay(1000);
ObjectPool.release(otherCollider.node); ObjectPool.release(ball.node);
} }
} }
} }

View File

@ -2,7 +2,7 @@
"ver": "4.0.23", "ver": "4.0.23",
"importer": "typescript", "importer": "typescript",
"imported": true, "imported": true,
"uuid": "4aff560e-243a-45dd-99f1-c35c3f3ac982", "uuid": "5339a157-2cf5-421d-aaa9-6c77cd05ac9d",
"files": [], "files": [],
"subMetas": {}, "subMetas": {},
"userData": {} "userData": {}

View File

@ -0,0 +1,45 @@
import { _decorator, Collider2D, Component, Contact2DType, Vec2, Node } from 'cc';
import { GameManager } from '../Manager/GameManager';
import Utilities from '../Utilities';
import { Ball } from './Ball';
const { ccclass, property } = _decorator;
@ccclass('MultiBall')
export class MultiBall extends Component {
@property({ type: Collider2D, visible: true })
private _collider: Collider2D;
@property({ type: Node, visible: true })
private _portLeft;
@property({ type: Node, visible: true })
private _portRight;
private originBall: Ball;
private trigged = false;
protected onLoad(): void {
this._collider.on(Contact2DType.BEGIN_CONTACT, this.onBeginContact, this);
}
protected lateUpdate(dt: number): void {
if (this.trigged) {
const ball1 = this.originBall;
const ball2 = GameManager.instance.spawnBall(false);
ball1.node.setWorldPosition(this._portRight.worldPosition);
ball1.addForce(new Vec2(10, 0));
ball2.node.setWorldPosition(this._portLeft.worldPosition);
ball2.addForce(new Vec2(-10, 0));
this.trigged = false;
}
}
private async onBeginContact(selfCollider: Collider2D, otherCollider: Collider2D) {
if (this.trigged) return;
this._collider.enabled = false;
this.originBall = otherCollider.getComponent(Ball);
this.trigged = true;
await Utilities.delay(500);
this._collider.enabled = true;
}
}

View File

@ -0,0 +1,9 @@
{
"ver": "4.0.23",
"importer": "typescript",
"imported": true,
"uuid": "02952a26-2842-48a0-af34-f4997260add9",
"files": [],
"subMetas": {},
"userData": {}
}

View File

@ -2,7 +2,7 @@
"ver": "1.1.0", "ver": "1.1.0",
"importer": "directory", "importer": "directory",
"imported": true, "imported": true,
"uuid": "8a40230e-4ec0-4996-91d6-ea77c9a2f5a5", "uuid": "7ccc8c31-3541-418f-98a0-c2b46990d9d2",
"files": [], "files": [],
"subMetas": {}, "subMetas": {},
"userData": { "userData": {

View File

@ -23,7 +23,7 @@ import IPoolable from '../Pool/IPoolable';
import { SoundManager } from '../Manager/SoundManager'; import { SoundManager } from '../Manager/SoundManager';
import PhysicsGroup from '../Enum/PhysicGroup'; import PhysicsGroup from '../Enum/PhysicGroup';
import ObjectPool from '../Pool/ObjectPool'; import ObjectPool from '../Pool/ObjectPool';
import Utilities from '../Utilities/Utilities'; import Utilities from '../Utilities';
const { ccclass, property } = _decorator; const { ccclass, property } = _decorator;
@ccclass('Ball') @ccclass('Ball')
@ -33,7 +33,7 @@ export class Ball extends Component implements IPoolable {
@property({ type: CCFloat, visible: true }) @property({ type: CCFloat, visible: true })
private _maxSpeed: number; private _maxSpeed: number;
@property({ type: RigidBody2D, visible: true }) @property({ type: RigidBody2D, visible: true })
private _rigidbody: RigidBody2D; private _rigidBody: RigidBody2D;
@property({ type: Node, visible: true }) @property({ type: Node, visible: true })
private _sprite: Node; private _sprite: Node;
@property({ type: ParticleSystem, visible: true }) @property({ type: ParticleSystem, visible: true })
@ -46,7 +46,7 @@ export class Ball extends Component implements IPoolable {
private _jumpCurve: geometry.AnimationCurve = new geometry.AnimationCurve(); private _jumpCurve: geometry.AnimationCurve = new geometry.AnimationCurve();
private _impactPool: ObjectPool; private _impactPool: ObjectPool;
private _hitted = false; private _isHit = false;
private _isJumping = false; private _isJumping = false;
private _jumpTime: number; private _jumpTime: number;
private _jumpDuration: number; private _jumpDuration: number;
@ -79,7 +79,7 @@ export class Ball extends Component implements IPoolable {
this._trail.trailModule.widthRatio.multiplier = 1; this._trail.trailModule.widthRatio.multiplier = 1;
this._isJumping = false; this._isJumping = false;
this._collider.group = PhysicsGroup.BALL; this._collider.group = PhysicsGroup.BALL;
this._rigidbody.group = PhysicsGroup.BALL; this._rigidBody.group = PhysicsGroup.BALL;
} }
} }
} }
@ -89,9 +89,11 @@ export class Ball extends Component implements IPoolable {
otherCollider: Collider2D, otherCollider: Collider2D,
contact: IPhysics2DContact | null, contact: IPhysics2DContact | null,
) { ) {
if (this._hitted) return; if (this._isHit) return;
this._hitted = true; this._isHit = true;
if (this._rigidbody.linearVelocity.length() >= 3) { console.log(contact.getTangentSpeed());
if (this._rigidBody.linearVelocity.length() >= 5) {
let hitPoint = contact.getWorldManifold().points[0]; let hitPoint = contact.getWorldManifold().points[0];
if (!hitPoint) { if (!hitPoint) {
const dir = otherCollider.node const dir = otherCollider.node
@ -102,54 +104,54 @@ export class Ball extends Component implements IPoolable {
const point = selfCollider.node.getWorldPosition().add(dir); const point = selfCollider.node.getWorldPosition().add(dir);
hitPoint = new Vec2(point.x, point.y); hitPoint = new Vec2(point.x, point.y);
} }
const hitfx = this._impactPool.get(this.node.parent, ParticleSystem); const hitFx = this._impactPool.get(this.node.parent, ParticleSystem);
hitfx.node.setWorldPosition(new Vec3(hitPoint.x, hitPoint.y, 10)); hitFx.node.setWorldPosition(new Vec3(hitPoint.x, hitPoint.y, 10));
hitfx.play(); hitFx.play();
SoundManager.instance.playSfx(this._hitSound); SoundManager.instance.playSfx(this._hitSound);
await Utilities.waitUntil(() => hitfx.isStopped, 100); await Utilities.waitUntil(() => hitFx.isStopped, 100);
this._impactPool.release(hitfx.node); this._impactPool.release(hitFx.node);
} }
} }
private onEndContact(selfCollider: Collider2D, otherCollider: Collider2D, contact: IPhysics2DContact | null) { private onEndContact(selfCollider: Collider2D, otherCollider: Collider2D, contact: IPhysics2DContact | null) {
this._hitted = false; this._isHit = false;
} }
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);
} }
} }
public addFocre(force: Vec2) { public addForce(force: Vec2) {
this._rigidbody.applyLinearImpulseToCenter(force, true); this._rigidBody.applyLinearImpulseToCenter(force, true);
} }
public throwBall(force: Vec2) { public throwBall(force: Vec2) {
this._collider.group = PhysicsGroup.BALLTHROWING; this._collider.group = PhysicsGroup.BALL_THROWING;
this._rigidbody.group = PhysicsGroup.BALLTHROWING; this._rigidBody.group = PhysicsGroup.BALL_THROWING;
this._rigidbody.applyLinearImpulseToCenter(force, true); this._rigidBody.applyLinearImpulseToCenter(force, true);
this._isJumping = true; this._isJumping = true;
this._jumpTime = 0; this._jumpTime = 0;
this._jumpDuration = this._rigidbody.linearVelocity.length() * 0.05; this._jumpDuration = this._rigidBody.linearVelocity.length() * 0.05;
} }
public setActiveRigi(value: boolean) { public setActiveRigi(value: boolean) {
this._rigidbody.enabled = value; this._rigidBody.enabled = value;
if (!value) { if (!value) {
this._rigidbody.linearVelocity = Vec2.ZERO.clone(); this._rigidBody.linearVelocity = Vec2.ZERO.clone();
this._rigidbody.angularVelocity = 0; this._rigidBody.angularVelocity = 0;
} }
} }
reuse() { onGet() {
this._isJumping = false; this._isJumping = false;
this._hitted = false; this._isHit = false;
this._rigidbody.enabled = true; this._rigidBody.enabled = true;
} }
unuse() { onRelease() {
this._rigidbody.linearVelocity = Vec2.ZERO.clone(); this._rigidBody.linearVelocity = Vec2.ZERO.clone();
this._rigidbody.angularVelocity = 0; this._rigidBody.angularVelocity = 0;
} }
} }

View File

@ -2,7 +2,7 @@
"ver": "4.0.23", "ver": "4.0.23",
"importer": "typescript", "importer": "typescript",
"imported": true, "imported": true,
"uuid": "b14f8356-cd12-4334-bf5e-45f3e10f1dc6", "uuid": "4630a499-ab09-45a9-be81-52dae28beb55",
"files": [], "files": [],
"subMetas": {}, "subMetas": {},
"userData": {} "userData": {}

View File

@ -2,7 +2,7 @@
"ver": "4.0.23", "ver": "4.0.23",
"importer": "typescript", "importer": "typescript",
"imported": true, "imported": true,
"uuid": "3bf75aec-53f8-41b1-b490-e0ae7bdf9798", "uuid": "87072b4f-2c3c-48b0-86a9-7d1dc17a750e",
"files": [], "files": [],
"subMetas": {}, "subMetas": {},
"userData": {} "userData": {}

View File

@ -2,7 +2,7 @@
"ver": "4.0.23", "ver": "4.0.23",
"importer": "typescript", "importer": "typescript",
"imported": true, "imported": true,
"uuid": "dabd58dc-7708-4931-ad63-cd7875b7b5df", "uuid": "bbe27534-d4c2-4d1c-bd39-07c2605e319c",
"files": [], "files": [],
"subMetas": {}, "subMetas": {},
"userData": {} "userData": {}

View File

@ -1,47 +0,0 @@
import { _decorator, Component, Node, Tween, tween, TweenSystem } from 'cc';
const { ccclass, property, float } = _decorator;
@ccclass('TweenPath')
export class TweenPath extends Component {
@property(Node)
private target: Node;
@property([Node])
private waypoints: Node[] = [];
@property(Node)
private startPoint: Node;
@float
private duration = 2;
private tweenPath: Tween<Node>;
protected onEnable(): void {
this.startFollow(1);
}
protected onDisable(): void {
this.stopFollow();
}
private followPath(duration: number) {
this.tweenPath = tween(this.target);
for (let i = 0; i < this.waypoints.length; i++) {
this.tweenPath.to(duration, {
position: this.waypoints[i].getPosition(),
});
}
// repeatForever method bug: not repeat on completed tween, use repeat(Number.MAX_SAFE_INTEGER, this.tweenPath) instead repeatForever to make infinite loop
this.tweenPath.repeat(Number.MAX_SAFE_INTEGER, this.tweenPath);
this.tweenPath.start();
}
public stopFollow() {
this.tweenPath?.stop();
}
public startFollow(speed: number = 1) {
if (this.waypoints.length > 0) {
this.target.setPosition(this.startPoint?.position || this.waypoints[this.waypoints.length - 1].position);
this.followPath(this.duration / speed);
}
}
}

View File

@ -1,7 +1,7 @@
import { _decorator, Component, Node, Prefab, Vec2, Vec3, randomRangeInt, CCInteger } from 'cc'; import { _decorator, Component, Node, Prefab, Vec2, Vec3, randomRangeInt, CCInteger } 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 Utilities from '../Utilities';
import GameState from '../Enum/GameState'; import GameState from '../Enum/GameState';
import { EventManger } from './EventManger'; import { EventManger } from './EventManger';
import GameEvent from '../Events/GameEvent'; import GameEvent from '../Events/GameEvent';
@ -34,6 +34,12 @@ export class GameManager extends Component {
public highestStreak: number; public highestStreak: number;
private _score = 0; private _score = 0;
private _isMultiBall = false;
private _currentBallInGame = 0;
public get score() {
return this._score;
}
protected onLoad(): void { protected onLoad(): void {
GameManager._instance = this; GameManager._instance = this;
@ -42,7 +48,8 @@ export class GameManager extends Component {
} }
protected start() { protected start() {
this.spawnBall(); this.spawnBall(true);
this.play();
} }
private changeGameState(state: GameState) { private changeGameState(state: GameState) {
@ -54,12 +61,31 @@ export class GameManager extends Component {
this._score += score; this._score += score;
const floatingScore = this._FloatingScorePool.get(this._floatingTextContainer, FloatingText); const floatingScore = this._FloatingScorePool.get(this._floatingTextContainer, FloatingText);
floatingScore.show(`+${score}`, position, score >= 100 ? 1.5 : 1, score >= 100 ? 1 : 0.7); floatingScore.show(`+${score}`, position, score >= 100 ? 1.5 : 1, score >= 100 ? 1 : 0.7);
EventManger.instance.emit(GameEvent.Score, [type, this._score]); EventManger.instance.emit(GameEvent.Score, [this._score, type]);
} }
public spawnBall(): Ball { private setCurrentBallInGame(value: number) {
this._currentBallInGame += value;
if (this._currentBallInGame >= 2) {
if (!this._isMultiBall) {
this._isMultiBall = true;
EventManger.instance.emit(GameEvent.MultiBall, false);
}
}
if (this._currentBallInGame <= 0) {
if (this._isMultiBall) {
this._isMultiBall = false;
EventManger.instance.emit(GameEvent.MultiBall, false);
}
}
}
public spawnBall(throwBall: boolean): Ball {
this.setCurrentBallInGame(1);
const ball = this._ballPool.get(this.node, Ball); const ball = this._ballPool.get(this.node, Ball);
ball.node.setPosition(this._ballSpawnPosition); ball.node.setPosition(this._ballSpawnPosition);
if (!throwBall) return ball;
let dir = randomRangeInt(-1, 2); let dir = randomRangeInt(-1, 2);
while (dir == 0) { while (dir == 0) {
dir = randomRangeInt(-1, 2); dir = randomRangeInt(-1, 2);
@ -70,26 +96,36 @@ export class GameManager extends Component {
} }
public async ballOut() { public async ballOut() {
this.setCurrentBallInGame(-1);
if (this._currentBallInGame <= 0) {
this._balls--; this._balls--;
EventManger.instance.emit(GameEvent.BallOut, null); EventManger.instance.emit(GameEvent.BallOut, null);
if (this._balls === 0) { if (this._balls === 0) {
this._ballPool.clear(); this.changeGameState(GameState.GameOver);
return; return;
} }
await Utilities.delay(1000); await Utilities.delay(1000);
this.spawnBall(); this.spawnBall(true);
}
} }
public async goal(bonusScore: number, position: Vec3) { public async goal(bonusScore: number, position: Vec3) {
this.addScore(bonusScore, ScoreType.Goal, position); this.setCurrentBallInGame(-1);
await Utilities.delay(1000); this.addScore(this._isMultiBall ? bonusScore * 2 : bonusScore, ScoreType.Goal, position);
this.spawnBall(); if (this._currentBallInGame <= 0) {
await Utilities.delay(2000);
this.spawnBall(true);
}
} }
public destroyEnviromentsObject(bonusScore: number, position: Vec3) { public destroyEnviromentsObject(bonusScore: number, position: Vec3) {
this.addScore(bonusScore, ScoreType.DestroyObject, position); this.addScore(bonusScore, ScoreType.DestroyObject, position);
} }
public play() {
this.changeGameState(GameState.Playing);
}
public onRevive() { public onRevive() {
throw new Error('Method not implemented.'); throw new Error('Method not implemented.');
} }

View File

@ -1,4 +1,4 @@
export default interface IPoolable { export default interface IPoolable {
reuse(); onGet();
unuse(); onRelease();
} }

View File

@ -60,7 +60,7 @@ export default class ObjectPool {
// Invoke pool handler // Invoke pool handler
const handler = this._poolHandlerComp ? obj.getComponent(this._poolHandlerComp) : null; const handler = this._poolHandlerComp ? obj.getComponent(this._poolHandlerComp) : null;
if (handler) { if (handler) {
(handler as unknown as IPoolable)?.reuse(); (handler as unknown as IPoolable)?.onGet();
} }
if (classConstructor) { if (classConstructor) {
@ -82,7 +82,7 @@ export default class ObjectPool {
const handler = this._poolHandlerComp ? node.getComponent(this._poolHandlerComp) : null; const handler = this._poolHandlerComp ? node.getComponent(this._poolHandlerComp) : null;
if (handler) { if (handler) {
(handler as unknown as IPoolable)?.unuse(); (handler as unknown as IPoolable)?.onRelease();
} }
// Remove from parent, but don't cleanup // Remove from parent, but don't cleanup
node.removeFromParent(); node.removeFromParent();

View File

@ -1,9 +0,0 @@
{
"ver": "4.0.23",
"importer": "typescript",
"imported": true,
"uuid": "d70404b0-c2fe-4a29-9dcc-8cf6586ec85f",
"files": [],
"subMetas": {},
"userData": {}
}

View File

@ -0,0 +1,9 @@
{
"ver": "4.0.23",
"importer": "typescript",
"imported": true,
"uuid": "7d32e2cc-3de9-4e9a-afb6-d19704ae3f5a",
"files": [],
"subMetas": {},
"userData": {}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 KiB

View File

@ -0,0 +1,134 @@
{
"ver": "1.0.25",
"importer": "image",
"imported": true,
"uuid": "484d60bf-6c5c-4dfc-b5b8-b7d903dfac37",
"files": [
".json",
".png"
],
"subMetas": {
"6c48a": {
"importer": "texture",
"uuid": "484d60bf-6c5c-4dfc-b5b8-b7d903dfac37@6c48a",
"displayName": "Enemy",
"id": "6c48a",
"name": "texture",
"userData": {
"wrapModeS": "clamp-to-edge",
"wrapModeT": "clamp-to-edge",
"imageUuidOrDatabaseUri": "484d60bf-6c5c-4dfc-b5b8-b7d903dfac37",
"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": "484d60bf-6c5c-4dfc-b5b8-b7d903dfac37@f9941",
"displayName": "Enemy",
"id": "f9941",
"name": "spriteFrame",
"userData": {
"trimType": "auto",
"trimThreshold": 1,
"rotated": false,
"offsetX": -0.5,
"offsetY": 0,
"trimX": 5,
"trimY": 4,
"width": 28,
"height": 62,
"rawWidth": 39,
"rawHeight": 70,
"borderTop": 0,
"borderBottom": 0,
"borderLeft": 0,
"borderRight": 0,
"packable": true,
"pixelsToUnit": 100,
"pivotX": 0.5,
"pivotY": 0.5,
"meshType": 0,
"vertices": {
"rawPosition": [
-14,
-31,
0,
14,
-31,
0,
-14,
31,
0,
14,
31,
0
],
"indexes": [
0,
1,
2,
2,
1,
3
],
"uv": [
5,
66,
33,
66,
5,
4,
33,
4
],
"nuv": [
0.1282051282051282,
0.05714285714285714,
0.8461538461538461,
0.05714285714285714,
0.1282051282051282,
0.9428571428571428,
0.8461538461538461,
0.9428571428571428
],
"minPos": [
-14,
-31,
0
],
"maxPos": [
14,
31,
0
]
},
"isUuid": true,
"imageUuidOrDatabaseUri": "484d60bf-6c5c-4dfc-b5b8-b7d903dfac37@6c48a",
"atlasUuid": ""
},
"ver": "1.0.11",
"imported": true,
"files": [
".json"
],
"subMetas": {}
}
},
"userData": {
"type": "sprite-frame",
"fixAlphaTransparencyArtifacts": true,
"hasAlpha": true,
"redirect": "484d60bf-6c5c-4dfc-b5b8-b7d903dfac37@f9941"
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

View File

@ -0,0 +1,134 @@
{
"ver": "1.0.25",
"importer": "image",
"imported": true,
"uuid": "6a4d47ab-64f8-42b2-88e9-3f17c88f90bb",
"files": [
".json",
".png"
],
"subMetas": {
"6c48a": {
"importer": "texture",
"uuid": "6a4d47ab-64f8-42b2-88e9-3f17c88f90bb@6c48a",
"displayName": "Referee",
"id": "6c48a",
"name": "texture",
"userData": {
"wrapModeS": "clamp-to-edge",
"wrapModeT": "clamp-to-edge",
"imageUuidOrDatabaseUri": "6a4d47ab-64f8-42b2-88e9-3f17c88f90bb",
"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": "6a4d47ab-64f8-42b2-88e9-3f17c88f90bb@f9941",
"displayName": "Referee",
"id": "f9941",
"name": "spriteFrame",
"userData": {
"trimType": "auto",
"trimThreshold": 1,
"rotated": false,
"offsetX": -0.5,
"offsetY": 1,
"trimX": 8,
"trimY": 12,
"width": 22,
"height": 44,
"rawWidth": 39,
"rawHeight": 70,
"borderTop": 0,
"borderBottom": 0,
"borderLeft": 0,
"borderRight": 0,
"packable": true,
"pixelsToUnit": 100,
"pivotX": 0.5,
"pivotY": 0.5,
"meshType": 0,
"vertices": {
"rawPosition": [
-11,
-22,
0,
11,
-22,
0,
-11,
22,
0,
11,
22,
0
],
"indexes": [
0,
1,
2,
2,
1,
3
],
"uv": [
8,
58,
30,
58,
8,
14,
30,
14
],
"nuv": [
0.20512820512820512,
0.2,
0.7692307692307693,
0.2,
0.20512820512820512,
0.8285714285714286,
0.7692307692307693,
0.8285714285714286
],
"minPos": [
-11,
-22,
0
],
"maxPos": [
11,
22,
0
]
},
"isUuid": true,
"imageUuidOrDatabaseUri": "6a4d47ab-64f8-42b2-88e9-3f17c88f90bb@6c48a",
"atlasUuid": ""
},
"ver": "1.0.11",
"imported": true,
"files": [
".json"
],
"subMetas": {}
}
},
"userData": {
"type": "sprite-frame",
"fixAlphaTransparencyArtifacts": true,
"hasAlpha": true,
"redirect": "6a4d47ab-64f8-42b2-88e9-3f17c88f90bb@f9941"
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 222 KiB

After

Width:  |  Height:  |  Size: 66 KiB

View File

@ -2,7 +2,7 @@
"ver": "1.0.25", "ver": "1.0.25",
"importer": "image", "importer": "image",
"imported": true, "imported": true,
"uuid": "12b8f875-a7c7-4af5-91be-6aac2e7547be", "uuid": "3edb092d-e894-4a3f-8a19-d1dcb1c80ff8",
"files": [ "files": [
".json", ".json",
".png" ".png"
@ -10,14 +10,14 @@
"subMetas": { "subMetas": {
"6c48a": { "6c48a": {
"importer": "texture", "importer": "texture",
"uuid": "12b8f875-a7c7-4af5-91be-6aac2e7547be@6c48a", "uuid": "3edb092d-e894-4a3f-8a19-d1dcb1c80ff8@6c48a",
"displayName": "goal", "displayName": "Goal",
"id": "6c48a", "id": "6c48a",
"name": "texture", "name": "texture",
"userData": { "userData": {
"wrapModeS": "clamp-to-edge", "wrapModeS": "clamp-to-edge",
"wrapModeT": "clamp-to-edge", "wrapModeT": "clamp-to-edge",
"imageUuidOrDatabaseUri": "12b8f875-a7c7-4af5-91be-6aac2e7547be", "imageUuidOrDatabaseUri": "3edb092d-e894-4a3f-8a19-d1dcb1c80ff8",
"isUuid": true, "isUuid": true,
"visible": false, "visible": false,
"minfilter": "linear", "minfilter": "linear",
@ -34,22 +34,22 @@
}, },
"f9941": { "f9941": {
"importer": "sprite-frame", "importer": "sprite-frame",
"uuid": "12b8f875-a7c7-4af5-91be-6aac2e7547be@f9941", "uuid": "3edb092d-e894-4a3f-8a19-d1dcb1c80ff8@f9941",
"displayName": "goal", "displayName": "Goal",
"id": "f9941", "id": "f9941",
"name": "spriteFrame", "name": "spriteFrame",
"userData": { "userData": {
"trimType": "auto", "trimType": "auto",
"trimThreshold": 1, "trimThreshold": 1,
"rotated": false, "rotated": false,
"offsetX": 0, "offsetX": -0.5,
"offsetY": 0, "offsetY": 0.5,
"trimX": 0, "trimX": 15,
"trimY": 0, "trimY": 26,
"width": 2304, "width": 269,
"height": 1469, "height": 147,
"rawWidth": 2304, "rawWidth": 300,
"rawHeight": 1469, "rawHeight": 200,
"borderTop": 0, "borderTop": 0,
"borderBottom": 0, "borderBottom": 0,
"borderLeft": 0, "borderLeft": 0,
@ -61,17 +61,17 @@
"meshType": 0, "meshType": 0,
"vertices": { "vertices": {
"rawPosition": [ "rawPosition": [
-1152, -134.5,
-734.5, -73.5,
0, 0,
1152, 134.5,
-734.5, -73.5,
0, 0,
-1152, -134.5,
734.5, 73.5,
0, 0,
1152, 134.5,
734.5, 73.5,
0 0
], ],
"indexes": [ "indexes": [
@ -83,38 +83,38 @@
3 3
], ],
"uv": [ "uv": [
0, 15,
1469, 174,
2304, 284,
1469, 174,
0, 15,
0, 27,
2304, 284,
0 27
], ],
"nuv": [ "nuv": [
0, 0.05,
0, 0.135,
1, 0.9466666666666667,
0, 0.135,
0, 0.05,
1, 0.87,
1, 0.9466666666666667,
1 0.87
], ],
"minPos": [ "minPos": [
-1152, -134.5,
-734.5, -73.5,
0 0
], ],
"maxPos": [ "maxPos": [
1152, 134.5,
734.5, 73.5,
0 0
] ]
}, },
"isUuid": true, "isUuid": true,
"imageUuidOrDatabaseUri": "12b8f875-a7c7-4af5-91be-6aac2e7547be@6c48a", "imageUuidOrDatabaseUri": "3edb092d-e894-4a3f-8a19-d1dcb1c80ff8@6c48a",
"atlasUuid": "" "atlasUuid": ""
}, },
"ver": "1.0.11", "ver": "1.0.11",
@ -129,6 +129,6 @@
"type": "sprite-frame", "type": "sprite-frame",
"fixAlphaTransparencyArtifacts": true, "fixAlphaTransparencyArtifacts": true,
"hasAlpha": true, "hasAlpha": true,
"redirect": "12b8f875-a7c7-4af5-91be-6aac2e7547be@f9941" "redirect": "3edb092d-e894-4a3f-8a19-d1dcb1c80ff8@f9941"
} }
} }

View File

@ -74,7 +74,7 @@
"_value": false "_value": false
}, },
"geometry-renderer": { "geometry-renderer": {
"_value": true "_value": false
}, },
"debug-renderer": { "debug-renderer": {
"_value": true "_value": true
@ -104,16 +104,16 @@
"_value": false "_value": false
}, },
"light-probe": { "light-probe": {
"_value": true "_value": false
}, },
"tiled-map": { "tiled-map": {
"_value": true "_value": true
}, },
"spine": { "spine": {
"_value": true "_value": false
}, },
"dragon-bones": { "dragon-bones": {
"_value": true "_value": false
}, },
"marionette": { "marionette": {
"_value": false "_value": false
@ -129,17 +129,13 @@
"audio", "audio",
"base", "base",
"debug-renderer", "debug-renderer",
"dragon-bones",
"geometry-renderer",
"gfx-webgl", "gfx-webgl",
"gfx-webgl2", "gfx-webgl2",
"intersection-2d", "intersection-2d",
"light-probe",
"particle", "particle",
"particle-2d", "particle-2d",
"physics-2d-box2d", "physics-2d-box2d",
"profiler", "profiler",
"spine",
"tiled-map", "tiled-map",
"tween", "tween",
"ui", "ui",

View File

@ -29,14 +29,19 @@
{ {
"index": 4, "index": 4,
"name": "BORDER" "name": "BORDER"
},
{
"index": 5,
"name": "ENEMY"
} }
], ],
"collisionMatrix": { "collisionMatrix": {
"0": 21, "0": 21,
"1": 4, "1": 4,
"2": 23, "2": 55,
"3": 16, "3": 16,
"4": 29 "4": 29,
"5": 4
} }
}, },
"custom_joint_texture_layouts": [], "custom_joint_texture_layouts": [],