import { _decorator, clamp, Component, director, find, instantiate, lerp, Node, Prefab, tween, UITransform, v2, v3, Vec3 } from 'cc'; import { SuDacePlayer } from './SuDacePlayer'; import { SuDace } from './SuDace'; import { SuDaceBullet } from './SuDaceBullet'; import { SuDacePoint } from './SuDacePoint'; const { ccclass, property } = _decorator; @ccclass('SuDaceMap') export class SuDaceMap extends Component { @property(Prefab) enemyTemplate: Prefab = null; /**子弹模版 */ @property(Prefab) bulletTemplate: Prefab = null; /**落石模版 */ @property(Prefab) stoneTemplate: Prefab = null; player: SuDacePlayer = null; gridNode: Node = null; enemyNode: Node = null; bulletNode: Node = null; spawnPointNode: Node = null; private readonly _tmpV2 = v2(); protected onLoad(): void { this.player = find("player", this.node).getComponent(SuDacePlayer); this.gridNode = find("grids", this.node); this.enemyNode = find("enemys", this.node); this.bulletNode = find("bullets", this.node); this.spawnPointNode = find("spawnPoints", this.node); } /** * 根据世界坐标查找所在格子节点(grids 子节点)。 * 多个格子重叠时以子节点顺序先命中者为准。 */ getGridCellAtWorld(worldPos: Readonly): Node | null { if (!this.gridNode?.isValid) return null; this._tmpV2.set(worldPos.x, worldPos.y); for (let i = 0; i < this.gridNode.children.length; i++) { const cell = this.gridNode.children[i]; if (!cell.activeInHierarchy) continue; const ui = cell.getComponent(UITransform); if (!ui) continue; if (ui.getBoundingBoxToWorld().contains(this._tmpV2)) { return cell; } } return null; } /** 格子上的 SuDacePoint(无组件则返回 null) */ getSuDacePointAtWorld(worldPos: Readonly): SuDacePoint | null { const cell = this.getGridCellAtWorld(worldPos); return cell?.getComponent(SuDacePoint) ?? null; } protected start(): void { tween(this.node).to(0.5, { scale: v3(0.6, 0.6, 0.6) }, { onUpdate: () => { this.checkMapBoundary(); } }).start(); } /**生成怪物 */ generateMonster(): Node { const spawnPos = this.spawnPointNode?.worldPosition ?? this.player?.node?.worldPosition ?? Vec3.ZERO; let monster: Node = null; if (SuDace.instance.enemyPool.length > 0) { monster = SuDace.instance.enemyPool.shift(); } else { monster = instantiate(this.enemyTemplate); } monster.setParent(this.enemyNode ?? this.node); monster.setWorldPosition(spawnPos.clone().add(v3(Math.random() * 200 - 100, 0, 0))); monster.active = true; return monster; } /**生成子弹 */ generateBullet(): Node { let bullet = null; if (SuDace.instance.bulletPool.length > 0) { bullet = SuDace.instance.bulletPool.shift()!; } else { bullet = instantiate(this.bulletTemplate); } bullet.setParent(this.bulletNode); const comp = bullet.getComponent(SuDaceBullet); if (comp) { comp.isStone = false; } bullet.active = true; return bullet; } /**生成落石 */ generateStone(): Node { let stone: Node = null; if (SuDace.instance.stonePool.length > 0) { stone = SuDace.instance.stonePool.shift(); } else { stone = instantiate(this.stoneTemplate); } stone.setParent(this.bulletNode); const comp = stone.getComponent(SuDaceBullet); if (comp) { comp.isStone = true; } // 竖直向下 stone.angle = 180; stone.active = true; if (stone.children.length > 0) { const index = Math.floor(Math.random() * stone.children.length); stone.children.forEach((x, idx) => x.active = index === idx); } return stone; } protected update(dt: number): void { //差值移动地图,将地图的本地坐标设置为角色本地坐标乘-1 if (this.player?.node) { let x = this.player.node.position.x * -1 * this.node.scale.x; let y = this.player.node.position.y * -1 * this.node.scale.y; this.node.setPosition(lerp(this.node.position.x, x, 0.1), lerp(this.node.position.y, y, 0.1), 0); this.checkMapBoundary(); } } /** * 验证地图边界 */ private checkMapBoundary() { let minY = -45; let maxY = 30; let minX = -720; let maxX = 720; let tf = this.node.getComponent(UITransform); minX = -tf.width * this.node.scale.x / 2 + 375; maxX = tf.width * this.node.scale.x / 2 - 375; minY = tf.height * this.node.scale.y / 2 + 800; maxY = tf.height * this.node.scale.y / 2 - 800; if (this.node.y < minY) this.node.y = minY; if (this.node.y > maxY) this.node.y = maxY; if (this.node.x > maxX) this.node.x = maxX; if (this.node.x < minX) this.node.x = minX; } }