using System.Collections.Generic; using Godot; /// <summary> /// 角色基类 /// </summary> public abstract class Role : ActivityObject { /// <summary> /// 重写的纹理 /// </summary> public Texture OverrideTexture { get; protected set; } /// <summary> /// 移动速度 /// </summary> public float MoveSpeed = 150f; /// <summary> /// 所属阵营 /// </summary> public CampEnum Camp; /// <summary> /// 携带的道具包裹 /// </summary> public List<object> PropsPack { get; } = new List<object>(); /// <summary> /// 角色携带的枪套 /// </summary> public Holster Holster { get; private set; } /// <summary> /// 武器挂载点 /// </summary> public Position2D MountPoint { get; private set; } /// <summary> /// 背后武器的挂载点 /// </summary> public Position2D BackMountPoint { get; private set; } /// <summary> /// 互动碰撞区域 /// </summary> public Area2D InteractiveArea { get; private set; } /// <summary> /// 脸的朝向 /// </summary> public FaceDirection Face { get => _face; set => SetFace(value); } private FaceDirection _face; /// <summary> /// 血量 /// </summary> public int Hp { get => _hp; protected set { int temp = _hp; _hp = value; if (temp != _hp) OnChangeHp(_hp); } } private int _hp = 0; /// <summary> /// 最大血量 /// </summary> public int MaxHp { get => _maxHp; protected set { int temp = _maxHp; _maxHp = value; if (temp != _maxHp) OnChangeMaxHp(_maxHp); } } private int _maxHp = 0; //初始缩放 private Vector2 StartScele; //所有角色碰撞的道具 private readonly List<ActivityObject> InteractiveItemList = new List<ActivityObject>(); private CheckInteractiveResult TempResultData; /// <summary> /// 可以互动的道具 /// </summary> protected ActivityObject InteractiveItem { get; private set; } /// <summary> /// 当血量改变时调用 /// </summary> protected abstract void OnChangeHp(int hp); /// <summary> /// 当最大血量改变时调用 /// </summary> protected abstract void OnChangeMaxHp(int maxHp); /// <summary> /// 当可互动的物体改变时调用, result 参数为 null 表示变为不可互动 /// </summary> /// <param name="result">检测是否可互动时的返回值</param> protected abstract void ChangeInteractiveItem(CheckInteractiveResult result); public override CheckInteractiveResult CheckInteractive(ActivityObject master) { return new CheckInteractiveResult(this); } public override void Interactive(ActivityObject master) { } public Role() : base("res://prefab/role/Role.tscn") { } public Role(string scenePath) : base(scenePath) { } public override void _Ready() { base._Ready(); StartScele = Scale; MountPoint = GetNode<Position2D>("MountPoint"); BackMountPoint = GetNode<Position2D>("BackMountPoint"); if (OverrideTexture != null) { // 更改纹理 ChangeFrameTexture(AnimatorNames.Idle, AnimatedSprite, OverrideTexture); ChangeFrameTexture(AnimatorNames.Run, AnimatedSprite, OverrideTexture); ChangeFrameTexture(AnimatorNames.ReverseRun, AnimatedSprite, OverrideTexture); } Holster = new Holster(this); Face = FaceDirection.Right; //连接互动物体信号 InteractiveArea = GetNode<Area2D>("InteractiveArea"); InteractiveArea.Connect("area_entered", this, nameof(_OnPropsEnter)); InteractiveArea.Connect("area_exited", this, nameof(_OnPropsExit)); } public override void _Process(float delta) { base._Process(delta); //检查可互动的道具 bool findFlag = false; for (int i = 0; i < InteractiveItemList.Count; i++) { var item = InteractiveItemList[i]; if (item == null) { InteractiveItemList.RemoveAt(i--); } else { //找到可互动的道具了 if (!findFlag) { var result = item.CheckInteractive(this); if (result.CanInteractive) //可以互动 { findFlag = true; if (InteractiveItem != item) //更改互动物体 { InteractiveItem = item; ChangeInteractiveItem(result); } else if (result.ShowIcon != TempResultData.ShowIcon) //切换状态 { ChangeInteractiveItem(result); } } TempResultData = result; } } } //没有可互动的道具 if (!findFlag && InteractiveItem != null) { InteractiveItem = null; ChangeInteractiveItem(null); } } /// <summary> /// 拾起一个武器, 并且切换到这个武器 /// </summary> /// <param name="weapon">武器对象</param> public void PickUpWeapon(Weapon weapon) { if (Holster.PickupWeapon(weapon) != -1) { //从可互动队列中移除 InteractiveItemList.Remove(weapon); } } /// <summary> /// 切换到下一个武器 /// </summary> public void TriggerExchangeNext() { Holster.ExchangeNext(); } /// <summary> /// 切换到上一个武器 /// </summary> public void ExchangePrev() { Holster.ExchangePrev(); } /// <summary> /// 扔掉当前使用的武器, 切换到上一个武器 /// </summary> public void TriggerThrowWeapon() { var weapon = Holster.RmoveWeapon(Holster.ActiveIndex); //播放抛出效果 if (weapon != null) { weapon.StartThrowWeapon(this); } } /// <summary> /// 返回是否存在可互动的物体 /// </summary> public bool HasInteractive() { return InteractiveItem != null; } /// <summary> /// 触发与碰撞的物体互动, 并返回与其互动的物体 /// </summary> public ActivityObject TriggerInteractive() { if (HasInteractive()) { var item = InteractiveItem; item.Interactive(this); return item; } return null; } /// <summary> /// 触发换弹 /// </summary> public void TriggerReload() { if (Holster.ActiveWeapon != null) { Holster.ActiveWeapon._Reload(); } } /// <summary> /// 触发攻击 /// </summary> public void TriggerAttack() { if (Holster.ActiveWeapon != null) { Holster.ActiveWeapon.Trigger(); } } /// <summary> /// 设置脸的朝向 /// </summary> private void SetFace(FaceDirection face) { if (_face != face) { _face = face; if (face == FaceDirection.Right) { RotationDegrees = 0; Scale = StartScele; } else { RotationDegrees = 180; Scale = new Vector2(StartScele.x, -StartScele.y); } } } /// <summary> /// 更改指定动画的纹理 /// </summary> private void ChangeFrameTexture(string anim, AnimatedSprite animatedSprite, Texture texture) { SpriteFrames spriteFrames = animatedSprite.Frames; if (spriteFrames != null) { int count = spriteFrames.GetFrameCount(anim); for (int i = 0; i < count; i++) { AtlasTexture temp = spriteFrames.GetFrame(anim, i) as AtlasTexture; temp.Atlas = OverrideTexture; } } } /// <summary> /// 连接信号: InteractiveArea.area_entered /// 与物体碰撞 /// </summary> private void _OnPropsEnter(Area2D other) { ActivityObject propObject = other.AsActivityObject(); if (propObject != null) //道具类型 { if (!InteractiveItemList.Contains(propObject)) { InteractiveItemList.Add(propObject); } } } /// <summary> /// 连接信号: InteractiveArea.area_exited /// 物体离开碰撞区域 /// </summary> private void _OnPropsExit(Area2D other) { ActivityObject propObject = other.AsActivityObject(); if (propObject != null) //道具类型 { if (InteractiveItemList.Contains(propObject)) { InteractiveItemList.Remove(propObject); } if (InteractiveItem == propObject) { InteractiveItem = null; ChangeInteractiveItem(null); } } } }