【原創】使用JS封裝的一個小型遊戲引擎及源碼分享



1
/** 2 * @description: 引擎的設計與實現 3 * @user: xiugang 4 * @time: 2018/10/01 5 */ 6 7 /* 8 * V1.0: 引擎實現的基本模塊思路 9 * 1.建立一個遊戲引擎對象及精靈對象 10 * 2.將精靈對象添加到引擎中去,並實現播放動畫效果以及須要用到的回調方法 11 * 3.啓動引擎 12 * */ 13 14 /* 15 * V2.0: 實現遊戲循環模塊 16 * 1.若是遊戲暫停了,就跳過如下各步驟,並在100毫秒後再次執行遊戲循環 17 * 2.更新幀速率 18 * 3.設置遊戲時間 19 * 4.清除屏幕內容 20 * 5.在播放動畫前,調用startAnimate的方法(能夠進行碰撞檢測) 21 * 6.繪製精靈背後的內容(繪製背景) 22 * 7.更新精靈 23 * 8.繪製精靈 24 * 9.繪製精靈前方的內容 25 * 10.動畫播放完畢以後,調用endAnimate方法 26 * 11.請求瀏覽器播放下一幀動畫 27 * 28 * */ 29 30 31 /** 32 * V3.0: 實如今暫停狀態與運行狀態之間的切換togglePaused 33 */ 34 35 /** 36 * V4.0:實現基於時間的運動效果 :pixelPerFrame 37 * 計算公式:(pixels / second) * (second / frame) = pixeld / second【單位:每一秒移動的像素數】 38 */ 39 40 /** 41 * V5.0: 實現加載圖像的功能: 42 * queueImage(imageUrl): 將圖像放入到加載隊列中去 43 * loadImages(): 開發者須要持續調用該方法,知道返回100位置(方法的返回值表示圖像加載完成的百分比) 44 * getImage(imageUrl):返回圖像對象, 只有咋loadImages()返回100以後,才能夠調用該方法 45 */ 46 47 /** 48 * V6.0:實現同時播放多個聲音的功能 49 * canPlay(): 用於查詢瀏覽器是否可以播放某種特定格式的聲音文件 50 * playSound():用於播放聲音 51 */ 52 53 54 /** 55 * V7.0: 鍵盤事件的處理 56 * addKeyListener(): 用於向遊戲註冊按鍵監聽器 57 */ 58 59 60 /** 61 * V8.0: 高分榜的維護:遊戲的高分榜數組以json格式存檔在本地 62 */ 63 64 /** 65 * V9.0: 實現了一個比較完整的遊戲引擎,開始使用這個簡單的遊戲引擎去製做一個小遊戲 66 * 需求分析: 67 * 1.資源加載的畫面 68 * 2.遊戲資源的管理 69 * 3.聲音的播放 70 * 4.具備視差動畫的滾動背景 71 * 5.生命數量的顯示 72 * 6.高分榜的維護 73 * 7.按鍵的監聽與處理 74 * 8.暫停功能與自動暫停機制實現 75 * 9.遊戲結束的流程處理 76 */ 77 78 79 /** 80 * 遊戲類 81 * @param gameName 遊戲名稱 82 * @param canvasId 畫布ID 83 * @returns {Game} 遊戲實例 84 * @constructor 85 */ 86 var Game = function (gameName, canvasId) { 87 // 獲取canvas畫布 88 var canvas = document.getElementById(canvasId); 89 console.log(canvas); 90 var self = this; 91 92 93 //----------------------------------------基本屬性 94 this.context = canvas.getContext('2d'); // 定義遊戲中的基本須要的屬性 95 this.sprites = []; // 遊戲中的精靈對象 96 this.gameName = gameName; // 遊戲的名字 97 98 99 //----------------------------------------時間管理 100 this.startTime = 0; // 遊戲開始時間 101 this.lastTime = 0; // 遊戲上一次的時間 102 this.gameTime = 0; // 遊戲總時間 103 this.fps = 0; // 遊戲幀速率(實時更新的) 104 this.STARTING_FPS = 60; // 默認啓動的時候的幀速率 105 106 this.paused = false; // 遊戲是否暫停 107 this.startedPauseAt = 0; 108 this.PAUSE_TIMEOUT = 100; // 遊戲暫停的持續時間 109 110 111 //---------------------------------------圖像加載 112 this.imageLoadingProgressCallback; // 圖像加載過程的回調函數 113 this.images = {}; // 圖像對象 114 this.imageUrls = []; // 圖像的Urls 115 this.imagesLoaded = 0; // 已加載完成的圖像個數 116 this.imagesFailedToLoad = 0; // 加載失敗的圖像個數 117 this.imagesIndex = 0; // 圖像數組的下標, 從0開始的 118 119 120 121 //-----------------------------------------聲音加載播放 122 this.soundOn = true; 123 this.soundChannels = []; // 初始化一個播放信道數組 124 this.audio = new Audio(); // 這裏的Audio其實是JavaScript內置的DOM對象, 不須要本身手動去建立一個Audio對象 125 this.NUM_SOUND_CHANNELS = 10; // 設置初始信道的數量 126 127 128 129 //----------------------------------------鍵盤事件的監聽 130 this.keyListeners = []; // 用於存放keyandListener的鍵值對 131 132 window.onkeypress = function (ev) { // 這裏的對象處理的是DOM Window這個窗體對象,添加了一個監聽事件 133 self.keyPressed(ev); 134 } 135 window.onkeydown = function (ev) { 136 self.keyPressed(ev); 137 } 138 139 140 //-----------------------------------------高分榜的維護 141 this.HIGH_SCORES_SUFFIX = '_highscores'; // 後綴名字 142 this.highScores = []; // 用於存儲遊戲分數的數組 143 144 145 146 // 構造10個Audio對象,將其加入到數組中去, 當調用playSound()方法,遊戲引擎會找出第一個未被佔用的聲道,並用它來播放指定的聲音文件 147 for (var i = 0; i < this.NUM_SOUND_CHANNELS; i++){ 148 var audio = new Audio(); 149 this.soundChannels.push(audio); 150 } 151 152 return this; // 把當前的遊戲對象返回 153 } 154 155 156 157 158 /** 159 * 遊戲的成員方法 160 * @type {{start: Game.start, animate: Game.animate, tick: Game.tick, updateFrameRate: Game.updateFrameRate, clearScreen: Game.clearScreen, startAnimate: Game.startAnimate, paintUnderSprites: Game.paintUnderSprites, updateSprites: Game.updateSprites, paintSprites: Game.paintSprites, paintOverSprites: Game.paintOverSprites, endAnimate: Game.endAnimate}} 161 */ 162 Game.prototype = { 163 // 遊戲加載圖像的模塊------------------------------------------------------- 164 /** 165 * 經過圖像的Url地址,獲取這個圖像(json格式對象取出值的方法)對象 166 * @param imageUrl 167 */ 168 getImage : function (imageUrl) { 169 return this.images[imageUrl]; 170 }, 171 172 173 174 /** 175 * 圖像加載完成的回調函數 176 */ 177 imageLoadedCallback : function (e) { 178 // 每次加載完成一個圖像,次數加一 179 this.imagesLoaded++; 180 }, 181 182 183 184 /** 185 * 當一個圖像加載失敗的回調函數 186 */ 187 imageLoadErrorCallback : function (e) { 188 this.imagesFailedToLoad++; 189 }, 190 191 192 /** 193 * 正式加載一張圖像 194 * @param imageUrl 195 */ 196 loadImage : function (imageUrl) { 197 var self = this; 198 var image = new Image(); 199 200 image.src = imageUrl; 201 202 // 圖像加載完成的回調函數 203 204 image.addEventListener("load", function (e) { 205 self.imageLoadedCallback(e); 206 207 // 顯示出來, 測試成功 208 //self.context.drawImage(image, 0, 0); 209 }); 210 211 212 // 圖像加載失敗的回調函數 213 image.addEventListener("error", function (e) { 214 self.imageLoadErrorCallback(e); 215 }); 216 217 218 // 把全部的加載的Images存起來 219 this.images[imageUrl] = image; 220 }, 221 222 /** 223 * 加載圖像的過程當中反覆調用這個函數, 這個函數返回已經處理完成的圖像百分比 224 * 當圖像返回100%的時候, 表示全部的圖像已經所有加載完畢 225 * @returns {number} 226 */ 227 loadImages : function () { 228 // 若是還有圖像沒有加載【圖像的url個數多餘已經加載完成的圖像下標】 229 if (this.imagesIndex < this.imageUrls.length){ 230 // 再次把當前這個圖像去加載(把沒有加載的所有加載進來) 231 this.loadImage(this.imageUrls[this.imagesIndex]); 232 this.imagesIndex ++; 233 } 234 235 236 // 返回已經加載完成的圖像百分比(加載成功的個數+加載失敗的個數 佔整個事先提供的全部URL個數的百分比) 237 var percentage = (this.imagesLoaded + this.imagesFailedToLoad) / this.imageUrls.length * 100; 238 console.log(percentage); 239 return (this.imagesLoaded + this.imagesFailedToLoad) / this.imageUrls.length * 100; 240 }, 241 242 /** 243 * 用於把全部的圖像URL放在一個隊列裏面【數組】 244 * @param imageUrl 245 */ 246 queueImage : function (imageUrl) { 247 this.imageUrls.push(imageUrl); 248 }, 249 250 251 252 253 254 // 遊戲循環模塊--------------------------------------------------------------- 255 start: function () { 256 var self = this; 257 258 this.startTime = +new Date(); // 獲取遊戲當前的時間 259 console.log("遊戲啓動成功, 當前時間:", this.startTime); 260 261 262 // 開始遊戲循環(這是一個系統實現的幀速率方法) 263 window.requestNextAnimationFrame( 264 function (time) { 265 // self is the game, and this is the window 266 console.log(self, this); 267 // 每次把遊戲實例對象的引用和當前的時間傳過去 268 self.animate.call(self, time); // self is the game 269 } 270 ); 271 }, 272 273 animate: function (time) { 274 // 這裏的this 指向的是Game對象 275 var self = this; 276 277 if (this.paused) { 278 // 若是用戶暫停了遊戲,而後每隔100ms的時間檢查一次去看一下有沒有開始循環 279 // (因爲遊戲暫停的狀況不會頻繁出現,所以使用setTimeout()方法就能夠知足咱們的需求, 每隔100ms去看一次) 280 281 setTimeout(function () { 282 self.animate.call(self, time); 283 }, this.PAUSE_TIMEOUT); 284 } 285 // 沒有暫停的話 286 else { 287 this.tick(time); // 1.更新幀速率, 設置遊戲時間 288 this.clearScreen(); // 2.清空屏幕內容 289 290 // 碰撞檢測代碼 291 292 this.startAnimate(time); // 3.開始遊戲動畫 293 this.paintUnderSprites(); // 4.繪製精靈後面的內容---背景 294 295 this.updateSprites(time); // 5.更新精靈的位置 296 this.paintSprites(time); // 6.繪製精靈 297 298 this.paintOverSprites(); // 7.繪製精靈前方的內容 299 this.endAnimate(); // 8.動畫結束 300 301 302 // 回調這個方法, 開始進入到下一幀動畫 303 window.requestNextAnimationFrame( 304 function (time) { 305 console.log(self, this); 306 // 注意這裏不能直接傳過去哈, 若是直接傳過去的話,第一個參數就是就會把time 的指向修改成Game這個類 307 // self.animate(self, time); 308 // 第一個參數是用來校訂animate函數內部的this的指向, 第二個參數是用來傳遞animate()函數執行須要的參數 309 self.animate.call(self, time); 310 } 311 ); 312 } 313 }, 314 togglePaused : function () { 315 // 這是一個遊戲暫停的方法 316 var now = +new Date(); // 獲取遊戲暫停的那個時間點 317 318 this.paused = !this.paused; // 每次在暫停與不暫停之間來回切換 319 320 if (this.paused){ 321 // 若是遊戲暫停了(暫停的那個時間點就是當前的時間) 322 this.startedPauseAt = now; 323 }else{ 324 // 沒有暫停的話:調整開始的時間, 使得遊戲開始是從點擊開始遊戲以後就開始計時的 325 // this.startTime 記錄的是:開始時間 + 當前時間 - 遊戲上一次暫停的時間點 326 // now - this.startedPauseAt = 遊戲暫停的時長, 而後再加上游戲開始的時候的時間,就能從原來的暫停位置處繼續執行下去 327 this.startTime = this.startTime + now - this.startedPauseAt; 328 this.lastTime = now; 329 } 330 }, 331 // 實現動畫中須要實現的功能 332 /** 333 * // 1.更新幀速率(實現基於時間的運動效果) 334 * @param time 335 */ 336 tick: function (time) { 337 // 1. 更新幀幀速率 338 this.updateFrameRate(time); 339 340 // 2. 設置遊戲時間(每一幀間隔的時間) 341 this.gameTime = (+new Date()) - this.startTime; 342 console.log("設置遊戲的時間:" + this.gameTime); 343 this.lastTime = time; 344 345 }, 346 updateFrameRate: function (time) { 347 // 啓動時候的幀速率 348 if (this.lastTime === 0) { 349 this.fps = this.STARTING_FPS; 350 } 351 else { 352 // 計算當前的幀速率(每秒執行的幀數) 353 this.fps = 1000 / (time - this.lastTime); 354 console.log("實時更新遊戲當前的幀速率", this.fps); 355 } 356 357 }, 358 /** 359 * 實現基於時間的運動效果 360 * @param time 361 * @param velocity 362 */ 363 pixelsPerFrame : function (time, velocity) { 364 // 是動畫平滑地運動起來 365 // 計算公式:(pixels / second) * (second / frame) = pixeld / second【單位:每一秒移動的像素數】 366 return velocity / this.fps; 367 }, 368 369 /** 370 * // 2.清空屏幕內容 371 */ 372 clearScreen: function () { 373 // 注意this.context.canvas.width, this.context.canvas.height 用於獲取畫布的寬度和高度 374 // this.context.clearRect(0, 0, this.canvas.width, this.canvas.height); 375 this.context.clearRect(0, 0, this.context.canvas.width, this.context.canvas.height); 376 console.log("畫布屏幕清空成功!"); 377 }, 378 379 380 /** 381 * // 3.開始遊戲動畫 382 * @param time 383 */ 384 startAnimate: function (time) { 385 console.log(time, "開始遊戲動畫………………"); 386 }, 387 /** 388 * // 4.繪製精靈後面的內容 389 */ 390 paintUnderSprites: function () { 391 console.log("繪製精靈後面的內容!"); 392 }, 393 /** 394 * // 5. 更新精靈的位置 395 * @param time 396 */ 397 updateSprites: function (time) { 398 console.log("更新全部精靈的位置!"); 399 for (var i = 0; i < this.sprites.length; i++) { 400 var sprite = this.sprites[i]; 401 // 從新繪製精靈(調用每個精靈本身的方法去繪製顯示) 402 sprite.update(this.context, time); 403 } 404 }, 405 406 // 6.繪製全部可見的精靈對象 407 paintSprites: function (time) { 408 console.log("繪製全部可見的精靈對象"); 409 for (var i = 0; i < this.sprites.length; i++) { 410 var sprite = this.sprites[i]; 411 // 繪製以前須要先判斷一下 412 if (sprite.visible) { 413 sprite.paint(this.context); //繪製精靈的時候須要拿到繪製精靈的繪圖句柄 414 } 415 } 416 }, 417 418 // 7. 繪製精靈前方的內容 419 paintOverSprites: function () { 420 console.log("繪製精靈前面的內容!"); 421 }, 422 // 8. 繪製動畫結束 423 endAnimate: function () { 424 console.log("繪製動畫結束!"); 425 }, 426 427 428 429 430 // 聲音文件加載播放的模塊---------------------------------------------------------- 431 /** 432 * 瀏覽器是否支持ogg格式的文件 433 * @returns {boolean} 434 */ 435 canPlayOggVorbis : function () { 436 // 只要返回的有內容,就說明瀏覽器支持這個文件格式 437 return "" != this.audio.canPlayType('audio/ogg; codecs="vorbis"'); 438 }, 439 440 /** 441 * 瀏覽器是否支持MP3格式的音樂播放 442 * @returns {boolean} 443 */ 444 canPlayMp3 : function () { 445 // 返回的內容不爲空,說明支持 446 return "" != this.audio.canPlayType('audio/mpeg'); 447 }, 448 449 /** 450 * 用於返回當前系統中可使用的信道 451 * @returns {*} 452 */ 453 getAvailableSoundChannel : function () { 454 var audio; 455 456 // 遍歷初始化中的全部信道 457 for (var i = 0; i < this.NUM_SOUND_CHANNELS; i++){ 458 audio = this.soundChannels[i]; 459 // 若是當前的audio信道已經開始播放了(並且已經播放的信道數量不爲空) 460 if (audio.played && audio.played.length > 0){ 461 // 若是當前的信道已經播放完畢了音樂 462 if (audio.ended){ 463 return audio; 464 } 465 } else{ 466 // 若是當前的信道已經播放完畢音樂了, 就返回當前的這個audio對象 467 if (!audio.ended) 468 return audio; 469 } 470 } 471 472 // 若是全部的信道都在使用的話,就返回undifined 473 return undefined; 474 }, 475 /** 476 * 用於播放指定ID的音樂 477 * @param id 478 */ 479 playSound : function (id) { 480 // 獲取當前可使用的一個信道 481 var track = this.getAvailableSoundChannel(), 482 element = document.getElementById(id); 483 484 485 // 若是不爲空(undefined) 486 if (track && element){ 487 // 獲取當前選中的媒體資源的URL地址 488 track.src = element.src === '' ? element.currentSrc : element.src; 489 490 // 加載並播放音樂 491 track.load(); 492 track.play(); 493 494 } 495 }, 496 497 498 499 // 鍵盤事件的監聽與處理操做--------------------------------------------- 500 /** 501 * 把一個鍵值對添加到監聽數組中去 502 * @param keyAndListener 503 */ 504 addKeyListener : function (keyAndListener) { 505 this.keyListeners.push(keyAndListener); 506 }, 507 508 /** 509 * 經過key來查找相應的listener對象 510 * @param key 511 * @returns {undefined} 512 */ 513 findKeyListener : function (key) { 514 var listener = undefined; 515 516 // 遍歷全部的keyListeners數組 517 for (var i = 0; i < this.keyListeners.length; i++){ 518 // 拿到當前的鍵值監聽對象及按鍵的key值 519 var keyAndListener = this.keyListeners[i], 520 currentKey = keyAndListener.key; 521 522 // 若是按下的按鍵是在我今天按下的全部keyAndListener中,就獲得了這個listener 523 if (currentKey === key){ 524 listener = keyAndListener.listener; 525 } 526 } 527 528 return listener; 529 }, 530 531 /** 532 * 鍵盤按下的回調事件 533 * @param e 534 */ 535 keyPressed : function (e) { 536 var listener = undefined, 537 key = undefined; 538 539 switch (e.keyCode){ 540 // 添加一些經常使用的按鍵處理鍵值對 541 case 32: 542 key = 'space'; 543 break; 544 case 65: 545 key = 'a'; 546 break; 547 case 83: 548 key = 's'; 549 break; 550 case 80: 551 key = 'p'; 552 break; 553 case 87: 554 key = 'w'; 555 break; 556 // 記憶:左上右下的順序,依次爲:37 38 39 40 557 case 37: 558 key = 'left arrow'; 559 break; 560 case 39: 561 key = 'right arrow'; 562 break; 563 case 38: 564 key = 'up arrow'; 565 break; 566 case 40: 567 key = 'down arrow'; 568 break; 569 } 570 571 // 獲取當前按下的按鍵的監聽事件 572 listener = this.findKeyListener(key); 573 if (listener){ 574 listener(); // 這裏的listener是一個監聽函數,若是按下的按鍵有監聽事件的處理,就去處理這個監聽事件 575 } 576 577 }, 578 579 580 581 // 高分榜的維護管理模塊---------------------------------------------------- 582 /** 583 * 從本地存儲中獲取存儲的數據(返回的是一個本地存儲的高分列表) 584 * @returns {any} 585 */ 586 getHighScores : function () { 587 // 把key的值存儲起來 588 var key = this.gameName + this.HIGH_SCORES_SUFFIX, 589 highScoresString = localStorage[key]; 590 591 592 // 若是爲空的話,返回一個空的Json數據 593 if (highScoresString == undefined){ 594 localStorage[key] = JSON.stringify([]); 595 } 596 597 // 使用JSON解析字符串內容(返回的是一個JSon與key相對應的數值內容) 598 return JSON.parse(localStorage[key]); 599 }, 600 /** 601 * 存儲內容到本地存儲 602 * @param highScore 603 */ 604 setHighScore : function (highScore) { 605 // unshift() 方法不建立新的建立,而是直接修改原有的數組【會在數組的頭部插入新的元素】 606 var key = this.gameName + this.HIGH_SCORES_SUFFIX, 607 highScoresString = localStorage[key]; 608 609 610 611 // 主要目的是把每一次最高分放在數組的第一位置,方便查看和管理 612 // 這裏的highScores數組,是一個用戶初始化的數組(全局變量)【數組的第一個元素始終是最高分】 613 //this.highScores.unshift(highScore);(每次都在原理的基礎上添加數據) 614 if (this.highScores.length === 0){ 615 this.highScores = this.getHighScores(); 616 } 617 this.highScores.unshift(highScore); 618 619 620 // 遊戲的key始終是唯一的,每一次都將會修改成最新的狀態 621 localStorage[key] = JSON.stringify(this.highScores); 622 }, 623 624 /** 625 * 清空高分榜(清空瀏覽器的本地存儲) 626 */ 627 clearHighScores : function () { 628 // 直接把相應的鍵對應的值設置爲空便可 629 localStorage[this.name + this.HIGH_SCORES_SUFFIX] = JSON.stringify([]); 630 } 631 632 }

下面的是一個測試案例:javascript

 

功能實現的比較簡單,可是也就是對上面的這個引擎的基本使用吧。css

 

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Game 1.0</title>
    <!--引入須要的css文件, 注意這裏的引入使用的是link方式來引入css文件-->
    <link rel='stylesheet' type='text/css' href='css/Main.css'/>
</head>
<body>
<!--canvas畫布-->
<canvas id="gameCanvas" width="580" height="600">
    Canvas not supported in your browser!
</canvas>


<!--canvas上方的懸浮div-->
<div id="loadingToast">
    <span id="gameTitle">Engine Development</span>
    <span id="loadingContents">
        <p class="mainFunctions">
            主要功能:
        </p>


        <ul class="Contents">
            <li>1.資源加載的畫面</li>
            <li>2.遊戲資源的管理</li>
            <li>3.聲音的播放</li>
            <li>4.具備視差動畫的滾動背景</li>
            <li>5.生命數量的顯示</li>
            <li>6.高分榜的維護</li>
            <li>7.按鍵的監聽與處理</li>
            <li>8.暫停功能與自動暫停機制實現</li>
            <li>9.遊戲結束的流程處理</li>
        </ul>

    </span>

    <span id="loadButtonSpan">
            <button autofocus="true" id="loadButton">載入引擎...</button><br/>
            <span id="loadingMessage">Loading……</span>
        </span>
    <!--用於顯示進度條-->
    <div id="progressDiv">
    </div>

</div>


<!--左上角計時器-->
<div id="gameTimerDiv">
    <span>000</span>
</div>
<!--右上角生命值-->
<div id="leftLives">
    <span id="lifeValue">生命值:100</span>
</div>

<!--中部的暫停-->
<div id="pausedToast">
    <span>暫停</span><br/>
    <span>點擊此區域任意位置繼續</span>
</div>



<!--中下位置的點擊按鈕-->
<div id="loseLifePanel">
    <button id="loseLifeButton" onmouseover="this.style.backgroundColor='#00aced'"
            onmouseleave="this.style.backgroundColor = ''">開殺
    </button>
</div>



<!--遊戲結束及高分榜-->
<div id="gameoverPan">
    <div id="topPan">
        <span id="scoreText">140</span>
    </div>
    <div id="middlePan">
        <span>High Score!</span><br/>
        <span class="Name">What's your name?</span><br/>

        <input id='playerName' type='text' autofocus='true'><button id="addMyScoreButton">添加</button><button id="newGameButton">新遊戲</button>
    </div>
    <div id="downPan">
        <span>Previous High Scores</span>
        <ul id="highScoreList">
        </ul>
    </div>
</div>


<!--遊戲播放音樂須要使用的音頻文件; preload 屬性規定是否在頁面加載後載入音頻。-->
<audio id="pop" preload="auto">
    <source src="sounds/pop.ogg" type="audio/ogg">
    <source src="sounds/pop.mp3" type="audio/mp3">
</audio>
<audio id="whoosh" preload="auto">
    <source src="sounds/whoosh.ogg" type="audio/ogg">
    <source src="sounds/whoosh.mp3" type="audio/mp3">
</audio>



<!--引入須要的js文件-->
<script type="text/javascript" src="Engine/progressbar.js"></script>
<script type="text/javascript" src="Engine/requestNextAnimationFrame.js"></script>
<script type="text/javascript" src="Engine/GameEngine1.0.js"></script>
<script type="text/javascript" src="js/Main.js"></script>
</body>
</html>

  

 

實現的功能基本介紹:(目前是開發期間的9個版本及功能介紹)

/*
* V1.0: 引擎實現的基本模塊思路
* 1.建立一個遊戲引擎對象及精靈對象
* 2.將精靈對象添加到引擎中去,並實現播放動畫效果以及須要用到的回調方法
* 3.啓動引擎
* */

/*
* V2.0: 實現遊戲循環模塊
* 1.若是遊戲暫停了,就跳過如下各步驟,並在100毫秒後再次執行遊戲循環
* 2.更新幀速率
* 3.設置遊戲時間
* 4.清除屏幕內容
* 5.在播放動畫前,調用startAnimate的方法(能夠進行碰撞檢測)
* 6.繪製精靈背後的內容(繪製背景)
* 7.更新精靈
* 8.繪製精靈
* 9.繪製精靈前方的內容
* 10.動畫播放完畢以後,調用endAnimate方法
* 11.請求瀏覽器播放下一幀動畫
*
* */


/**
* V3.0: 實如今暫停狀態與運行狀態之間的切換togglePaused
*/

/**
* V4.0:實現基於時間的運動效果 :pixelPerFrame
* 計算公式:(pixels / second) * (second / frame) = pixeld / second【單位:每一秒移動的像素數】
*/

/**
* V5.0: 實現加載圖像的功能:
* queueImage(imageUrl): 將圖像放入到加載隊列中去
* loadImages(): 開發者須要持續調用該方法,知道返回100位置(方法的返回值表示圖像加載完成的百分比)
* getImage(imageUrl):返回圖像對象, 只有咋loadImages()返回100以後,才能夠調用該方法
*/

/**
* V6.0:實現同時播放多個聲音的功能
* canPlay(): 用於查詢瀏覽器是否可以播放某種特定格式的聲音文件
* playSound():用於播放聲音
*/


/**
* V7.0: 鍵盤事件的處理
* addKeyListener(): 用於向遊戲註冊按鍵監聽器
*/


/**
* V8.0: 高分榜的維護:遊戲的高分榜數組以json格式存檔在本地
*/

/**
* V9.0: 實現了一個比較完整的遊戲引擎,開始使用這個簡單的遊戲引擎去製做一個小遊戲
* 需求分析:
* 1.資源加載的畫面
* 2.遊戲資源的管理
* 3.聲音的播放
* 4.具備視差動畫的滾動背景
* 5.生命數量的顯示
* 6.高分榜的維護
* 7.按鍵的監聽與處理
* 8.暫停功能與自動暫停機制實現
* 9.遊戲結束的流程處理
*/

其餘的文件已經所有上傳到Github,感興趣的朋友能夠下載查看學習交流,若是以爲不錯,歡迎給個star支持一下:

 

https://github.com/xiugangzhang/GameEngine

 

其餘的幾個小遊戲也已經分享:

中國象棋:https://github.com/xiugangzhang/ChineseChess

超級馬里奧小遊戲:https://github.com/xiugangzhang/SuperMarioGame

蘇拉卡爾塔小遊戲:https://github.com/xiugangzhang/SularaGame

相關文章
相關標籤/搜索