Newer
Older
DungeonShooting / DungeonShooting_Godot / src / game / activity / weapon / knife / Knife.cs

using Godot;

/// <summary>
/// 近战武器,刀
/// </summary>
[Tool]
public partial class Knife : Weapon
{
    /// <summary>
    /// 近战攻击范围
    /// </summary>
    [Export]
    public int AttackRange { get; set; } = 41;

    /// <summary>
    /// 开始蓄力时武器抬起角度
    /// </summary>
    [Export]
    public int BeginChargeAngle { get; set; } = 120;
    
    private Area2D _hitArea;
    private int _attackIndex = 0;
    private CollisionPolygon2D _collisionPolygon;
    
    public override void OnInit()
    {
        base.OnInit();
        
        //没有Master时不能触发开火
        NoMasterCanTrigger = false;
        _hitArea = GetNode<Area2D>("HitArea");
        _collisionPolygon = new CollisionPolygon2D();
        var a = Mathf.Abs(-BeginChargeAngle + Attribute.UpliftAngle);
        var ca = Utils.ConvertAngle(-a / 2f);
        _collisionPolygon.Polygon = Utils.CreateSectorPolygon(ca, AttackRange, a, 6);
        _hitArea.AddChild(_collisionPolygon);
        
        _hitArea.Monitoring = false;
        _hitArea.Monitorable = false;
        _hitArea.BodyEntered += OnBodyEntered;
        _hitArea.AreaEntered += OnArea2dEntered;
        
        //更新碰撞层级
        _hitArea.CollisionMask = Role.AttackLayer | PhysicsLayer.Bullet;

        //禁用自动播放动画
        IsAutoPlaySpriteFrames = false;
    }

    protected override void Process(float delta)
    {
        base.Process(delta);
        if (IsActive)
        {
            //让碰撞节点与武器挂载节点位置保持一致, 而不跟着武器走
            _hitArea.GlobalPosition = Master.MountPoint.GlobalPosition;
        }
    }

    protected override void PhysicsProcess(float delta)
    {
        base.PhysicsProcess(delta);
        //过去两个物理帧后就能关闭碰撞了
        if (++_attackIndex >= 2)
        {
            _hitArea.Monitoring = false;
        }
    }

    protected override void OnBeginCharge()
    {
        //开始蓄力时武器角度
        RotationDegrees = -BeginChargeAngle;
    }

    protected override void OnFire()
    {
        Debug.Log("近战武器攻击! 蓄力时长: " + GetTriggerChargeTime() + ", 扳机按下时长: " + GetTriggerDownTime());
        //启用碰撞
        _hitArea.Monitoring = true;
        _attackIndex = 0;

        if (IsActive) //被使用
        {
            //播放挥刀特效
            SpecialEffectManager.PlaySpriteFrames(
                Master,
                ResourcePath.resource_spriteFrames_weapon_Weapon0004_hit_tres, "default",
                Master.MountPoint.Position,
                Master.MountPoint.Rotation + Mathf.DegToRad(Attribute.UpliftAngle + 60),
                AnimatedSprite.Scale,
                new Vector2(17, 4), 1
            );
        }


        if (Master == World.Player)
        {
            var r = Master.MountPoint.RotationDegrees;
            //创建屏幕抖动
            if (Master.Face == FaceDirection.Right)
            {
                //GameCamera.Main.DirectionalShake(Vector2.FromAngle(Mathf.DegToRad(r - 90)) * 5);
                GameCamera.Main.DirectionalShake(Vector2.FromAngle(Mathf.DegToRad(r - 180)) * Attribute.CameraShake);
            }
            else
            {
                //GameCamera.Main.DirectionalShake(Vector2.FromAngle(Mathf.DegToRad(270 - r)) * 5);
                GameCamera.Main.DirectionalShake(Vector2.FromAngle(Mathf.DegToRad(-r)) * Attribute.CameraShake);
            }
        }
    }

    protected override void OnShoot(float fireRotation)
    {
        
    }

    protected override int UseAmmoCount()
    {
        //这里要做判断, 如果没有碰到敌人, 则不消耗弹药 (耐久)
        return 0;
    }

    private void OnBodyEntered(Node2D body)
    {
        if (body is IHurt hurt)
        {
            HandlerCollision(hurt);
        }
        else if (body is Bullet bullet) //攻击子弹
        {
            if (TriggerRole != null && TriggerRole.IsEnemy(bullet.BulletData.TriggerRole))
            {
                //反弹子弹
                bullet.OnPlayDisappearEffect();
                var scale = -1f;
                var weapon = bullet.BulletData.Weapon;
                if (weapon != null)
                {
                    scale /= weapon.AiUseAttribute.AiAttackAttr.BulletSpeedScale;
                }
                bullet.MoveController.ScaleAllVelocity(scale);
                bullet.Rotation += Mathf.Pi;
                bullet.Camp = TriggerRole.Camp;
                bullet.RefreshBulletColor(false);
            }
        }
    }
    
    private void OnArea2dEntered(Area2D area)
    {
        if (area is IHurt hurt)
        {
            HandlerCollision(hurt);
        }
    }

    private void HandlerCollision(IHurt hurt)
    {
        if (TriggerRole == null || hurt.CanHurt(TriggerRole.Camp))
        {
            var damage = Utils.Random.RandomConfigRange(Attribute.Bullet.HarmRange);
            //计算子弹造成的伤害
            if (TriggerRole != null)
            {
                damage = TriggerRole.RoleState.CalcDamage(damage);
            }
            //击退
            var attr = GetUseAttribute(TriggerRole);
            var repel = Utils.Random.RandomConfigRange(attr.Bullet.RepelRange);
            //计算击退
            if (TriggerRole != null)
            {
                repel = TriggerRole.RoleState.CalcBulletRepel(repel);
            }
        
            var globalPosition = GlobalPosition;
            if (repel != 0)
            {
                var o = hurt.GetActivityObject();
                if (o != null && o is not Player) //不是玩家才能被击退
                {
                    Vector2 position;
                    if (TriggerRole != null)
                    {
                        position = o.GlobalPosition - TriggerRole.MountPoint.GlobalPosition;
                    }
                    else
                    {
                        position = o.GlobalPosition - globalPosition;
                    }
                    var v2 = position.Normalized() * repel;
                    o.AddRepelForce(v2);
                }
            }
            
            //造成伤害
            hurt.Hurt(TriggerRole, damage, (hurt.GetPosition() - globalPosition).Angle());
        }
    }
}