FindItem.ts 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217
  1. import { _decorator, Component, EventTouch, instantiate, Node, Prefab, Slider, tween, Vec2, Vec3 } from 'cc';
  2. const { ccclass, property } = _decorator;
  3. // 物品数据类
  4. export class ItemData {
  5. position: Vec3 = new Vec3(0, 0, 0);
  6. scale: number = 1;
  7. }
  8. // 物品状态枚举
  9. export enum ItemState {
  10. EDIT, // 编辑状态
  11. NORMAL, // 正常状态
  12. FOUND, // 已找到状态
  13. HINT // 提示状态
  14. }
  15. @ccclass
  16. export default class FindItem extends Component {
  17. @property({ type: Node })
  18. spineNode: Node = null;
  19. @property({ type: Slider })
  20. scaleSlider: Slider = null; // 缩放滑动条
  21. @property({ type: Node })
  22. redFrame: Node = null; // 红色框
  23. @property({ type: Node })
  24. blueFrame: Node = null; // 蓝色框
  25. // 组件数据
  26. private data: ItemData = {
  27. position: new Vec3(0, 0, 0),
  28. scale: 1
  29. };
  30. // 当前状态
  31. private currentState: ItemState = ItemState.EDIT;
  32. // 拖动相关
  33. private isDragging: boolean = false;
  34. // 缩放范围
  35. private readonly MIN_SCALE: number = 0.1;
  36. private readonly MAX_SCALE: number = 1.5;
  37. onLoad() {
  38. this.setupEventListeners();
  39. }
  40. start() {
  41. this.initializeFromData();
  42. this.setState(this.currentState);
  43. }
  44. onDestroy() {
  45. this.removeEventListeners();
  46. }
  47. // 设置事件监听
  48. private setupEventListeners() {
  49. this.node.on(Node.EventType.TOUCH_START, this.onTouchStart, this);
  50. this.node.on(Node.EventType.TOUCH_MOVE, this.onTouchMove, this);
  51. this.node.on(Node.EventType.TOUCH_END, this.onTouchEnd, this);
  52. this.node.on(Node.EventType.TOUCH_CANCEL, this.onTouchEnd, this);
  53. }
  54. // 移除事件监听
  55. private removeEventListeners() {
  56. this.node.off(Node.EventType.TOUCH_START, this.onTouchStart, this);
  57. this.node.off(Node.EventType.TOUCH_MOVE, this.onTouchMove, this);
  58. this.node.off(Node.EventType.TOUCH_END, this.onTouchEnd, this);
  59. this.node.off(Node.EventType.TOUCH_CANCEL, this.onTouchEnd, this);
  60. }
  61. // 根据数据初始化
  62. private initializeFromData() {
  63. this.node.setPosition(this.data.position);
  64. this.spineNode.setScale(this.data.scale, this.data.scale, 1);
  65. if (this.scaleSlider) {
  66. const sliderComp = this.scaleSlider.getComponent(Slider);
  67. if (sliderComp) {
  68. sliderComp.progress = (this.data.scale - this.MIN_SCALE) / (this.MAX_SCALE - this.MIN_SCALE);
  69. }
  70. }
  71. }
  72. // 设置状态
  73. public setState(state: ItemState) {
  74. this.currentState = state;
  75. this.updateVisualState();
  76. }
  77. // 更新视觉状态
  78. private updateVisualState() {
  79. // 重置所有状态
  80. this.scaleSlider.node.active = false;
  81. this.redFrame.active = false;
  82. this.blueFrame.active = false;
  83. switch (this.currentState) {
  84. case ItemState.EDIT:
  85. this.scaleSlider.node.active = true;
  86. break;
  87. case ItemState.NORMAL:
  88. // 正常状态,无特殊显示
  89. break;
  90. case ItemState.FOUND:
  91. this.redFrame.active = true;
  92. break;
  93. case ItemState.HINT:
  94. this.blueFrame.active = true;
  95. this.startBlueFrameAnimation();
  96. break;
  97. }
  98. }
  99. // 开始蓝色框动画
  100. private startBlueFrameAnimation() {
  101. tween(this.blueFrame)
  102. .to(0.5, { scale: new Vec3(1.2, 1.2, 1) })
  103. .to(0.5, { scale: new Vec3(1, 1, 1) })
  104. .repeatForever()
  105. .start();
  106. }
  107. _touchStartPos: Vec2 = new Vec2(0, 0);
  108. _nodeStartPos: Vec3 = new Vec3(0, 0, 0);
  109. // 触摸开始
  110. private onTouchStart(event: EventTouch) {
  111. const touch = event.touch;
  112. if (this.currentState === ItemState.EDIT) {
  113. this._touchStartPos = new Vec2(touch.getUILocation().x, touch.getUILocation().y);
  114. this._nodeStartPos = this.node.getPosition();
  115. // 编辑状态可以拖动
  116. this.isDragging = true;
  117. } else if (this.currentState === ItemState.NORMAL || this.currentState === ItemState.HINT) {
  118. // 正常状态和提示状态可以点击
  119. // 这里只是标记,在touchEnd时处理点击
  120. }
  121. }
  122. // 触摸移动
  123. private onTouchMove(event: EventTouch) {
  124. if (this.isDragging && this.currentState === ItemState.EDIT) {
  125. const touchLoc = event.getUILocation();
  126. var deltaX = touchLoc.x - this._touchStartPos.x;
  127. var deltaY = touchLoc.y - this._touchStartPos.y;
  128. this.node.setPosition(this._nodeStartPos.x + deltaX, this._nodeStartPos.y + deltaY, 0);
  129. this.data.position.set(this.node.position);
  130. }
  131. }
  132. // 触摸结束
  133. private onTouchEnd(event: EventTouch) {
  134. if (this.isDragging) {
  135. this.isDragging = false;
  136. } else {
  137. // 处理点击
  138. if (this.currentState === ItemState.NORMAL || this.currentState === ItemState.HINT) {
  139. this.setState(ItemState.FOUND);
  140. this.node.emit("itemFound", this);
  141. }
  142. }
  143. }
  144. // 缩放滑动条值改变
  145. private onScaleSliderChanged(slider: Slider) {
  146. const newScale = this.MIN_SCALE + slider.progress * (this.MAX_SCALE - this.MIN_SCALE);
  147. this.spineNode.setScale(newScale, newScale, 1);
  148. this.data.scale = newScale;
  149. }
  150. // 公共接口:设置数据
  151. public setData(data: ItemData) {
  152. this.data = { ...data };
  153. this.initializeFromData();
  154. }
  155. // 公共接口:获取数据
  156. public getData(): ItemData {
  157. return { ...this.data };
  158. }
  159. // 公共接口:获取当前状态
  160. public getState(): ItemState {
  161. return this.currentState;
  162. }
  163. // 公共接口:切换到编辑模式
  164. public enterEditMode() {
  165. this.setState(ItemState.EDIT);
  166. }
  167. // 公共接口:退出编辑模式
  168. public exitEditMode() {
  169. this.setState(ItemState.NORMAL);
  170. }
  171. // 公共接口:显示提示
  172. public showHint() {
  173. this.setState(ItemState.HINT);
  174. }
  175. addSpineContentByPrefab(prefab: Prefab) {
  176. const spineNode = instantiate(prefab);
  177. this.spineNode.addChild(spineNode);
  178. }
  179. }