成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

Chrome 小恐龍游戲源碼探究一 -- 繪制靜態(tài)地面

lixiang / 2085人閱讀

摘要:首先是繪制靜態(tài)的地面。上一篇下一篇無小恐龍游戲源碼探究二讓地面動(dòng)起來

文章首發(fā)于我的 GitHub 博客
目錄

Chrome 小恐龍游戲源碼探究一 -- 繪制靜態(tài)地面

Chrome 小恐龍游戲源碼探究二 -- 讓地面動(dòng)起來

Chrome 小恐龍游戲源碼探究三 -- 進(jìn)入街機(jī)模式

Chrome 小恐龍游戲源碼探究四 -- 隨機(jī)繪制云朵

Chrome 小恐龍游戲源碼探究五 -- 隨機(jī)繪制障礙

Chrome 小恐龍游戲源碼探究六 -- 記錄游戲分?jǐn)?shù)

Chrome 小恐龍游戲源碼探究七 -- 晝夜模式交替

Chrome 小恐龍游戲源碼探究八 -- 奔跑的小恐龍

Chrome 小恐龍游戲源碼探究九 -- 游戲碰撞檢測

Chrome 小恐龍游戲源碼探究完 -- 游戲結(jié)束和其他要素

前言

當(dāng) Chrome 處于離線情況下,會(huì)顯示以下頁面:

當(dāng)按下空格鍵或者 ↑ 鍵,小恐龍游戲彩蛋就觸發(fā)啦 (??????)??

游戲雖然簡單,但源碼卻有三千多行,代碼嚴(yán)謹(jǐn)且富有邏輯,值得拿來學(xué)習(xí)研究。這個(gè)教程將會(huì)從零開始,一步步解讀源碼并最終實(shí)現(xiàn)這個(gè)游戲。

獲取源碼、素材

要獲取游戲的源碼,可以通過下面幾種方式:

斷網(wǎng)后,訪問任意網(wǎng)址,進(jìn)入小恐龍頁面,用開發(fā)者工具獲取源碼

在瀏覽器地址欄輸入 chrome://dino,進(jìn)入小恐龍頁面,用開發(fā)者工具獲取源碼

官方提供的源碼網(wǎng)址

有人將源碼提取出來放在了 GitHub 上:t-rex-runner

游戲用到的雪碧圖,音頻文件可以在官方提供的源碼網(wǎng)址里獲取到。

為了方便食用,我將雪碧圖中各個(gè)小圖片的坐標(biāo)信息標(biāo)了出來(W: Width, H: Height, L: Left, T: Top):

關(guān)于上面雪碧圖的坐標(biāo)信息,我是用一個(gè)在線工具獲取的:http://www.spritecow.com/,個(gè)別坐標(biāo)信息通過這個(gè)網(wǎng)站獲取的不太準(zhǔn),這里我已經(jīng)通過參考源碼里的數(shù)據(jù)進(jìn)行了修正。

戳這里獲取上面這張圖片的 JPG 原圖和 PSD 原圖。
開始探究

游戲源碼主要包括九個(gè)類:

游戲的主體類 Runner

背景類 Horizon

地面類 HorizonLine

云朵類 Cloud

障礙物類 Obstacle

晝夜更替類 NightMode

小恐龍類 Trex

分?jǐn)?shù)類 DistanceMeter

游戲結(jié)束面板類 GameOverPanel

這個(gè)教程并不會(huì)完全按照源碼來,而是抽取主要的內(nèi)容來一步步實(shí)現(xiàn)這個(gè)游戲。這樣做并不意味著改變?cè)创a的思路,而是去除了一些目前可以先不考慮的代碼,比如:去除了適配 HDPI 和 LDPI、適配移動(dòng)端等。

這個(gè)游戲源碼的探究已經(jīng)有前輩 @逐影 寫了系列教程。在這里,我寫這個(gè)教程的目的,一是當(dāng)做學(xué)習(xí)筆記,二是提供與前輩不一樣的源碼解讀思路。
游戲主體搭建

游戲文件結(jié)構(gòu)目錄:

chrome-dino
  - index.html
  - index.css
  - index.js     // JS 入口文件
  - offline.js   // 游戲邏輯實(shí)現(xiàn)
  - imgs
  - sounds
想要獲取整個(gè)教程的源代碼,戳這里:GitHub

HTML、CSS 就不過多解釋,直接貼代碼:



  
    
    
    
    Chrome Dino
    
    
  
  
    
    
* {
  margin: 0;
  padding: 0;
}

*,
*::before,
*::after {
  box-sizing: border-box;
}

#chrome-dino {
  width: 100%;
  max-width: 600px;
  margin: 0 auto;
}

#offline-resources {
  display: none;
}

.offline .runner-container {
  position: absolute;
  top: 35px;
  width: 100%;
  max-width: 600px;
  height: 150px;
  overflow: hidden;
}

.offline .runner-canvas {
  z-index: 10;
  position: absolute;
  top: 0;
  height: 150px;
  max-width: 600px;
  overflow: hidden;
  opacity: 1;
}

下面來分析 JS 代碼:

首先看一下游戲的主體類 Runner,這個(gè)類用于控制游戲的主要邏輯:

/**
 * 游戲主體類,控制游戲的整體邏輯
 * @param {String} containerSelector 畫布外層容器的選擇器
 * @param {Object} opt_config 配置選項(xiàng)
 */
function Runner(containerSelector, opt_config) {
  // 獲取游戲的 “根” DOM 節(jié)點(diǎn),整個(gè)游戲都會(huì)輸出到這個(gè)節(jié)點(diǎn)里
  this.outerContainerEl = document.querySelector(containerSelector);
  // canvas 的外層容器
  this.containerEl = null;

  this.config = opt_config || Runner.config;
  this.dimensions = Runner.defaultDimensions;

  this.time = 0;                         // 時(shí)鐘計(jì)時(shí)器
  this.currentSpeed = this.config.SPEED; // 當(dāng)前的速度

  this.activated  = false; // 游戲彩蛋是否被激活(沒有被激活時(shí),游戲不會(huì)顯示出來)
  this.playing = false;    // 游戲是否進(jìn)行中
  this.crashed = false;    // 小恐龍是否碰到了障礙物
  this.paused = false      // 游戲是否暫停

  // 加載雪碧圖,并初始化游戲
  this.loadImages();
}

window["Runner"] = Runner;  // 將 Runner 類掛載到 window 對(duì)象上

相關(guān)的數(shù)據(jù)和配置參數(shù):

var DEFAULT_WIDTH = 600; // 游戲畫布默認(rèn)寬度
var FPS = 60;            // 游戲默認(rèn)幀率

// 游戲配置參數(shù)
Runner.config = {
  SPEED: 6, // 移動(dòng)速度
};

// 游戲畫布的默認(rèn)尺寸
Runner.defaultDimensions = {
  WIDTH: DEFAULT_WIDTH,
  HEIGHT: 150,
};

// 游戲用到的 className
Runner.classes = {
  CONTAINER: "runner-container",
  CANVAS: "runner-canvas",
  PLAYER: "", // 預(yù)留出的 className,用來控制 canvas 的樣式
};

// 雪碧圖中圖片的坐標(biāo)信息
Runner.spriteDefinition = {
  LDPI: {
    HORIZON: { x: 2, y: 54 }, // 地面
  },
};

// 游戲中用到的鍵盤碼
Runner.keyCodes = {
  JUMP: { "38": 1, "32": 1 }, // Up, Space
  DUCK: { "40": 1 },          // Down
  RESTART: { "13": 1 },       // Enter
};

// 游戲中用到的事件
Runner.events = {
  LOAD: "load",
};

Runner 原型鏈上添加的方法:

Runner.prototype = {
  // 初始化游戲
  init: function () {
    // 生成 canvas 容器元素
    this.containerEl = document.createElement("div");
    this.containerEl.className = Runner.classes.CONTAINER;

    // 生成 canvas
    this.canvas = createCanvas(this.containerEl, this.dimensions.WIDTH,
      this.dimensions.HEIGHT, Runner.classes.PLAYER);

    this.ctx = this.canvas.getContext("2d");
    this.ctx.fillStyle = "#f7f7f7";
    this.ctx.fill();

    // 加載背景類 Horizon
    this.horizon = new Horizon(this.canvas, this.spriteDef);

    // 將游戲添加到頁面中
    this.outerContainerEl.appendChild(this.containerEl);
  },
  // 加載雪碧圖資源
  loadImages() {
    // 圖片在雪碧圖中的坐標(biāo)
    this.spriteDef = Runner.spriteDefinition.LDPI;

    // 獲取雪碧圖
    Runner.imageSprite = document.getElementById("offline-resources-1x");

    // 當(dāng)圖片加載完成(complete 是 DOM 中 Image 對(duì)象自帶的一個(gè)屬性)
    if (Runner.imageSprite.complete) {
      this.init();
    } else { // 圖片沒有加載完成,監(jiān)聽其 load 事件
      Runner.imageSprite.addEventListener(Runner.events.LOAD,
        this.init.bind(this));
    }
  },
};

其中 createCanvas 方法定義如下:

/**
 * 生成 canvas 元素
 * @param {HTMLElement} container canva 的容器
 * @param {Number} width canvas 的寬度
 * @param {Number} height canvas 的高度
 * @param {String} opt_className 給 canvas 添加的類名(可選)
 * @return {HTMLCanvasElement}
 */
function createCanvas(container, width, height, opt_className) {
  var canvas = document.createElement("canvas");
  canvas.className = opt_className
    ? opt_className + " " + Runner.classes.CANVAS
    : Runner.classes.CANVAS;
  canvas.width = width;
  canvas.height = height;
  container.appendChild(canvas);

  return canvas;
}
地面類 HorizonLine

定義好 Runner 類之后,為了方便探究,接下來從簡單的背景開始說起。首先是繪制靜態(tài)的地面。

定義地面類 HorizonLine

/**
 * 地面類
 * @param {HTMLCanvasElement} canvas 畫布
 * @param {Object} spritePos 雪碧圖中的位置
 */
function HorizonLine(canvas, spritePos) {
  this.canvas = canvas;
  this.ctx = this.canvas.getContext("2d");

  this.dimensions = {};       // 地面的尺寸
  this.spritePos = spritePos; // 雪碧圖中地面的位置
  this.sourceXPos = [];       // 雪碧圖中地面的兩種地形的 x 坐標(biāo)
  this.xPos = [];             // canvas 中地面的 x 坐標(biāo)
  this.yPos = 0;              // canvas 中地面的 y 坐標(biāo)

  this.bumpThreshold = 0.5;   // 隨機(jī)地形系數(shù),控制兩種地形的出現(xiàn)頻率

  this.init();
  this.draw();
}

HorizonLine.dimensions = {
  WIDTH: 600,
  HEIGHT: 12,
  YPOS: 127,  // 繪制到 canvas 中的 y 坐標(biāo)
};

HorizonLine 原型鏈上添加方法:

HorizonLine.prototype = {
  // 初始化地面
  init: function () {
    for (const d in HorizonLine.dimensions) {
      if (HorizonLine.dimensions.hasOwnProperty(d)) {
        const elem = HorizonLine.dimensions[d];
        this.dimensions[d] = elem;
      }
    }
    this.sourceXPos = [this.spritePos.x,
      this.spritePos.x + this.dimensions.WIDTH];
    this.xPos = [0, HorizonLine.dimensions.WIDTH];
    this.yPos = HorizonLine.dimensions.YPOS;
  },
  // 繪制地面
  draw: function () {
    // 使用 canvas 中 9 個(gè)參數(shù)的 drawImage 方法
    this.ctx.drawImage(
      Runner.imageSprite,                   // 原圖片
      this.sourceXPos[0], this.spritePos.y, // 原圖中裁剪區(qū)域的起點(diǎn)坐標(biāo)
      this.dimensions.WIDTH, this.dimensions.HEIGHT,
      this.xPos[0], this.yPos,              // canvas 中繪制區(qū)域的起點(diǎn)坐標(biāo)
      this.dimensions.WIDTH, this.dimensions.HEIGHT,
    );
    this.ctx.drawImage(
      Runner.imageSprite,
      this.sourceXPos[1], this.spritePos.y,
      this.dimensions.WIDTH, this.dimensions.HEIGHT,
      this.xPos[1], this.yPos,
      this.dimensions.WIDTH, this.dimensions.HEIGHT,
    );
  },
};

背景類 Horizon 負(fù)責(zé)管理 HorizonLine、Cloud、Obstacle、NightMode 這幾個(gè)類。

所以接下來需要通過 Horizon 類來調(diào)用 HorizonLine 類。

背景類 Horizon

定義背景類 Horizon

/**
 * 背景類
 * @param {HTMLCanvasElement} canvas 畫布
 * @param {Object} spritePos 雪碧圖中的位置
 */
function Horizon(canvas, spritePos) {
  this.canvas = canvas;
  this.ctx = this.canvas.getContext("2d");
  this.spritePos = spritePos;

  // 地面
  this.horizonLine = null;

  this.init();
}

Horizon 原型鏈上添加方法:

Horizon.prototype = {
  // 初始化背景
  init: function () {
    this.horizonLine = new HorizonLine(this.canvas, this.spritePos.HORIZON);
  },
};

最后,通過調(diào)用 Runner 類來運(yùn)行游戲:

index.js:

window.onload = function () {
  var chromeDino = document.getElementById("chrome-dino");
  chromeDino.classList.add("offline");

  new Runner("#chrome-dino");
};

到這里,不出意外的話,就可以繪制出靜態(tài)的地面,如圖:

查看完整的代碼:戳這里

這里各個(gè)方法和類之間的調(diào)用邏輯是(箭頭代指調(diào)用):

new Runner()
-> loadImage() // Runner
-> init()      // Runner
-> new Horizon()
-> init()      // Horizon
-> new HorizonLine()
-> init()      // HorizonLine
-> draw()      // HorizonLine

簡單來說就是:游戲主體類 Runner 控制背景類 Horizon,再由背景類 Horizon 控制地面類 HorizonLine。

遵循的思想就是把游戲?qū)訉映橄螅沙橄蟪潭雀叩念愐粚右粚酉蛳抡{(diào)用抽象程度低的類。這樣做的好處是,思路清晰并且易于擴(kuò)展。

上一篇 下一篇
無 ?????????? ?????????? Chrome 小恐龍游戲源碼探究二 -- 讓地面動(dòng)起來

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/103890.html

相關(guān)文章

  • Chrome 恐龍游戲源碼探究二 -- 讓地面動(dòng)起來

    摘要:文章首發(fā)于我的博客前言上一篇文章小恐龍游戲源碼探究一繪制靜態(tài)地面中定義了游戲的主體類,并實(shí)現(xiàn)了靜態(tài)地面的繪制。 文章首發(fā)于我的 GitHub 博客 前言 上一篇文章:《Chrome 小恐龍游戲源碼探究一 -- 繪制靜態(tài)地面》 中定義了游戲的主體類 Runner,并實(shí)現(xiàn)了靜態(tài)地面的繪制。這一篇文章中,將實(shí)現(xiàn)效果:1、地面無限滾動(dòng)。2、剛開始地面不動(dòng),按下空格后地面滾動(dòng)。 地面無限滾動(dòng) ...

    siberiawolf 評(píng)論0 收藏0
  • Chrome 恐龍游戲源碼探究八 -- 奔跑的恐龍

    摘要:例如,將函數(shù)修改為小恐龍眨眼這樣小恐龍會(huì)不停的眨眼睛。小恐龍的開場動(dòng)畫下面來實(shí)現(xiàn)小恐龍對(duì)鍵盤按鍵的響應(yīng)。接下來還需要更新動(dòng)畫幀才能實(shí)現(xiàn)小恐龍的奔跑動(dòng)畫。 文章首發(fā)于我的 GitHub 博客 前言 上一篇文章:《Chrome 小恐龍游戲源碼探究七 -- 晝夜模式交替》實(shí)現(xiàn)了游戲晝夜模式的交替,這一篇文章中,將實(shí)現(xiàn):1、小恐龍的繪制 2、鍵盤對(duì)小恐龍的控制 3、頁面失焦后,重新聚焦會(huì)重置...

    paulquei 評(píng)論0 收藏0
  • Chrome 恐龍游戲源碼探究三 -- 進(jìn)入街機(jī)模式

    摘要:文章首發(fā)于我的博客前言上一篇文章小恐龍游戲源碼探究二讓地面動(dòng)起來實(shí)現(xiàn)了地面的移動(dòng)。街機(jī)模式的效果就是游戲開始后,進(jìn)入全屏模式。例如可以看到,進(jìn)入街機(jī)模式之前,有一段開場動(dòng)畫。 文章首發(fā)于我的 GitHub 博客 前言 上一篇文章:《Chrome 小恐龍游戲源碼探究二 -- 讓地面動(dòng)起來》 實(shí)現(xiàn)了地面的移動(dòng)。這一篇文章中,將實(shí)現(xiàn)效果:1、瀏覽器失焦時(shí)游戲暫停,聚焦游戲繼續(xù)。 2、開場動(dòng)...

    yeooo 評(píng)論0 收藏0
  • Chrome 恐龍游戲源碼探究五 -- 隨機(jī)繪制障礙

    摘要:文章首發(fā)于我的博客前言上一篇文章小恐龍游戲源碼探究四隨機(jī)繪制云朵實(shí)現(xiàn)了云朵的隨機(jī)繪制,這一篇文章中將實(shí)現(xiàn)仙人掌翼龍障礙物的繪制游戲速度的改變障礙物的類型有兩種仙人掌和翼龍。 文章首發(fā)于我的 GitHub 博客 前言 上一篇文章:《Chrome 小恐龍游戲源碼探究四 -- 隨機(jī)繪制云朵》 實(shí)現(xiàn)了云朵的隨機(jī)繪制,這一篇文章中將實(shí)現(xiàn):1、仙人掌、翼龍障礙物的繪制 2、游戲速度的改變 障礙物...

    tomorrowwu 評(píng)論0 收藏0
  • Chrome 恐龍游戲源碼探究四 -- 隨機(jī)繪制云朵

    摘要:文章首發(fā)于我的博客前言上一篇文章小恐龍游戲源碼探究三進(jìn)入街機(jī)模式實(shí)現(xiàn)了開場動(dòng)畫和街機(jī)模式。 文章首發(fā)于我的 GitHub 博客 前言 上一篇文章:《Chrome 小恐龍游戲源碼探究三 -- 進(jìn)入街機(jī)模式》 實(shí)現(xiàn)了開場動(dòng)畫和街機(jī)模式。這一篇文章中,將實(shí)現(xiàn)云朵的隨機(jī)繪制。 云朵類 Cloud 定義云朵類 Cloud: /** * 云朵類 * @param {HTMLCanvasEle...

    svtter 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<