pinball/assets/_Game/Scripts/Gameplay/Ball.ts

252 lines
9.0 KiB
TypeScript
Raw Normal View History

2024-02-28 03:25:11 -08:00
import {
_decorator,
2024-05-15 00:42:31 -07:00
Animation,
2024-03-06 10:08:30 -08:00
AudioClip,
2024-02-28 03:25:11 -08:00
CCFloat,
2024-05-15 00:42:31 -07:00
CircleCollider2D,
2024-02-28 03:25:11 -08:00
Collider2D,
Component,
Contact2DType,
Director,
director,
2024-05-15 00:42:31 -07:00
ERigidBody2DType,
2024-03-07 03:15:08 -08:00
geometry,
2024-05-15 00:42:31 -07:00
IPhysics2DContact,
2024-03-07 03:15:08 -08:00
math,
2024-05-15 00:42:31 -07:00
Node,
2024-03-07 03:15:08 -08:00
ParticleSystem,
Prefab,
2024-05-15 00:42:31 -07:00
RigidBody2D,
2024-03-21 01:59:08 -07:00
Sprite,
2024-05-15 00:42:31 -07:00
Vec2,
Vec3,
2024-02-28 03:25:11 -08:00
} from 'cc';
2024-03-07 03:15:08 -08:00
import PhysicsGroup from '../Enum/PhysicGroup';
2024-05-15 00:42:31 -07:00
import { SequenceSound } from '../Environments/SequenceSound';
import GameEvent from '../Events/GameEvent';
2024-05-27 02:19:31 -07:00
import AudioManager from '../Manager/AudioManager';
2024-05-15 00:42:31 -07:00
import { EventManger } from '../Manager/EventManger';
import IPoolable from '../Pool/IPoolable';
2024-03-07 03:15:08 -08:00
import ObjectPool from '../Pool/ObjectPool';
2024-06-09 05:12:08 -07:00
import Utils from '../Utilities';
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: 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 _fireParticle: 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
@property({ type: Sprite, visible: true })
private _normalSprite: Sprite;
@property({ type: Sprite, visible: true })
private _cheeseModeSprite: Sprite;
@property({ type: Sprite, visible: true })
private _spriteShadow: Sprite;
2024-03-06 10:08:30 -08:00
@property({ type: AudioClip, visible: true })
2024-04-24 01:52:31 -07:00
private _impactSound: AudioClip;
2024-03-10 20:46:50 -07:00
@property({ type: AudioClip, visible: true })
2024-04-24 01:52:31 -07:00
private _impactFlipperSound: AudioClip;
@property({ type: SequenceSound, visible: true })
private _collectSound: SequenceSound;
@property({ type: SequenceSound, visible: true })
private _cheeseModeCollectSound: SequenceSound;
2024-04-03 02:43:18 -07:00
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;
private _parent: Node;
2024-04-24 01:52:31 -07:00
private _cheeseModeOn = false;
2024-02-27 18:19:33 -08:00
2024-03-28 20:35:44 -07:00
public init(boosterActive: boolean) {
2024-04-23 03:36:31 -07:00
if (boosterActive) {
2024-04-24 01:52:31 -07:00
this.onBoosterActive();
2024-04-23 03:36:31 -07:00
} else {
2024-04-24 01:52:31 -07:00
this.onBoosterDisable();
2024-04-23 03:36:31 -07:00
}
2024-03-28 20:35:44 -07:00
}
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
}
director.on(Director.EVENT_AFTER_PHYSICS, this.afterPhysicUpdate, 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._normalSprite.node.setScale(scale);
this._cheeseModeSprite.node.setScale(scale);
2024-03-21 01:59:08 -07:00
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._normalSprite.node.setScale(Vec3.ONE);
this._cheeseModeSprite.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;
this.node.setParent(this._parent);
2024-03-07 03:15:08 -08:00
}
}
2024-02-27 18:19:33 -08:00
}
2024-04-23 03:36:31 -07:00
protected lateUpdate(dt: number): void {
if (this._rigidBody.linearVelocity.length() > 60) {
this._fireParticle.rateOverTime.constant = 8;
this._fireParticle.rateOverDistance.constant = 0.02;
// if (this._fireParticle.isStopped) {
// }
} else {
this._fireParticle.rateOverDistance.constant = 0;
this._fireParticle.rateOverTime.constant = 0;
// if (this._fireParticle.isPlaying) {
// this._fireParticle.stopEmitting();
// }
}
}
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();
2024-04-24 01:52:31 -07:00
if (!otherCollider.sensor) {
if (velocity >= 5) {
this._animation.play();
let hitPoint = contact.getWorldManifold().points[0];
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);
}
const hitFx = this._impactPool.get(ParticleSystem, this.node.parent);
hitFx.node.setWorldPosition(new Vec3(hitPoint.x, hitPoint.y, 10));
2024-05-27 02:19:31 -07:00
AudioManager.playSfx(
2024-04-24 01:52:31 -07:00
otherCollider.group == PhysicsGroup.FLIPPER ? this._impactFlipperSound : this._impactSound,
);
2024-06-09 05:12:08 -07:00
await Utils.waitUntil(() => hitFx.isStopped, 0.1);
2024-04-24 01:52:31 -07:00
this._impactPool.release(hitFx);
}
} else if (otherCollider.tag == 1) {
if (this._cheeseModeOn) {
this._cheeseModeCollectSound.playSound();
} else {
this._collectSound.playSound();
2024-03-07 03:15:08 -08:00
}
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._fireParticle.play();
2024-04-24 01:52:31 -07:00
this._cheeseModeOn = true;
2024-05-07 03:20:37 -07:00
this._cheeseModeSprite.setNodeActive(true);
this._normalSprite.setNodeActive(false);
2024-03-28 20:35:44 -07:00
}
private onBoosterDisable() {
// this._fireParticle.stop();
2024-04-24 01:52:31 -07:00
this._cheeseModeOn = false;
2024-05-07 03:20:37 -07:00
this._cheeseModeSprite.setNodeActive(false);
this._normalSprite.setNodeActive(true);
2024-03-28 20:35:44 -07:00
}
private afterPhysicUpdate() {
let velocity = this._rigidBody.linearVelocity.length();
if (velocity > this._maxSpeed) {
2024-03-10 03:12:55 -07:00
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-05-15 00:42:31 -07:00
public clearRigiState(active: boolean) {
this._rigidBody.type = active ? ERigidBody2DType.Dynamic : ERigidBody2DType.Kinematic;
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-05-15 00:42:31 -07:00
this.clearRigiState(true);
2024-03-07 03:15:08 -08:00
this._isJumping = false;
2024-03-10 03:12:55 -07:00
this._isHit = false;
this._parent = this.node.getParent();
2024-04-23 03:36:31 -07:00
this._fireParticle.rateOverDistance.constant = 0;
this._fireParticle.rateOverTime.constant = 0;
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
}