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