如何构建游戏实体列表自定义数据结构

时间:2010-03-02 15:23:52

标签: flash actionscript-3 data-structures collections

我在Flash(玩家10)中编写游戏,需要想出一个很好的方法来管理游戏中的对象/实体/演员列表(玩家角色,障碍物,敌人等)。它有这些要求:

  • 可迭代
  • 迭代时可添加和删除的对象。
    • remove()函数的参数将是要删除的对象,而不是索引。
  • [可选]可以为对象分配名称,并使用该名称进行检索。
  • [可选]可排序,因此某些对象比其他对象更早更新。

我该如何实现?


我正在考虑内存数据库表,其中包含:

  • 包含对象(记录)的数组。
  • 将名称链接到数组索引的散列图(索引)。
  • 将对象链接到其索引的另一个hashmap(通过传递要删除的对象进行删除)。

删除实体会使相应的记录为空。偶尔需要压缩数组(删除空格)或者它会变得太大。这需要重建hashmap以指向正确的记录(但这可以有效地完成)。

思考?它会表现良好吗?以及如何在迭代零件时进行可排序和添加/删除?

6 个答案:

答案 0 :(得分:2)

听起来我想要一个链接列表。

  • 您可以从头到尾枚举列表,或者完成开始
  • 要添加到集合中,只需附加到开头或结尾(只需更改2个指针,非常快!)
  • 如果对象本身充当链表节点,那么你可以直接删除一个对象(只需交换四个指针,真的很快!)
  • 可以使用merge sort
  • 在O(nlongn)中对链接列表进行排序

答案 1 :(得分:1)

听起来这就是你要找的东西:

http://gamedev.michaeljameswilliams.com/2008/09/20/actionscript-3-collection-class/

它是AS3的Collection类,它扩展了Array并添加了add()和remove()等函数,以及一些非常有用的排序函数。我已经习惯了,它表现很好,没有任何抱怨。希望这是你正在寻找的东西,它对你有用。

答案 2 :(得分:1)

如果您正在寻找AS3的一些不同(和高性能)数据结构,我发现这些数据结构在过去非常舒适:

DataStructures by polygonal

答案 3 :(得分:1)

我使用我创建的Manager类来管理一堆可以根据String分配给任何类型“列表”的对象。即你可以将它分配给“敌人”和“ALL_OBJECTS”。该类使用pop()进行几乎即时删除(并使用对象而不是像你想要的那样删除索引)。

以下是您要创建并链接到经理的对象:

public class AvGlyph extends Object
    {
        // vars
        internal var signatures:Array = [];
        private var _attachment:Object;

        /**
         * Constructor
         * @param attachTo An Object to set as the attachment for this
         */
        public function AvGlyph(attachTo:Object)
        {
            _attachment = attachTo;
        }

        /**
         * Dissolves this, destroying reference to _attachment and fully detaching itself
         */
        public function dissolve():void
        {
            _attachment = null;
            AvGlyphManager.fullyDetach(this);
        }

        /**
         * Basic getters
         */
        public function get attachment():Object{ return _attachment; }

        /**
         * Returns an Array containing all signatures applied to this
         */
        public function get allSignatures():Array
        {
            var a:Array = [];

            var i:String;
            for(i in signatures) a.push(i);

            return a;
        }
    }

这是这些经理:

public class AvGlyphManager
    {
        // properties
        private static var _glyphs:Array = [];

        /**
         * Attaches an AvGlyph to a specified list
         * @param glyph The AvGlyph to attach
         * @param signatures Signature Strings used to represent categories
         */
        public static function attach(glyph:AvGlyph, ...signatures):void
        {
            var i:String;
            for each(i in signatures)
            {
                if(!_glyphs[i]) _glyphs[i] = [];

                if(!glyph.signatures[i])
                {
                    glyph.signatures[i] = _glyphs[i].length;
                    _glyphs[i].push(glyph);
                }
            }
        }

        /**
         * Detach an AvGlyph from a specified list
         * @param glyph The AvGlyph to detach
         * @param signature Signature Strings used to represent categories
         */
        public static function detach(glyph:AvGlyph, ...signatures):void
        {
            var i:String;
            for each(i in signatures)
            {
                var n:uint = glyph.signatures[i];

                if(n == _glyphs[i].length - 1) _glyphs[i].pop();
                else
                {
                    _glyphs[i][n] = _glyphs[i].pop();
                    _glyphs[i][n].signatures[i] = n;
                }

                if(_glyphs[i].length < 1) delete _glyphs[i];
            }
        }

        /**
         * Detach an AvGlyph from all previously specified listings
         * @param glyph The AvGlyph to detach
         */
        public static function fullyDetach(glyph:AvGlyph):void
        {
            var i:String;
            for(i in glyph.signatures) detach(glyph, i);
        }

        /**
         * Returns a Array of all AvGlyphs that have been attached with a specified signature
         * @param signature A signature String used to represent a category
         */
        public static function getGlyphs(signature:String):Array
        {
            if(!_glyphs[signature])return [];
            return _glyphs[signature].slice();
        }

        /**
         * Trace a tree of signatures and their children
         */
        public static function traceTree():void
        {
            trace('a');
        }
    }

使用很简单:

在你的课堂上,比如Zombie.as,你可以拥有。

public class Zombie extends Sprite
{
    private var _glyph:AvGlyph;

    /**
     * Constructor
     */
    public function Zombie()
    {
            _glyph = new AvGlyph(this);
        AvGlyphManager.attach(_glyph, "enemies");
    }
}

从这里开始,您可以在应用程序/游戏中的任何地方使用:

AvGlyphManager.getGlyphs("enemies");

哪会返回“敌人”下列出的字形数组。只需通过glyph.attachment即可访问Zombie。因此,对于遍历所有对象的循环,它将是:

var li:Array = AvGlyphManager.getGlyphs("enemies");

var i:AvGlyph;
for each(i in li)
{
    trace(i.attachment);
}

一旦您快速浏览AvGlyphManager,删除可能很简单。还有一个:

AvGlyphManager.fullyDetach(glyph);

当您想要完全删除对象时,这非常有用。

答案 4 :(得分:0)

考虑一下:数组或字典是否符合您的需求?是的,它们并不快速,但它们易于使用(并且符合您的要求)。

如果根据它们采用的代码路径(即静态对象,实体,射弹)正确地隔离对象,通常会得到相当小的动态对象列表和大型静态对象列表。

静态对象不需要花哨的数据结构,因为你可以对它们做很多假设(或者在加载时做繁重的工作),动态对象不需要花哨的数据结构,因为没有许多人。不要优化这种事情,除非:你有重大的架构问题,或者你有一个实际的瓶颈。

因为最终,重要的是:花时间制作游戏,而不是数据结构。 :)

或许我误解了这种情况?

答案 5 :(得分:0)

我目前的解决方案是使用EntityManager类来维护所有实体的字典以及活动数组。前者用于通过id检索实体。后者用于更新循环,如下所示:

var len:int = actives.length;
for(var i:int = 0; i < len; i++)
{
    var entity:Entity = actives[i];
    if(!entity.isActive)
    {
        actives.splice(i,1);
        --len;
    }
    else
    {
        entity.update();    
    }
}

我建议为您的实体管理器创建一个界面,实现可行的功能,如果您发现需要提高性能或添加功能,请稍后再修复它。