如何以实用的方式在HaxeFlixel游戏事件中编码"?

时间:2016-03-30 03:51:27

标签: events haxe haxeflixel

以" 实用方式"我的意思是它可能不会妨碍游戏的速度。

我正在为RPG编程,而且正如你们许多人所知,他们已经完成了很多事件:

  1. 你走进一个事件触发的新房间

  2. 在chars和npcs

  3. 之间进行了一些对话
  4. 但是当你重新进入那个房间时没有任何反应。

  5. 我编写了我的游戏编码,以便每次地图更改时(让我们说它转到地图6)它会在类EventReg.hx中检查Bool数组,如果值(在这种情况下为6)是为true,并将其复制到PlayState.hx中的变量 eventAvailable

    然后在更新函数中,它根据地图编号运行事件,但我觉得这种方法需要在PlayState.hx中以交换机的形式拥挤的大量代码(将当前地图的值作为参考)。

    有没有人知道一些开源RPG,示例或教程处理这个问题? TIA!

    示例:

    //Event Helper
    private var eventAvailable:Bool;
    private var currentMap:Int = MapReg.currentMap;
    
    override public function create():Void
    {
        //Checks if there's an even in the current map.
        eventAvailable = EventReg.isEvent[currentMap];
        if (eventAvailable)
            setupEvent();
    }
    
    private function setupEvent():Void
    {
        switch(currentMap)
        {
            case 0: //code
            case 1: //code
        }
    }
    

1 个答案:

答案 0 :(得分:0)

处理事件的有效方法可能类似于Observer Pattern。我已经使用了这种模式的变体来处理我正在使用的平台游戏库,其中观察者将订阅某个特定事件。它对我来说非常好,所以我想我可以分享它。

这是我的基类:

1)BaxEventSubscriber

interface BaxEventSubscriber {
    function getNotified(baxEventKey:String):Void;  
}

2)BaxEvent

    class BaxEvent implements BaxEventSubscriber
{
    public var id:String;

    /** Event will be fired when all prequisite events are triggered. 
     * Once a prequisite is satisfied, it will be removed from this list. 
     * When the list is empty, the event will trigger */
    public var prequisiteEvents:Array<String>;

    /** 
     * If serialExecution is true, the prequisites must be executed in a serialised order (first to last)
     * In other words, every prequisite will be satisfied only if it is first in the prequisited list
     * 
     * If serial execution is false (default, the prequisites can be satisfied in any order)
     */
    public var serialExecution : Bool = false;

    public function new (id:String) 
    {
        if (id == null) {
            throw "any Event should have an id";
        }

        this.id = id;
        prequisiteEvents = new Array<String>();

    }


    public function addPrequisite(key:String):Void {

        if (key == null || key.length == 0) {
            return;
        }

        var isUnique:Bool = true;
        for (i in 0...prequisiteEvents.length) {
            var ss:String = prequisiteEvents[i];
            if (ss == key) {
                isUnique = false;
            }
        }

        if (isUnique) {

            prequisiteEvents.push(key);
            BaxEventManager.getManager().addSubscriberForEvent(this, key);
        }
    }

    public function getNotified(baxEventKey:String):Void {
        this.eventTriggered(baxEventKey);
    }

    public function eventTriggered(key:String):Void {
        var isPrequisite :Bool = false ;

        for ( i in 0...prequisiteEvents.length) {
            var ss:String = prequisiteEvents[i];
            if (ss == key) {
                isPrequisite = true;
            }
        }

        if (isPrequisite) {

            var ind:Int = prequisiteEvents.indexOf(key);
            // If no serialExecution, checkout this event.
            // Else, check it out only if it's the first on the prequisites list
            if (! serialExecution || ind == 0  ) {
                prequisiteEvents.splice(ind, 1);
            }
        }
        // if all prequisites are satisfied, fite the Event
        if (prequisiteEvents.length == 0) {
            BaxEventManager.getManager().broadcastEvent(this.id);
        }
    }


}

3)BaxEventManager

    class BaxEventManager 
{
    /** the names of registered Events */
    public var events:Array<BaxEvent>;

    /**
     * Objects that need to be notified for a certain event
     * 
     * structure: 
     * [key] = event name (as in events[])
     * subscribers : Array<BaxEventSubscriber> : an array of subcribers for this Event
     */
    public var eventSubscribers : StringMap<Array<BaxEventSubscriber>>;

    private static var eventManager:BaxEventManager;

    public static inline function getManager():BaxEventManager {

        if (eventManager == null)
            return eventManager = new BaxEventManager();
        else
          return eventManager;
    }

    private function new() {
        trace(" BaxEventManager CONSTRUCT");
        events = new Array<BaxEvent>();
        eventSubscribers = new StringMap<Array<BaxEventSubscriber>>();
    }

    /**
     * Registers an event's key, and an array with Subscribers for it. FailSafe, as it checks if event already exists
     * @param   key
     */
    public function addEvent(key : String):Void {
        //trace("check to add key :"+key);
        var alreadyExists :Bool = false;

        for ( i in 0...events.length) {

            var ss :String = events[i].id;
            if ( ss == key ) {
                //trace("key " + key + " exists");
                alreadyExists = true;
                break;

            }
        }
        if (!alreadyExists) {

            events.push( new BaxEvent(key) );

            var subscribers : Array<BaxEventSubscriber> = new Array<BaxEventSubscriber>();
            eventSubscribers.set(key , subscribers);
        }
    }

    public function addSubscriberForEvent(subscriber:BaxEventSubscriber, eventKey:String):Void {
        this.addEvent(eventKey);
        var subscribers :Array<BaxEventSubscriber>  =  eventSubscribers.get(eventKey);
        subscribers.push(subscriber);
    }

    public function broadcastEvent(evt:String) : Void {
        if (evt == null) {
            return;
        }

        var subscribers :Array<BaxEventSubscriber>  =  eventSubscribers.get(evt);
        if (subscribers != null && subscribers.length > 0) {
            for ( i in 0...subscribers.length) {
                var sub:BaxEventSubscriber = subscribers[i];
                sub.getNotified(evt);
            }
        }
    }

    /**
     * Clears up the registered Events and their subscribers.
     * Make sure to Call this when resseting a level, as the subscribers might be nullified
     */
    public function clearEvents():Void {
        ArrayUtils.emptyArray(events);

        eventSubscribers = null;
        eventSubscribers = new StringMap<Array<BaxEventSubscriber>>();
    }   
}

在我的实际实现中,我还使用了不同类型的事件,这些事件定义事件是否应该在每个游戏会话中注册(和触发)一次,或者是否会被触发,或者将被无限触发。现在我正在考虑它,我应该将它包含在BaxEvent类中。

无论如何,关键在于这个设计

  • 您可以更好地控制已触发事件,并且可以更轻松地跟踪已触发的事件
  • 您不必通过所有事件或订阅者迭代更新功能
  • 它是可扩展的,您可以将它用于不同类型的事件,例如关卡事件(收集的所有硬币),步行事件,完成的对话框,开关和交互式对象等。

事件管理器是一个单例类,但您也可以将其设计为静态实用程序类。

BaxEvent实现Event订阅者的唯一原因是支持复杂事件,以便在满足其先决条件(其他事件)时触发它们。但是,如果这对您来说太过分了,您可以删除此功能并简化代码。