手写坦克大战联网版(持续更新)
用到腳本語言
??????????? javascript es5 es6 es7
??????????? node
??????????????? | ? models
???????????????????????? | ????? socket.io
??????????? mysql
先了解下目錄結構
前端
?????? css:游戲的一些樣式
?????? js:動態腳本 觸碰系統等】
?????? index.html 網頁腳本
?????? images 圖片 ???????
后臺
?????? node_modules? 模塊
?????? main.js? 主啟動
搭建服務
?服務器部署
我使用的是nginx?? node部署到服務器 需要 反向代理接口
server服務
listen?? 監聽端口號80
location/api? 監聽到/api的參數就將值代理給3000端口號
準備工作
brick磚塊
explose爆炸圖
my坦克圖
bullet子彈圖
分享圖片
下載素材當前無效過后我會搭建素材頁面的
地圖計算
所有素材 模型 大小 32 * 32
橫向14 * 32??
豎向18 * 32
<canvas id = 'ctx' width = '448' height = '576'></canvas>首先我們先獲取canvas
let c = document.getElementById("ctx"); var ctx=c.getContext("2d");接下來創建繪制圖片系統
drawCreate = async (url,x,y,w,h,id) =>{ //繪制圖片let image = new Image();let app = await new Promise((resolve)=>{image.src = url;image.onload = function(){resolve(image);}}).then((image)=>{if(id == 0){_1ps = {w:w,h:h,x:x,y:y}}ctx.drawImage(image,x,y,w,h);});return image; }改繪制圖片方法有6個參數? url為圖片路徑? x y 為坐標 w h 為圖片 大小 id 0,1,2?? 0為1p玩家?? 1為2p玩家? 2為地圖繪制也就是素材
移動系統
//添加移動事件 let move = async (url,obj,type,value) =>{ //玩家移動方法ctx.clearRect(obj.x,obj.y,obj.w,obj.h);if(type == 1){if(obj.up == undefined && value < 0){ //判斷是否是首次加載圖片let item = await drawCreate(url,obj.x,obj.y + value,obj.w,obj.h,0);return item;}if(obj.down == undefined && value > 0){if(type == 1){let item = await drawCreate(url,obj.x,obj.y + value,obj.w,obj.h,0);return item;}}}else{if(obj.right == undefined && value > 0){let item = await drawCreate(url,obj.x + value,obj.y,obj.w,obj.h,0);return item;}if(obj.left == undefined && value < 0){let item = await drawCreate(url,obj.x + value,obj.y,obj.w,obj.h,0);return item;}}if(type == 1){ctx.drawImage(url,obj.x,obj.y += value ,obj.w,obj.h);return url;}else{ctx.drawImage(url,obj.x += value,obj.y ,obj.w,obj.h);return url;} } document.body.onkeydown = async (event) =>{let item = "";switch(event.keyCode){case 65: //a后if(mapScope(_1ps.x - 4,0,32,28))return;item = await move(_1ps.left || _1p.left,_1ps,0,-4);_1ps.left = item;break;case 68: //d前if(mapScope(_1ps.x + 4,0,32,28)))return;item = await move(_1ps.right || _1p.right,_1ps,0,4);_1ps.right = item;break;case 83: //s下if(mapScope(_1ps.y + 4,1,32,28)))return;item = await move(_1ps.down || _1p.down,_1ps,1,4);_1ps.down = item;break;case 87: //w上if(mapScope(_1ps.y - 4,1,32,28)))return;item = await move(_1ps.up || _1p.up,_1ps,1,-4);_1ps.up = item;break;} }范圍限制
let mapScope = (value,type,w,h) => { //檢測是否超出地圖限制 type = 0 左右地圖限制 type = 1 上下地圖限制if(type == 0){if(value < 0 || value > 448 - w)return true;}else{if(value > 576 - h || value < 0)return true;} }編輯一張地圖
因為先前設置的地圖高度是32*18 寬度是32*14? 我們要創建一個 14*18的二維數組
?
像上面構造玩家一樣構造沒個建筑物 有些不合適 隱藏 需要一個地圖構造器
let level = [ //關卡[[3,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,2,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,2,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,3,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,4,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,5,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,6,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,0,0]] ]地圖構造器
現在地圖控制器設置一個規則 方便創建出來的對象樣式 然后對該規則做一套適配
1p?? 0
2p?? 1
普通磚 ? 2
剛磚? 3
草坪? 4
水池? 5
冰路? 6
修改上面我們改好的loadGame
let loadGame = async () =>{ //加載游戲let item = await drawCreate(_1p.up,32,545,32,32,0);mapCreate(); } let mapCreate = async () => {//地圖構造器 // 1p:1 普通磚:2 剛轉:3 草坪:4 水池:5 冰路:6let s = 0;for(let i = 0;level[levels][i]!=undefined;i++){for(let j = 0;level[levels][i][j]!=undefined;j++){if(level[levels][i][j] > 0){if(level[levels][i][j] >= 1){let item = await drawCreate(matter[level[levels][i][j] - 2],j*32,i*32,32,32);obj.push({ //將所有建筑物的坐標保存到objw:32,h:32,x:j*32,y:i*32,ev:level[levels][i][j],index:s++,el:item,id:createId()})}}}} } let createId = (length = 32)=>{ //創建idlet str = "";let arr = "qwertyuiopasdfghjklmnbcvxzQWERTYUIOPLKJHGFDSAZXCBNM1234567890"for(let i = 0;i<=length;i++){str += arr[Math.round(Math.random() * 61)];}return str; }地圖構造器原理其實很簡單 就是遍歷關卡的數組中以及對應的位置
當前現在雖然地圖制作好了 但是由于沒有觸碰檢測 觸碰磚塊時怪物就會消失? 因此我們還要寫個觸碰檢測
每次移動和子彈發射以及一系列的操作都需要通過觸碰檢測
觸碰檢測
let detection = (x,y,w,h,type) => { //檢測觸碰for(let i = 0;obj[i]!=undefined;i++){if(type == 0){if((y < obj[i].y + 40 && y > obj[i].y) && (x >= obj[i].x - 28 && x <= obj[i].x + 28))return true;}else if(type == 1){if((y < obj[i].y + 28 && y > obj[i].y - 40) && (x >= obj[i].x - 28 && x <= obj[i].x + 28))return true;}else if(type == 2){if((y < obj[i].y + 32 && y > obj[i].y - 28) && (x >= obj[i].x - 28 && x <= obj[i].x + 28))return true;}else if(type == 3){if((y < obj[i].y + 32 && y > obj[i].y - 28) && (x >= obj[i].x - 28 && x <= obj[i].x + 28))return true;}} }將該檢測放到移動時
document.body.onkeydown = async (event) => {let item = "";switch(event.keyCode){case 65: //a后if(mapScope(_1ps.x - 4,0,32,28)))return;if(detection(_1ps.x - 4,_1ps.y,32,32,2))return;item = await move(_1ps.left || _1p.left,_1ps,0,-4);_1ps.left = item;break;case 68: //d前if(mapScope(_1ps.x + 4,0,32,28)))return;if(detection(_1ps.x + 4,_1ps.y,32,32,3))return;item = await move(_1ps.right || _1p.right,_1ps,0,4);_1ps.right = item;break;case 83: //s下if(mapScope(_1ps.y + 4,1,32,28)))return;if(detection(_1ps.x,_1ps.y - 4,32,32,1))return;item = await move(_1ps.down || _1p.down,_1ps,1,4);_1ps.down = item;break;case 87: //w上if(mapScope(_1ps.y - 4,1,32,28)))return;if(detection(_1ps.x,_1ps.y + 4,32,32,0))return;item = await move(_1ps.up || _1p.up,_1ps,1,-4);_1ps.up = item;break;case 74: //j子彈createBullet();break;} }接下來我們構造子彈
構造子彈
let createBullet = async (x,y,direction) => { //創建子彈if(disabled == true)return;if(direction == 0){ //上_bullet = await drawCreate(bullet,x + 11,y - 8,8,8);bulletMove(0,x+11,y - 8,8,8);}if(direction == 1){ //下_bullet = await drawCreate(bullet,x + 11,y + 24,8,8);bulletMove(1,x+11,y+24,8,8)}if(direction == 2){ //右_bullet = await drawCreate(bullet,x + 32,y + 4,8,8);bulletMove(2,x+32,y+4,8,8);} if(direction == 3){ //左_bullet = await drawCreate(bullet,x - 8,y+4,8,8);bulletMove(3,x - 8,y+4,8,8);}disabled = true;setTimeout(()=>{ //子彈設置0.5秒一發disabled = false;},500) }當然 現在這些子彈還是不會動的
稍后我們修改讓其動起來
會動的子彈
function bulletMove(d,x,y,w,h){ //子彈移動 方向 坐標 大小let value = d == 0 || d == 3?-4:4;if(disabled == true)return;let move = setInterval(()=>{if(d == 0 || d == 1){ctx.clearRect(x,y,w,h);if(mapScope(y + value,1)){clearInterval(move);return false;}ctx.drawImage(_bullet,x,y += value,w,h);}else{ctx.clearRect(x,y,w,h);if(mapScope(x + value,0)){clearInterval(move);return false;}ctx.drawImage(_bullet,x += value,y,w,h);}},20); }子彈觸碰
let bulletDetection = (d,x,y,w,h) =>{ //子彈觸碰檢測for(let i = 0;obj[i]!=undefined;i++){if(d == 0){if((y - 36 <= obj[i].y && y + 8 >= obj[i].y) && (x >= obj[i].x - 8 && x <= obj[i].x + 28))return true;}else if(d == 1){if((y >= obj[i].y - 8 && y <= obj[i].y + 8) && (x >= obj[i].x - 8 && x <= obj[i].x + 28))return true;}else if(d == 2){if((x >= obj[i].x - 8 && x <= obj[i].x + 32) && (y >= obj[i].y - 8 && y <= obj[i].y + 32))return true;}else if(d == 3){if((x >= obj[i].x - 8 && x <= obj[i].x + 32) && (y >= obj[i].y - 8 && y <= obj[i].y + 32))return true;}} }?
let bulletDetection = (d,x,y,w,h) =>{ //子彈觸碰檢測for(let i = 0;obj[i]!=undefined;i++){if(d == 0){if((y - 36 <= obj[i].y && y + 8 >= obj[i].y) && (x >= obj[i].x - 8 && x <= obj[i].x + 28)){if(touchBulletElement(obj[i]))return true;}}else if(d == 1){if((y >= obj[i].y - 8 && y <= obj[i].y + 8) && (x >= obj[i].x - 8 && x <= obj[i].x + 28)){let bullet = {x:x,y:y,}if(touchBulletElement(obj[i],bullet))return true;}}else if(d == 2){if((x >= obj[i].x - 8 && x <= obj[i].x + 32) && (y >= obj[i].y - 8 && y <= obj[i].y + 32)){if(touchBulletElement(obj[i],bullet))return true;}}else if(d == 3){if((x >= obj[i].x - 8 && x <= obj[i].x + 32) && (y >= obj[i].y - 8 && y <= obj[i].y + 32)){if(touchBulletElement(obj[i],bullet))return true;}}} }判斷當前打到的道具是什么
let touchBulletElement = (obj,bullets,d) =>{ //判斷子彈觸碰到的是什么元素switch(obj.ev){case 2:attackDirection(obj,bullets,d)break;case 3: //剛轉attackDirection(obj,bullets,d)break;case 6: //草地ctx.clearRect(obj.x,obj.y,obj.w,obj.h);ctx.drawImage(obj.el,obj.x,obj.y,obj.w,obj.h);return false;case 5: //水池ctx.clearRect(obj.x,obj.y,obj.w,obj.h);ctx.drawImage(obj.el,obj.x,obj.y,obj.w,obj.h);return false;}return true; }修改這些后需要將創建子彈套上觸碰
接下來該判斷子彈打中了什么元素了
在此我們來分析一下
? 每塊磚都要一分為四? 也就是說當前x ~ 16? y ~ 16為第一塊磚? x + 16 ~ x + 32 ~ y ~ y + 16 第二塊磚
?????????????????????????????????????????????????????????????????? x ~ 16 y + 16 ~ y + 32第三塊磚? x + 16 y + 16 ~ y + 32 最后一塊磚
在bulletDetection嵌套檢測攻擊子彈函數
打中后清空磚塊
let attackDirection = (obj,bullets,d) =>{ //攻擊磚塊ctx.clearRect(obj.x,obj.y,32,32);removeObj(obj.id) } let removeObj = (id) =>{ //刪除對象for(let i = 0;obj[i]!=undefined;i++){if(obj[i].id == id)obj.splice(i,1);} }?
?
?
?
?
總結
以上是生活随笔為你收集整理的手写坦克大战联网版(持续更新)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 数仓建模(维度建模)
- 下一篇: nginx转发配置