Newer
Older
DungeonShooting / DungeonShooting_Godot / src / framework / ActivityObject.cs
@lijincheng lijincheng on 11 Nov 2022 19 KB 添加Role状态控制器
  1.  
  2. using System;
  3. using System.Collections.Generic;
  4. using Godot;
  5. using Plugin;
  6.  
  7. /// <summary>
  8. /// 房间内活动物体基类
  9. /// </summary>
  10. public abstract class ActivityObject : KinematicBody2D
  11. {
  12. /// <summary>
  13. /// 当前物体类型id, 用于区分是否是同一种物体, 如果不是通过 ActivityObject.Create() 函数创建出来的对象那么 ItemId 为 null
  14. /// </summary>
  15. public string ItemId { get; internal set; }
  16. /// <summary>
  17. /// 是否放入 ySort 节点下
  18. /// </summary>
  19. public bool UseYSort { get; }
  20. /// <summary>
  21. /// 当前物体显示的精灵图像, 节点名称必须叫 "AnimatedSprite", 类型为 AnimatedSprite
  22. /// </summary>
  23. public AnimatedSprite AnimatedSprite { get; }
  24.  
  25. /// <summary>
  26. /// 当前物体显示的阴影图像, 节点名称必须叫 "ShadowSprite", 类型为 Sprite
  27. /// </summary>
  28. public Sprite ShadowSprite { get; }
  29.  
  30. /// <summary>
  31. /// 当前物体碰撞器节点, 节点名称必须叫 "Collision", 类型为 CollisionShape2D
  32. /// </summary>
  33. public CollisionShape2D Collision { get; }
  34.  
  35. /// <summary>
  36. /// 是否调用过 Destroy() 函数
  37. /// </summary>
  38. public bool IsDestroyed { get; private set; }
  39.  
  40. /// <summary>
  41. /// 是否正在投抛过程中
  42. /// </summary>
  43. public bool IsThrowing => _throwData != null && !_throwData.IsOver;
  44.  
  45. /// <summary>
  46. /// 阴影偏移
  47. /// </summary>
  48. public Vector2 ShadowOffset { get; protected set; } = new Vector2(0, 2);
  49.  
  50. //组件集合
  51. private List<KeyValuePair<Type, Component>> _components = new List<KeyValuePair<Type, Component>>();
  52. private bool initShadow;
  53. private string _prevAnimation;
  54. private int _prevAnimationFrame;
  55.  
  56. //存储投抛该物体时所产生的数据
  57. private ObjectThrowData _throwData;
  58.  
  59. public ActivityObject(string scenePath)
  60. {
  61. //加载预制体
  62. var tempPrefab = ResourceManager.Load<PackedScene>(scenePath);
  63. if (tempPrefab == null)
  64. {
  65. throw new Exception("创建 ActivityObject 没有找到指定挂载的预制体: " + scenePath);
  66. }
  67.  
  68. var tempNode = tempPrefab.Instance<ActivityObjectTemplate>();
  69. ZIndex = tempNode.ZIndex;
  70. CollisionLayer = tempNode.CollisionLayer;
  71. CollisionMask = tempNode.CollisionMask;
  72. UseYSort = tempNode.UseYSort;
  73.  
  74. //移动子节点
  75. var count = tempNode.GetChildCount();
  76. for (int i = 0; i < count; i++)
  77. {
  78. var body = tempNode.GetChild(0);
  79. tempNode.RemoveChild(body);
  80. AddChild(body);
  81. switch (body.Name)
  82. {
  83. case "AnimatedSprite":
  84. AnimatedSprite = (AnimatedSprite)body;
  85. break;
  86. case "ShadowSprite":
  87. ShadowSprite = (Sprite)body;
  88. ShadowSprite.Visible = false;
  89. ShadowSprite.ZIndex = -5;
  90. break;
  91. case "Collision":
  92. Collision = (CollisionShape2D)body;
  93. break;
  94. }
  95. }
  96. }
  97.  
  98. /// <summary>
  99. /// 显示阴影
  100. /// </summary>
  101. public void ShowShadowSprite()
  102. {
  103. if (!initShadow)
  104. {
  105. initShadow = true;
  106. ShadowSprite.Material = ResourceManager.BlendMaterial;
  107. }
  108.  
  109. var anim = AnimatedSprite.Animation;
  110. var frame = AnimatedSprite.Frame;
  111. if (_prevAnimation != anim || _prevAnimationFrame != frame)
  112. {
  113. //切换阴影动画
  114. ShadowSprite.Texture = AnimatedSprite.Frames.GetFrame(anim, frame);
  115. }
  116. _prevAnimation = anim;
  117. _prevAnimationFrame = frame;
  118. CalcShadow();
  119. ShadowSprite.Visible = true;
  120. }
  121.  
  122. /// <summary>
  123. /// 隐藏阴影
  124. /// </summary>
  125. public void HideShadowSprite()
  126. {
  127. ShadowSprite.Visible = false;
  128. }
  129.  
  130. /// <summary>
  131. /// 设置默认序列帧动画的第一帧, 即将删除, 请直接设置 AnimatedSprite.Frames
  132. /// </summary>
  133. [Obsolete]
  134. public void SetDefaultTexture(Texture texture)
  135. {
  136. if (AnimatedSprite.Frames == null)
  137. {
  138. SpriteFrames spriteFrames = new SpriteFrames();
  139. AnimatedSprite.Frames = spriteFrames;
  140. spriteFrames.AddFrame("default", texture);
  141. }
  142. else
  143. {
  144. SpriteFrames spriteFrames = AnimatedSprite.Frames;
  145. spriteFrames.SetFrame("default", 0, texture);
  146. }
  147.  
  148. AnimatedSprite.Animation = "default";
  149. AnimatedSprite.Playing = true;
  150. }
  151.  
  152. /// <summary>
  153. /// 获取当前序列帧动画的 Texture
  154. /// </summary>
  155. public Texture GetCurrentTexture()
  156. {
  157. return AnimatedSprite.Frames.GetFrame(AnimatedSprite.Name, AnimatedSprite.Frame);
  158. }
  159.  
  160. /// <summary>
  161. /// 获取默认序列帧动画的第一帧
  162. /// </summary>
  163. public Texture GetDefaultTexture()
  164. {
  165. return AnimatedSprite.Frames.GetFrame("default", 0);
  166. }
  167.  
  168. /// <summary>
  169. /// 返回是否能与其他ActivityObject互动
  170. /// </summary>
  171. /// <param name="master">触发者</param>
  172. public virtual CheckInteractiveResult CheckInteractive(ActivityObject master)
  173. {
  174. return new CheckInteractiveResult(this);
  175. }
  176.  
  177. /// <summary>
  178. /// 与其它ActivityObject互动时调用, 如果要检测是否能互动请 CheckInteractive() 函数, 如果直接调用该函数那么属于强制互动行为, 例如子弹碰到物体
  179. /// </summary>
  180. /// <param name="master">触发者</param>
  181. public virtual void Interactive(ActivityObject master)
  182. {
  183. }
  184.  
  185. /// <summary>
  186. /// 投抛该物体达到最高点时调用
  187. /// </summary>
  188. protected virtual void OnThrowMaxHeight(float height)
  189. {
  190. }
  191.  
  192. /// <summary>
  193. /// 投抛状态下第一次接触地面时调用, 之后的回弹落地将不会调用该函数
  194. /// </summary>
  195. protected virtual void OnFirstFallToGround()
  196. {
  197. }
  198.  
  199. /// <summary>
  200. /// 投抛状态下每次接触地面时调用
  201. /// </summary>
  202. protected virtual void OnFallToGround()
  203. {
  204. }
  205.  
  206. /// <summary>
  207. /// 投抛结束时调用
  208. /// </summary>
  209. protected virtual void OnThrowOver()
  210. {
  211. }
  212.  
  213. /// <summary>
  214. /// 当前物体销毁时调用, 销毁物体请调用 Destroy() 函数
  215. /// </summary>
  216. protected virtual void OnDestroy()
  217. {
  218. }
  219.  
  220. /// <summary>
  221. /// 拾起一个 node 节点
  222. /// </summary>
  223. public void Pickup()
  224. {
  225. var parent = GetParent();
  226. if (parent != null)
  227. {
  228. if (IsThrowing)
  229. {
  230. StopThrow();
  231. }
  232.  
  233. parent.RemoveChild(this);
  234. }
  235. }
  236.  
  237. /// <summary>
  238. /// 将一个节点扔到地上, 并设置显示的阴影
  239. /// </summary>
  240. public virtual void PutDown()
  241. {
  242. var parent = GetParent();
  243. var root = GameApplication.Instance.Room.GetRoot(UseYSort);
  244. if (parent != root)
  245. {
  246. if (parent != null)
  247. {
  248. parent.RemoveChild(this);
  249. }
  250.  
  251. root.AddChild(this);
  252. }
  253.  
  254. if (IsInsideTree())
  255. {
  256. ShowShadowSprite();
  257. }
  258. else
  259. {
  260. //注意需要延时调用
  261. CallDeferred(nameof(ShowShadowSprite));
  262. }
  263. }
  264.  
  265. /// <summary>
  266. /// 将一个节点扔到地上, 并设置显示的阴影
  267. /// </summary>
  268. /// <param name="position">放置的位置</param>
  269. public void PutDown(Vector2 position)
  270. {
  271. PutDown();
  272. Position = position;
  273. }
  274.  
  275. /// <summary>
  276. /// 将该节点投抛出去
  277. /// </summary>
  278. /// <param name="size">碰撞器大小</param>
  279. /// <param name="start">起始坐标 (全局)</param>
  280. /// <param name="startHeight">起始高度</param>
  281. /// <param name="direction">投抛角度 (0-360)</param>
  282. /// <param name="xSpeed">移动速度</param>
  283. /// <param name="ySpeed">下坠速度</param>
  284. /// <param name="rotate">旋转速度</param>
  285. /// <param name="bounce">落地时是否回弹</param>
  286. /// <param name="bounceStrength">落地回弹力度, 1为不消耗能量, 值越小回弹力度越小</param>
  287. /// <param name="bounceSpeed">落地回弹后的速度, 1为不消速度, 值越小回弹速度消耗越大</param>
  288. public void Throw(Vector2 size, Vector2 start, float startHeight, float direction, float xSpeed,
  289. float ySpeed, float rotate, bool bounce = false, float bounceStrength = 0.5f, float bounceSpeed = 0.8f)
  290. {
  291. if (_throwData == null)
  292. {
  293. _throwData = new ObjectThrowData();
  294. }
  295.  
  296. SetThrowCollision();
  297.  
  298. _throwData.IsOver = false;
  299. _throwData.Size = size;
  300. _throwData.StartPosition = _throwData.CurrPosition = start;
  301. _throwData.Direction = direction;
  302. _throwData.XSpeed = xSpeed;
  303. _throwData.YSpeed = ySpeed;
  304. _throwData.StartXSpeed = xSpeed;
  305. _throwData.StartYSpeed = ySpeed;
  306. _throwData.RotateSpeed = rotate;
  307. _throwData.LinearVelocity = new Vector2(_throwData.XSpeed, 0).Rotated(_throwData.Direction * Mathf.Pi / 180);
  308. _throwData.Y = startHeight;
  309. _throwData.Bounce = bounce;
  310. _throwData.BounceStrength = bounceStrength;
  311. _throwData.BounceSpeed = bounceSpeed;
  312.  
  313. _throwData.RectangleShape.Extents = _throwData.Size * 0.5f;
  314.  
  315. Throw();
  316. }
  317.  
  318. /// <summary>
  319. /// 强制停止投抛运动
  320. /// </summary>
  321. public void StopThrow()
  322. {
  323. _throwData.IsOver = true;
  324. RestoreCollision();
  325. }
  326.  
  327. public void AddComponent(Component component)
  328. {
  329. if (!ContainsComponent(component))
  330. {
  331. _components.Add(new KeyValuePair<Type, Component>(component.GetType(), component));
  332. component._SetActivityObject(this);
  333. component.OnMount();
  334. }
  335. }
  336.  
  337. public void RemoveComponent(Component component)
  338. {
  339. for (int i = 0; i < _components.Count; i++)
  340. {
  341. if (_components[i].Value == component)
  342. {
  343. _components.RemoveAt(i);
  344. component.OnUnMount();
  345. component._SetActivityObject(null);
  346. return;
  347. }
  348. }
  349. }
  350.  
  351. public Component GetComponent(Type type)
  352. {
  353. for (int i = 0; i < _components.Count; i++)
  354. {
  355. var temp = _components[i];
  356. if (temp.Key == type)
  357. {
  358. return temp.Value;
  359. }
  360. }
  361.  
  362. return null;
  363. }
  364.  
  365. public TC GetComponent<TC>() where TC : Component
  366. {
  367. var component = GetComponent(typeof(TC));
  368. if (component == null) return null;
  369. return (TC)component;
  370. }
  371.  
  372. public override void _Process(float delta)
  373. {
  374. //更新组件
  375. if (_components.Count > 0)
  376. {
  377. var arr = _components.ToArray();
  378. for (int i = 0; i < arr.Length; i++)
  379. {
  380. if (IsDestroyed) return;
  381. var temp = arr[i].Value;
  382. if (temp != null && temp.ActivityObject == this && temp.Enable)
  383. {
  384. if (!temp.IsStart)
  385. {
  386. temp.Ready();
  387. }
  388.  
  389. temp.Process(delta);
  390. }
  391. }
  392. }
  393.  
  394. //投抛计算
  395. if (_throwData != null && !_throwData.IsOver)
  396. {
  397. _throwData.LinearVelocity = MoveAndSlide(_throwData.LinearVelocity);
  398. Position = new Vector2(Position.x, Position.y - _throwData.YSpeed * delta);
  399. var rotate = GlobalRotationDegrees + _throwData.RotateSpeed * delta;
  400. GlobalRotationDegrees = rotate;
  401.  
  402. var pos = AnimatedSprite.GlobalPosition;
  403. ShadowSprite.GlobalRotationDegrees = rotate;
  404.  
  405. var ysp = _throwData.YSpeed;
  406.  
  407. _throwData.Y += _throwData.YSpeed * delta;
  408. _throwData.YSpeed -= GameConfig.G * delta;
  409.  
  410. //达到最高点
  411. if (ysp * _throwData.YSpeed < 0)
  412. {
  413. ZIndex = 0;
  414. OnThrowMaxHeight(_throwData.Y);
  415. }
  416.  
  417. //落地判断
  418. if (_throwData.Y <= 0)
  419. {
  420. Collision.GlobalPosition = pos;
  421.  
  422. _throwData.IsOver = true;
  423.  
  424. //第一次接触地面
  425. if (_throwData.FirstOver)
  426. {
  427. _throwData.FirstOver = false;
  428. OnFirstFallToGround();
  429. }
  430.  
  431. //如果落地高度不够低, 再抛一次
  432. if (_throwData.StartYSpeed > 1 && _throwData.Bounce)
  433. {
  434. _throwData.StartPosition = Position;
  435. _throwData.Y = 0;
  436. _throwData.XSpeed = _throwData.StartXSpeed = _throwData.StartXSpeed * _throwData.BounceSpeed;
  437. _throwData.YSpeed = _throwData.StartYSpeed = _throwData.StartYSpeed * _throwData.BounceStrength;
  438. _throwData.RotateSpeed = _throwData.RotateSpeed * _throwData.BounceStrength;
  439. _throwData.LinearVelocity *= _throwData.BounceSpeed;
  440. // _throwData.LinearVelocity =
  441. // new Vector2(_throwData.XSpeed, 0).Rotated(_throwData.Direction * Mathf.Pi / 180);
  442. _throwData.FirstOver = false;
  443. _throwData.IsOver = false;
  444.  
  445. OnFallToGround();
  446. }
  447. else //结束
  448. {
  449. OnFallToGround();
  450. ThrowOver();
  451. }
  452. }
  453. else
  454. {
  455. //碰撞器位置
  456. Collision.GlobalPosition = pos + new Vector2(0, _throwData.Y);
  457. }
  458. }
  459.  
  460. if (ShadowSprite.Visible)
  461. {
  462. //更新阴影贴图, 使其和动画一致
  463. var anim = AnimatedSprite.Animation;
  464. var frame = AnimatedSprite.Frame;
  465. if (_prevAnimation != anim || _prevAnimationFrame != frame)
  466. {
  467. //切换阴影动画
  468. ShadowSprite.Texture = AnimatedSprite.Frames.GetFrame(anim, AnimatedSprite.Frame);
  469. }
  470. _prevAnimation = anim;
  471. _prevAnimationFrame = frame;
  472. //计算阴影
  473. CalcShadow();
  474. }
  475.  
  476. }
  477.  
  478. /// <summary>
  479. /// 重新计算物体阴影的位置和旋转信息, 无论是否显示阴影
  480. /// </summary>
  481. public void CalcShadow()
  482. {
  483. //缩放
  484. ShadowSprite.Scale = AnimatedSprite.Scale;
  485. //阴影角度
  486. ShadowSprite.GlobalRotationDegrees = GlobalRotationDegrees;
  487. //阴影位置计算
  488. var pos = AnimatedSprite.GlobalPosition;
  489. if (_throwData != null && !_throwData.IsOver)
  490. {
  491. ShadowSprite.GlobalPosition = new Vector2(pos.x + ShadowOffset.x, pos.y + ShadowOffset.y + _throwData.Y);
  492. }
  493. else
  494. {
  495. ShadowSprite.GlobalPosition = pos + ShadowOffset;
  496. }
  497. }
  498.  
  499. public override void _PhysicsProcess(float delta)
  500. {
  501. //更新组件
  502. if (_components.Count > 0)
  503. {
  504. var arr = _components.ToArray();
  505. for (int i = 0; i < arr.Length; i++)
  506. {
  507. if (IsDestroyed) return;
  508. var temp = arr[i].Value;
  509. if (temp != null && temp.ActivityObject == this && temp.Enable)
  510. {
  511. if (!temp.IsStart)
  512. {
  513. temp.Ready();
  514. }
  515.  
  516. temp.PhysicsProcess(delta);
  517. }
  518. }
  519. }
  520. }
  521.  
  522. /// <summary>
  523. /// 销毁物体
  524. /// </summary>
  525. public void Destroy()
  526. {
  527. if (IsDestroyed)
  528. {
  529. return;
  530. }
  531.  
  532. IsDestroyed = true;
  533. OnDestroy();
  534. QueueFree();
  535. var arr = _components.ToArray();
  536. for (int i = 0; i < arr.Length; i++)
  537. {
  538. arr[i].Value?.Destroy();
  539. }
  540. }
  541.  
  542. /// <summary>
  543. /// 延时销毁
  544. /// </summary>
  545. public void DelayDestroy()
  546. {
  547. CallDeferred(nameof(Destroy));
  548. }
  549.  
  550. //返回该组件是否被挂载到当前物体上
  551. private bool ContainsComponent(Component component)
  552. {
  553. for (int i = 0; i < _components.Count; i++)
  554. {
  555. if (_components[i].Value == component)
  556. {
  557. return true;
  558. }
  559. }
  560.  
  561. return false;
  562. }
  563.  
  564. /// <summary>
  565. /// 触发投抛动作
  566. /// </summary>
  567. private void Throw()
  568. {
  569. var parent = GetParent();
  570. //投抛时必须要加入 sortRoot 节点下
  571. var root = GameApplication.Instance.Room.GetRoot(false);
  572. var sortRoot = GameApplication.Instance.Room.GetRoot(true);
  573. if (parent == null)
  574. {
  575. sortRoot.AddChild(this);
  576. }
  577. else if (parent == root)
  578. {
  579. parent.RemoveChild(this);
  580. sortRoot.AddChild(this);
  581. }
  582.  
  583. GlobalPosition = _throwData.StartPosition + new Vector2(0, -_throwData.Y);
  584.  
  585. //显示阴影
  586. ShowShadowSprite();
  587. }
  588.  
  589. /// <summary>
  590. /// 设置投抛状态下的碰撞器
  591. /// </summary>
  592. private void SetThrowCollision()
  593. {
  594. if (_throwData != null && _throwData.UseOrigin)
  595. {
  596. _throwData.OriginShape = Collision.Shape;
  597. _throwData.OriginPosition = Collision.Position;
  598. _throwData.OriginRotation = Collision.Rotation;
  599. _throwData.OriginScale = Collision.Scale;
  600. _throwData.OriginZIndex = ZIndex;
  601. _throwData.OriginCollisionEnable = Collision.Disabled;
  602. _throwData.OriginCollisionPosition = Collision.Position;
  603. _throwData.OriginCollisionRotation = Collision.Rotation;
  604. _throwData.OriginCollisionScale = Collision.Scale;
  605. _throwData.OriginCollisionMask = CollisionMask;
  606. _throwData.OriginCollisionLayer = CollisionLayer;
  607.  
  608. if (_throwData.RectangleShape == null)
  609. {
  610. _throwData.RectangleShape = new RectangleShape2D();
  611. }
  612.  
  613. Collision.Shape = _throwData.RectangleShape;
  614. //Collision.Position = Vector2.Zero;
  615. Collision.Rotation = 0;
  616. Collision.Scale = Vector2.One;
  617. ZIndex = 0;
  618. //ZIndex = 2;
  619. Collision.Disabled = false;
  620. Collision.Position = Vector2.Zero;
  621. Collision.Rotation = 0;
  622. Collision.Scale = Vector2.One;
  623. CollisionMask = 1;
  624. CollisionLayer = 0;
  625. _throwData.UseOrigin = false;
  626. }
  627. }
  628.  
  629. /// <summary>
  630. /// 重置碰撞器
  631. /// </summary>
  632. private void RestoreCollision()
  633. {
  634. if (_throwData != null && !_throwData.UseOrigin)
  635. {
  636. Collision.Shape = _throwData.OriginShape;
  637. Collision.Position = _throwData.OriginPosition;
  638. Collision.Rotation = _throwData.OriginRotation;
  639. Collision.Scale = _throwData.OriginScale;
  640. ZIndex = _throwData.OriginZIndex;
  641. Collision.Disabled = _throwData.OriginCollisionEnable;
  642. Collision.Position = _throwData.OriginCollisionPosition;
  643. Collision.Rotation = _throwData.OriginCollisionRotation;
  644. Collision.Scale = _throwData.OriginCollisionScale;
  645. CollisionMask = _throwData.OriginCollisionMask;
  646. CollisionLayer = _throwData.OriginCollisionLayer;
  647.  
  648. _throwData.UseOrigin = true;
  649. }
  650. }
  651.  
  652. /// <summary>
  653. /// 投抛结束
  654. /// </summary>
  655. private void ThrowOver()
  656. {
  657. GetParent().RemoveChild(this);
  658. GameApplication.Instance.Room.GetRoot(UseYSort).AddChild(this);
  659. RestoreCollision();
  660.  
  661. OnThrowOver();
  662. }
  663.  
  664. /// <summary>
  665. /// 通过 ItemId 实例化 ActivityObject 对象
  666. /// </summary>
  667. public static T Create<T>(string itemId) where T : ActivityObject
  668. {
  669. return null;
  670. }
  671. }