148 lines
5.1 KiB
TypeScript
148 lines
5.1 KiB
TypeScript
import {
|
|
_decorator,
|
|
AudioClip,
|
|
CCFloat,
|
|
Collider2D,
|
|
Component,
|
|
Contact2DType,
|
|
Director,
|
|
director,
|
|
EventTarget,
|
|
IPhysics2DContact,
|
|
RigidBody2D,
|
|
Vec2,
|
|
geometry,
|
|
math,
|
|
Node,
|
|
Vec3,
|
|
ParticleSystem,
|
|
Prefab,
|
|
CircleCollider2D,
|
|
} from 'cc';
|
|
import IPoolable from '../Pool/IPoolable';
|
|
import { SoundManager } from '../Manager/SoundManager';
|
|
import PhysicsGroup from '../Enum/PhysicGroup';
|
|
import ObjectPool from '../Pool/ObjectPool';
|
|
import Utilities from '../Utilities/Utilities';
|
|
const { ccclass, property } = _decorator;
|
|
|
|
@ccclass('Ball')
|
|
export class Ball extends Component implements IPoolable {
|
|
@property({ type: Prefab, visible: true })
|
|
private _impactPrefab: Prefab;
|
|
@property({ type: CCFloat, visible: true })
|
|
private _maxSpeed: number;
|
|
@property({ type: RigidBody2D, visible: true })
|
|
private _rigidbody: RigidBody2D;
|
|
@property({ type: Node, visible: true })
|
|
private _sprite: Node;
|
|
@property({ type: ParticleSystem, visible: true })
|
|
private _trail: ParticleSystem;
|
|
@property({ type: CircleCollider2D, visible: true })
|
|
private _collider: CircleCollider2D;
|
|
@property({ type: AudioClip, visible: true })
|
|
private _hitSound: AudioClip;
|
|
@property({ type: geometry.AnimationCurve, visible: true })
|
|
private _jumpCurve: geometry.AnimationCurve = new geometry.AnimationCurve();
|
|
|
|
private _impactPool: ObjectPool;
|
|
private _hitted = false;
|
|
private _isJumping = false;
|
|
private _jumpTime: number;
|
|
private _jumpDuration: number;
|
|
|
|
public eventHitObstacle = new EventTarget();
|
|
public eventGoal = new EventTarget();
|
|
|
|
protected onLoad(): void {
|
|
if (this._collider) {
|
|
this._collider.on(Contact2DType.BEGIN_CONTACT, this.onBeginContact, this);
|
|
this._collider.on(Contact2DType.END_CONTACT, this.onEndContact, this);
|
|
}
|
|
director.on(Director.EVENT_AFTER_PHYSICS, this.setMaxVelocity, this);
|
|
this._impactPool = new ObjectPool(this._impactPrefab, 5, false);
|
|
}
|
|
|
|
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();
|
|
scale = scale.add(Vec3.ONE.clone().multiplyScalar(this._jumpCurve.evaluate(jumpProcess)));
|
|
|
|
this._sprite.setScale(scale);
|
|
this._trail.trailModule.widthRatio.multiplier = scale.x;
|
|
|
|
if (jumpProcess >= 1) {
|
|
this._sprite.setScale(Vec3.ONE);
|
|
this._trail.trailModule.widthRatio.multiplier = 1;
|
|
this._isJumping = false;
|
|
this._collider.group = PhysicsGroup.BALL;
|
|
this._rigidbody.group = PhysicsGroup.BALL;
|
|
}
|
|
}
|
|
}
|
|
|
|
private async onBeginContact(
|
|
selfCollider: Collider2D,
|
|
otherCollider: Collider2D,
|
|
contact: IPhysics2DContact | null,
|
|
) {
|
|
if (this._hitted) return;
|
|
this._hitted = true;
|
|
if (this._rigidbody.linearVelocity.length() >= 3) {
|
|
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(this.node.parent, ParticleSystem);
|
|
hitfx.node.setWorldPosition(new Vec3(hitPoint.x, hitPoint.y, 10));
|
|
hitfx.play();
|
|
SoundManager.instance.playSfx(this._hitSound);
|
|
await Utilities.waitUntil(() => hitfx.isStopped, 100);
|
|
this._impactPool.release(hitfx.node);
|
|
}
|
|
}
|
|
|
|
private onEndContact(selfCollider: Collider2D, otherCollider: Collider2D, contact: IPhysics2DContact | null) {
|
|
// console.log(otherCollider.tag, otherCollider.node.name);
|
|
this._hitted = false;
|
|
}
|
|
|
|
private setMaxVelocity() {
|
|
if (this._rigidbody.linearVelocity.length() > this._maxSpeed) {
|
|
this._rigidbody.linearVelocity = this._rigidbody.linearVelocity.normalize().multiplyScalar(this._maxSpeed);
|
|
}
|
|
}
|
|
|
|
public addFocre(force: Vec2) {
|
|
this._rigidbody.applyLinearImpulseToCenter(force, true);
|
|
}
|
|
|
|
public throwBall(force: Vec2) {
|
|
this._collider.group = PhysicsGroup.BALLTHROWING;
|
|
this._rigidbody.group = PhysicsGroup.BALLTHROWING;
|
|
this._rigidbody.applyLinearImpulseToCenter(force, true);
|
|
this._isJumping = true;
|
|
this._jumpTime = 0;
|
|
this._jumpDuration = this._rigidbody.linearVelocity.length() * 0.05;
|
|
}
|
|
|
|
reuse() {
|
|
this._isJumping = false;
|
|
this._hitted = false;
|
|
}
|
|
|
|
unuse() {
|
|
this._rigidbody.linearVelocity = Vec2.ZERO.clone();
|
|
this._rigidbody.angularVelocity = 0;
|
|
}
|
|
}
|