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.
169 lines
5.9 KiB
169 lines
5.9 KiB
import { _decorator, CCBoolean, CCFloat, Component, instantiate, Node, NodePool, Prefab, UITransform, v3 } from 'cc';
|
|
import { GBundle } from '../../game/ConfigRes';
|
|
import { atgSkill } from './atgSkill';
|
|
import { gaoyaguo } from './gaoyaguo';
|
|
import { GEvent } from 'db://assets/mx/module/event/GEvent';
|
|
const { ccclass, property } = _decorator;
|
|
|
|
@ccclass('zidanScript')
|
|
export class zidanScript extends Component {
|
|
//子弹内存池
|
|
@property(Prefab)
|
|
zidanPrefab: Prefab = null;
|
|
|
|
zidanPool: NodePool = null;
|
|
|
|
bulletSpeed: number = 700;
|
|
_dt: number = 0;
|
|
deltaTime: number = 0.016;
|
|
|
|
/** jiedianIndex==3 时:子弹世界坐标 Y 需接近主角才做命中判定,避免门廊区被超大 UITransform 误杀 */
|
|
@property(CCFloat)
|
|
playerHitWorldYOffset: number = 180;
|
|
|
|
@property(CCBoolean)
|
|
debugBulletMove: boolean = false;
|
|
|
|
/** 子弹世界坐标越界回收的边界(避免飞出屏幕后一直存在)。按设计分辨率 750x1600 做默认值,可在编辑器调。 */
|
|
@property(CCFloat)
|
|
recycleWorldHalfWidth: number = 750;
|
|
@property(CCFloat)
|
|
recycleWorldHalfHeight: number = 1600;
|
|
@property(CCFloat)
|
|
recycleWorldPadding: number = 300;
|
|
|
|
private _debugAcc = 0;
|
|
protected onDestroy(): void {
|
|
if (this.zidanPool) this.zidanPool.clear()
|
|
}
|
|
protected start(): void {
|
|
this.zidanPool = new NodePool()
|
|
//添加100个子弹
|
|
for (let i = 0; i < 100; i++) {
|
|
let zidan = instantiate(this.zidanPrefab)
|
|
this.zidanPool.put(zidan)
|
|
}
|
|
}
|
|
|
|
|
|
|
|
//获取子弹
|
|
getZidan(): Node {
|
|
|
|
if (this.zidanPool.size() > 0) {
|
|
|
|
}else{
|
|
let zidan = instantiate(this.zidanPrefab)
|
|
this.zidanPool.put(zidan)
|
|
}
|
|
return this.zidanPool.get()
|
|
}
|
|
|
|
//放入子弹
|
|
putZidan(zidan: Node) {
|
|
|
|
zidan.removeFromParent();
|
|
this.zidanPool.put(zidan)
|
|
}
|
|
|
|
|
|
|
|
protected update(dt: number): void {
|
|
if(gaoyaguo.Instance.isGameOver){
|
|
return
|
|
|
|
}
|
|
const children = this.node.children;
|
|
const hitList: Node[] = [];
|
|
/** 飞过主角仍未碰到主角盒,只回收不计分(避免与 qiang 超大 AABB 误杀整屏子弹) */
|
|
const missRecycleList: Node[] = [];
|
|
const g = gaoyaguo.Instance;
|
|
const guoTrans = g?.gaoyaguo_guo?.getComponent(UITransform) ?? null;
|
|
const guoBox = guoTrans ? guoTrans.getBoundingBoxToWorld() : null;
|
|
//const zhujueTrans = g?.zhujueNode?.getComponent(UITransform) ?? null;
|
|
// const zhujueBox = zhujueTrans ? zhujueTrans.getBoundingBoxToWorld() : null;
|
|
|
|
this._debugAcc += dt;
|
|
const doDbg = this.debugBulletMove && this._debugAcc >= 1;
|
|
if (doDbg) this._debugAcc = 0;
|
|
|
|
let sampleChild: Node | null = null;
|
|
children.forEach((child)=>{
|
|
if (doDbg && !sampleChild) sampleChild = child;
|
|
if(!child.active){
|
|
return
|
|
}
|
|
const skill = child.getComponent(atgSkill);
|
|
if (skill?.ignoreContactFrames > 0) {
|
|
skill.ignoreContactFrames--;
|
|
if (skill.ignoreContactFrames <= 0) {
|
|
skill.ignoreDoorUuid = null;
|
|
}
|
|
}
|
|
const dir = skill?.moveDir ?? v3(0, 1, 0);
|
|
const p = child.position;
|
|
child.setPosition(
|
|
p.x + dir.x * this.bulletSpeed * dt,
|
|
p.y + dir.y * this.bulletSpeed * dt,
|
|
p.z
|
|
);
|
|
|
|
// 世界坐标越界回收(含 padding)
|
|
const wp = child.worldPosition;
|
|
if (
|
|
Math.abs(wp.x) > this.recycleWorldHalfWidth + this.recycleWorldPadding ||
|
|
Math.abs(wp.y) > this.recycleWorldHalfHeight + this.recycleWorldPadding
|
|
) {
|
|
missRecycleList.push(child);
|
|
return;
|
|
}
|
|
|
|
// jiedianIndex == 2:子弹命中高压锅才触发回收/扣血(否则会导致“子弹一生成就被回收”)
|
|
if (g?.jiedianIndex === 2 && guoBox) {
|
|
const bulletTrans = child.getComponent(UITransform);
|
|
if (bulletTrans) {
|
|
const bulletBox = bulletTrans.getBoundingBoxToWorld();
|
|
if (bulletBox.intersects(guoBox)) {
|
|
hitList.push(child);
|
|
}
|
|
}
|
|
}else if(g?.jiedianIndex == 3){
|
|
// 只用主角盒判定「命中计分」;左右墙 UITransform 常过大,若参与 OR 会导致整路子弹同一帧进 hitList(length 上百)
|
|
|
|
}
|
|
})
|
|
|
|
if (doDbg) {
|
|
const s = sampleChild?.getComponent(atgSkill);
|
|
console.log('[zidanScript] tick', {
|
|
jiedianIndex: g?.jiedianIndex,
|
|
children: children.length,
|
|
sample: sampleChild?.name ?? null,
|
|
sampleLocal: sampleChild ? { x: sampleChild.position.x, y: sampleChild.position.y } : null,
|
|
sampleWorld: sampleChild ? { x: sampleChild.worldPosition.x, y: sampleChild.worldPosition.y } : null,
|
|
sampleDir: s ? { x: s.moveDir.x, y: s.moveDir.y } : null,
|
|
bulletSpeed: this.bulletSpeed,
|
|
});
|
|
}
|
|
|
|
// 统一处理命中,避免遍历 children 时修改层级
|
|
if (hitList.length > 0) {
|
|
|
|
for (const child of hitList) {
|
|
this.putZidan(child);
|
|
}
|
|
if (g?.jiedianIndex == 2) {
|
|
GEvent.Ins.emit(GEvent.hitGaoyaguo, hitList.length, hitList[0]);
|
|
}
|
|
}
|
|
if (missRecycleList.length > 0) {
|
|
console.log('missRecycleList', missRecycleList.length)
|
|
|
|
for (const child of missRecycleList) {
|
|
this.putZidan(child);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|