这个游戏基本上是建立在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 封装的一个超级马里奥游戏(包含源码)的更多相关文章

  1. 高性能动画!HTML5 Canvas JavaScript框架KineticJS

    高性能动画!HTML5 Canvas JavaScript框架KineticJS KineticJS是一款开源的HTML5 Canvas JavaScript框架,能为桌面和移动应用提供高性能动画,并 ...

  2. HTML5 Canvas中实现绘制一个像素宽的细线

    正统的HTML5 Canvas中如下代码 ctx.lineWidth = 1; ctx.beginPath(); ctx.moveTo(10, 100); ctx.lineTo(300,100); c ...

  3. Unity 2D游戏开发高速入门第1章创建一个简单的2D游戏

    Unity 2D游戏开发高速入门第1章创建一个简单的2D游戏 即使是如今,非常多初学游戏开发的同学.在谈到Unity的时候.依旧会觉得Unity仅仅能用于制作3D游戏的. 实际上.Unity在2013 ...

  4. 【JavaScript游戏开发】JavaScript+HTML5封装的苏拉卡尔塔游戏(包含源码)

    /** 苏拉克尔塔游戏 * 思路: * 1.棋盘设置:使用HTML5的canvas标签绘制整个棋盘 * 2.点击事件:当页面被点击时,获取点击的x,y像素点,根据此像素点进行判断,再在合适位置绘制黑红 ...

  5. 【原创】使用HTML5+canvas+JavaScript开发的原生中国象棋游戏及源码分享

    目前已经实现的功能: V1.0 : 实现棋子的布局,画布及游戏场景的初始化V2.0 : 实现棋子的颜色改变V3.0 :实现所有象棋的走棋规则V4.0 : 实现所有棋子的吃子功能 GItHub源码下载地 ...

  6. 自己写的HTML5 Canvas + Javascript五子棋

    看到一些曾经只会灌水的网友,在学习了前端之后,已经能写出下载量几千几万的脚本.样式,帮助大众,成为受欢迎的人,感觉满羡慕的.我也想学会前端技术,变得受欢迎呀.于是心血来潮,开始学习前端知识,并写下了这 ...

  7. 【读书笔记《Android游戏编程之从零开始》】12.游戏开发基础(Canvas 画布)

    1.Canvas 画布 画布类 Canvas 封装了图形和图片绘制等内容,此类常用的函数说明如下: drawColor(int color) 作用:绘制颜色覆盖画布,常用于刷屏 参数:颜色值,也可用十 ...

  8. 使用PhoneGap开发基于Html5应用二:第一个PhoneGap应用:百度

    上一篇博文使用PhoneGap开发基于Html5应用一:PhoneGap简单介绍 中我介绍了怎样从phonegap官网上下载源代码并启动第一个应用,今天我们把phonegap的应用略微改一下,让他实现 ...

  9. 如何实现一个HTTP请求库——axios源码阅读与分析 JavaScript

    概述 在前端开发过程中,我们经常会遇到需要发送异步请求的情况.而使用一个功能齐全,接口完善的HTTP请求库,能够在很大程度上减少我们的开发成本,提高我们的开发效率. axios是一个在近些年来非常火的 ...

随机推荐

  1. Android实战简易教程-第二十四枪(基于Baas的用户表查询功能实现!)

    接着上一篇,我们注冊了几个用户,用户表例如以下: 以下我们用ListView将表中数据显示出来吧. 首先看一下main.xml: <RelativeLayout xmlns:android=&q ...

  2. 运用smali自己主动注入技术分析android应用程序行为

    如今android开发人员社区里,除了app开发外,还有非常多周边的工具类产品,比方安全.性能等,app产品 已经出现了巨无霸,可是工具类的产品.眼下还没有出现规模比較大的公司,大部分还处于创业阶段, ...

  3. K度限制MST poj 1639

    /* k度限制MST:有一个点的度<=k的MST poj 1639 要求1号点的度不超过k 求MST 我们先把1号点扔掉 跑MST 假设有sum个连通分支 然后把这sum个分支连到1上 就得到了 ...

  4. velocity.js 中文文档 (教程)

    velocity.js 是一个简单易用.高性能.功能丰富的轻量级JS动画库.它能和 jQuery 完美协作,并和$.animate()有相同的 API, 但它不依赖 jQuery,可单独使用. Vel ...

  5. P1043 数字游戏

    P1043 数字游戏 题目描述 丁丁最近沉迷于一个数字游戏之中.这个游戏看似简单,但丁丁在研究了许多天之后却发觉原来在简单的规则下想要赢得这个游戏并不那么容易.游戏是这样的,在你面前有一圈整数(一共n ...

  6. map集合遍历的五种方法

    package com.jackey.topic; import java.util.ArrayList;import java.util.HashMap;import java.util.Itera ...

  7. Opencv保存摄像头视频&&各种编码器下视频文件占用空间对比

    打开视频文件或摄像头视频需要使用Opencv中的VideoCapture类,保存视频或摄像头视频到本地磁盘,需要使用Opencv中的VideoWriter类,使用都很简单,这篇文章就记录一下Video ...

  8. 洛谷 P1081 开车旅行 —— 倍增

    题目:https://www.luogu.org/problemnew/show/P1081 真是倍增好题! 预处理:f[i][j] 表示从 i 点开始走 2^j 次 AB (A,B各走一次)到达的点 ...

  9. Spark入门之DataFrame/DataSet

    目录 Part I. Gentle Overview of Big Data and Spark Overview 1.基本架构 2.基本概念 3.例子(可跳过) Spark工具箱 1.Dataset ...

  10. PCB .NET连接MySQL与Oracle DLL文分享件 MySql.Data,Oracle.ManagedDataAccess

    虽然我们C#对SQL SERVER天然的支持,但对于C#要连接MYSQL或Oracle就不同了, 需要用到第3方组件才行,本文将2个组件连接数据库代码与DLL下载地址贴出. 一.C#连接MYSQL   ...