前一篇已经使用ScriptableObject(SO)
类配置可放置物体,本篇探索更多的SO类应用场景。
需求分析
将若干指定物体放在工作台上,可以生成新的物体。
成果展示
Scene部分
准备工作台,放在工作台上的物体全部放在指定PlacedObjects
空物体下。
准备如下几种物体及其配方:
- 正方体;
- 长方体 <= 两个正方体;
- 圆柱;
- 轮组 <= 长方体 + 圆柱;
- 汽车 <= 两个长方体 + 两个轮组;
上一章节以及设计了PlaceObjectTypeSO
配置所有可以放置物体,接下来需要设计配方SO类。
-
需要定义其配方和输出的物体;
-
每当新的物体放在工作台上,就要检查是否是配方中的物体类型,是否集齐全部物体。
脚本部分
PlacedObjectTypeSO.cs
内容与前篇一致,修改了两个地方
1、当项目中出现多个SO
类时,可以定义如下内容,使其他在editor
中合理的展示。
[CreateAssetMenu(fileName = "PlacedObjectTypeSO",menuName= "ScriptableObjects/PlacedObjectTypeSO")]
2、public Sprite sprite
仓库栏中的Image
也可以配置在SO
,这样更加合理。
[Serializable]
[CreateAssetMenu(fileName = "PlacedObjectTypeSO",menuName= "ScriptableObjects/PlacedObjectTypeSO")]
public class PlacedObjectTypeSO : ScriptableObject
{
public GoodsName goodsName;
public string nameString;
public Transform prefab;
public Sprite sprite;
public int width;
public int height;
}
CraftingRecipeSO.cs
这里检查工作台上是否集齐配方物体的逻辑:
- 创建一个列表
waitInPlaceObjectSOList
,初始状态时包括所有配方物体; - 每当有物体放在工作台上时,检查是否是配方元素,如果是就从列表中移除对应物体。直到列表元素为0,表示已经集齐所有配方元素,输出合成的物体。
- 成功合成的物体放回仓库栏,并清除工作台的所有物体,并恢复列表初始状态。
该逻辑只是暂时用在演示合成物体的部分,只能仅供参考,存在很多尚未考虑的内容,暂时不予解决,如:
如果两个配方存在重合的元素,如AB = A+B,ACB =A+B+C,那种A和B先放置在工作台上时,永远只能合成AB,无法合成ACB;
[CreateAssetMenu(fileName = "CraftingRecipeSO", menuName = "ScriptableObjects/CraftingRecipeSO")]
public class CraftingRecipeSO : ScriptableObject
{
public PlacedObjectTypeSO outPlaceObjectSO;
public PlacedObjectTypeSO[] recipeArray;
private List<PlacedObjectTypeSO> waitInPlaceObjectSOList;
public void Init()
{
waitInPlaceObjectSOList = new List<PlacedObjectTypeSO>();
for (int i = 0; i < recipeArray.Length; i++)
{
waitInPlaceObjectSOList.Add(recipeArray[i]);
}
}
public PlacedObjectTypeSO GoodsOnTableChanged(PlacedObjectTypeSO inPlaceObjectSO)
{
if (waitInPlaceObjectSOList == null|| waitInPlaceObjectSOList.Count==0) Init();
if (waitInPlaceObjectSOList.Contains(inPlaceObjectSO))
{
waitInPlaceObjectSOList.Remove(inPlaceObjectSO);
if (waitInPlaceObjectSOList.Count == 0)
{
return outPlaceObjectSO;
}
}
return null;
}
}
PlaceObjectBuilding.cs
大多数内容与前篇一致,需要完善工作台部分内容。
public class PlaceObjectBuilding : MonoBehaviour{
[SerializeField] List<CraftingRecipeSO> craftingRecipeSOList;
[SerializeField] Transform craftTable;
private void Update()
{
if (selectedPlacedObjectTypeSO != null)
{
if (Input.GetMouseButtonDown(0))
{
Vector3 placePosition = Mouse3D.GetMouseWorldPosition();
placePosition.y = 0;
Transform placeObjectTransform = Instantiate(
selectedPlacedObjectTypeSO.prefab,
placePosition,
Quaternion.Euler(0, selectedPlacedObjectTypeSO.GetRotationAngle(dir), 0)
);
//如果放在了工作台地板上,就将craftTable作为父物体
if (Mouse3D.GetClickedTransform().parent.parent == craftTable.parent)
{
placeObjectTransform.SetParent(craftTable);
//放置的物体在所有配方中进行检查
craftingRecipeSOList.ForEach(_ =>
{
PlacedObjectTypeSO outGoodsSo = _.GoodsOnTableChanged(selectedPlacedObjectTypeSO);
//成功合成之后,清除工作台上的物品,恢复配方中的缓存列表,新物体放回仓库
if (outGoodsSo != null)
{
for (int i = 0; i < craftTable.childCount; i++)
{
Destroy(craftTable.GetChild(i).gameObject);
}
craftingRecipeSOList.ForEach(recipeSo =>
{
recipeSo.Init();
});
inventory.AddGoods(outGoodsSo);
};
});
}
else if (Mouse3D.GetClickedTransform().parent == transform.parent)
{
placeObjectTransform.SetParent(transform.parent);
}
DeselectObjectType();
}
}
}
}