消消方块阵换皮表情
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

89 lines
3.1 KiB

import { _decorator, Collider2D, Component, Contact2DType, IPhysics2DContact, Node, Vec3 } from 'cc';
import { SuDace } from './SuDace';
import { SuDaceEnemy } from './SuDaceEnemy';
const { ccclass, property } = _decorator;
@ccclass('SuDaceBullet')
export class SuDaceBullet extends Component {
@property
moveSpeed: number = 100;
@property
hitRadius = 24;
/**攻击力 */
@property
damage = 1;
/** true 表示陷阱落石:仅向下运动,并回收到 stonePool */
@property
isStone = false;
private _col: Collider2D | null = null;
onEnable() {
this._col = this.node.getComponent(Collider2D);
this._col?.on(Contact2DType.BEGIN_CONTACT, this.onBeginContact, this);
}
onDisable() {
this._col?.off(Contact2DType.BEGIN_CONTACT, this.onBeginContact, this);
this._col = null;
}
update(deltaTime: number) {
let direction: Vec3;
if (this.isStone) {
// 落石固定竖直下落,避免被角度/复用状态影响成横向发射
direction = new Vec3(0, -1, 0);
} else {
// 普通子弹按角度飞行
const angle = this.node.angle * Math.PI / 180 + Math.PI / 2;
// Node.angle 在 2D 中是“顺时针为正”,而 sin/cos 按“逆时针为正”来解释角度
// 这里对 Y 分量取反,修正“右下变右上/上下颠倒”的问题
direction = new Vec3(Math.cos(angle), -Math.sin(angle), 0).normalize();
}
// 地图节点每帧在移动(相机跟随),子弹必须用世界坐标移动,否则会叠加父节点位移导致“角度对但轨迹偏”
const wp = this.node.worldPosition;
this.node.setWorldPosition(
wp.x + direction.x * deltaTime * this.moveSpeed,
wp.y + direction.y * deltaTime * this.moveSpeed,
wp.z
);
this.checkEnemyHitByDistance();
}
private onBeginContact(self: Collider2D, other: Collider2D, contact: IPhysics2DContact | null) {
if (!this.node.active || !other?.node?.active) return;
const otherName = other.node.name.toLowerCase();
if (otherName === "enemy" || otherName.includes("enemy")) {
this.hitEnemy(other.node);
}
}
private checkEnemyHitByDistance() {
const enemyRoot = SuDace.instance?.map?.enemyNode;
if (!enemyRoot || !this.node.active) return;
const bp = this.node.worldPosition;
for (let i = 0; i < enemyRoot.children.length; i++) {
const enemy = enemyRoot.children[i];
if (!enemy.active) continue;
if (Vec3.distance(bp, enemy.worldPosition) <= this.hitRadius) {
this.hitEnemy(enemy);
break;
}
}
}
private hitEnemy(enemy: Node) {
if (!this.node.active || !enemy?.active) return;
enemy.getComponent(SuDaceEnemy)?.hit(this.damage);
if (this.isStone) {
SuDace.instance?.recycleStone(this.node);
} else {
SuDace.instance?.recycleBullet(this.node);
}
}
}