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