昨天参加了hack day的一个比赛,赛制大致是:24小时,自由组队2~4人,任意发挥。运气比较好,拿了第三名和最佳创意奖。

建议先看看这个demo,bug是有的,chrome下玩玩,测试测试就行,O(∩_∩)O~

  DEMO:http://qianduannotes.sinaapp.com/3dtank/html/index.html

基本效果:

关于

懒得去SAE上折腾,没把那另外一半的功能补上,不过我还是介绍下这几个没补上功能吧。

  1. 音效。开始音乐是比较古老的坦克大战开机音乐。

    ① 开始音效 点击播放

    ② 发子弹    点击播放

    ③ 击中坦克 点击播放

    ④ 爆炸       点击播放

  ②和③是自己录制的,呵呵,DIY的东西才好玩。

  2. 登录验证

  

  采用的是解锁,这个创意应该是非常不错的,当登录的时候,A、B玩家下方会生成一个如上图的canvas解锁块,当然这个解锁卡也会通过socket传送到手机遥控端,手机解锁成功后方可登录。

  

  3. 坦克360°旋转

  由于键盘控制只能上下左右,所以360°是转不出来的..刚想截一张手机控制游戏的图,总是报错...囧(后台用的是php,socket控制信号传输,刚打开手机端网页的时候php socket报错)。

手机遥控端视图:

  这里主要利用的是手机多点触控,touchstart,touchmove,touchend这三个事件。

function canvasAddListener() {canvas.addEventListener('touchstart', onTouchStart, false);canvas.addEventListener('touchmove', onTouchMove, false);canvas.addEventListener('touchend', onTouchEnd, false);
}

  4. 重新开始游戏和打死坦克添加效果等

以上都是没有公开显示出来的效果,下次弄好了再上传吧,嘻嘻。

先说说前台

前台主要采用的是css3和js(这是废话)。

1. css3构建一个3D游戏场地

效果:

.box {width:500px;height:500px;position:relative;-webkit-transform-style: preserve-3d;/*-webkit-transform: rotateY(40deg);*/-webkit-transition:all 1s ease-in-out;
}
.inBox {width:300px;height:300px;overflow: hidden;text-align: center;box-shadow: 0px 0px 2px white;background:rgba(255,255,255,.2);/*background:#779443;*/position:absolute;top:100px;left:100px;color:white;
}
.box-forward {-webkit-transform: rotateY(0deg) translateZ(150px);
}
.box-back {-webkit-transform: rotateY(180deg) translateZ(150px);
}
.box-left {-webkit-transform: rotateY(270deg) translateZ(150px);
}
.box-right {-webkit-transform: rotateY(90deg) translateZ(150px);
}
.box-top {-webkit-transform:rotateX(90deg) translateZ(150px);
}
.box-bottom {-webkit-transform:rotateX(-90deg) translateZ(150px);
}

上面是css部分,比赛过程中,参看了下张鑫旭大哥的文章(之前这块还不是很了解的),文章链接。就不细说了。

下面是HTML部分:

<div class="w"><div class="box"><div class="inBox box-forward" data-num="upF rightF downF leftF" data-v="1"><div></div></div><div class="inBox box-back" data-num="upF leftF downF rightF" data-v="2"><div></div></div><div class="inBox box-left" data-num="upF forwardF downF backF" data-v="3"><div></div></div><div class="inBox box-right" data-num="upF backF downF forwardF" data-v="4"><div></div></div><div class="inBox box-top" data-num="backF rightF forwardF leftF" data-v="5"><div></div></div><div class="inBox box-bottom" data-num="backF leftF forwardF rightF" data-v="6"><div></div></div></div>
</div>

2. JS这块,写了比较多。

var $ = document.querySelectorAll.bind(document);/**
* @description core part
* @author hustskyking
*/
var faces = $(".inBox"),bloodA = $(".bloodA div")[0],bloodB = $(".bloodB div")[0],box = $(".box")[0],upF = $(".box-top")[0],downF = $(".box-bottom")[0],leftF = $(".box-left")[0],rightF = $(".box-right")[0],forwardF = $(".box-forward")[0],backF = $(".box-back")[0],cSize = upF.clientWidth,datas = {"upF": upF,"downF": downF,"leftF": leftF,"rightF": rightF,"forwardF": forwardF,"backF": backF},stopN = 0,tanks = {},  randomTank = 2,tankLimit  = 20,//a   w   d  s   j      ←   ↑   →  ↓   pdebug_keySet = [[65, 87, 68, 83, 74], [37, 38, 39, 40, 80]];/**
* @Class Tank
* @attrs width, height, currentX, currentY, speedX, speedY, angleX, angleY, plusy, plusx
*        container, dataset, stopN, tank, tankId, life, bulletBox, color, timerLimit, timer, gap,sTime
*/
var Tank = function(setting){var opts = setting || {};this.container = opts.container || forwardF;this.dataset   = this.container.getAttribute('data-num').split(" ");this.belong = 0;this.grade  = 0;this.debug  = false;this.width  = opts.width || 14;this.height = opts.height || 18;this.stopN  = "keyup" + (window.stopN++);this.gap    = opts.gap || 30;this.speed  = opts.speed || 3;this.ax     = 0;this.ay     = 0;this.cx     = opts.cx || (cSize - this.width) / 2;this.cy     = opts.cy || (cSize - this.height) / 2;this.sx     = 0;this.sy     = 0;this.tank   = null;this.tankId = "";this.life   = 100;this.color  = opts.color || "#0047B3";this.bulletBox = [];this.bColor = opts.bColor || "#0047B3";this.timerLimit= 400;this.gunAngle  = 0;this.timer     = null;this.sTime     = 0;
}Tank.prototype = {init: function(tankId, debug){if(tankId){this.tankId = tankId;this.belong = (Number(tankId) > 2 ? 2 :Number(tankId));}else{throw new Error("必须设置tank ID");}var this_ = this;//绘制坦克this.paintTank();if(debug){this.debug = true;this.keySet = debug.keySet;window.addEventListener("keydown", function(){this_.move_debug();}, false);}window.addEventListener(this.stopN, function(){clearInterval(this_.timer);}, false);},paintTank: function(){var tank = document.createElement("span");var circle = document.createElement("span");var gun = document.createElement("span");gun.setAttribute("class", "gun");tank.setAttribute("class", "tank");circle.setAttribute("class", "circle");tank.setAttribute("id", "tank" + this.tankId);gun.style.borderColor = this.color;circle.style.borderColor = this.color;tank.style.cssText = "width:" + this.width + "px;height:" + this.height + "px;top:" + this.cy + "px;left:" + this.cx + "px;border-color:" + this.color;tank.appendChild(gun);tank.appendChild(circle);this.container.getElementsByTagName("div")[0].appendChild(tank);this.tank = tank;return tank;},switchPainter: function(N){//N  1->up 2->right 3->down 4->downthis.ay %= 360;var r = false,a = 0;if (this.ay > 180) {this.ay -= 360;r = true;}if (this.ay < -180) this.ay += 360;this.container = datas[this.dataset[N]];this.dataset   = this.container.getAttribute('data-num').split(" ");this.container.getElementsByTagName("div")[0].appendChild(this.tank);if(this.belong >= 2) return;box.style.cssText = "-webkit-transform: rotateY(" + (this.ay + (r ? -a : a)) + "deg);";},setAngle: function(x, y, ang){this.sx = x;this.sy = y;this.gunAngle = 90 - ang / Math.PI * 180;$("#tank" + this.tankId)[0].style.cssText += "-webkit-transform: rotate(" + this.gunAngle + "deg);";},move: function(ang){this.setAngle(Math.cos(ang), -Math.sin(ang), ang);this.stopAni();this.ani();},direction_debug: function(){switch(event.keyCode) {case this.keySet[0]:return "left";case this.keySet[1]:return "up";case this.keySet[2]:return "right";case this.keySet[3]:return "down";case this.keySet[4]:return "shooter";}},move_debug: function(){this.stopAni();switch(this.direction_debug()) {case "up":console.log("up");this.setAngle(0, -1, Math.PI / 2);this.gunAngle_debug = 0;break;case "down":console.log("down");this.setAngle(0, 1, Math.PI / 2 * 3);this.gunAngle_debug = 180;break;case "left":console.log("left");this.setAngle(-1, 0, Math.PI);this.gunAngle_debug = 90;break;case "right":console.log("right");this.setAngle(1, 0, Math.PI * 2);this.gunAngle_debug = -90;break;case "shooter":console.log("shooter");this.shooter();default:return;}this.ani();},ani: function(){var this_ = this;this.timer = setInterval(function(){this_.detective();// this_.detectiveTank();
this_.cx += this_.sx * this_.speed;this_.cy += this_.sy * this_.speed;this_.detective();this_.tank.style.top = this_.cy + "px";this_.tank.style.left = this_.cx + "px";}, this.gap);},stopAni: function(){var event = document.createEvent('HTMLEvents');event.initEvent(this.stopN, true, true);event.eventName = this.stopN;window.dispatchEvent(event);}, detective: function(){if(this.cx - this.width >= cSize){  //rightthis.ay += -90;this.ax += 0;this.switchPainter(1);this.cx = 1;}if(this.cx + this.width <= 0){      //leftthis.ay += 90;this.ax += 0;this.switchPainter(3);this.cx = cSize + this.width - 1;}if(this.cy <= 0){                   //topthis.sy = 0;this.cy = 4;}if(this.cy + this.width >= cSize){  //bottomthis.sy = 0;this.cy = cSize - this.width - 8;}},detectiveTank: function(){if(this.cx - this.width >= cSize){  //rightthis.ay += -90;this.ax += 0;this.switchPainter(1);this.cx = 1;}if(this.cx + this.width <= 0){      //leftthis.ay += 90;this.ax += 0;this.switchPainter(3);this.cx = cSize + this.width - 1;}if(this.cy <= 0){                   //topthis.sy = 0;this.cy = 4;}if(this.cy + this.width >= cSize){  //bottomthis.sy = 0;this.cy = cSize - this.width - 8;}},shooter: function(){if((new Date()).getTime() - this.sTime < this.timerLimit) return;var bullet = new Bullet(this.gunAngle, this.cx, this.cy, this.tankId);this.container.getElementsByTagName("div")[0].appendChild(bullet.bullet);bullet.move();this.sTime = (new Date()).getTime();},destroy: function(){this.stopAni();this.shooterTimer && clearInterval(this.shooterTimer);  this.moveTimer && clearInterval(this.moveTimer);  if(this.tankId >= 2 && randomTank <= tankLimit) createRandomTank();delete tanks[this.tankId];this.tank.parentNode && this.tank.parentNode.removeChild(this.tank);delete this;}
}/**
* @Bullet Tank
* @attrs bullet, timer, gap, x, yadsjsw
*/
var Bullet = function(gA, x, y, tankId){  this.bullet = document.createElement("span");this.timer  = null;this.gap    = 30;this.passed = 0;var a = Math.cos(gA / 180 * Math.PI - Math.PI / 2), b = Math.sin(gA / 180 * Math.PI - Math.PI / 2);if(Math.abs(a) > 1) a = a > 0 ? Math.floor(a) : Math.ceil(a);if(Math.abs(b) > 1) b = b > 0 ? Math.floor(b) : Math.ceil(b);this.a = a;this.b = b;this.x = x + 6;this.y = y + 7;this.bullet.setAttribute("class", "bullet");this.bullet.style.top = -10 + "px";this.bullet.style.left = -10 + "px";this.bullet.style.borderColor = tanks[tankId].bColor;this.tankId = tankId;this.container = $("#tank" + this.tankId)[0].parentNode.parentNode;this.belong = tanks[this.tankId].belong;
}
Bullet.prototype = {bSwitchPainter: function(N){this.container = this.bullet.parentNode.parentNode;this.dataset   = this.container.getAttribute('data-num').split(" ");this.container = datas[this.dataset[N]];this.dataset   = this.container.getAttribute('data-num').split(" ");this.container.getElementsByTagName("div")[0].appendChild(this.bullet);this.passed++;if(this.passed == 4){this.destroy();}},detective: function(){if(this.x - 2 >= cSize){      //rightthis.bSwitchPainter(1);this.x = 1;}if(this.y - 2 >= cSize){      //bottomthis.destroy();}if(this.x + 2 <= 0){          //leftthis.bSwitchPainter(3); this.x = cSize + 3;}if(this.y + 2 <= 0){          //topthis.destroy();}},move: function(){var this_ = this;this.timer = setInterval(function(){this_.detective();this_.x += this_.a * 5;this_.y += this_.b * 5;this_.checkHit();this_.bullet.style.top = this_.y + "px";this_.bullet.style.left = this_.x + "px";}, this.gap);},checkHit: function(){for (var i in tanks) { if (i == this.tankId) continue;if (tanks[i].belong == this.belong) continue;  var tx = tanks[i].cx,ty = tanks[i].cy,bc = this.container.getAttribute("data-v"),tc = tanks[i].container.getAttribute("data-v"),w = 14;if ((bc == tc) && (this.x < tx + w) && (this.x > tx - w) && (this.y < ty + w) && (this.y > ty - w) ) {console.log(i, tanks[i].life);this.hit(tanks[i]);this.destroy();}}},hit: function(tTank){tTank.life -= 20;if(tTank.belong == 0){console.log("1掉血");bloodA.style.bottom = 300 * tTank.life / 100 + "px";if(tTank.life == 0){setTimeout(function(){$(".pujieL")[0].style.display = "block";}, 2000);}}else if(tTank.belong == 1){console.log("2掉血");bloodB.style.bottom = 300 * tTank.life / 100 + "px";if(tTank.life == 0){setTimeout(function(){$(".pujieR")[0].style.display = "block";}, 2000);}}else {var add = 5;if(tanks[this.tankId].belong == 0){if(tTank.life == 0){add = 20;//window.addTankGrade(0);
                }tanks[this.tankId].grade += add;$("#gradeA")[0].innerHTML = tanks[this.tankId].grade;}else{if(tTank.life == 0){add = 20;//window.addTankGrade(1);
                }tanks[this.tankId].grade += add;$("#gradeB")[0].innerHTML = tanks[this.tankId].grade;}}if(tTank.life <= 0){tTank.destroy();console.log("destroyed");}},destroy: function(){clearInterval(this.timer);if (typeof tanks[this.tankId] != 'undefined') {var tankArr = tanks[this.tankId].bulletBox;tankArr.splice(tankArr.indexOf(this),1);}this.bullet.parentNode && this.bullet.parentNode.removeChild(this.bullet);}
}/*
function createTank(color){var tank = document.createElement("span");var circle = document.createElement("span");var gun = document.createElement("span");gun.setAttribute("class", "gun");tank.setAttribute("class", "tank");circle.setAttribute("class", "circle");gun.style.borderColor = color;circle.style.borderColor = color;tank.style.cssText = "width:14px;height:18px;position:relative;border-color:" + color;tank.appendChild(gun);tank.appendChild(circle);return tank;
}function addTankGrade(N){var box, color, tank;if(N == 0) {box = $("#tankBoxA")[0];color = "#8500FF";}else{box = $("#tankBoxB")[0];color = "#6D6D27";}tank = createTank(color);box.appendChild(tank);}
*/
function createRandomTank(obj) {var obj = obj || {cx: 150, cy: 150, color:"#ECFF0B", bColor:"#ECFF0B", speed: 1, container: backF};var rTank = new Tank(obj);rTank.init(String(randomTank));rTank.shooterTimer = null;rTank.shooterTimer = setInterval(function(){if(Math.random() > 0.8){rTank.shooter();   }}, 200);rTank.moveTimer = null;rTank.moveTimer = setInterval(function(){if(Math.random() > 0.4){var ang = Math.PI * 2 * Math.random();rTank.move.call(rTank, ang);}}, 1200);tanks[randomTank] = rTank;randomTank++;
}function run_debug(){tanks[0] = new Tank({cx: 50, cy: 220, color:"red", bColor:"red"});tanks[0].init('0', {keySet:debug_keySet[0]});tanks[1] = new Tank();tanks[1].init('1', {keySet:debug_keySet[1]});createRandomTank({cx: 250, cy: 220, color:"#ECFF0B", bColor:"#ECFF0B", speed: 1, container: backF});createRandomTank({cx: 220, cy: 220, color:"#ECFF0B", bColor:"#ECFF0B", speed: 1, container: backF});createRandomTank({cx: 190, cy: 220, color:"#ECFF0B", bColor:"#ECFF0B", speed: 1, container: backF});createRandomTank({cx: 160, cy: 220, color:"#ECFF0B", bColor:"#ECFF0B", speed: 1, container: backF});createRandomTank({cx: 130, cy: 220, color:"#ECFF0B", bColor:"#ECFF0B", speed: 1, container: backF});createRandomTank({cx: 100, cy: 220, color:"#ECFF0B", bColor:"#ECFF0B", speed: 1, container: backF});
}/*
window.onload = function(){var layer = document.createElement("div");layer.setAttribute("id", "layer");var stripe = document.createElement("div");stripe.setAttribute("id", "stripe");stripe.style.top = (document.clientHeight - 250) / 2 + "px";document.body.appendChild(layer);document.body.appendChild(stripe);
}*/
$("#gradeA")[0].innerHTML = $("#gradeB")[0].innerHTML = 0;//run_debug();function showMsg(msgContent){   var box = document.createElement("div");var msg = document.createElement("div");box.setAttribute("id", "showMsgBox");msg.setAttribute("id", "msgBox");with(box.style){position = "absolute";top = 0;left = 0;bottom = 0;right = 0;}with(msg.style){margin = "0 auto";width = "500px";height = "400px";marginTop = "100px";padding = "55px";fontSize = "30px";fontFamily = "微软雅黑";lineHeight = "40px";}msg.innerHTML = msgContent || "空";box.appendChild(msg);document.body.appendChild(box);
}showMsg("<b style='color:white'>[测试版本]</b>本版本只实现了一半的功能,最终版本是手机控制,并且有音效、登录验证、坦克可以360°旋转,因为需要配置环境,没有公开。左右边界可以穿过,为3D效果。5枪可以搞定一个坦克。" +
"<p style='color:yellow;text-align:center'>按键 ctrl+alt+J 开始</p><p>①:WSAD 控制上下左右,J发子弹</p><p>②:↑↓←→ 控制上下左右,p发子弹</p>")window.onkeydown = function(){if(event.ctrlKey && event.altKey && event.keyCode == 74){$("#showMsgBox")[0].style.display = "none";$("#msgBox")[0].style.display = "none";run_debug();}
}

3D Tank JavaScript

拆开分析下:

  ① Tank对象

DIY坦克(还行,哈哈哈~):

var Tank = function(setting){var opts = setting || {};this.container = opts.container || forwardF;this.dataset   = this.container.getAttribute('data-num').split(" ");//....
}Tank.prototype = {init: function(tankId, debug){//....if(debug){this.debug = true;this.keySet = debug.keySet;window.addEventListener("keydown", function(){this_.move_debug();}, false);}window.addEventListener(this.stopN, function(){clearInterval(this_.timer);}, false);},paintTank: function(){//....
    },switchPainter: function(N){//....
    },direction_debug: function(){//....
    },move_debug: function(){//....
    },ani: function(){ //....},stopAni: function(){var event = document.createEvent('HTMLEvents');event.initEvent(this.stopN, true, true);event.eventName = this.stopN;window.dispatchEvent(event);}, detective: function(){
        //....},detectiveTank: function(){//....
    },shooter: function(){//....
    },destroy: function(){//....
    }
}

  

  难点在于一些边界的判断,但是好好考虑下也不算什么难点咯~这些代码中应该看到了很多debug之类的变量和函数,因为我写了两种模式,一种是手机端玩,一中是电脑键盘控制(debug模式)。

  ②子弹对象

/**
* @Bullet Tank
* @attrs bullet, timer, gap, x, yadsjsw
*/
var Bullet = function(gA, x, y, tankId){  //....
};

Bullet.prototype = {move: function(){//....
    },checkHit: function(){//....
    },hit: function(tTank){//....
    },destroy: function(){clearInterval(this.timer);if (typeof tanks[this.tankId] != 'undefined') {var tankArr = tanks[this.tankId].bulletBox;tankArr.splice(tankArr.indexOf(this),1);}this.bullet.parentNode && this.bullet.parentNode.removeChild(this.bullet);}
}

  和坦克一样,都有一个destroy函数,销毁对象。

  ③ 构建AI对象

function createRandomTank(obj) {var obj = obj || {cx: 150, cy: 150, color:"#ECFF0B", bColor:"#ECFF0B", speed: 1, container: backF};var rTank = new Tank(obj);rTank.init(String(randomTank));rTank.shooterTimer = null;rTank.shooterTimer = setInterval(function(){if(Math.random() > 0.8){rTank.shooter();   }}, 200);rTank.moveTimer = null;rTank.moveTimer = setInterval(function(){if(Math.random() > 0.4){var ang = Math.PI * 2 * Math.random();rTank.move.call(rTank, ang);}}, 1200);tanks[randomTank] = rTank;randomTank++;
}

  机器人是个麻烦的东西,这块虽然不难,销毁他们的时候费了不少力气~~~主要是那么timer要跟着一起销毁。

  ④ 构建对象说明

tanks[0] = new Tank({cx: 50, cy: 220, color:"red", bColor:"red"});
tanks[0].init('0', {keySet:debug_keySet[0]
});

  这里需要说明一下,只要init后面加了第二个参数,就是调试模式,也就是说键盘是可以控制运行的。

  设置了一个全局变量

                //a   w   d  s   j      ←   ↑   →  ↓   p
debug_keySet = [[65, 87, 68, 83, 74], [37, 38, 39, 40, 80]];

3. socket这块

  整个平台信息的交互就是以他为核心,socket这个东西还算比较新,所以学习的时候也没找到太多的资料,只能对着w3c的一些文档边试边做。

var socket;
function ws_init() {var host = "ws://192.168.86.1:1111/";// var host = "ws://202.114.20.79:1111/";try {socket = new WebSocket(host);logMsg('WebSocket - status '+socket.readyState);socket.onopen    = function(msg) { logMsg("Welcome - status "+this.readyState); send('display'); };socket.onclose   = function(msg) { logMsg("Disconnected - status "+this.readyState); };socket.onmessage = function(msg) { //.... };} catch(ex) {logMsg(ex);}
}
function send(msg) {try {socket.send(msg + '=');} catch(ex) {logMsg(ex);}
}

  socket在前端部分是非常简单的,就是三个事件onopen, onclose, onmessage来驱动,重点还是后台操作,真心麻烦!

后台部分

后台用的是php,本来打算使用nodeJS,不是十分熟练,24个小时的赛制花太长时间去学习也不现实,所以就用了比较熟悉的php来建立socket连接,还算成功吧。

这个部分以后有时间说。先碎觉~~

最后,别忘了这个DEMO哦, http://qianduannotes.sinaapp.com/3dtank/html/index.html

【屌丝之作】3D遥控坦克大战相关推荐

  1. 3D坦克大战游戏源码

    3D坦克大战游戏源码,该游戏是基于xcode 4.3,ios sdk 5.1开发.在xcode4.3.3上完美无报错.兼容ios4.3-ios6.0 ,一款ios平台上难得的3D坦克大战游戏源码,有2 ...

  2. Unity项目 - 坦克大战3D TankBattle

    目录 游戏原型 项目演示 绘图资源 代码实现 技术探讨 参考来源 游戏原型 游戏玩法:在有界的战场上,玩家将驾驶坦克,代表绿色阵营,与你的队友一起击溃红蓝阵营的敌人,在这场三方大战中夺得胜利! 操作指 ...

  3. js版 3D坦克大战 V0.5

    欢迎体验js版的 3D坦克大战 V0.5 测试地址:http://121.199.29.66:88/. 目前只支持新版本的的chrome浏览器,有时同时进入的玩家较多,暂没有分房间,导致偶尔会较卡,请 ...

  4. ava联网3D坦克大战(网络编程)2020

    .游戏效果 Java网络编程联机3D坦克大战 在这里插入图片描述 在这里插入图片描述 二.游戏涉及知识 服务器端运用了 IO.线程.网络.面向对象.异常 的内容, 客户端使用 unity3d引擎进行开 ...

  5. unity学习3D坦克大战(六)

    Unity 3D坦克大战案列学习(五) 实现相机视野的跟随 using UnityEngine; using System.Collections; /// <summary> /// 控 ...

  6. unity学习3D坦克大战(一)

    Unity 3D坦克大战案列学习(一) 实现坦克移动和转向 using UnityEngine; using System.Collections; public class TankMovement ...

  7. unity学习3D坦克大战(四)

    Unity 3D坦克大战案列学习(四) 实现控制特效存在的时间 using UnityEngine; using System.Collections; /// <summary> /// ...

  8. unity学习3D坦克大战(五)

    Unity 3D坦克大战案列学习(五) 实现坦克的生命值和伤害机制 using UnityEngine; using System.Collections; using UnityEngine.UI; ...

  9. 小白学习Unity 3D做经典游戏坦克大战日常

    老师 | Trigger 学习者 |小白 出品 | Siki 学院 Hello,小伙伴们.接下来小白跟Trigger老师做一款2D游戏坦克大战.从素材.代码到场景和UI的游戏开发.小白把日常遇到的问题 ...

最新文章

  1. 【廖雪峰python入门笔记】for循环
  2. linux服务器性能监控命令汇总之iostat命令(三)
  3. 服务器传感器不显示,服务器传感器不显示
  4. linux最常用的20条命令
  5. linux信号学习02
  6. django-后台传图0912
  7. 我求求你了,GC日志打印别再瞎配置了
  8. QT中PRO文件写法
  9. NLP学习—7.CNN与TextCNN
  10. JavaScript = TypeScript 入门
  11. 北斗导航 | BDS RTK高精度定位算法在形变检测中的应用(算法原理讲解)
  12. python opencv 获取图片清晰度
  13. R语言使用epiDisplay包的roc.from.table函数可视化临床诊断表格数据对应的ROC曲线并输出新的诊断表(diagnostic table)、输出灵敏度、1-特异度、AUC值等
  14. centos:/usr/bin/perl is needed by mysql-community-server
  15. CAD梦想画图中的“绘图工具——圆弧”
  16. java所用到的英语单词_JAVA常用英语单词
  17. FANUC机器人动作指令的定位类型FINE和CNT详解
  18. linux系列(七):shell编程、shell概念、ssh协议概念、执行shell文件的三种方式
  19. android立体3D效果_Android实现八大行星绕太阳3D旋转效果
  20. 第四章 JavaWeb CSS入门 核心基础 基础形式 + 选择器

热门文章

  1. 关于“无穷”的概念---数学笔记“无穷”
  2. Jquery中AJAX参数详细列表
  3. PAT 甲级 1157 Anniversary
  4. 计算机电缆的表示方式,各种电缆型号的表示方法
  5. 微信小程序音乐播放列表
  6. 04、江苏专转本(专业课笔记)第四章、计算机网络与因特网
  7. 缺失数据填补基础方法(1)——k-Nearest Neighbors (kNN) 填补
  8. 单片机c语言报错_asm啥意思,SPMC75系列单片机地C和ASM( - 控制/MCU - 电子发烧友网...
  9. 正则环视 php,正则基础之 环视 Lookaround
  10. Win10中找不到gpedit.msc