Newer
Older
DungeonShooting / DungeonShooting_Godot / src / game / activity / bullet / normal / Bullet.cs
@小李xl 小李xl on 5 Nov 2023 5 KB 优化子弹创建逻辑
using System.Collections;
using Config;
using Godot;

/// <summary>
/// 子弹类
/// </summary>
[Tool]
public partial class Bullet : ActivityObject, IBullet
{
    /// <summary>
    /// 碰撞区域
    /// </summary>
    [Export, ExportFillNode]
    public Area2D CollisionArea { get; set; }

    /// <summary>
    /// 攻击的层级
    /// </summary>
    public uint AttackLayer
    {
        get => CollisionArea.CollisionMask;
        set => CollisionArea.CollisionMask = value;
    }

    public BulletData BulletData { get; private set; }


    //当前子弹已经飞行的距离
    private float CurrFlyDistance = 0;

    public override void OnInit()
    {
        CollisionArea.AreaEntered += OnArea2dEntered;
    }
    
    public void InitData(BulletData data, uint attackLayer)
    {
        BulletData = data;
        AttackLayer = attackLayer;
        Position = data.Position;
        Rotation = data.Rotation;
        ShadowOffset = new Vector2(0, 5);
        BasisVelocity = new Vector2(data.FlySpeed, 0).Rotated(Rotation);
        
        //如果子弹会对玩家造成伤害, 则显示红色描边
        if (Player.Current.CollisionWithMask(attackLayer))
        {
            ShowBorderFlashes();
        }
        PutDown(RoomLayerEnum.YSortLayer);
        //播放子弹移动动画
        PlaySpriteAnimation(AnimatorNames.Move);
    }
    
    /// <summary>
    /// 显示红色描边
    /// </summary>
    public void ShowBorderFlashes()
    {
        ShowOutline = true;
        OutlineColor = new Color(1, 0, 0);
        StartCoroutine(BorderFlashes());
    }
    
    private IEnumerator BorderFlashes()
    {
        while (true)
        {
            ShowOutline = !ShowOutline;
            yield return new WaitForSeconds(0.12f);
        }
    }

    /// <summary>
    /// 播放子弹消失的特效
    /// </summary>
    public virtual void PlayDisappearEffect()
    {
        var packedScene = ResourceManager.Load<PackedScene>(ResourcePath.prefab_effect_weapon_BulletDisappear_tscn);
        var node = packedScene.Instantiate<Node2D>();
        node.GlobalPosition = GlobalPosition;
        node.AddToActivityRoot(RoomLayerEnum.YSortLayer);
    }
    
    protected override void PhysicsProcessOver(float delta)
    {
        //移动
        var lastSlideCollision = GetLastSlideCollision();
        //撞到墙
        if (lastSlideCollision != null)
        {
            //创建粒子特效
            var packedScene = ResourceManager.Load<PackedScene>(ResourcePath.prefab_effect_weapon_BulletSmoke_tscn);
            var smoke = packedScene.Instantiate<GpuParticles2D>();
            smoke.GlobalPosition = lastSlideCollision.GetPosition();
            smoke.GlobalRotation = lastSlideCollision.GetNormal().Angle();
            smoke.AddToActivityRoot(RoomLayerEnum.YSortLayer);
            Destroy();
            return;
        }
        //距离太大, 自动销毁
        CurrFlyDistance += BulletData.FlySpeed * delta;
        if (CurrFlyDistance >= BulletData.MaxDistance)
        {
            PlayDisappearEffect();
            Destroy();
        }
    }
    
    private void OnArea2dEntered(Area2D other)
    {
        var role = other.AsActivityObject<Role>();
        if (role != null)
        {
            var packedScene = ResourceManager.Load<PackedScene>(ResourcePath.prefab_effect_weapon_BulletDisappear_tscn);
            var node = packedScene.Instantiate<Node2D>();
            node.GlobalPosition = GlobalPosition;
            node.AddToActivityRoot(RoomLayerEnum.YSortLayer);

            //计算子弹造成的伤害
            var damage = Utils.Random.RandomRangeInt(BulletData.MinHarm, BulletData.MaxHarm);
            if (BulletData.TriggerRole != null)
            {
                damage = BulletData.TriggerRole.RoleState.CallCalcDamageEvent(damage);
            }

            //击退
            if (role is not Player) //目标不是玩家才会触发击退
            {
                var attr = BulletData.Weapon.GetUseAttribute(BulletData.TriggerRole);
                var repel = Utils.Random.RandomConfigRange(attr.Bullet.RepelRnage);
                if (repel != 0)
                {
                    role.MoveController.AddForce(Vector2.FromAngle(BasisVelocity.Angle()) * repel);
                }
            }
            
            //造成伤害
            role.CallDeferred(nameof(Role.Hurt), damage, Rotation);
            Destroy();
        }
    }

    protected override void OnDestroy()
    {
        StopAllCoroutine();
    }

    private void TestBoom()
    {
        //击中爆炸,测试用
        if (BulletData.TriggerRole == null || !BulletData.TriggerRole.IsAi)
        {
            var explode = ObjectManager.GetExplode(ResourcePath.prefab_bullet_explode_Explode0001_tscn);
            explode.Position = Position;
            explode.RotationDegrees = Utils.Random.RandomRangeInt(0, 360);
            explode.AddToActivityRootDeferred(RoomLayerEnum.YSortLayer);
            explode.Init(BulletData.TriggerRole.AffiliationArea, AttackLayer, 25, BulletData.MinHarm, BulletData.MaxHarm, 50, 150);
            explode.RunPlay();
        }
    }
}