寻找有关游戏中攻击和攻击类型的编程设计的一些见解


14

因此,我开始向我们的2D空间RTS引入攻击(这是在Unity中进行的,因此它是组件驱动的)。最初,它很简单,例如“范围内的敌人,造成的伤害”。但是,将有多种“类型”的武器/攻击与其特定的船只或结构相关联。以及其他仅涉及原始损坏的因素,例如损坏类型,以及将来可能的惯性。

你们每个单位和结构类型都有自己的攻击类型吗?意思是您为每个单元/结构制作一个脚本,以定义其攻击类型,伤害,效果,射程,粒子,精灵...等,并将其作为组件附加?

或制作一个定义攻击类型的脚本,一个与该攻击类型关联的弹丸类型的脚本...等等,然后扩展它们并为每个单位修改它们,将每个脚本附加到单位/结构上。


我希望我有一定的道理,我已经考虑了很长时间了,我不确定是要解决问题,还是只是自己解决问题并陷入困境。

如果您的游戏可能具有多种攻击类型,并且可能不受限于特定的单元/结构,那么您如何设计在组件驱动的设计环境中将框架与特定的单元/结构绑定在一起的框架?

如果还不清楚,请告诉我。

编辑:很好的答案,谢谢。

扩展问题:

答案似乎有所不同,从“每个对象都可以拥有自己的攻击脚本”到“将攻击类型作为自己的脚本并将其分配给每个对象以提供更可重用的解决方案”。可以说我有一次“冲击波”攻击,它以一定速度射击红色弹丸。它的伤害,射速和弹丸大小取决于发射它的单位。只是为该部队制作攻击脚本,还是尝试修改“爆炸攻击”以适合每个想要使用它的部队的目的,这更好吗?


1
对于一般的游戏编程构想,我想参考RPG FFV的完整规格-gamefaqs.com/snes/588331-final-fantasy-v/faqs/30040
Code Whisperer

Answers:


12

好吧,老实说,我不是专家,但是...我认为这取决于您认为攻击将变得多么复杂和多样。由于它是RTS,我猜您可能会有10-50个左右的具有不同攻击类型的单位或结构。

选项1:如果攻击的单位数量相对较少,则将所有内容放入一个大脚本中并定义检查器中使用的参数。

选项2:另一方面,如果您设想大量具有不同行为的攻击类型,则可以分解所有内容,以便每个单元和建筑物都具有自己独特的攻击脚本。我在想,如果这样做,您可能想创建一个“帮助程序”脚本,该脚本定义许多单个脚本可以从中获取的常用代码块。这样,您就不必重写所有内容,并且知道所有内容在哪里。

选项3:您可能不应该做的是让某些单位的单位共享脚本,这可能会使您感到困惑,并且如果您需要攻击的代码位于10个不同的脚本中,则会变得一团糟。

在这里,我画了一张照片。

在此处输入图片说明


2
非常感谢你的答复。由于某种原因,我开始倾向于选择3,而我很难找到一种方法来证明它的合理性。我可能会走第二条路线,每个单元都将获得自己的自定义攻击脚本,并通过将公共代码作为每个单元/建筑物的组成部分进行攻击来共享公共代码。我不确定我的思路会导致我走到选项3的方向,谢谢。我要离开这个开放的,直到我起床AM的情况下,有一些想附和其他海报。
道格拉斯·加斯克尔

没问题,这不是绝对的答案,但希望能有所帮助。
2015年

1
您可以通过将类似的攻击在一个大的脚本杂交1和2以及分离出不同的攻击
棘轮怪胎

4
我很惊讶建议反对#3?是否不是模块化/泛型类的全部要点,以便每个单元都不必定义自己的类型?如果游戏是RTS,而攻城伤害(通常是“远程”)是一种伤害类型,则您需要定义一次,并在执行其伤害计算时有多个火炮式单位引用它,因此如果攻城伤害曾经需要神经(平衡),您只需要更新一堂课?
HC_

1
"Here, I drew you a picture."让我想起了这一点
FreeAsInBeer

4

我对Unity不太了解,而且我有一段时间没有做游戏开发了,所以让我给您这个问题的一般编程答案。我的回答基于我对实体组件系统的一般了解,其中实体是与N个许多组件相关联的数字,一个组件仅包含数据,并且系统对与之相关联的组件集进行操作同一实体。

您的问题空间是这样的:

  • 整个游戏中有多种攻击敌人的方法。
  • 每艘船,构筑物等可能有多种攻击方式(每种方式都以某种方式确定)
  • 每次攻击可能都有其自己的粒子效果。
  • 攻击必须考虑目标和用户身上存在的某些因素(例如,惯性或装甲)。

我将构建如下的解决方案:

  • 攻击具有标识符-可以是字符串。
  • 实体“知道”它可以使用攻击(基于攻击的标识符)。
  • 当实体使用攻击时,会将相应的显示组件添加到场景中。
  • 您具有一些了解攻击目标,攻击者和所使用攻击的逻辑-该逻辑应确定您造成的损失(并可以使用惯性或两个实体中的任何一个)。

重要的是,攻击与实体之间的接触点应尽可能薄-这将使您的代码可重复使用,并防止您不得不为使用同一类型攻击的每种不同类型的实体提供重复的代码。换句话说,这里有一些JavaScript伪代码可以帮助您了解。

// components
var bulletStrength = { strength: 50 };
var inertia = { inertia: 100 };
var target = { entityId: 0 };
var bullets = {};
var entity = entityManager.create([bulletStrength, inertia, target, bullets]);

var bulletSystem = function() {
  this.update = function(deltaTime, entityId) {
    var bulletStrength = this.getComponentForEntity('bulletStrength', entityId);
    var targetComponent = this.getComponentForEntity('target', entityId);
    // you may instead elect to have the target object contain properties for the target, rather than expose the entity id
    var target = this.getComponentForEntity('inertia', targetComponent.entityId);

    // do some calculations based on the target and the bullet strength to determine what damage to deal
    target.health -= ....;
  }
};

register(bulletSystem).for(entities.with(['bullets']));

抱歉,这个答案有点“麻烦”。我只有一个半小时的午餐休息时间,很难在不完全了解Unity的情况下提出一些建议:(


3

当单位/结构/武器攻击时,我可能会创建一个攻击(以您所有有趣的细节归类),以攻击者和防御者(或多个防御者)为对象。然后,攻击可以与目标/防御者(慢速,毒药,伤害,改变状态)进行交互,绘制自身(光束,射线,子弹),并在完成时自行处理。我可以预见一些问题,例如多次毒药攻击,因此也许您的目标将实现与攻击进行交互的Damageable接口,但是我认为这是一种可行的方法,可以模块化且灵活地进行更改。

扩展的答案
这就是我用这种方法来处理 blaster攻击的方法。我让其他人自己回答。

我将让我的单位使用基本攻击统计信息/方法来实现IAttacker接口或类。当IAttacker攻击IDamageable时,它将创建自身和目标(IAttacker和IDamageable或IDamageable的集合)通过的特定攻击。攻击从IAttacker获取其所需的统计信息(以避免在升级过程中进行更改或类似的操作,我们不希望攻击在启动后更改其统计信息),如果需要专门的统计信息,则将IAttacker转换为其所需的类型(例如IBlasterAttacker),并以这种方式获取专门的统计信息。

按照这种方法,BlasterAttacker只需要创建一个BlasterAttack,而BlasterAttack负责其余的工作。您可以将BlasterAttack子类化,也可以创建单独的FastBlasterAttacker,MegaBlasterAttacker,SniperBlasterAttacker等,并且每一个的攻击代码都相同(并且可能继承自BlasterAttack):创建BlasterAttack并将自己和我的目标传递给BlasterAttack处理细节。 。


本质上,该单元继承自IAttacker接口(我已经有这个接口),并且“敌人”有一个IDamageable接口(也有此接口)。攻击者攻击时,将调用BlasterAttack(或派生类)。这种“攻击”会从IAttacker检索所需的数据,并在射弹命中时将其应用于IDamageable?射弹本身是否包含BlasterAttack类,因此一旦发射,它就不再受IAttacker更改的影响,并且仅在射弹实际命中时,它才能对IDamageable施加伤害/效果。
Douglas Gaskell 2015年

当您说“调用了BlasterAttack(或派生类)”时,我会说创建了BlasterAttack。这个新创建的BlasterAttack实例表示光束(或子弹或射线或其他任何东西),因此它射弹。BlasterAttack从IAttacker和IDamageable对象复制所需的任何统计信息:位置,攻击者统计信息等。然后,BlasterAttack跟踪其自身的位置,并在适用时对“接触点”造成损害。您需要弄清楚如果错过或到达目的地(目标的旧位置)时该怎么办。烧地面?消失?你的来电。
ricksmt 2015年

对于影响范围内的攻击,您可能希望访问(敌人)单位的全局集合,因为谁在射程内和谁不在射程内,可以在火力和冲击力之间进行切换。当然,可以为BlasterAttack提出类似的论点:您错过了最初的目标,但击中了身后的家伙。我唯一关心的是,您可能会通过大量敌人反复进行许多攻击,以找出它们是否击中了什么以及击中了什么。这是性能方面的问题。
ricksmt 2015年

嗯,那很有道理。对于错过的攻击,弹丸将具有其自己的预设范围/寿命。如果在该寿命结束之前撞到了其他物体,它将获得对与它碰撞的刚体的所有物体的引用,并且将以这种方式施加损坏。实际上,这就是所有弹丸的工作方式,他们不知道它们要向“前进”的方向,只是他们正在前进(不包括像导弹一样的归巢的弹丸)。AEO效果只能在目标上启用球体碰撞器,并获得其中的所有对象。谢谢您的帮助。
道格拉斯·加斯凯尔

没问题。很高兴我可以。忘了Unity使所有这些冲突变得更容易了。
ricksmt
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.