闲杂:
想玩游戏的时候就来写博客,其实我个人的感觉写博客就跟写书是一样的吗,写书是将内心的故事呈现给读者,而写博客就是将技术呈现给读者,一方面我们可以将自己的技术分享出来供大家学习,第二个是希望大家可以给我的技术做一些指点,互相学习互相交流,希望能在评论区多多留言,我也可以解决疑难杂症。
故事开始:
在FPS的游戏开发当中设计到枪械的方面,手雷的方面,近战武器,以及一些特殊的道具,所以这些模块值得去深挖和细品,古人云:彩虹风雨后,成功细节中(我也不知道是哪个古人说的)
我的思路,搭建场景,然后给box添加上Rigibody组件(不要给地面也添加该组件,会出现很奇怪的情况,如果想试一试的小伙伴,可以玩一下)
接下来就是Granade,吐槽一下,我的第一版手雷和上面的箱子一样大,由于太过搞笑所以我就弄了手雷2.0,看起来就舒服多了
接下来就是脚本方面了,我的思路是这样的,首先是Granade.cs的脚本
- 手雷延时爆炸delay
- 手雷的爆炸半径
- 手雷的爆炸力度
这三方面考虑好后就可以开始写脚本了,代码如下:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Granade : MonoBehaviour
{
public float delay = 3f;
public float radius = 5f;
public float force = 700f;
public GameObject ExplosionEffect;
public GameObject ExplosionAudio;
float countDown;
bool hasExploaded = false;
void Start()
{
countDown = delay;
}
void Update()
{
countDown -= Time.deltaTime;
if (countDown <= 0f && !hasExploaded)
{
Explode();
hasExploaded = true;
}
}
void Explode()
{
Instantiate(ExplosionEffect, transform.position, transform.rotation);
Instantiate(ExplosionAudio, transform.position, transform.rotation);
//add force to move
//该半径内的所有碰撞器,返回一个数组
Collider[] collidersToMove = Physics.OverlapSphere(transform.position,radius);
//遍历球体内的所有Collider
foreach (Collider nearbyObject in collidersToMove)
{
//获取球体半径范围内的rigibody
Rigidbody rb = nearbyObject.GetComponent<Rigidbody>();
if (rb != null)
{
//向模拟爆炸效果的刚体施加力
rb.AddExplosionForce(force,transform.position, radius);
}
}
Destroy(gameObject);
}
//Granade Demage
}
代码分析:
我在此脚本中用了一个特殊的方法,我们知道,当物体被销毁的时候,身上的脚本以及组件都被销毁了,所以不能够将声音和爆炸的特效挂载到手雷上面,而是应该单独做成两个预制体,接下来在手雷爆炸的时候将这两个预制体加载出来,这样就解决了这个办法。
Instantiate(ExplosionEffect, transform.position, transform.rotation);
Instantiate(ExplosionAudio, transform.position, transform.rotation);
然后给Granade添加爆炸力和爆炸范围
Collider[] collidersToMove = Physics.OverlapSphere(transform.position,radius);
在官方文档中,讲到了参数和使用方法。我解释一下返回Collider数组的作用,这里是将球形范围内的所有包含Collder组件的物体都存起来,接下来遍历球体内物体上的Rigibody组件,然后可以给含有该组件的物体添加爆炸力度,爆炸力是手雷来提供的,这样就实现了手雷爆炸击飞箱子。
rb.AddExplosionForce(force,transform.position, radius);
Granade的部分就完成了,接下来就是手雷爆炸特效和手雷音效销毁,回收的阶段,我遇到的问题是特效如果不销毁就会一直常驻内存,而且特效也会重复播放,所以,我就另外写了一个脚本来专门管理它,DestroyGameObject(名字起的不是很恰当,后期优化)
代码如下:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class DestroyGameObject : MonoBehaviour
{
public float effectTime = 6f;
public GameObject BigExplosionEffect;
public GameObject GranadeAudio;
float currentDown;
bool hasPerfab = true;
void Start()
{
currentDown = effectTime;
}
void Update()
{
currentDown -= Time.deltaTime;
if (currentDown <= 0 && hasPerfab)
{
if (BigExplosionEffect != null && GranadeAudio != null)
{
currentDown = effectTime;
DestoryExplosinEffect();
DestoryExlosinAudio();
hasPerfab = true;
}
else
{
hasPerfab = false;
}
}
}
void DestoryExplosinEffect()
{
GameObject obj = GameObject.Find("BigExplosionEffect(Clone)");
if (obj != null)
{
Destroy(obj);
}
}
void DestoryExlosinAudio()
{
GameObject obj = GameObject.Find("GranadeAudio(Clone)");
if (obj != null)
{
Destroy(obj);
}
}
}
代码解释:
我先定义了一个计时器,由于我的特效和声音大概是3秒,加上之前的手雷延时爆炸3秒,所以是6秒之后销毁,这样写是比较简单的,分开控制,方法也是分开写的,方便后期的管理。
添加了一个控制条件hasPerfab ,控制它只销毁一次,之前想一次扔好几个手雷,但是出现了一些小问题(其实问题蛮大的),我下来解决一下,在下回书中我们在讲解。然后将其挂载到场景CheckDestory上,如图
最后是控制手雷的扔出,ThrowerGranade,代码如下:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class GranadeThrower : MonoBehaviour
{
public float throwerForce = 15f;
public GameObject GranadePrefab;
private AudioSource audioSource;
bool isFirst = true;
void Start()
{
audioSource = GetComponent<AudioSource>();
}
void Update()
{
if (Input.GetMouseButtonDown(0))
{
//播放手雷扔出的音效
audioSource.Play();
if (isFirst)
{
ThrowGranade();
isFirst = false;
}
}
}
void ThrowGranade()
{
GameObject granade = Instantiate(GranadePrefab,transform.position, transform.rotation);
Rigidbody rb = granade.GetComponent<Rigidbody>();
rb.AddForce(transform.forward * throwerForce,ForceMode.VelocityChange);
}
}
代码解释:
挂载到相机上,按下鼠标左键时,添加一个向前的力,这样手雷就扔出去了,我后期想加上抛物线,后面在改进,这样就可以实现真正的手雷模拟器(无情)
完整的演示图: