Newer
Older
DungeonShooting / DungeonShooting_Godot / src / framework / activity / ActivityObject.cs
@lijincheng lijincheng on 25 Jul 2023 41 KB 调整部分 Ui 函数名称
  1.  
  2. using System;
  3. using System.Collections;
  4. using System.Collections.Generic;
  5. using Config;
  6. using Godot;
  7.  
  8. /// <summary>
  9. /// 房间内活动物体基类, 所有物体都必须继承该类,<br/>
  10. /// 该类提供基础物体运动模拟, 互动接口, 自定义组件, 协程等功能<br/>
  11. /// ActivityObject 子类实例化请不要直接使用 new, 而用该在类上标上 [Tool], 并在 ActivityObject.xlsx 配置文件中注册物体, 导出配置表后使用 ActivityObject.Create(id) 来创建实例.<br/>
  12. /// </summary>
  13. public abstract partial class ActivityObject : CharacterBody2D, IDestroy, ICoroutine
  14. {
  15. /// <summary>
  16. /// 是否是调试模式
  17. /// </summary>
  18. public static bool IsDebug { get; set; }
  19.  
  20. /// <summary>
  21. /// 当前物体对应的配置数据, 如果不是通过 ActivityObject.Create() 函数创建出来的对象那么 ItemConfig 为 null
  22. /// </summary>
  23. public ExcelConfig.ActivityObject ItemConfig { get; private set; }
  24.  
  25. /// <summary>
  26. /// 是否是静态物体, 如果为true, 则会禁用移动处理
  27. /// </summary>
  28. [Export]
  29. public bool IsStatic { get; set; }
  30.  
  31. /// <summary>
  32. /// 当前物体显示的阴影图像, 节点名称必须叫 "ShadowSprite", 类型为 Sprite2D
  33. /// </summary>
  34. [Export, ExportFillNode]
  35. public Sprite2D ShadowSprite { get; set; }
  36. /// <summary>
  37. /// 当前物体显示的精灵图像, 节点名称必须叫 "AnimatedSprite2D", 类型为 AnimatedSprite2D
  38. /// </summary>
  39. [Export, ExportFillNode]
  40. public AnimatedSprite2D AnimatedSprite { get; set; }
  41.  
  42. /// <summary>
  43. /// 当前物体碰撞器节点, 节点名称必须叫 "Collision", 类型为 CollisionShape2D
  44. /// </summary>
  45. [Export, ExportFillNode]
  46. public CollisionShape2D Collision { get; set; }
  47.  
  48. /// <summary>
  49. /// 是否调用过 Destroy() 函数
  50. /// </summary>
  51. public bool IsDestroyed { get; private set; }
  52. /// <summary>
  53. /// 阴影偏移
  54. /// </summary>
  55. public Vector2 ShadowOffset { get; protected set; } = new Vector2(0, 2);
  56. /// <summary>
  57. /// 移动控制器
  58. /// </summary>
  59. public MoveController MoveController { get; private set; }
  60.  
  61. /// <summary>
  62. /// 物体移动基础速率
  63. /// </summary>
  64. public Vector2 BasisVelocity
  65. {
  66. get
  67. {
  68. if (MoveController != null)
  69. {
  70. return MoveController.BasisVelocity;
  71. }
  72.  
  73. return Vector2.Zero;
  74. }
  75. set
  76. {
  77. if (MoveController != null)
  78. {
  79. MoveController.BasisVelocity = value;
  80. }
  81. }
  82. }
  83.  
  84. /// <summary>
  85. /// 当前物体归属的区域, 如果为 null 代表不属于任何一个区域
  86. /// </summary>
  87. public AffiliationArea AffiliationArea
  88. {
  89. get => _affiliationArea;
  90. set
  91. {
  92. if (value != _affiliationArea)
  93. {
  94. var prev = _affiliationArea;
  95. _affiliationArea = value;
  96. if (!IsDestroyed)
  97. {
  98. OnAffiliationChange(prev);
  99. }
  100. }
  101. }
  102. }
  103.  
  104. /// <summary>
  105. /// 是否正在投抛过程中
  106. /// </summary>
  107. public bool IsThrowing => _throwForce != null && !_isFallOver;
  108.  
  109. /// <summary>
  110. /// 当前物体的海拔高度, 如果大于0, 则会做自由落体运动, 也就是执行投抛代码
  111. /// </summary>
  112. public float Altitude
  113. {
  114. get => _altitude;
  115. set
  116. {
  117. _altitude = value;
  118. _hasResilienceVerticalSpeed = false;
  119. }
  120. }
  121.  
  122. private float _altitude = 0;
  123.  
  124. /// <summary>
  125. /// 物体纵轴移动速度, 如果设置大于0, 就可以营造向上投抛物体的效果, 该值会随着重力加速度衰减
  126. /// </summary>
  127. public float VerticalSpeed
  128. {
  129. get => _verticalSpeed;
  130. set
  131. {
  132. _verticalSpeed = value;
  133. _hasResilienceVerticalSpeed = false;
  134. }
  135. }
  136.  
  137. private float _verticalSpeed;
  138. /// <summary>
  139. /// 物体投抛时旋转速度, 角度制
  140. /// </summary>
  141. public float ThrowRotationDegreesSpeed { get; set; }
  142.  
  143. /// <summary>
  144. /// 落地之后是否回弹
  145. /// </summary>
  146. public bool Bounce { get; set; } = true;
  147.  
  148. /// <summary>
  149. /// 物体下坠回弹的强度
  150. /// </summary>
  151. public float BounceStrength { get; set; } = 0.5f;
  152.  
  153. /// <summary>
  154. /// 物体下坠回弹后的运动速度衰减量
  155. /// </summary>
  156. public float BounceSpeed { get; set; } = 0.75f;
  157.  
  158. /// <summary>
  159. /// 投抛状态下物体碰撞器大小, 如果 (x, y) 都小于 0, 则默认使用 AnimatedSprite 的默认动画第一帧的大小
  160. /// </summary>
  161. [Export]
  162. public Vector2 ThrowCollisionSize { get; set; } = new Vector2(-1, -1);
  163.  
  164. /// <summary>
  165. /// 是否启用垂直方向上的运动模拟, 默认开启, 如果禁用, 那么下落和投抛效果, 同样 Throw() 函数也将失效
  166. /// </summary>
  167. public bool EnableVerticalMotion { get; set; } = true;
  168.  
  169. /// <summary>
  170. /// 是否启用物体更新行为, 默认 true, 如果禁用, 则会停止当前物体的 Process(), PhysicsProcess() 调用, 并且禁用 Collision 节点, 禁用后所有组件也同样被禁用行为
  171. /// </summary>
  172. public bool EnableBehavior
  173. {
  174. get => _enableBehavior;
  175. set
  176. {
  177. if (value != _enableBehavior)
  178. {
  179. _enableBehavior = value;
  180. SetProcess(value);
  181. SetPhysicsProcess(value);
  182. if (value)
  183. {
  184. Collision.Disabled = _enableBehaviorCollisionDisabledFlag;
  185. }
  186. else
  187. {
  188. _enableBehaviorCollisionDisabledFlag = Collision.Disabled;
  189. Collision.Disabled = true;
  190. }
  191. }
  192. }
  193. }
  194.  
  195. /// <summary>
  196. /// 是否启用自定义行为, 默认 true, 如果禁用, 则会停止调用子类重写的 Process(), PhysicsProcess() 函数, 并且当前物体除 MoveController 以外的组件 Process(), PhysicsProcess() 也会停止调用
  197. /// </summary>
  198. public bool EnableCustomBehavior { get; set; } = true;
  199. /// <summary>
  200. /// 所在的 World 对象
  201. /// </summary>
  202. public World World { get; private set; }
  203.  
  204. /// <summary>
  205. /// 是否开启描边
  206. /// </summary>
  207. public bool ShowOutline
  208. {
  209. get => _showOutline;
  210. set
  211. {
  212. if (_blendShaderMaterial != null)
  213. {
  214. if (value != _showOutline)
  215. {
  216. _blendShaderMaterial.SetShaderParameter("show_outline", value);
  217. if (_shadowBlendShaderMaterial != null)
  218. {
  219. _shadowBlendShaderMaterial.SetShaderParameter("show_outline", value);
  220. }
  221. _showOutline = value;
  222. }
  223. }
  224. }
  225. }
  226.  
  227. /// <summary>
  228. /// 描边颜色
  229. /// </summary>
  230. public Color OutlineColor
  231. {
  232. get
  233. {
  234. if (!_initOutlineColor)
  235. {
  236. _initOutlineColor = true;
  237. if (_blendShaderMaterial != null)
  238. {
  239. _outlineColor = _blendShaderMaterial.GetShaderParameter("outline_color").AsColor();
  240. }
  241. }
  242.  
  243. return _outlineColor;
  244. }
  245. set
  246. {
  247. _initOutlineColor = true;
  248. if (value != _outlineColor)
  249. {
  250. _blendShaderMaterial.SetShaderParameter("outline_color", value);
  251. }
  252.  
  253. _outlineColor = value;
  254. }
  255. }
  256.  
  257. // --------------------------------------------------------------------------------
  258.  
  259. //组件集合
  260. private List<KeyValuePair<Type, Component>> _components = new List<KeyValuePair<Type, Component>>();
  261. //上一帧动画名称
  262. private string _prevAnimation;
  263. //上一帧动画
  264. private int _prevAnimationFrame;
  265.  
  266. //播放 Hit 动画
  267. private bool _playHit;
  268. private float _playHitSchedule;
  269.  
  270. //混色shader材质
  271. private ShaderMaterial _blendShaderMaterial;
  272. private ShaderMaterial _shadowBlendShaderMaterial;
  273. //存储投抛该物体时所产生的数据
  274. private ActivityFallData _fallData = new ActivityFallData();
  275. //所在层级
  276. private RoomLayerEnum _currLayer;
  277. //标记字典
  278. private Dictionary<string, object> _signMap;
  279. //开启的协程
  280. private List<CoroutineData> _coroutineList;
  281.  
  282. //物体所在区域
  283. private AffiliationArea _affiliationArea;
  284.  
  285. //是否是第一次下坠
  286. private bool _firstFall = true;
  287. //下坠是否已经结束
  288. private bool _isFallOver = true;
  289.  
  290. //下坠状态碰撞器形状
  291. private RectangleShape2D _throwRectangleShape;
  292.  
  293. //投抛移动速率
  294. private ExternalForce _throwForce;
  295. //落到地上回弹的速度
  296. private float _resilienceVerticalSpeed = 0;
  297. private bool _hasResilienceVerticalSpeed = false;
  298.  
  299. //是否启用物体行为
  300. private bool _enableBehavior = true;
  301. private bool _enableBehaviorCollisionDisabledFlag;
  302.  
  303. private bool _processingBecomesStaticImage = false;
  304.  
  305. // --------------------------------------------------------------------------------
  306. //实例索引
  307. private static long _instanceIndex = 0;
  308.  
  309. //是否启用描边
  310. private bool _showOutline = false;
  311. //描边颜色
  312. private bool _initOutlineColor = false;
  313. private Color _outlineColor = new Color(0, 0, 0, 1);
  314.  
  315. //初始化节点
  316. private void _InitNode(RegisterActivityData activityData, World world)
  317. {
  318. #if TOOLS
  319. if (!Engine.IsEditorHint())
  320. {
  321. if (GetType().GetCustomAttributes(typeof(ToolAttribute), false).Length == 0)
  322. {
  323. throw new Exception($"ActivityObject子类'{GetType().FullName}'没有加[Tool]标记!");
  324. }
  325. }
  326. #endif
  327. World = world;
  328. ItemConfig = activityData.Config;
  329. Name = GetType().Name + (_instanceIndex++);
  330. _blendShaderMaterial = AnimatedSprite.Material as ShaderMaterial;
  331. _shadowBlendShaderMaterial = ShadowSprite.Material as ShaderMaterial;
  332. if (_blendShaderMaterial != null)
  333. {
  334. _showOutline = _blendShaderMaterial.GetShaderParameter("show_outline").AsBool();
  335. }
  336.  
  337. if (_shadowBlendShaderMaterial != null)
  338. {
  339. _shadowBlendShaderMaterial.SetShaderParameter("show_outline", _showOutline);
  340. }
  341.  
  342. ShadowSprite.Visible = false;
  343. MotionMode = MotionModeEnum.Floating;
  344. MoveController = AddComponent<MoveController>();
  345. MoveController.Enable = !IsStatic;
  346. OnInit();
  347. }
  348.  
  349. /// <summary>
  350. /// 子类重写的 _Ready() 可能会比 _InitNode() 函数调用晚, 所以禁止子类重写, 如需要 _Ready() 类似的功能需重写 OnInit()
  351. /// </summary>
  352. public sealed override void _Ready()
  353. {
  354.  
  355. }
  356.  
  357. /// <summary>
  358. /// 子类需要重写 _EnterTree() 函数, 请重写 EnterTree()
  359. /// </summary>
  360. public sealed override void _EnterTree()
  361. {
  362. #if TOOLS
  363. // 在工具模式下创建的 template 节点自动创建对应的必要子节点
  364. if (Engine.IsEditorHint())
  365. {
  366. _InitNodeInEditor();
  367. return;
  368. }
  369. #endif
  370. EnterTree();
  371. }
  372. /// <summary>
  373. /// 子类需要重写 _ExitTree() 函数, 请重写 ExitTree()
  374. /// </summary>
  375. public sealed override void _ExitTree()
  376. {
  377. #if TOOLS
  378. // 在工具模式下创建的 template 节点自动创建对应的必要子节点
  379. if (Engine.IsEditorHint())
  380. {
  381. return;
  382. }
  383. #endif
  384. ExitTree();
  385. }
  386.  
  387. /// <summary>
  388. /// 显示阴影
  389. /// </summary>
  390. public void ShowShadowSprite()
  391. {
  392. var anim = AnimatedSprite.Animation;
  393. var frame = AnimatedSprite.Frame;
  394. if (_prevAnimation != anim || _prevAnimationFrame != frame)
  395. {
  396. var frames = AnimatedSprite.SpriteFrames;
  397. if (frames != null && frames.HasAnimation(anim))
  398. {
  399. //切换阴影动画
  400. ShadowSprite.Texture = frames.GetFrameTexture(anim, frame);
  401. }
  402. }
  403.  
  404. _prevAnimation = anim;
  405. _prevAnimationFrame = frame;
  406.  
  407. CalcShadow();
  408. ShadowSprite.Visible = true;
  409. }
  410.  
  411. /// <summary>
  412. /// 隐藏阴影
  413. /// </summary>
  414. public void HideShadowSprite()
  415. {
  416. ShadowSprite.Visible = false;
  417. }
  418.  
  419. /// <summary>
  420. /// 设置默认序列帧动画的第一帧
  421. /// </summary>
  422. public void SetDefaultTexture(Texture2D texture)
  423. {
  424. if (AnimatedSprite.SpriteFrames == null)
  425. {
  426. SpriteFrames spriteFrames = new SpriteFrames();
  427. AnimatedSprite.SpriteFrames = spriteFrames;
  428. spriteFrames.AddFrame("default", texture);
  429. }
  430. else
  431. {
  432. SpriteFrames spriteFrames = AnimatedSprite.SpriteFrames;
  433. spriteFrames.SetFrame("default", 0, texture);
  434. }
  435. AnimatedSprite.Play("default");
  436. }
  437.  
  438. /// <summary>
  439. /// 获取默认序列帧动画的第一帧
  440. /// </summary>
  441. public Texture2D GetDefaultTexture()
  442. {
  443. return AnimatedSprite.SpriteFrames.GetFrameTexture("default", 0);
  444. }
  445. /// <summary>
  446. /// 获取当前序列帧动画的 Texture2D
  447. /// </summary>
  448. public Texture2D GetCurrentTexture()
  449. {
  450. var spriteFrames = AnimatedSprite.SpriteFrames;
  451. if (spriteFrames == null)
  452. {
  453. return null;
  454. }
  455. return spriteFrames.GetFrameTexture(AnimatedSprite.Animation, AnimatedSprite.Frame);
  456. }
  457.  
  458. /// <summary>
  459. /// 物体初始化时调用
  460. /// </summary>
  461. public virtual void OnInit()
  462. {
  463. }
  464.  
  465. /// <summary>
  466. /// 进入场景树时调用
  467. /// </summary>
  468. public virtual void EnterTree()
  469. {
  470. }
  471.  
  472. /// <summary>
  473. /// 离开场景树时调用
  474. /// </summary>
  475. public virtual void ExitTree()
  476. {
  477. }
  478. /// <summary>
  479. /// 返回是否能与其他ActivityObject互动
  480. /// </summary>
  481. /// <param name="master">触发者</param>
  482. public virtual CheckInteractiveResult CheckInteractive(ActivityObject master)
  483. {
  484. return new CheckInteractiveResult(this);
  485. }
  486.  
  487. /// <summary>
  488. /// 与其它ActivityObject互动时调用, 如果要检测是否能互动请 CheckInteractive() 函数, 如果直接调用该函数那么属于强制互动行为, 例如子弹碰到物体
  489. /// </summary>
  490. /// <param name="master">触发者</param>
  491. public virtual void Interactive(ActivityObject master)
  492. {
  493. }
  494.  
  495. /// <summary>
  496. /// 开始投抛该物体时调用
  497. /// </summary>
  498. protected virtual void OnThrowStart()
  499. {
  500. }
  501. /// <summary>
  502. /// 投抛该物体达到最高点时调用
  503. /// </summary>
  504. protected virtual void OnThrowMaxHeight(float height)
  505. {
  506. }
  507.  
  508. /// <summary>
  509. /// 投抛状态下第一次接触地面时调用, 之后的回弹落地将不会调用该函数
  510. /// </summary>
  511. protected virtual void OnFirstFallToGround()
  512. {
  513. }
  514.  
  515. /// <summary>
  516. /// 投抛状态下每次接触地面时调用
  517. /// </summary>
  518. protected virtual void OnFallToGround()
  519. {
  520. }
  521.  
  522. /// <summary>
  523. /// 投抛结束时调用
  524. /// </summary>
  525. protected virtual void OnThrowOver()
  526. {
  527. }
  528.  
  529. /// <summary>
  530. /// 当前物体销毁时调用, 销毁物体请调用 Destroy() 函数
  531. /// </summary>
  532. protected virtual void OnDestroy()
  533. {
  534. }
  535.  
  536. /// <summary>
  537. /// 每帧调用一次, 物体的 Process() 会在组件的 Process() 之前调用
  538. /// </summary>
  539. protected virtual void Process(float delta)
  540. {
  541. }
  542. /// <summary>
  543. /// 每帧调用一次, ProcessOver() 会在组件的 Process() 之后调用
  544. /// </summary>
  545. protected virtual void ProcessOver(float delta)
  546. {
  547. }
  548. /// <summary>
  549. /// 每物理帧调用一次, 物体的 PhysicsProcess() 会在组件的 PhysicsProcess() 之前调用
  550. /// </summary>
  551. protected virtual void PhysicsProcess(float delta)
  552. {
  553. }
  554. /// <summary>
  555. /// 每物理帧调用一次, PhysicsProcessOver() 会在组件的 PhysicsProcess() 之后调用
  556. /// </summary>
  557. protected virtual void PhysicsProcessOver(float delta)
  558. {
  559. }
  560. /// <summary>
  561. /// 如果开启 debug, 则每帧调用该函数, 可用于绘制文字线段等
  562. /// </summary>
  563. protected virtual void DebugDraw()
  564. {
  565. }
  566.  
  567. /// <summary>
  568. /// 归属区域发生改变
  569. /// </summary>
  570. /// <param name="prevArea">上一个区域, 注意可能为空</param>
  571. protected virtual void OnAffiliationChange(AffiliationArea prevArea)
  572. {
  573. }
  574.  
  575. /// <summary>
  576. /// 返回当物体 CollisionLayer 是否能与 mask 层碰撞
  577. /// </summary>
  578. public bool CollisionWithMask(uint mask)
  579. {
  580. return (CollisionLayer & mask) != 0;
  581. }
  582. /// <summary>
  583. /// 拾起一个 node 节点, 也就是将其从场景树中移除
  584. /// </summary>
  585. public void Pickup()
  586. {
  587. var parent = GetParent();
  588. if (parent != null)
  589. {
  590. if (IsThrowing)
  591. {
  592. StopThrow();
  593. }
  594.  
  595. parent.RemoveChild(this);
  596. }
  597. }
  598.  
  599. /// <summary>
  600. /// 将一个节点扔到地上
  601. /// <param name="layer">放入的层</param>
  602. /// <param name="showShadow">是否显示阴影</param>
  603. /// </summary>
  604. public virtual void PutDown(RoomLayerEnum layer, bool showShadow = true)
  605. {
  606. _currLayer = layer;
  607. var parent = GetParent();
  608. var root = GameApplication.Instance.World.GetRoomLayer(layer);
  609. if (parent != root)
  610. {
  611. if (parent != null)
  612. {
  613. parent.RemoveChild(this);
  614. }
  615.  
  616. this.AddToActivityRoot(layer);
  617. }
  618.  
  619. if (showShadow)
  620. {
  621. if (IsInsideTree())
  622. {
  623. ShowShadowSprite();
  624. }
  625. else
  626. {
  627. //注意需要延时调用
  628. CallDeferred(nameof(ShowShadowSprite));
  629. }
  630. }
  631. else
  632. {
  633. ShadowSprite.Visible = false;
  634. }
  635. }
  636.  
  637. /// <summary>
  638. /// 将一个节点扔到地上
  639. /// </summary>
  640. /// <param name="position">放置的位置</param>
  641. /// <param name="layer">放入的层</param>
  642. /// <param name="showShadow">是否显示阴影</param>
  643. public void PutDown(Vector2 position, RoomLayerEnum layer, bool showShadow = true)
  644. {
  645. PutDown(layer);
  646. Position = position;
  647. }
  648.  
  649. /// <summary>
  650. /// 将该节点投抛出去
  651. /// </summary>
  652. /// <param name="altitude">初始高度</param>
  653. /// <param name="verticalSpeed">纵轴速度</param>
  654. /// <param name="velocity">移动速率</param>
  655. /// <param name="rotateSpeed">旋转速度</param>
  656. public void Throw(float altitude, float verticalSpeed, Vector2 velocity, float rotateSpeed)
  657. {
  658. var parent = GetParent();
  659. if (parent == null)
  660. {
  661. GameApplication.Instance.World.YSortLayer.AddChild(this);
  662. }
  663. else if (parent != GameApplication.Instance.World.YSortLayer)
  664. {
  665. parent.RemoveChild(this);
  666. GameApplication.Instance.World.YSortLayer.AddChild(this);
  667. }
  668. Altitude = altitude;
  669. //Position = Position + new Vector2(0, altitude);
  670. VerticalSpeed = verticalSpeed;
  671. ThrowRotationDegreesSpeed = rotateSpeed;
  672. if (_throwForce != null)
  673. {
  674. MoveController.RemoveForce(_throwForce);
  675. }
  676.  
  677. _throwForce = new ExternalForce("throw");
  678. _throwForce.Velocity = velocity;
  679. MoveController.AddForce(_throwForce);
  680.  
  681. InitThrowData();
  682. }
  683.  
  684. /// <summary>
  685. /// 将该节点投抛出去
  686. /// </summary>
  687. /// <param name="position">初始位置</param>
  688. /// <param name="altitude">初始高度</param>
  689. /// <param name="verticalSpeed">纵轴速度</param>
  690. /// <param name="velocity">移动速率</param>
  691. /// <param name="rotateSpeed">旋转速度</param>
  692. public void Throw(Vector2 position, float altitude, float verticalSpeed, Vector2 velocity, float rotateSpeed)
  693. {
  694. GlobalPosition = position;
  695. Throw(altitude, verticalSpeed, velocity, rotateSpeed);
  696. }
  697.  
  698.  
  699. /// <summary>
  700. /// 强制停止投抛运动
  701. /// </summary>
  702. public void StopThrow()
  703. {
  704. _isFallOver = true;
  705. RestoreCollision();
  706. }
  707.  
  708. /// <summary>
  709. /// 往当前物体上挂载一个组件
  710. /// </summary>
  711. public T AddComponent<T>() where T : Component, new()
  712. {
  713. var component = new T();
  714. _components.Add(new KeyValuePair<Type, Component>(typeof(T), component));
  715. component.ActivityInstance = this;
  716. return component;
  717. }
  718.  
  719. /// <summary>
  720. /// 移除一个组件, 并且销毁
  721. /// </summary>
  722. /// <param name="component">组件对象</param>
  723. public void RemoveComponent(Component component)
  724. {
  725. for (int i = 0; i < _components.Count; i++)
  726. {
  727. if (_components[i].Value == component)
  728. {
  729. _components.RemoveAt(i);
  730. component.Destroy();
  731. return;
  732. }
  733. }
  734. }
  735.  
  736. /// <summary>
  737. /// 根据类型获取一个组件
  738. /// </summary>
  739. public Component GetComponent(Type type)
  740. {
  741. for (int i = 0; i < _components.Count; i++)
  742. {
  743. var temp = _components[i];
  744. if (temp.Key == type)
  745. {
  746. return temp.Value;
  747. }
  748. }
  749.  
  750. return null;
  751. }
  752.  
  753. /// <summary>
  754. /// 根据类型获取一个组件
  755. /// </summary>
  756. public T GetComponent<T>() where T : Component
  757. {
  758. var component = GetComponent(typeof(T));
  759. if (component == null) return null;
  760. return (T)component;
  761. }
  762.  
  763. /// <summary>
  764. /// 设置混色材质的颜色
  765. /// </summary>
  766. public void SetBlendColor(Color color)
  767. {
  768. _blendShaderMaterial.SetShaderParameter("blend", color);
  769. }
  770.  
  771. /// <summary>
  772. /// 获取混色材质的颜色
  773. /// </summary>
  774. public Color GetBlendColor()
  775. {
  776. return _blendShaderMaterial.GetShaderParameter("blend").AsColor();
  777. }
  778. /// <summary>
  779. /// 设置混色材质的强度
  780. /// </summary>
  781. public void SetBlendSchedule(float value)
  782. {
  783. _blendShaderMaterial.SetShaderParameter("schedule", value);
  784. }
  785.  
  786. /// <summary>
  787. /// 获取混色材质的强度
  788. /// </summary>
  789. public float GetBlendSchedule()
  790. {
  791. return _blendShaderMaterial.GetShaderParameter("schedule").AsSingle();
  792. }
  793.  
  794. /// <summary>
  795. /// 设置混色颜色
  796. /// </summary>
  797. public void SetBlendModulate(Color color)
  798. {
  799. _blendShaderMaterial.SetShaderParameter("modulate", color);
  800. _shadowBlendShaderMaterial.SetShaderParameter("modulate", color);
  801. }
  802. /// <summary>
  803. /// 获取混色颜色
  804. /// </summary>
  805. public Color SetBlendModulate()
  806. {
  807. return _blendShaderMaterial.GetShaderParameter("modulate").AsColor();
  808. }
  809. /// <summary>
  810. /// 每帧调用一次, 为了防止子类覆盖 _Process(), 给 _Process() 加上了 sealed, 子类需要帧循环函数请重写 Process() 函数
  811. /// </summary>
  812. public sealed override void _Process(double delta)
  813. {
  814. #if TOOLS
  815. if (Engine.IsEditorHint())
  816. {
  817. return;
  818. }
  819. #endif
  820. var newDelta = (float)delta;
  821. if (EnableCustomBehavior)
  822. {
  823. Process(newDelta);
  824. }
  825. //更新组件
  826. if (_components.Count > 0)
  827. {
  828. if (EnableCustomBehavior) //启用所有组件
  829. {
  830. var arr = _components.ToArray();
  831. for (int i = 0; i < arr.Length; i++)
  832. {
  833. if (IsDestroyed) return;
  834. var temp = arr[i].Value;
  835. if (temp != null && temp.ActivityInstance == this && temp.Enable)
  836. {
  837. if (!temp.IsReady)
  838. {
  839. temp.Ready();
  840. temp.IsReady = true;
  841. }
  842.  
  843. temp.Process(newDelta);
  844. }
  845. }
  846. }
  847. else //只更新 MoveController 组件
  848. {
  849. if (MoveController.Enable)
  850. {
  851. if (!MoveController.IsReady)
  852. {
  853. MoveController.Ready();
  854. MoveController.IsReady = true;
  855. }
  856.  
  857. MoveController.Process(newDelta);
  858. }
  859. }
  860. }
  861.  
  862. // 下坠判定
  863. if (Altitude > 0 || VerticalSpeed != 0)
  864. {
  865. if (_isFallOver) // 没有处于下坠状态, 则进入下坠状态
  866. {
  867. InitThrowData();
  868. }
  869. else
  870. {
  871. if (EnableVerticalMotion) //如果启用了纵向运动, 则更新运动
  872. {
  873. GlobalRotationDegrees = GlobalRotationDegrees + ThrowRotationDegreesSpeed * newDelta;
  874.  
  875. var ysp = VerticalSpeed;
  876.  
  877. _altitude += VerticalSpeed * newDelta;
  878. _verticalSpeed -= GameConfig.G * newDelta;
  879.  
  880. //当高度大于16时, 显示在所有物体上
  881. if (Altitude >= 16)
  882. {
  883. AnimatedSprite.ZIndex = 20;
  884. }
  885. else
  886. {
  887. AnimatedSprite.ZIndex = 0;
  888. }
  889. //达到最高点
  890. if (ysp > 0 && ysp * VerticalSpeed < 0)
  891. {
  892. OnThrowMaxHeight(Altitude);
  893. }
  894.  
  895. //落地判断
  896. if (Altitude <= 0)
  897. {
  898. _altitude = 0;
  899.  
  900. //第一次接触地面
  901. if (_firstFall)
  902. {
  903. _firstFall = false;
  904. OnFirstFallToGround();
  905. }
  906.  
  907. MoveController.ScaleAllForce(BounceSpeed);
  908. //如果落地高度不够低, 再抛一次
  909. if (Bounce && (!_hasResilienceVerticalSpeed || _resilienceVerticalSpeed > 5))
  910. {
  911. if (!_hasResilienceVerticalSpeed)
  912. {
  913. _hasResilienceVerticalSpeed = true;
  914. _resilienceVerticalSpeed = -VerticalSpeed * BounceStrength;
  915. }
  916. else
  917. {
  918. if (_resilienceVerticalSpeed < 25)
  919. {
  920. _resilienceVerticalSpeed = _resilienceVerticalSpeed * BounceStrength * 0.4f;
  921. }
  922. else
  923. {
  924. _resilienceVerticalSpeed = _resilienceVerticalSpeed * BounceStrength;
  925. }
  926. }
  927. _verticalSpeed = _resilienceVerticalSpeed;
  928. ThrowRotationDegreesSpeed = ThrowRotationDegreesSpeed * BounceStrength;
  929. _isFallOver = false;
  930.  
  931. OnFallToGround();
  932. }
  933. else //结束
  934. {
  935. _verticalSpeed = 0;
  936.  
  937. if (_throwForce != null)
  938. {
  939. MoveController.RemoveForce(_throwForce);
  940. _throwForce = null;
  941. }
  942. _isFallOver = true;
  943. OnFallToGround();
  944. ThrowOver();
  945. }
  946. }
  947. }
  948.  
  949. //计算精灵位置
  950. CalcThrowAnimatedPosition();
  951. }
  952. }
  953.  
  954. //阴影
  955. if (ShadowSprite.Visible)
  956. {
  957. //更新阴影贴图, 使其和动画一致
  958. var anim = AnimatedSprite.Animation;
  959. var frame = AnimatedSprite.Frame;
  960. if (_prevAnimation != anim || _prevAnimationFrame != frame)
  961. {
  962. //切换阴影动画
  963. ShadowSprite.Texture = AnimatedSprite.SpriteFrames.GetFrameTexture(anim, AnimatedSprite.Frame);
  964. }
  965.  
  966. _prevAnimation = anim;
  967. _prevAnimationFrame = frame;
  968.  
  969. //计算阴影
  970. CalcShadow();
  971. }
  972.  
  973. // Hit 动画
  974. if (_playHit)
  975. {
  976. if (_playHitSchedule < 0.05f)
  977. {
  978. _blendShaderMaterial.SetShaderParameter("schedule", 1);
  979. }
  980. else if (_playHitSchedule < 0.15f)
  981. {
  982. _blendShaderMaterial.SetShaderParameter("schedule", Mathf.Lerp(1, 0, (_playHitSchedule - 0.05f) / 0.1f));
  983. }
  984. if (_playHitSchedule >= 0.15f)
  985. {
  986. _blendShaderMaterial.SetShaderParameter("schedule", 0);
  987. _playHitSchedule = 0;
  988. _playHit = false;
  989. }
  990. else
  991. {
  992. _playHitSchedule += newDelta;
  993. }
  994. }
  995. //协程更新
  996. if (_coroutineList != null)
  997. {
  998. ProxyCoroutineHandler.ProxyUpdateCoroutine(ref _coroutineList, newDelta);
  999. }
  1000.  
  1001. ProcessOver(newDelta);
  1002. //调试绘制
  1003. if (IsDebug)
  1004. {
  1005. QueueRedraw();
  1006. }
  1007. }
  1008.  
  1009. /// <summary>
  1010. /// 每物理帧调用一次, 为了防止子类覆盖 _PhysicsProcess(), 给 _PhysicsProcess() 加上了 sealed, 子类需要帧循环函数请重写 PhysicsProcess() 函数
  1011. /// </summary>
  1012. public sealed override void _PhysicsProcess(double delta)
  1013. {
  1014. #if TOOLS
  1015. if (Engine.IsEditorHint())
  1016. {
  1017. return;
  1018. }
  1019. #endif
  1020. var newDelta = (float)delta;
  1021. if (EnableCustomBehavior)
  1022. {
  1023. PhysicsProcess(newDelta);
  1024. }
  1025. //更新组件
  1026. if (_components.Count > 0)
  1027. {
  1028. if (EnableCustomBehavior) //启用所有组件
  1029. {
  1030. var arr = _components.ToArray();
  1031. for (int i = 0; i < arr.Length; i++)
  1032. {
  1033. if (IsDestroyed) return;
  1034. var temp = arr[i].Value;
  1035. if (temp != null && temp.ActivityInstance == this && temp.Enable)
  1036. {
  1037. if (!temp.IsReady)
  1038. {
  1039. temp.Ready();
  1040. temp.IsReady = true;
  1041. }
  1042.  
  1043. temp.PhysicsProcess(newDelta);
  1044. }
  1045. }
  1046. }
  1047. else //只更新 MoveController 组件
  1048. {
  1049. if (MoveController.Enable)
  1050. {
  1051. if (!MoveController.IsReady)
  1052. {
  1053. MoveController.Ready();
  1054. MoveController.IsReady = true;
  1055. }
  1056.  
  1057. MoveController.PhysicsProcess(newDelta);
  1058. }
  1059. }
  1060. }
  1061.  
  1062. PhysicsProcessOver(newDelta);
  1063. }
  1064.  
  1065. /// <summary>
  1066. /// 绘制函数, 子类不允许重写, 需要绘制函数请重写 DebugDraw()
  1067. /// </summary>
  1068. public sealed override void _Draw()
  1069. {
  1070. #if TOOLS
  1071. if (Engine.IsEditorHint())
  1072. {
  1073. return;
  1074. }
  1075. #endif
  1076. if (IsDebug)
  1077. {
  1078. DebugDraw();
  1079. var arr = _components.ToArray();
  1080. for (int i = 0; i < arr.Length; i++)
  1081. {
  1082. if (IsDestroyed) return;
  1083. var temp = arr[i].Value;
  1084. if (temp != null && temp.ActivityInstance == this && temp.Enable)
  1085. {
  1086. temp.DebugDraw();
  1087. }
  1088. }
  1089. }
  1090. }
  1091.  
  1092. /// <summary>
  1093. /// 重新计算物体阴影的位置和旋转信息, 无论是否显示阴影
  1094. /// </summary>
  1095. public void CalcShadow()
  1096. {
  1097. //缩放
  1098. ShadowSprite.Scale = AnimatedSprite.Scale;
  1099. //阴影角度
  1100. ShadowSprite.Rotation = 0;
  1101. //阴影位置计算
  1102. var pos = AnimatedSprite.GlobalPosition;
  1103. ShadowSprite.GlobalPosition = new Vector2(pos.X + ShadowOffset.X, pos.Y + ShadowOffset.Y + Altitude);
  1104. }
  1105.  
  1106. //计算位置
  1107. private void CalcThrowAnimatedPosition()
  1108. {
  1109. if (Scale.Y < 0)
  1110. {
  1111. var pos = new Vector2(_fallData.OriginSpritePosition.X, -_fallData.OriginSpritePosition.Y);
  1112. AnimatedSprite.GlobalPosition = GlobalPosition + new Vector2(0, -Altitude) - pos.Rotated(Rotation + Mathf.Pi);
  1113. }
  1114. else
  1115. {
  1116. AnimatedSprite.GlobalPosition = GlobalPosition + new Vector2(0, -Altitude) + _fallData.OriginSpritePosition.Rotated(Rotation);
  1117. }
  1118. }
  1119.  
  1120.  
  1121. /// <summary>
  1122. /// 销毁物体
  1123. /// </summary>
  1124. public void Destroy()
  1125. {
  1126. if (IsDestroyed)
  1127. {
  1128. return;
  1129. }
  1130.  
  1131. IsDestroyed = true;
  1132. if (AffiliationArea != null)
  1133. {
  1134. AffiliationArea.RemoveItem(this);
  1135. }
  1136. QueueFree();
  1137. OnDestroy();
  1138.  
  1139. var arr = _components.ToArray();
  1140. for (int i = 0; i < arr.Length; i++)
  1141. {
  1142. arr[i].Value?.Destroy();
  1143. }
  1144. if (AffiliationArea != null)
  1145. {
  1146. AffiliationArea.RemoveItem(this);
  1147. }
  1148. }
  1149.  
  1150. /// <summary>
  1151. /// 延时销毁
  1152. /// </summary>
  1153. public void DelayDestroy()
  1154. {
  1155. CallDeferred(nameof(Destroy));
  1156. }
  1157.  
  1158. /// <summary>
  1159. /// 继承指定物体的运动速率
  1160. /// </summary>
  1161. /// <param name="other">目标对象</param>
  1162. /// <param name="scale">继承的速率缩放</param>
  1163. public void InheritVelocity(ActivityObject other, float scale = 0.5f)
  1164. {
  1165. MoveController.AddVelocity(other.Velocity * scale);
  1166. }
  1167.  
  1168. /// <summary>
  1169. /// 触发投抛动作
  1170. /// </summary>
  1171. private void Throw()
  1172. {
  1173. var parent = GetParent();
  1174. //投抛时必须要加入 YSortLayer 节点下
  1175. if (parent == null)
  1176. {
  1177. this.AddToActivityRoot(RoomLayerEnum.YSortLayer);
  1178. }
  1179. else if (parent == GameApplication.Instance.World.NormalLayer)
  1180. {
  1181. parent.RemoveChild(this);
  1182. this.AddToActivityRoot(RoomLayerEnum.YSortLayer);
  1183. }
  1184.  
  1185. CalcThrowAnimatedPosition();
  1186. //显示阴影
  1187. ShowShadowSprite();
  1188.  
  1189. if (EnableVerticalMotion)
  1190. {
  1191. OnThrowStart();
  1192. }
  1193. }
  1194.  
  1195. /// <summary>
  1196. /// 设置下坠状态下的碰撞器
  1197. /// </summary>
  1198. private void SetFallCollision()
  1199. {
  1200. if (_fallData != null && _fallData.UseOrigin)
  1201. {
  1202. _fallData.OriginShape = Collision.Shape;
  1203. _fallData.OriginPosition = Collision.Position;
  1204. _fallData.OriginRotation = Collision.Rotation;
  1205. _fallData.OriginScale = Collision.Scale;
  1206. _fallData.OriginZIndex = ZIndex;
  1207. _fallData.OriginSpritePosition = AnimatedSprite.Position;
  1208. _fallData.OriginCollisionEnable = Collision.Disabled;
  1209. _fallData.OriginCollisionPosition = Collision.Position;
  1210. _fallData.OriginCollisionRotation = Collision.Rotation;
  1211. _fallData.OriginCollisionScale = Collision.Scale;
  1212. _fallData.OriginCollisionMask = CollisionMask;
  1213. _fallData.OriginCollisionLayer = CollisionLayer;
  1214.  
  1215. if (_throwRectangleShape == null)
  1216. {
  1217. _throwRectangleShape = new RectangleShape2D();
  1218. }
  1219. Collision.Shape = _throwRectangleShape;
  1220. Collision.Position = Vector2.Zero;
  1221. Collision.Rotation = 0;
  1222. Collision.Scale = Vector2.One;
  1223. ZIndex = 0;
  1224. Collision.Disabled = false;
  1225. Collision.Position = Vector2.Zero;
  1226. Collision.Rotation = 0;
  1227. Collision.Scale = Vector2.One;
  1228. CollisionMask = 1;
  1229. CollisionLayer = PhysicsLayer.Throwing;
  1230. _fallData.UseOrigin = false;
  1231. }
  1232. }
  1233.  
  1234. /// <summary>
  1235. /// 重置碰撞器
  1236. /// </summary>
  1237. private void RestoreCollision()
  1238. {
  1239. if (_fallData != null && !_fallData.UseOrigin)
  1240. {
  1241. Collision.Shape = _fallData.OriginShape;
  1242. Collision.Position = _fallData.OriginPosition;
  1243. Collision.Rotation = _fallData.OriginRotation;
  1244. Collision.Scale = _fallData.OriginScale;
  1245. ZIndex = _fallData.OriginZIndex;
  1246. AnimatedSprite.Position = _fallData.OriginSpritePosition;
  1247. Collision.Disabled = _fallData.OriginCollisionEnable;
  1248. Collision.Position = _fallData.OriginCollisionPosition;
  1249. Collision.Rotation = _fallData.OriginCollisionRotation;
  1250. Collision.Scale = _fallData.OriginCollisionScale;
  1251. CollisionMask = _fallData.OriginCollisionMask;
  1252. CollisionLayer = _fallData.OriginCollisionLayer;
  1253.  
  1254. _fallData.UseOrigin = true;
  1255. }
  1256. }
  1257.  
  1258. /// <summary>
  1259. /// 投抛结束
  1260. /// </summary>
  1261. private void ThrowOver()
  1262. {
  1263. var parent = GetParent();
  1264. var roomLayer = GameApplication.Instance.World.GetRoomLayer(_currLayer);
  1265. if (parent != roomLayer)
  1266. {
  1267. parent.RemoveChild(this);
  1268. roomLayer.AddChild(this);
  1269. }
  1270. RestoreCollision();
  1271.  
  1272. OnThrowOver();
  1273. }
  1274.  
  1275. //初始化投抛状态数据
  1276. private void InitThrowData()
  1277. {
  1278. SetFallCollision();
  1279.  
  1280. _isFallOver = false;
  1281. _firstFall = true;
  1282. _hasResilienceVerticalSpeed = false;
  1283. _resilienceVerticalSpeed = 0;
  1284. if (ThrowCollisionSize.X < 0 && ThrowCollisionSize.Y < 0)
  1285. {
  1286. _throwRectangleShape.Size = GetDefaultTexture().GetSize();
  1287. }
  1288. else
  1289. {
  1290. _throwRectangleShape.Size = ThrowCollisionSize;
  1291. }
  1292.  
  1293. Throw();
  1294. }
  1295.  
  1296. /// <summary>
  1297. /// 设置标记, 用于在物体上记录自定义数据
  1298. /// </summary>
  1299. /// <param name="name">标记名称</param>
  1300. /// <param name="v">存入值</param>
  1301. public void SetSign(string name, object v)
  1302. {
  1303. if (_signMap == null)
  1304. {
  1305. _signMap = new Dictionary<string, object>();
  1306. }
  1307.  
  1308. _signMap[name] = v;
  1309. }
  1310.  
  1311. /// <summary>
  1312. /// 返回是否存在指定名称的标记数据
  1313. /// </summary>
  1314. public bool HasSign(string name)
  1315. {
  1316. return _signMap == null ? false : _signMap.ContainsKey(name);
  1317. }
  1318.  
  1319. /// <summary>
  1320. /// 根据名称获取标记值
  1321. /// </summary>
  1322. public object GetSign(string name)
  1323. {
  1324. if (_signMap == null)
  1325. {
  1326. return null;
  1327. }
  1328.  
  1329. _signMap.TryGetValue(name, out var value);
  1330. return value;
  1331. }
  1332.  
  1333. /// <summary>
  1334. /// 根据名称获取标记值
  1335. /// </summary>
  1336. public T GetSign<T>(string name)
  1337. {
  1338. if (_signMap == null)
  1339. {
  1340. return default;
  1341. }
  1342.  
  1343. _signMap.TryGetValue(name, out var value);
  1344. if (value is T v)
  1345. {
  1346. return v;
  1347. }
  1348. return default;
  1349. }
  1350.  
  1351. /// <summary>
  1352. /// 根据名称删除标记
  1353. /// </summary>
  1354. public void RemoveSign(string name)
  1355. {
  1356. if (_signMap != null)
  1357. {
  1358. _signMap.Remove(name);
  1359. }
  1360. }
  1361.  
  1362. /// <summary>
  1363. /// 播放受伤动画, 该动画不与 Animation 节点的动画冲突
  1364. /// </summary>
  1365. public void PlayHitAnimation()
  1366. {
  1367. _playHit = true;
  1368. _playHitSchedule = 0;
  1369. }
  1370. public long StartCoroutine(IEnumerator able)
  1371. {
  1372. return ProxyCoroutineHandler.ProxyStartCoroutine(ref _coroutineList, able);
  1373. }
  1374. public void StopCoroutine(long coroutineId)
  1375. {
  1376. ProxyCoroutineHandler.ProxyStopCoroutine(ref _coroutineList, coroutineId);
  1377. }
  1378. public void StopAllCoroutine()
  1379. {
  1380. ProxyCoroutineHandler.ProxyStopAllCoroutine(ref _coroutineList);
  1381. }
  1382.  
  1383. /// <summary>
  1384. /// 将当前 ActivityObject 变成静态图像绘制到地面上, 用于优化渲染大量物体<br/>
  1385. /// 调用该函数后会排队进入渲染队列, 并且禁用所有行为, 当渲染完成后会销毁当前对象, 也就是调用 Destroy() 函数<br/>
  1386. /// </summary>
  1387. public void BecomesStaticImage()
  1388. {
  1389. if (_processingBecomesStaticImage)
  1390. {
  1391. return;
  1392. }
  1393. if (AffiliationArea == null)
  1394. {
  1395. GD.PrintErr($"调用函数: BecomesStaticImage() 失败, 物体{Name}没有归属区域, 无法确定绘制到哪个ImageCanvas上, 直接执行销毁");
  1396. Destroy();
  1397. return;
  1398. }
  1399.  
  1400. _processingBecomesStaticImage = true;
  1401. EnableBehavior = false;
  1402. var staticImageCanvas = AffiliationArea.RoomInfo.StaticImageCanvas;
  1403. var position = staticImageCanvas.ToImageCanvasPosition(GlobalPosition);
  1404. staticImageCanvas.CanvasSprite.DrawActivityObjectInCanvas(this, position.X, position.Y, () =>
  1405. {
  1406. Destroy();
  1407. });
  1408. }
  1409.  
  1410. /// <summary>
  1411. /// 是否正在处理成为静态图片
  1412. /// </summary>
  1413. public bool IsProcessingBecomesStaticImage()
  1414. {
  1415. return _processingBecomesStaticImage;
  1416. }
  1417. }