WheelDialog.ts 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199
  1. import { _decorator, Component, Node, tween, Vec3 } from "cc";
  2. import BaseUI from "../../scripts/base/BaseUI";
  3. import { Hall } from "../hall/Hall";
  4. import { RewardLayer } from "../layer/RewardLayer";
  5. import { GoodsId } from "../../scripts/api/GoodsId";
  6. const { ccclass, property } = _decorator;
  7. @ccclass("WheelDialog")
  8. export class WheelDialog extends BaseUI {
  9. static async show(taskId: number) {
  10. let dialog = await Hall.ins.showLayer("prefab/play/WheelDialog");
  11. dialog.getComponent(WheelDialog).init(taskId);
  12. }
  13. private taskId: number;
  14. init(taskId: number) {
  15. this.taskId = taskId;
  16. this.requestAndStartSpin();
  17. }
  18. requestAndStartSpin() {
  19. // random 1-wheelRewardAllCount
  20. let index = Math.floor(Math.random() * this.wheelRewardAllCount) + 1;
  21. this.spinToIndex(index);
  22. }
  23. private rotateSprite: Node;
  24. private isSpinning: boolean = false;
  25. private currentAngle: number = 0;
  26. @property(Number)
  27. public wheelRewardAllCount: number = 8;
  28. @property(Number)
  29. public spinDuration: number = 3.0; // 轉動持續時間
  30. @property(Number)
  31. public spinRounds: number = 5; // 轉動圈數
  32. protected onLoad(): void {
  33. super.onLoad();
  34. this.rotateSprite = this.FindNode("rotateSprite");
  35. }
  36. update(deltaTime: number) {}
  37. protected simpleOnBtnClick(name: string): void {
  38. if (name.startsWith("btn_start_")) {
  39. let to = parseInt(name.replace("btn_start_", "")) - 1;
  40. console.warn("to", to);
  41. this.spinToIndex(to);
  42. return;
  43. }
  44. switch (name) {
  45. case "btn_spin":
  46. if (!this.isSpinning) {
  47. this.spinToIndex(2);
  48. }
  49. break;
  50. }
  51. }
  52. /**
  53. * 轉動到指定索引的獎品
  54. * @param index 獎品索引 (0 到 wheelRewardAllCount-1)
  55. */
  56. spinToIndex(index: number) {
  57. if (this.isSpinning) {
  58. console.warn("轉盤正在轉動中,請稍後再試");
  59. return;
  60. }
  61. this.resetWheel();
  62. // 確保索引在有效範圍內
  63. if (index < 0 || index >= this.wheelRewardAllCount) {
  64. console.error(
  65. `無效的獎品索引: ${index}, 有效範圍: 0-${this.wheelRewardAllCount - 1}`
  66. );
  67. return;
  68. }
  69. this.isSpinning = true;
  70. // 計算每個獎品的角度
  71. const anglePerReward = 360 / this.wheelRewardAllCount;
  72. // 計算目標角度
  73. // 轉盤順時針轉動,索引0在頂部12點鐘方向
  74. // 每個獎品區域的中心角度
  75. const targetAngle = anglePerReward * index + anglePerReward / 2;
  76. // 計算總轉動角度(多轉幾圈然後停在目標位置)
  77. // 從當前角度開始轉動
  78. const totalRotation =
  79. this.currentAngle + this.spinRounds * 360 + targetAngle;
  80. // 停止之前的動畫
  81. tween(this.rotateSprite).stop();
  82. // 開始新的轉動動畫
  83. tween(this.rotateSprite)
  84. .to(
  85. this.spinDuration,
  86. { angle: totalRotation },
  87. {
  88. easing: "expoOut", // 使用指數緩出效果,快速開始然後急劇減速
  89. }
  90. )
  91. .call(() => {
  92. // 動畫完成後的回調
  93. this.currentAngle = totalRotation;
  94. this.onSpinComplete(index);
  95. })
  96. .start();
  97. }
  98. /**
  99. * 轉動完成後的回調
  100. * @param index 最終停止的獎品索引
  101. */
  102. private onSpinComplete(index: number) {
  103. this.isSpinning = false;
  104. console.log(`轉盤停止在獎品索引: ${index}`);
  105. // 這裡可以添加獲獎邏輯
  106. this.onReward(index);
  107. }
  108. /**
  109. * 獲獎處理
  110. * @param index 獎品索引
  111. */
  112. private onReward(index: number) {
  113. console.log(`恭喜獲得獎品索引: ${index}`);
  114. RewardLayer.show(
  115. [
  116. {
  117. id: GoodsId.POG,
  118. count: 100,
  119. },
  120. ],
  121. () => {
  122. this.resetWheel();
  123. }
  124. );
  125. // 這裡可以觸發獲獎事件或顯示獲獎界面
  126. // 外部可以監聽這個事件來處理具體的獎品邏輯
  127. // EM.emit('wheel_reward', index);
  128. }
  129. /**
  130. * 重置轉盤角度
  131. */
  132. public resetWheel() {
  133. tween(this.rotateSprite).stop();
  134. this.rotateSprite.angle = 0;
  135. this.currentAngle = 0;
  136. this.isSpinning = false;
  137. }
  138. /**
  139. * 檢查轉盤是否正在轉動
  140. */
  141. public getIsSpinning(): boolean {
  142. return this.isSpinning;
  143. }
  144. /**
  145. * 設置轉盤配置
  146. * @param rewardCount 獎品總數
  147. * @param duration 轉動時間
  148. * @param rounds 轉動圈數
  149. */
  150. public setWheelConfig(
  151. rewardCount: number,
  152. duration: number = 3.0,
  153. rounds: number = 5
  154. ) {
  155. this.wheelRewardAllCount = rewardCount;
  156. this.spinDuration = duration;
  157. this.spinRounds = rounds;
  158. }
  159. /**
  160. * 開始轉動到指定索引
  161. * @param index 要轉到的獎品索引
  162. */
  163. public startSpin(index: number) {
  164. if (!this.isSpinning) {
  165. this.spinToIndex(index);
  166. }
  167. }
  168. }
  169. function Random() {
  170. throw new Error("Function not implemented.");
  171. }