Unity射击游戏手榴弹笔记

功能

  1. 按3如果没在用手榴弹,则拿出手榴弹。如果在用,则切换下一种手榴弹。没有则空手;

数据

  1. 新增手榴弹配表数据类,新建手榴弹配表,配表管理器新增手榴弹配表字典,初始化增加读取配表并转换成字典的代码,增加根据id得到手榴弹详情的方法;
  2. 手榴弹的预制体需要可拾取的、扔出的;
  3. 背包界面增加背包内的手榴弹、场景里的手榴弹、别人背包的手榴弹格子预制体和类;
  4. 人物有一个int grenadeIndex记录当前拿着的手榴弹在背包手榴弹列表的索引,没拿手榴弹时是-1;
  5. 每种手榴弹有一个待拾取预制体和一个生效预制体。待拾取预制体有一个手榴弹模型、一个触发器用来被玩家检测到,一个数据脚本记录自己是哪种手榴弹,没有投掷、爆炸相关功能。生效预制体有刚体碰撞体管理运动,投掷、爆炸相关功能。

用枚举记录手榴弹类型

public enum GrenadeType{
        Frag,Smoke,Flash
    }

 手榴弹详细数据,这里不管类型,所有需要的数据都写在这里

 [Serializable]
    public class GrenadeDataBin:ItemDataBin{
        public GrenadeType grenadeType;
        public Grenade prefabThrowed;
        public ParticleSystem explosionEffect;
        public AudioClip explodeAudio;
        public float explodeDelay=3;
        public float lifeTimeAfterExplode;
        public float explodeRadius=2;
        public int damage;
    }

逻辑

拾取和使用

  1. 在交互系统的拾取物品分支增加对手榴弹类的判断;
  2. 按拿出手榴弹的按键时
    public void GetThrowInput(InputAction.CallbackContext input){
            if(input.ReadValue<float>()==0){
                switch(player.animator.GetInteger(CharacterBase.gunStatusPara)){
                    case CharacterBase.noWeaponState:
                    case CharacterBase.rifleState:
                    case CharacterBase.handgunState:
                        player.UseGrenade();
                        break;
                    case 3:
                        player.PutAwayGun();
                        break;
                }
            }
        }

  3. GetNextGrenade():在背包的手榴弹列表遍历,有和grenadeIndex类型不同的手榴弹则返回索引,没有则返回-1;
    public int GetNextGrenade(){
            if(grenadeInHandIndex==-1){//手里没有手榴弹
                if(backpack.itemsInPack.grenadesInPack.Count>0){//背包里有,拿第一个
                    return 0;
                }
                else{
                    return -1;//背包里没有,不拿
                }
            }
            for(int i=0;i<backpack.itemsInPack.grenadesInPack.Count;i++){//手里有手榴弹,切换下一种
                if(backpack.itemsInPack.grenadesInPack[i].id!=
                backpack.itemsInPack.grenadesInPack[grenadeInHandIndex].id){
                    return i;
                }
            }
            return -1;
        }
  4. UseGrenade(),先执行grenadeIndex=GetNextGrenade(),在右手实例化手榴弹,没有则回到空手;
public void UseGrenade(){
        grenadeInHandIndex=GetNextGrenade();//去背包拿手榴弹
        if(grenadeInHandIndex==-1){//没拿到
            PutAwayGun();
            return;
        }
        animator.SetInteger(gunStatusPara,3);
        GrenadeDataBin grenadeDataBin=ItemDataManager.Instance.GetGrenadeData(
            backpack.itemsInPack.grenadesInPack[grenadeInHandIndex].id);
        grenadeInHand=Instantiate(grenadeDataBin.prefab,weaponHolder).GetComponent<Grenade>();
        grenadeInHand.grenadeDataBin = grenadeDataBin;
        grenadeInHand.owner=this;
    }
  1. 扔手榴弹方法通过动画事件执行
public void ThrowGrenade(){
        grenadeInHand.Throwed(aimAxis.forward*throwSpeed);
        backpack.TakeOutGrenade(grenadeInHandIndex);
        grenadeInHand=null;
        grenadeInHandIndex=-1;
        UseGrenade();//拿下一个或空手
    }

物理

手榴弹只和地面层碰撞,不能碰撞人物,否则干扰扔出手榴弹的弹道。

爆炸效果

扔出一段时间后爆炸,生成粒子效果,播放爆炸声音, 粒子效果播放完后销毁。

public void Throwed(Vector3 velocity){
            transform.SetParent(null);
            _rigidbody.isKinematic=false;
            _collider.isTrigger=false;
            _rigidbody.velocity=velocity;
            StartCoroutine(Explode());
        }
        IEnumerator Explode(){
            yield return new WaitForSeconds(grenadeData.explodeDelay);
           ParticleSystem effect=Instantiate(grenadeData.explosionEffect,transform.position,Quaternion.identity);
            switch(grenadeData.grenadeType){
                case GrenadeType.Frag://杀伤弹,爆炸后消失,特效存留一段时间
                ExplodeDamage();
                break;
            }
            if(grenadeData.explodeAudio){
                MyAudioManager.Instance.MyPlaySound(effect.AddComponent<AudioSource>(),grenadeData.explodeAudio);
            }
            Destroy(effect.gameObject,effect.main.duration+effect.main.startLifetime.constant);
            Destroy(gameObject,grenadeData.lifeTimeAfterExplode);
        }

    伤害判定

    进行球形范围检测,检测到人物后再拿人物躯干和手榴弹做一次连线检测Physics.LineCast(),检测手榴弹和人物chest之间没障碍,再触发伤害。这里不再用人物的中枪触发器,只要人物碰撞体在爆炸范围内就受到一样的伤害。

    void ExplodeDamage(){
                Collider[] colliders=Physics.OverlapSphere(transform.position,
                grenadeData.explodeRadius,1<<MyGameManager.characterLayer);
                CharacterBase character;
                for(int i=0;i<colliders.Length;i++){
                    if(colliders[i].TryGetComponent(out character)){
                        if(!Physics.Linecast(transform.position,character.
                        chest.position,1<<MyGameManager.groundLayer)){
                            character.TakeDamage(grenadeData.damage,"注意敌人");
                        }
                    }
                }
            }

    声音

    爆炸声音会在手榴弹爆炸并消失后持续一段时间,不能把声源放在手榴弹上并在爆炸时销毁或失活手榴弹,可以把声源放在粒子效果上。

    人物动画

    1. 手榴弹动画放在上半身层,有一个空闲动画和投掷动画;

    温雷功能

    需求:按下鼠标拔环,拔环结束后如果没有松开则保持,开始计时。如果已经松开则抛出。

    动画剪裁为拉环、抛出两段。

    拉环和抛出各用一个trigger,按下鼠标设置拉环trigger,松开设置抛出trigger。这样即使立即按下抬起,抛出trigger也会保持着,直到拔环动作结束,直接出发抛出。

    问题是在输入回调脚本和人物脚本分开的架构下,原本射击逻辑只关心鼠标是true还是false,现在扔雷要知道按下抬起的瞬间。要怎么修改?

    我们想到inputSystem的回调函数就是在输入值改变时执行。但是还需要判断人物是不是拿着手雷,是则在执行时设置人物的那两个trigger。然后我发现按下鼠标时这个回调会执行2次,会把pullRing触发2次,但是并没有造成问题,第二次触发pullTrigger也被复原了?

    public void GetFireInput(InputAction.CallbackContext input)
            {
                firePressed = input.ReadValue<float>() == 1;
                if (firePressed)
                {
                    player.StartPullTrigger();
                }
                else
                {
                    player.StopPullTrigger();
                }
            }

    评论
    成就一亿技术人!
    拼手气红包6.0元
    还能输入1000个字符
     
    红包 添加红包
    表情包 插入表情
     条评论被折叠 查看
    添加红包

    请填写红包祝福语或标题

    红包个数最小为10个

    红包金额最低5元

    当前余额3.43前往充值 >
    需支付:10.00
    成就一亿技术人!
    领取后你会自动成为博主和红包主的粉丝 规则
    hope_wisdom
    发出的红包
    实付
    使用余额支付
    点击重新获取
    扫码支付
    钱包余额 0

    抵扣说明:

    1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
    2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

    余额充值