using System; using System.Collections; using System.Collections.Generic; using Config; using Godot; /// <summary> /// 房间内活动物体基类, 所有物体都必须继承该类,<br/> /// 该类提供基础物体运动模拟, 互动接口, 自定义组件, 协程等功能<br/> /// ActivityObject 子类实例化请不要直接使用 new, 而用该在类上标上 [Tool], 并在 ActivityObject.xlsx 配置文件中注册物体, 导出配置表后使用 ActivityObject.Create(id) 来创建实例.<br/> /// </summary> [Tool] public partial class ActivityObject : CharacterBody2D, ICoroutine, IInteractive, IOutline { /// <summary> /// 是否是调试模式 /// </summary> public static bool IsDebug { get; set; } /// <summary> /// 实例唯一 Id /// </summary> public long Id { get; set; } /// <summary> /// 当前物体对应的配置数据, 如果不是通过 ActivityObject.Create() 函数创建出来的对象那么 ItemConfig 为 null /// </summary> public ExcelConfig.ActivityBase ActivityBase { get; private set; } /// <summary> /// 是否是静态物体, 如果为true, 则会禁用移动处理 /// </summary> public bool IsStatic { get => MoveController != null ? !MoveController.Enable : true; set { if (MoveController != null) { MoveController.Enable = !value; } } } /// <summary> /// 是否显示阴影 /// </summary> public bool IsShowShadow { get; private set; } /// <summary> /// 当前物体显示的阴影图像, 节点名称必须叫 "ShadowSprite", 类型为 Sprite2D /// </summary> [Export, ExportFillNode] public Sprite2D ShadowSprite { get; set; } /// <summary> /// 当前物体显示的精灵图像, 节点名称必须叫 "AnimatedSprite2D", 类型为 AnimatedSprite2D /// </summary> [Export, ExportFillNode] public AnimatedSprite2D AnimatedSprite { get; set; } /// <summary> /// 阴影自定义缩放值 /// </summary> public float ShadowScale { get; set; } = 1; /// <summary> /// 当前物体碰撞器节点, 节点名称必须叫 "Collision", 类型为 CollisionShape2D /// </summary> [Export, ExportFillNode] public CollisionShape2D Collision { get; set; } /// <summary> /// 是否调用过 Destroy() 函数 /// </summary> public bool IsDestroyed { get; private set; } /// <summary> /// 阴影偏移 /// </summary> [Export] public Vector2 ShadowOffset { get; set; } = new Vector2(0, 2); /// <summary> /// 移动控制器 /// </summary> public MoveController MoveController { get; private set; } /// <summary> /// 物体移动基础速率 /// </summary> public Vector2 BasisVelocity { get { if (MoveController != null) { return MoveController.BasisVelocity; } return Vector2.Zero; } set { if (MoveController != null) { MoveController.BasisVelocity = value; } } } /// <summary> /// 当前物体归属的区域, 如果为 null 代表不属于任何一个区域 /// </summary> public AffiliationArea AffiliationArea { get => _affiliationArea; set { if (value != _affiliationArea) { var prev = _affiliationArea; _affiliationArea = value; if (!IsDestroyed) { OnAffiliationChange(prev); } } } } /// <summary> /// 下坠逻辑是否执行完成 /// </summary> public bool IsFallOver => _isFallOver; /// <summary> /// 是否正在投抛过程中 /// </summary> public bool IsThrowing => VerticalSpeed != 0 && !_isFallOver; /// <summary> /// 当前物体的海拔高度, 如果大于0, 则会做自由落体运动, 也就是执行投抛逻辑 /// </summary> public float Altitude { get => _altitude; set { _altitude = value; _hasResilienceVerticalSpeed = false; } } private float _altitude = 0; /// <summary> /// 物体纵轴移动速度, 如果设置大于0, 就可以营造向上投抛物体的效果, 该值会随着重力加速度衰减 /// </summary> public float VerticalSpeed { get => _verticalSpeed; set { _verticalSpeed = value; _hasResilienceVerticalSpeed = false; } } private float _verticalSpeed; /// <summary> /// 是否启用垂直方向上的运动模拟, 默认开启, 如果禁用, 那么下落和投抛效果, 同样 Throw() 函数也将失效 /// </summary> public bool EnableVerticalMotion { get; set; } = true; /// <summary> /// 是否启用物体更新行为, 默认 true, 如果禁用, 则会停止当前物体的 Process(), PhysicsProcess() 调用, 并且禁用 Collision 节点, 禁用后所有组件也同样被禁用行为 /// </summary> public bool EnableBehavior { get => _enableBehavior; set { if (value != _enableBehavior) { _enableBehavior = value; SetProcess(value); SetPhysicsProcess(value); if (value) { Collision.Disabled = _enableBehaviorCollisionDisabledFlag; } else { _enableBehaviorCollisionDisabledFlag = Collision.Disabled; Collision.Disabled = true; } } } } /// <summary> /// 是否启用自定义行为, 默认 true, 如果禁用, 则会停止调用子类重写的 Process(), PhysicsProcess() 函数, 并且当前物体除 MoveController 以外的组件 Process(), PhysicsProcess() 也会停止调用 /// </summary> public bool EnableCustomBehavior { get; set; } = true; /// <summary> /// 物体材质数据 /// </summary> public ExcelConfig.ActivityMaterial ActivityMaterial { get; private set; } /// <summary> /// 所在的 World 对象 /// </summary> public World World { get; set; } public bool ShowOutline { get => _blendShaderMaterial == null ? false : _blendShaderMaterial.GetShaderParameter(ShaderParamNames.ShowOutline).AsBool(); set { _blendShaderMaterial?.SetShaderParameter(ShaderParamNames.ShowOutline, value); _shadowBlendShaderMaterial?.SetShaderParameter(ShaderParamNames.ShowOutline, value); } } public Color OutlineColor { get => _blendShaderMaterial == null ? Colors.Black : _blendShaderMaterial.GetShaderParameter(ShaderParamNames.OutlineColor).AsColor(); set => _blendShaderMaterial?.SetShaderParameter(ShaderParamNames.OutlineColor, value); } /// <summary> /// 灰度 /// </summary> public float Grey { get => _blendShaderMaterial == null ? 0 : _blendShaderMaterial.GetShaderParameter(ShaderParamNames.Grey).AsSingle(); set => _blendShaderMaterial?.SetShaderParameter(ShaderParamNames.Grey, value); } /// <summary> /// 是否是自定义阴影纹理 /// </summary> public bool IsCustomShadowSprite { get; set; } /// <summary> /// 记录绘制液体的笔刷上一次绘制的位置<br/> /// 每次调用 DrawLiquid() 后都会记录这一次绘制的位置, 记录这个位置用作执行补间操作, 但是一旦停止绘制了, 需要手动清理记录的位置, 也就是将 BrushPrevPosition 置为 null /// </summary> public Vector2I? BrushPrevPosition { get; set; } /// <summary> /// 默认所在层级 /// </summary> public RoomLayerEnum DefaultLayer { get; set; } /// <summary> /// 投抛状态下的碰撞器层级 /// </summary> public uint ThrowCollisionMask { get; set; } = PhysicsLayer.Wall; // -------------------------------------------------------------------------------- //是否正在调用组件 Update 函数 private bool _updatingComp = false; //组件集合 private readonly List<KeyValuePair<Type, Component>> _components = new List<KeyValuePair<Type, Component>>(); //修改的组件集合, value 为 true 表示添加组件, false 表示移除组件 private readonly List<KeyValuePair<Component, bool>> _changeComponents = new List<KeyValuePair<Component, bool>>(); //上一帧动画名称 private StringName _prevAnimation; //上一帧动画 private int _prevAnimationFrame; //播放 Hit 动画 private bool _playHit; private float _playHitSchedule; //混色shader材质 private ShaderMaterial _blendShaderMaterial; private ShaderMaterial _shadowBlendShaderMaterial; //存储投抛该物体时所产生的数据 private readonly ActivityFallData _fallData = new ActivityFallData(); //标记字典 private Dictionary<string, object> _signMap; //开启的协程 private List<CoroutineData> _coroutineList; //物体所在区域 private AffiliationArea _affiliationArea; //是否是第一次下坠 private bool _firstFall = true; //下坠是否已经结束 private bool _isFallOver = true; //投抛移动速率 private ExternalForce _throwForce; //落到地上回弹的速度 private float _resilienceVerticalSpeed = 0; private bool _hasResilienceVerticalSpeed = false; //是否启用物体行为 private bool _enableBehavior = true; private bool _enableBehaviorCollisionDisabledFlag; private bool _processingBecomesStaticImage = false; //击退外力 private ExternalForce _repelForce; //绑定销毁物体集合 private HashSet<IDestroy> _destroySet; //挂载的物体集合 private HashSet<IMountItem> _mountObjects; // -------------------------------------------------------------------------------- //实例索引 private static long _instanceIndex = 0; //冻结显示的Sprite private FreezeSprite _freezeSprite; //初始化节点 private void _InitNode(ExcelConfig.ActivityBase config, World world) { #if TOOLS if (!Engine.IsEditorHint()) { if (GetType().GetCustomAttributes(typeof(ToolAttribute), false).Length == 0) { throw new Exception($"ActivityObject子类'{GetType().FullName}'没有加[Tool]标记!"); } } #endif if (config.Material == null) { ActivityMaterial = ExcelConfig.ActivityMaterial_List[0]; } else { ActivityMaterial = config.Material; } //GravityScale 为 0 时关闭重力 if (ActivityMaterial.GravityScale == 0) { EnableVerticalMotion = false; } World = world; ActivityBase = config; #if TOOLS Name = GetType().Name + '#' + (_instanceIndex++); #endif Id = _instanceIndex; _blendShaderMaterial = AnimatedSprite.Material as ShaderMaterial; IsCustomShadowSprite = ShadowSprite.Texture != null; if (!IsCustomShadowSprite) //没有自定义阴影纹理 { _shadowBlendShaderMaterial = ShadowSprite.Material as ShaderMaterial; if (_shadowBlendShaderMaterial != null && _blendShaderMaterial != null) { var value = _blendShaderMaterial.GetShaderParameter(ShaderParamNames.ShowOutline); _shadowBlendShaderMaterial.SetShaderParameter(ShaderParamNames.ShowOutline, value); } ShadowSprite.Visible = false; } MotionMode = MotionModeEnum.Floating; MoveController = AddComponent<MoveController>(); IsStatic = config.IsStatic; OnInit(); } public override string ToString() { if (ActivityBase != null) { return "<" + Name + ":" + ActivityBase.Id + ">"; } return "<" + Name + ">"; } /// <summary> /// 子类重写的 _Ready() 可能会比 _InitNode() 函数调用晚, 所以禁止子类重写, 如需要 _Ready() 类似的功能需重写 OnInit() /// </summary> public sealed override void _Ready() { } /// <summary> /// 子类需要重写 _EnterTree() 函数, 请重写 EnterTree() /// </summary> public sealed override void _EnterTree() { #if TOOLS // 在工具模式下创建的 template 节点自动创建对应的必要子节点 if (Engine.IsEditorHint()) { _InitNodeInEditor(); return; } #endif EnterTree(); } /// <summary> /// 子类需要重写 _ExitTree() 函数, 请重写 ExitTree() /// </summary> public sealed override void _ExitTree() { #if TOOLS // 在工具模式下创建的 template 节点自动创建对应的必要子节点 if (Engine.IsEditorHint()) { return; } #endif ExitTree(); } /// <summary> /// 显示并更新阴影 /// </summary> public void ShowShadowSprite() { if (!IsCustomShadowSprite) { var anim = AnimatedSprite.Animation; var frame = AnimatedSprite.Frame; if (_prevAnimation != anim || _prevAnimationFrame != frame) { var frames = AnimatedSprite.SpriteFrames; if (frames != null && frames.HasAnimation(anim)) { //切换阴影动画 ShadowSprite.Texture = frames.GetFrameTexture(anim, frame); } } _prevAnimation = anim; _prevAnimationFrame = frame; } IsShowShadow = true; CalcShadowTransform(IsInsideTree()); ShadowSprite.Visible = true; } /// <summary> /// 隐藏阴影 /// </summary> public void HideShadowSprite() { ShadowSprite.Visible = false; IsShowShadow = false; } /// <summary> /// 设置默认序列帧动画的第一帧 /// </summary> public void SetDefaultTexture(Texture2D texture) { if (AnimatedSprite.SpriteFrames == null) { SpriteFrames spriteFrames = new SpriteFrames(); AnimatedSprite.SpriteFrames = spriteFrames; spriteFrames.AddFrame("default", texture); } else { SpriteFrames spriteFrames = AnimatedSprite.SpriteFrames; if (spriteFrames.GetFrameCount("default") > 0) { spriteFrames.SetFrame("default", 0, texture); } else { spriteFrames.AddFrame("default", texture); } } AnimatedSprite.Play("default"); } /// <summary> /// 获取默认序列帧动画的第一帧 /// </summary> public Texture2D GetDefaultTexture() { return AnimatedSprite.SpriteFrames.GetFrameTexture("default", 0); } /// <summary> /// 获取当前序列帧动画的 Texture2D /// </summary> public Texture2D GetCurrentTexture() { var spriteFrames = AnimatedSprite.SpriteFrames; if (spriteFrames == null) { return null; } return spriteFrames.GetFrameTexture(AnimatedSprite.Animation, AnimatedSprite.Frame); } /// <summary> /// 物体初始化时调用 /// </summary> public virtual void OnInit() { } /// <summary> /// 进入场景树时调用 /// </summary> public virtual void EnterTree() { } /// <summary> /// 离开场景树时调用 /// </summary> public virtual void ExitTree() { } public virtual CheckInteractiveResult CheckInteractive(ActivityObject master) { return new CheckInteractiveResult(this); } public virtual void Interactive(ActivityObject master) { } public virtual void OnTargetEnterd(ActivityObject target) { if (target is Player) { OutlineColor = Colors.White; } } public virtual void OnTargetExitd(ActivityObject target) { if (target is Player) { OutlineColor = Colors.Black; } } /// <summary> /// 开始投抛该物体时调用 /// </summary> protected virtual void OnThrowStart() { } /// <summary> /// 投抛该物体达到最高点时调用 /// </summary> protected virtual void OnThrowMaxHeight(float height) { } /// <summary> /// 投抛状态下第一次接触地面时调用, 之后的回弹落地将不会调用该函数 /// </summary> protected virtual void OnFirstFallToGround() { } /// <summary> /// 投抛状态下每次接触地面时调用 /// </summary> protected virtual void OnFallToGround() { } /// <summary> /// 投抛结束时调用 /// </summary> protected virtual void OnThrowOver() { } /// <summary> /// 当前物体销毁时调用, 销毁物体请调用 Destroy() 函数 /// </summary> protected virtual void OnDestroy() { } /// <summary> /// 每帧调用一次, 物体的 Process() 会在组件的 Process() 之前调用 /// </summary> protected virtual void Process(float delta) { } /// <summary> /// 每物理帧调用一次, 物体的 PhysicsProcess() 会在组件的 PhysicsProcess() 之前调用 /// </summary> protected virtual void PhysicsProcess(float delta) { } /// <summary> /// 如果开启 debug, 则每帧调用该函数, 可用于绘制文字线段等 /// </summary> protected virtual void DebugDraw() { } /// <summary> /// 归属区域发生改变 /// </summary> /// <param name="prevArea">上一个区域, 注意可能为空</param> protected virtual void OnAffiliationChange(AffiliationArea prevArea) { } /// <summary> /// 移动并碰撞到物体时调用该函数, 参数为碰撞数据, 该函数由 MoveController 调用 /// </summary> public virtual void OnMoveCollision(KinematicCollision2D collision) { } /// <summary> /// 撞到墙壁反弹时调用该函数, 参数为反弹的角度, 弧度制, 该函数由 MoveController 调用 /// </summary> public virtual void OnBounce(float rotation) { } /// <summary> /// 添加组件时调用 /// </summary> public virtual void OnAddComponent(Component component) { } /// <summary> /// 移除组件时调用 /// </summary> public virtual void OnRemoveComponent(Component component) { } /// <summary> /// 返回当物体 CollisionLayer 是否能与 mask 层碰撞 /// </summary> public bool CollisionWithMask(uint mask) { return (CollisionLayer & mask) != 0; } /// <summary> /// 拾起一个 node 节点, 也就是将其从场景树中移除 /// </summary> public void Pickup() { var parent = GetParent(); if (parent != null) { if (IsThrowing) { StopThrow(); } parent.RemoveChild(this); } } /// <summary> /// 将一个节点扔到地上 /// <param name="layer">放入的层</param> /// <param name="showShadow">是否显示阴影</param> /// </summary> public virtual void PutDown(RoomLayerEnum layer, bool showShadow = true) { DefaultLayer = layer; var parent = GetParent(); var root = World.Current.GetRoomLayer(layer); if (parent != root) { if (parent != null) { Reparent(root); } else { root.AddChild(this); } } if (showShadow) { if (IsInsideTree()) { ShowShadowSprite(); } else { //注意需要延时调用 CallDeferred(nameof(ShowShadowSprite)); CalcShadowTransform(false); } } else { ShadowSprite.Visible = false; } } /// <summary> /// 将一个节点扔到地上 /// </summary> /// <param name="position">放置的位置</param> /// <param name="layer">放入的层</param> /// <param name="showShadow">是否显示阴影</param> public void PutDown(Vector2 position, RoomLayerEnum layer, bool showShadow = true) { PutDown(layer); Position = position; } /// <summary> /// 将该节点投抛出去 /// </summary> /// <param name="altitude">初始高度</param> /// <param name="verticalSpeed">纵轴速度</param> /// <param name="velocity">移动速率</param> /// <param name="rotateSpeed">旋转速度</param> public void Throw(float altitude, float verticalSpeed, Vector2 velocity, float rotateSpeed) { Altitude = altitude; //Position = Position + new Vector2(0, altitude); VerticalSpeed = verticalSpeed; //ThrowRotationDegreesSpeed = rotateSpeed; if (_throwForce != null) { MoveController.RemoveForce(_throwForce); } _throwForce = new ExternalForce(ForceNames.Throw); _throwForce.Velocity = velocity; _throwForce.RotationSpeed = Mathf.DegToRad(rotateSpeed); MoveController.AddForce(_throwForce); InitThrowData(); } /// <summary> /// 将该节点投抛出去 /// </summary> /// <param name="position">初始位置</param> /// <param name="altitude">初始高度</param> /// <param name="verticalSpeed">纵轴速度</param> /// <param name="velocity">移动速率</param> /// <param name="rotateSpeed">旋转速度</param> public void Throw(Vector2 position, float altitude, float verticalSpeed, Vector2 velocity, float rotateSpeed) { GlobalPosition = position; Throw(altitude, verticalSpeed, velocity, rotateSpeed); } /// <summary> /// 往一个指定位置投抛物体, 使其能正好落到目标位置 /// </summary> /// <param name="position">起始位置</param> /// <param name="altitude">起始高度</param> /// <param name="rotateSpeed">旋转速度</param> /// <param name="targetPosition">目标位置</param> /// <param name="speed">投抛到目标点的速度</param> public void ThrowToPosition(Vector2 position, float altitude, float rotateSpeed, Vector2 targetPosition, float speed) { var distance = position.DistanceTo(targetPosition); var time = distance / speed; var verticalSpeed = -(altitude - 0.5f * GameConfig.G * time * time) / time; var velocity = (targetPosition - position).Normalized() * speed; Throw(position, altitude, verticalSpeed, velocity, rotateSpeed); } /// <summary> /// 强制停止投抛运动 /// </summary> public void StopThrow() { _isFallOver = true; RestoreCollision(); } /// <summary> /// 往当前物体上挂载一个组件 /// </summary> public T AddComponent<T>() where T : Component, new() { var component = new T(); if (_updatingComp) { _changeComponents.Add(new KeyValuePair<Component, bool>(component, true)); } else { _components.Add(new KeyValuePair<Type, Component>(typeof(T), component)); } component.Master = this; component.Ready(); component.OnEnable(); OnAddComponent(component); return component; } /// <summary> /// 往当前物体上挂载一个组件 /// </summary> public Component AddComponent(Type type) { var component = (Component)Activator.CreateInstance(type); if (_updatingComp) { _changeComponents.Add(new KeyValuePair<Component, bool>(component, true)); } else { _components.Add(new KeyValuePair<Type, Component>(type, component)); } component.Master = this; component.Ready(); component.OnEnable(); OnAddComponent(component); return component; } /// <summary> /// 移除一个组件, 并且销毁 /// </summary> /// <param name="component">组件对象</param> public void RemoveComponent(Component component) { if (component.IsDestroyed) { return; } if (_updatingComp) { _changeComponents.Add(new KeyValuePair<Component, bool>(component, false)); OnRemoveComponent(component); component.Destroy(); } else { for (var i = 0; i < _components.Count; i++) { if (_components[i].Value == component) { _components.RemoveAt(i); OnRemoveComponent(component); component.Destroy(); return; } } } } /// <summary> /// 根据类型获取一个组件 /// </summary> public Component GetComponent(Type type) { for (int i = 0; i < _components.Count; i++) { var temp = _components[i]; if (temp.Key.IsAssignableTo(type)) { return temp.Value; } } if (_updatingComp) { for (var i = 0; i < _changeComponents.Count; i++) { var temp = _components[i]; if (temp.Value.GetType().IsAssignableTo(type)) { return temp.Value; } } } return null; } /// <summary> /// 根据类型获取一个组件 /// </summary> public T GetComponent<T>() { for (int i = 0; i < _components.Count; i++) { var temp = _components[i]; if (temp.Value is T component) { return component; } } if (_updatingComp) { for (var i = 0; i < _changeComponents.Count; i++) { var temp = _components[i]; if (temp.Value is T component) { return component; } } } return default; } /// <summary> /// 根据类型获取所有相同类型的组件 /// </summary> public Component[] GetComponents(Type type) { var list = new List<Component>(); for (int i = 0; i < _components.Count; i++) { var temp = _components[i]; if (temp.Key.IsAssignableTo(type)) { list.Add(temp.Value); } } if (_updatingComp) { for (var i = 0; i < _changeComponents.Count; i++) { var temp = _components[i]; if (temp.Value.GetType().IsAssignableTo(type)) { list.Add(temp.Value); } } } return list.ToArray(); } /// <summary> /// 根据类型获取所有相同类型的组件 /// </summary> public T[] GetComponents<T>() { var list = new List<T>(); for (int i = 0; i < _components.Count; i++) { var temp = _components[i]; if (temp.Value is T component) { list.Add(component); } } if (_updatingComp) { for (var i = 0; i < _changeComponents.Count; i++) { var temp = _components[i]; if (temp.Value is T component) { list.Add(component); } } } return list.ToArray(); } /// <summary> /// 设置混色材质的颜色 /// </summary> public void SetBlendColor(Color color) { _blendShaderMaterial?.SetShaderParameter("blend", color); } /// <summary> /// 获取混色材质的颜色 /// </summary> public Color GetBlendColor() { if (_blendShaderMaterial == null) { return Colors.White; } return _blendShaderMaterial.GetShaderParameter("blend").AsColor(); } /// <summary> /// 设置混色材质的强度 /// </summary> public void SetBlendSchedule(float value) { _blendShaderMaterial?.SetShaderParameter("schedule", value); } /// <summary> /// 获取混色材质的强度 /// </summary> public float GetBlendSchedule() { if (_blendShaderMaterial == null) { return default; } return _blendShaderMaterial.GetShaderParameter("schedule").AsSingle(); } /// <summary> /// 设置混色颜色 /// </summary> public void SetBlendModulate(Color color) { _blendShaderMaterial?.SetShaderParameter("modulate", color); _shadowBlendShaderMaterial?.SetShaderParameter("modulate", color); } /// <summary> /// 获取混色颜色 /// </summary> public Color SetBlendModulate() { if (_blendShaderMaterial == null) { return Colors.White; } return _blendShaderMaterial.GetShaderParameter("modulate").AsColor(); } /// <summary> /// 每帧调用一次, 为了防止子类覆盖 _Process(), 给 _Process() 加上了 sealed, 子类需要帧循环函数请重写 Process() 函数 /// </summary> public sealed override void _Process(double delta) { #if TOOLS if (Engine.IsEditorHint()) { return; } #endif var newDelta = (float)delta; UpdateProcess(newDelta); //更新组件 UpdateComponentProcess(newDelta); // 更新下坠处理逻辑 UpdateFall(newDelta); //阴影 UpdateShadowSprite(newDelta); // Hit 动画 if (_playHit) { if (_playHitSchedule < 0.05f) { _blendShaderMaterial?.SetShaderParameter("schedule", 1); } else if (_playHitSchedule < 0.15f) { _blendShaderMaterial?.SetShaderParameter("schedule", Mathf.Lerp(1, 0, (_playHitSchedule - 0.05f) / 0.1f)); } if (_playHitSchedule >= 0.15f) { _blendShaderMaterial?.SetShaderParameter("schedule", 0); _playHitSchedule = 0; _playHit = false; } else { _playHitSchedule += newDelta; } } //协程更新 UpdateCoroutine(newDelta); //调试绘制 if (IsDebug) { QueueRedraw(); } } /// <summary> /// 触发调用 Process() 函数 /// </summary> public void UpdateProcess(float delta) { if (EnableCustomBehavior) { Process(delta); } } /// <summary> /// 触发调用 PhysicsProcess() 函数 /// </summary> public void UpdatePhysicsProcess(float delta) { if (EnableCustomBehavior) { PhysicsProcess(delta); } } /// <summary> /// 更新组件 /// </summary> public void UpdateComponentProcess(float delta) { //更新组件 if (_components.Count > 0) { _updatingComp = true; if (EnableCustomBehavior) //启用所有组件 { for (int i = 0; i < _components.Count; i++) { if (IsDestroyed) return; var temp = _components[i].Value; if (temp != null && temp.Enable) { temp.Process(delta); } } } else //只更新 MoveController 组件 { if (MoveController.Enable) { MoveController.Process(delta); } } _updatingComp = false; if (_changeComponents.Count > 0) { RefreshComponent(); } } } /// <summary> /// 物理帧更新组件 /// </summary> public void UpdateComponentPhysicsProcess(float delta) { if (_components.Count > 0) { _updatingComp = true; if (EnableCustomBehavior) //启用所有组件 { for (int i = 0; i < _components.Count; i++) { if (IsDestroyed) return; var temp = _components[i].Value; if (temp != null && temp.Enable) { temp.PhysicsProcess(delta); } } } else //只更新 MoveController 组件 { if (MoveController.Enable) { MoveController.PhysicsProcess(delta); } } _updatingComp = false; if (_changeComponents.Count > 0) { RefreshComponent(); } } } /// <summary> /// 更新协程 /// </summary> public void UpdateCoroutine(float delta) { ProxyCoroutineHandler.ProxyUpdateCoroutine(ref _coroutineList, delta); } /// <summary> /// 更新下坠处理逻辑 /// </summary> public void UpdateFall(float delta) { // 下坠判定 if (Altitude > 0 || VerticalSpeed != 0) { if (_isFallOver) // 没有处于下坠状态, 则进入下坠状态 { InitThrowData(); } else { if (EnableVerticalMotion) //如果启用了纵向运动, 则更新运动 { //GlobalRotationDegrees = GlobalRotationDegrees + ThrowRotationDegreesSpeed * newDelta; var ysp = VerticalSpeed; _altitude += VerticalSpeed * delta; _verticalSpeed -= GameConfig.G * ActivityMaterial.GravityScale * delta; //当高度大于32时, 显示在所有物体上, 并且关闭碰撞 if (Altitude >= 32) { AnimatedSprite.ZIndex = 20; } else { AnimatedSprite.ZIndex = 0; } //动态开关碰撞器 if (ActivityMaterial.DynamicCollision) { Collision.Disabled = Altitude >= 32; } //达到最高点 if (ysp > 0 && ysp * VerticalSpeed < 0) { OnThrowMaxHeight(Altitude); } //落地判断 if (Altitude <= 0) { _altitude = 0; //第一次接触地面 if (_firstFall) { _firstFall = false; OnFirstFallToGround(); } if (_throwForce != null) { //缩放移动速度 //MoveController.ScaleAllForce(BounceSpeed); _throwForce.Velocity *= ActivityMaterial.FallBounceSpeed; //缩放旋转速度 //MoveController.ScaleAllRotationSpeed(BounceStrength); _throwForce.RotationSpeed *= ActivityMaterial.FallBounceRotation; } //如果落地高度不够低, 再抛一次 if (ActivityMaterial.Bounce && (!_hasResilienceVerticalSpeed || _resilienceVerticalSpeed > 5)) { if (!_hasResilienceVerticalSpeed) { _hasResilienceVerticalSpeed = true; _resilienceVerticalSpeed = -VerticalSpeed * ActivityMaterial.FallBounceStrength; } else { if (_resilienceVerticalSpeed < 25) { _resilienceVerticalSpeed = _resilienceVerticalSpeed * ActivityMaterial.FallBounceStrength * 0.4f; } else { _resilienceVerticalSpeed = _resilienceVerticalSpeed * ActivityMaterial.FallBounceStrength; } } _verticalSpeed = _resilienceVerticalSpeed; _isFallOver = false; OnFallToGround(); } else //结束 { _verticalSpeed = 0; if (_throwForce != null) { MoveController.RemoveForce(_throwForce); _throwForce = null; } _isFallOver = true; OnFallToGround(); ThrowOver(); } } } //计算精灵位置 CalcThrowAnimatedPosition(); } } } /// <summary> /// 更新阴影逻辑 /// </summary> public void UpdateShadowSprite(float delta) { // 阴影 if (ShadowSprite.Visible) { if (!IsCustomShadowSprite) { //更新阴影贴图, 使其和动画一致 var anim = AnimatedSprite.Animation; var frame = AnimatedSprite.Frame; if (_prevAnimation != anim || _prevAnimationFrame != frame) { //切换阴影动画 ShadowSprite.Texture = AnimatedSprite.SpriteFrames.GetFrameTexture(anim, AnimatedSprite.Frame); } _prevAnimation = anim; _prevAnimationFrame = frame; } if (_freezeSprite == null || !_freezeSprite.IsFrozen) { //计算阴影 CalcShadowTransform(true); } } } /// <summary> /// 每物理帧调用一次, 为了防止子类覆盖 _PhysicsProcess(), 给 _PhysicsProcess() 加上了 sealed, 子类需要帧循环函数请重写 PhysicsProcess() 函数 /// </summary> public sealed override void _PhysicsProcess(double delta) { #if TOOLS if (Engine.IsEditorHint()) { return; } #endif var newDelta = (float)delta; UpdatePhysicsProcess(newDelta); //更新组件 UpdateComponentPhysicsProcess(newDelta); } //更新新增/移除的组件 private void RefreshComponent() { for (var i = 0; i < _changeComponents.Count; i++) { var item = _changeComponents[i]; if (item.Value) //添加组件 { _components.Add(new KeyValuePair<Type, Component>(item.Key.GetType(), item.Key)); } else //移除组件 { for (var j = 0; j < _components.Count; j++) { if (_components[i].Value == item.Key) { _components.RemoveAt(i); break; } } } } } /// <summary> /// 绘制函数, 子类不允许重写, 需要绘制函数请重写 DebugDraw() /// </summary> public sealed override void _Draw() { #if TOOLS if (Engine.IsEditorHint()) { return; } #endif if (IsDebug) { DebugDraw(); if (_components.Count > 0) { var arr = _components.ToArray(); for (int i = 0; i < arr.Length; i++) { if (IsDestroyed) return; var temp = arr[i].Value; if (temp != null && temp.Master == this && temp.Enable) { temp.DebugDraw(); } } } } } /// <summary> /// 重新计算物体阴影的位置和旋转信息, 无论是否显示阴影 /// </summary> public void CalcShadowTransform(bool isInTree) { //偏移 if (!IsCustomShadowSprite) { ShadowSprite.Offset = AnimatedSprite.Offset; } //缩放 ShadowSprite.Scale = AnimatedSprite.Scale * ShadowScale; //阴影角度 ShadowSprite.Rotation = 0; //阴影位置计算 if (isInTree) { var pos = AnimatedSprite.GlobalPosition; ShadowSprite.GlobalPosition = new Vector2(pos.X + ShadowOffset.X, pos.Y + ShadowOffset.Y + Altitude); } else { var pos = AnimatedSprite.Position; ShadowSprite.Position = new Vector2(pos.X + ShadowOffset.X, pos.Y + ShadowOffset.Y + Altitude); } } /// <summary> /// 计算物体精灵和阴影位置 /// </summary> public void CalcThrowAnimatedPosition() { if (Scale.Y < 0) { var pos = new Vector2(_fallData.OriginSpritePosition.X, -_fallData.OriginSpritePosition.Y); AnimatedSprite.GlobalPosition = GlobalPosition + new Vector2(0, -Altitude) - pos.Rotated(Rotation + Mathf.Pi); } else { AnimatedSprite.GlobalPosition = GlobalPosition + new Vector2(0, -Altitude) + _fallData.OriginSpritePosition.Rotated(Rotation); } } /// <summary> /// 销毁物体 /// </summary> public void Destroy() { if (IsDestroyed) { return; } if (_mountObjects != null) { foreach (var item in _mountObjects) { item.OnUnmount(this); } _mountObjects = null; } IsDestroyed = true; if (AffiliationArea != null) { AffiliationArea.RemoveItem(this); } QueueFree(); OnDestroy(); if (_freezeSprite != null) { _freezeSprite.Destroy(); } var arr = _components.ToArray(); for (var i = 0; i < arr.Length; i++) { arr[i].Value?.Destroy(); } _components.Clear(); if (_destroySet != null) { foreach (var destroy in _destroySet) { destroy.Destroy(); } _destroySet = null; } } /// <summary> /// 延时销毁 /// </summary> public void DelayDestroy() { CallDeferred(nameof(Destroy)); } /// <summary> /// 继承指定物体的运动速率 /// </summary> /// <param name="other">目标对象</param> /// <param name="scale">继承的速率缩放</param> public void InheritVelocity(ActivityObject other, float scale = 0.5f) { MoveController.AddVelocity(other.Velocity * scale); } /// <summary> /// 获取投抛该物体时所产生的数据, 只在 IsFallOver 为 false 时有效 /// </summary> public ActivityFallData GetFallData() { if (!IsFallOver && !_fallData.UseOrigin) { return _fallData; } return null; } /// <summary> /// 触发投抛动作 /// </summary> private void Throw() { var parent = GetParent(); //投抛时必须要加入 YSortLayer 节点下 if (parent == null) { this.AddToActivityRoot(RoomLayerEnum.YSortLayer); } else if (parent != World.Current.YSortLayer) { Reparent(World.Current.YSortLayer); } CalcThrowAnimatedPosition(); //显示阴影 ShowShadowSprite(); if (EnableVerticalMotion) { OnThrowStart(); } } /// <summary> /// 设置下坠状态下的碰撞器 /// </summary> private void SetFallCollision() { if (_fallData.UseOrigin) { _fallData.OriginShape = Collision.Shape; _fallData.OriginPosition = Collision.Position; _fallData.OriginRotation = Collision.Rotation; _fallData.OriginScale = Collision.Scale; _fallData.OriginZIndex = ZIndex; _fallData.OriginSpritePosition = AnimatedSprite.Position; _fallData.OriginCollisionEnable = Collision.Disabled; _fallData.OriginCollisionPosition = Collision.Position; _fallData.OriginCollisionRotation = Collision.Rotation; _fallData.OriginCollisionScale = Collision.Scale; _fallData.OriginCollisionMask = CollisionMask; _fallData.OriginCollisionLayer = CollisionLayer; Collision.Position = Vector2.Zero; Collision.Rotation = 0; Collision.Scale = Vector2.One; ZIndex = 0; Collision.Disabled = false; Collision.Position = Vector2.Zero; Collision.Rotation = 0; Collision.Scale = Vector2.One; CollisionMask = ThrowCollisionMask; CollisionLayer = _fallData.OriginCollisionLayer | PhysicsLayer.Throwing; _fallData.UseOrigin = false; } } /// <summary> /// 重置碰撞器 /// </summary> private void RestoreCollision() { if (!_fallData.UseOrigin) { Collision.Shape = _fallData.OriginShape; Collision.Position = _fallData.OriginPosition; Collision.Rotation = _fallData.OriginRotation; Collision.Scale = _fallData.OriginScale; ZIndex = _fallData.OriginZIndex; AnimatedSprite.Position = _fallData.OriginSpritePosition; Collision.Disabled = _fallData.OriginCollisionEnable; Collision.Position = _fallData.OriginCollisionPosition; Collision.Rotation = _fallData.OriginCollisionRotation; Collision.Scale = _fallData.OriginCollisionScale; CollisionMask = _fallData.OriginCollisionMask; CollisionLayer = _fallData.OriginCollisionLayer; _fallData.UseOrigin = true; } } /// <summary> /// 投抛结束 /// </summary> private void ThrowOver() { var parent = GetParent(); var roomLayer = World.Current.GetRoomLayer(DefaultLayer); if (parent != roomLayer) { parent.RemoveChild(this); roomLayer.AddChild(this); } RestoreCollision(); OnThrowOver(); } //初始化投抛状态数据 private void InitThrowData() { SetFallCollision(); _isFallOver = false; _firstFall = true; _hasResilienceVerticalSpeed = false; _resilienceVerticalSpeed = 0; Throw(); } /// <summary> /// 设置标记, 用于在物体上记录自定义数据 /// </summary> /// <param name="name">标记名称</param> /// <param name="v">存入值</param> public void SetSign(string name, object v) { if (_signMap == null) { _signMap = new Dictionary<string, object>(); } _signMap[name] = v; } /// <summary> /// 返回是否存在指定名称的标记数据 /// </summary> public bool HasSign(string name) { return _signMap == null ? false : _signMap.ContainsKey(name); } /// <summary> /// 根据名称获取标记值 /// </summary> public object GetSign(string name) { if (_signMap == null) { return null; } _signMap.TryGetValue(name, out var value); return value; } /// <summary> /// 根据名称获取标记值 /// </summary> public T GetSign<T>(string name) { if (_signMap == null) { return default; } _signMap.TryGetValue(name, out var value); if (value is T v) { return v; } return default; } /// <summary> /// 根据名称删除标记 /// </summary> public void RemoveSign(string name) { if (_signMap != null) { _signMap.Remove(name); } } /// <summary> /// 播放受伤动画, 该动画不与 Animation 节点的动画冲突 /// </summary> public void PlayHitAnimation() { _playHit = true; _playHitSchedule = 0; } /// <summary> /// 获取当前摩擦力 /// </summary> public float GetCurrentFriction() { return ActivityMaterial.Friction; } /// <summary> /// 获取当前旋转摩擦力 /// </summary> public float GetCurrentRotationFriction() { return ActivityMaterial.RotationFriction; } public long StartCoroutine(IEnumerator able) { return ProxyCoroutineHandler.ProxyStartCoroutine(ref _coroutineList, able); } public void StopCoroutine(long coroutineId) { ProxyCoroutineHandler.ProxyStopCoroutine(ref _coroutineList, coroutineId); } public bool IsCoroutineOver(long coroutineId) { return ProxyCoroutineHandler.ProxyIsCoroutineOver(ref _coroutineList, coroutineId); } public void StopAllCoroutine() { ProxyCoroutineHandler.ProxyStopAllCoroutine(ref _coroutineList); } /// <summary> /// 播放 AnimatedSprite 上的动画, 如果没有这个动画, 则什么也不会发生 /// </summary> /// <param name="name">动画名称</param> public bool PlaySpriteAnimation(string name) { var spriteFrames = AnimatedSprite.SpriteFrames; if (spriteFrames != null && spriteFrames.HasAnimation(name)) { AnimatedSprite.Play(name); return true; } return false; } /// <summary> /// 将当前 ActivityObject 变成静态图像绘制到地面上, 用于优化渲染大量物体<br/> /// 调用该函数后会排队进入渲染队列, 并且禁用所有行为, 当渲染完成后会销毁当前对象, 也就是调用 Destroy() 函数<br/> /// </summary> public void BecomesStaticImage() { if (_processingBecomesStaticImage) { return; } if (AffiliationArea == null) { Debug.LogError($"调用函数: BecomesStaticImage() 失败, 物体{Name}没有归属区域, 无法确定绘制到哪个ImageCanvas上, 直接执行销毁"); Destroy(); return; } _processingBecomesStaticImage = true; EnableBehavior = false; var roomInfo = AffiliationArea.RoomInfo; var position = roomInfo.ToCanvasPosition(GlobalPosition); roomInfo.StaticImageCanvas.DrawActivityObjectInCanvas(this, position.X, position.Y, () => { Destroy(); }); } /// <summary> /// 是否正在处理成为静态图片 /// </summary> public bool IsProcessingBecomesStaticImage() { return _processingBecomesStaticImage; } /// <summary> /// 冻结物体,多余的节点就会被移出场景树,逻辑也会被暂停,用于优化性能 /// </summary> public void Freeze() { if (_freezeSprite == null) { _freezeSprite = new FreezeSprite(this); } _freezeSprite.Freeze(); } /// <summary> /// 解冻物体, 恢复正常逻辑 /// </summary> public void Unfreeze() { if (_freezeSprite == null) { return; } _freezeSprite.Unfreeze(); } /// <summary> /// 获取中心点坐标 /// </summary> public Vector2 GetCenterPosition() { return AnimatedSprite.Position + Position; } /// <summary> /// 设置物体朝向 /// </summary> public void SetForwardDirection(FaceDirection face) { if ((face == FaceDirection.Left && Scale.X > 0) || (face == FaceDirection.Right && Scale.X < 0)) { Scale *= new Vector2(-1, 1); } } /// <summary> /// 添加一个击退力 /// </summary> public void AddRepelForce(Vector2 velocity) { if (_repelForce == null) { _repelForce = new ExternalForce(ForceNames.Repel); } //不在 MoveController 中 if (_repelForce.MoveController == null) { _repelForce.Velocity = velocity; MoveController.AddForce(_repelForce); } else { _repelForce.Velocity += velocity; } } /// <summary> /// 获取击退力 /// </summary> public Vector2 GetRepelForce() { if (_repelForce == null || _repelForce.MoveController == null) { return Vector2.Zero; } return _repelForce.Velocity; } /// <summary> /// 根据笔刷 id 在该物体位置绘制液体, 该 id 为 LiquidMaterial 表的 id<br/> /// 需要清除记录的点就请将 BrushPrevPosition 置为 null /// </summary> public void DrawLiquid(string brushId) { if (AffiliationArea != null) { DrawLiquid(LiquidBrushManager.GetBrush(brushId)); } } /// <summary> /// 根据笔刷数据在该物体位置绘制液体<br/> /// 需要清除记录的点就请将 BrushPrevPosition 置为 null /// </summary> public void DrawLiquid(BrushImageData brush) { if (AffiliationArea != null) { var pos = AffiliationArea.RoomInfo.LiquidCanvas.ToLiquidCanvasPosition(Position); AffiliationArea.RoomInfo.LiquidCanvas.DrawBrush(brush, BrushPrevPosition, pos, 0); BrushPrevPosition = pos; } } /// <summary> /// 根据笔刷 id 在该物体位置绘制液体, 该 id 为 LiquidMaterial 表的 id<br/> /// 需要清除记录的点就请将 BrushPrevPosition 置为 null /// </summary> public void DrawLiquid(string brushId, Vector2I offset) { if (AffiliationArea != null) { DrawLiquid(LiquidBrushManager.GetBrush(brushId), offset); } } /// <summary> /// 根据笔刷数据在该物体位置绘制液体<br/> /// 需要清除记录的点就请将 BrushPrevPosition 置为 null /// </summary> public void DrawLiquid(BrushImageData brush, Vector2I offset) { if (AffiliationArea != null) { var pos = AffiliationArea.RoomInfo.LiquidCanvas.ToLiquidCanvasPosition(Position) + offset; AffiliationArea.RoomInfo.LiquidCanvas.DrawBrush(brush, BrushPrevPosition, pos, 0); BrushPrevPosition = pos; } } /// <summary> /// 绑定可销毁对象, 绑定的物体会在当前物体销毁时触发销毁 /// </summary> public void AddDestroyObject(IDestroy destroy) { if (_destroySet == null) { _destroySet = new HashSet<IDestroy>(); } _destroySet.Add(destroy); } /// <summary> /// 移除绑定可销毁对象 /// </summary> public void RemoveDestroyObject(IDestroy destroy) { if (_destroySet == null) { return; } _destroySet.Remove(destroy); } /// <summary> /// 绑定挂载对象, 绑定的物体会在当前物体销毁时触发扔出 /// </summary> public void AddMountObject(IMountItem target) { if (_mountObjects == null) { _mountObjects = new HashSet<IMountItem>(); } if (_mountObjects.Add(target)) { target.OnMount(this); } } /// <summary> /// 移除绑定挂载对象 /// </summary> public void RemoveMountObject(IMountItem target) { if (_mountObjects == null) { return; } if (_mountObjects.Remove(target)) { target.OnUnmount(this); } } /// <summary> /// 设置是否启用碰撞层, 该函数是设置下坠状态下原碰撞层 /// </summary> public void SetOriginCollisionLayerValue(uint layer, bool vale) { if (vale) { if (!Utils.CollisionMaskWithLayer(_fallData.OriginCollisionLayer, layer)) { _fallData.OriginCollisionLayer |= layer; } } else { if (Utils.CollisionMaskWithLayer(_fallData.OriginCollisionLayer, layer)) { _fallData.OriginCollisionLayer ^= layer; } } } /// <summary> /// 通过标记创建时调用 /// </summary> /// <param name="roomPreinstall">当前所在的预设</param> /// <param name="activityMark">创建当前物体的标记对象</param> public virtual void OnCreateWithMark(RoomPreinstall roomPreinstall, ActivityMark activityMark) { } }