本系列文章由Shin-Knight编写,转载需注明出处。
作者:Shin-Knight
邮箱:shinknight@163.com
文章链接:http://www.cnblogs.com/knightls/p/3281387.html
在笔记一中,我们对html5游戏开发做了一个总的概述,接下来就该轮到实现功能的时候了。在上一章中也提到过,图片是游戏中不可缺少的一部分,因此我们今天就先来实现一下。
首先,我觉得可以先讲一讲本次开发的原理和设计方案:
为了方便以后实现层次化效果,我们可以采用绘画的先后顺序来实现。但是如果说我们有两个层:A和B,如下图放置:
假设我们先画了B层,然后再画了A层。接着,我们往B层上添加个C层,这时候,如果还是将C层直接画在界面上,显示是在A层上,而不是B层上,因此,我们需要不断地重画这个界面。将A层,B层,C层加到显示列表中,通过遍历这个列表进行显示。当然,这是以后涉及到层次化效果的时候要使用的,现在讲讲只是为了理解本文中,我采取重绘界面做法的意义。
由于本次开发涉及到封装,所以暂时给这个项目取名为Tomato2D吧,哈哈。 名字是随便想的,以后或许还会改。
一,TGlobalVar 、TMainWindow和TApplication类
有一些全局的变量和函数为了使用起来不重复,因此定义了一个TGlobalVar静态类,它负责装一些全局变量和函数,以免使用的时候和其他的变量相同。如下:
1 var TGlobalVar = function(){this.type = "TGlobalVar";};
这个以后如果有其他变量加入的话,会慢慢拓展。接下来为了使界面结构更清晰我们还要建立一个TMainWindow和TApplication类。负责全局的驱动和存储一些全局数据。
先看TMainWindow的代码:
1 function TMainWindow(data){ 2 var self = this; 3 4 self.type = "TMainWindow"; 5 6 self.childList = new Array(); 7 self.width = data.width || 200; 8 self.height = data.height || 120; 9 TGlobalVar.TApplicationObj.id = data.id; 10 TGlobalVar.TApplicationObj.frameRate = data.frameRate; 11 } 12 TMainWindow.prototype.init = function(){ 13 var self = this; 14 15 if(TGlobalVar.isAddMainWindow == true)return; 16 TGlobalVar.TMainWindowObj = self; 17 TGlobalVar.isAddMainWindow = true; 18 var w = self.width; 19 var h = self.height; 20 TGlobalVar.TApplicationObj.canvasObj = document.getElementById(TGlobalVar.TApplicationObj.id); 21 TGlobalVar.TApplicationObj.canvasObj.width = w; 22 TGlobalVar.TApplicationObj.canvasObj.height = h; 23 }; 24 TMainWindow.prototype.onShow = function(){ 25 var self = this; 26 if(TGlobalVar.TApplicationObj.canvas == null)return; 27 TGlobalVar.TApplicationObj.canvas.clearRect(0,0,TGlobalVar.TApplicationObj.width,TGlobalVar.TApplicationObj.height); 28 self.show(self.childList); 29 }; 30 TMainWindow.prototype.show = function(showlist,cood){ 31 if(cood == null)cood={x:0,y:0}; 32 var key = null; 33 for(key in showlist){ 34 if(showlist[key].show){ 35 showlist[key].show(cood); 36 } 37 } 38 };
这个类实例化的时候有一个参数,是一个json对象,格式如下:
1 { 2 id:canvas的id, 3 canvas的宽, 4 height:canvas的高, 5 frameRate:刷新频率 6 }
然后调用TMainWindow的init时,会自动保存这些数据,在其中用到了TGlobalVar.isAddMainWindow,TGlobalVar.TMainWindowObj,TGlobalVar.TApplicationObj这几个变量,其中TGlobalVar.isAddMainWindow是用来判断是否已经init过TMainWindow,因为界面上不可能有两个TMainWindow,所以用这个加以限制,而TGlobalVar.TMainWindowObj是用来保存界面上TMainWindow的变量,TGlobalVar.TApplicationObj是用来保存界面上TApplication对象的变量。
在TMainWindow类中,还有个onShow和show方法,这两个方法是用来刷新界面用的。onShow是负责清空界面和调用show方法用的。在show方法中通过遍历TMainWindow里的childList,调用遍历到的元素的show方法,实现重绘,也就是说,在childList里的元素必须有show方法才行。onShow方法在TApplication中会用到。
具体TApplication里的代码如下:
1 function TApplication(){ 2 var self = this; 3 self.type = "TApplication"; 4 self.canvas = null; 5 self.canvasObj = null; 6 self.frameRate = 50; 7 self.objectIndex = 0; 8 self.id = null; 9 self.driver = null; 10 11 TGlobalVar.TApplicationObj = self; 12 } 13 TApplication.prototype.exec = function(){ 14 var self = this; 15 16 if(TGlobalVar.isAddApplication == true)return; 17 TGlobalVar.isAddApplication = true; 18 self.canvas = self.canvasObj.getContext("2d"); 19 self.driver = setInterval(function(){TGlobalVar.TMainWindowObj.onShow();},self.frameRate); 20 };
这个类应该是在TMainWindow前实例化,否则就会报错。但是在调用成员函数exec时,要在TMainWindow对象调用init之后调用。这个exec相当于是一个开启游戏重画的函数,也就是说,不调用这个函数界面将不能重画。在exec中又用到了TGlobalVar.isAddApplication这个变量,它和上文的TGlobalVar.isAddMainWindow的用途差不多,只不过一个是用来判断是否加入了TMainWindow对象,另一个是用来判断是否加入了TApplication对象。也就是说,我们使用的时候只能有一个TMainWindow对象和一个TApplication对象。用TGlobalVar.TApplicationObj和TGlobalVar.TMainWindowObj分别保存TApplication和TMainWindow对象是为了方便以后的操作。看到下面你就会明白。
因为在TGlobalVar中加了几个成员属性,因此修改TGlobalVar,完整TGlobalVar代码如下:
1 var TGlobalVar = function(){this.type = "TGlobalVar";}; 2 TGlobalVar.TApplicationObj = null; 3 TGlobalVar.TMainWindowObj = null; 4 TGlobalVar.isAddApplication = false; 5 TGlobalVar.isAddMainWindow = false;
有了这些,我们就可以用来显示图片了~~
二,用于显示图片的TImage类
上面我们已经把一些公有属性都保存好了,因此我们要实现绘画就很简单了。先看TImage类的代码:
1 function TImage(){ 2 var self = this; 3 4 self.type = "TImage"; 5 self.x = 0; 6 self.y = 0; 7 self.scaleX = 1; 8 self.scaleY = 1; 9 self.isLoadComplete = false; 10 self.content = null; 11 self.sx = 0; 12 self.sy = 0; 13 self.swidth = 0; 14 self.sheight = 0; 15 self.width = 0; 16 self.height = 0; 17 self.toSwidth = self.swidth; 18 self.toSheight = self.sheight; 19 self.toSx = self.sx; 20 self.toSy = self.sy; 21 } 22 TImage.prototype.load = function(u){ 23 var self = this; 24 self.isLoadComplete = false; 25 self.content = new Image(); 26 self.content.onload = function(){ 27 self.content.onload = null; 28 self.swidth = self.content.width; 29 self.sheight = self.content.height; 30 self.width = self.content.width; 31 self.height = self.content.height; 32 self.isLoadComplete = true; 33 }; 34 self.content.src = u; 35 }; 36 TImage.prototype.draw = function(layer){ 37 var self = this; 38 if(!layer)layer = TGlobalVar.TMainWindowObj; 39 layer.childList.push(self); 40 self.parent = layer; 41 }; 42 TImage.prototype.scale = function(scaleX,scaleY){ 43 var self = this; 44 45 self.scaleX = scaleX || self.scaleX; 46 self.scaleY = scaleY || self.scaleY; 47 }; 48 TImage.prototype.move = function(x,y){ 49 var self = this; 50 51 self.x = x || self.x; 52 self.y = y || self.y; 53 }; 54 TImage.prototype.setProperties = function(sx,sy,swidth,sheight){ 55 var self = this; 56 57 self.toSwidth = swidth || self.swidth; 58 self.toSheight = sheight || self.sheight; 59 self.toSx = sx || self.sx; 60 self.toSy = sy || self.sy; 61 }; 62 TImage.prototype.show = function(){ 63 var self = this; 64 65 if(self.isLoadComplete == false)return; 66 self.swidth = self.toSwidth || self.swidth; 67 self.sheight = self.toSheight || self.swidth; 68 self.sx = self.toSx || 0; 69 self.sy = self.toSy || 0; 70 self.width = self.swidth; 71 self.height = self.sheight; 72 73 TGlobalVar.TApplicationObj.canvas.drawImage( 74 self.content, 75 self.sx,self.sy, 76 self.swidth,self.sheight, 77 self.x,self.y, 78 self.width*self.scaleX, 79 self.height*self.scaleY 80 ); 81 };
这里面的代码不难理解,显示图片的部分主要在show函数中。要加载图片需要在load函数中加载,也就是说,要显示图片需要先load一遍。另外,为了show函数并不需要自己去调用,在TGlobalVar.TMainWindowObj.show里面已经自动调用了。不过要显示图片要调用draw函数,这个函数有个参数,这个参数代表显示层,不添的话就是默认的最底层,这个参数现在只能不赋值,因为现在还没实现到层次化这一部分。
要移动图片的话,调用move方法就可以了。参数:[x坐标, y坐标]
要设置显示部分图片调用setProperties就行了,参数是:[图片可视范围x, 图片可视范围y, 图片可视范围宽度, 图片可视范围高度]
要拉伸图片就调用scale函数,参数[x轴拉伸倍数, y轴拉伸倍数]
好了,我们有了TImage类,就来做个测试吧,测试代码:
1 <!DOCTYPE html> 2 <html> 3 <head> 4 <meta charset="utf-8" /> 5 <title>显示一张图片</title> 6 <script src="./TMain.js"></script> 7 <script src="./TApplication.js"></script> 8 <script src="./TMainWindow.js"></script> 9 <script src="./TImage.js"></script> 10 <script> 11 function main(){ 12 var app = new TApplication(); 13 var mainwindow = new TMainWindow({ 14 id:"tomatogame", 15 800, 16 height:600, 17 frameRate:50 18 }); 19 mainwindow.init(); 20 app.exec(); 21 showImage(); 22 } 23 function showImage(){ 24 var img = new TImage(); 25 img.load("./face.jpg"); 26 img.draw(); 27 img.move(20,20); 28 img.scale(0.5,0.8); 29 30 var img2 = new TImage(); 31 img2.load("./face.jpg"); 32 img2.draw(); 33 img2.move(150,150); 34 img2.setProperties(100,100,200,200); 35 } 36 </script> 37 </head> 38 <body onload="main()"> 39 <canvas id="tomatogame"></canvas> 40 </body> 41 </html>
运行出来的界面如下:
over,是不是很简单?下一次我们来实现一下层次化效果。敬请期待~~
源代码下载:点击这里下载源代码
如果大家有不懂的地方,欢迎在文章下方留言。能看到你们的留言,是我最开心的事了~~如果文章有疏漏的地方,也欢迎指出,多谢大家的支持。