当我正在开发我的小游戏时,我已经取得了很多进展,但对许多事情感到沮丧。最新的事情是creating a list of required items
,并且您了解我将为您提供我创建的Explanation
以及Code
,但显然无效...
我 - 解释
为了让玩家建造一座建筑物,他必须完成一些必要的研究,每项研究都需要更多的研究才能研究......就像一棵研究树,玩家将通过探索它来经历它们。游戏和做一些任务......
所以想象一下,你可以更准确地看一下我的小代码
II - 代码
//Available Main Elements
var carbon = new Element {Name = "Carbon"};
var hydrogen = new Element {Name = "Hydrogen"};
var oxygen = new Element {Name = "Oxygen"};
var nitrogen = new Element {Name = "Nitrogen"};
//Example Research
var steam = new Research(name : "Steam", requiredElements: null, requiredResearches: /*Fire*/ & /*Water*/ & /*Iron*/);
所以从最后一段代码[只是为了解释],玩家想要研究Steam
,例如需要另外3个研究才能被研究......其中一个{{1}还需要再研究1个研究等等[可能更少或许更多或根本没有要求] ......
结论是问题是:我怎样才能创建这样的嵌套,以便当玩家尝试进行研究时,系统会快速查看他所做的研究以及他想做的研究[包括它的嵌套研究] ]如果玩家不符合要求,它只会返回一棵树,上面有他想要实现的东西?
毕竟,我只想提前感谢你,我正在等待你非常宝贵的支持......
答案 0 :(得分:5)
我会从Research对象本身中删除需求逻辑。简单来说就是这样:
public class Research
{
public string Name { get; set; }
}
然后,我会在Dictonary
中保留一份要求列表,其中每个Research
包含一桶其他Researches
:
Dictionary<Research, List<Research>> requiredResearches =
new Dictionary<Research, List<Research>>();
// the list of Researches the player has completed
List<Research> playersResearched = new List<Research>;
例如,“Steam”将包含“Fire”,“Water”和“Iron”。也许“铁”包含“锡”。
接下来,给定一项研究,我们可以查看所有需求,包括要求的要求:
// e.g. research is "Steam" and returns "Fire", "Water", "Iron", "Tin"
var chainOfRequirements = GetReq(requiredResearches, research);
调用这样的递归函数:
public IList<Research> GetReq(Dictionary<Research, List<Research>> reqs,
Research target)
{
var chain = new List<Research>();
if(reqs.ContainsKey(target))
{
foreach(var item in reqs[target])
{
chain.Add(item);
chain.AddRange(GetReq(reqs, item));
}
}
return chain;
}
您返回的是一系列要求(包括要求要求)。此时,针对Researches
的玩家列表的一点查询可以向您返回哪些缺失:
var missing = chainOfRequirements.Where (c =>
playerResearches.Where (r => r == c).Any () == false).Distinct();
public sealed class NameEqualityComparer : IEqualityComparer<Research>
{
public bool Equals(Research x, Research y)
{
if (ReferenceEquals(x, y)) return true;
if (ReferenceEquals(x, null)) return false;
if (ReferenceEquals(y, null)) return false;
if (x.GetType() != y.GetType()) return false;
return string.Equals(x.Name, y.Name);
}
public int GetHashCode(Research obj)
{
return (obj.Name != null ? obj.Name.GetHashCode() : 0);
}
}
答案 1 :(得分:1)
我不清楚C#
提供代码,但您可以让每个Research
都有Array
类型Research
,这样就可以保存Research
必须完成才能生成实际的Research
,然后您只需要迭代Array
检查是否所有这些都已完成。
您甚至不需要检查要求的要求,就好像它们已经完成,它们已经完成了所有要求。
如果Research
没有任何要求,您只需将Array
清空。
答案 2 :(得分:1)
一种可能性是将bool completed
添加到Element
和Research
类。然后,您可以使用一个函数来检查completed == false
的任何子研究。
bool CanCompleteResearch(Research r)
{
for (Research sub in r.requiredResearches)
{
// No need to recursively check 'sub'; in order for 'sub' to be marked as
// completed, its sub-researches must've been already completed.
if (!sub.completed)
return false;
}
return true;
}
我确信你可以用LINQ做一些单线技巧。
编辑:这仅适用于一次不在多个地方使用研究树的情况(即如果您在多个播放器实例中共享研究对象)。
编辑2:为了找出所有缺失的研究,您可以使用简单的递归函数:
void ListMissingResearch(Research r)
{
for (Research sub in r.requiredResearches)
{
if (!sub.completed)
{
// print message saying "Research <r> requires research <sub>"
ListMissingResearch(sub); // list any missing sub-sub-research
}
}
}
答案 3 :(得分:1)
我建议您创建自己的requirementsTree
课程,该课程必须是至少包含以下成员的链接列表:
requirementsTree[] prerequisiteResearch
属性,包含该特定项目所需的所有研究。bool isResearched
属性,表示玩家是否实际上已经研究过这个项目。bool isEligibleToResearch()
,它循环遍历prerequisiteResearch
中的所有项目,以检查玩家是否已经对它们进行了研究。有了这个,我认为你有一个结构良好且可扩展的需求类。
答案 4 :(得分:1)
我无法想到会阻止这种事情发生的任何具体事情,但我可以理解为什么你会犹豫不决,只是在没有仔细思考的情况下跳进编码。为了尝试给出一些指示,这里有一些我想象你到底有的功能:
// Having a function to retrieve a unique variable by its name (backed by a Dictionary<string, Research>)
// is often handy for me, especially if you decide to script the requirements tree in a text file.
// If you have enough references passed around that you can do this without a static method, all
// the better.
Research.getResearchByName(string name)
// A recursive function. If this research has not been completed, it adds itself to the set, as well
// as any prerequisites (by calling this function on its prerequisites). The top-level, public
// version of this function would create the set, and then return it after performing this check. If
// the Set is empty, then the player can start the research.
Research.addUnresearched_Internal(Set<Research> unresearched)
我认为我的方法的主要问题是我只想使用Set而不是Tree; 但有一些变化,你可能比我做得更好。
答案 5 :(得分:1)
听起来你想做这样的事情:
public class Research
{
private Collection<Research> prerequisites
public Collection<Research> Prerequisites
{
get { return this.prerequisistes; }
}
public bool IsComplete { get; set; }
public IEnumerable<Research> RequiredResearch()
{
if (this.IsComplete)
{
return new Research[0];
}
else
{
return new[] { this }.Concat(
this.Prerequisites.SelectMany(r => r.RequiredResearch()));
}
}
}
如果你正在制作一个多人游戏,它可能必须是这样的:
public class Player
{
private Collection<Research> completedResearch
public Collection<Research> CompletedResearch
{
get { return this.completedResearch; }
}
}
public class Research
{
private Collection<Research> prerequisites
public Collection<Research> Prerequisites
{
get { return this.prerequisistes; }
}
public IEnumerable<Research> RequiredResearch(Player player)
{
if (player.CompletedResearch.Contains(this))
{
return new Research[0];
}
else
{
return new[] { this }.Concat(
this.Prerequisites.SelectMany(r => r.RequiredResearch(player)));
}
}
}
如果这些方法尚未完成(而不仅仅是它的先决条件),这两种方法都将返回当前的研究。您可以简单地对结果执行.Skip(1)
以忽略当前结果。
答案 6 :(得分:1)
你可以在你的研究班中使用这样的函数,只需要一个可用的Research
列表,用来检查玩家是否具有先决条件。这假设在Research
类中有一个名为Prereqs
的本地列表或其他可枚举Research
个。
public bool CanHas(IEnumerable<Research> researches)
{
return Prereqs.All((pr) => researches.Contains(pr) && pr.CanHas(researches));
}
该函数只是递归检查每个Prereq以查看它是否在传入的列表中,然后检查先决条件先决条件。 All
是一个linq扩展方法,如果枚举中的所有元素都符合条件,则返回true。如果没有元素,则返回true(元素的所有零都满足条件),因此当你到达没有Prereqs的Research
时,这将终止。
注意:这是深度优先搜索,对于同一研究是多于一个先决条件的子研究并不聪明。