Newer
Older
DungeonShooting / src / gun / Gun.cs
@小李xl 小李xl on 17 May 2022 4 KB 第一次提交
using Godot;
using System;

public class Gun : Area2D
{
    /// <summary>
    /// 开火回调事件
    /// </summary>
    public event Action<Gun> FireEvent;

    /// <summary>
    /// 属性数据
    /// </summary>
    public GunAttribute Attribute
    {
        get
        {
            if (_attribute == null)
            {
                throw new Exception("请先调用Init来初始化枪的属性");
            }
            return _attribute;
        }
        private set => _attribute = value;
    }
    private GunAttribute _attribute;

    /// <summary>
    /// 枪的图片
    /// </summary>
    public Sprite Sprite { get; private set; }

    /// <summary>
    /// 枪攻击的目标阵营
    /// </summary>
    public CampEnum TargetCamp { get; set; }
    /// <summary>
    /// 开火点
    /// </summary>
    public Position2D FirePoint { get; private set; }
    /// <summary>
    /// 原点
    /// </summary>
    public Position2D OriginPoint { get; private set; }

    /// <summary>
    /// 枪的当前散射半径
    /// </summary>
    public float CurrScatteringRange { get; private set; } = 0;

    //是否按下
    private bool triggerFlag = false;
    private float fireInterval = 0;
    private float fireAngle = 0;
    private float attackTimer = 0;
    private bool attackFlag = false;
    private int downFrame = 0;
    //子弹
    private PackedScene bulletPacked;

    public override void _EnterTree()
    {
        Sprite = GetNode<Sprite>("Sprite");
        FirePoint = GetNode<Position2D>("FirePoint");
        OriginPoint = GetNode<Position2D>("OriginPoint");
    }

    public override void _Process(float delta)
    {
        downFrame = triggerFlag ? downFrame : 0;
        // 攻击的计时器
        if (attackTimer > 0)
        {
            attackTimer -= delta;
        }
        else if (!attackFlag && attackTimer < 0)
        {
            attackTimer = 0;
        }

        if (!attackFlag && attackTimer <= 0)
        {
            CurrScatteringRange = Mathf.Max(CurrScatteringRange - Attribute.ScatteringRangeBackSpeed * delta, Attribute.StartScatteringRange);
        }
        triggerFlag = false;
        attackFlag = false;

        //枪身回归
        Position = Position.MoveToward(Vector2.Zero, 35 * delta);
        if (fireInterval == 0)
        {
            RotationDegrees = 0;
        }
        else
        {
            RotationDegrees = Mathf.Lerp(0, fireAngle, attackTimer / fireInterval);
        }
    }

    public void Init(GunAttribute attribute)
    {
        Attribute = attribute;
        //更新图片
        var texture = ResourceLoader.Load<Texture>(attribute.Sprite);
        Sprite.Texture = texture;
        //子弹
        bulletPacked = ResourceLoader.Load<PackedScene>(attribute.Bullet);
        //开火位置
        FirePoint.Position = new Vector2(attribute.BarrelLength, FirePoint.Position.y);
    }

    /// <summary>
    /// 扳机函数, 调用即视为扣动扳机
    /// </summary>
    public void Trigger()
    {
        //是否第一帧按下
        var justDown = downFrame++ == 0;

        if (Attribute.ContinuousShoot || justDown)
        {
            if (attackTimer <= 0)
            {
                fireInterval = 60 / Attribute.FiringSpeed;
                attackTimer += fireInterval;
                Fire();
                //当前的散射半径
                CurrScatteringRange = Mathf.Min(CurrScatteringRange + Attribute.ScatteringRangeAddValue, Attribute.FinalScatteringRange);
                //枪的旋转角度
                RotationDegrees -= Attribute.UpliftAngle;
                fireAngle = RotationDegrees;
                //枪身位置
                Position = new Vector2(Mathf.Max(-Attribute.MaxBacklash, Position.x - MathUtils.RandRange(Attribute.MinBacklash, Attribute.MaxBacklash)), Position.y);

                if (FireEvent != null)
                {
                    FireEvent(this);
                }
            }
            attackFlag = true;
        }
        triggerFlag = true;
    }

    protected virtual void Fire()
    {
        //开火发射的子弹数量
        var bulletCount = MathUtils.RandRangeInt(Attribute.MaxFireBulletCount, Attribute.MinFireBulletCount);
        //枪口角度
        var angle = new Vector2(GameConfig.ScatteringDistance, CurrScatteringRange).Angle();

        //创建子弹
        for (int i = 0; i < bulletCount; i++)
        {
            //先算枪口方向
            Rotation = (float)GD.RandRange(-angle, angle);

            //创建子弹
            var bullet = bulletPacked.Instance<Bullet>();
            bullet.GlobalPosition = FirePoint.GlobalPosition;
            bullet.Rotation = (FirePoint.GlobalPosition - OriginPoint.GlobalPosition).Angle();
            GetTree().CurrentScene.AddChild(bullet);

            //飞行距离
            var distance = MathUtils.RandRange(Attribute.MinDistance, Attribute.MaxDistance);
            //初始化子弹数据
            bullet.Init(TargetCamp, distance, Colors.White);
        }
    }
}