html5游戏源码是怎么做的。有谁知道

17883人阅读
【游戏引擎】(14)
【Lufylegend.js】(32)
【Html5&JavaScript】(51)
一,话说天下大事
前不久看到的博客上,有一位朋友想要一个RPG游戏引擎,出于兴趣准备动手做一做。由于我研究lufylegend有一段时间了,对它有一定的依赖性,因此就准备将这个引擎基于lufylegend。暂时命名为lufylegendRPG。毕竟基于lufylegend,如果名称中不加上lufylegend这几个字的话,有点说不通啊。。。最近发布了0.1.0版,但是不理想,连一惯都是鼓励和赞赏我的lufy老先生都是出于真心的表示不满意。想了解0.1.0版的朋友可以看看这里(其实最好别看,因为1.0在用法上做了很大的调整):
于是我不得不重新来开发它。首先想到了地图类,今天就来实现一下。
我们的地图不应该是一张大地图,而是用小地图拼接而成,这样方便我们修改地图。
这样的话我们需要许多地图块的图片,通常我们把它们放在一张上。我们就用lufy老先生blog上一张图片作为例子,给大家看看这种装满小地图的大图是什么样的:
我们要完成的效果是什么样的呢?我把它放在这里,完成后看看实现度到底有多少:
二,如何实现
准备工作:
首先你需要下载lufylegend,最新版本是1.7.5,用1.7.3都行。
下载地址:
上面有它的API和论坛,可以看看。
另外推荐一本相关图书,lufy写的,叫《HTML5 Canvas游戏开发实战》。用于学习基础和了解开发技巧还是不错的。其中还有一些很不错的js技术指导。值得一看。
书籍介绍:
由于lufylegend做的比较完美,那么我们封装起来就比较简单了。看看LTileMap完整构造器:
function LTileMap(data,img,width,height){
base(s,LSprite,[]);
s.mapData =
s.imgData =
if(!width){
var wbitmap = new LBitmapData(s.imgData);
s.partWidth = wbitmap.image.
s.partWidth =
if(!height){
var hbitmap = new LBitmapData(s.imgData);
s.partHeight = hbitmap.image.
s.partHeight =
s.onshow();
首先为了减少引擎的大小,我们把变量s和this等起来,下面用到this的地方就都能用s来实现了。
※lufy大神最近提示我:“把变量s和this等起来是为了防止this的指向发生变化,并非单一减少引擎的大小。因为this的指向不一定一直指向当前函数的。”在此再次感谢lufy的支持。
首先我们让它继承LSprite,这样如果我们改变x和y属性后就可以直接变换位置了。再追加两个属性:mapData和imgData。
mapData是通过data参数赋值的,data的赋值应该是一个二维数组,格式如下:
[18,18,18,18,18,18,18,18,18,18,18,18,55,55,18],
[18,18,18,17,17,17,17,17,17,17,17,17,55,55,18],
[18,18,17,17,17,17,18,18,17,17,17,17,55,55,18],
[18,17,17,17,18,18,18,18,18,17,17,55,55,17,18],
[18,17,17,18,22,23,23,23,24,18,17,55,55,17,18],
[18,17,17,18,25,28,26,79,27,18,55,55,17,17,18],
[18,17,17,17,17,10,11,12,18,18,55,55,17,17,18],
[18,18,17,17,10,16,16,16,11,55,55,17,17,17,18],
[18,18,17,17,77,16,16,16,16,21,21,17,17,17,18],
[18,18,18,18,18,18,18,18,18,55,55,18,18,18,18]它装载着地图块的样式,18对应的图块和55对应的图块是不一样的。后面我们会细讲。
imgData顾名思义,它是一个装图片的容器。
还有两个参数,它们是用来表示地图快的高度和宽度的。例如每张地图块是32*42的,那么就要将width设为32,height设为42。这样的话就会将装满地图块的图片分成小地图。例如我们把上面那张图片分成每个小地图块是32*32的,也就是说width设为32,height也设为32,那么就呈现现以下的形式:
(以上图片我直接用了lufy博客里的图片)这时你可以看看18和55所对应的是什么。18是一棵树,而55对应的是水,因此我们就做到了让每张地图块显示得不同。
接下来是onshow方法:
LTileMap.prototype.onshow = function(){
var mapdata = s.mapD
var partWidth = s.partW
var partHeight = s.partH
var index,indexY,indexX;
var bitmapdata,
for(i=0;i&mapdata.i++){
for(j=0;j&mapdata[0].j++){
index = mapdata[i][j];
indexY = Math.floor(index/mapdata.length);
indexX = index - indexY*mapdata.
bitmapdata = new LBitmapData(s.imgData,indexX*partWidth,indexY*partHeight,partWidth,partHeight);
bitmap = new LBitmap(bitmapdata);
bitmap.x = j*partWidth + s.x;
bitmap.y = i*partHeight + s.y;
s.addChild(bitmap);
}它的功能很简单,就是画出地图。其中的逻辑都很简单。主要是这里:
for(i=0;i&mapdata.i++){
for(j=0;j&mapdata[0].j++){
index = mapdata[i][j];
indexY = Math.floor(index/mapdata.length);
indexX = index - indexY*mapdata.
bitmapdata = new LBitmapData(s.imgData,indexX*partWidth,indexY*partHeight,partWidth,partHeight);
bitmap = new LBitmap(bitmapdata);
bitmap.x = j*partWidth + s.x;
bitmap.y = i*partHeight + s.y;
s.addChild(bitmap);
}这一段代码是画出地图的核心,首先它遍历了地图数组,然后每遍历一个就画一张,然后加到自身中。由于自身是继承自LSprite,所当地图被加到自身中时,再将自身加到底层或者其他Sprite中时,整个截面就会显示。
over,很简单是不是?实现后我们怎么用它呢?看以下代码:
&!DOCTYPE html&
&html lang=&en&&
&meta charset=&utf-8& /&
&title&LTileMap&/title&
&script type=&text/javascript& src=&../lufylegend-1.7.3.min.js&&&/script&
&script type=&text/javascript& src=&../lufylegendrpg-1.0.0.min.js&&&/script&
init(30,&legend&,480,320,main);
LGlobal.setDebug(true);
var backLayer,loadingL
var loadData = [
{name:&map&,path:&./map.jpg&}
var imglist = [];
var mapData = [
[18,18,18,18,18,18,18,18,18,18,18,18,55,55,18],
[18,18,18,17,17,17,17,17,17,17,17,17,55,55,18],
[18,18,17,17,17,17,18,18,17,17,17,17,55,55,18],
[18,17,17,17,18,18,18,18,18,17,17,55,55,17,18],
[18,17,17,18,22,23,23,23,24,18,17,55,55,17,18],
[18,17,17,18,25,28,26,79,27,18,55,55,17,17,18],
[18,17,17,17,17,10,11,12,18,18,55,55,17,17,18],
[18,18,17,17,10,16,16,16,11,55,55,17,17,17,18],
[18,18,17,17,77,16,16,16,16,21,21,17,17,17,18],
[18,18,18,18,18,18,18,18,18,55,55,18,18,18,18]
function main(){
//加入进度条
loadingLayer = new LoadingSample1();
addChild(loadingLayer);
//加载图片并显示进度
LLoadManage.load(
function(progress){
loadingLayer.setProgress(progress);
function gameInit(result){
removeChild(loadingLayer);
//初始化层
backLayer = new LSprite();
addChild(backLayer);
//加入地图
function addMap(){
map = new LTileMap(mapData,imglist[&map&],32,32);
backLayer.addChild(map);
&div id=&legend&&&/div&
运行代码得到如下效果:
为了防止大家以为我ps图片,那我就不仿把测试链接给出,大家自己看吧。
测试地址:
代码很少,可以自己复制粘贴下来看看。哈!
最近做了一个留言板,欢迎大家发表自己的意见
留言板地址:
----------------------------------------------------------------
欢迎大家转载我的文章。
转载请注明:转自
欢迎继续关注我的博客
参考知识库
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:609110次
积分:7384
积分:7384
排名:第1879名
原创:63篇
评论:794条
基于HTML5和lufylegend.js开源引擎的一款类似于贪吃蛇的游戏。相信这款游戏能给你带来欲速则不达、近在咫尺却无法接触地虐心体验!
本游戏基于开源HTML5引擎lufylegend.js开发,是一款跨平台休闲类翻牌游戏。本游戏一共有五个关卡,随着关卡难度的增加会有更多卡牌出现。快来考验一下自己的记忆力吧~
阅读:55787
文章:19篇
阅读:251537
(3)(3)(1)(2)(1)(2)(1)(1)(1)(1)(3)(1)(1)(1)(1)(1)(1)(1)(2)(1)(3)(3)(6)(3)(4)(3)(2)(1)(1)(4)(4)分类首页益智挑战敏捷测试射击美女拼图连连看打地鼠神经猫
最新HTML5游戏
游戏吧HTML5游戏采用 WordPress 创作如何针对Windows 8平台制作HTML5复古游戏_百度知道
如何针对Windows 8平台制作HTML5复古游戏
提问者采纳
}, 0),还可以将载入图像的功能封装成一个类或别的任何形式: 0,这样我们才能计算时间差(自上次循环以来经过的时间),
y,每张图片都需要这样处理;Goblins caught、英雄,当用户开始输入时,而不是立即处理, false)!5,游戏每隔一定时间会调用它一次;、怪物)。8;
monster。然后将起始时间保存到变量then中并启动游戏的主循环;
当你能够看到你的行动时游戏才会变得更有趣: 256。(对具有web开发背景的人来说;&#47。首先调用reset来开始新游戏;
bgImage;monstersCaught表示玩家抓住的怪物数量;
if (heroReady) {
ctx,这有些不同;
var bgImage = new Image()。因为不需要复杂的动画或者对文字进行移动.y &lt。通常update函数调用的间隔很短,不过我在这儿先解释一下. 开始游戏吧[javascript] view plaincopy&#47。我想尽量简单化;left&&#47。7.png&quot。6. 处理玩家输入[javascript] view plaincopy&#47.keyCode] =
定义一些变量。注意顺序很重要。最后调用render并更新记录的时间;
var monstersCaught = 0。如果间隔刚好为1秒时。9. Let&#39.speed * modifier.x,它的值就会为1;monster对象不会移动,但我们还可以在移动英雄时对其进行检查;&#47.width - 64));
canvas。代码中的bgReady用来标识图片是否已完全载入,这是最后一段代码.textBaseline = &quot,这会将英雄置中并随机安放怪物),我们调用fillText函数显示玩家的分数; The main game loop
var main = function () {
var now = Date.speed * modifier,当然。该函数将英雄(即玩家角色)放到屏幕中间; 1000), /&#47.now();
then = now,所以modifier的值很小。可以用JavaScript或HTML来做;);= (monster。如果是, function (e) {
delete keysDown[e.x,只有当图片载入完成后, monster, 32;,我们就可以获取它的上下文对象(context);&#47.now()。更多关于游戏循环的内容见“O 2;
bgImage. 创建一个Canvas对象[javascript] view plaincopy&#47.height = 480,这是目前为止第一个具有挑战性的部分)对一般的网页来说;
update(delta &#47. 载入图片[javascript] view plaincopy&#47,JS将会报一个DOM error的错误;
if (40 in keysDown) { &#47.speed *
}; Game objects
var hero = {
movement in pixels per second
x.drawImage(heroI
&#47。简单吧;
reset().y);/&#47.appendChild(canvas). 渲染对象[javascript] view plaincopy/
addEventListener(&quot。update有一个modifier参数,所以只是绘制一下就ok了;
}。我们会用到三张图片(背景; / Reset the game when the player catches a monster
var reset = function () {
canvas&quot,我们想让游戏逻辑在一个单独的地方对游戏中发生的事情进行处理,所以只用了Image对象来做;
var monster = {
x:英雄是否与怪物发生了碰撞——当英雄与怪物发生碰撞时.width /秒);
}。首先我们要获得当前的时间。接下来是文字.x = 32 + (Math.y -= hero.random() * (
if (monsterReady) {
,所以让我们在屏幕上绘制吧; + monstersCaught。例如.onload = function () {
bgReady = Background image
var bgReady = false, 1);
}.font = &24px Helvetica&quot.drawImage(bgI
Throw the monster somewhere on the screen randomly
monster.x + 32)
&& monster.y &
}; Player holding up
hero.speed *秒),它的值就为0。modifier参数是一个从1开始的与时间相关的数,如果在载入完成前就对其进行绘制或渲染. 新游戏[javascript] view plaincopy&#47.textAlign = &quot,但用这种方式能够确保不管代码执行的速度怎么样,英雄移动的距离即为256像素(英雄的速度为256像素/
setInterval(main.x -= hero, 0,keyup&quot。首先我们将背景图片绘制到canvas.y + 32)
&&&#47,因为任何位于表层的图片都会将其下面的像素覆盖掉.x &lt,以确定是否有其他事件发生,然后随机选择一个位置来安置怪物: &quot,然后是英雄和怪物.random() * ( Player holding down
hero.createElement(&quot、设置尺寸;
var then = Date。(还记得吗;&#47, false), 250)&
ctx.src = &quot。此处我用的是JS.x + 32)
addEventListener(&quot,以此类推,我们才能使用它.width = 512.fillText(&quot: 0
},并且把它加到当前文档中;;;
var ctx = canvas。我们通过简单地将事件对应的键编码(keyCode)保存在keysDown变量中来实现; Update game objects
var update = function (modifier) {
if (38 in keysDown) { &#47.5秒; Player holding right
= (monster! Arena Case Study”;&#47.y + 32)
++monstersCaught, 250.x =/top& Draw everything
var render = function () {
if (bgReady) {
ctx.drawImage(monsterI&#47。我们已经实现了根据用户的输入来移动英雄: 0。然后计算modifier的值并交给update(需要将delta除以1000以将其转换为毫秒);= (hero.height - 64)); Are they touching, hero。2;&#47。hero对象的speed属性表示英雄的移动速度(像素&#47,稍后会用到.5;
现在进行输入的处理;
游戏的主循环用来控制游戏流程.height &#47.x &lt,所以让我们载入一些图片吧;&#47。如果该变量中具有某个键编码,即英雄移动的距离为其速度的一半, 32););
var delta = now -
if (39 in keysDown) { /= (hero,这看起来好像有点奇怪;
游戏需要图像;
/keydown&quot,我们为玩家进行计分(monstersCaught加1)并重置游戏(调用reset函数)。3;&#47。你会在游戏的主函数即main函数中看到它, function (e) {
keysDown[e. 游戏主循环[javascript] view plaincopy&#47。为此我们需要将用户输入保存下来以备稍后处理;
images&#47, monster。它所做的第一件事情是检查用户是否按下了上下左右四个箭头键.y += hero,就表示用户目前正按下这个键;。OK.y = 32 + (Math.y)。但在这里;
这是update函数!
reset(): 0
ctx,就将我们的英雄向相应的方向移动,英雄的移动速度都是相同的。当创建了canvas之后;/
if (37 in keysDown) { &#47,所以仅仅具有一对坐标;/而如果间隔是0.x += hero,可能需要马上开始播放动画或请求数据;2d& Player holding left
Create the canvas
var canvas = document1. 定义游戏要使用的对象[javascript] view plaincopy/ Execute as fast as possible
快完成了!(但愿)你现在已经理解了在HTML5 Canvas中用JS来开发游戏的基础知识了。建议最好是能够自己亲自试一把;
通过调用reset函数来开始新游戏;
canvas.fillStyle = &
}; Handle keyboard controls
var keysDown = {}.y =;
我们首先要做的是创建一个canvas对象.keyCode],都非常简单。4. 更新对象[javascript] view plaincopy&#47.getContext(&quot
来自团队:
为您推荐:
html5的相关知识
等待您来回答
下载知道APP
随时随地咨询
出门在外也不愁Posts - 102,
Articles - 0,
Comments - 9956
18:28 by 【当耐特】, ... 阅读,
Hello world
创建player
         a:使用jQuery Hotkeys
         b:移动player
添加更多游戏元素
你想使用HTML5的Canvas制作一款游戏吗?跟着这个教程,你将立刻上道儿。
阅读该教程需要至少熟悉javascript相关知识。
你可以先玩这款或者直接阅读文章并且下载游戏。
在画任何东西之前,我们必须创建一个画布。因为这是完全指南,并且我们将用到jQuery.
var CANVAS_WIDTH = 480;
var CANVAS_HEIGHT = 320;
var canvasElement = $(&&canvas width='& + CANVAS_WIDTH +
&' height='& + CANVAS_HEIGHT + &'&&/canvas&&);
var canvas = canvasElement.get(0).getContext(&2d&);
canvasElement.appendTo('body');
为了呈现给玩家连贯流畅的游戏动画,我们要频繁地渲染画布来欺骗玩家的眼睛。
var FPS = 30;
setInterval(function() {
}, 1000/FPS);
现在我们先不管update和draw里面的实现,重要的是我们要知道setInterval()会周期性的执行update和draw
Hello world
现在我们已经搭建好了一个循环的架子,我们去修改update和draw方法来写一些文字到屏幕。
function draw() {
canvas.fillStyle = &#000&; // Set color to black
canvas.fillText(&Sup Bro!&, 50, 50);
专家提醒: 当你稍微更改了一些代码的时候就执行一下程序,这样可以更快的找到程序出错地方。
静止文字正常的显示出来了。因为我们已经有了循环,所以我们可以很容易地让文字动起来~~~
var textX = 50;
var textY = 50;
function update() {
textX += 1;
textY += 1;
function draw() {
canvas.fillStyle = &#000&;
canvas.fillText(&Sup Bro!&, textX, textY);
执行程序。如果你一步一步照着上面做下来,可以看到文字移动。但是上一次的文字却还留在屏幕上,因为我们没有擦除画布。现在我们在draw方法中加入擦除方法。
function draw() {
canvas.clearRect(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT);
canvas.fillStyle = &#000&;
canvas.fillText(&Sup Bro!&, textX, textY);
现在你可以看到文字在屏幕上移动了,它已经算是一个真正意义上的游戏,只不过是个半成品。
创建player
创建一个包含player所有信息的对象,并且要有draw方法。这里创建了一个简单的对象包含了所有的player信息。
var player = {
color: &#00A&,
width: 32,
height: 32,
draw: function() {
canvas.fillStyle = this.color;
canvas.fillRect(this.x, this.y, this.width, this.height);
我们现在用一个纯色的矩形来代表player.当我们把它加入游戏当中的时候,我们需要清除画布并且画上player.
function draw() {
canvas.clearRect(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT);
player.draw();
使用jQuery Hotkeys
在处理键盘行为的时候,可以更加容易的兼容不同的浏览器。让开发者不用因为不同浏览器之间的keyCode andcharCode不同而苦恼,我们这样绑定事件:
$(document).bind(&keydown&, &left&, function() { ... });
移动player
function update() {
if (keydown.left) {
player.x -= 2;
if (keydown.right) {
player.x += 2;
是不是感觉移动不够快?那么我们来提高它的移动速度。
function update() {
if (keydown.left) {
player.x -= 5;
if (keydown.right) {
player.x += 5;
player.x = player.x.clamp(0, CANVAS_WIDTH - player.width);
我们可以很容易的添加其他元素,比如炮弹:
function update() {
if (keydown.space) {
player.shoot();
if (keydown.left) {
player.x -= 5;
if (keydown.right) {
player.x += 5;
player.x = player.x.clamp(0, CANVAS_WIDTH - player.width);
player.shoot = function() {
console.log(&Pew pew&);
// :) Well at least adding the key binding was easy...
添加更多游戏元素
我们开始真正意义上的添加炮弹,首先,我们需要一个集合来存储它:
var playerBullets = [];
然后,我们需要一个构造器来创建炮弹:
function Bullet(I) {
I.active = true;
I.xVelocity = 0;
I.yVelocity = -I.speed;
I.width = 3;
I.height = 3;
I.color = &#000&;
I.inBounds = function() {
return I.x &= 0 && I.x &= CANVAS_WIDTH &&
I.y &= 0 && I.y &= CANVAS_HEIGHT;
I.draw = function() {
canvas.fillStyle = this.color;
canvas.fillRect(this.x, this.y, this.width, this.height);
I.update = function() {
I.x += I.xVelocity;
I.y += I.yVelocity;
I.active = I.active && I.inBounds();
当玩家开火,我们需要向集合中添加炮弹:
player.shoot = function() {
var bulletPosition = this.midpoint();
playerBullets.push(Bullet({
x: bulletPosition.x,
y: bulletPosition.y
player.midpoint = function() {
x: this.x + this.width/2,
y: this.y + this.height/2
修改update和draw方法,实现开火:
function update() {
playerBullets.forEach(function(bullet) {
bullet.update();
playerBullets = playerBullets.filter(function(bullet) {
return bullet.active;
function draw() {
playerBullets.forEach(function(bullet) {
bullet.draw();
enemies = [];
function Enemy(I) {
I = I || {};
I.active = true;
I.age = Math.floor(Math.random() * 128);
I.color = &#A2B&;
I.x = CANVAS_WIDTH / 4 + Math.random() * CANVAS_WIDTH / 2;
I.xVelocity = 0
I.yVelocity = 2;
I.width = 32;
I.height = 32;
I.inBounds = function() {
return I.x &= 0 && I.x &= CANVAS_WIDTH &&
I.y &= 0 && I.y &= CANVAS_HEIGHT;
I.draw = function() {
canvas.fillStyle = this.color;
canvas.fillRect(this.x, this.y, this.width, this.height);
I.update = function() {
I.x += I.xVelocity;
I.y += I.yVelocity;
I.xVelocity = 3 * Math.sin(I.age * Math.PI / 64);
I.active = I.active && I.inBounds();
function update() {
enemies.forEach(function(enemy) {
enemy.update();
enemies = enemies.filter(function(enemy) {
return enemy.active;
if(Math.random() & 0.1) {
enemies.push(Enemy());
function draw() {
enemies.forEach(function(enemy) {
enemy.draw();
player.sprite = Sprite(&player&);
player.draw = function() {
this.sprite.draw(canvas, this.x, this.y);
function Enemy(I) {
I.sprite = Sprite(&enemy&);
I.draw = function() {
this.sprite.draw(canvas, this.x, this.y);
function collides(a, b) {
return a.x & b.x + b.width &&
a.x + a.width & b.x &&
a.y & b.y + b.height &&
a.y + a.height & b.y;
function handleCollisions() {
playerBullets.forEach(function(bullet) {
enemies.forEach(function(enemy) {
if (collides(bullet, enemy)) {
enemy.explode();
bullet.active = false;
enemies.forEach(function(enemy) {
if (collides(enemy, player)) {
enemy.explode();
player.explode();
function update() {
handleCollisions();
function Enemy(I) {
I.explode = function() {
this.active = false;
// Extra Credit: Add an explosion graphic
player.explode = function() {
this.active = false;
// Extra Credit: Add an explosion graphic and then end the game
function Enemy(I) {
I.explode = function() {
this.active = false;
// Extra Credit: Add an explosion graphic
player.explode = function() {
this.active = false;
// Extra Credit: Add an explosion graphic and then end the game
DNT砖家提醒: 跟着上面的步骤,大概让大家了解了一款游戏的各种元素的制作过程,这类游戏做一遍就够,没有必要做第二遍,没有很难的算法,全是流程和经验性质的东西,倘若想做好看,做炫一点,那就是美工拼了老命切图的事情,或者开发人员介入做一些性能优化和碰撞优化。最后重复一遍----看过就好,不要当宝。
你可能还喜欢:10款超炫HTML5游戏 附游戏源码 | HTML5资源教程

我要回帖

更多关于 html5游戏引擎 的文章

 

随机推荐