[javascript]自製記憶遊戲實作細節(1/2)

本篇承接以兒子為素材的Web記憶遊戲,說明遊戲實作細節,包含以下部分

  • 整體架構
  • 螢幕適應
  • 進度條

程式碼的部分,為了說明方便,會與實際程式中出現順序不同,但作用是一樣的,可能宣告在最外層,在某方法中賦值,之後在另一個方法中放至畫面上,說明時擺在一起看較容易理解。原始碼Open Source。

整體架構

主要重心都在javascript中,因此HTML部分只有一個div,每一個頁面,和遊戲中的元素,都是使用DOM或者動態附加HTML上去的,載入頁面後,才開始運行javascript進行初始化

<body onload="onload()">
  <div id="game_area"></div>
</body>

首先定義有哪幾頁要呈現,像是讀取中、主選單、遊戲頁等

//關卡階段
var currentStage = 0;
const STAGE_LOADING = 0;
const STAGE_MENU = 1;
const STAGE_GALLERY = 2;
const STAGE_PREPARE = 3;
const STAGE_PLAYING = 4;
const STAGE_GAME_COMPLETE = 5;
const STAGE_GAME_OVER = 6;

接著宣告介面上會用到的物件,像是主選單標題、按鈕等,在需要時,動態添加到畫面上,不顯示時,再清除,但其實物件資訊都還保留在記憶體中,下一次再添加到畫面時,不需要重新宣告。

var title;
//建立一個div的物件
title = document.createElement('div');
title.id = 'title';
//設定該div的class
title.classList.add('center');
//建立一個img物件
var title_img = document.createElement('img');
title_img.src = 'title.png';
//將img放入div中
title.appendChild(title_img);

var gameArea = document.getElementById('game_area');
//將div放至畫面上呈現,此時該div才可見
gameArea.appendChild(title);

//將畫面上的元素都清除,即不可見
function clearScreen(){
  removeAllElements(gameArea);
}

//實際走訪每個子節點,將其從父節點中清除
function removeAllElements(node){
  while (node.firstChild) {
    node.removeChild(node.firstChild);
  }
}

//以遊戲完成頁面為例,先清除所有畫面上的物件,再添加此頁面所需要的物件
function gameComlete(){
  currentStage = STAGE_GAME_COMPLETE;
  clearScreen();
  gameArea.appendChild(title);
  tip.innerHTML = '恭喜你在時間內完成挑戰~';
  gameArea.appendChild(empty);
  gameArea.appendChild(tip);
  btnIndex.classList.add('btn-index');
  gameArea.appendChild(btnIndex);
  gameArea.appendChild(logo);
}

螢幕適應

面對各種尺寸的手機,一開始我使用網頁的RWD作法,設定mediaquery,分橫豎兩個方向作呈現,不過後來發現太多預料外的狀況了,導致後來改用固定比例的呈現方式,固定以3比4呈現,空白的部分補黑邊,這樣相對單純許多,目前有個小問題,就是之前的mediaquery沒有拿掉就調整,所以有點混用到了,現在如果拿掉反而不會正常顯示,後續再來改正。

#game_area {
  position: absolute;
  left:     50%;
  top:      50%;
  background-image: url('bg.png');
}
//定義resize事件
window.addEventListener("resize", function(){
  resizeGame();
});

//首次執行時,也需要手動觸發一次調整畫面
window.dispatchEvent(new Event('resize'));

//動態調整遊戲區域的寬高
function resizeGame() {
  var widthToHeight = 3 / 4;
  var newWidth = window.innerWidth;
  var newHeight = window.innerHeight;
  var newWidthToHeight = newWidth / newHeight;
		    
  if (newWidthToHeight > widthToHeight) {
    newWidth = newHeight * widthToHeight;
    gameArea.style.height = newHeight + 'px';
    gameArea.style.width = newWidth + 'px';
  } else {
    newHeight = newWidth / widthToHeight;
    gameArea.style.width = newWidth + 'px';
    gameArea.style.height = newHeight + 'px';
  }
  //除寬高外,也要動態調整位置保持置中
  gameArea.style.marginTop = (-newHeight / 2) + 'px';
  gameArea.style.marginLeft = (-newWidth / 2) + 'px';			    
}

進度條

進度條設計主要是避免遊戲途中,圖片來不及讀取顯示空白或者音效首次播放延遲,因為以前沒有做過類似功能,有點不清楚,後來才知道原來不難,可以使用DOM的方式建立,再透過complete屬性判斷是否已讀取完成,或者建立onload事件,則會在讀取完成時觸發,指定src後,瀏覽器便會自動開始讀取,只要在讀取完成時,計算已完成的百分比,再更新進度條的長度,就完成了

是不是很簡單呢? 下方程式碼可以看到我同時使用complete和onload是因為,當瀏覽器已經有該資源的快取時,不會觸發onload所以只好先手動判斷一次complete屬性,確保有執行到更新進度條的方法。

var loadCount = 0;
var loadPercent = 0;

var img = new Image();
img.src = 'cover.png';
if(img.complete){
  updateProgress();
}else{
  img.onload = function(){
    updateProgress();
  };
}
//設定所有的照片讀取事件
for(var i=0;i<CARD_IMG_NUMBER;i++){
  img = new Image();
  img.src = 'card_'+cardImgList[i]+'.png';
  if(img.complete){
    updateProgress();
  }else{
    img.onload = function(){
      updateProgress();
    };
  }
}
//設定音訊讀取事件
sound_start = document.createElement('audio');
sound_start.src = 'start.mp3';
sound_start.preload = 'auto';
sound_start.oncanplaythrough = updateProgress();

function updateProgress(){
  loadCount++;
  loadPercent = Math.floor(loadCount*100/(CARD_IMG_NUMBER + SOUND_NUMBER + 1));
  //更新進度條長度
  bar.style.width = loadPercent + '%';
  //更新顯示百分比
  percent.innerHTML = loadPercent + '%';
  if(loadPercent == 100){
    showMenu();
  }
}

其餘部分的說明,請待下回分曉,如果有不同的想法歡迎一同討論~

延伸閱讀 [javascript]自製記憶遊戲實作細節(2/2)

對「[javascript]自製記憶遊戲實作細節(1/2)」的一則回應

Add yours

發表迴響

在下方填入你的資料或按右方圖示以社群網站登入:

WordPress.com 標誌

您的留言將使用 WordPress.com 帳號。 登出 /  變更 )

Google photo

您的留言將使用 Google 帳號。 登出 /  變更 )

Twitter picture

您的留言將使用 Twitter 帳號。 登出 /  變更 )

Facebook照片

您的留言將使用 Facebook 帳號。 登出 /  變更 )

連結到 %s

Create a website or blog at WordPress.com

向上 ↑

%d 位部落客按了讚: