Unity对象池初了解
目录
- Unity对象池初了解
- 前言
- 一、对象池是什么?
- 二、代码实现对象池
- 1.首先创建一个空物体,以作为我们的第一个预制体来使用对象池
- 2.编写对象池!!!
- 3.编写Dash脚本
- 总结
前言
例如:随着对游戏设计的深入了解,本文就介绍了unity的对象池的基础内容。
一、对象池是什么?
对象池简单来说就好比一个池子,有一池子空物体,预制体,一开始就实例化这些物体,当我们需要使用时,便从其他将其拿出(SetActive(true)),当用完时,便将其放回池子中(SetActive(false)),以便下次使用。就如打羽毛球,如果我们每次打一个球只打一次便扔掉,然后又打新球,这样就造成了极大浪费,而对象池就是将打过的球放回其中,减少开支消耗。
二、代码实现对象池
——这里以制作冲刺残影为例子进行讲解
1.首先创建一个空物体,以作为我们的第一个预制体来使用对象池
如下图:
并且创建挂载上一个脚本来进行获取玩家的数据坐标图像等:
并且写入代码:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class ShadowsScript : MonoBehaviour
{
private Transform player;
private SpriteRenderer thisSprite;
private SpriteRenderer playerSprite;
private Color color;//进行透明度调节
[Header("时间控制参数")]
public float activeTime;//显示时间
public float activeStart;//开始显示的时间点
[Header("不透明度控制")]
private float alpha;
public float alphaSet;//初始值
public float alphaMultiplier;//乘以系数逐渐减小
private void OnEnable()
{
//记得切换unity角色的Player标签
player = GameObject.FindGameObjectWithTag("Player").transform;
thisSprite = GetComponent<SpriteRenderer>();
playerSprite = player.GetComponent<SpriteRenderer>();
alpha = alphaSet;
thisSprite.sprite = playerSprite.sprite;
transform.position = player.position;
transform.localScale = player.localScale;
transform.rotation = player.rotation;
activeStart = Time.time;
}
void Update()
{
alpha *= alphaMultiplier;
color = new Color(1, 1, 1, alpha);
thisSprite.color = color;
if (Time.time >= activeStart + activeTime)
{
PoolScript.instance.ReturnPool(gameObject);
//返回对象池(写好对象池后添加)
}
}
}
接着回到unity中进行参数设置和制作预制体:
预制体中需要加上精灵组件:
2.编写对象池!!!
首先在unity中创建空物体并命名为Pool:
接着创建脚本,并且命名为PoolScript:
然后进行编写代码:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PoolScript : MonoBehaviour
{
public static PoolScript instance;
public GameObject shadowPrefab;
public int shadowCount;
//创建队列(重点)
private Queue<GameObject> availableObjects = new Queue<GameObject>();
void Awake()
{
instance = this;
//初始化对象池
FillPool();
}
public void FillPool()
{
for(int i = 0; i < shadowCount; i++)
{
var newShadow = Instantiate(shadowPrefab);
newShadow.transform.SetParent(transform);
//生成之后,取消启用,返回对象池(进入队列)
ReturnPool(newShadow);
}
}
public void ReturnPool(GameObject gameObject)
{
gameObject.SetActive(false);
availableObjects.Enqueue(gameObject);
}
public GameObject GetFromPool()
{
//如果数量不够,则再次进行填充
if (availableObjects.Count == 0)
{
FillPool();
}
var outShadow = availableObjects.Dequeue();
outShadow.SetActive(true);
return outShadow;
}
}
接着在unity中进行设置:
3.编写Dash脚本
using UnityEngine;
public class PlayerController : MonoBehaviour
{
private float movementInputDirection;
private Rigidbody2D rb;
[Header("Dash参数")]
public float dashTime;//dash时长
private float dashTimeLeft;//dash剩余时间
private float lastDash=-10;//上一次dash的时间点,赋初值,确保一开始可冲锋
public float dashCoolDown;//UIcd时间(暂时未用到)
public float dashSpeed;
private bool isDashing;
void Start()
{
rb = GetComponent<Rigidbody2D>();
}
void Update()
{
CheckInput();
}
private void FixedUpdate()
{
Dash();
}
private void CheckInput()
{
movementInputDirection = Input.GetAxisRaw("Horizontal");
if (Input.GetButtonDown("Jump"))
{
if (Time.time >= (lastDash + dashCoolDown))
{
isDashing = true;
dashTimeLeft = dashTime;
lastDash = Time.time;
}
}
}
private void Dash()
{
if (isDashing)
{
if (dashTimeLeft > 0)
{
rb.velocity = new Vector2(dashSpeed * movementInputDirection, rb.velocity.y);
dashTimeLeft -= Time.fixedDeltaTime;
PoolScript.instance.GetFromPool();
}
if (dashTimeLeft <= 0)
{
isDashing = false;
}
}
}
}
接着在unity中进行设置:
最后在游戏进行测试:
首先游戏一开始,对象池中便生成了10个对象:
然后进行冲刺测试:
最后完美成功,此次为使用对象池制作角色冲刺残影的例子了。
总结
在我们开发中,往往会遇见需要不断创建和销毁同一物体的情况。(如飞机大战,许多FPS游戏,三消类游戏等),这时我们系统不断的实例化资源和销毁资源对于内存以及性能的消耗是非常大的。对于这种我们可以使用对象池技术进行优化。效果十分明显。
对象池及时的原理:
适用范围:有大量的物体需要被不断的创建和销毁的时候。
关键点:
从对象池中放入对象。
从对象池中取出对象。
使用何种数据类型来对这些对象进行储存。
关键思想:
相比于Instantiate和Destroy,不断的实例化和销毁,对象池只是对它们实例化出的对象进行激活和失活的处理。