文章目录
- 玩家射击管理
- 基本配置
- 添加射击脚步
- 玩家生命值管理
- 建立玩家生命值UI元素
- 编写玩家生命值管理脚本
- 敌人生命值管理
- 敌人自动生成管理
- 编写敌人自动生成脚本
- 游戏结束的管理
- 编写游戏结束脚本
接上一篇博客
玩家射击管理
基本配置
- 在玩家预制体的第二层级,有一个GunBarrelEnd子物体,在其上管理我们的射击事件。
- 首先,添加射击的声音。
- 在资源包中找到Gunparticles这个粒子特效,拖到物体上,作为射击开火的特效。
- 添加Light组件,设置颜色为黄色,意思是火线。
- 添加LineRender组件,设置射线粗细以及材质
添加射击脚步
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityProject;
public class PlayerShooting : MonoBehaviour
{
public int damagePerShot = 20;
public float timeBetweenBullets = 0.15f;
public float range = 100f;
float timer;
Ray shootRay; //子弹飞行时的射线轨迹
RaycastHit shootHit;
int shootableMask; //shootable层的掩码
ParticleSystem gunParticles;
LineRenderer gunLine;
AudioSource gunAudio;
Light gunLight;
float effectsDisplayTime = 0.2f;
void Awake()
{
shootableMask = LayerMask.GetMask("Shootable");
gunParticles = GetComponent<ParticleSystem>();
gunLine = GetComponent<LineRenderer>();
gunAudio = GetComponent<AudioSource>();
gunLight = GetComponent<Light>();
}
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
void Update()
{
timer += Time.deltaTime;
//玩家按下射击键,射击
if (Input.GetButton("Fire1") && timer >= timeBetweenBullets)
{
Shoot();
}
//玩家未按下射击键,且超过规定时间间隔
if (timer >= timeBetweenBullets * effectsDisplayTime)
{
DisableEffects();
}
}
//熄火
public void DisableEffects()
{
gunLine.enabled = false; //组件禁用
gunLight.enabled = false;
}
void Shoot()
{
timer = 0f;
gunAudio.Play();
gunLight.enabled = true;
gunParticles.Stop();
gunParticles.Play();
gunLine.enabled = true;
gunLine.SetPosition(0, transform.position);
shootRay.origin = transform.position;
shootRay.direction = transform.forward;
//检测shootRay在指定方向(由transform.forward指定)上和指定层(shootableMask)上与怪物对象的碰撞情况
if (Physics.Raycast(shootRay, out shootHit, range, shootableMask))
{
//如果shootRay和shootableMask层上的对象发生率碰撞,则调取碰撞对象上的EnemyHealth脚本
EnemyHealth enemyHealth = shootHit.collider.GetComponent<EnemyHealth>();
//如果组件不为空
if (enemyHealth != null)
{
//对象的生命值减少damagePerShot,且在击中点shootHit.point播放击中的粒子特效
//然后设置LineRender组件的终点为碰撞点。这样就会显示激光的效果
enemyHealth.TakeDamage(damagePerShot, shootHit.point);
}
//终点序号为1,起点序号为0
gunLine.SetPosition(1, shootHit.point);
}
else
{
//如果未击中对象,则在射击方向上显示长度为range的激光
gunLine.SetPosition(1, shootRay.origin + shootRay.direction * range);
}
}
}
玩家生命值管理
建立玩家生命值UI元素
- 首先,我们在Hierachy层级新建UI—Canvas,重命名为HUDCanvas。
- 在其上建立HealthUI空物体,将其位置定位在左下角。
- 在HealthUI子物体上建立一个Image物体和滑动条,自定义进行设置
- 另外呢,一般咱玩游戏时,玩家受到伤害,在UI上会有交互,这里也样。在画布下新建Image物体重命名为DamageImage。设置它为平铺的效果,铺满整个屏幕。在脚本中来设置它的颜色,当玩家一受到伤害,这个图片就闪现一下。
编写玩家生命值管理脚本
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using UnityProject;
public class PlayerHealth : MonoBehaviour
{
public int startingHealth = 100;
public int currentHealth;
public Slider healthSlider;
public Image damageImage;
public AudioClip deathClip;
public float flashSpeed = 5f;
public Color flashColor = new Color(1f, 0f, 0f ,0.1f);
Animator anim;
AudioSource playerAudio;
PlayerMovement playerMovement;
PlayerShooting playerShooting;
bool isDead;
bool damaged;
void Awake()
{
anim = GetComponent<Animator>();
playerAudio = GetComponent<AudioSource>();
playerMovement = GetComponent<PlayerMovement>();
playerShooting = GetComponentInChildren<PlayerShooting>();
currentHealth = startingHealth;
}
// Start is called before the first frame update
void Start()
{
}
// 更新damageImage的color属性
void Update()
{
if(damaged)
{
damageImage.color = flashColor;
}
else
{
damageImage.color = Color.Lerp(damageImage.color, Color.clear, flashSpeed * Time.deltaTime);
}
damaged = false;
}
//public权限可以在其他脚本中调用该函数
public void TakeDamage(int amount)
{
damaged = true;
currentHealth -= amount;
healthSlider.value = currentHealth;
playerAudio.Play();
if(currentHealth <= 0 && !isDead)
{
Death();
}
}
void Death()
{
isDead = true;
playerShooting.DisableEffects();
anim.SetTrigger("Die");
playerAudio.clip = deathClip;
playerAudio.Play();
playerMovement.enabled = false;
playerShooting.enabled = false;
}
}
敌人生命值管理
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.AI;
public class EnemyHealth : MonoBehaviour
{
public int startingHealth = 100;
public int currentHealth ;
public float sinkSpeed = 2.5f;
public int scoreValue = 10;
public AudioClip deathClip;
Animator anim;
AudioSource enemyAudio;
ParticleSystem hitParticles;
CapsuleCollider capsuleCollider;
bool isDead;
bool isSinking;
void Awake()
{
anim = GetComponent<Animator>();
enemyAudio = GetComponent<AudioSource>();
hitParticles = GetComponentInChildren<ParticleSystem>();
capsuleCollider = GetComponent<CapsuleCollider>();
currentHealth = startingHealth;
}
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
void Update()
{
if (isSinking)
{
transform.Translate(-Vector3.up * sinkSpeed * Time.deltaTime);
}
}
public void TakeDamage(int amount ,Vector3 hitPoint)
{
if (isDead) {return;}
enemyAudio.Play();
currentHealth -= amount;
//先设定粒子系统的坐标为hitPoint,然后播放粒子特效
hitParticles.transform.position = hitPoint;
hitParticles.Play();
if (currentHealth <=0)
{
Death();
}
}
void Death()
{
isDead = true;
capsuleCollider.isTrigger = true;
anim.SetTrigger("Dead");
enemyAudio.clip = deathClip;
enemyAudio.Play();
}
//怪物下沉
public void StartSinking()
{
GetComponent<NavMeshAgent>().enabled = false;
GetComponent<Rigidbody>().isKinematic = true;
isSinking = true;
Destroy(gameObject, 2f); //2s后销毁
}
}
敌人自动生成管理
- 在这里我们把Hierarchy层级中我们做好的敌人拖到Project面板中做成预制体,将Hierarchy层级中的敌人删除。
- 在Hierarchy层级中新建一个空物体重命名为EnemyManager。
- 在Hierarchy层级中新建一个空物体重命名为SpawnPoints,然后新建两个子物体ZombunnySpanwPoint和HellephantSpawnPoint作为敌人的诞生点。
编写敌人自动生成脚本
把脚本挂载到EnemyManager上
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class EnemyManager : MonoBehaviour
{
public PlayerHealth playerHealth;
public GameObject enemy;
public float spawnTime = 3f;
public Transform[] spawnPoints;
// Start is called before the first frame update
void Start()
{
//用于在每间隔spawnTime时间之后,重复调用函数Spawn来不断实例化敌人对象
InvokeRepeating("Spawn", spawnTime, spawnTime);
}
void Spawn()
{
if (playerHealth.currentHealth <= 0f)
{
return;
}
int spawnPointIndex = Random.Range(0, spawnPoints.Length);
Instantiate(enemy, spawnPoints[spawnPointIndex].position, spawnPoints[spawnPointIndex].rotation);
}
// Update is called once per frame
void Update()
{
}
}
游戏结束的管理
- 在我们之前创建的画布下新建一个Image物体,叫ScreenFader。同样是要平铺整个屏幕。
- 在画布下创建一个Text物体,叫GameOverText。
- 然后呢,我们想实现一个效果,就是玩家死了,游戏结束,这个结束画面就弹出来,这个功能可以通过制作一个animation动画实现。
- 我们在Project窗口中新建一个Animation动画重命名为GameOverClip。
- 然后我们首先选中我们的画布,在Animation窗口中添加四个参数:GameOverText.Scale , GameOverText.Text.Color , ScoreText.Scale, ScreenFader.Image.Color
- 我们把所有参数都拖到开始帧和结束帧上,然后在中间设置关键帧,比如设置ScoreText文字的大小。设置开始帧和结束帧不同的参数值,比如缩放比例,开始为0 ,结束为1,再比如图片的alpha值,这样就生成了渐变动画。
- 最后我们在Project新建Animator Controller重命名为HUDCanvas,把我们刚才制作的GameOverClip拖到动画控制器窗口。左边添加一个Trigger属性的GameOver。
- 在窗口中添加一个空白状态机,不然的话不管什么状况直接就从Entry进入到GameOverClip,这样显然不合理。设置这个空状态机为默认状态。设置空状态机到GameOverClip的连接,条件是GameOver。
- 最后我们在这个画布上添加Animator组件,选择动画控制器。
编写游戏结束脚本
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;
public class GameOverManager : MonoBehaviour
{
public PlayerHealth playerHealth;
public float restartDelay = 5f;
Animator anim;
float restartTime;
void Awake()
{
anim = GetComponent<Animator>();
}
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
void Update()
{
if (playerHealth.currentHealth <= 0)
{
anim.SetTrigger("GameOver");
restartTime += Time.deltaTime;
if (restartTime >= restartDelay)
{
SceneManager.LoadScene("Mainstage");
}
}
}
}
嗯嗯基本大功告成啦!!!!!