【JavaScript游戏开发】使用HTML5+Canvas+JavaScript 封装的一个超级马里奥游戏(包含源码)
这个游戏基本上是建立在JavaScript模块化的开发基础上进行封装的,对游戏里面需要使用到的游戏场景进行了封装,分别实现了Game,Sprite,enemy,player, base,Animation 等游戏类,后续代码还可以继续优化,最终实现的效果如下:
其他的所有核心代码已经开源:https://github.com/xiugangzhang/SuperMarioGame
在线预览游戏效果:
http://htmlpreview.github.io/?https://github.com/xiugangzhang/SuperMarioGame/blob/master/index.html
感兴趣的朋友可以对其进行继续优化,加上后续的其他功能!
其中游戏Game类代码如下:
// 完成Game类的封装
function Game(cfg) {
for (var attr in cfg) {
// 这里的this指的就是Game的对象
this[attr] = cfg[attr];
}
}
// 定义原型方法和属性
Game.prototype = {
constructor: Game,
// 游戏画布的初始化(这个是游戏画布的默认宽度和高度)
width: 640,
height: 480,
// 画布canvas和绘图句柄gc(在构造函数中已经完成了初始化)
canvas: null,
gc: null,
// 帧速率和时间间隔
FPS: 40,
sleep: 0,
// 游戏中的精灵
sprites: null,
// 游戏中的运动的背景
skyOffset: 0,
grassOffset: 0,
treeOffset: 0,
nearTreeoffset: 0,
TREE_VELOCITY: 20,
FAST_TREE_VELOCITY: 40,
SKY_VELOCITY: 8,
GRASS_VELOCITY: 75,
lastTime: 0,
lastUpdateFPS: 0,
lastUpdateTime: 0,
// 游戏场景的初始化(主要场景参数的初始化处理)
init: function () {
// 直接手动创建canvas元素
this.canvas = document.createElement("canvas");
this.canvas.width = this.width;
this.canvas.height = this.height;
document.body.appendChild(this.canvas);
// 设置我的绘图句柄
this.gc = this.canvas.getContext("2d");
// 初始化键盘的事件
this.initEvent();
// 帧速率不为空,设置我的间隔时间
if (this.FPS) {
this.sleep = Math.floor(1000 / this.FPS);
}
// 当前的精灵(要么是自己, 要么是一个空数组)
this.sprites = this.sprites || [];
// 对每一个精灵完成初始化
for (var i = 0, len = this.sprites.length; i < len; i++) {
this.sprites[i].init();
}
},
// 初始化键盘的事件
initEvent: function () {
// 按下按键
document.addEventListener("keydown", function (ev) {
keyState[ev.keyCode] = true;
console.log(keyState);
}, true);
// 松开按键
document.addEventListener("keyup", function (ev) {
keyState[ev.keyCode] = false;
console.log(keyState);
}, true);
},
// 游戏开始, 就进入到主循环
start: function () {
// this指向的是Game这个对象
var Me = this;
// 记录一下,游戏开始的时间
Me.startTime = Date.now();
// 主循环
this.mainLoop = setInterval(function () {
// 距离上一次间隔的时间
var deltaTime = Me.sleep;
// 在主循环的执行过程中来实现碰撞检测的功能(一直在不断地检测是否发生了碰撞)
Me.run(deltaTime);
}, Me.sleep);
},
// 主循环中需要执行的操作
run: function (deltaTime) {
// 显示当前游戏持续进行的时间(玩家在这个游戏中持续的时间就是他的分数)
var playedTime = Date.now() - this.startTime;
// 在主界面上面显示时间(span标签)
document.getElementById("timeCount").innerHTML = playedTime.toString();
document.getElementById("lifeCount").innerHTML = this.sprites[0].HP.toString();
// 开始碰撞检测
var coll = this.checkCollide();
// 只要coll不为空, 就说明有其他玩家和我发生了碰撞
if (coll) {
// 如果发生敌人和玩家的碰撞, 就结束游戏(有三个生命值)
if (this.sprites[0].HP > 0) {
this.sprites[0].HP--;
}
}
// 我是精灵角色中的第0个角色,直接得到我的生命值并显示
document.getElementById("lifeCount").innerHTML = this.sprites[0].HP.toString();
if (this.sprites[0].HP == 0) {
// 1. 清空主循环中的定时器
clearInterval(this.mainLoop);
alert("Game Over.\n Your score : " + playedTime);
// 2.直接退出程序
return;
}
// 更新画布
this.update(deltaTime);
// 清空画布
this.clear(deltaTime);
// 重绘画布
this.draw(deltaTime);
// 进入主循环之后, 还要不断地处理接收键盘事件
this.handleInput();
},
// 开始实现碰撞的检测, 返回true就表示发生了玩家和敌人的碰撞
checkCollide: function () {
// 1.拿到我的玩家这个对象
var player = this.sprites[0];
// 注意这里是从第一个场景中的人物和我来逐一检测(我是第0个人物, 其他的都是敌人)
for (var i = 1, len = this.sprites.length; i < len; i++) {
var sprite = this.sprites[i];
// 对于游戏场景中的除了自己的其他所有的精灵和我一一进行碰撞检测
var coll = sprite.collideWidthOther(player);
if (coll) {
return coll;
}
}
return false;
},
// 更新精灵的状态
update: function (deltaTime) {
for (var i = 0, len = this.sprites.length; i < len; i++) {
var sprite = this.sprites[i];
// 开始更新每一个精灵的坐标状态(运动状态信息)
sprite.update(deltaTime);
}
},
// 清空画布信息
clear: function () {
// 清空画布
this.gc.clearRect(0, 0, this.canvas.width, this.canvas.height);
var fps = this.caculateFPS();
this.fps = fps;
// 显示帧速率到画布上面
var now = Date.now();
if (now - this.lastUpdateTime > 1000) {
this.lastUpdateTime = now;
this.lastUpdateFPS = fps;
document.getElementById("fps").innerText = this.lastUpdateFPS.toFixed();
}
this.initGameMap();
},
// 绘制背景地图
initGameMap: function () {
var fps = this.fps;
// 实现移动的位移量
this.skyOffset = this.skyOffset < this.canvas.width ?
this.skyOffset + this.SKY_VELOCITY / fps : 0;
this.grassOffset = this.grassOffset < this.canvas.width ?
this.grassOffset + this.GRASS_VELOCITY / fps : 0;
this.treeOffset = this.treeOffset < this.canvas.width ?
this.treeOffset + this.TREE_VELOCITY / fps : 0;
this.nearTreeOffset = this.nearTreeOffset < this.canvas.width ?
this.nearTreeOffset + this.FAST_TREE_VELOCITY / fps : 0;
var sky = ImgCache["sky"],
tree = ImgCache["tree-twotrunks"],
nearTree = ImgCache["smalltree"],
grass = ImgCache["grass"],
grass2 = ImgCache["grass2"];
this.gc.save();
this.gc.translate(-this.skyOffset, 0);
this.gc.drawImage(sky, 0, 0);
this.gc.drawImage(sky, sky.width - 2, 0);
this.gc.restore();
this.gc.save();
this.gc.translate(-this.treeOffset, 0);
this.gc.drawImage(tree, 100, 240);
this.gc.drawImage(tree, 1100, 240);
this.gc.drawImage(tree, 400, 240);
this.gc.drawImage(tree, 1400, 240);
this.gc.drawImage(tree, 700, 240);
this.gc.drawImage(tree, 1700, 240);
this.gc.restore();
this.gc.save();
this.gc.translate(-this.nearTreeOffset, 0);
this.gc.drawImage(nearTree, 250, 240);
this.gc.drawImage(nearTree, 1250, 240);
this.gc.drawImage(nearTree, 800, 240);
this.gc.drawImage(nearTree, 1800, 240);
this.gc.restore();
this.gc.save();
this.gc.translate(-this.grassOffset, 0);
this.gc.drawImage(grass, 0, this.canvas.height - grass.height);
this.gc.drawImage(grass, grass.width - 5,
this.canvas.height - grass.height);
this.gc.drawImage(grass2, 0, this.canvas.height - grass2.height);
this.gc.drawImage(grass2, grass2.width,
this.canvas.height - grass2.height);
this.gc.restore();
},
// 绘制背景滚动的效果
caculateFPS: function (now) {
if (now == undefined) {
now = Date.now();
}
var fps = 1000 / (now - this.lastTime);
this.lastTime = now;
return fps;
},
// 开始重新绘制精灵
draw: function (deltaTime) {
for (var i = 0, len = this.sprites.length; i < len; i++) {
var sprite = this.sprites[i];
// 开始绘制
sprite.draw(this.gc);
}
},
// 游戏中的处理用户的输入
handleInput: function () {
for (var i = 0, len = this.sprites.length; i < len; i++) {
var sprite = this.sprites[i];
// 先判断一下,这个精灵有没有handleInput属性
if (sprite.handleInput) {
// 如果这个精灵有这个属性或者方法的话, 就去调用精灵自己的处理函数
sprite.handleInput();
}
}
}
}
鉴于代码太多,已经将SuperMario的所有核心代码开源:
开源地址:https://github.com/xiugangzhang/SuperMarioGame
【JavaScript游戏开发】使用HTML5+Canvas+JavaScript 封装的一个超级马里奥游戏(包含源码)的更多相关文章
- 高性能动画!HTML5 Canvas JavaScript框架KineticJS
高性能动画!HTML5 Canvas JavaScript框架KineticJS KineticJS是一款开源的HTML5 Canvas JavaScript框架,能为桌面和移动应用提供高性能动画,并 ...
- HTML5 Canvas中实现绘制一个像素宽的细线
正统的HTML5 Canvas中如下代码 ctx.lineWidth = 1; ctx.beginPath(); ctx.moveTo(10, 100); ctx.lineTo(300,100); c ...
- Unity 2D游戏开发高速入门第1章创建一个简单的2D游戏
Unity 2D游戏开发高速入门第1章创建一个简单的2D游戏 即使是如今,非常多初学游戏开发的同学.在谈到Unity的时候.依旧会觉得Unity仅仅能用于制作3D游戏的. 实际上.Unity在2013 ...
- 【JavaScript游戏开发】JavaScript+HTML5封装的苏拉卡尔塔游戏(包含源码)
/** 苏拉克尔塔游戏 * 思路: * 1.棋盘设置:使用HTML5的canvas标签绘制整个棋盘 * 2.点击事件:当页面被点击时,获取点击的x,y像素点,根据此像素点进行判断,再在合适位置绘制黑红 ...
- 【原创】使用HTML5+canvas+JavaScript开发的原生中国象棋游戏及源码分享
目前已经实现的功能: V1.0 : 实现棋子的布局,画布及游戏场景的初始化V2.0 : 实现棋子的颜色改变V3.0 :实现所有象棋的走棋规则V4.0 : 实现所有棋子的吃子功能 GItHub源码下载地 ...
- 自己写的HTML5 Canvas + Javascript五子棋
看到一些曾经只会灌水的网友,在学习了前端之后,已经能写出下载量几千几万的脚本.样式,帮助大众,成为受欢迎的人,感觉满羡慕的.我也想学会前端技术,变得受欢迎呀.于是心血来潮,开始学习前端知识,并写下了这 ...
- 【读书笔记《Android游戏编程之从零开始》】12.游戏开发基础(Canvas 画布)
1.Canvas 画布 画布类 Canvas 封装了图形和图片绘制等内容,此类常用的函数说明如下: drawColor(int color) 作用:绘制颜色覆盖画布,常用于刷屏 参数:颜色值,也可用十 ...
- 使用PhoneGap开发基于Html5应用二:第一个PhoneGap应用:百度
上一篇博文使用PhoneGap开发基于Html5应用一:PhoneGap简单介绍 中我介绍了怎样从phonegap官网上下载源代码并启动第一个应用,今天我们把phonegap的应用略微改一下,让他实现 ...
- 如何实现一个HTTP请求库——axios源码阅读与分析 JavaScript
概述 在前端开发过程中,我们经常会遇到需要发送异步请求的情况.而使用一个功能齐全,接口完善的HTTP请求库,能够在很大程度上减少我们的开发成本,提高我们的开发效率. axios是一个在近些年来非常火的 ...
随机推荐
- iOS:改变UITableViewCell的选中背景色
要改变UITableViewCell选中时的背景色,需要在-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtInde ...
- Unity3D中的Coroutine具体解释
本文太乱,推荐frankjfwang的:全面解析Coroutine技术 Unity中的coroutine是通过yield expression;来实现的.官方脚本中到处会看到这种代码. 疑问: yie ...
- 升级DM5校验
1,将某个文件生成带DM5的文件,使用srec_cat工具: read A #原始文件 srec_cat $A -o 要生成的文件名称 -Line_Length 46 -Address_Leng ...
- LA3276
费用流 这种棋盘模型大概都是网络流吧 首先我们知道棋子之间不会影响到达目标的步数,那么就好做了,枚举终点,然后就是最小权匹配了,因为就是寻找总和最小,然后费用流就行了. #include<bit ...
- 排序系列 之 堆排序算法 —— Java实现
基本概念: 二叉堆是完全二叉树或者是近似完全二叉树. 当父结点的键值总是大于或等于任何一个子节点的键值时为最大堆. 当父结点的键值总是小于或等于任何一个子节点的键值时为最小堆. 一般将二叉堆简称 ...
- bzoj1030 文本生成器(AC自动机+dp)
1030: [JSOI2007]文本生成器 Time Limit: 1 Sec Memory Limit: 162 MBSubmit: 4777 Solved: 1986[Submit][Stat ...
- HTML中常用的颜色词汇
white (白色). black(黑色) . blue(蓝色) . green(绿色) .red(红色) .yellow(黄色) . pink(粉色).gray(灰色).brown(棕色). gre ...
- [NOI2015,LuoguP2146]软件包管理器------树剖
***题目链接戳我*** 又是在树上瞎搞滴题目.... 我们如果以安装的软件为1,未安装的软件为0,那么软件改变的数量即树上权值总和的数量,涉及到区间修改,区间查询,考虑树剖 分析完毕,似乎没啥好说的 ...
- 运行Django项目指定IP和端口
默认IP和端口 python manage.py runserver 指定端口: python manage.py runserver 192.168.12.12:8080 此时会报错,我们需要修改配 ...
- Laravel5.1学习笔记6 响应
基本响应 附加头信息到响应 附加Cookie到响应 其他响应 View视图响应 JSON响应 File下载 重定向 重定向到命名路由 重定向到控制器Action 附带闪回Session数据重定向 响应 ...