子弹连发以及后坐力动画制作

本文介绍了如何在Unity中创建一个名为Ryun_WeaponController的脚本来实现武器的子弹连发功能和后坐力动画。脚本使用协程(Coroutine)来控制子弹的发射间隔和后坐力的平滑过渡,同时详细解释了协程的工作原理及其在游戏循环中的作用。通过这种方式,可以优化性能,避免频繁更新带来的开销。
摘要由CSDN通过智能技术生成

首先我们看到Weapon_01的一些内容:注意层级关系

Ryun_WeaponController 脚本制作

给出子弹连发的具体脚本,新建一个Ryun_WeaponController 脚本:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Ryun_WeaponController : MonoBehaviour
{
     public Transform bulletstartpoint;
     public GameObject bullet;//首先在hierarchy窗口新建一个bullet_001,设置好Material材质,调整大小后将其生成预制体。后面将该预制体拖给bullet变量
     public float bulletstartspeed = 100;//设置子弹初始的发射速度为100
     public float fireinterval = 0.1f;//设置子弹开火间隔时间为0.1f
     public bool isFire = false;//设置布尔类型的isFire初始化为false

     public Transform dufalutpoint;
     public Transform Backpoint;//为子弹后坐力动画设置两个Transform类型的位置,分别代表默认位置和后坐力位置,调整这两个Transform的位置(一前一后)
     public float lerpRatio = 0.2f;//设置插值ratio为0.2f.

     public AudioSource shootaudio;//定义一个AudioSource 类型的音频变量,首先要在Weapon_01上挂载一个AudioSource组件,并加载开火音效。设置Play On Awake为false

// Start is called before the first frame update
  void Start()
  {

  }

// Update is called once per frame
  void Update()
  {
     OpenFire();
  }

  private void OpenFire()//控制动画开火的函数
  {
     if (Input.GetMouseButtonDown(0))//按下鼠标左键瞬间
     {
      isFire = true;
      StartCoroutine("Fire");//开火时调用协程函数


      }
     if (Input.GetMouseButton(0))
     {




     }
    if (Input.GetMouseButtonUp(0))
     {

     isFire = false;
     StopCoroutine("Fire");//如果鼠标松开,isFire设置为false,停止开火,停止调用协程函数



     }


 }


  IEnumerator Fire()//定义协程函数 Fire() ---协程并不会在Unity中开辟新的线程来执行,其执行仍然发生在主线程中。当我们有较为耗时的操作时,可以将该操作分散到几帧或者几秒内完成,而不用在一帧内等这个操作完成后再执行其他操作。(互不影响)
 {
     while (isFire == true)//大前提
    {
       if (bulletstartpoint != null || bullet != null)//bulletstartpoint 即为子弹发射的初始位置
      {
         GameObject newbullet = Instantiate(bullet, bulletstartpoint.position, bulletstartpoint.rotation);
      //GameObject :Unity 场景中所有实体的基类。这里定义一个GameObject 类型的变量newbullet,并将其实例化



         newbullet.GetComponent<Rigidbody>().velocity = newbullet.transform.forward * -bulletstartspeed;
        //将该变量获取一个Rigidbody的Component,将子弹的速度velocity给一个bulletstartspeed
         shootaudio.Play();//开火时调用音频播放函数

         StopCoroutine("Weaponbackanimation");//每帧调用时将上一帧的播放动画停止以防连击发生冲突
         StartCoroutine("Weaponbackanimation");//开火时调用Weaponbackanimation协程函数
         Destroy(newbullet, 5);//每间隔5秒销毁一个子弹


       }

        yield return new WaitForSeconds(fireinterval);//中断函数,间隔0.2秒重新执行IEnumerator Fire(),这里将开火的函数调用改变为0.2秒的响应时间。在这中间可能有多帧在调用后坐力动画的效果。关于这个yield return new WaitForSeconds的设置就很有必要


      }
 }


  IEnumerator Weaponbackanimation()//利用协程函数控制子弹后坐力动画
  {


       if (dufalutpoint != null && Backpoint != null)//大前提
       {
           while (this.transform.localPosition != Backpoint.localPosition)
          {

            this.transform.localPosition = Vector3.Lerp(this.transform.localPosition, Backpoint.localPosition, lerpRatio*4);
      //Lerp函数在unity中可以用于物体到达另外一个目标物体之间进行平滑过渡运动效果。
      //函数原型为Lerp(a,b,t);内部实现为y = b+(1-t)*a;其中t被clamp在了[0,1],也就是说最小为0,最大为1.


             yield return null;
           // yield return null表示暂缓一帧,在下一帧接着往下处理,即等待下一帧(Update函数执行后)继续执行,这恰恰做到了单帧所做不到的事!大家可以自行思考。
           }


           while (this.transform.localPosition != dufalutpoint.localPosition)//反向过渡
          {

            this.transform.localPosition = Vector3.Lerp(this.transform.localPosition, dufalutpoint.localPosition, lerpRatio);
            yield return null;
          }
        }

  }
    private void Playshootaudio()//定义一个播放开火音频的函数,在开火瞬间调用
    {

         if (shootaudio)
        {
         shootaudio.Play();
        }

     }

}

自此,可实现子弹连击和后坐力动画的播放。

关于IEnumerator函数

Ryun_WeaponController 脚本里的协程:

  1. IEnumerator Fire()//定义协程函数 Fire() ---协程并不会在Unity中开辟新的线程来执行,其执行仍然发生在主线程中。当我们有较为耗时的操作时,可以将该操作分散到几帧或者几秒内完成,而不用在一帧内等这个操作完成后再执行其他操作。

  1. IEnumerator Weaponbackanimation()//利用协程函数控制子弹后坐力动画

Update调用函数时,函数将运行到完成状态,然后返回。这实际上意味着在函数中发生的任何动作都必须在单帧更新内发生;函数调用不能用于包含程序性动画或随时间推移的一系列事件。

引入协程:(操作分散到几帧或者几秒内完成)

协程:协程是一个分部执行,遇到条件(yield return 语句)时才会挂起,直到条件满足才会被唤醒继续执行后面的代码。

此协程本质上是一个用返回类型 IEnumerator 声明的函数,并在主体中的某个位置包含 yield return 语句。yield return null 行是暂停执行并随后在下一帧恢复的点(单帧频率执行)。要将协程设置为运行状态,必须使用 StartCoroutine 函数:

 StopCoroutine("Weaponbackanimation");//每帧调用时将上一帧的播放动画停止以防连击发生冲突
 StartCoroutine("Weaponbackanimation");//开火时调用Weaponbackanimation协程函数

默认情况下,协程将在执行 yield 后的帧上恢复,但也可以使用 WaitForSeconds 来引入时间延迟

IEnumerator Fade()
{
  for (float ft = 1f; ft >= 0; ft -= 0.1f)
  {
    Color c = renderer.material.color;
    c.a = ft;
    renderer.material.color = c;
    yield return new WaitForSeconds(0.1f);
  }
}

可通过这样的协程在一段时间内传播效果,但也可将其作为一种有用的优化。游戏中的许多任务需要定期执行,最容易想到的方法是将任务包含在 Update 函数中。但是,通常情况下,每帧将多次调用该函数。不需要以这样的频繁程度重复任务时,可以将其放在协程中来进行定期更新,而不是每一帧都更新。

这方面的一个示例可能是在附近有敌人时向玩家发出的警报。此代码可能如下所示:

function ProximityCheck() 
{
    for (int i = 0; i < enemies.Length; i++)
    {
        if (Vector3.Distance(transform.position, enemies[i].transform.position)< dangerDistance)
        {
                return true;
        }
    }
    
    return false;
}

如果有很多敌人,那么每帧都调用此函数可能会带来很大开销。但是,可以使用协程,每十分之一秒调用一次:

IEnumerator DoCheck() 
{
    for(;;) 
    {
        ProximityCheck();
        yield return new WaitForSeconds(.1f);
    }
}

这将大大减少所进行的检查次数,而不会对游戏运行过程产生任何明显影响。

补充内容来源于:

(122条消息) unity笔记--协程StartCoroutine和yield return_协程与yield return_babywang0的博客-CSDN博客

具体可参考下面博主的文章:

版权声明:本文为CSDN博主「做一只会飞的猪」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。

原文链接:https://blog.csdn.net/beihuanlihe130/article/details/76098844

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

嘿君

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值