html遊戲引擎,createJs框架

聲明:本文爲原創文章,如需轉載,請註明來源WAxes,謝謝!html

  createJs網上的中文教程挺少的,之前UC有個Xcanvas的論壇有createJs的詳細教程,可是隨着XCanvas團隊的解散,那個網 站也關閉了。。網上的大部分都是很是基礎的教程,有點千遍一概的感受。因此樓主就去把createJs下載下來,硬着頭皮看英文文檔了。憑着樓主這英語六 級只考了三百多分的渣渣來講,看起來很費力啊,不過仍是勉強摸索出了大概的用法。因此如今就是學了多少就記錄多少,以後或許也會不按期更新一下該框架的新 的學習心得。畢竟對本身之後仍是有幫助的。canvas

  閒話說到這,直接進入主題。數組

  樓主用createJs寫了個簡單的跑酷遊戲DEMO,就拿它作例子吧。 看DEMO戳我。瀏覽器

  createJs的由來,基礎什麼的就不說了,就直接說createJs的用法吧。框架

  接下來開始分析代碼:dom

 

1. <script src='easeljs-0.7.1.min.js'></script>
2. <script src='preloadjs-0.4.1.min.js'></script>

 

01. function init(){
02. stage = new createjs.Stage('cas');
03. C_W = stage.canvas.width;
04. C_H = stage.canvas.height;
05.  
06. var manifest = [
07. {src:'image/man.png' , id:'man'},
08. {src:'image/ground.png' , id:'ground'},
09. {src:'image/bg.png' , id:'bg'},
10. {src:'image/high.jpg' , id:'high'},
11. {src:'image/coins.png' , id:'coin'}
12. ]
13.  
14. loader = new createjs.LoadQueue(false);
15. loader.addEventListener('complete' , handleComplete);
16. loader.loadManifest(manifest);
17.  
18. drawLoading();
19. }

 

01. function handleComplete(){        //當圖片素材load完後執行該方法
02. var manImage = loader.getResult('man'),
03. lowground = loader.getResult('ground'),
04. highground = loader.getResult('high'),
05. bgImage = loader.getResult('bg'),
06. coins = loader.getResult('coin');
07.  
08. sky = new createjs.Shape();
09. sky.graphics.bf(bgImage).drawRect(0,0,C_W,C_H);
10. sky.setTransform(001 , C_H/bgImage.height);
11. stage.addChild(sky);
12.  
13. man = createMan(200,326,manImage);
14.  
15. //該框爲斷定角色的斷定區域
16. kuang = new createjs.Shape();
17. kuang.graphics.beginStroke('rgba(255,0,0,0.5)').drawRect(0 0 , man.size().w , man.picsize().h*1.5);
18. // stage.addChild(kuang);
19.  
20. mapHandle(lowground , highground , coins);
21.  
22. createjs.Ticker.timingMode = createjs.Ticker.RAF;//設置循環方法,能夠是requestAnimationFrame或者是setTimeout
23. createjs.Ticker.setFPS(30);//舞臺幀率控制
24. createjs.Ticker.addEventListener('tick', tick);//綁定舞臺每一幀的邏輯發生函數
25.  
26. window.addEventListener('keydown' , function(event){
27. event = event||window.event;
28. if(event.keyCode===32&&man.jumpNum<man.jumpMax){
29. man.jump();
30. }
31. })
32. }

  而後進行舞臺循環設置,上面有註釋了,就不說了。函數

 

001. (function(w){
002. var FRAME_RATE = 13,    //精靈表播放速度
003. SCALE_X = 1.5,    //X軸縮放
004. SCALE_Y = 1.5,    //Y軸縮放
005. GRAVITY = 3,    //重力加速度
006. JUMP_SPEED = 2.6,        //垂直速度
007. WIDTH = 40,
008. HEIGHT = 96,
009. PICWIDTH = 64,
010. PICHEIGHT = 64,
011. PROPORTION = 150/1;  //遊戲與實際的距離比例
012.  
013. var Man = function(x , y , img){
014. this.x = x;
015. this.y = y;
016. this.endy = y;
017. this.vx = 0.5;
018. this.vy = 0;
019. this.ground = [];
020. this.state = 'run';
021. this.jumpNum = 0;
022. this.jumpMax = 1;
023. this.init(img);
024. }
025.  
026. Man.prototype = {
027. constructors:Man,
028.  
029. init:function(img){
030. var manSpriteSheet = new createjs.SpriteSheet({  //實例化精靈表繪製器
031. 'images':[img],
032. 'frames':{'regX':0,'height':PICWIDTH,'count':45,'regY':1,'width':PICHEIGHT},
033. 'animations':{
034. 'run':{
035. frames:[21,20,19,18,17,16,15,14,13,12],    //精靈表每一幀的位置
036. next:'run',                    //當精靈表循環完後的下一步動做
037. speed:1,                      //精靈表播放速度
038. },
039. 'jump':{
040. frames:[34,35,36,37,38,39,40,41,42,43],
041. next:'run',
042. speed:1,
043. },
044. 'die':{
045. frames:[8,7,6,5,4,3,2,1,0],
046. next:'die',
047. speed:1,
048. }
049. }
050. });
051. this.sprite = new createjs.Sprite(manSpriteSheet , this.state);  //實例化精靈
052. this.sprite.framerate = FRAME_RATE;      //精靈表繪製速率
053. this.sprite.setTransform(this.x, this.y, SCALE_X, SCALE_Y);  //設置精靈的位置
054. stage.addChild(this.sprite);    //添加到舞臺
055. },
056.  
057. update:function(){
058. var sprite = this.sprite;
059. var time = createjs.Ticker.getInterval()/1000;    //獲取當前幀與上一幀的時間間隔
060.  
061. if(this.state==='run'){          
062. if(sprite.x<this.x){
063. sprite.x +=this.vx;
064. }else {
065. sprite.x = this.x
066. }
067. }
068. if(this.endy>sprite.y||this.state==='jump'){  //角色的動做處理
069. var nexty = sprite.y+time*this.vy*PROPORTION;
070. this.vy += time*GRAVITY;
071. sprite.y += time*this.vy*PROPORTION;
072. if(Math.abs(sprite.y-this.endy)<10&&this.vy>0){
073. this.state = 'run';
074. sprite.y=this.endy;
075. this.vy = 0;
076. }
077. }
078.  
079. if(sprite.x+(PICWIDTH*SCALE_X-WIDTH)/2<0||sprite.y>C_H+200){
080. this.die();
081. createjs.Ticker.reset();
082. alert('you are Die!');
083. }
084.  
085. switch(this.state){
086. case 'run':
087. this.jumpNum = 0;
088. break;
089. case 'die':
090. if(sprite.currentFrame===0){
091. sprite.paused = true;
092. }
093. break;
094. }
095. },
096.  
097. run:function(){
098. this.sprite.gotoAndPlay('run')
099. },
100.  
101. jump:function(){
102. this.vy = -JUMP_SPEED;
103. this.state = 'jump';
104. this.sprite.gotoAndPlay('jump');  //讓精靈表播放特定的動畫
105. this.jumpNum++;
106. },
107.  
108. die:function(){
109. this.state = 'die';
110. this.sprite.gotoAndPlay('die')
111. },
112.  
113. size:function(){
114. return {
115. w:WIDTH,
116. h:HEIGHT
117. }
118. },
119.  
120. picsize:function(){
121. return {
122. w:PICWIDTH,
123. h:PICHEIGHT
124. }
125. }
126. }
127.  
128. w.createMan = function(x , y , img){
129. return new Man(x , y , img)
130. };
131. })(window)

下面貼出封裝的石頭以及金幣模塊,簡單說下背景的循環,預先實例化一堆石頭和金幣,而後移動響應的石頭,當石頭移動到超出舞臺區域時,把他的visible屬性置爲false,再從新添加一個石頭在最後的位置進行新的一次移動。學習

001. (function(w){
002. var SPEED = 4,
003. COIN_STAY_X = 20,
004. COIN_STAY_Y = 20,
005. COIN_STAY_WIDTH = 30,
006. COIN_STAY_HEIGHT = 30,
007. COIN_SCALE_X = 0.08,
008. COIN_SCALE_Y = 0.08;
009.  
010. //地上的石頭類
011.  
012. var Stone = function(x,kind,allImage){
013. this.x = x;
014. this.kind = kind;
015. this.allImage = allImage;
016. this.init();
017. }
018.  
019. var sp = Stone.prototype;
020.  
021. sp.init=function(){
022. this.shape = new createjs.Shape();
023. if(this.kind!=='C'){
024. this.h = this.allImage[this.kind].height;
025. this.w = this.allImage[this.kind].width*2;
026. this.y = C_H - this.h;
027. this.shape.graphics.beginBitmapFill(this.allImage[this.kind]).drawRect(00this.w, this.h);
028. this.shape.setTransform(this.x, this.y, 11);
029. }else {
030. this.h = -1000;
031. this.w = 170;
032. this.y = C_H - this.h;
033. this.shape.graphics.beginFill('#000').drawRect(00this.w, this.h);
034. this.shape.setTransform(this.x, this.y, 11);
035. }
036. this.shape.visible = false;
037. this.shape.cache(0 0 this.w , this.h);
038. stage.addChild(this.shape);
039. }
040.  
041. sp.update=function(){
042. this.shape.x -= SPEED;
043. }
044.  
045. //金幣類
046. var Coin = function(image){
047. this.sizeX = COIN_SCALE_X;
048. this.sizeY = COIN_SCALE_Y;
049.  
050. this.isget = false;
051. this.init = function(){
052. this.shape = new createjs.Shape();
053. this.shape.graphics.beginBitmapFill(image).drawRect(00, image.width, image.height);
054. this.shape.setTransform(00, COIN_SCALE_X, COIN_SCALE_Y);
055. this.shape.visible = false;
056. stage.addChild(this.shape);
057. }
058. this.init();
059.  
060. this.update = function(){
061. if(this.isget){
062. this.sizeX = this.sizeX + ((COIN_STAY_WIDTH/image.width) - this.sizeX)*0.1;
063. this.sizeY = this.sizeY + ((COIN_STAY_HEIGHT/image.height) - this.sizeY)*0.1;
064. this.shape.setTransform(
065. this.shape.x + (COIN_STAY_X - this.shape.x)*0.1,
066. this.shape.y + (COIN_STAY_Y - this.shape.y)*0.1,
067. this.sizeX,
068. this.sizeY
069. );
070.  
071. if(Math.abs(this.shape.x-COIN_STAY_X)<0.5&&Math.abs(this.shape.y-COIN_STAY_Y)<0.5){
072. this.shape.visible = false;
073. this.isget = false;
074. this.sizeX = COIN_SCALE_X;
075. this.sizeY = COIN_SCALE_Y;
076. this.shape.setTransform(0,0,this.sizeX,this.sizeY);
077. }
078. else{
079. this.shape.x -= SPEED;
080. if(this.shape.x<-image.width*COIN_SCALE_X){
081. this.shape.visible = false;
082. }
083. }
084. }
085.  
086. this.size = function(){
087. return {
088. w:image.width*COIN_SCALE_X,
089. h:image.height*COIN_SCALE_Y
090. }
091. }
092. }
093.  
094. w.createCoin = function(image){
095. return new Coin(image)
096. }
097.  
098. w.createStone = function(x,kind,allImage){
099. return new Stone(x,kind,allImage);
100. }
101. })(window)

最後是舞臺逐幀處理的tick方法:動畫

01. function tick(event){        //舞臺逐幀邏輯處理函數
02. man.update();
03.  
04. kuang.x = man.sprite.x+(man.picsize().w*1.5-man.size().w)/2;    //參考框
05. kuang.y = man.sprite.y;
06.  
07. man.ground.length=0;
08. var cg = stoneHandle();
09.  
10. if(man.ground[0]&&!cg) {
11. man.ground.sort(function(a,b){return b.h-a.h});
12. man.endy = man.ground[0].y-man.picsize().h*1.5;
13. }
14.  
15. allCoins.forEach(function(cc , index){
16. if(cc.shape.visible){
17. if(
18. Math.abs((kuang.x+man.size().w/2) - (cc.shape.x+cc.size().w/2)) <= (man.size().w+cc.size().w)/2&&
19. Math.abs((kuang.y+man.size().h/2) - (cc.shape.y+cc.size().h/2)) <= (man.size().h+cc.size().h)/2&&
20. !cc.isget
21. ){
22. cc.isget = true;
23. countCoin.innerHTML = parseInt(countCoin.innerHTML)+1
24. }
25. cc.update();
26. }
27. })
28.  
29. document.getElementById('showFPS').innerHTML = man.endy
30. stage.update(event)
31. }

在每一幀的處理,就像本身寫遊戲同樣啦,就是把舞臺裏的全部對象逐個進行邏輯運算,進行相應處理。 this

主頁面:

 

001. <!doctype html>
002. <html lang='en'>
003. <head>
004. <meta charset='UTF-8'>
005. <style>
006. /*#cas{margin:auto;display: block;}*/
007. .view{width: 700px;height:500px;position: relative;}
008. #coins{width:90px;height: 70px;line-height: 70px;position:absolute;left:0px;top:0;padding-left: 60px;background:url(image/coins.png) no-repeat;background-size:30px 30px;background-position:20px 20px;font-size: 34px;color: #FFF;}
009. </style>
010. <title>跑酷遊戲</title>
011. <script src='easeljs-0.7.1.min.js'></script>
012. <script src='preloadjs-0.4.1.min.js'></script>
013. <script src='person.js'></script>
014. <script src='otherThings.js'></script>
015. </head>
016. <body>
017. <div class='view'>
018. <canvas id='cas' width='700' height='500'>您的<a href="http://www.it165.net/edu/ewl/" target="_blank" class="keylink">瀏覽器</a>不支持canvas</canvas>
019. <div id='coins'>0</div>
020. </div>
021. <div id='showFPS' style='display: none;'></div>
022. <script>
023. var fps = document.getElementById('showFPS'),
024. countCoin = document.getElementById('coins');
025. var stage , C_W , C_H , loader;
026. var man , ground , sky;
027.  
028. function init(){
029. stage = new createjs.Stage('cas');
030. C_W = stage.canvas.width;
031. C_H = stage.canvas.height;
032.  
033. var manifest = [
034. {src:'image/man.png' , id:'man'},
035. {src:'image/ground.png' , id:'ground'},
036. {src:'image/bg.png' , id:'bg'},
037. {src:'image/high.jpg' , id:'high'},
038. {src:'image/coins.png' , id:'coin'}
039. ]
040.  
041. loader = new createjs.LoadQueue(false);
042. loader.addEventListener('complete' , handleComplete);
043. loader.loadManifest(manifest);
044.  
045. drawLoading();
046. }
047.  
048. function drawLoading(){
049. var ctx = stage.canvas.getContext('2d');
050. ctx.textAlign = 'center';
051. ctx.textBaseline = 'middle';
052. ctx.fillStyle = '#000';
053. ctx.fillRect(0,0,C_W,C_H);
054. ctx.fillStyle = '#FFF';
055. ctx.font = '25px 微軟雅黑';
056. ctx.fillText('Loading...',C_W/2,C_H/2)
057. }
058.  
059. //地圖數據,mapData爲石頭數據,coinCode爲金幣數據
060. var mapData = [
061. 'AAAACBBAAACABBAAACAABBBAAAABAAAAAACABCABCABCAAAABBBBBBAAAAACAAAAAAAAAAAABBBBBBAAAAAACACACACACAAAABBBBAAAAACAAAAAAAAAAAABBBBBBAAAAAACACACACACAABBAAAAAAABBA',
062. 'AAAAAAAACAABAAAAAAAAAAAAAAABBBBBBCBBBBBBBBAAAAAAAAAAAAAAAAAAAAAAAAACACACACACACACACACACBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABBBBBBBBBBBBBCBCBCBCAAAAAAAAAAAAAAAAAA',
063. 'AAAAAAAACAABAAAAAAAAAAAACACACACACACACACABAABABABABABABABACBCBCBCBCBCBCBCBCBCBCBCBCBCBCBCABABACBCBCACACACACACACACACACACACACACACACACACACACACACAAAAAAAAAAAAAAAA'
064. ],
065. coinCode = [
066. '--------##########----------------############-#--#---##############-----------------##########-#-#-#-#-#-#-#-##-------################-------------###',
067. '--#--#-------####----------##----###-----####-#--#---####-#-#-#-######------####------#####-#-#-#-#-#-#-#-##-------################---############--###',
068. '-------#--#-------####----------##----##--##############---------######------####------#####-#-#-#-#-#-#-#-##----------################-------------###'
069. ]
070.  
071. function handleComplete(){        //當圖片素材load完後執行該方法
072. var manImage = loader.getResult('man'),
073. lowground = loader.getResult('ground'),
074. highground = loader.getResult('high'),
075. bgImage = loader.getResult('bg'),
076. coins = loader.getResult('coin');
077.  
078. sky = new createjs.Shape();
079. sky.graphics.bf(bgImage).drawRect(0,0,C_W,C_H);
080. sky.setTransform(001 , C_H/bgImage.height);
081. stage.addChild(sky);
082.  
083. man = createMan(200,326,manImage);
084.  
085. //該框爲斷定角色的斷定區域
086. kuang = new createjs.Shape();
087. kuang.graphics.beginStroke('rgba(255,0,0,0.5)').drawRect(0 0 , man.size().w , man.picsize().h*1.5);
088. // stage.addChild(kuang);
089.  
090. mapHandle(lowground , highground , coins);
091.  
092. createjs.Ticker.timingMode = createjs.Ticker.RAF;
093. createjs.Ticker.setFPS(30);
094. createjs.Ticker.addEventListener('tick', tick);
095.  
096. window.addEventListener('keydown' , function(event){
097. event = event||window.event;
098. if(event.keyCode===32&&man.jumpNum<man.jumpMax){
099. man.jump();
100. }
101. })
102. }
103.  
104.  
105. var mapIndex = 0,        //地圖序列
106. Mix = 0,            //地圖數組的索引
107. allStones = [],        //存放全部的石頭
108. allCoins = [],        //全部金幣
109. showSt = [];        //存放顯示出來的石頭
110.  
111. function mapHandle(lowground , highground , coins){        //初始化地圖
112. allStones.length = 0;
113. var stoneImage = {'A':lowground , 'B':highground},kind = null;
114. for(var i=0;i<30;i++){            //把須要用到的石頭預先放入容器中準備好
115. switch(i){
116. case 0:kind='A';break;
117. case 10:kind='B';break;
118. case 20:kind='C';break;
119. }
120. var st = createStone(C_W , kind , stoneImage);
121. allStones.push(st)
122. }
123.  
124. for(var i=0;i<10;i++){            //把須要用到的金幣預先放入容器中
125. var coin = createCoin(coins);
126. allCoins.push(coin);
127. }
128.  
129. Mix = Math.floor(Math.random()*mapData.length);            //隨機地圖序列
130. for(var i=0;i<8;i++){
131. setStone(false)
132. }
133. }
134.  
135. function setStone(remove){        //添加陸地的石頭
136. var arg = mapData[Mix].charAt(mapIndex),
137. coarg = coinCode[Mix].charAt(mapIndex),
138. cc = null;
139.  
140. if(coarg==='#'){
141. for(var i=0;i<allCoins.length;i++){
142. if(!allCoins[i].shape.visible){
143. cc = allCoins[i];
144. cc.shape.visible = true;
145. break;
146. }
147. }
148. }
149.  
150. for(var z=0;z<allStones.length;z++){
151. if(!allStones[z].shape.visible&&allStones[z].kind===arg){
152. var st = allStones[z];
153. st.shape.visible = true;
154. st.shape.x = showSt.length===0?0:showSt[showSt.length-1].shape.x+showSt[showSt.length-1].w;
155.  
156. if(cc){
157. cc.shape.x = showSt.length===0?allStones[z].w/2-cc.size().w/2:showSt[showSt.length-1].shape.x+showSt[showSt.length-1].w+allStones[z].w/2-cc.size().w/2;
158. cc.shape.y = arg==='C'? C_H-loader.getResult('high').height-50 : allStones[z].shape.y-cc.size().h/2-50;
159. }
160.  
161. if(remove) showSt.shift();
162. showSt.push(st);
163. break;
164. }
165. }
166.  
167. mapIndex++;
168. if(mapIndex>=mapData[Mix].length){
169. Mix = Math.floor(Math.random()*mapData.length)
170. mapIndex=0;
171. }
172. }
173.  
174. function tick(event){        //舞臺逐幀邏輯處理函數
175. man.update();
176.  
177. kuang.x = man.sprite.x+(man.picsize().w*1.5-man.size().w)/2;    //參考框
178. kuang.y = man.sprite.y;
179.  
180. man.ground.length=0;
181. var cg = stoneHandle();
182.  
183. if(man.ground[0]&&!cg) {
184. man.ground.sort(function(a,b){return b.h-a.h});
185. man.endy = man.ground[0].y-man.picsize().h*1.5;
186. }
187.  
188. allCoins.forEach(function(cc , index){
189. if(cc.shape.visible){
190. if(
191. Math.abs((kuang.x+man.size().w/2) - (cc.shape.x+cc.size().w/2)) <= (man.size().w+cc.size().w)/2&&
192. Math.abs((kuang.y+man.size().h/2) - (cc.shape.y+cc.size().h/2)) <= (man.size().h+cc.size().h)/2&&
193. !cc.isget
194. ){
195. cc.isget = true;
196. countCoin.innerHTML = parseInt(countCoin.innerHTML)+1
197. }
198. cc.update();
199. }
200. })
201.  
202. document.getElementById('showFPS').innerHTML = man.endy
203. stage.update(event)
204. }
205.  
206.  
207. function stoneHandle(){        //石頭的逐幀處理  cg爲判斷當前角色的位置是否被阻擋,overStone是保存離開stage的石頭塊
208. var cg = false , overStone = null;
209. allStones.forEach(function(s){   //遍歷石頭,肯定玩家落點
210. if(s.shape.visible){
211. s.update();
212.  
213. if(s.shape.visible&&s.shape.x<=-s.w){
214. overStone = s;
215. }
216.  
217. var juli = Math.abs((kuang.x+man.size().w/2)-(s.shape.x+s.w/2));
218. if(juli<=(man.size().w+s.w)/2 && man.ground.indexOf(s)===-1){
219. man.ground.push(s);
220.  
221. if((s.shape.x+s.w/2)>(kuang.x+man.size().w/2)&&s.y<(kuang.y+man.size().h-10)){
222. man.sprite.x = s.shape.x-man.picsize().w-8;
223. cg = true;
224. }
225. }
相關文章
相關標籤/搜索