任务目的
- 练习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!