BulletTrailController.ts 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266
  1. import { _decorator, Component, Node, MotionStreak, Color, Texture2D } from 'cc';
  2. const { ccclass, property } = _decorator;
  3. /**
  4. * 子弹拖尾控制器
  5. * 负责管理子弹的拖尾效果
  6. */
  7. @ccclass('BulletTrailController')
  8. export class BulletTrailController extends Component {
  9. @property({
  10. type: MotionStreak,
  11. tooltip: '拖尾组件引用'
  12. })
  13. public motionStreak: MotionStreak | null = null;
  14. private secondaryStreak: MotionStreak | null = null;
  15. // 拖尾配置
  16. private trailConfig = {
  17. fadeTime: 0.5, // 拖尾消失时间
  18. minSeg: 1, // 最小分段
  19. stroke: 30, // 拖尾宽度
  20. fastMode: false // 快速模式
  21. };
  22. // 预设颜色
  23. private trailColors = {
  24. default: new Color(255, 255, 0, 255), // 黄色
  25. white: new Color(255, 255, 255, 255), // 白色
  26. fire: new Color(255, 100, 0, 255), // 橙红色
  27. gold: new Color(255, 200, 80, 255), // 金黄(更接近外黄效果)
  28. ice: new Color(0, 200, 255, 255), // 冰蓝色
  29. poison: new Color(100, 255, 0, 255), // 毒绿色
  30. electric: new Color(200, 0, 255, 255) // 紫色
  31. };
  32. onLoad() {
  33. this.initializeTrail();
  34. }
  35. /**
  36. * 初始化拖尾效果
  37. */
  38. private initializeTrail() {
  39. if (!this.motionStreak) {
  40. // 尝试从子节点中查找MotionStreak组件
  41. this.motionStreak = this.getComponentInChildren(MotionStreak);
  42. if (!this.motionStreak) {
  43. // 尝试从当前节点获取
  44. this.motionStreak = this.getComponent(MotionStreak);
  45. }
  46. }
  47. if (this.motionStreak) {
  48. this.applyTrailConfig();
  49. }
  50. }
  51. /**
  52. * 应用拖尾配置
  53. */
  54. private applyTrailConfig() {
  55. if (!this.motionStreak) return;
  56. this.motionStreak.fadeTime = this.trailConfig.fadeTime;
  57. this.motionStreak.minSeg = this.trailConfig.minSeg;
  58. this.motionStreak.stroke = this.trailConfig.stroke;
  59. this.motionStreak.fastMode = this.trailConfig.fastMode;
  60. // 保持当前颜色,不在通用配置中强制重置为白色,避免覆盖武器专属颜色
  61. }
  62. /**
  63. * 设置拖尾颜色
  64. * @param colorType 颜色类型
  65. */
  66. public setTrailColor(colorType: 'default' | 'white' | 'fire' | 'ice' | 'poison' | 'electric') {
  67. if (!this.motionStreak) return;
  68. const color = this.trailColors[colorType];
  69. if (color) {
  70. this.motionStreak.color = color;
  71. }
  72. }
  73. /**
  74. * 设置自定义拖尾颜色
  75. * @param color 颜色
  76. */
  77. public setCustomTrailColor(color: Color) {
  78. if (!this.motionStreak) return;
  79. this.motionStreak.color = color;
  80. }
  81. /**
  82. * 设置拖尾宽度
  83. * @param width 宽度
  84. */
  85. public setTrailWidth(width: number) {
  86. if (!this.motionStreak) return;
  87. this.trailConfig.stroke = width;
  88. this.motionStreak.stroke = width;
  89. }
  90. /**
  91. * 设置拖尾消失时间
  92. * @param fadeTime 消失时间
  93. */
  94. public setTrailFadeTime(fadeTime: number) {
  95. if (!this.motionStreak) return;
  96. this.trailConfig.fadeTime = fadeTime;
  97. this.motionStreak.fadeTime = fadeTime;
  98. }
  99. /**
  100. * 设置拖尾最小分段(越小越平滑,减少三角形感)
  101. * @param minSeg 最小分段
  102. */
  103. public setTrailMinSeg(minSeg: number) {
  104. if (!this.motionStreak) return;
  105. this.trailConfig.minSeg = minSeg;
  106. this.motionStreak.minSeg = minSeg;
  107. }
  108. /**
  109. * 设置拖尾纹理
  110. * @param texture 纹理
  111. */
  112. public setTrailTexture(texture: Texture2D) {
  113. if (!this.motionStreak) return;
  114. this.motionStreak.texture = texture;
  115. if (this.secondaryStreak) {
  116. this.secondaryStreak.texture = texture;
  117. }
  118. }
  119. /**
  120. * 设置快速模式(拖尾响应更灵敏)
  121. */
  122. public setFastMode(enabled: boolean) {
  123. if (!this.motionStreak) return;
  124. this.trailConfig.fastMode = enabled;
  125. this.motionStreak.fastMode = enabled;
  126. }
  127. /**
  128. * 预设:火焰喷射拖尾(用于秋葵导弹)
  129. */
  130. public applyPresetRocket() {
  131. if (!this.motionStreak) return;
  132. // 颜色:火焰橙红
  133. this.setTrailColor('fire');
  134. // 更粗的拖尾,形成喷焰柱效果
  135. this.setTrailWidth(36);
  136. // 更短的消失时间,拖尾更紧凑
  137. this.setTrailFadeTime(0.14);
  138. // 更小的分段让曲线更贴合,避免顶部太宽的三角形感
  139. this.setTrailMinSeg(0.05);
  140. // 启用快速模式,响应更快
  141. this.setFastMode(true);
  142. // 在下一帧再次强制颜色,防止其他初始化流程覆盖颜色(例如材质或默认值)
  143. this.scheduleOnce(() => {
  144. if (this.motionStreak) {
  145. this.motionStreak.color = this.trailColors.fire;
  146. }
  147. }, 0);
  148. }
  149. /**
  150. * 启用拖尾效果
  151. */
  152. public enableTrail() {
  153. if (this.motionStreak) {
  154. this.motionStreak.enabled = true;
  155. }
  156. }
  157. /**
  158. * 禁用拖尾效果
  159. */
  160. public disableTrail() {
  161. if (this.motionStreak) {
  162. this.motionStreak.enabled = false;
  163. }
  164. }
  165. /**
  166. * 重置拖尾效果
  167. */
  168. public resetTrail() {
  169. if (this.motionStreak) {
  170. this.motionStreak.reset();
  171. }
  172. if (this.secondaryStreak) {
  173. this.secondaryStreak.reset();
  174. }
  175. }
  176. onDestroy() {
  177. // 清理资源
  178. this.motionStreak = null;
  179. this.secondaryStreak = null;
  180. }
  181. /** 创建或获取次级拖尾(用于双层效果) */
  182. private getOrCreateSecondaryStreak(): MotionStreak | null {
  183. if (!this.motionStreak) return null;
  184. if (this.secondaryStreak && this.secondaryStreak.isValid) return this.secondaryStreak;
  185. try {
  186. const hostNode = this.motionStreak.node;
  187. // 为次级拖尾创建一个子节点,避免与主拖尾同节点可能产生的覆盖/冲突
  188. const child = new Node('TrailEffectSecondary');
  189. hostNode.addChild(child);
  190. this.secondaryStreak = child.addComponent(MotionStreak);
  191. // 复制基础纹理与参数
  192. this.secondaryStreak.texture = this.motionStreak.texture;
  193. this.secondaryStreak.minSeg = this.trailConfig.minSeg;
  194. this.secondaryStreak.fadeTime = this.trailConfig.fadeTime;
  195. this.secondaryStreak.stroke = this.trailConfig.stroke;
  196. this.secondaryStreak.fastMode = this.trailConfig.fastMode;
  197. return this.secondaryStreak;
  198. } catch (e) {
  199. console.warn('[BulletTrailController] 创建次级拖尾失败:', e);
  200. return null;
  201. }
  202. }
  203. /**
  204. * 预设:双层喷焰(边缘橙红,中心白色)
  205. */
  206. public applyPresetRocketDualLayer() {
  207. if (!this.motionStreak) return;
  208. // 主拖尾:中心白色,稍窄
  209. this.setTrailWidth(24);
  210. this.setTrailFadeTime(0.5);
  211. this.setTrailMinSeg(1);
  212. this.setFastMode(false);
  213. this.setTrailColor('white');
  214. // 次级拖尾:边缘橙红,更宽
  215. const secondary = this.getOrCreateSecondaryStreak();
  216. if (secondary) {
  217. secondary.stroke = 30;
  218. secondary.fadeTime = 0.5;
  219. secondary.minSeg = 1;
  220. secondary.fastMode = false;
  221. // 使用金黄色增强外层可见性
  222. secondary.color = this.trailColors.gold;
  223. }
  224. // 保护色:下一帧再次写入
  225. this.scheduleOnce(() => {
  226. if (this.motionStreak && this.motionStreak.isValid) {
  227. this.motionStreak.color = this.trailColors.white;
  228. }
  229. if (this.secondaryStreak && this.secondaryStreak.isValid) {
  230. this.secondaryStreak.color = this.trailColors.gold;
  231. }
  232. }, 0);
  233. }
  234. }