2D游戏中对象的c#结构

本文关键字:结构 对象 游戏 2D | 更新日期: 2023-09-27 18:09:35

首先,请允许我为提出一个看起来有点模糊(或不太正式)的问题道歉,但我缺乏经验,无法提出更具体的问题。

我正在用c#创建一个用于玩2D冒险游戏的引擎(你点击一个对象,然后发生一些事情),我正在考虑它的最佳结构。你可以想象,当你与一个物体互动时,不同的事情会发生:如果它是一扇门,你希望进入另一个房间,如果它是一个人,你希望开始与他们交谈,等等。我的想法是通过委托实现这种行为,像这样:

public abstract class GameObject {
    public delegate void onAction();
    public onAction Click;
}
public class Door : GameObject {
    public Door() {
        Click = new onAction(ChangeRoom);
    }
    private void ChangeRoom() {
        //code to change room here
    }
}
public class Person : GameObject {
    public Person() {
        Click = new onAction(StartTalking);
    }
    private void StartTalking() {
        //code to display dialogue here
    }
}

我发现这个解决方案非常优雅,因为如果我想创建一个特殊的对象,它的类没有涵盖一些行为,我可以简单地这样做:

specialObject.Click += new onAction(SpecialMethod);

但这也是事情变得复杂的地方。我希望我的引擎能够简单地通过加载不同的数据来玩不同的游戏,而不需要改变引擎本身,所以在引擎中的某个地方硬编码SpecialMethod是不可行的,它必须是数据的一部分。对于普通对象,这都可以通过(反)序列化来完成,但据我所知,这对于委托来说是有问题的。你能建议一个做这件事的方法吗?

注:因为我还在概念层面,上面的代码还没有实现,你可以自由地提出任何你认为最好的解决方案,甚至是完全避免委托的解决方案。

2D游戏中对象的c#结构

你需要的是脚本

本质上,脚本是一种外部资源(即外部文件),它包含描述操作的源代码。

c#有不同的选项。

可以从。net语言发出程序集。或者您可以集成另一种语言(例如python),并在运行时执行脚本。基本上,脚本会在正确的时间加载、解释或编译并执行。如果脚本能够修改应用程序状态(数据结构),您可以使用外部数据(数据驱动的开发)定义对象行为。

关于这个问题有很多文献,但我觉得建议使用GPU Programming Gems 6(第4节)。然而,集成一个伟大的脚本引擎需要付出很大的努力。通过这种方式,我试图找出一个基于XML文件的简单逻辑(这里是我的问题,加入另一个定义XML内容的问题);遗憾的是,我发现这几乎取决于你需要的灵活性。

首先,当你缺乏经验时,编写引擎可能比你想象的要困难。我建议你在没有引擎和硬代码的情况下编写你的第一款游戏,然后从经验中学习并编写你的引擎……我知道这不是你想要的:D

如果您还没有检查,请查看http://www.adventuregamestudio.co.uk/,使用编辑器并考虑下面的对象模型。这会有帮助的。

既然你希望你的游戏是数据驱动的,你就必须能够动态加载和执行代码。"它不一定是一种脚本语言。"建议在学习如何构建引擎的同时添加脚本语言并学习它是违背我的本性的。net框架有一个很棒的反射系统,允许你加载c#代码并在运行时编译它。我必须指出,这是一种c#脚本,但缺乏脚本语言的适当定义。

既然你在这方面没有很多经验,我的建议是使用XML文件来定义你的房间,并有一个基本的节点(命令)序列来定义当你点击某些东西时应该发生什么。你应该在你的"引擎"中执行所有命令,但你可以轻松地创建新的房间,因此类似的游戏。XML也是一种非常可扩展的方法,因为它的层次结构允许你添加条件、循环等,这将扩展你的引擎的"脚本"功能。

你不需要硬编码SpecialMethod函数到你的引擎中,你可以在使用你的引擎的不同游戏中使用它:

var medievalDoor = new Door();
medievalDoor.Click += OpenDoorNormally;

但是在另一个游戏中:

var starTrekDoor = new Door();
starTrekDoor.Click += SlideDoorUpward;

只要公开Click事件,就不需要在引擎中硬编码任何内容。它可以放在你的游戏中,你的游戏引擎可以作为DLL参考。

如果执行某些特殊行为的"决定"留给游戏对象本身,我不认为有什么问题。如果你想让引擎做出决定,那么我认为你有不兼容的设计规范,因为你会有效地让引擎做出游戏定义的决定,而这正是你不想要的。

在你的游戏对象中创建一个ISpecialBehaviorProvider字段,并在必要时将其设置为适当的值(通过构造函数,公共属性,等等)

当用户单击时,您的引擎将始终执行GameObject.Click。但是,如果specialBehaviorProvider为null,则使GameObject.Click执行'in class'代码,否则调用ISpecialBehaviorProvider.SpecialMethod

这样,引擎不参与决定调用哪个方法。

这里我要注意的第一件事是由于这些是类,多态性在这里将是非常理想的—例如使用虚拟的Click方法。

委托对于序列化器来说确实很棘手,这取决于序列化方法。BinaryFormatter 做到这一点,但作为一般规则,我倾向于不惜一切代价避免该序列化器。

如果可能的话,我建议让您的自定义子类的标准实现,并使用多态性。如果它必须完全通过数据定义,那么您实际上是在实现一个脚本引擎。在。net中有很多这样的工具——IronPython可能很有用,尽管对于游戏来说lua很常见(你应该能够使用lua)。. NET非常容易)。然后,您只需将一个可选脚本与该操作关联,并调用该脚本(在数据中定义)。