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