我在使用C#制作的游戏中遇到了一个问题。这是一个简单的基于平铺的匹配游戏,问题出现在我试图制造的电源上:
假设我们有基本的瓷砖类型,圆形正方形和菱形,它们都是瓷砖的子类。我试图将“匹配”行为提取到抽象的Tile方法,而不是让圈子只与圈子匹配:canMatchWith(Tile t)。 Tiles还有两种方法来添加/删除它们可以匹配的Tiles。
所以说我们在游戏中间有一个圆形瓷砖,我们有一个补充说“圆形瓷砖本回合可以与方形瓷砖匹配”。我将浏览所有Circle图块并说出circleTile.addCanMatchWith(typeof(Square))。在内部,我们有一个List canMatchWith。
然后,我想说“圆圈不能再与正方形匹配”,只需说circleTile.removeCanMatchWith(typeOf(Square))。
这是我目前的解决方案,它的效果很好,没有我注意到的性能缺陷(这是一个基于区块的匹配游戏,所以这些类型每个'移动'只评估一次,而不是逐帧评估)。然而,我脑中的声音告诉我,这是完成这种行为的一种不好的方法。所以我有一些选择:
这里的问题是冗余,我的枚举现在也有OVAL和ELIPSE,并且Elipse类将具有(CIRCLE,OVAL,ELIPSE TileTypes)作为它可以匹配的类型。这完全是多余的,我想只说“Circle”,我可以用类型。我想Tiles可以有TileType baseType和TileType actualType。
总之,我想要实现的是让多个对象类型能够与任意数量的不同类型进行交互。问题是,我应该为Type使用什么。可以在这里使用GetType吗?枚举?或者有人会推荐更好的策略吗?我试图尽可能通用,这些磁贴不应该在其他磁贴上有任何硬编码依赖,并且必须能够在运行时更改他们可以与之交互的人。假设我创建了一个新的Tile子类,五角形......好吧,Pentagons可以与Squares,Circles和Pentagons匹配。我的实现很简单,但有些东西告诉我这是一个肮脏的OOP练习。
我觉得我必须使用Types / Enums,因为我不是想说这个Tile.addCanMatch(Tile someOtherObject)。这太具体了,我希望thisTile能够与作为特定类的实例的所有tile匹配。
答案 0 :(得分:2)
如果类似类型的所有形状总是共享行为,那么将该行为存储在每个实例上是有意义的,'水平。相反,你可以拥有一个' CanMatchManager,'存储由形状类型索引的列表字典。然后,当圆圈试图比较匹配时,它会从MatchManager请求它可以匹配的类型。或者,MatchManager可以接收两个形状,并确定它们是否匹配。这是Mediator Pattern
答案 1 :(得分:2)
我知道这个问题已经得到了回答和接受,但我曾经做过类似的事情,我想我只是在这里发布代码。
public class TypeMatchManager
{
private Dictionary<Type, List<Type>> savedMatches = new Dictionary<Type, List<Type>>();
public TypeMatchManager() { }
public void AddMatch(Type firstType, Type secondType)
{
this.addToList(firstType, secondType);
this.addToList(secondType, firstType);
}
public void DeleteMatch(Type firstType, Type secondType)
{
this.deleteFromList(firstType, secondType);
this.deleteFromList(secondType, firstType);
}
public bool CanMatch(Type firstType, Type secondType)
{
List<Type> firstTypeList = this.findListForType(firstType);
List<Type> secondTypeList = this.findListForType(secondType);
return (firstTypeList.Contains(secondType) || secondTypeList.Contains(firstType));
}
private void addToList(Type firstType, Type secondType)
{
var matchingTypes = this.findListForType(firstType);
if (!matchingTypes.Contains(secondType))
{
matchingTypes.Add(secondType);
}
}
private void deleteFromList(Type firstType, Type secondType)
{
var matchingTypes = this.findListForType(firstType);
if (matchingTypes.Contains(secondType))
{
matchingTypes.Remove(secondType);
}
}
private List<Type> findListForType(Type type)
{
foreach (var keyValuePair in savedMatches)
{
if (keyValuePair.Key == type)
{
return keyValuePair.Value;
}
}
savedMatches.Add(type, new List<Type>());
return findListForType(type);
}
}
该类的设计使得您提供哪种类型的参数无关紧要;它检查type1.list是否有type2,type2.list是否有类型。
一个简单的例子:
typeManager.AddMatch(a, b);
Console.WriteLine(typeManager.CanMatch(a, b)); // True
typeManager.DeleteMatch(b, a);
Console.WriteLine(typeManager.CanMatch(a, b)); // False
Console.WriteLine(typeManager.CanMatch(a, c)); // False
typeManager.AddMatch(a, c);
Console.WriteLine(typeManager.CanMatch(a, c)); // True
Console.WriteLine(typeManager.CanMatch(a, d)); // False
typeManager.AddMatch(b, d);
Console.WriteLine(typeManager.CanMatch(a, d)); // False
Console.WriteLine(typeManager.CanMatch(d, b)); // True
typeManager.DeleteMatch(d, b);
Console.WriteLine(typeManager.CanMatch(d, b)); // False
Console.WriteLine(typeManager.CanMatch(b, d)); // False