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