| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145 |
- import { _decorator, Component, Node, Vec3, Prefab, instantiate, Collider2D, Contact2DType, IPhysics2DContact, math } from 'cc';
- import { BulletInitData, WeaponConfig, BulletLifecycleConfig } from './BulletTypes';
- import { ConfigLoader } from './ConfigLoader';
- import { BulletCount } from './effects/BulletCount';
- import { BulletTrajectory as BCBulletTrajectory } from './effects/BulletTrajectory';
- import { BulletHitEffect as BCBulletHitEffect } from './effects/BulletHitEffect';
- import { BulletLifecycle as BCBulletLifecycle } from './effects/BulletLifecycle';
- import { BulletTrailController } from './BulletTrailController';
- const { ccclass } = _decorator;
- /** 可移植的统一子弹控制器 */
- @ccclass('WeaponBulletController')
- export class WeaponBulletController extends Component {
- private trajectory: BCBulletTrajectory | null = null;
- private hitEffect: BCBulletHitEffect | null = null;
- private lifecycle: BCBulletLifecycle | null = null;
- private trail: BulletTrailController | null = null;
- private weaponConfig: WeaponConfig | null = null;
- private isInitialized = false;
- // 图片“上为前进方向”的偏移修正(度)
- private readonly _orientationOffsetByWeapon: Record<string, number> = {
- sharp_carrot: -90,
- hot_pepper: -90,
- okra_missile: -90,
- mace_club: -90
- };
- private getOrientationOffset(): number {
- const id = this.weaponConfig?.id;
- if (!id) return 0;
- return this._orientationOffsetByWeapon[id] ?? 0;
- }
- public init(initData: BulletInitData) {
- // 装配配置
- this.weaponConfig = initData.weaponConfig ?? ConfigLoader.getWeaponConfig(initData.weaponId);
- if (!this.weaponConfig) {
- this.node.destroy();
- return;
- }
- // 计算方向
- const direction = (initData.direction?.clone() ?? new Vec3(1, 0, 0)).normalize();
- // 弹道
- this.trajectory = this.getComponent(BCBulletTrajectory) || this.addComponent(BCBulletTrajectory);
- const trajCfg = { ...this.weaponConfig.bulletConfig.trajectory, speed: this.weaponConfig.stats.bulletSpeed };
- this.trajectory.init(trajCfg, direction, initData.firePosition, initData.sourceBlock);
- // 初始位置略微前移,避免贴边重叠
- const spawnOffset = 30;
- const pos = this.node.position.clone();
- this.node.setPosition(pos.x + direction.x * spawnOffset, pos.y + direction.y * spawnOffset);
- // 命中效果
- this.hitEffect = this.getComponent(BCBulletHitEffect) || this.addComponent(BCBulletHitEffect);
- this.hitEffect.init(this.weaponConfig.bulletConfig.hitEffects);
- // 生命周期
- this.lifecycle = this.getComponent(BCBulletLifecycle) || this.addComponent(BCBulletLifecycle);
- const lc: BulletLifecycleConfig = { ...this.weaponConfig.bulletConfig.lifecycle };
- if (lc.type === 'return_trip' && !lc.maxRange && this.weaponConfig.stats.range) {
- lc.maxRange = this.weaponConfig.stats.range;
- }
- // 透传 pierce/ricochet 初始计数(若命中效果中有)
- const pierceInit = this.weaponConfig.bulletConfig.hitEffects.find(e => e.type === 'pierce_damage')?.pierceCount ?? lc.penetration ?? 0;
- const ricochetInit = this.weaponConfig.bulletConfig.hitEffects.find(e => e.type === 'ricochet_damage')?.ricochetCount ?? lc.ricochetCount ?? 0;
- this.lifecycle.init(lc, initData.firePosition, pierceInit, ricochetInit);
- // 拖尾(可选)
- this.trail = this.getComponent(BulletTrailController) || this.addComponent(BulletTrailController);
- // 旋转对齐外观
- const deg = math.toDegree(Math.atan2(direction.y, direction.x)) + this.getOrientationOffset();
- const shouldRotate = this.weaponConfig?.bulletConfig?.shouldRotate;
- const pelletNode = this.node.getChildByName('Pellet');
- if (shouldRotate === false && pelletNode) {
- pelletNode.angle = deg;
- } else {
- this.node.angle = deg;
- }
- // 启用持续外观对齐/自旋(贴合两种模式)
- if (this.trajectory) {
- this.trajectory.setFacingOptions({
- shouldRotate: shouldRotate,
- offsetDeg: this.getOrientationOffset(),
- targetChildName: pelletNode ? 'Pellet' : undefined,
- spinSpeedDeg: 720
- });
- }
- // 碰撞监听(若存在 Collider2D)
- const collider = this.getComponent(Collider2D);
- if (collider) {
- collider.on(Contact2DType.BEGIN_CONTACT, this.onCollision, this);
- }
- this.isInitialized = true;
- }
- private onCollision(self: Collider2D, other: Collider2D, contact: IPhysics2DContact | null) {
- if (!this.isInitialized || !this.hitEffect || !this.lifecycle) return;
- const result = this.hitEffect.applyOnHit();
- this.lifecycle.notifyHit(result);
- if (this.lifecycle.shouldDestroyNow()) {
- this.node.destroy();
- return;
- }
- }
- }
- /**
- * 工具:批量创建子弹(Prefab 或 Node 模板)
- */
- export class BulletEngine {
- static createBullets(initData: BulletInitData, bulletTemplate: Prefab | Node): Node[] {
- // 获取配置
- const config = initData.weaponConfig ?? ConfigLoader.getWeaponConfig(initData.weaponId);
- if (!config) return [];
- const dir = (initData.direction?.clone() ?? new Vec3(1, 0, 0)).normalize();
- const spawns = BulletCount.calculateSpawns(config.bulletConfig.count, initData.firePosition, dir);
- const nodes: Node[] = [];
- for (const s of spawns) {
- const node = instantiate(bulletTemplate) as Node;
- const ctrl = node.getComponent(WeaponBulletController) || node.addComponent(WeaponBulletController);
- // 处理延迟:先禁用,延时后启用
- if (s.delayMs > 0) {
- node.active = false;
- ctrl.init({ ...initData, firePosition: s.position, direction: s.direction, weaponConfig: config });
- nodes.push(node);
- setTimeout(() => { if (node && node.isValid) node.active = true; }, s.delayMs);
- } else {
- ctrl.init({ ...initData, firePosition: s.position, direction: s.direction, weaponConfig: config });
- nodes.push(node);
- }
- }
- return nodes;
- }
- }
|