手写坦克大战联网版(持续更新)
用到脚本语言
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);}
}
手写坦克大战联网版(持续更新)相关推荐
- 有手就能学会- C语言零基础手写坦克大战
1.2 项目介绍 2.1. 项目需求 实现1款和经典的<90坦克大战>一样的游戏,任务是消灭敌对坦克,保护己方领地.防止敌方打破你的老窝围墙而把你的鹰打坏. 2.2. 学习目标 回顾经 ...
- android studio写坦克大战代码_GitHub 项目推荐:俄罗斯小游戏、Markdown 幻灯片、头像生成器、Logo 制作、坦克大战...
今天跟大家分享一下,过去几天在各大社交平台分享的一些开源项目. 本周新增了粉丝推荐环节,如果你有发现优质的开源项目,欢迎在公众号或其它平台私信推荐,我们会不定期筛选推送. 小编推荐 俄罗斯方块小游戏 ...
- javascript写坦克大战
无意间浏览到别人写的js坦克大战,这是我这段时间看过最复杂的代码了(相对而言),作者博文链接:http://blog.whlcsj.com/js-tankwar.html github链接:https ...
- Unity 2D手游——坦克大战 C#
需要下载项目的朋友,请打开CSDN链接:Unity2D坦克大战项目工程 本项目涉及到的功能: 1.UI部分: a .游戏开始界面UI b.主场景UI c.游戏胜利界面UI ...
- 世界崩塌前要写下游戏心得(持续更新)
前言 有一部纪录片中问道,你为什么看电影?有人回答"想要体验不同的人生","可以看到丰富的故事,增加人生阅历","因为电影特效好看,很刺激" ...
- 在android view中写坦克大战
我是把以前写在java里的代码直接移植到android上了(后面贴的代码有比较的部分) 只改了画笔的对象,和控制方式 代码大致思路 1.画 我们要画出坦克,炮弹,爆炸效果 1.1画坦克 1.1.1画竖 ...
- 《方圆·齐物》手游项目初期总结(持续更新)
游戏仍在开发中,还有很多功能未实现(试玩地址:方圆·齐物) 游戏功能模块 通用模块 数据配置 资源加载 用户数据操作 场景异步加载 UI界面数据的显示与更新 道具系统 背包系统 任务系统 邮件系统 消 ...
- 从零开始用js手写飞机大战全过程(附源码)
plane game 前言 此文章帮助初学者学习制作一个简单小游戏 目标 利用css,html,js制作出飞机大战的简略版 前置准备 1. 绝对定位与相对定位 这里除了背景都设置为绝对定位,使飞机和敌 ...
- python飞机大战联网版_Python 飞机大战搞怪版本
python 飞机大战搞怪版本 (飞机为迷你亚索,外星人为迷你小诺手,由于时间关系和图片素材较难寻找,仅仅做了简易版,没有贴上背景图片.由于篇幅原因,对于函数讲解较为简略,可以自行搜索相应函数的用法) ...
最新文章
- 2018-3-18 中国计算机之母-- 夏培肃
- ios玩全民奇迹不显示服务器,全民奇迹关于IOS充值游戏物品不到账公告
- Django 1.10中更新modules同步数据库
- boost::advance用法的测试程序
- R语言心得-分词包的安装
- 文献记录(part9)--A biclustering-based method for market segmentation using customer pain points
- jvm与非jvm语言优劣_都灵JVM编程语言:使用ANTLR构建高级词法分析器
- 西安4年java多少时间_西安学习java一般要多久
- ORA-12519: TNS:no appropriate service handler found 解决方法
- 8年前端开发的知识点沉淀(不知道会多少字,一直写下去吧,)
- ubuntu18.04下hadoop安装与集群配置
- 材料的构成 —— 塑料
- 多个Excel文件合并成一个文件
- 19个程序员接私活平台汇总升级版!你有技术就有钱!
- 软件工程:状态,行为,事件
- pop,oop,aop编程思想
- 什么是JavaScript异步编程?
- R语言 AHP层次分析法——如何验证矩阵一致性
- basler恢复出厂设置_bios恢复出厂设置
- windows sc使用方法之一
热门文章
- java+ee+网页修改数据库_基于jsp的作业批改-JavaEE实现作业批改 - java项目源码
- java8双层for循环,Java8处理List的双层循环问题
- 蓝牙遥控器 – 将手机模拟为键盘、鼠标、翻页笔、遥控器
- Python---自动生成二维码
- 【毕业设计】Java ssm校园兼职系统 大学生兼职系统
- 编码器测距离使用外部中断计脉冲
- office 和 wps 对于超链接的处理浅析
- 计算机硬件组成学情分析,初中信息技术_探究计算机的硬件组成教学设计学情分析教材分析课后反思.doc...
- Excel工作表中最常用的10个经典技巧
- python处理大数据量json数据的方法_python-利用json模块处理json数据几个函数总结...