栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 游戏开发 > 其他

Unity学习笔记--如何优雅简便地利用对象池生成游戏对象

其他 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Unity学习笔记--如何优雅简便地利用对象池生成游戏对象

目录
  • 前言
  • 提前准备
  • 实现步骤
    • 步骤一:创建对象池管理者
    • 步骤二:创建抽象工厂
    • 步骤三:子弹工厂代码
    • 步骤四:如何生成游戏对象
    • 步骤五:如何回收游戏对象
  • 添加新对象池
  • 注意事项
  • 最后

前言

最近在复习自己所做的FPS项目,发现之前写的对象池代码简直就难以入目。。。
加上我最近学习了工厂模式。我就优化了下我的对象池代码。
更新后:代码更加简洁,更加易懂,操作方便,代码耦合性降低。

提前准备
  • 注意:本例子用的是子弹预制体,大家可以换其他的预制体。

1.我们需要在Assets文件夹下创建一个Resources文件夹

2. 需要在Resources文件夹下加入我们的预制体

实现步骤 步骤一:创建对象池管理者

创建一个对象池,让他继承自单例模板类。
(关于单例模板类怎么写:浅谈设计模式和其Unity中的应用:一、单例模式)
PS:代码如果没有注释的话会简短很多,但是为了大家方便看懂,我还是打了注释。

using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class PoolManager : Singleton
{
    /// 
    /// 所有的对象池,每一个元素都对应一个游戏对象的对象池
    /// 
    private Dictionary> pool = new Dictionary>()
    {
        {"AssaultRifleBullet", new Stack() },           //步枪子弹对象池
        {"SniperBullet", new Stack() },                 //狙击子弹对象池
        {"HandgunBullet", new Stack() },                //手枪子弹对象池
        {"SMGBullet", new Stack() },                    //冲锋枪子弹对象池
        {"ShotGunBullet", new Stack() },                //霰弹枪子弹对象池
    };
    /// 
    /// 存储所有的可以用于对象池的预制体,放在Resources文件夹下
    /// 
    private Dictionary Prefabs = new Dictionary();
    [SerializeField]
    /// 
    /// 存储需要动态加载的预制体的名字
    /// 
    private List prefabsName;
    protected override void Awake()
    {
        base.Awake();
        DontDestroyOnLoad(this);
        InitDictionary();
    }
    /// 
    /// 动态加载预制体,注意Resources文件夹下的所有预制体的名字要和对象池名字相同
    /// 
    private void InitDictionary()
    {
        for (int i = 0; i < prefabsName.Count; i++)
        {
            Prefabs.Add(prefabsName[i], (GameObject)Resources.Load(prefabsName[i]));
        }
    }
    /// 
    /// 回收至对象池
    /// 
    /// 游戏对象在对象池中的名字
    /// 被回收的游戏对象
    public void CollectObject(string gameobjectName, GameObject go)
    {
        if(pool.TryGetValue(gameobjectName, out Stack stack))
        {
            //将游戏对象压入栈(加入到对象池)
            go.SetActive(false);
            stack.Push(go);
        }
    }
    /// 
    /// 创建对象调用
    /// 
    /// 游戏对象在对象池中的名字
    /// 从对象池取出来的游戏对象
    public GameObject Creat(string gameobjectName)
    {
        GameObject res = null;
        //如果存在该游戏对象所对应的对象池
        if (pool.TryGetValue(gameobjectName, out Stack stack) && Prefabs.ContainsKey(gameobjectName))
        {
            //如果对象池里面有对象,就直接拿出来,不然重新生成一个预制体。
            res = stack.Count >= 1 ? stack.Pop() : Instantiate(Prefabs[gameobjectName]);
            res?.gameObject.SetActive(true);
        }
        return res;
    }
    /// 
    /// 创建对象调用
    /// 
    /// 游戏对象在对象池中的名字
    /// 游戏对象的坐标
    /// 游戏对象的旋转
    /// 从对象池取出来的游戏对象
    public GameObject Creat(string gameobjectName, Vector3 position, Quaternion rotation)
    {
        GameObject res = Creat(gameobjectName);
        res.transform.position = position;
        res.transform.rotation = rotation;
        return res;
    }
}
  • 注意,处于Resources文件夹下的预制体名字要和prefabsName列表里的名字要一样。
步骤二:创建抽象工厂

这里限于篇幅,我就不贴代码了。
抽象工厂步骤我写过一个文章:浅谈设计模式和其Unity中的应用:三、抽象工厂模式

步骤三:子弹工厂代码
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System;

public class BulletFactory : Singleton, IBaseFactory
{
    protected override void Awake()
    {
        base.Awake();
        DontDestroyOnLoad(this);
    }
    /// 
    /// 创建子弹时调用
    /// 
    /// 子弹名称:AssaultRifleBullet、SniperBullet、HandgunBullet、SMGBullet、ShotGunBullet
    /// 子弹
    public GameObject Creat(string produceName)
    {
        return PoolManager.Ins.Creat(produceName);
    }
    /// 
    /// 创建子弹时调用
    /// 
    /// 子弹名称:AssaultRifleBullet、SniperBullet、HandgunBullet、SMGBullet、ShotGunBullet
    /// 子弹位置
    /// 子弹旋转
    /// 子弹
    public GameObject Creat(string produceName, Vector3 position, Quaternion rotation)
    {
        GameObject go = Creat(produceName);
        go.transform.position = position;
        go.transform.rotation = rotation;
        return go;
    }
}
步骤四:如何生成游戏对象

假设我的枪械脚本有一个射击函数,那我们就可以这样调用

public void HandleShot()
{
	GameObject bullet = FactoryProducer.GetFactory(FactoryType.BulletFactory).Creat(firearmBulletName);
}
步骤五:如何回收游戏对象

比如我的子弹脚本有一个定时器,过5s就自动回收本游戏对象,那我们就可以这么写:

private void RecoveryToPool()
{
    PoolManager.Ins.CollectObject(owner.firearmBulletName, gameObject);
}
添加新对象池

如果以后我们要增加一个对象池,只需要在PoolManager的对象池中添加一行代码
然后在下方两张图添加对应预制体和预制体名字(和上方的对象池名字要一样)

注意事项




这三张图片箭头指向的名字要一样,不然无法正确加载。

最后

如果大家有什么更好的方式,希望大佬可以指点下,一起学习,共同进步!

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/903573.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号