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