supce's blog

IFE Task 14


任务目的

  • 练习JavaScript面向对象设计
  • 实践一些基础的设计模式

任务描述

  • 基于上个任务,我们继续改善我们的任务
  • 第一代宇宙飞船系统真是糟糕的实现,所以我们需要进行改进飞船自身,我们在几个部件进行了更多的组合可能性,在创建新飞船时可以自行选择
  • 我们新增了几种动力系统,能够让飞船飞得更快,相应的能源消耗也会不同
  • 我们新增了集中能源系统,能够让飞船能量补充能源速度越快
  • 接下来改进的是指令的传播问题
  • 我们发明了新一代的传播介质BUS,它的单次传播失败率降低到10%,传播速度提升到300ms,而且他增加了多次重试的功能,可以保证信息一定能够传递出去,请你实现这个可以通过多次重试保证在10%丢包率情况下顺利将信息传递出去的BUS传播介质
  • 但BUS有个弱点,就是无法直接传递JSON格式,它只能传递二进制码,但指挥官并不能够直接下达二进制编码指令,所以我们需要在行星上的发射器部分增加一个模块Adapter,把原来的指令格式翻译成二进制码。同时还需要在飞船的接收器部分增加一个Adapter,用来把二进制码翻译成原来能够理解的指令格式
  • 二进制码格式自定,可以参考的例子:前四位标示飞船编号,后四位标示具体指令(0001:开始飞行,0010:停止飞行,1100:自我销毁)

整体思路

由于飞船能够设置飞行速度和能量恢复速度。所以在原来代码的基础上添加两个select

<div id="panel_base">
    <label id="panel_title">飞船操控板</label>
    <label class="info_label">飞船速度:</label>
    <select id="selEngine">
        <option value="speed_one">用恨飞行</option>
        <option value="speed_two">手摇飞行</option>
        <option value="speed_three">电能飞行</option>
        <option value="speed_four">核能飞行</option>
    </select>
    <label class="info_label">充能速度:</label>
    <select id="selSupply">
        <option value="900">用爱充能</option>
        <option value="600">手摇充能</option>
        <option value="300">燃料充能</option>
        <option value="100">核变充能</option>
    </select>
    <button id="craft_creat">增加新飞船</button>
</div>

然后将原来的CSS代码重新分类,设置不同的飞行速度

.speed_one{
    animation: 32s spin infinite linear;
    animation-play-state:paused;
}
.speed_two{
    animation: 24s spin infinite linear;
    animation-play-state:paused;
}
.speed_three{
    animation: 16s spin infinite linear;
    animation-play-state:paused;
}
.speed_four{
    animation: 8s spin infinite linear;
    animation-play-state:paused;
}

重新修改飞船类代码,添加飞船引擎属性和飞船动力恢复系统属性,并且重新修改原来的若干方法。

//飞船类
function Craft(id,engine,supply){
    //飞船id
    this.id = id;
    //飞船引擎控制飞船速度
    this.engine = engine;
    //飞船供能系统控制能量恢复速度
    this.supply = supply;
    //飞船能量
    this.power = 100;
    //飞船是否正在飞行
    this.state = "stop";
    //控制飞船动力系统
    this.timer = null;
}
Craft.prototype = {
    constructor: Craft,
    receiveCommond : function(commond){
        var adapter = new Adapter();
        var commond = adapter.decode(commond);
        if(commond.id == this.id){
            order = commond.commond;
            switch(order){
                case 'start':
                    msgControl("有嘎达~ 信息传递成功!");
                    this.powerConsume();
                    this.state = "start";
                    this.start();
                    break;
                case 'stop':
                    msgControl("有嘎达~ 信息传递成功!");
                    this.powerAdd();
                    this.state = "stop";
                    this.stop();
                    break;
                case 'destroy':
                    msgControl("有嘎达~ 信息传递成功!");
                    this.destroy();
                    break;
            }
        }
    },
    start : function(){
        msgControl("Nozomi power注入! 嗨~ 噗咻!" + (this.id+1) + "号飞船已经起飞");
        var craftImg = document.querySelector("." + craftsMap[this.id]);
        craftImg.classList.add("craft_start");
        craftImg.classList.add(this.engine);
    },
    stop : function(){
        msgControl("sa si su se so!" + (this.id+1) + "号飞船停止飞行");
        var craftImg = document.querySelector("." + craftsMap[this.id]);
        craftImg.classList.remove("craft_start"); 
    },
    destroy : function(){
        msgControl("dame! dame!" + (this.id+1) + "号飞船被销毁了");
        //先停止再销毁
        var id = this.id;
        var craftImg = document.querySelector("." + craftsMap[id]);
        craftImg.classList.remove("craft_start");
        clearInterval(this.timer);
        //销毁飞船
        craftImg.classList.remove(this.engine);
        craftImg.classList.remove("craft_create");
        //销毁控制板
        document.getElementById(id).classList.add("li_hidden");
        //将飞船从轨道撤下
        for(var i=0,len=crafts.length;i<len;i++){
            if(crafts[i].id == id){
                crafts.splice(i,1);
                break;
            }
        }
    },
    powerConsume : function(){
        var speedMap = {
            speed_one : 900,
            speed_two : 600,
            speed_three : 300,
            speed_four : 100 
        };
        var _this = this;
        if(this.timer){
            clearInterval(this.timer);
        }
        this.timer = setInterval(run,speedMap[this.engine]);
        function run(){
            if(_this.power>0){
                _this.power = _this.power - 1;
                var craftImg = document.querySelector("." + craftsMap[_this.id]);
                craftImg.innerHTML = _this.power + "%";
            }else{
                _this.stop();
                _this.state = "charge";
                clearInterval(_this.timer);
                _this.powerAdd();
            }
        }
    },
    powerAdd : function(){
        var _this = this;
        if(this.timer){
            clearInterval(this.timer);
        }
        this.timer = setInterval(run,parseInt(this.supply));
        function run(){
            if(_this.power<100){
                _this.power = _this.power + 1;
                var craftImg = document.querySelector("." + craftsMap[_this.id]);
                craftImg.innerHTML = _this.power + "%";
            }else{
                if(_this.state == "charge"){
                    _this.start();
                    _this.state = "start";
                    clearInterval(_this.timer);
                    _this.powerConsume();
                }else{
                    clearInterval(_this.timer);
                }
            }
        }
    }
}

然后我们添加一个飞船工厂,用于创建不同的飞船

//飞船工厂
function CraftFactory(){
}
CraftFactory.prototype = {
    createCraft : function(){
        //查询是否存在空闲轨道
        var path = $("control_panel").querySelector(".li_hidden");
        if(path){
            var id = path.getAttribute("id");
            var engine = $("selEngine").options[$("selEngine").selectedIndex].value;
            var supply = $("selSupply").options[$("selSupply").selectedIndex].value;
            console.log(id + engine + supply);
            crafts.push(new Craft(id, engine, supply));
            //使飞船送达预定轨道
            var craftImg = document.querySelector("." + craftsMap[id]);
            craftImg.classList.add("craft_create");
            craftImg.innerHTML = "100%";
            //创建panel
            path.classList.remove("li_hidden");
            var btns = path.getElementsByTagName('button');
            for(var i=0,len=btns.length;i<len;i++){
                addHandler(btns[i],"click",function(e){
                    btnHandler(e);
                });
            }
            msgControl("飞船" + (id+1) + "号已到达预定轨道,请发送下个命令撒~");
        }else{
            msgControl("部署失败,不存在空闲轨道");
        }
    }
}

重新信号发射器,设置该发射器可以通过多次重试保证在10%丢包率情况下顺利将信息传递

//信号发射器类
function Mediator(){
}
Mediator.prototype = {
    sendCommond : function(commond){
        var timer = null;
        var adapter = new Adapter();
        var commond = adapter.encode(commond);
        timer = setInterval(run,300);
        function run(){
            var num = Math.floor(Math.random()*10+1);
            if(num > 1){
                for(var i=0;i<crafts.length;i++){
                    crafts[i].receiveCommond(commond);
                }
                clearInterval(timer);
            }else{
                msgControl("信息传递失败!正在重试,fight だよ!");
            }
        }
    }
}

由于发送的数据格式发生变化,需要写一个适配器,用于编码和解码。

//适配器
function Adapter(){
}
Adapter.prototype = {
    //编码器
    encode : function(commond){
        var str = "";
        var id = commond.id;
        var order = commond.commond;
        switch(id){
            case '0':
                str += "00";
                break;
            case '1':
                str += "01";
                break;
            case '2':
                str += "10";
                break;
            case '3':
                str += "11";
                break;
        }
        switch(order){
            case 'start':
                str += "0001";
                break;
            case 'stop':
                str += "0010";
                break;
            case 'destroy':
                str += "1100";
                break;
        }
        return str;
    },
    //解码器
    decode : function(commond){
        var str_id = "",str_order = "";
        switch(commond.substring(0,2)){
            case '00':
                str_id = 0;break;
            case '01':
                str_id = 1;break;
            case '10':
                str_id = 2;break;
            case '11':
                str_id = 3;break;
        }
        switch(commond.substring(2)){
            case '0001':
                str_order = "start";break;
            case '0010':
                str_order = "stop";break;
            case '1100':
                str_order = "destroy";break;
        }
        return {
            id : str_id,
            commond : str_order
        }
    }
}   

OK much nicer!


最终代码

最终代码
demo