Laya 1.x AS3 游戏开发 以玩家死亡为例子 了解如何通过事件调用函数

42 阅读3分钟

先明确方案的目的:

使得类当中的函数,在事件分发的时候被调用

比如:希望当玩家死亡的时候,玩家的角色倒下

我们希望的是 当玩家死亡的时候,系统“告诉”死亡处理函数:“玩家现在死亡了,倒下了”,即当玩家死亡的时候调用Player类中的onPlayerDead函数


/*系统提示类*/
public class Player
{
    ...
    /*
    玩家死亡的时候调用
    @param data 附带的数据
    */
    public function onPlayerDead(data:*):void
    {
        console.log("玩家死亡!死因:{1}",parseToString(data));
        fall(data);//玩家的角色倒下
    }
    ...
}

方案一:要求类实现接口

我们编写一个“关心数据”接口,并将实现这个接口的类被注册到控制中心的“关心数据的类”的集合当中。

控制中心可将事件以及附带的数据向集合中的每个类发送。

类根据收到的事件类型,以及相应的数据做相应的处理。 如图1所示,其中A和B都是“关心数据的类”。

image.png

可以在基类中添加判断,继承了该类的子类是否实现“关心数据”接口,如果事件了,则注册到控制中心中的集合当中。

注意:当对象的生命周期结束的时候应该从“关心数据”集合当中注销掉

简化代码如下:

关心数据的接口,要求类实现 对派发的事件的类型以及数据做出相应处理

public interface ICareAboutData
{
    function updateData(type:String,param:Object):void
}

控制中心需要负责存储注册的物体,以及分发事件

/*控制中心*/
public class Class Control
{
    //因为该集合是全局唯一的 所以使用static
    private static var dic:Object = new Object();
    ...
    /*注意 调用static方法的时候 不需要实例化类,就可以调用*/
    /*注册Object*/
    public static function registerObject(object:ICareAboutData):void
    {
        //使用自带的内部成员属性(带有$)的
        dic[object["$_GID"] = object;
    }   
    ...
    /*注销Object*/
    public static function unregisterObject(object:ICareAboutData):void
    {
        delete dic[view["$_GID"]];
    }
    
    /*广播事件*/
    public static function dispatch(type:*,param:Object):void
    {
        for(var key:* in dic)
        {
        var object:ICareAboutData = dic[key];
        object.updateData(type,param);
        }
    }
}

基类,这里主要是想说明,可以通过在基类编写判断是否为"关心数据"的逻辑,来避免为每个物体(每种角色,比如:如果敌人也要求死亡就倒下,那么继承基类就好了)都单独写逻辑。

/*自定义的基类,生命周期根据使用的游戏引擎有区别,这里以Laya 1.x为例*/
public class BaseCharacter extends Object
{
    ...
    protected function onAdded()
    {
        ...
        if(this is ICareAboutData)
        {
            Control.registerObject(this);
        }
        ...
    }
    ...
    /*当然地,在生命周期结束的时候应该注销*/
    protected function onRemoved():void
    {
        ...
        if(this is ICareAboutData)
        {
            Control.unregisterObject(this);
        }
        ...
    }
    
}

这时,可以使玩家的角色类Player 继承这个基类,并实现接口,如下所示:

适配之后的Player类:

/*系统提示类*/
public class Player extends BaseCharacter implements ICareAboutData
{
    ...
   
    //玩家死亡的时候调用
    //@param data 附带的数据
    public function onPlayerDead(data:*):void
    {
        console.log("玩家死亡!死因:{1}",parseToString(data));
        fall(data);//玩家的角色倒下
    }
    ...
    
    /*为到来的事件以及数据做处理*/
    /*不同的事件类型 以及不同的数据 可以做不同的处理的 也可以不做处理*/
    public function updateData(type:String,param:Object = null):void
    {
            swich(type)
            {
                case EventType.PLAYERED:
                    onPlayerDead(param);
                    break;
                case EventType.SOMEEVENT:;
                    break;//不做处理,当然不写也行,这里是为了表现差异化
                defalut:
                    break;
            }
            
    }
    
}

这时候 可以假设,有以下通信协议类,收到服务器的信息之后可以发事件,通报玩家死亡:

public class PlayerCtr
{
    public function onReceive(playerData:*):void
    {
        if(playerData.hp <= 0 )
        {
            Control.dispatchAll(EventType.PLAYERED);
        }
    }
}