用javascript写星际飞机大战游戏
在github里看到了个不错的脚本游戏,决定亲自动手来写,效果如下

下面是代码的思路分享
把整个代码理解消化确实不容易,但是如果你坚持看完相信你一定会有收获
如果没兴趣可以直接点击下面的链接 复制代码 开玩:
http://www.cnblogs.com/demonxian3/p/6241755.html
1丶首先准备好素材
游戏的元素有:飞机 敌机 子弹 背景 暂停

素材的大小可以通过drawImage()来改变其大小,因此不需要太纠结素材多少像素
创建一个html文件 和一个js文件
然后开始编辑该html文件
2.写一个画布:
<canvas id="canvas" width=500 height=500 style="border:1px solid #c3c3c3"></canvas>
3.获取画布对象
canvas = document.getElementById('canvas')
cxt = canvas.getContext('2d');
4.设置画布属性
var boxx=0 var boxy=0 var boxwidth=500 var boxheight=500
**************************画飞机****************************
5.声明飞机相关的变量
飞机横坐标 纵坐标 宽度 高度 这些都是为下面的drawImage做准备的
var planex; var planey; var planewidth=60; var planeheight=60; var planeImage = new Image(); planeImage.src="data:images/hero.jpg"; //引入图片
6.布置飞机初始位置
planex = (boxwidth - planewidth) / 2 //画布的中央 planey = boxheight - planeheight //画布的底端
因为这里的坐标(x,y)指的是飞机左上角的坐标,因此需要把飞机的长度算上
7.画出飞机
有了坐标和宽高就可以把飞机画出来了
cxt.drawImage(planeImage,planex,planey,planewidth,planeheight);
现在可以打开网页测试下,看看飞机是否画出来了,
如果没有画出来,那么请别灰心,耐心的查一下有什么错误的地方
如果成功显示出飞机了那么go on!
飞机画出来了但是飞机不会动
那么怎么能让飞机动呢?
改变其坐标!
那么什么时候动呢?
按下键盘上的 ↑ ↓ ← → 键的时候
我们知道键盘有个事件驱动 onkeydown
而这个事件驱动有个属性keycode
用这个属性可以绑定上下左右键对应的函数
如下可以看到对应的keycode码

下面是四个我们需要的按键的对应码
左 : 37
上 : 38
右 : 39
下 : 40
光有事件驱动onkeydown还不够,我们还需要实时监听事件的发生
说的通俗点就是 你在任意时刻去按键盘 程序都能够及时响应
下面这个函数就可以帮我们实时监听事件
addEventListener()函数
语法
var sp=0;
body.addEventListener('keydown',function (event){
switch(event.keyCode){
case 37 : if(planex>boxx){sp=8}else{sp=0}planex-=sp;break;
case 38 : if(planey>boxy){sp=8}else{sp=0}planey-=sp;break;
case 39 : if((planex+planewidth)<boxwidth){sp=8}else{sp=0}planex+=sp;break;
case 40 : if((planey+planeheight)<boxheight){sp=8}else{sp=0}planey+=sp;break;
default:break;
}
},false)
到这里 你可以测试一下飞机是否可以动起来了
当然我会直接告诉你结果----不能动!!
因为上面的事件监听改变的只是飞机的坐标,但是图片还在原地
为了让图片跟着坐标动起来,我们需要写一个函数
9.更新飞机图片位置函数
function drawplane(){
cxt.clearRect(boxx,boxy,boxwidth,boxheight); //清除所有就元素
cxt.drawImage(planeImage,planex,planey,planewidth,planeheight); //重新画出飞机
}
var fps //其实只是用来调飞机流畅度
var gameTimmer = setInterval (run,1000/fps); //gameTimer是游戏的总驱动计时器
function run(){ //drawplane函数自动运行
drawplane();
}
**************************画子弹****************************
10.设置子弹的相关变量 也是为drawImage函数的五个参数所做准备
var bulletx; var bullety; var bulletwidth=10; var bulletheight=10; var bulletImage=new Image(); bulletImage.src="data:images/bullet.png"
11.存放子弹的弹夹-----数组
用数组来存放子弹方便我们访问每个子弹对象
var herobullet; //用来表示单个子弹 var allbullets = new Array(); //用来表示所有子弹
12.设置子弹初始位置
我们希望 每颗子弹的起始位置是随着飞机而改变的 因此把飞机的变量引进来
bulletx=planex+planewidth/2 bullety=planey+bulletheight
13.声明子弹的构造函数、
这部分有点难理解 也是本代码的难点
下面声明的构造函数是用来制作子弹的
function bullet(x,y){
this.x=x; //子弹横坐标
this.y=y; //子弹纵坐标
this.islive=true; //子弹存活属性
this.timmer=null; //子弹计时器 用来使得子弹自己运动
this.run = function run(){ //子弹的运动方法
if(this.islive==false||this.y<-10){ //判断子弹是否存活或出界
clearInterval(this.timmer); //停止运动
this.islive=false;
}else{
this.y-=20 //让子弹往上飞
}
}
}
14.生产子弹
有了做子弹的秘方 那么就可以开始制造子弹了
在这里可以使用到我们之前定义的数组存放每颗子弹
function producebullet(){
herobullet = new bullet(bulletx,bullety); //生产子弹
allbullets.push(herobullet); //存放子弹
var timmer = setInterval("allbullets[" + (allbullets.length-1) +"].run()" , 50); //设置子弹子弹运行 这里用到eval可以将字符变为有效方法
allbullets[allbullets.length-1].timmer=timmer; //将自动运行的子弹方法赋予到子弹的属性
}
15.画出子弹
同飞机的道理相同:光改变坐标是看不出效果,还需要把图片位置也更新了
function drawbullet(){
for (var i=0;i<allbullets.length;i++){ //遍历每颗子弹
if(allbullets[i].islive){ //如果子弹挂了 就不需要再画出来了
cxt.drawImage(bulletImage,allbullets.x,allbullets.y,bulletwidth,bulletheight);
}
}
}
16.让drawbullet函数自动运行
然后把drawbullet函数 放到之前定义的run函数里 不是子弹的方法
function run(){
drawplane();
drawbullet();
}
17.让子弹自动生产
给生产子弹的函数加个计时器
btimmer = setInterval(producebullet,500)
**************************画敌机****************************
我们来回顾下画子弹的步骤
设置相关属性 -> 确定初始坐标 -> 子弹构造函数 -> 生产子弹 -> 画出子弹 -> 自动生产和绘画
画敌机的步骤和上面的步骤是一样的
但是有个不同的点 那就是敌机初始的横坐标应该是随机的 而纵坐标都是0 (顶部位置)
说到随机 Math.random()函数 是不可以缺少的
但这个只能产生0~1的随机数
因此 Math.random*500 范围就是0~500范围
最后四拾伍入 Math.ceil(Math.random*500);
18.设置敌机的相关属性
var enemyx;
var enemyy;
var enemywidth=30
var enemyheight=30
var allenemys = new Arr(); //和子弹一样 数组用来存放所有敌机
var heroenemy; //用来表示其中单个敌机
var enemyImage= new Image();
enemyImage.src="data:images/enemy.png"
19.敌机构造函数
//构造函数
//下面基本上和子弹差不多 就不解释了
function enemy(x,y){ this.x=x; this.y=y; this.islive=true; this.timmer=null; this.run = function run(){ if (this.islive==false||this.y>boxheight){ clearInterval(this.timmer); this.islive=false; }else{ this.y+=2.5; } } }
20生产敌机
//生产随机位置的敌机
function produceenemy(){
enemyx=Math.ceil(Math.random()*500); //产生随机初始位
enemyy=33; //在画布顶端产生敌机
heroenemy = new enemy(enemyx,enemyy); //生产敌机
allenemys.push(heroenemy); //加入数组
var timmer = setInterval("allenemys[" + (allenemys.length-1) + "].run()"); //启动run函数并使其自动运行
allenemys[allenemys.length-1].timmer=timmer; //run函数赋予在enemy属性
}
21画出敌机
//画出敌机
function drawenemy(){
for (var i=0;i<allenemys.length;i++){
if(allenemys[i].islive){
cxt.drawImage(enemyImage,allenemys[i].x,allenemys[i].y,enemywidth,enemyheight)
}
}
}
22自动生产敌机 更新敌机
最后把 drawenemy 加入run函数里 给produeenemy 加个计时器
function run(){
drawplane();
drawbullet();
drawenemy();
}
etimmer = setInterval(produceenemy,800);
**************************击中敌机****************************
飞机 敌机 子弹 都画好了 而且都可以动起来了 , 现在来写子弹碰到敌机时敌机消失的规则

上图可以清晰的看出子弹击中敌机的范围
击中条件:
bulletx + bulletwidth > enemyx
bulletx < enemyx + enemywidth
bullety < enemyy + enemyheight
function checkbullet{
for(var i=0;i<allenemys.length;i++){ //遍历敌机
if (allenemys[i].islive){
var e = allenemys[i]; //获取敌机对象
}
for(var j=0;j<allbullets.length;j++){ //遍历
if(allbullets[j].islive){
var b = allbullets[j];
if(b.x+b.width>e.x&&b.x<e.x+e.width&&b.y<e.y+e.height){ //这里使用到上面的规则
b.islive=false; //在构造函数里只要islive的属性为假 就会停止run函数的计时器
e.islive=false; //因此子弹和敌机相关计时器都被clear掉了
score+=100; //加分
}
}
}
}
}
**************************击中我机****************************
我机的死亡的规则:

击中条件:
enemyx+enemywidth > planex
enemyx < planex + planewidth
enemyy + enemyheight > planey
function checkenemy(){
for(var i=0;i<allenemys[i].length;i++){
if(allenemys[i].islive){
var e = allenemys[i];
if(e.x+e.width > planex && e.x < planex + planewidth && e.y + e.height > planey){
e.islive=false;
stop();
}
}
}
}
**************************停止一切****************************
然后把stop函数写出来
function stop(){
clearInterval(btimmer); //停止生产子弹
clearInterval(etimmer); //停止生产敌机
clearInterval(gameTimmer); //停止游戏
allenemys.length=0; //初始化
allbullets.length=0; //初始化
show.innerHTML=score; //统计总分
score=0;
}
**************************启动一切****************************
然后把checkbullet函数 和checkenemy函数 放到游戏驱动run 里头
function run(){
drawplane(); //画飞机
drawenemy(); //画敌机
drawbullet(); //画子弹
checkbullet(); //检查子弹
checkenemy(); //检查敌机
drawscore(); //实时加分
}
最后设置一下加分相关的标签
这个标签用来显示当前分数
<div style="position: absolute;top: 90px;left: 30px;
font-weight: bold;font-size: 40px;color:cornflowerblue">
<span id="show">0</span></div>
获取标签
show = document.getElementById('show');
实时计分
function drawscore(){
show.innerHTML=score;
}
当然还可以加一些小细节,比如暂停按钮 弹出窗口统计得分
还可以玩好玩的,比如飞机无敌 无限子弹 超级子弹 无敌并排子弹 总之你自己想怎么改都行
源代码:http://www.cnblogs.com/demonxian3/p/6241755.html
用javascript写星际飞机大战游戏的更多相关文章
- 用Javascript模拟微信飞机大战游戏
最近微信的飞机大战非常流行,下载量非常高. 利用JS进行模拟制作了一个简单的飞机大战[此源码有很多地方可以进行重构和优化] [此游戏中没有使用HTML5 任何浏览器都可以运行]. 效果图: 原理:利用 ...
- android:怎样用一天时间,写出“飞机大战”这种游戏!(无框架-SurfaceView绘制)
序言作为一个android开发人员,时常想开发一个小游戏娱乐一下大家,今天就说说,我是怎么样一天写出一个简单的"飞机大战"的. 体验地址:http://www.wandoujia. ...
- 基于Cocos2d-x-1.0.1的飞机大战游戏开发实例(下)
在飞机大战游戏开发中遇到的问题和解决方法: 1.在添加菜单时,我要添加一个有背景的菜单,需要在菜单pMenu中添加一个图片精灵,结果编译过了但是运行出错,如下图: 查了很多资料,调试了很长时间,整个人 ...
- 基于Cocos2d-x-1.0.1的飞机大战游戏开发实例(中)
接<基于Cocos2d-x-1.0.1的飞机大战游戏开发实例(上)> 三.代码分析 1.界面初始化 bool PlaneWarGame::init() { bool bRet = fals ...
- 基于Cocos2d-x-1.0.1的飞机大战游戏开发实例(上)
最近接触过几个版本的cocos2dx,决定每个大变动的版本都尝试一下.本实例模仿微信5.0版本中的飞机大战游戏,如图: 一.工具 1.素材:飞机大战的素材(图片.声音等)来自于网络 2.引擎:coco ...
- 11.pygame飞机大战游戏整体代码
主程序 # -*- coding: utf-8 -*- # @Time: 2022/5/20 22:26 # @Author: LiQi # @Describe: 主程序 import pygame ...
- 一、利用Python编写飞机大战游戏-面向对象设计思想
相信大家看到过网上很多关于飞机大战的项目,但是对其中的模块方法,以及使用和游戏工作原理都不了解,看的也是一脸懵逼,根本看不下去.下面我做个详细讲解,在做此游戏需要用到pygame模块,所以这一章先进行 ...
- Canvas:飞机大战 -- 游戏制作
Canvas:飞机大战 最开始我们要初始化信息,我们有五个状态:游戏封面,加载状态,运行状态,游戏暂停,游戏结束. 我们还需要 得分--score,生命--life. var START = 1;/ ...
- web版canvas做飞机大战游戏 总结
唠唠:两天的时间跟着做了个飞机大战的游戏,感觉做游戏挺好的.说是用html5做,发现全都是js.说js里一切皆为对象,写的最多的还是函数,都是函数调用.对这两天的代码做个总结,希望路过的大神指点一下, ...
随机推荐
- redux-amrc:用更少的代码发起异步 action
很多人说 Redux 代码多,开发效率低.其实 Redux 是可以灵活使用以及拓展的,经过充分定制的 Redux 其实写不了几行代码.今天先介绍一个很好用的 Redux 拓展-- redux-amrc ...
- 对抗假人 —— 前后端结合的 WAF
前言 之前介绍了一些前后端结合的中间人攻击方案.由于 Web 程序的特殊性,前端脚本的参与能大幅弥补后端的不足,从而达到传统难以实现的效果. 攻防本为一体,既然能用于攻击,类似的思路同样也可用于防御. ...
- 记一个mvn奇怪错误: Archive for required library: 'D:/mvn/repos/junit/junit/3.8.1/junit-3.8.1.jar' in project 'xxx' cannot be read or is not a valid ZIP file
我的maven 项目有一个红色感叹号, 而且Problems 存在 errors : Description Resource Path Location Type Archive for requi ...
- CSS 3学习——transition 过渡
以下内容根据官方规范翻译以及自己的理解整理. 1.介绍 这篇文档介绍能够实现隐式过渡的CSS新特性.文档中介绍的CSS新特性描述了CSS属性的值如何在给定的时间内平滑地从一个值变为另一个值. 2.过渡 ...
- Linux基础介绍【第二篇】
远程连接Linux的原理 SHH远程连接介绍 当前,在几乎所有的互联网企业环境中,最常用的Linux提供远程连接服务的工具就是SSH软件,SSH分为SSH客户端和SSH服务端两部分.其中,SSH服务端 ...
- VS2010 release编译下进行调试,“当前不会命中任何断点,还没有为文档加载”问题解决方案
在release模式下调试程序,经常出现"当前不会命中任何断点,还没有为文档加载"的问题,可尝试以下方法: 1. 属性 → 配置属性 → C/C++ → 常规 → 调试信息格式:选 ...
- ASP.NET Core MVC 中的 [Controller] 和 [NonController]
前言 我们知道,在 MVC 应用程序中,有一部分约定的内容.其中关于 Controller 的约定是这样的. 每个 Controller 类的名字以 Controller 结尾,并且放置在 Contr ...
- linux下mono,powershell安装教程
1简介 简单来说pash就是bash+powershell 2官网 https://github.com/Pash-Project/Pash 3下载fedora20---lxde桌面---32位版. ...
- Linux1 在Linux(CentOS)上安装MySql详细记录
前记: 毕业两年了,前两天换了份工作,由以前的传统行业跳到了互联网行业.之前的公司一直在用WinServer2003+Tomcat+SqlServer/Oracle这套部署环境.对于Linux+To ...
- 淘宝UWP中的100个为什么
从淘宝UWP第一版发布到现在,已经有十个月了,期间收到了用户各种各样的反馈,感谢这些用户的反馈,指导我们不断的修正.完善应用.但是也有一部分需求或建议,由于资源或技术的限制,目前确实无法做到,只能对广 ...