BulletCount.ts 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320
  1. import { _decorator, Component, Node, Vec3, instantiate } from 'cc';
  2. import { SkillManager } from '../SkillSelection/SkillManager'; // 导入SkillManager(用于多重射击技能)
  3. import { WeaponBullet } from '../WeaponBullet'; // 正确导入WeaponBullet
  4. import { BulletCountConfig } from '../../Core/ConfigManager';
  5. const { ccclass, property } = _decorator;
  6. /**
  7. * 子弹数量控制器
  8. * 负责根据配置生成不同数量和模式的子弹
  9. */
  10. export interface BulletSpawnInfo {
  11. position: Vec3; // 发射位置
  12. direction: Vec3; // 发射方向
  13. delay: number; // 延迟时间
  14. index: number; // 子弹索引
  15. }
  16. @ccclass('BulletCount')
  17. export class BulletCount extends Component {
  18. /**
  19. * 根据配置计算所有子弹的生成信息
  20. * @param config 子弹数量配置
  21. * @param firePosition 发射位置
  22. * @param baseDirection 基础方向
  23. * @returns 子弹生成信息数组
  24. */
  25. public static calculateBulletSpawns(
  26. config: BulletCountConfig,
  27. firePosition: Vec3,
  28. baseDirection: Vec3
  29. ): BulletSpawnInfo[] {
  30. const spawns: BulletSpawnInfo[] = [];
  31. switch (config.type) {
  32. case 'single':
  33. spawns.push(...this.createSingleShot(config, firePosition, baseDirection));
  34. break;
  35. case 'spread':
  36. spawns.push(...this.createSpreadShot(config, firePosition, baseDirection));
  37. break;
  38. case 'burst':
  39. spawns.push(...this.createBurstShot(config, firePosition, baseDirection));
  40. break;
  41. }
  42. return spawns;
  43. }
  44. /**
  45. * 单发模式
  46. */
  47. private static createSingleShot(
  48. config: BulletCountConfig,
  49. firePosition: Vec3,
  50. baseDirection: Vec3
  51. ): BulletSpawnInfo[] {
  52. return [{
  53. position: firePosition.clone(),
  54. direction: baseDirection.clone().normalize(),
  55. delay: 0,
  56. index: 0
  57. }];
  58. }
  59. /**
  60. * 散射模式 - 同时发射多颗子弹,呈扇形分布
  61. */
  62. private static createSpreadShot(
  63. config: BulletCountConfig,
  64. firePosition: Vec3,
  65. baseDirection: Vec3
  66. ): BulletSpawnInfo[] {
  67. const spawns: BulletSpawnInfo[] = [];
  68. const bulletCount = config.amount;
  69. const spreadAngleRad = config.spreadAngle * Math.PI / 180;
  70. if (bulletCount === 1) {
  71. // 只有一颗子弹时,直接使用基础方向
  72. return this.createSingleShot(config, firePosition, baseDirection);
  73. }
  74. // 计算每颗子弹的角度偏移
  75. const angleStep = spreadAngleRad / (bulletCount - 1);
  76. const startAngle = -spreadAngleRad / 2;
  77. for (let i = 0; i < bulletCount; i++) {
  78. const angle = startAngle + angleStep * i;
  79. const direction = this.rotateVector(baseDirection, angle);
  80. spawns.push({
  81. position: firePosition.clone(),
  82. direction: direction.normalize(),
  83. delay: 0,
  84. index: i
  85. });
  86. }
  87. return spawns;
  88. }
  89. /**
  90. * 连发模式 - 按时间间隔依次发射子弹
  91. */
  92. private static createBurstShot(
  93. config: BulletCountConfig,
  94. firePosition: Vec3,
  95. baseDirection: Vec3
  96. ): BulletSpawnInfo[] {
  97. const spawns: BulletSpawnInfo[] = [];
  98. const burstCount = config.burstCount || config.amount;
  99. for (let i = 0; i < burstCount; i++) {
  100. spawns.push({
  101. position: firePosition.clone(),
  102. direction: baseDirection.clone().normalize(),
  103. delay: i * config.burstDelay,
  104. index: i
  105. });
  106. }
  107. return spawns;
  108. }
  109. /**
  110. * 旋转向量
  111. */
  112. private static rotateVector(vector: Vec3, angleRad: number): Vec3 {
  113. const cos = Math.cos(angleRad);
  114. const sin = Math.sin(angleRad);
  115. return new Vec3(
  116. vector.x * cos - vector.y * sin,
  117. vector.x * sin + vector.y * cos,
  118. vector.z
  119. );
  120. }
  121. /**
  122. * 创建散射位置偏移(可选功能,用于霰弹枪等)
  123. */
  124. public static createSpreadPositions(
  125. basePosition: Vec3,
  126. spreadRadius: number,
  127. count: number
  128. ): Vec3[] {
  129. const positions: Vec3[] = [];
  130. if (count === 1) {
  131. positions.push(basePosition.clone());
  132. return positions;
  133. }
  134. const angleStep = (Math.PI * 2) / count;
  135. for (let i = 0; i < count; i++) {
  136. const angle = angleStep * i;
  137. const offset = new Vec3(
  138. Math.cos(angle) * spreadRadius,
  139. Math.sin(angle) * spreadRadius,
  140. 0
  141. );
  142. positions.push(basePosition.clone().add(offset));
  143. }
  144. return positions;
  145. }
  146. /**
  147. * 验证配置有效性
  148. */
  149. public static validateConfig(config: BulletCountConfig): boolean {
  150. if (!config) return false;
  151. // 检查基本参数
  152. if (config.amount <= 0) return false;
  153. if (config.spreadAngle < 0 || config.spreadAngle > 360) return false;
  154. if (config.burstDelay < 0) return false;
  155. // 检查类型特定参数
  156. switch (config.type) {
  157. case 'spread':
  158. if (config.amount > 20) {
  159. console.warn('散射子弹数量过多,可能影响性能');
  160. return false;
  161. }
  162. break;
  163. case 'burst':
  164. if (config.burstCount <= 0) return false;
  165. if (config.burstDelay <= 0.01) {
  166. console.warn('连发间隔过短,可能影响性能');
  167. }
  168. break;
  169. }
  170. return true;
  171. }
  172. /**
  173. * 创建多发子弹
  174. */
  175. public static createBullets(initData: any, bulletPrefab: Node): Node[] {
  176. // 关卡备战或其他情况下可关闭生成
  177. if (!(window as any).WeaponBullet?.shootingEnabled) return [];
  178. // 检查游戏是否暂停,暂停时不创建子弹
  179. const gamePause = (window as any).GamePause?.getInstance?.();
  180. if (gamePause && !gamePause.isBulletFireEnabled()) {
  181. return [];
  182. }
  183. // 获取武器配置
  184. const config = initData.weaponConfig || (window as any).WeaponBullet?.getWeaponConfig?.(initData.weaponId);
  185. if (!config) {
  186. return [];
  187. }
  188. // === 应用多重射击技能 ===
  189. const modifiedConfig = BulletCount.applyMultiShotSkill(config);
  190. // === 计算基础发射方向 ===
  191. let direction: Vec3;
  192. if (initData.direction) {
  193. direction = initData.direction.clone();
  194. } else if (initData.autoTarget) {
  195. // 使用 EnemyController 单例获取最近敌人,避免频繁 find
  196. const enemyController = (window as any).EnemyController?.getInstance?.();
  197. if (enemyController) {
  198. const nearestEnemy = enemyController.getNearestEnemy(initData.firePosition);
  199. if (nearestEnemy) {
  200. direction = nearestEnemy.worldPosition.clone().subtract(initData.firePosition).normalize();
  201. }
  202. }
  203. // 如果没有敌人或计算失败,则不创建子弹
  204. if (!direction) {
  205. console.log('【BulletCount】自动瞄准未找到有效目标,取消创建子弹');
  206. return [];
  207. }
  208. } else {
  209. // 非自动瞄准时使用默认方向
  210. const angleRand = Math.random() * Math.PI * 2;
  211. direction = new Vec3(Math.cos(angleRand), Math.sin(angleRand), 0);
  212. }
  213. // 计算批量生成信息(保持原逻辑)
  214. const spawnInfos = BulletCount.calculateBulletSpawns(
  215. modifiedConfig.bulletConfig.count,
  216. initData.firePosition,
  217. direction
  218. );
  219. const bullets: Node[] = [];
  220. // 为每个生成信息创建子弹实例
  221. for (const spawnInfo of spawnInfos) {
  222. try {
  223. const bullet = instantiate(bulletPrefab);
  224. const weaponBullet = bullet.getComponent(WeaponBullet) || bullet.addComponent(WeaponBullet);
  225. weaponBullet.init({
  226. ...initData,
  227. firePosition: spawnInfo.position,
  228. direction: spawnInfo.direction,
  229. weaponConfig: modifiedConfig
  230. });
  231. bullets.push(bullet);
  232. } catch (error) {
  233. console.error(`[BulletCount] 子弹创建失败:`, error);
  234. }
  235. }
  236. return bullets;
  237. }
  238. /**
  239. * 应用多重射击技能效果
  240. * @param originalConfig 原始武器配置
  241. * @returns 应用技能后的武器配置
  242. */
  243. public static applyMultiShotSkill(originalConfig: any): any {
  244. // 获取SkillManager实例
  245. const skillManager = SkillManager.getInstance();
  246. if (!skillManager) {
  247. return originalConfig; // 如果没有技能管理器,返回原配置
  248. }
  249. // 获取多重射击技能等级
  250. const multiShotSkillLevel = skillManager.getSkillLevel('multi_shots');
  251. console.log(`[BulletCount] 多重射击技能等级: ${multiShotSkillLevel}`);
  252. if (multiShotSkillLevel <= 0) {
  253. console.log(`[BulletCount] 技能等级为0,返回原配置`);
  254. return originalConfig; // 技能等级为0,返回原配置
  255. }
  256. const bulletCountConfig = originalConfig.bulletConfig.count;
  257. // 计算多重射击几率
  258. const baseMultiShotChance = 0; // 基础几率为0
  259. const multiShotChance = SkillManager.calculateMultiShotChance(baseMultiShotChance, multiShotSkillLevel);
  260. console.log(`[BulletCount] 多重射击几率: ${multiShotChance}`);
  261. // 检查是否触发多重射击
  262. const shouldTriggerMultiShot = SkillManager.rollMultiShot(multiShotChance);
  263. console.log(`[BulletCount] 是否触发多重射击: ${shouldTriggerMultiShot}`);
  264. if (!shouldTriggerMultiShot) {
  265. return originalConfig; // 未触发多重射击,返回原配置
  266. }
  267. // 触发多重射击,计算子弹数量
  268. const baseBulletCount = 1;
  269. const multiShotBulletCount = SkillManager.calculateMultiShotBulletCount(baseBulletCount, multiShotSkillLevel);
  270. // 创建修改后的配置
  271. const modifiedConfig: any = JSON.parse(JSON.stringify(originalConfig)); // 深拷贝
  272. // 修改子弹配置为连射模式(同一方向连续发射)
  273. modifiedConfig.bulletConfig.count = {
  274. type: 'burst',
  275. amount: 2, // 每次连射发射1发子弹
  276. burstCount: multiShotBulletCount, // 连射次数
  277. burstDelay: 200 // 连射间隔200毫秒,可以根据需要调整
  278. };
  279. console.log(`多重射击触发!技能等级: ${multiShotSkillLevel}, 子弹数量: ${multiShotBulletCount}`);
  280. return modifiedConfig;
  281. }
  282. }