2024-02-28 03:25:11 -08:00
|
|
|
import {
|
|
|
|
_decorator,
|
2024-03-06 10:08:30 -08:00
|
|
|
AudioClip,
|
2024-02-28 03:25:11 -08:00
|
|
|
CCFloat,
|
|
|
|
Collider2D,
|
|
|
|
Component,
|
|
|
|
Contact2DType,
|
|
|
|
Director,
|
|
|
|
director,
|
|
|
|
EventTarget,
|
|
|
|
IPhysics2DContact,
|
|
|
|
RigidBody2D,
|
2024-03-06 10:08:30 -08:00
|
|
|
Vec2,
|
2024-03-07 03:15:08 -08:00
|
|
|
geometry,
|
|
|
|
math,
|
|
|
|
Vec3,
|
|
|
|
ParticleSystem,
|
|
|
|
Prefab,
|
|
|
|
CircleCollider2D,
|
2024-03-21 01:59:08 -07:00
|
|
|
Animation,
|
|
|
|
Sprite,
|
2024-04-03 20:20:56 -07:00
|
|
|
RealCurve,
|
2024-02-28 03:25:11 -08:00
|
|
|
} from 'cc';
|
2024-03-06 07:10:31 -08:00
|
|
|
import IPoolable from '../Pool/IPoolable';
|
2024-03-06 10:08:30 -08:00
|
|
|
import { SoundManager } from '../Manager/SoundManager';
|
2024-03-07 03:15:08 -08:00
|
|
|
import PhysicsGroup from '../Enum/PhysicGroup';
|
|
|
|
import ObjectPool from '../Pool/ObjectPool';
|
2024-03-10 03:12:55 -07:00
|
|
|
import Utilities from '../Utilities';
|
2024-03-28 20:35:44 -07:00
|
|
|
import { EventManger } from '../Manager/EventManger';
|
|
|
|
import GameEvent from '../Events/GameEvent';
|
2024-02-27 18:19:33 -08:00
|
|
|
const { ccclass, property } = _decorator;
|
|
|
|
|
|
|
|
@ccclass('Ball')
|
2024-03-06 07:10:31 -08:00
|
|
|
export class Ball extends Component implements IPoolable {
|
2024-03-07 03:15:08 -08:00
|
|
|
@property({ type: Prefab, visible: true })
|
|
|
|
private _impactPrefab: Prefab;
|
2024-03-06 10:08:30 -08:00
|
|
|
@property({ type: CCFloat, visible: true })
|
|
|
|
private _maxSpeed: number;
|
|
|
|
@property({ type: RigidBody2D, visible: true })
|
2024-03-10 03:12:55 -07:00
|
|
|
private _rigidBody: RigidBody2D;
|
2024-04-03 02:43:18 -07:00
|
|
|
|
2024-03-21 01:59:08 -07:00
|
|
|
@property({ type: Sprite, visible: true })
|
|
|
|
private _sprite: Sprite;
|
|
|
|
@property({ type: Sprite, visible: true })
|
|
|
|
private _spriteShadow: Sprite;
|
2024-04-03 02:43:18 -07:00
|
|
|
|
2024-03-21 01:59:08 -07:00
|
|
|
@property({ type: Animation, visible: true })
|
|
|
|
private _animation: Animation;
|
2024-03-07 03:15:08 -08:00
|
|
|
@property({ type: ParticleSystem, visible: true })
|
|
|
|
private _trail: ParticleSystem;
|
2024-03-21 01:59:08 -07:00
|
|
|
@property({ type: ParticleSystem, visible: true })
|
|
|
|
private _buffParticle: ParticleSystem;
|
2024-03-28 20:35:44 -07:00
|
|
|
@property({ type: ParticleSystem, visible: true })
|
|
|
|
private _boosterParticle: ParticleSystem;
|
2024-03-07 03:15:08 -08:00
|
|
|
@property({ type: CircleCollider2D, visible: true })
|
|
|
|
private _collider: CircleCollider2D;
|
2024-04-03 02:43:18 -07:00
|
|
|
|
2024-03-06 10:08:30 -08:00
|
|
|
@property({ type: AudioClip, visible: true })
|
|
|
|
private _hitSound: AudioClip;
|
2024-03-10 20:46:50 -07:00
|
|
|
@property({ type: AudioClip, visible: true })
|
2024-04-03 02:43:18 -07:00
|
|
|
private _hitFlipperSound: AudioClip;
|
|
|
|
|
2024-03-07 03:15:08 -08:00
|
|
|
@property({ type: geometry.AnimationCurve, visible: true })
|
|
|
|
private _jumpCurve: geometry.AnimationCurve = new geometry.AnimationCurve();
|
2024-03-06 10:08:30 -08:00
|
|
|
|
2024-03-07 03:15:08 -08:00
|
|
|
private _impactPool: ObjectPool;
|
2024-03-10 03:12:55 -07:00
|
|
|
private _isHit = false;
|
2024-03-07 03:15:08 -08:00
|
|
|
private _isJumping = false;
|
|
|
|
private _jumpTime: number;
|
|
|
|
private _jumpDuration: number;
|
2024-02-27 18:19:33 -08:00
|
|
|
|
|
|
|
public eventHitObstacle = new EventTarget();
|
|
|
|
public eventGoal = new EventTarget();
|
|
|
|
|
2024-03-28 20:35:44 -07:00
|
|
|
public init(boosterActive: boolean) {
|
|
|
|
if (boosterActive) this._boosterParticle.play();
|
|
|
|
else this._boosterParticle.stop();
|
|
|
|
}
|
|
|
|
|
2024-02-28 03:25:11 -08:00
|
|
|
protected onLoad(): void {
|
2024-03-06 10:08:30 -08:00
|
|
|
if (this._collider) {
|
|
|
|
this._collider.on(Contact2DType.BEGIN_CONTACT, this.onBeginContact, this);
|
|
|
|
this._collider.on(Contact2DType.END_CONTACT, this.onEndContact, this);
|
2024-02-27 18:19:33 -08:00
|
|
|
}
|
2024-02-28 03:25:11 -08:00
|
|
|
director.on(Director.EVENT_AFTER_PHYSICS, this.setMaxVelocity, this);
|
2024-03-28 20:35:44 -07:00
|
|
|
this._impactPool = new ObjectPool(this._impactPrefab, 10, false);
|
|
|
|
|
|
|
|
EventManger.instance.on(GameEvent.BoosterActive, this.onBoosterActive, this);
|
|
|
|
EventManger.instance.on(GameEvent.BoosterDisable, this.onBoosterDisable, this);
|
2024-03-07 03:15:08 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
protected update(dt: number): void {
|
|
|
|
if (this._isJumping) {
|
|
|
|
this._jumpTime += dt;
|
|
|
|
let jumpProcess = this._jumpTime / this._jumpDuration;
|
|
|
|
jumpProcess = math.clamp01(jumpProcess);
|
|
|
|
let scale = Vec3.ONE.clone();
|
2024-03-21 01:59:08 -07:00
|
|
|
const jumpValue = this._jumpCurve.evaluate(jumpProcess);
|
|
|
|
scale = scale.add(Vec3.ONE.clone().multiplyScalar(jumpValue));
|
|
|
|
this._sprite.node.setScale(scale);
|
|
|
|
this._spriteShadow.node.setScale(scale);
|
2024-03-07 03:15:08 -08:00
|
|
|
this._trail.trailModule.widthRatio.multiplier = scale.x;
|
2024-03-21 01:59:08 -07:00
|
|
|
this._spriteShadow.node.setWorldPosition(
|
|
|
|
this.node.worldPosition.clone().add(Vec3.ONE.clone().multiplyScalar(-jumpValue * 100)),
|
|
|
|
);
|
2024-03-07 03:15:08 -08:00
|
|
|
|
|
|
|
if (jumpProcess >= 1) {
|
2024-03-21 01:59:08 -07:00
|
|
|
this._spriteShadow.node.setPosition(Vec3.ZERO);
|
|
|
|
this._sprite.node.setScale(Vec3.ONE);
|
2024-03-07 03:15:08 -08:00
|
|
|
this._trail.trailModule.widthRatio.multiplier = 1;
|
|
|
|
this._isJumping = false;
|
|
|
|
this._collider.group = PhysicsGroup.BALL;
|
2024-03-10 03:12:55 -07:00
|
|
|
this._rigidBody.group = PhysicsGroup.BALL;
|
2024-03-07 03:15:08 -08:00
|
|
|
}
|
|
|
|
}
|
2024-02-27 18:19:33 -08:00
|
|
|
}
|
|
|
|
|
2024-03-07 09:45:13 -08:00
|
|
|
private async onBeginContact(
|
|
|
|
selfCollider: Collider2D,
|
|
|
|
otherCollider: Collider2D,
|
|
|
|
contact: IPhysics2DContact | null,
|
|
|
|
) {
|
2024-03-10 03:12:55 -07:00
|
|
|
if (this._isHit) return;
|
|
|
|
this._isHit = true;
|
2024-03-28 20:35:44 -07:00
|
|
|
const velocity = this._rigidBody.linearVelocity.length();
|
|
|
|
if (!otherCollider.sensor && velocity >= 5) {
|
2024-03-21 01:59:08 -07:00
|
|
|
this._animation.play();
|
2024-03-07 03:15:08 -08:00
|
|
|
let hitPoint = contact.getWorldManifold().points[0];
|
2024-03-21 01:59:08 -07:00
|
|
|
|
2024-03-07 03:15:08 -08:00
|
|
|
if (!hitPoint) {
|
|
|
|
const dir = otherCollider.node
|
|
|
|
.getWorldPosition()
|
|
|
|
.subtract(selfCollider.node.getWorldPosition())
|
|
|
|
.normalize();
|
|
|
|
dir.multiplyScalar(this._collider.radius / 2);
|
|
|
|
const point = selfCollider.node.getWorldPosition().add(dir);
|
|
|
|
hitPoint = new Vec2(point.x, point.y);
|
|
|
|
}
|
2024-04-03 02:43:18 -07:00
|
|
|
const hitFx = this._impactPool.get(ParticleSystem, this.node.parent);
|
2024-03-10 03:12:55 -07:00
|
|
|
hitFx.node.setWorldPosition(new Vec3(hitPoint.x, hitPoint.y, 10));
|
2024-04-03 02:43:18 -07:00
|
|
|
SoundManager.instance.playSfx(
|
|
|
|
otherCollider.group == PhysicsGroup.FLIPPER ? this._hitFlipperSound : this._hitSound,
|
|
|
|
);
|
2024-03-21 01:59:08 -07:00
|
|
|
await Utilities.waitUntil(() => hitFx.isStopped, 0.1);
|
2024-04-03 02:43:18 -07:00
|
|
|
this._impactPool.release(hitFx);
|
2024-03-06 10:08:30 -08:00
|
|
|
}
|
|
|
|
}
|
2024-02-28 03:25:11 -08:00
|
|
|
|
2024-03-07 03:15:08 -08:00
|
|
|
private onEndContact(selfCollider: Collider2D, otherCollider: Collider2D, contact: IPhysics2DContact | null) {
|
2024-03-10 03:12:55 -07:00
|
|
|
this._isHit = false;
|
2024-03-07 03:15:08 -08:00
|
|
|
}
|
|
|
|
|
2024-03-28 20:35:44 -07:00
|
|
|
private onBoosterActive() {
|
|
|
|
this._boosterParticle.play();
|
|
|
|
}
|
|
|
|
|
|
|
|
private onBoosterDisable() {
|
|
|
|
this._boosterParticle.stop();
|
|
|
|
}
|
|
|
|
|
2024-02-28 03:25:11 -08:00
|
|
|
private setMaxVelocity() {
|
2024-03-10 03:12:55 -07:00
|
|
|
if (this._rigidBody.linearVelocity.length() > this._maxSpeed) {
|
|
|
|
this._rigidBody.linearVelocity = this._rigidBody.linearVelocity.normalize().multiplyScalar(this._maxSpeed);
|
2024-02-28 03:25:11 -08:00
|
|
|
}
|
2024-02-27 18:19:33 -08:00
|
|
|
}
|
|
|
|
|
2024-03-10 03:12:55 -07:00
|
|
|
public addForce(force: Vec2) {
|
|
|
|
this._rigidBody.applyLinearImpulseToCenter(force, true);
|
2024-02-27 18:19:33 -08:00
|
|
|
}
|
2024-03-06 07:10:31 -08:00
|
|
|
|
2024-03-07 03:15:08 -08:00
|
|
|
public throwBall(force: Vec2) {
|
2024-03-10 03:12:55 -07:00
|
|
|
this._collider.group = PhysicsGroup.BALL_THROWING;
|
|
|
|
this._rigidBody.group = PhysicsGroup.BALL_THROWING;
|
2024-03-26 20:04:28 -07:00
|
|
|
this._rigidBody.applyAngularImpulse(-5 * force.x || 2, true);
|
2024-03-10 03:12:55 -07:00
|
|
|
this._rigidBody.applyLinearImpulseToCenter(force, true);
|
2024-03-07 03:15:08 -08:00
|
|
|
this._isJumping = true;
|
|
|
|
this._jumpTime = 0;
|
2024-03-10 03:12:55 -07:00
|
|
|
this._jumpDuration = this._rigidBody.linearVelocity.length() * 0.05;
|
2024-03-06 07:10:31 -08:00
|
|
|
}
|
|
|
|
|
2024-03-21 01:59:08 -07:00
|
|
|
public playMultiBallEffect() {
|
|
|
|
this._buffParticle.play();
|
|
|
|
}
|
|
|
|
|
2024-03-08 03:07:41 -08:00
|
|
|
public setActiveRigi(value: boolean) {
|
2024-03-10 03:12:55 -07:00
|
|
|
this._rigidBody.enabled = value;
|
2024-03-08 03:07:41 -08:00
|
|
|
if (!value) {
|
2024-03-10 03:12:55 -07:00
|
|
|
this._rigidBody.linearVelocity = Vec2.ZERO.clone();
|
|
|
|
this._rigidBody.angularVelocity = 0;
|
2024-03-08 03:07:41 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-03-10 03:12:55 -07:00
|
|
|
onGet() {
|
2024-03-07 03:15:08 -08:00
|
|
|
this._isJumping = false;
|
2024-03-10 03:12:55 -07:00
|
|
|
this._isHit = false;
|
|
|
|
this._rigidBody.enabled = true;
|
2024-03-07 03:15:08 -08:00
|
|
|
}
|
2024-03-06 10:08:30 -08:00
|
|
|
|
2024-03-10 03:12:55 -07:00
|
|
|
onRelease() {
|
|
|
|
this._rigidBody.linearVelocity = Vec2.ZERO.clone();
|
|
|
|
this._rigidBody.angularVelocity = 0;
|
2024-03-21 01:59:08 -07:00
|
|
|
this._buffParticle.stop();
|
2024-03-28 20:35:44 -07:00
|
|
|
this.getComponentsInChildren(ParticleSystem).forEach((particle) => {
|
|
|
|
particle.clear();
|
|
|
|
});
|
2024-03-06 07:10:31 -08:00
|
|
|
}
|
2024-02-28 03:25:11 -08:00
|
|
|
}
|