引言
在某些射击游戏里(2D和3D都适用),可能你需要创建子弹,第一想到的可能是新建一个发射子弹的脚本,就叫BulletController,然后每次按下什么键就直接上Instantiate函数。
伪代码如下:
public GameObject bullet;//子弹预制件
private void Update()
{
if(某些触发事件导致需要发射子弹)
{
Shoot();
}
}
private void FixedUpdate()
{
Move();
}
private void Shoot()
{
Instantiate(bullet, 需要从哪发射的position, Quaternion.identity);
}
private void Move()
{
transform.Translate(速度的三维向量);
}
这种方法很简单,但是假如子弹种类多了,那么每一个子弹都需要创建一个相同作用的脚本,唯一区别就是bullet预制件不一样。代码耦合性很高,逻辑性很差。因为想一想现实生活,子弹应该是控制位置的,发射子弹不是应该是枪该做的是吗?
第二种想法是创建一个GunController脚本和一个BulletController,然后每次需要发射子弹的时候让GunController来控制发射子弹。BulletController则是控制子弹的运动。
GunController的部分伪代码
public GameObject bullet;//子弹预制件
private void Update()
{
if(某些触发事件导致需要发射子弹)
{
Shoot();
}
}
private void Shoot()
{
Instantiate(bullet, 需要从哪发射的position, Quaternion.identity);
}
Bulletontroller的部分伪代码
private void FixedUpdate()
{
Move();
}
private void Move()
{
transform.Translate(速度的三维向量);
}
这样就使得代码很简洁,而且耦合性很低,逻辑更加合理。
其实写到这也差不多了,但是如果是那种大型游戏,每次射击都需要创建一个新的子弹,如果子弹很多,那么会造成一些配置比较低的电脑卡顿,导致玩家体验效果极差。下面就用到了池的思想,把所有的子弹都放到池(可以用容器List)里,当需要创建子弹的时候,先看看子弹池里面有没有子弹,如果有子弹,直接拿一个出来就可以了,不需要新建一个子弹了;如果没有子弹,那么就新建一个子弹就ok了。其实只是一开始需要创建子弹,后面基本都是复用子弹,不用创建子弹的了。
下面上伪代码
GameManager脚本代码
public GameObject bullet;//子弹预制件
public List<GameObject> bulletPool;//子弹池
//第一个参数是需要创建子弹的位置
public GameObject MakeBullet(Vector3 pos)
{
if(playerBulletPool.Count > 0)
{
//从子弹池取出一个子弹
bullet = playerBulletPool[0];
playerBulletPool.RemoveAt(0);
bullet.transform.position = pos;
bullet.SetActive(true);
}
else
{
//新建一个子弹
bullet = Instantiate(bullet, pos, Quaternion.identity);
}
return bullet;
}
GunController的部分伪代码
private void Update()
{
if(某些触发事件导致需要发射子弹)
{
Shoot();
}
}
private void Shoot()
{
GameObject newBullet = GameManager.Ins.MakeBullet(transform.position);
}
总结
其实池这个思想很值得学习,也不一定用到子弹这个例子,例如共享单车什么的,也是利用复用这个思想。