VR的100天的第31天:游戏结束时停止计时系统

欢迎回到第31天!

昨天,我们创建了一个简单的基于时间的系统,该系统在游戏进行时会在屏幕上运行。 我们只增加时间,但比赛结束后我们永不暂停。

今天,我们将要:

  1. 输赢后暂停我们的时间
  2. 游戏结束后,停止播放玩家的动画和声音效果

今天将是相对较短的一天,但让我们开始吧,对吧?

要阻止我们的游戏显示计时器更新,我们需要做两件事:

  1. 阻止我们的ScoreManager更新字符串的代码
  2. ScoreManager知道游戏结束的某种方式。 谁负责? 我们的GameManager

我们需要做的第一件事是让我们的ScoreManager在游戏结束时停止更新时间。

以下是我们所做的更改:

 使用UnityEngine; 
使用UnityEngine.UI;
公共课ScoreManager:MonoBehaviour
{
公开文字评分;
私人字串_time;
私人布尔值_gameOver;
无效开始()
{
_time =“”;
_gameOver = false;
}
无效Update()
{
如果(!_gameOver)
{
更新时间();
}
}
私有void UpdateTime()
{
int分钟= Mathf.FloorToInt(Time.time / 60);
int秒= Mathf.FloorToInt(Time.time%60);
浮动毫秒= Time.time * 100;
毫秒=毫秒%100;
_time = string.Format(“ {0:0}:{1:00}:{2:00}”,分钟,秒,毫秒);
Score.text = _time;
}
公共无效GameOver()
{
_gameOver = true;
}
}

我们的目标是停止对UpdateTime ()的调用,我们引入了一个名为_gameOver的新布尔值来表明这一点。

我们在这里所做的更改很简单:

  1. Start()中,我们设置实例化_gameOver
  2. Update()中,如果我们仍在玩,我们会更新时间,否则我们什么也不做
  3. 我们创建了一个公共GameOver(),以便其他内容(我们的GameManager )可以告诉我们游戏已经结束,并且我们可以停止更新分数

现在我们有了停止计时器运行的方法,接下来要做的就是调用它。

对我们来说幸运的是,我们有一个GameManager脚本,它可以处理与游戏状态有关的所有事情。 让我们在此处添加代码!

这是我们的更改:

 使用UnityEngine;公共类GameManager:MonoBehaviour 
{
公共Animator GameOverAnimator;
公共动画师VictoryAnimator;
私人GameObject _player;
私人SpawnManager _spawnManager;
私人ScoreManager _scoreManager;
无效Start()
{
_player = GameObject.FindGameObjectWithTag(“ Player”);
_spawnManager = GetComponentInChildren ();
_scoreManager = GetComponent ();
}
公共无效GameOver()
{
GameOverAnimator.SetBool(“ IsGameOver”,true);
DisableGame();
_spawnManager.DisableAllEnemies();
}
公共无效Victory()
{
VictoryAnimator.SetBool(“ IsGameOver”,true);
DisableGame();
}
私人无效DisableGame()
{
_player.GetComponent ()。enabled = false;
_player.GetComponentInChildren ()。enabled = false;
_player.GetComponentInChildren ()。enabled = false;
Cursor.lockState = CursorLockMode.None;
_scoreManager.GameOver();
}
}

就像我们之前说的,我们引入了ScoreManager对象_scoreManager,因此我们可以调用GameOver()

没有进行任何重大或令人惊讶的更改:

  1. Start()中,我们获得了_scoreManager ,该_scoreManager已附加到GameManager游戏对象
  2. DisableGame()中 ,我们将禁用所有内容, 然后_scoreManager调用GameOver()来暂停计时器。

接下来要做的是解决过去两天左右我一直在谈论的问题。 当我们获胜时,我们的玩家(尤其是枪支)会陷入永久射击状态,并且射击声音效果会一直发挥到游戏结束为止。

我们将解决此问题。

大多数代码已经到位,我们只需要:

  1. 创建一个新的状态转换以停止在我们的枪动画师中射击
  2. 为游戏创建新的游戏结束功能,以在游戏结束时停止所有操作
  3. 从我们的GameManager调用游戏结束功能

如果您可能记得从第16天起添加了武器,那么我们创建了一个状态机,每当激活射击触发器时,该状态机就会从射击动画过渡到空闲信息(反之亦然)

我们将创建一个新的GameOver状态,并创建一个从Any StateGameOver的新过渡。

这是我们要做的:

  1. 选择“ 播放器”>“主摄像机”>“ MachineGun_00”,然后打开“ 动画”选项卡 (Windows>“动画”)
  2. 创建一个新参数,它将是一个触发器并将其命名为GameOver
  3. 创建一个名为GameOver的新状态
  4. 创建从任何州到新的新过渡
  5. 选择该过渡并将过渡条件设置为触发GameOver

完成后,我们应该有以下内容:

在这一点上,您可能想知道,如果我们的GameOver状态没有任何剪辑,为什么不重用默认状态呢?

答案是,因为这是我们完成的状态。 我们不想意外触发新的过渡并将我们从默认状态转移到另一个状态。

现在我们有了新的过渡,是时候使用它了!

我们可能还记得,控制玩家射击的脚本是PlayerShootingController

我们将进行一些细微的更改:

 使用UnityEngine; 
使用System.Collections;
公共类PlayerShootingController:MonoBehaviour
{
公共浮动范围= 100;
公共浮动ShootingDelay = 0.1f;
公共AudioClip ShotSfxClips;
公共变换GunEndPoint;
公共浮标MaxAmmo = 10f;
私人相机_camera;
专用ParticleSystem _particle;
私有LayerMask _shootableMask;
私有浮点数_timer;
私有AudioSource _audioSource;
私人Animator _animator;
私人布尔_isShooting;
私人布尔_isReloading;
私人LineRenderer _lineRenderer;
私有浮点数_currentAmmo;
私人ScreenManager _screenManager;
无效开始(){
_camera = Camera.main;
_particle = GetComponentInChildren ();
Cursor.lockState = CursorLockMode.Locked;
_shootableMask = LayerMask.GetMask(“ Shootable”);
_timer = 0;
SetupSound();
_animator = GetComponent ();
_isShooting = false;
_isReloading = false;
_lineRenderer = GetComponent ();
_currentAmmo = MaxAmmo;
_screenManager = GameObject.FindWithTag(“ ScreenManager”)。GetComponent ();
}

无效更新()
{
_timer + = Time.deltaTime;
//在相机视口的中心创建一个矢量
Vector3 lineOrigin = _camera.ViewportToWorldPoint(new Vector3(0.5f,0.5f,0.0f));
//在场景视图中从点lineOrigin沿fpsCam.transform.forward *武器范围的方向绘制一条线,使用绿色
Debug.DrawRay(lineOrigin,_camera.transform.forward * Range,Color.green);
如果(Input.GetMouseButton(0)&& _timer> = ShootingDelay &&!_isReloading && _currentAmmo> 0)
{
射击();
如果(!_isShooting)
{
TriggerShootingAnimation();
}
}
否则if(!Input.GetMouseButton(0)
_currentAmmo <= 0)
{
StopShooting();
如果(_isShooting)
{
TriggerShootingAnimation();
}
}
如果(Input.GetKeyDown(KeyCode.R))
{
StartReloading();
}
}
私有void StartReloading()
{
_animator.SetTrigger(“ DoReload”);
StopShooting();
_isShooting = false;
_isReloading = true;
}
私有void TriggerShootingAnimation()
{
_isShooting =!_isShooting;
_animator.SetTrigger(“ Shoot”);
}
私有无效StopShooting()
{
_audioSource.Stop();
_particle.Stop();
}
私人void Shoot()
{
_timer = 0;
Ray ray = _camera.ScreenPointToRay(Input.mousePosition);
RaycastHit hit =新的RaycastHit();
_audioSource.Play();
_particle.Play();
_currentAmmo--;
_screenManager.UpdateAmmoText(_currentAmmo,MaxAmmo);
_lineRenderer.SetPosition(0,GunEndPoint.position);
StartCoroutine(FireLine());
如果(Physics.Raycast(ray,out hit,Range,_shootableMask))
{
print(“ hit” + hit.collider.gameObject);
_lineRenderer.SetPosition(1,hit.point);
EnemyHealth health = hit.collider.GetComponent ();
EnemyMovement敌人运动= hit.collider.GetComponent ();
打印(健康);
如果(enemyMovement!= null)
{
敌意运动.KnockBack();
}
如果(健康!= null)
{
health.TakeDamage(1);
}
}
其他
{
_lineRenderer.SetPosition(1,ray.GetPoint(Range));
}
}
私有IEnumerator FireLine()
{
_lineRenderer.enabled = true;
收益率ShootingDelay-0.05f; _lineRenderer.enabled = false;
}
//从动画中调用完成
公共无效ReloadFinish()
{
_isReloading = false;
_currentAmmo = MaxAmmo;
_screenManager.UpdateAmmoText(_currentAmmo,MaxAmmo);
}
私人void SetupSound()
{
_audioSource = gameObject.AddComponent ();
_audioSource.volume = 0.2f;
_audioSource.clip = ShotSfxClips;
}
公共无效GameOver()
{
_animator.SetTrigger(“ GameOver”);
StopShooting();
}
}

没有

对于这次代码更改,我们仅添加了一个新的公共函数: GameOver()。

我们做两件事:

  1. 我们调用GameOver触发器来停止射击状态
  2. 我们重新使用StopShooting()来停止粒子和声音效果。

GameOver()是一个公共函数,因此它可以从外部某个地方(在本例中为我们的GameManager脚本) 调用

现在我们有了代码,可以在游戏结束时阻止玩家射击,现在该在GameManager中使用它了

这是我们的更改:

 使用UnityEngine;公共类GameManager:MonoBehaviour 
{
公共Animator GameOverAnimator;
公共动画师VictoryAnimator;
私人GameObject _player;
私人SpawnManager _spawnManager;
私人ScoreManager _scoreManager;
无效Start()
{
_player = GameObject.FindGameObjectWithTag(“ Player”);
_spawnManager = GetComponentInChildren ();
_scoreManager = GetComponent ();
}
公共无效GameOver()
{
GameOverAnimator.SetBool(“ IsGameOver”,true);
DisableGame();
_spawnManager.DisableAllEnemies();
}
公共无效Victory()
{
VictoryAnimator.SetBool(“ IsGameOver”,true);
DisableGame();
}
私人无效DisableGame()
{
_player.GetComponent ()。enabled = false;
_player.GetComponentInChildren ()。enabled = false;
PlayerShootingController ShootingController = _player.GetComponentInChildren ();
ShootingController.GameOver();
ShootingController.enabled = false;
Cursor.lockState = CursorLockMode.None;
_scoreManager.GameOver();
}
}

没有

一切都已经准备就绪,我们唯一要更改的就是在DisableGame()内部

具体来说,我们确保不调用现有的PlayerShootingController ,而是要调用GameOver() ,然后禁用它以防止任何新的用户输入/

有了所有这些功能,我们的游戏就比完成还快1步!

今天我们做到了,这样我们就可以不再计算游戏结束时的时间,并且解决了一个令人讨厌的错误,该错误会使玩家在游戏结束时不断射击。

第31天就这样了! 我认为在第32天,我们将研究创建一个高分系统并将其显示在我们的游戏中!

对此期待!

资料来源:第31天

访问Unity VR开发的100天主页。

访问我们的主页