原文作者: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



朋友们的留言

  1. llq | 08月 17th, 2011 at 11:22

    Demo在Unbutu +chrome 13下, 10多秒以后疯狂闪屏。

    Reply to this comment
  2. hydRAnger | 08月 23rd, 2011 at 21:27

    李老师~继续加油翻译啊~拭目以待后续章节!~

    Reply to this comment
  3. 烧饼君 | 08月 31st, 2011 at 08:57

    博主在吗?请教一个问题,我想在CANVAS响应一个鼠标按键事件,但不在定义CANVAS的地方放调用函数名(如只是这样的)

    那么该怎么做?

    感谢。

    Reply to this comment
  4. hydRAnger | 08月 31st, 2011 at 22:02

    呃~后面的章节怎么很久不更新了呀~李老师加油啊~~

    Reply to this comment
  5. 识字 | 09月 13th, 2011 at 13:29

    好久没逛博客了,呵呵,我来了。

    Reply to this comment
  6. Jerrod Cucuta | 09月 15th, 2011 at 23:25

    Magnificent weblog! Plenty of helpful information here. I was looking for this.Thanks for sharing!

    Reply to this comment
  7. free porn teen movie | 09月 16th, 2011 at 02:11

    Hello fellow web master! I truly enjoy your web site! I liked the color of your sidebar.

    Reply to this comment
  8. 浙江油烟机 | 09月 20th, 2011 at 15:06

    我来逛逛,顺便帮博主顶一下,嘿嘿

    Reply to this comment
  9. 宁波商务礼品 | 09月 22nd, 2011 at 15:16

    我轻轻的来,就如我轻轻的走,我挥一挥衣袖,留下一条留言。

    Reply to this comment
  10. 厨卫电器厂家 | 09月 26th, 2011 at 11:18

    不管我留或是没留言,你这里总是得有人留的呗!

    Reply to this comment
  11. UGG Highkoo Sale | 09月 27th, 2011 at 10:30

    I hope you will keep updating your content constantly as you have one dedicated reader here.

    Reply to this comment
  12. chi flat iron | 09月 29th, 2011 at 09:49

    I just like the approach you took with this subject. It isn’t every day that you discover something so concise and enlightening.

    Reply to this comment
  13. moncler jackets | 09月 29th, 2011 at 09:52

    Nice brief and this post helped me alot in my college assignement. Say thank you you as your information.

    Reply to this comment
  14. mac makeup | 09月 29th, 2011 at 09:57

    I searched for something completely different, but found your website! And have to say thanks. Nice read. Will come back.

    Reply to this comment
  15. chi flat iron outlet | 09月 29th, 2011 at 10:04

    Thanks for posting! I really enjoyed the report. I’ve already bookmark this article.

    Reply to this comment
  16. tory burch shoes | 09月 29th, 2011 at 10:07

    I hope you will keep updating your content constantly as you have one dedicated reader here.

    Reply to this comment
  17. 厨卫电器厂家 | 10月 8th, 2011 at 13:08

    你通不通过我的留言,我就在那里,不悲不喜

    Reply to this comment
  18. 手拉手会议系统 | 10月 8th, 2011 at 15:01

    在这博客用键盘敲下美好的回忆,短暂的幸福真的有点可惜

    Reply to this comment
  19. welpher.yu | 10月 10th, 2011 at 16:18

    对于一个前端er,这个肯定要好好学习一下的

    Reply to this comment
  20. christian louboutin Boots | 10月 10th, 2011 at 22:25

    Nice read. Will come back.Thanks again for share

    Reply to this comment
  21. 识字 | 10月 11th, 2011 at 16:39

    很开心能来到博主的博客哦,支持你

    Reply to this comment
  22. 宁波不锈钢酒柜|宁波不锈钢门|宁波不锈钢茶几|宁波不锈钢岗亭|宁波发光茶几| | 10月 16th, 2011 at 00:28

    宁波市铭富装饰工程有限公司:发光茶几|不锈钢发光茶几|不锈钢茶几|KTV茶几|宁波家装|宁波工装|宁波KTV装修| 是一家专业从事中高档室内装饰、装修、设计、施工为一体的企业,专精别墅、复式、公寓、酒店、娱乐场所和商业空间。

    Reply to this comment
  23. 金枪鱼罐头 | 10月 19th, 2011 at 21:14

    顶一下,支持了啊 呵呵

    Reply to this comment
  24. LED outdoor lights | 10月 24th, 2011 at 16:46

    这行业目前很赚钱吧?

    Reply to this comment
  25. moncler polo | 11月 4th, 2011 at 17:26

    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.

    Reply to this comment
  26. Office 2010 | 11月 7th, 2011 at 11:09

    这本书确实值得一读!

    Reply to this comment
  27. replica watches uk | 11月 8th, 2011 at 09:56

    nice post it looks very hard i think but i must thank you

    Reply to this comment
  28. chanel replica bags | 11月 8th, 2011 at 09:57

    我不是读计算机的但我对计算机很感兴趣你的文章则很难得很不错

    Reply to this comment
  29. Herve Leger Bandage | 11月 14th, 2011 at 16:23

    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.

    Reply to this comment
  30. the sunglasses hut | 11月 16th, 2011 at 09:55

    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.

    Reply to this comment
  31. 阿杰 | 12月 6th, 2011 at 16:34

    继续 !继续 !继续 !

    Reply to this comment
  32. cheap new era hats | 12月 7th, 2011 at 15:16

    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/

    Reply to this comment
  33. mobile crusher | 12月 7th, 2011 at 17:09

    后面的章节怎么很久不更新了呀

    Reply to this comment
  34. burberry scarf | 12月 15th, 2011 at 09:29

    I have got to run.

    Reply to this comment
  35. cheap newport cigarettes | 12月 21st, 2011 at 14:36

    Your article is useful for me. It is a good article.

    Reply to this comment
  36. 开锁公司 | 12月 24th, 2011 at 02:12

    都是啥东西呀看不懂呀

    Reply to this comment
  37. 会议策划制作| | 12月 24th, 2011 at 02:13

    看其来好难哦

    Reply to this comment
  38. 防锈油 | 12月 24th, 2011 at 02:13

    Your article is useful for me. It is a good article.

    Reply to this comment
  39. 三维动画 | 01月 2nd, 2012 at 00:04

    好难哦看不懂呢

    Reply to this comment
  40. MR 唐 | 01月 5th, 2012 at 09:00

    期待后续翻译。
    也买过你翻译的书籍,支持。

    Reply to this comment
  41. MR 唐 | 01月 5th, 2012 at 09:46

    这里把 ApplicationManager 都改变了,
    如果要加上前面的移动的笑脸图,就要改动很大了, 有点不解。。。

    Reply to this comment
  42. 法国公鸡 | 01月 7th, 2012 at 12:08

    第一次来,博客很清爽,2012年了,新一年新开始,支持一下。

    Reply to this comment
  43. crack86 | 01月 13th, 2012 at 22:19

    i5 2300, CPU Usage 40%+ @ 4 cores. Chrome 16.0

    Reply to this comment
  44. Linux Hosting | 01月 26th, 2012 at 18:00

    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.

    Reply to this comment
  45. 维科 | 02月 21st, 2012 at 17:10

    希望博主能多多的分享好的文章给我们读者,十分感谢。

    Reply to this comment

我来说两句儿

可以在留言中使用以下标签 :<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

Spam Protection by WP-SpamFree