BulletCount.ts 11 KB

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