功能需求
- 查看玩家拥有的所有物品,可以放下其中的任意物品;
- 查看已死的他人背包的物品,可以拿起其中的任意物品;
- 查看附近的物品,可以拿起其中的任意物品(暂时不考虑背包容量);
难点
1.背包里的物品数据存在脚本里,玩家不可能直接在检查器面板查看背包的物品,必须把它们呈现到UI界面上,这就使同一份数据在脚本和UI界面存在两份,必须使两份数据保持一致。玩家通过UI界面操作改变脚本里的数据时,为了保持两份数据一致理论上UI界面的数据必须总是从脚本读取,而不能直接操作UI界面,比如从场景拿一个弹匣到背包里,如果用代码把附近物品栏的这个弹匣删掉,再在背包物品栏加上这个弹匣,实际上进行了脚本数据和UI界面的两线操作,造成了两边数据不一致的可能性。比如如果弹匣UI的脚本记录的是自己在背包物品列表的索引,玩家拿起了不是最后一个的弹匣,那么被拿起弹匣后面的弹匣在背包物品列表的索引实际上变化了,这时候就应该把附近物品列表的所有物品删除,重新从脚本读取显示。
2.玩家从场景拿起一个物品放进背包时需要把该物品销毁,从背包放下物品时需要把物品实例化。实例化时需要知道实例化哪个物品,背包里的物品没有场景里的实例,只是数据,这个数据就要记录如果自己被放到场景里需要实例化一个什么物体,即记录自己的预制体。
背包里记录弹匣数据的结构体定义为:
[Serializable]
public struct MagInPack{
public Mag magPrefab;
public int ammoNum;
public MagInPack(Mag magPrefab, int ammoNum){
this.magPrefab=magPrefab;
this.ammoNum=ammoNum;
}
}
然后我发现拾取场景里的弹匣时我只知道这个实体弹匣,这个弹匣放进背包时这个物体就销毁了,背包里的弹匣数据结构体需要记录弹匣的预制体,也就是场景里的弹匣实体都要记录自己的预制体,捡起放进背包时存入弹匣结构体。
然后我发现让一个预制体的脚本里一个引用指向预制体它自己,预制体实例化后这个引用指向的也是场景里的实例它自己了。不能让一个预制体脚本里的引用指向它自己来记录预制体。
背包里的弹匣结构体保存有它的预制体,放下弹匣的时候把预制体引用传给实例的预制体引用;拿起弹匣的时候则从实例的预制体引用传给背包里的结构体。
背包界面的物品UI,在场景里的有对应物体,在玩家背包里和附近其他人背包里的物品在场景里没有物体,都要生成物品UI。
子弹信息记录的数据结构
而换弹的逻辑我没写把背包的子弹加到弹匣,而是没打完的弹匣放回背包,在弹匣队列尾部。这样背包里的子弹数不能用一个数字记录,必须用一个列表:
这样换弹的时候会麻烦点,需要在列表里遍历,直到找到需要的子弹。
后来发现,如果换弹逻辑做成把背包里的子弹加到弹匣里,那么应该定义子弹种类的枚举,然后使用相同子弹的不同枪从同一个子弹数字段里取子弹;如果换弹逻辑做成把背包里的弹匣换上,没打完的弹匣放回背包,那么使用相同子弹的不同枪的弹匣也是不通用的,比如G17和M9使用同一种子弹,但是弹匣不通用,容弹量不一样,应该定义枪的型号的枚举,定义子弹型号的枚举就没有意义。
需要做的测试
1.点开背包界面,显示的物品和人物拥有的一致
2.走近其他物品,点开背包界面,其他物品出现在附近物品栏
3.点拥有的枪或物品,把它放下,此物品出现在附近物品栏;如果是弹匣这样在背包里没有实体的物品,附近应该出现它的实体
4.捡起身上没有的物品,此物品从附近物品栏消失,加入拥有的物品;如果是弹匣,此物品在场景里的实体消失
5.和附近的枪交换
6.打开背包界面查看附近的物品,按F拾取,再打开背包界面,该物品从附近物品栏消失
7.打开背包界面查看附近的物品,按F放下枪,再打开背包界面,该物品出现在附近物品栏
附近物品列表及其维护
背包脚本声明了一个列表记录周围可拾取的物品:
如果不做可拾取物品列表,背包界面不显示附近可拾取物品,拾取物品一律按F拾取,背包系统会简单很多。但是就无法拿其他人背包里的物品。
Physics.OverlapSphere()检测附近物品
打开背包界面时用Physics.OverlapSphere()得到一个球形区域的碰撞体,筛选出可拾取的、没有主人的物品,加入附近物品列表。加之前要先把附近物品列表清空。
public float pickUpRange=2;
public LayerMask packCheckLayerMask;
public void CheckItemsAround(){
itemsAround.Clear();
packsAround.Clear();
Collider[] thingsAround=Physics.OverlapSphere(transform.position,pickUpRange,packCheckLayerMask);//检测周围球形区域里的物品
Item item;
Weapon gun;
MyCharacter other;
for(int i=0;i<thingsAround.Length;i++){
if(thingsAround[i].TryGetComponent(out item)){//检测到是物品
if(item is Weapon){
gun=item as Weapon;
if(gun!=myCharacter.rifleScript&&gun!=myCharacter.pistolScript&&gun.owner==null){//不是人物自己的枪&&枪没有主人
itemsAround.Add(item);
}
}
}
else if(thingsAround[i].TryGetComponent(out other)){//检测到是人
if(other.life<=0&&other.backpack){//人已经死了&&人有背包
for(int j=0;j<other.backpack.magsInPack.Count;j++){
packsAround.Add(other.backpack);
}
}
}
}
}