zoukankan      html  css  js  c++  java
  • 马里奥项目中对象直接通讯小结

    提到对象之间的通讯,我想到了设计模式中的责任链模式,他为请求创建了一个接受者对象的链.这种模式通过请求类型,在责任链上的对象来判断是否进行处理,对请求的发送者和接受者进行解耦
    下面是转自菜鸟教程的实例UML图

    但是我的项目中,对象请求和处理对象一般是一一对应的,并没有用到责任链模式,而是以下的几种处理方法:

    1. 类的静态变量
    2. 请求者对象包含了处理者对象的引用并直接调用其处理函数
    3. 请求者对象包含了处理者对象的引用但处理函数只改变标记变量,处理者对象自动检查标记变量判断是否进行处理
    4. 创建事件的监听器,事件发生时回调处理者的处理函数,并将请求者对象作为参数传入
      下面我以项目中的代码来展示这四种实现

    类的静态变量

    将要请求的变量设置为类的静态变量,这样所有的请求者可以直接通过类名来访问,而不需要包含处理者的对象

    	// 分数
        private static Integer score = 0;
        // 显示分数的标签
    	private static Label scoreLabel;
    
    
        public static void reSetScore(){
            score = 0;
        }
    
        /**
         * 加分
         */
        public static void addScore(int value){
            score += value;
            scoreLabel.setText(String.format("%06d",score));
        }
    
    

    这种方法的好处是实现简单,且操作的结果可以直接反应出来.但静态变量相当于全局变量破坏了封装性,在多个请求者进行调用时,会在在安全性方面大大降低

    请求者直接调用处理函数

    当请求者对象中的逻辑发出了请求时,直接调用内部响应者对象的处理函数,在下面例子中,当主类判断马里奥应该死亡时,便直接调用了马里奥对象(die())方法

        /**
         * 马里奥死亡
         */
        public void die(){
            if(!isDead()){
                Mario.manager.get("assets/audio/music/mario_music.ogg", Music.class).stop();
                Mario.manager.get("assets/audio/sounds/mariodie.wav", Sound.class).play();
                marioIsDead = true;                     //设置死亡状态
                Filter filter = new Filter();
                filter.maskBits = Mario.NOTHING_BIT;    //不可碰撞
                for (Fixture fixture : b2body.getFixtureList()) {
                    fixture.setFilterData(filter);
                }
                // 向上的速度
                b2body.applyLinearImpulse(new Vector2(0, 4f), b2body.getWorldCenter(), true);
            }
        }
    

    这种实现的好处是逻辑简单,逻辑调用与实际执行是同一个方法,实现也比较简单,但这种方法提高了函数功能的复杂程度.改变人物图像的功能应在特定函数中执行,而在(die())函数中却掺杂了这一功能.

    请求者调用改变其标记变量

    该方式与上种方式其请求者对象都含有与其对应的相应者的引用,但该方式在发出请求时,响应者只改变其内部的标记变量,在他自身的更新函数执行时才真正的处理该请求

    下面例子中马里奥吃到蘑菇,边调用马里奥的(grow())方法,而在该方法中只对其标记变量进行改变,在更新时根据标记变量,来调用生成大马里奥的函数

    
        /**
         *  马里奥增长
         */
        public void grow() {
            // 当前为大马里奥则不需要变大
            if(marioIsBig)  return;
            runGrowAnimation = true;
            marioIsBig = true;
            timeToDefineBigMario = true;
            setBounds(getX(), getY(), getWidth(), getHeight() * 2);
            Mario.manager.get("assets/audio/sounds/powerup.wav", Sound.class).play();
        }
    
    	// 更新函数中生成大马里奥的代码
        if (timeToDefineBigMario) {
    		// 实际重新生成大马里奥的逻辑
            defineMario(b2body.getPosition().add(0,10/Mario.PPM),true);
        }
    
    

    监听器处理

    我们在事件的发生源添加一个监听器,当事件发生时由监听器捕捉,并传递给响应者

    下面是个处理刚体碰撞的例子,我们为所有能产生碰撞的对象中添加碰撞监听器,发生碰撞时通过刚体自带的碰撞掩码来确定碰撞源,之后调用不同碰撞源的处理函数

    
        Fixture fixA = contact.getFixtureA();   // A碰撞源
        Fixture fixB = contact.getFixtureB();   // B碰撞源
        // 获得碰撞码
        int cDef = fixA.getFilterData().categoryBits | fixB.getFilterData().categoryBits;
    
        // 敌人 与 敌人
        // 敌人 调用 敌人碰撞方法 并传入另一碰撞源
        case Mario.ENEMY_BIT :
            ((Enemy)fixA.getUserData()).onEnemyHit((Enemy)fixB.getUserData());
           ((Enemy)fixB.getUserData()).onEnemyHit((Enemy)fixA.getUserData());
            break;
    

    该方法是java常见的事件处理方法,在为对象添加监听器后,在监听器中处理事件,但在本例中将重新确认事件源后再调用事件源本身的处理函数,看起来是多余. 但这种做法一是为了适配碰撞监听器,二是保持了模块的内聚,使得碰撞处理模块更加通用和可扩充.

    以上大致是我项目中的对象通讯的实践,说是对象的通讯,其实也就只是函数之间的互相调用,加上自己的一些想法算是一个总结.

  • 相关阅读:
    Android之绚丽的图片游览效果--有点像W7效果,透明的倒影,层叠的图片,渐变的颜色透明度
    小程序自定义弹出框
    从零学React Native之04自定义对话框
    ajax的content-download时间过慢问题的解决与思考
    小程序
    使用自定义视图的AlertDialog
    Android浮动按钮
    android 实现微信分享多张图片的功能
    AndroidUI多线程网络请求更新导致BUG
    ==比较时的坑
  • 原文地址:https://www.cnblogs.com/xxrlz/p/11127328.html
Copyright © 2011-2022 走看看