使用JavaScript和Canvas开发游戏(五)
2011年08月17日 Web开发, 编程技术, 翻译
原文作者:Matthew Casperson • 编辑:Michele McDonough
原文链接: Game Development with JavaScript and the Canvas element
1、认识一下Canvas
2、在Canvas上绘图
3、通过Canvas元素实现高级图像操作
4、写一个游戏框架(一)
5、写一个游戏框架(二)
6、通过Canvas实现视差滚动
7、动画
8、JavaScript键盘输入
9、综合运用
10、定义级别
11、跳跃与坠落
12、添加道具
13、加载资源
14、添加主菜单
在Canvas元素上实现视差滚动
http://www.brighthub.com/internet/web-development/articles/40511.aspx
视差滚动是在2D应用中创造立体纵深感的一种技术。这篇文章就来看一看在我们刚刚创建的游戏框架基础上实现视差滚动有多容易。
视差滚动
有了游戏框架,就可以通过画布元素来做一些好玩的东西了。
视差滚动指的是屏幕上的几个图层发生相对位移的效果,换句话说,背景图层滚动得比它前面的那些图层要慢一些。这种创造视觉纵深感的技术在2D游戏中的应用极为普遍。
RepeatingGameObject.js
/**
这个类可以重复显示纹理图像,支持纹理图像在x轴或y轴偏移
@class
*/
function RepeatingGameObject()
{
/** 最终图像占据的宽度
@type Number
*/
this.width = 0;
/** 最终图像占据的高度
@type Number
*/
this.height = 0;
/** 绘制时应用多少scrollX和scrollY
@type Number
*/
this.scrollFactor = 1;
/**
初始化对象
@return 对初始化对象的引用
*/
this.startupRepeatingGameObject = function(image, x, y, z, width, height, scrollFactor)
{
this.startupVisualGameObject(image, x, y, z);
this.width = width;
this.height = height;
this.scrollFactor = scrollFactor;
return this;
}
/**
清理对象
*/
this.shutdownstartupRepeatingGameObject = function()
{
this.shutdownVisualGameObject();
}
/**
把当前元素绘制到后台缓冲
@param dt 自上一帧绘制起经过的秒数
@param context 绘制上下文
@param xScroll x轴的全局滚动值
@param yScroll y轴的全局滚动值
*/
this.draw = function(dt, canvas, xScroll, yScroll)
{
var areaDrawn = [0, 0];
for (var y = 0; y < this.height; y += areaDrawn[1])
{
for (var x = 0; x < this.width; x += areaDrawn[0])
{
// 绘制下一张贴片左上角的点
var newPosition = [this.x + x, this.y + y];
// 剩余的绘制空间
var newFillArea = [this.width - x, this.height - y];
// 第一次必须从图像的中央开始绘制
// 后续贴片从上方或左侧绘制
var newScrollPosition = [0, 0];
if (x==0) newScrollPosition[0] = xScroll * this.scrollFactor;
if (y==0) newScrollPosition[1] = yScroll * this.scrollFactor;
areaDrawn = this.drawRepeat(canvas, newPosition, newFillArea, newScrollPosition);
}
}
}
this.drawRepeat = function(canvas, newPosition, newFillArea, newScrollPosition)
{
// 找到重复绘制纹理图像的起点(左上角)
var xOffset = Math.abs(newScrollPosition[0]) % this.image.width;
var yOffset = Math.abs(newScrollPosition[1]) % this.image.height;
var left = newScrollPosition[0]<0?this.image.width-xOffset:xOffset;
var top = newScrollPosition[1]<0?this.image.height-yOffset:yOffset;
var width = newFillArea[0] < this.image.width-left?newFillArea[0]:this.image.width-left;
var height = newFillArea[1] < this.image.height-top?newFillArea[1]:this.image.height-top;
// 绘制图像
canvas.drawImage(this.image, left, top, width, height, newPosition[0], newPosition[1], width, height);
return [width, height];
}
}
RepeatingGameObject.prototype = new VisualGameObject();
这个RepeatingGameObject类可以让图像在一个确定的区域内重复和滚动。此前,我们已经实现了绘制整幅图像。而RepeatingGameObject的不同之处在于,它拿到一幅图像并用它来填充一块范围既定的区域(其尺寸与绘制的图像无关)。我们通过这个类每次显示一幅大图像(如一座山的全景图)的一小部分,从而创建出一个背景。
也许你已经注意到了GameObjectManager的xScroll和yScroll属性,它们被传递给了GameObject的draw和updata函数。这两个值定义的是摄像机沿x轴或y轴移动了多远。RepeatingGameObject使用这两个值来它们显示的纹理,以创造移动的假象。
首先,定义RepeatingGameObject要绘制的区域。底层的GameObject类的x和y属性定义了左上角位置,而新的width和height属性定义的是绘制区域。
/** 最终图像占据的宽度
@type Number
*/
this.width = 0;
/** 最终图像占据的高度
@type Number
*/
this.height = 0;
/** 绘制时应用多少scrollX和scrollY
@type Number
*/
而scrollFactor属性用于改变RepeatingGameObject滚动的量,该变化是通过传递到draw函数的xScroll和yScroll来控制的。将scrollFactor设置为小于1的值,会导致滚动变慢,从而造就画面中的远景。
/** 绘制时应用多少scrollX和scrollY
@type Number
*/
this.scrollFactor = 1;
最后两个draw和drawRepeat函数具体负责渲染贴片及偏移的纹理。
/**
把当前元素绘制到后台缓冲
@param dt 自上一帧绘制起经过的秒数
@param context 绘制上下文
@param xScroll x轴的全局滚动值
@param yScroll y轴的全局滚动值
*/
this.draw = function(dt, canvas, xScroll, yScroll)
{
var areaDrawn = [0, 0];
for (var y = 0; y < this.height; y += areaDrawn[1])
{
for (var x = 0; x < this.width; x += areaDrawn[0])
{
// 绘制下一张贴片左上角的点
var newPosition = [this.x + x, this.y + y];
// 剩余的绘制空间
var newFillArea = [this.width - x, this.height - y];
// 第一次必须从图像的中央开始绘制
// 后续贴片从上方或左侧绘制
var newScrollPosition = [0, 0];
if (x==0) newScrollPosition[0] = xScroll * this.scrollFactor;
if (y==0) newScrollPosition[1] = yScroll * this.scrollFactor;
areaDrawn = this.drawRepeat(canvas, newPosition, newFillArea, newScrollPosition);
}
}
}
this.drawRepeat = function(canvas, newPosition, newFillArea, newScrollPosition)
{
// 找到重复绘制纹理图像的起点(左上角)
var xOffset = Math.abs(newScrollPosition[0]) % this.image.width;
var yOffset = Math.abs(newScrollPosition[1]) % this.image.height;
var left = newScrollPosition[0]<0?this.image.width-xOffset:xOffset;
var top = newScrollPosition[1]<0?this.image.height-yOffset:yOffset;
var width = newFillArea[0] < this.image.width-left?newFillArea[0]:this.image.width-left;
var height = newFillArea[1] < this.image.height-top?newFillArea[1]:this.image.height-top;
// 绘制图像
canvas.drawImage(this.image, left, top, width, height, newPosition[0], newPosition[1], width, height);
return [width, height];
}
ApplicationManager.js
/**
ApplicationManager用于管理应用
@class
*/
function ApplicationManager()
{
/**
初始化对象
@return A 对初始化对象的引用
*/
this.startupApplicationManager = function()
{
this.startupGameObject();
this.background3 = new RepeatingGameObject().startupRepeatingGameObject(g_back2, 0, 100, 3, 600, 320, 1);
this.background2 = new RepeatingGameObject().startupRepeatingGameObject(g_back1, 0, 100, 2, 600, 320, 0.75);
this.background = new RepeatingGameObject().startupRepeatingGameObject(g_back0, 0, 0, 1, 600, 320, 0.5);
return this;
}
/**
更新当前对象
@param dt 自上一帧绘制起经过的秒数
@param context 绘制上下文
@param xScroll x轴的全局滚动值
@param yScroll y轴的全局滚动值
*/
this.update = function(/**Number*/ dt, /**CanvasRenderingContext2D*/ context, /**Number*/ xScroll, /**Number*/ yScroll)
{
g_GameObjectManager.xScroll += 50 * dt;
}
}
ApplicationManager.prototype = new GameObject
在这里,我们通过ApplicationManager创建了三个RepeatingGameObject类的实例,每个实例分别显示为一个图层,使用z(深度)和scrollFactor值来创造RepeatingGameObject 渐远和渐慢的效果。
最终结果很不错。视差滚动为画布赋予了完美的纵深感,而整个效果只多编写了一个类就实现了。
看一看视差滚动的Demo吧。http://webdemos.sourceforge.net/jsplatformer4/jsplatformer4.html
为之漫笔(李松峰),本博客专注于Web前后端技术、移动平台开发技术、交互设计和技术翻译。声明一下,因为时常需要外出审稿,而且基本不带笔记本,所以有时可能会迟一点回复大家的留言。
Demo在Unbutu +chrome 13下, 10多秒以后疯狂闪屏。
李老师~继续加油翻译啊~拭目以待后续章节!~
博主在吗?请教一个问题,我想在CANVAS响应一个鼠标按键事件,但不在定义CANVAS的地方放调用函数名(如只是这样的)
那么该怎么做?
感谢。
呃~后面的章节怎么很久不更新了呀~李老师加油啊~~
好久没逛博客了,呵呵,我来了。
Magnificent weblog! Plenty of helpful information here. I was looking for this.Thanks for sharing!
Hello fellow web master! I truly enjoy your web site! I liked the color of your sidebar.
我来逛逛,顺便帮博主顶一下,嘿嘿
我轻轻的来,就如我轻轻的走,我挥一挥衣袖,留下一条留言。
不管我留或是没留言,你这里总是得有人留的呗!
I hope you will keep updating your content constantly as you have one dedicated reader here.
I just like the approach you took with this subject. It isn’t every day that you discover something so concise and enlightening.
Nice brief and this post helped me alot in my college assignement. Say thank you you as your information.
I searched for something completely different, but found your website! And have to say thanks. Nice read. Will come back.
Thanks for posting! I really enjoyed the report. I’ve already bookmark this article.
I hope you will keep updating your content constantly as you have one dedicated reader here.
你通不通过我的留言,我就在那里,不悲不喜
在这博客用键盘敲下美好的回忆,短暂的幸福真的有点可惜
对于一个前端er,这个肯定要好好学习一下的
Nice read. Will come back.Thanks again for share
很开心能来到博主的博客哦,支持你
宁波市铭富装饰工程有限公司:发光茶几|不锈钢发光茶几|不锈钢茶几|KTV茶几|宁波家装|宁波工装|宁波KTV装修| 是一家专业从事中高档室内装饰、装修、设计、施工为一体的企业,专精别墅、复式、公寓、酒店、娱乐场所和商业空间。
顶一下,支持了啊 呵呵
这行业目前很赚钱吧?
La distruzione di contraffazione e falso una piumini moncler reputazione "Made in Italia", è stata una qualità superiore e un eccellente rappresentante creativo. A proposito di questa attività, Moncler anche diretta contro l’importo dovuto a costare milioni di commercio del mercato nero dei danni collaterali causati dal marchio, ha fatto male i contribuenti e le imprese, ma anche portare un sacco di rischi professionali.
这本书确实值得一读!
nice post it looks very hard i think but i must thank you
我不是读计算机的但我对计算机很感兴趣你的文章则很难得很不错
Hello, this is my first time i visit here. I found so many interesting in your blog especially on how to determine the topic. keep up the good work.
http://www.sunglasseshut.us/ Time did not teach me anything, it taught me not easy to believe the myth. Leave, to make things simple, people become good, like a child, we start again.
继续 !继续 !继续 !
Thus among the “Top 50 China IT Rich List.” He has been awarded the “National Youth self-taught model” “Long March udarnik new model” and so on. In some ways his success is his success in life is to overcome the will of their own success, is to overcome their disability, success is not success to the fate of the bow! http://www.newerahatfactory.com/
后面的章节怎么很久不更新了呀
I have got to run.
Your article is useful for me. It is a good article.
都是啥东西呀看不懂呀
看其来好难哦
Your article is useful for me. It is a good article.
好难哦看不懂呢
期待后续翻译。
也买过你翻译的书籍,支持。
这里把 ApplicationManager 都改变了,
如果要加上前面的移动的笑脸图,就要改动很大了, 有点不解。。。
第一次来,博客很清爽,2012年了,新一年新开始,支持一下。
i5 2300, CPU Usage 40%+ @ 4 cores. Chrome 16.0
It is nice to read the information provided in your blog and i like this information because it is based on reality and i like this information. And it provides knowledge and useful information to the visitors of this site and i would like to visit this site again.
希望博主能多多的分享好的文章给我们读者,十分感谢。