不好意思,最近实在忙的慌。好久没发文章了。不管怎样,先发个图压压惊。<br/>
是的。这就是大名鼎鼎的打飞机。看到那小飞机没有,是我用Cube拼出来的-_-。不过那不是重点。我们今天的重点是讲对象池。我们更多关注的是怎么管理子弹,而不是飞机~~~
不过文章最后还是会给出完整工程和可运行exe的下载地址。
0、为什么写
A、刚好项目需要,然后之前的对象池我胡写的(可以说没有)
B、刚好群里有人在问
C、刚好好久没发文章,不知道写什么
1、什么是对象池
我经常说的一点,理解概念,理解基础很重要。因为概念理解深刻了,代码也就出来了。
所以大家对这个概念如果还不懂的,要赶紧去查查。这里我不多说了,各种百科都可以找到。
2、我的设计
我的对象池主要由:对象池、对象、对象工厂组成。
为了拓展,对象池抽象为IObjectPool、对象为泛型、对象工厂为IObjectFactory。
3、IObjectPool
接口比较简单,也做了注释。就不说明了。接着看
4、IObjectFactory
依旧很简单的接口。没错,对象池真的很简单。
5、对象池实现BaseObjectPool
这是一个基础的对象池。他构造的时候指定工厂和最大空闲的对象数目。
最大空闲的对象数目是干嘛的?就是比如你一般情况同时只会存在10个对象A。但是某个峰值从池中取出了100个。那么当这些对象被存回对象池的时候,有些会被抛弃。最后池中可用的对象不超过构造时指定的最大数目。
6、休息一下
这时候,基本一个对象池已经完成了。就是你可以new BaseObjectPool。指定自己的工厂,然后就可以通过Take从池中取对象,通过Restore将对象存回。但是,还没完。
我们不会就此止步。
我还想着。这样我需要手动调用Restore来将对象存回对象池。有没有方便一点的。
7、定义一个主动回收的对象池IActiveRestoreObjectPool
可以看到这个接口是从我们前面的对象池接口中继承的,然后又增加了一个检查可回收对象的方法。
8、主动回收对象池的实现ActiveRestoreObjectPool
可以看到,这个类其实很多接口的实现是托管给我们之前的BaseObjectPool来实现的。这样我们可以省下不少功夫~~
然后可以看到CheckRestore方法中是通过IAutoRestoreObject中的IAutoRestoreChecker来检查一个对象是否可以被回收到池中。
IAutoRestoreObject和IAutoRestoreChecker都是为了做主动回收而引入的新接口。
我们接着看
这两个接口和实现都简单的没法说了。。。
9、为了更方便的和U3D结合,我继续提供了U3DAutoRestoreObjectPool
之前的类和接口都是与U3D无关的,没有引用到U3D的类。可以放到任何C#项目中使用。
其实大家设计代码也应该如此,应该一步步地,从最本质剥离出通用的东西。
到这一步,我们才设计出U3DAutoRestoreObjectPool,他是一个U3D组件。但是也具备了我们的对象池功能。
从代码中可以看到这个组件引用了一个主动回收(ActiveRestoreObjectPool)的对象池,并且用PrefabFactory来构造这个对象池。
然后在Update的时候会调用对象池的CheckRestore来检查哪些对象可以被回收,并实施回收处理。
那么PrefabFactory是什么?
是的,就几行代码。他就是从预设创建GameObject、隐藏和显示GameObject而已。
看了那么多无聊的代码。或许应该看看怎么使用。
10、怎么调用对象池
A、你可以直接通过new创建具体的对象池实现,然后从中获取对象。
B、可以直接获取U3DAutoRestoreObjectPool组件,然后从中获取对象。
C、通过实现我们定义的IObjectPool或IActiveRestoreObjectPool接口来自定义对象池(不要以为自定义就很麻烦,从上面就可以看到自定义其实很多还是组合了我们已经实现的BaseObjectPool来实现的)。
11、具体案例-打飞机
A、打开我们工程中的场景
B、选择Airplane对象
这个就是飞机了。可以发现他上面有两个组件。
一个是我们之前定义的U3D对象池实现U3DAutoRestoreObjectPool
另一个是TestCastBullet组件。
这个组件主要就是控制飞机移动、发射3种类型的子弹的。好吧。写到这里。我发现这个类名取的不好,如果叫AirplaneController可能更好。。。
不管了。。先看代码
大家可以看到在Update里面,是怎么从池中取数据的。
至此,对象池从定义到实现到调用基本都讲完了。
项目中还有控制雷和子弹的类的,大家有兴趣就自己去翻翻咯。
是不是觉得一个对象池还是挺简单的,这。。怪我咯~~
最后大家有不懂的再讨论就OK啦。
然后可运行文件是免费下载的。工程是要蛮牛币的,大家觉得好就多支持!
是的。这就是大名鼎鼎的打飞机。看到那小飞机没有,是我用Cube拼出来的-_-。不过那不是重点。我们今天的重点是讲对象池。我们更多关注的是怎么管理子弹,而不是飞机~~~
不过文章最后还是会给出完整工程和可运行exe的下载地址。
0、为什么写
A、刚好项目需要,然后之前的对象池我胡写的(可以说没有)
B、刚好群里有人在问
C、刚好好久没发文章,不知道写什么
1、什么是对象池
我经常说的一点,理解概念,理解基础很重要。因为概念理解深刻了,代码也就出来了。
所以大家对这个概念如果还不懂的,要赶紧去查查。这里我不多说了,各种百科都可以找到。
2、我的设计
我的对象池主要由:对象池、对象、对象工厂组成。
为了拓展,对象池抽象为IObjectPool、对象为泛型、对象工厂为IObjectFactory。
3、IObjectPool
[C#]
纯文本查看
复制代码
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
|
namespace
Com.Duoyu001.Pool
{
/* ==============================================================================
* 功能描述:一个对象池接口
* 创 建 者:cjunhong
* 邮 箱:[url=mailto:john.cha@qq.com]john.cha@qq.com[/url]
* Q Q:327112182
* ==============================================================================*/
/// <summary>
/// 一个对象池接口
/// </summary>
/// <typeparam name="T">该对象池中存放的对象类型</typeparam>
public
interface
IObjectPool<T>
{
/// <summary>
/// 从对象池中取对象
/// </summary>
/// <returns></returns>
T Take();
/// <summary>
/// 把对象存回对象池
/// </summary>
/// <param name="t"></param>
void
Restore(T t);
/// <summary>
/// 对象池增加对象
/// </summary>
void
AddObject();
/// <summary>
/// 对象池中空闲(可用)对象的数目
/// </summary>
/// <returns></returns>
int
IdleNum();
/// <summary>
/// 对象池中空闲(可用)对象的数目
/// </summary>
/// <returns></returns>
int
ActiveNum();
/// <summary>
/// 清除对象池中所有对象
/// </summary>
void
Clear();
}
}
|
接口比较简单,也做了注释。就不说明了。接着看
4、IObjectFactory
[C#]
纯文本查看
复制代码
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
|
namespace
Com.Duoyu001.Pool
{
/* ==============================================================================
* 功能描述:对象工厂,用于创建、销毁、激活、反激活对象
* 创 建 者:cjunhong
* 邮 箱:[url=mailto:john.cha@qq.com]john.cha@qq.com[/url]
* Q Q:327112182
* ==============================================================================*/
public
interface
IObjectFactory<T>
{
/// <summary>
/// 创建一个对象
/// </summary>
/// <returns></returns>
T CreateObject(
bool
doActive);
/// <summary>
/// 销毁对象
/// </summary>
/// <param name="t"></param>
void
DestroyObject(T t);
/// <summary>
/// 激活对象
/// </summary>
/// <param name="t"></param>
void
ActivateObject(T t);
/// <summary>
/// 反激活对象
/// </summary>
/// <param name="t"></param>
void
UnActivateObject(T t);
}
}
|
依旧很简单的接口。没错,对象池真的很简单。
5、对象池实现BaseObjectPool
[C#]
纯文本查看
复制代码
001
002
003
004
005
006
007
008
009
010
011
012
013
014
015
016
017
018
019
020
021
022
023
024
025
026
027
028
029
030
031
032
033
034
035
036
037
038
039
040
041
042
043
044
045
046
047
048
049
050
051
052
053
054
055
056
057
058
059
060
061
062
063
064
065
066
067
068
069
070
071
072
073
074
075
076
077
078
079
080
081
082
083
084
085
086
087
088
089
090
091
092
093
094
095
096
097
098
099
100
101
102
|
using
System;
using
System.Collections.Generic;
namespace
Com.Duoyu001.Pool
{
/* ==============================================================================
* 功能描述:基础对象池实现
* 创 建 者:cjunhong
* 邮 箱:[url=mailto:john.cha@qq.com]john.cha@qq.com[/url]
* Q Q:327112182
* ==============================================================================*/
public
class
BaseObjectPool<T> : IObjectPool<T>
{
private
readonly
List<T> pools =
new
List<T>();
private
readonly
IObjectFactory<T> factory;
/// <summary>
/// 最大可达到的空闲对象数目
/// </summary>
private
readonly
int
maxIdleNum;
private
int
activeNum = 0;
public
BaseObjectPool(IObjectFactory<T> factory,
int
maxIdleNum)
{
if
(factory ==
null
)
{
throw
new
ObjectPoolExeception(
"factory can not be null"
);
}
this
.factory = factory;
this
.maxIdleNum = maxIdleNum;
}
public
T Take()
{
T t;
if
(pools.Count == 0)
{
t = factory.CreateObject(
true
);
}
else
{
t = pools[0];
factory.ActivateObject(t);
pools.RemoveAt(0);
}
activeNum++;
return
t;
}
/// <summary>
/// 将一个指定对象返回对象池,如果对象池已达到空闲对象上限,则指定对象直接被工厂销毁。
/// </summary>
/// <param name="t"></param>
public
void
Restore(T t)
{
if
(pools.Count >= maxIdleNum)
{
factory.DestroyObject(t);
}
else
{
factory.UnActivateObject(t);
pools.Add(t);
}
activeNum--;
}
/// <summary>
/// 如果池没达到空闲对象上限,则往池中增加一个对象。
/// 如果池已经达到空闲对象上限,则不进行任何处理。
/// </summary>
public
void
AddObject()
{
if
(pools.Count < maxIdleNum){
T t = factory.CreateObject(
false
);
pools.Add(t);
}
}
public
int
IdleNum()
{
return
pools.Count;
}
public
int
ActiveNum()
{
return
activeNum;
}
public
void
Clear()
{
foreach
(T t
in
pools)
{
factory.DestroyObject(t);
}
pools.Clear();
}
}
}
|
这是一个基础的对象池。他构造的时候指定工厂和最大空闲的对象数目。
最大空闲的对象数目是干嘛的?就是比如你一般情况同时只会存在10个对象A。但是某个峰值从池中取出了100个。那么当这些对象被存回对象池的时候,有些会被抛弃。最后池中可用的对象不超过构造时指定的最大数目。
6、休息一下
这时候,基本一个对象池已经完成了。就是你可以new BaseObjectPool。指定自己的工厂,然后就可以通过Take从池中取对象,通过Restore将对象存回。但是,还没完。
我们不会就此止步。
我还想着。这样我需要手动调用Restore来将对象存回对象池。有没有方便一点的。
7、定义一个主动回收的对象池IActiveRestoreObjectPool
[C#]
纯文本查看
复制代码
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
|
namespace
Com.Duoyu001.Pool
{
/* ==============================================================================
* 功能描述:一个能主动回收的对象池
* 创 建 者:cjunhong
* 邮 箱:[url=mailto:john.cha@qq.com]john.cha@qq.com[/url]
* Q Q:327112182
* ==============================================================================*/
public
interface
IActiveRestoreObjectPool<T> : IObjectPool<IAutoRestoreObject<T>>
{
/// <summary>
/// 此方法必须能识别哪些对象可以回收,而且回收到池中
/// </summary>
void
CheckRestore();
}
}
|
可以看到这个接口是从我们前面的对象池接口中继承的,然后又增加了一个检查可回收对象的方法。
8、主动回收对象池的实现ActiveRestoreObjectPool
[C#]
纯文本查看
复制代码
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
|
using
System.Collections.Generic;
namespace
Com.Duoyu001.Pool
{
/* ==============================================================================
* 功能描述:主动回收对象池
* 创 建 者:cjunhong
* 邮 箱:[url=mailto:john.cha@qq.com]john.cha@qq.com[/url]
* Q Q:327112182
* ==============================================================================*/
/// <summary>
///
/// </summary>
/// <typeparam name="T"></typeparam>
public
class
ActiveRestoreObjectPool<T> : IObjectPool<IAutoRestoreObject<T>>
{
private
BaseObjectPool<T> baseObjectPool;
private
List<IAutoRestoreObject<T>> checkList =
new
List<IAutoRestoreObject<T>>();
private
IObjectFactory<T> factory;
public
ActiveRestoreObjectPool(IObjectFactory<T> factory,
int
maxIdleNum)
{
baseObjectPool =
new
BaseObjectPool<T>(factory, maxIdleNum);
this
.factory = factory;
}
public
IAutoRestoreObject<T> Take()
{
T t = baseObjectPool.Take();
AutoRestoreObject<T> autoRestoreObject =
new
AutoRestoreObject<T>(t);
checkList.Add(autoRestoreObject);
return
autoRestoreObject;
}
/// <summary>
/// 每次调用会把可回收的对象重新存入对象池
/// </summary>
public
void
CheckRestore()
{
for
(
int
i = 0; i < checkList.Count; i++)
{
IAutoRestoreObject<T> check = checkList[i];
IAutoRestoreChecker autoRestoreChecker = check.Restore;
if
(autoRestoreChecker !=
null
&& autoRestoreChecker.Restore)
{
baseObjectPool.Restore(check.Get());
checkList.RemoveAt(i);
i--;
}
}
}
public
void
Restore(IAutoRestoreObject<T> t)
{
baseObjectPool.Restore(t.Get());
checkList.Remove(t);
}
public
void
AddObject()
{
baseObjectPool.AddObject();
}
public
int
IdleNum()
{
return
baseObjectPool.IdleNum();
}
public
int
ActiveNum()
{
return
baseObjectPool.ActiveNum();
}
public
void
Clear()
{
baseObjectPool.Clear();
foreach
(IAutoRestoreObject<T> autoRestoreObject
in
checkList)
{
factory.DestroyObject(autoRestoreObject.Get());
}
checkList.Clear();
}
}
}
|
可以看到,这个类其实很多接口的实现是托管给我们之前的BaseObjectPool来实现的。这样我们可以省下不少功夫~~
然后可以看到CheckRestore方法中是通过IAutoRestoreObject中的IAutoRestoreChecker来检查一个对象是否可以被回收到池中。
IAutoRestoreObject和IAutoRestoreChecker都是为了做主动回收而引入的新接口。
我们接着看
[C#]
纯文本查看
复制代码
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
namespace
Com.Duoyu001.Pool
{
/* ==============================================================================
* 功能描述:能被自动回收的对象
* 创 建 者:cjunhong
* 邮 箱:[url=mailto:john.cha@qq.com]john.cha@qq.com[/url]
* Q Q:327112182
* ==============================================================================*/
public
interface
IAutoRestoreObject<T>
{
/// <summary>
/// 是否能被回收的接口
/// </summary>
IAutoRestoreChecker Restore {
get
;
set
; }
/// <summary>
///
/// </summary>
/// <returns></returns>
T Get();
}
}
|
[C#]
纯文本查看
复制代码
01
02
03
04
05
06
07
08
09
10
11
12
13
|
namespace
Com.Duoyu001.Pool
{
/* ==============================================================================
* 功能描述:自动回收检查器
* 创 建 者:cjunhong
* 邮 箱:[url=mailto:john.cha@qq.com]john.cha@qq.com[/url]
* Q Q:327112182
* ==============================================================================*/
public
interface
IAutoRestoreChecker
{
bool
Restore {
get
; }
}
}
|
[C#]
纯文本查看
复制代码
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
|
namespace
Com.Duoyu001.Pool
{
/* ==============================================================================
* 功能描述:可主动回收的对象
* 创 建 者:cjunhong
* 邮 箱:[url=mailto:john.cha@qq.com]john.cha@qq.com[/url]
* Q Q:327112182
* ==============================================================================*/
public
class
AutoRestoreObject<T> : IAutoRestoreObject<T>
{
private
T t;
public
AutoRestoreObject(T t)
{
this
.t = t;
}
public
IAutoRestoreChecker Restore {
get
;
set
; }
public
T Get()
{
return
t;
}
}
}
|
这两个接口和实现都简单的没法说了。。。
9、为了更方便的和U3D结合,我继续提供了U3DAutoRestoreObjectPool
之前的类和接口都是与U3D无关的,没有引用到U3D的类。可以放到任何C#项目中使用。
其实大家设计代码也应该如此,应该一步步地,从最本质剥离出通用的东西。
到这一步,我们才设计出U3DAutoRestoreObjectPool,他是一个U3D组件。但是也具备了我们的对象池功能。
[C#]
纯文本查看
复制代码
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
|
using
UnityEngine;
using
Com.Duoyu001.Pool;
namespace
Com.Duoyu001.Pool.U3D
{
/* ==============================================================================
* 功能描述:对象池组件,可以挂在U3D对象上
* 创 建 者:cjunhong
* 邮 箱:[url=mailto:john.cha@qq.com]john.cha@qq.com[/url]
* Q Q:327112182
* ==============================================================================*/
public
class
U3DAutoRestoreObjectPool : MonoBehaviour, IActiveRestoreObjectPool<GameObject>
{
private
ActiveRestoreObjectPool<GameObject> pool;
public
GameObject prefab;
public
Transform parent;
public
int
maxNum;
public
int
initNum;
private
static
int
idGenerate;
private
int
_id = -1;
private
int
id
{
get
{
if
(_id == -1)
{
_id = idGenerate;
idGenerate++;
}
return
_id;
}
}
void
Awake()
{
pool =
new
ActiveRestoreObjectPool<GameObject>(
new
PrefabFactory(prefab, parent), maxNum);
if
(initNum > maxNum)
{
initNum = maxNum;
}
for
(
int
i = 0; i < initNum; i++)
{
pool.AddObject();
}
}
void
OnGUI()
{
int
y = 10+40*id;
GUI.Label(
new
Rect(10, y, 300, 20),
"Idle num in pools#"
+gameObject.name+
" : "
+ pool.IdleNum());
GUI.Label(
new
Rect(10, y+20, 300, 20),
"Active num in pools#"
+gameObject.name+
" : "
+ pool.ActiveNum());
}
public
void
Update()
{
pool.CheckRestore();
}
public
IAutoRestoreObject<GameObject> Take()
{
return
pool.Take();
}
public
void
Restore(IAutoRestoreObject<GameObject> t)
{
pool.Restore(t);
}
public
void
AddObject()
{
pool.AddObject();
}
public
int
IdleNum()
{
return
pool.IdleNum();
}
public
int
ActiveNum()
{
return
pool.ActiveNum();
}
public
void
Clear()
{
pool.Clear();
}
public
void
CheckRestore()
{
pool.CheckRestore();
}
}
}
|
从代码中可以看到这个组件引用了一个主动回收(ActiveRestoreObjectPool)的对象池,并且用PrefabFactory来构造这个对象池。
然后在Update的时候会调用对象池的CheckRestore来检查哪些对象可以被回收,并实施回收处理。
那么PrefabFactory是什么?
[C#]
纯文本查看
复制代码
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
|
using
UnityEngine;
namespace
Com.Duoyu001.Pool.U3D
{
/* ==============================================================================
* 功能描述:U3D预设-对象池工厂
* 创 建 者:cjunhong
* 邮 箱:[url=mailto:john.cha@qq.com]john.cha@qq.com[/url]
* Q Q:327112182
* ==============================================================================*/
public
class
PrefabFactory : IObjectFactory<GameObject>
{
private
GameObject prefab;
private
Transform parent;
public
PrefabFactory(GameObject prefab, Transform parent)
{
this
.prefab = prefab;
this
.parent = parent;
}
public
GameObject CreateObject(
bool
doActive)
{
GameObject go = GameObject.Instantiate(prefab)
as
GameObject;
go.transform.parent = parent;
go.transform.localPosition = Vector3.zero;
if
(doActive)
{
ActivateObject(go);
}
else
{
go.SetActive(
false
);
}
return
go;
}
public
void
DestroyObject(GameObject t)
{
GameObject.Destroy(t);
}
public
void
ActivateObject(GameObject t)
{
t.SetActive(
true
);
}
public
void
UnActivateObject(GameObject t)
{
t.SetActive(
false
);
}
}
}
|
是的,就几行代码。他就是从预设创建GameObject、隐藏和显示GameObject而已。
看了那么多无聊的代码。或许应该看看怎么使用。
10、怎么调用对象池
A、你可以直接通过new创建具体的对象池实现,然后从中获取对象。
B、可以直接获取U3DAutoRestoreObjectPool组件,然后从中获取对象。
C、通过实现我们定义的IObjectPool或IActiveRestoreObjectPool接口来自定义对象池(不要以为自定义就很麻烦,从上面就可以看到自定义其实很多还是组合了我们已经实现的BaseObjectPool来实现的)。
11、具体案例-打飞机
A、打开我们工程中的场景
B、选择Airplane对象
这个就是飞机了。可以发现他上面有两个组件。
一个是我们之前定义的U3D对象池实现U3DAutoRestoreObjectPool
另一个是TestCastBullet组件。
这个组件主要就是控制飞机移动、发射3种类型的子弹的。好吧。写到这里。我发现这个类名取的不好,如果叫AirplaneController可能更好。。。
不管了。。先看代码
[C#]
纯文本查看
复制代码
001
002
003
004
005
006
007
008
009
010
011
012
013
014
015
016
017
018
019
020
021
022
023
024
025
026
027
028
029
030
031
032
033
034
035
036
037
038
039
040
041
042
043
044
045
046
047
048
049
050
051
052
053
054
055
056
057
058
059
060
061
062
063
064
065
066
067
068
069
070
071
072
073
074
075
076
077
078
079
080
081
082
083
084
085
086
087
088
089
090
091
092
093
094
095
096
097
098
099
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
|
using
UnityEngine;
using
System.Collections.Generic;
using
Com.Duoyu001.Pool;
using
Com.Duoyu001.Pool.U3D;
public
class
TestCastBullet : MonoBehaviour
{
/// <summary>
/// 开火口
/// </summary>
public
Transform[] firePoint;
/// <summary>
/// 飞机移动速度
/// </summary>
public
float
velocity;
/// <summary>
/// 开火时间间隔
/// </summary>
public
float
castDuration;
/// <summary>
/// 子弹受力
/// </summary>
public
float
bulletForce;
/// <summary>
/// 子弹速度
/// </summary>
public
float
bulletVelocity;
/// <summary>
/// 子弹生命
/// </summary>
public
float
bulletLife;
/// <summary>
/// 子弹迸发特效的对象池
/// </summary>
public
U3DAutoRestoreObjectPool burstEffectPool;
/// <summary>
/// 雷受力
/// </summary>
public
float
boomForce;
/// <summary>
/// 雷速度
/// </summary>
public
float
boomVelocity;
/// <summary>
/// 雷生命
/// </summary>
public
float
boomLife;
/// <summary>
/// 雷里每个单位的力大小
/// </summary>
public
float
boomUnitForce;
/// <summary>
/// 雷里每个单位的生命
/// </summary>
public
float
boomUnitInitLife;
/// <summary>
/// 雷里每个单位的速度
/// </summary>
public
float
boomUnitVelocity;
/// <summary>
/// 雷的单位数目
/// </summary>
public
int
boomUnitNum;
/// <summary>
/// 雷转圈数
/// </summary>
public
float
boomCircleNum;
/// <summary>
/// 雷的单位间隔
/// </summary>
public
float
boomDuration;
//子弹特效的对象池
private
U3DAutoRestoreObjectPool pool;
//飞机的Transform
private
Transform _CacheTransform;
//下次可攻击事件
private
float
nextCanCastTime;
private
List<TestBoom> booms =
new
List<TestBoom>();
private
void
Awake()
{
pool = GetComponent<U3DAutoRestoreObjectPool>();
_CacheTransform = gameObject.GetComponent<Transform>();
}
private
void
Update()
{
if
(Input.GetKey(KeyCode.J) && Time.time >= nextCanCastTime)
{
nextCanCastTime = Time.time + castDuration;
foreach
(var tran
in
firePoint)
{
IAutoRestoreObject<GameObject> restoreObj =
null
;
GameObject go =
null
;
//从迸发特效对象池中获取
restoreObj = burstEffectPool.Take();
//获取对象实体
go = restoreObj.Get();
go.transform.position = tran.position;
TimeBaseChecker checker = go.GetComponent<TimeBaseChecker>();
if
(checker ==
null
)
{
checker = go.AddComponent<TimeBaseChecker>();
}
checker.Init(0.5f);
//特效时间大概是0.3秒。我们就让他0.5秒回收吧。这个暂时不需要很精确。
restoreObj.Restore = checker;
//将回收检查器用于对象
//从子弹特效对象池中取
restoreObj = pool.Take();
//获取子弹GameObject
go = restoreObj.Get();
go.transform.position = tran.position;
TestBullet bullet = go.GetComponent<TestBullet>();
bullet.Init(bulletForce, bulletLife, bulletVelocity,
delegate
(GameObject obj) { });
restoreObj.Restore = bullet;
}
}
if
(Input.GetKey(KeyCode.U) && Time.time >= nextCanCastTime)
{
nextCanCastTime = Time.time + castDuration;
int
[] angles = {-30, -20, -10, 0, 10, 20, 30};
for
(
int
i =0; i<angles.Length; i++)
{
int
angle = angles[i];
IAutoRestoreObject<GameObject> restoreObj =
null
;
GameObject go =
null
;
//从迸发特效对象池中获取
restoreObj = burstEffectPool.Take();
//获取对象实体
go = restoreObj.Get();
go.transform.position = _CacheTransform.position;
TimeBaseChecker checker = go.GetComponent<TimeBaseChecker>();
if
(checker ==
null
)
{
checker = go.AddComponent<TimeBaseChecker>();
}
checker.Init(0.5f);
//特效时间大概是0.3秒。我们就让他0.5秒回收吧。这个暂时不需要很精确。
restoreObj.Restore = checker;
//将回收检查器用于对象
//从子弹特效对象池中取
restoreObj = pool.Take();
//获取子弹GameObject
go = restoreObj.Get();
go.transform.position = _CacheTransform.position;
TestBullet bullet = go.GetComponent<TestBullet>();
bullet.Init(bulletForce, bulletLife, bulletVelocity,
delegate
(GameObject obj) { }, angle);
restoreObj.Restore = bullet;
}
}
if
(Input.GetKey(KeyCode.K))
{
//从子弹特效对象池中取
IAutoRestoreObject<GameObject> restoreObj = pool.Take();
//获取子弹GameObject
GameObject go = restoreObj.Get();
go.transform.position = _CacheTransform.position;
TestBullet bullet = go.GetComponent<TestBullet>();
bullet.Init(boomForce, boomLife, boomVelocity, CreateBoom);
restoreObj.Restore = bullet;
}
TryMovePlane();
ProcessBooms();
}
/// <summary>
/// 处理雷
/// </summary>
private
void
ProcessBooms()
{
for
(
int
i = 0; i < booms.Count; i++ )
{
var boom = booms[i];
if
(boom.End)
{
booms.RemoveAt(i);
i--;
}
else
{
boom.Update(Time.time);
}
}
}
private
void
CreateBoom(GameObject bullet)
{
booms.Add(
new
TestBoom(boomUnitNum, boomCircleNum, pool, boomDuration, bullet.gameObject.transform.position, boomUnitForce, boomUnitInitLife, boomUnitVelocity));
}
private
void
OnGUI()
{
int
y = Screen.height - 45;
int
height = 20;
GUI.Label(
new
Rect(10, y, 400, height),
"use `W`,`A`,`S`,`D` or `arrow` to move"
);
y -= height;
GUI.Label(
new
Rect(10, y, 400, height),
"use 'J' to shoot"
);
y -= height;
GUI.Label(
new
Rect(10, y, 400, height),
"use `U` to use shoot2"
);
y -= height;
GUI.Label(
new
Rect(10, y, 400, height),
"use `K` to use boom"
);
y -= height;
GUI.Label(
new
Rect(10, y, 400, height),
"---- Control ----"
);
}
/// <summary>
/// 根据实际情况看是否需要让飞机移动
/// </summary>
private
void
TryMovePlane()
{
Vector3 moveVelocity = Vector3.zero;
if
(Input.GetKey(KeyCode.A) || Input.GetKey(KeyCode.LeftArrow))
{
moveVelocity -= Vector3.right * velocity;
}
else
if
(Input.GetKey(KeyCode.D) || Input.GetKey(KeyCode.RightArrow))
{
moveVelocity += Vector3.right * velocity;
}
if
(Input.GetKey(KeyCode.W) || Input.GetKey(KeyCode.UpArrow))
{
moveVelocity += Vector3.up * velocity;
}
else
if
(Input.GetKey(KeyCode.S) || Input.GetKey(KeyCode.DownArrow))
{
moveVelocity -= Vector3.up * velocity;
}
if
(moveVelocity != Vector3.zero)
{
_CacheTransform.position += moveVelocity * Time.deltaTime;
}
}
}
|
大家可以看到在Update里面,是怎么从池中取数据的。
至此,对象池从定义到实现到调用基本都讲完了。
项目中还有控制雷和子弹的类的,大家有兴趣就自己去翻翻咯。
是不是觉得一个对象池还是挺简单的,这。。怪我咯~~
最后大家有不懂的再讨论就OK啦。
然后可运行文件是免费下载的。工程是要蛮牛币的,大家觉得好就多支持!