着手开始写原计划php小组项目的网络坦克对战。当时决定做游戏的原因是猫哥有h5开发能力,但现在自己做,自己要去学h5的东西。现在记录下学习和开发的过程。

2016.7.26

实现了坦克在空白地图上的移动。

途中遇到的问题:

坦克图片空白位置覆盖地图:

解决方案:通过美图秀秀抠图功能将坦克图抠下,并保存为png图片(如保存为jpg,则空白部分会变成白色,效果跟上图一样,原因是jpg没有alpha通道)

这个问题困扰了我两天,一开始以为是绘图方式的问题,学习了两张绘图方式,之后发现,并不是。然后才在图片上找原因。

目前完成的代码:

main.js

var canvas_width = 1280,canvas_height = 900;
var key_up = 38,key_down = 40,key_left = 37,key_right = 39;
var canvas, stage;
var txt;
var tank;window.onload = function() {creatcanvas();stage = new createjs.Stage(canvas)tank = new tankObj();txt = new createjs.Text("", "20px Arial", "#ff7700");stage.addChild(tank.now);createjs.Ticker.setFPS(60);createjs.Ticker.addEventListener("tick", tick);
}document.onkeydown = function(e) {e = !e ? window.event : e;console.log(e.keyCode);switch (e.keyCode) {case key_up:tank.now = tank.up;tank.ctrlary[0] = true;break;case key_down:tank.now = tank.down;tank.ctrlary[1] = true;break;case key_left:tank.now = tank.left;tank.ctrlary[2] = true;break;case key_right:tank.now = tank.right;tank.ctrlary[3] = true;break;return;}
}
document.onkeyup = function(e) {e = !e ? window.event : e;console.log(e.keyCode);switch (e.keyCode) {case key_up:tank.ctrlary[0] = false;break;case key_down:tank.ctrlary[1] = false;break;case key_left:tank.ctrlary[2] = false;break;case key_right:tank.ctrlary[3] = false;break;}
}function tick(e) {if (tank.ctrlary[0] == true) {if(tank.now.y - tank.speed > 0)tank.now.y = (tank.y -= tank.speed);elsetank.now.y = tank.y;tank.now.x = tank.x;console.log(tank.now.x, tank.now.y);}if (tank.ctrlary[1] == true) {if(tank.now.y + tank.speed < canvas_height - 60)tank.now.y = (tank.y += tank.speed);elsetank.now.y = tank.y;tank.now.x = tank.x;console.log(tank.now.x, tank.now.y);}if (tank.ctrlary[2] == true) {if (tank.now.x - tank.speed > 0)tank.now.x = (tank.x -= tank.speed);elsetank.now.x = tank.x;tank.now.y = tank.y;console.log(tank.now.x, tank.now.y);}if (tank.ctrlary[3] == true) {if (tank.now.x + tank.speed < canvas_width - 60)tank.now.x = (tank.x += tank.speed);elsetank.now.x = tank.x;tank.now.y = tank.y;console.log(tank.now.x, tank.now.x);}stage.removeChildAt(0);stage.addChild(tank.now);stage.update();
}function timepass(e) {console.log(tank.now.x);var time = new Date();txt.text = "Now Time : " + time.getHours() + ":" + time.getMinutes() + ":" + time.getSeconds() + "!";stage.update();
}

tank.js

var tankObj = function(){this.x = 0; //坦克x坐标this.y = 0; //坦克y坐标this.speed = 10;this.up = new createjs.Bitmap("img/tank-up.png");this.left = new createjs.Bitmap("img/tank-left.png");this.right = new createjs.Bitmap("img/tank-right.png");this.down = new createjs.Bitmap("img/tank-down.png");this.now = this.down; //坦克朝向this.up.scaleX = this.up.scaleY =this.down.scaleX = this.down.scaleY = this.left.scaleX = this.left.scaleY =this.right.scaleX = this.right.scaleY =0.3;this.ctrlary = [false,false,false,false]; //按键数组,true为按下,0123分别对应上下左右
};

7.30

27号出了不朽三,滚去玩了几天的dota。当然!我不可能单纯只玩dota!因为月末了嘛,炉石低保还是要拿的,这个月前半个月都在期末复习培训什么的,炉石天梯都没打,又花了些时间!不过!这几天空闲的时候我还是有想一些问题的。早上出去拿物流,下午才开工,7点完成。那么进入正题。

今天完成了单机攻击AI坦克,主要实现了发射炮弹,炮弹判定(击中,出界),以及AI坦克。

首先是发射炮弹:

首先tank类添加了一些属性

增加:count(填弹计时器) ProV(填弹速度),bulV(炮弹速度),boomtime(爆炸状态)以及AIcontime(AI当前状态时间,在AI里说明)

修改:新增参数tanktpye,传递坦克模型。扩增ctrlyary数组空间,代表开火状态,即空格键状态

var tankObj = function(tanktpye) {this.x = 0; //坦克x坐标this.y = 0; //坦克y坐标this.speed = 5;this.count = 0; //填弹计时器this.ProV = 20; //填弹速度this.bulV = 8;this.AIcontime = 0; //AI保持当前状态时间this.boomtime = 0; //爆炸状态this.up = new createjs.Bitmap("img/" + tanktpye + "-up.png");this.left = new createjs.Bitmap("img/" + tanktpye + "-left.png");this.right = new createjs.Bitmap("img/" + tanktpye + "-right.png");this.down = new createjs.Bitmap("img/" + tanktpye + "-down.png");this.now = this.down; //坦克朝向this.up.scaleX = this.up.scaleY = this.down.scaleX = this.down.scaleY = this.left.scaleX = this.left.scaleY = this.right.scaleX = this.right.scaleY = 0.3;this.ctrlary = [false, false, false, false, false]; //按键数组,true为按下,0123分别对应上下左右,4代表开火状态
};

整合函数:将控制坦克函数封装入tank.js内

tankObj.prototype.movement = function() {if(this.boomtime != 0) return;if (this.ctrlary[0] == true) {if (this.now.y - this.speed > 0)this.now.y = (this.y -= this.speed);elsethis.now.y = this.y;this.now.x = this.x;}if (this.ctrlary[1] == true) {if (this.now.y + this.speed < canvas_height - 60)this.now.y = (this.y += this.speed);elsethis.now.y = this.y;this.now.x = this.x;}if (this.ctrlary[2] == true) {if (this.now.x - this.speed > 0)this.now.x = (this.x -= this.speed);elsethis.now.x = this.x;this.now.y = this.y;}if (this.ctrlary[3] == true) {if (this.now.x + this.speed < canvas_width - 60)this.now.x = (this.x += this.speed);elsethis.now.x = this.x;this.now.y = this.y;}
}

新增爆炸函数用于处理坦克集中后动画及移除

tankObj.prototype.boom = function(){if(this.boomtime >= 20)return ;if(this.boomtime % 2 == 0){stage2.removeChild(this.now);this.now = new createjs.Bitmap("img/boom_"+this.boomtime/2+".png");this.now.x = this.x;this.now.y = this.y;this.now.scaleX = this.now.scaleY = (0.6 - 0.1*this.boomtime);stage2.addChild(this.now);}this.boomtime++;
}

爆炸图片编号为0-9,原本写boomtime上限是10即每一帧刷新换一张爆炸图片,效果不够明显,就换成2帧换一张,每一帧更新一次缩放,效果我说不清,就跟烟花一样,爆炸后向左上飘散,等我什么时候心情好了做个gif吧,下面附上爆炸每帧的原图

新增炮弹类

bullet.js

var bulletObj = function() {this.bullet = new createjs.Bitmap("img/bullet.png");this.bullet.scaleX = this.bullet.scaleY = 0.3;this.faceX = 0;this.faceY = 0;
}
bulletObj.prototype.movement = function(i) {this.bullet.x += this.faceX;this.bullet.y += this.faceY;if (bullet[i].bullet.x < 0 || bullet[i].bullet.y < 0 || bullet[i].bullet.x > canvas_width || bullet[i].bullet.y > canvas_height) {stage2.removeChild(bullet[i].bullet);bullet.splice(i, 1);}
}

其中faceX,faceY记录炮弹方向,faceX=-1代表向上发射

bullet为子弹数组定义在main.js中,movement函数每一次刷新都会调用,用于子弹移动已经出界判断

tank.js新增开火函数

tankObj.prototype.onfire = function() {if (this.boomtime != 0)return;if (this.count == 0) {if (this.ctrlary[4] == false)return;var len = bullet.length;bullet[len] = new bulletObj();switch (this.now) {case this.up:bullet[len].bullet.x = this.x + 27;bullet[len].bullet.y = this.y;bullet[len].faceY = -this.bulV;break;case this.down:bullet[len].bullet.x = this.x + 27;bullet[len].bullet.y = this.y + 60;bullet[len].faceY = this.bulV;break;case this.left:bullet[len].bullet.x = this.x;bullet[len].bullet.y = this.y + 20;bullet[len].faceX = -this.bulV;break;case this.right:bullet[len].bullet.x = this.x + 60;bullet[len].bullet.y = this.y + 20;bullet[len].faceX = this.bulV;break;}stage2.addChild(bullet[len].bullet);this.count = this.ProV;} else {this.count--;}
}

每一次刷新都会调用一次开火函数,只有当填弹完成(count=0)并且空格被按下(ctrlary[4]=true)才会触发开火,如果填弹未完成则填弹(count--),开火是通过判断坦克朝向设置子弹初始位置(bullet.x,bullet.y),已经子弹方向(faceX,faceY)

修改test.js

新增:敌人坦克数组entanks,爆炸中坦克数组boomtanks,子弹数组bullet,攻击判断函数AttackJudge,全局变量canvas2和stage2

修改:canvas创建函数createcanvas,帧刷新函数tick,主函数onload以及用于检测开火按键(空格)状态的对应函数

createcanvas函数

function creatcanvas() {canvas = document.createElement("canvas");canvas.id = "canvas";canvas.width = canvas_width;canvas.height = canvas_height;canvas.style.background = "green";document.body.appendChild(canvas);canvas2 = document.createElement("canvas");canvas2.id = "canvas2";canvas2.width = canvas_width;canvas2.height = canvas_height;canvas.style.position = canvas2.style.position = "absolute";canvas.style.buttom = canvas.style.left = canvas2.style.buttom = canvas2.style.left = 0;document.body.appendChild(canvas2);
}

增加第二个canvas标签创建,并设置两个canvas等大小,设置position为absolute,同时获取舞台2stag2,之后子弹,敌对坦克都在stage2刷新

attackjudge函数

function AttackJudge() {for (var i = 0; i < bullet.length; i++)for (var j = 0; j < entanks.length; j++) {if (bullet[i].bullet.x > entanks[j].x + 60)continue;if (bullet[i].bullet.y > entanks[j].y + 60)continue;if (bullet[i].bullet.x + 5 < entanks[j].x)continue;if (bullet[i].bullet.y + 5 < entanks[j].y)continue;stage2.removeChild(bullet[i].bullet);//           stage2.removeChild(entanks[j].now);bullet.splice(i, 1);boomtanks[boomtanks.length] = entanks[j];entanks[j].boom();entanks.splice(j, 1);}
}<strong>
</strong>

遍历所有子弹,判定子弹与所有敌对坦克的位置关系,一旦有重合则将子弹移除数组,敌对坦克移动到爆炸中坦克数组,并执行爆炸函数

onload函数

window.onload = function() {creatcanvas();stage = new createjs.Stage(canvas);stage2 = new createjs.Stage(canvas2);tank = new tankObj("tank");for (var i = 0; i < 3; i++) {entanks[i] = new tankObj("tank2");entanks[i].x = entanks[i].now.x = Math.random() * (canvas_width - 60);entanks[i].y = entanks[i].now.y = Math.random() * (canvas_height - 60);stage.addChild(entanks[i].now);}stage.addChild(tank.now);createjs.Ticker.setFPS(60);createjs.Ticker.addEventListener("tick", tick);
}

添加敌对(AI)坦克创建循环

tick函数

function tick(e) {tank.movement();tank.onfire();if (bullet.length != 0)for (var i = 0; i < bullet.length; i++) {bullet[i].movement(i);}stage.removeAllChildren();for(var i = 0; i<entanks.length;i++){entanks[i].AImove();entanks[i].movement();stage.addChild(entanks[i].now);}stage.addChild(tank.now);AttackJudge();for(var i = 0; i < boomtanks.length; i++){if(boomtanks[i].boomtime >= 20 ){stage2.removeChild(boomtanks[i].now);boomtanks.splice(i,1);continue;}boomtanks[i].boom();}stage.update();stage2.update();
}

封装坦克移动函数以tank.js,tick调用坦克移动函数movement,以及开火函数onfire。当屏幕中有子弹时遍历子弹数组调用子弹移动函数movement。新增循环用于调用AI坦克移动函数,新增循环用于爆炸中坦克动画处理。

坦克AI移动

tankObj.prototype.AImove = function() {if(this.AIcontime != 0){this.AIcontime--;return;}var x = parseInt(Math.random() * 5);for (var i = 0; i < 5; i++)this.ctrlary[i] = false;switch(x){case 0:this.now = this.up;this.ctrlary[0] = true;break;case 1:this.now = this.down;this.ctrlary[1] = true;break;case 2:this.now = this.left;this.ctrlary[2] = true;break;case 3:this.now = this.right;this.ctrlary[3] = true;break;case 4:this.ctrlary[4] = true;return;return;}this.AIcontime = 20;
}

AI坦克将保持移动动作20帧,随后从新随机选择一个方向移动,并重置AIcontime用于计算当前动作保持帧数,这里坦克移动方向随机,AI还没编写攻击性,只用于攻击判断attackjudge函数实验,计划中并不准备编写攻击性,毕竟要做成联网的。

7.31

在媳妇儿的监督下,效率提升,没几个小时就完成了昨天计划今天完成的东西。开始今天的正题。

今天完成了,地图,包括基础地形,特殊地形(坦克无法通行并且炮弹无法通行,坦克无法通行但炮台能通过)。写完这些还有半天以上的时间,本来想把坦克与坦克直接的碰撞也些,不过想了些细节的东西,因为涉及到AI要改很多地方,而且以后做成联网对战的还要不能用,就没去写。准备写完博客帮媳妇儿看算法。

新增地形类

landform.js

var landformObj = function() {this.landary = []; //地形数组this.tankland = []; //坦克通行数组,0为可通过this.bulletland = []; //炮弹通行数组,0为可通过this.landform = []; //地形图片this.background = []; //背景图片
}

地形数组landary中存放图片编号,,坦克通行数组tankland用于存放相对于tank的地形,炮弹通行数组bulletland用于存放相对于炮弹的地形

定义地图生成函数buildlandform

landformObj.prototype.buildlandform = function() {//    this.readlandform() //预留,从服务器上获取地形数组for (var i = 0; i < this.landary.length; i++) {this.landform[i] = new Array();this.background[i] = new Array();for (var j = 0; j < this.landary[i].length; j++) {this.background[i][j] = new createjs.Bitmap("img/land_0.png");this.background[i][j].x = j * 64;this.background[i][j].y = i * 60;stage2.addChild(this.background[i][j]);if (this.landary[i][j] != 0) {this.landform[i][j] = new createjs.Bitmap("img/land_" + this.landary[i][j] + ".png");this.landform[i][j].x = j * 64;this.landform[i][j].y = i * 60;stage2.addChild(this.landform[i][j]);}}}
}

每个地形尺寸都为64*60px。

附上地形素材:

草地(坦克以及炮弹都可通行)

河流(坦克不可通行但炮弹可通行)

岩石(坦克以及炮弹都不可通行)

这里需要补充,因为地形的原因,我修改了main.js中createcanvas函数

function creatcanvas() {canvas = document.createElement("canvas");canvas.id = "canvas";canvas.width = canvas_width;canvas.height = canvas_height;//  canvas.style.background = "green";canvas2 = document.createElement("canvas");canvas2.id = "canvas2";canvas2.width = canvas_width;canvas2.height = canvas_height;canvas.style.position = canvas2.style.position = "absolute";canvas.style.buttom = canvas.style.left = canvas2.style.buttom = canvas2.style.left = 0;//   canvas.style.z - index = 1;//  canvas2.style.z - index = 0;document.body.appendChild(canvas2);document.body.appendChild(canvas);
}

这里修改了下两个canvas的插入顺序,让stag2的canvas先插入,这样stag1就会在stag2上面,不这样做的,位于stag2的地形图片会覆盖位于stag1上的坦克图片

定义坦克通行判断函数tankJudge以及炮台通行判断函数bulletJudge

landformObj.prototype.tankJudge = function(x, y) {var ruj = Math.floor(x / 64); //右上角X坐标所在格子j坐标var rui = Math.floor(y / 60); //右上角Y坐标所在格子i坐标var ldj = Math.floor((x + 50) / 64); //左下角X坐标所在格子j坐标var ldi = Math.floor((y + 50) / 60); //左下角Y坐标所在格子i坐标if (rui < 0)rui = 0;if (ruj < 0)ruj = 0;if (ldi > 14)ldi = 14;if (ldj > 19)ldj = 19;if (this.tankland[rui][ruj] != 0) {console.log("rui,ruj");console.log(rui, ruj);return false;}if (this.tankland[rui][ldj] != 0) {console.log("rui,ldj");console.log(rui, ldj);return false;}if (this.tankland[ldi][ruj] != 0) {console.log("ldi,ruj");console.log(ldi, ruj);return false;}if (this.tankland[ldi][ldj] != 0) {console.log("ldi,ldj");console.log(ldi, ldj);return false;}return true;
}
landformObj.prototype.bulletJudge =function(x,y){var ruj = Math.floor(x / 64); //右上角X坐标所在格子j坐标var rui = Math.floor(y / 60); //右上角Y坐标所在格子i坐标var ldj = Math.floor((x + 5) / 64); //左下角X坐标所在格子j坐标var ldi = Math.floor((y + 5) / 60); //左下角Y坐标所在格子i坐标if (rui < 0)rui = 0;if (ruj < 0)ruj = 0;if (ldi > 14)ldi = 14;if (ldj > 19)ldj = 19;if (this.bulletland[rui][ruj] != 0) {console.log("rui,ruj");console.log(rui, ruj);return false;}if (this.bulletland[rui][ldj] != 0) {console.log("rui,ldj");console.log(rui, ldj);return false;}if (this.bulletland[ldi][ruj] != 0) {console.log("ldi,ruj");console.log(ldi, ruj);return false;}if (this.bulletland[ldi][ldj] != 0) {console.log("ldi,ldj");console.log(ldi, ldj);return false;}return true;
}

修改坦克移动函数

tankObj.prototype.movement = function() {if (this.boomtime != 0)return;if (this.ctrlary[0] == true) {if (this.now.y - this.speed > 0)this.now.y = (this.y - this.speed);elsethis.now.y = this.y;this.now.x = this.x;}if (this.ctrlary[1] == true) {if (this.now.y + this.speed < canvas_height - 60)this.now.y = (this.y + this.speed);elsethis.now.y = this.y;this.now.x = this.x;}if (this.ctrlary[2] == true) {if (this.now.x - this.speed > 0)this.now.x = (this.x - this.speed);elsethis.now.x = this.x;this.now.y = this.y;}if (this.ctrlary[3] == true) {if (this.now.x + this.speed < canvas_width - 60)this.now.x = (this.x + this.speed);elsethis.now.x = this.x;this.now.y = this.y;}if (landform.tankJudge(this.now.x, this.now.y) == false) {this.now.x = this.x;this.now.y = this.y;} else {this.x = this.now.x;this.y = this.now.y;}
}

每次完成移动后,不刷新而是进入tankJudge函数判断新的坐标是否处于可通行的位置,如果不可则返回原来的坐标,可通行则刷新。

修改炮弹移动函数

bulletObj.prototype.movement = function(i) {this.bullet.x += this.faceX;this.bullet.y += this.faceY;if (bullet[i].bullet.x < 0 || bullet[i].bullet.y < 0 || bullet[i].bullet.x > canvas_width || bullet[i].bullet.y > canvas_height || landform.bulletJudge(bullet[i].bullet.x, bullet[i].bullet.y) == false) {stage2.removeChild(bullet[i].bullet);bullet.splice(i, 1);}
}

出界或遇到不可通行地形时皆消失。

附目前运行截图

7.31晚

跟媳妇儿闲聊的时候有了新的想法,只要定义一个函数就可以进行完成坦克碰撞判断,其他地方都不需要修改,下面是新定义的坦克碰撞判断函数covertank

covertank函数

tankObj.prototype.covertank = function(x, y) {for (var i = 0; i < entanks.length; i++) {if (entanks[i] == this)continue;if (entanks[i].x >= x + 50)continue;if (entanks[i].x + 50 <= x)continue;if (entanks[i].y >= y + 50)continue;if (entanks[i].y + 50 <= y)continue;return false;}if (this != tank) {if (tank.x >= x + 50)return true;if (tank.x + 50 <= x)return true;if (tank.y >= y + 50)return true;if (tank.y + 50 <= y)return true;return false;}return true;
}

这个地形通行判断也可以用这个算法,可以提高判断精度,不过地形的数组比较大会影响效率。

然后在坦克移动函数movement里调用这个函数就好了,方式和坦克通行判断函数tankJudge一样。

[初学]H5+PHP 在线坦克开发日记相关推荐

  1. DC音乐播放器开发日记

    DC音乐播放器开发日记 MediaPlayer介绍: MediaPlayer的状态转换图也表征了它的生命周期,搞清楚这个图可以帮助我们在使用MediaPlayer时考虑情况更周全,写出的代码也更具健壮 ...

  2. 应用之星:十问十答,让你更快了解H5制作和app开发

    1.应用之星是什么? 答:应用之星是在线app开发平台,H5制作平台,无需编码技术,人人都能开发app,制作H5页面. 2.应用之星可以做什么? 答:应用之星可以做Android应用,iOS应用和H5 ...

  3. 我的uni框架APP(共享充电投放)独立开发日记 第一天

    我的uni框架APP(共享充电投放)独立开发日记 项目说明及介绍 练习阶段 APP开发第一天(设计和功能归类) 首页 物品 我的 项目说明及介绍 在前不久写完了第一个微信小程序之后,开始补课VUE,就 ...

  4. 我的uni框架APP(共享充电投放)独立开发日记 第二天

    我的uni框架APP(共享充电投放)独立开发日记 APP开发第二天(UI实现到创作) Tap_Bar: 首页 充电榜 邀请赚钱 项目说明 物品 我的 会员资料 下载APP 我的收益 我要提现 我的下级 ...

  5. 广东海洋大学体育馆管理系统 开发日记2

    GYM用来对体育馆进行管理,主要功能包括人员管理.场地使用管理.体育赛事管理.器材管理.运营金额数据报表. GYM包括三种角色(Actor): 1.   普通用户(User) 普通用户指的是GYM系统 ...

  6. 开发日记-20190513 关键词 汇编语言(六)

    其实,每次当我写一篇开发日记,并且这篇开发日记并没有关键词,或者我并没有和你扯东扯西的情况下... 这意味着我这天偷懒了= = ;AddTwo.asm --两个32位整数相加.386.model fl ...

  7. 开发日记-20190328 关键词 利用eolinker一键快速生成API接口文档

    今天感觉效率真的很低= =各个层面的,apk发布到现场发现出现了问题,所以一个下午都在忙着解决现场出现的问题,领导一直打电话询问进度,午觉也没有睡所以今天预计的很多计划都处于停滞状态,像昨天规划的今天 ...

  8. LayIM.AspNetCore Middleware 开发日记(一)闲言碎语

    前言 前几天写博客的时候突然看见了历史上的今天.不禁感慨时光如梭,这系列博客后来被我标注了已经过时,但是还有很多小伙伴咨询我.既然过时就要更新,正好 .NET Core 也出来很久了,于是乎想到把La ...

  9. YunTable开发日记(3) – BigTable的数据模型和调用接口 (转载)

    源地址:http://peopleyun.com/?p=665 本文将深入分析BigTable的数据模型,并介绍它是如何被调用的. 数据模型 就像向我之前所说的那样,其实BigTable顾名思义,是一 ...

最新文章

  1. 聊聊lettuce的shareNativeConnection参数
  2. 402. 移掉K位数字(单调栈)
  3. 【图像处理】——Python实现灰度特征提取
  4. LOJ#2145. 「SHOI2017」分手是祝愿
  5. UIScrollView的简单使用
  6. Visual Studio 2010 C++ 用户属性设置
  7. mac下mysql忘记root密码的解决办法
  8. 高等院校计算机考试等级,全国高等院校计算机等级试考试大纲.doc
  9. java bean 动作标签_jsp:javabean动作标签实例
  10. js截取字符长度加省略号
  11. Team Foundation 使用第三方比较工具
  12. 共享单车数据集_共享单车数据的数据可视化
  13. Mac 安装仿宋GB2312 For Word/WPS
  14. 如何阅读一本好书:APUE
  15. js将数字金额用符号间隔 vue中使用逗号间隔数字金额-共享博客
  16. (八)RHEL系统之红帽8操作系统基础环境配置及软件安装
  17. java append函数_请详细说一下java中append()的方法.
  18. mongodb导入数据
  19. mac python3 调用 .so_Mac OS X链接.so文件到动态库
  20. 在nsa组网架构中,3gpp定义的nr与epc的接口是什么

热门文章

  1. [蓝桥杯第十一届校内模拟赛] Apare_xzc
  2. 痞子衡嵌入式:揭秘i.MXRT1170 eFuse空间访问可靠性的保护策略(冗余与ECC)
  3. 用 rollup 打包 library
  4. 基于Cordova的博客园APP
  5. Android UsageStatsService 系统数据统计和数据上报
  6. 新手主播首播带货超20万,直播的标准脚本免费传授
  7. 【js正则表达式】小数点保留两位的js正则表达式
  8. 好好吃饭、不焦虑打工、潮酷同行,这些公司的新年礼盒越来越会玩~
  9. 监控-硬盘录像机问题集锦
  10. 餐厅点餐系统详细设计与系统实现