Newer
Older
DungeonShooting / DungeonShooting_Godot / src / framework / ActivityObject.cs
@小李xl 小李xl on 12 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. /// 是否调用过 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. /// <summary>
  328. /// 往当前物体上挂载一个组件
  329. /// </summary>
  330. /// <param name="component">组件对象</param>
  331. public void AddComponent(Component component)
  332. {
  333. if (!ContainsComponent(component))
  334. {
  335. _components.Add(new KeyValuePair<Type, Component>(component.GetType(), component));
  336. component._SetActivityObject(this);
  337. component.OnMount();
  338. }
  339. }
  340.  
  341. /// <summary>
  342. /// 移除一个组件
  343. /// </summary>
  344. /// <param name="component">组件对象</param>
  345. public void RemoveComponent(Component component)
  346. {
  347. for (int i = 0; i < _components.Count; i++)
  348. {
  349. if (_components[i].Value == component)
  350. {
  351. _components.RemoveAt(i);
  352. component.OnUnMount();
  353. component._SetActivityObject(null);
  354. return;
  355. }
  356. }
  357. }
  358.  
  359. /// <summary>
  360. /// 根据类型获取一个组件
  361. /// </summary>
  362. public Component GetComponent(Type type)
  363. {
  364. for (int i = 0; i < _components.Count; i++)
  365. {
  366. var temp = _components[i];
  367. if (temp.Key == type)
  368. {
  369. return temp.Value;
  370. }
  371. }
  372.  
  373. return null;
  374. }
  375.  
  376. /// <summary>
  377. /// 根据类型获取一个组件
  378. /// </summary>
  379. public TC GetComponent<TC>() where TC : Component
  380. {
  381. var component = GetComponent(typeof(TC));
  382. if (component == null) return null;
  383. return (TC)component;
  384. }
  385.  
  386. public override void _Process(float delta)
  387. {
  388. //更新组件
  389. if (_components.Count > 0)
  390. {
  391. var arr = _components.ToArray();
  392. for (int i = 0; i < arr.Length; i++)
  393. {
  394. if (IsDestroyed) return;
  395. var temp = arr[i].Value;
  396. if (temp != null && temp.ActivityObject == this && temp.Enable)
  397. {
  398. if (!temp.IsStart)
  399. {
  400. temp.Ready();
  401. }
  402.  
  403. temp.Process(delta);
  404. }
  405. }
  406. }
  407.  
  408. //投抛计算
  409. if (_throwData != null && !_throwData.IsOver)
  410. {
  411. _throwData.LinearVelocity = MoveAndSlide(_throwData.LinearVelocity);
  412. Position = new Vector2(Position.x, Position.y - _throwData.YSpeed * delta);
  413. var rotate = GlobalRotationDegrees + _throwData.RotateSpeed * delta;
  414. GlobalRotationDegrees = rotate;
  415.  
  416. var pos = AnimatedSprite.GlobalPosition;
  417. ShadowSprite.GlobalRotationDegrees = rotate;
  418.  
  419. var ysp = _throwData.YSpeed;
  420.  
  421. _throwData.Y += _throwData.YSpeed * delta;
  422. _throwData.YSpeed -= GameConfig.G * delta;
  423.  
  424. //达到最高点
  425. if (ysp * _throwData.YSpeed < 0)
  426. {
  427. ZIndex = 0;
  428. OnThrowMaxHeight(_throwData.Y);
  429. }
  430.  
  431. //落地判断
  432. if (_throwData.Y <= 0)
  433. {
  434. Collision.GlobalPosition = pos;
  435.  
  436. _throwData.IsOver = true;
  437.  
  438. //第一次接触地面
  439. if (_throwData.FirstOver)
  440. {
  441. _throwData.FirstOver = false;
  442. OnFirstFallToGround();
  443. }
  444.  
  445. //如果落地高度不够低, 再抛一次
  446. if (_throwData.StartYSpeed > 1 && _throwData.Bounce)
  447. {
  448. _throwData.StartPosition = Position;
  449. _throwData.Y = 0;
  450. _throwData.XSpeed = _throwData.StartXSpeed = _throwData.StartXSpeed * _throwData.BounceSpeed;
  451. _throwData.YSpeed = _throwData.StartYSpeed = _throwData.StartYSpeed * _throwData.BounceStrength;
  452. _throwData.RotateSpeed = _throwData.RotateSpeed * _throwData.BounceStrength;
  453. _throwData.LinearVelocity *= _throwData.BounceSpeed;
  454. // _throwData.LinearVelocity =
  455. // new Vector2(_throwData.XSpeed, 0).Rotated(_throwData.Direction * Mathf.Pi / 180);
  456. _throwData.FirstOver = false;
  457. _throwData.IsOver = false;
  458.  
  459. OnFallToGround();
  460. }
  461. else //结束
  462. {
  463. OnFallToGround();
  464. ThrowOver();
  465. }
  466. }
  467. else
  468. {
  469. //碰撞器位置
  470. Collision.GlobalPosition = pos + new Vector2(0, _throwData.Y);
  471. }
  472. }
  473.  
  474. if (ShadowSprite.Visible)
  475. {
  476. //更新阴影贴图, 使其和动画一致
  477. var anim = AnimatedSprite.Animation;
  478. var frame = AnimatedSprite.Frame;
  479. if (_prevAnimation != anim || _prevAnimationFrame != frame)
  480. {
  481. //切换阴影动画
  482. ShadowSprite.Texture = AnimatedSprite.Frames.GetFrame(anim, AnimatedSprite.Frame);
  483. }
  484. _prevAnimation = anim;
  485. _prevAnimationFrame = frame;
  486. //计算阴影
  487. CalcShadow();
  488. }
  489.  
  490. }
  491.  
  492. /// <summary>
  493. /// 重新计算物体阴影的位置和旋转信息, 无论是否显示阴影
  494. /// </summary>
  495. public void CalcShadow()
  496. {
  497. //缩放
  498. ShadowSprite.Scale = AnimatedSprite.Scale;
  499. //阴影角度
  500. ShadowSprite.GlobalRotationDegrees = GlobalRotationDegrees;
  501. //阴影位置计算
  502. var pos = AnimatedSprite.GlobalPosition;
  503. if (_throwData != null && !_throwData.IsOver)
  504. {
  505. ShadowSprite.GlobalPosition = new Vector2(pos.x + ShadowOffset.x, pos.y + ShadowOffset.y + _throwData.Y);
  506. }
  507. else
  508. {
  509. ShadowSprite.GlobalPosition = pos + ShadowOffset;
  510. }
  511. }
  512.  
  513. public override void _PhysicsProcess(float delta)
  514. {
  515. //更新组件
  516. if (_components.Count > 0)
  517. {
  518. var arr = _components.ToArray();
  519. for (int i = 0; i < arr.Length; i++)
  520. {
  521. if (IsDestroyed) return;
  522. var temp = arr[i].Value;
  523. if (temp != null && temp.ActivityObject == this && temp.Enable)
  524. {
  525. if (!temp.IsStart)
  526. {
  527. temp.Ready();
  528. }
  529.  
  530. temp.PhysicsProcess(delta);
  531. }
  532. }
  533. }
  534. }
  535.  
  536. /// <summary>
  537. /// 销毁物体
  538. /// </summary>
  539. public void Destroy()
  540. {
  541. if (IsDestroyed)
  542. {
  543. return;
  544. }
  545.  
  546. IsDestroyed = true;
  547. OnDestroy();
  548. QueueFree();
  549. var arr = _components.ToArray();
  550. for (int i = 0; i < arr.Length; i++)
  551. {
  552. arr[i].Value?.Destroy();
  553. }
  554. }
  555.  
  556. /// <summary>
  557. /// 延时销毁
  558. /// </summary>
  559. public void DelayDestroy()
  560. {
  561. CallDeferred(nameof(Destroy));
  562. }
  563.  
  564. //返回该组件是否被挂载到当前物体上
  565. private bool ContainsComponent(Component component)
  566. {
  567. for (int i = 0; i < _components.Count; i++)
  568. {
  569. if (_components[i].Value == component)
  570. {
  571. return true;
  572. }
  573. }
  574.  
  575. return false;
  576. }
  577.  
  578. /// <summary>
  579. /// 触发投抛动作
  580. /// </summary>
  581. private void Throw()
  582. {
  583. var parent = GetParent();
  584. //投抛时必须要加入 sortRoot 节点下
  585. var root = GameApplication.Instance.Room.GetRoot(false);
  586. var sortRoot = GameApplication.Instance.Room.GetRoot(true);
  587. if (parent == null)
  588. {
  589. sortRoot.AddChild(this);
  590. }
  591. else if (parent == root)
  592. {
  593. parent.RemoveChild(this);
  594. sortRoot.AddChild(this);
  595. }
  596.  
  597. GlobalPosition = _throwData.StartPosition + new Vector2(0, -_throwData.Y);
  598.  
  599. //显示阴影
  600. ShowShadowSprite();
  601. }
  602.  
  603. /// <summary>
  604. /// 设置投抛状态下的碰撞器
  605. /// </summary>
  606. private void SetThrowCollision()
  607. {
  608. if (_throwData != null && _throwData.UseOrigin)
  609. {
  610. _throwData.OriginShape = Collision.Shape;
  611. _throwData.OriginPosition = Collision.Position;
  612. _throwData.OriginRotation = Collision.Rotation;
  613. _throwData.OriginScale = Collision.Scale;
  614. _throwData.OriginZIndex = ZIndex;
  615. _throwData.OriginCollisionEnable = Collision.Disabled;
  616. _throwData.OriginCollisionPosition = Collision.Position;
  617. _throwData.OriginCollisionRotation = Collision.Rotation;
  618. _throwData.OriginCollisionScale = Collision.Scale;
  619. _throwData.OriginCollisionMask = CollisionMask;
  620. _throwData.OriginCollisionLayer = CollisionLayer;
  621.  
  622. if (_throwData.RectangleShape == null)
  623. {
  624. _throwData.RectangleShape = new RectangleShape2D();
  625. }
  626.  
  627. Collision.Shape = _throwData.RectangleShape;
  628. //Collision.Position = Vector2.Zero;
  629. Collision.Rotation = 0;
  630. Collision.Scale = Vector2.One;
  631. ZIndex = 0;
  632. //ZIndex = 2;
  633. Collision.Disabled = false;
  634. Collision.Position = Vector2.Zero;
  635. Collision.Rotation = 0;
  636. Collision.Scale = Vector2.One;
  637. CollisionMask = 1;
  638. CollisionLayer = 0;
  639. _throwData.UseOrigin = false;
  640. }
  641. }
  642.  
  643. /// <summary>
  644. /// 重置碰撞器
  645. /// </summary>
  646. private void RestoreCollision()
  647. {
  648. if (_throwData != null && !_throwData.UseOrigin)
  649. {
  650. Collision.Shape = _throwData.OriginShape;
  651. Collision.Position = _throwData.OriginPosition;
  652. Collision.Rotation = _throwData.OriginRotation;
  653. Collision.Scale = _throwData.OriginScale;
  654. ZIndex = _throwData.OriginZIndex;
  655. Collision.Disabled = _throwData.OriginCollisionEnable;
  656. Collision.Position = _throwData.OriginCollisionPosition;
  657. Collision.Rotation = _throwData.OriginCollisionRotation;
  658. Collision.Scale = _throwData.OriginCollisionScale;
  659. CollisionMask = _throwData.OriginCollisionMask;
  660. CollisionLayer = _throwData.OriginCollisionLayer;
  661.  
  662. _throwData.UseOrigin = true;
  663. }
  664. }
  665.  
  666. /// <summary>
  667. /// 投抛结束
  668. /// </summary>
  669. private void ThrowOver()
  670. {
  671. GetParent().RemoveChild(this);
  672. GameApplication.Instance.Room.GetRoot(UseYSort).AddChild(this);
  673. RestoreCollision();
  674.  
  675. OnThrowOver();
  676. }
  677.  
  678. /// <summary>
  679. /// 通过 ItemId 实例化 ActivityObject 对象
  680. /// </summary>
  681. public static T Create<T>(string itemId) where T : ActivityObject
  682. {
  683. return null;
  684. }
  685. }