摘要:另外一個(gè)與變量函數(shù)有關(guān)的約定是變量名函數(shù)名前加下橫杠,表示這是私有變量函數(shù),表達(dá)為沒(méi)有贏也沒(méi)有平局剛剛著棋的玩家贏了棋盤(pán)滿了,且平局剛剛著棋的玩家,走棋無(wú)效,再走一次把球放到指定列。
最近在看一本書(shū),里面提到j(luò)s的模塊化,覺(jué)得很有必要,所以記錄下來(lái)
Game.js
/**
* This is the main class that handles the game life cycle. It initializes
* other components like Board and BoardModel, listens to the DOM events and
* translates clicks to coordinates.
* @param canvas the canvas object to use for drawing
*/
function Game(canvas) {
this._boardRect = null;
this._canvas = canvas;
this._ctx = canvas.getContext("2d");
this._boardModel = new BoardModel();//實(shí)例化類(lèi)
this._boardRenderer = new boardRenderer(this._ctx, this._boardModel);
this.handleResize();
}
_h = Game.prototype;
/**
* Handles the click (or tap) on the Canvas. Translates the canvas coordinates
* into the column of the game board and makes the next turn in that column
* @param x the x coordinate of the click or tap
* @param y the y coordinate of the click or tap
*/
_h.handleClick = function(x, y) {
// 獲取列的索引
var column = Math.floor((x - this._boardRect.x)/this._boardRect.cellSize);
//生成回合并檢查結(jié)果
var turn = this._boardModel.makeTurn(column);
// 如果回合有效,更新游戲盤(pán)并繪制新球
if (turn.status != BoardModel.ILLEGAL_TURN) {
this._boardRenderer.drawToken(turn.x, turn.y);
}
// Do we have a winner after the last turn?
if (turn.status == BoardModel.WIN) {
// Tell the world about it and reset the board for the next game
alert((turn.piece == BoardModel.RED ? "red" : "green") + " won the match!");
this._reset();
}
// If we have the draw, do the same
if (turn.status == BoardModel.DRAW) {
alert("It is a draw!");
this._reset();
}
};
/**
* Reset the _boardModel and redraw the board.
*/
_h._reset = function() {
this._clearCanvas();
this._boardModel.reset();
this._boardRenderer.repaint();
};
/**
* Called when the screen has resized. In this case we need to calculate
* new size and position for the game board and repaint it.
*/
_h.handleResize = function() {
this._clearCanvas();
this._boardRect = this._getBoardRect();//拿到畫(huà)棋盤(pán)的3個(gè)重要參數(shù)
this._boardRenderer.setSize(this._boardRect.x, this._boardRect.y, this._boardRect.cellSize);
this._boardRenderer.repaint();
};
/**
* Get the optimal position and the size of the board
* @return the object that describes the optimal position and
* size for the board:
* {
* x: the x of the top-left corner of the board
* y: the y of the top-left corner of the board
* cellSize: the optimal size of the cell (in pixels)
* }
*/
_h._getBoardRect = function() {
var cols = this._boardModel.getCols();//這個(gè)游戲的列數(shù)
var rows = this._boardModel.getRows();//這個(gè)游戲的行數(shù)
var cellSize = Math.floor(Math.min(this._canvas.width/cols, this._canvas.height/rows));//每個(gè)單元格的長(zhǎng)
var boardWidth = cellSize*cols;
var boardHeight = cellSize*rows;
return {
x: Math.floor((this._canvas.width - boardWidth)/2),
y: Math.floor((this._canvas.height - boardHeight)/2),
cellSize: cellSize
}
};
/**
* 清除畫(huà)布的方法居然是直接在畫(huà)布上面畫(huà)一個(gè)白色的矩形!不需要使用clearRect()...
* 但是如果背景是一張圖片,直接就可以用這個(gè)方法
*/
_h._clearCanvas = function() {
this._ctx.fillStyle = "white";
this._ctx.fillRect(0, 0, this._canvas.width, this._canvas.height);
};
boardRenderer.js
/**
* 這個(gè)類(lèi)負(fù)責(zé)繪制,棋盤(pán),球
* @param context the 2d context to draw at
* @param model the BoardModel to take data from
*/
function boardRenderer(context,model){
this._ctx = context;
this._model = model;
//為方便保存
this._cols = model.getCols();
this._rows = model.getRows();
//游戲盤(pán)左上角的位置
this._x = 0;
this._y = 0;
//游戲盤(pán)矩形的寬度和高度
this.width = 0;
this.height = 0;
//游戲盤(pán)單元格的最佳大小
this._cellSize = 0;
}
_h = boardRenderer.prototype;
/**
* 重新繪制整個(gè)畫(huà)板Repaints the whole board.
*/
_h.repaint = function() {
this._ctx.save();
this._ctx.translate(this._x, this._y);
this._drawBackground();
this._drawGrid();
this._ctx.restore();
for (var i = 0; i < this._cols; i++) {
for (var j = 0; j < this._rows; j++) {
this.drawToken(i, j);
}
}
};
/**
* 畫(huà)背景
*
*/
_h._drawBackground = function(){
var ctx = this._ctx;
//背景
var gradient = ctx.createLinearGradient(0,0,0,this._height);
gradient.addColorStop(0,"#fffbb3");
gradient.addColorStop(1,"#f6f6b2");
ctx.fillStyle = gradient;
ctx.fillRect(0,0,this._width,this._height);
//繪制曲線
var co = this.width/6;
ctx.strokeStyle = "#dad7ac";
ctx.fillStyle = "#f6f6b2";
//第一條曲線
ctx.beginPath();
ctx.moveTo(co, this._height);
ctx.bezierCurveTo(this._width + co*3, -co, -co*3, -co, this._width - co, this._height);
ctx.fill();
//第二條曲線
ctx.beginPath();
ctx.moveTo(co, 0);
ctx.bezierCurveTo(this._width + co*3, this._height + co, -co*3, this._height + co, this._width - co, 0);
ctx.fill();
}
/**
* 畫(huà)網(wǎng)格.
*/
_h._drawGrid = function() {
var ctx = this._ctx;
ctx.beginPath();
//畫(huà)橫線 Drawing horizontal lines
for (var i = 0; i <= this._cols; i++) {
ctx.moveTo(i*this._cellSize + 0.5, 0.5);
ctx.lineTo(i*this._cellSize + 0.5, this._height + 0.5)
}
//畫(huà)豎線 Drawing vertical lines
for (var j = 0; j <= this._rows; j++) {
ctx.moveTo(0.5, j*this._cellSize + 0.5);
ctx.lineTo(this._width + 0.5, j*this._cellSize + 0.5);
}
//給這些線描邊
ctx.strokeStyle = "#CCC";
ctx.stroke();
};
/**
* 在指定的地方畫(huà)上指定顏色的標(biāo)記
* @param cellX 單元格的x坐標(biāo)
* @param cellY 單元格的y坐標(biāo)
*/
_h.drawToken = function(cellX, cellY) {
var ctx = this._ctx;
var cellSize = this._cellSize;
var tokenType = this._model.getPiece(cellX, cellY);
//如果單元格為空
if (!tokenType)
return;
var colorCode = "black";
switch(tokenType) {
case BoardModel.RED:
colorCode = "red";
break;
case BoardModel.GREEN:
colorCode = "green";
break;
}
//標(biāo)記的圓心位置
var x = this._x + (cellX + 0.5)*cellSize;
var y = this._y + (cellY + 0.5)*cellSize;
ctx.save();
ctx.translate(x, y);
//標(biāo)記的半徑
var radius = cellSize*0.4;
//漸變的中心
var gradientX = cellSize*0.1;
var gradientY = -cellSize*0.1;
var gradient = ctx.createRadialGradient(
gradientX, gradientY, cellSize*0.1, // 內(nèi)圓 (炫光)
gradientX, gradientY, radius*1.2); // 外圓
gradient.addColorStop(0, "yellow"); // “光線”的顏色
gradient.addColorStop(1, colorCode); // 標(biāo)記的顏色
ctx.fillStyle = gradient;
ctx.beginPath();
ctx.arc(0, 0, radius, 0, 2*Math.PI, true);
ctx.fill();
ctx.restore();
};
/**
* Sets the new position and size for the board. Should call repaint to
* see the changes
* @param x the x coordinate of the top-left corner
* @param y the y coordinate of the top-left corner
* @param cellSize optimal size of the cell in pixels
*/
_h.setSize = function(x, y, cellSize) {
this._x = x;
this._y = y;
this._cellSize = cellSize;
this._width = this._cellSize*this._cols;
this._height = this._cellSize*this._rows;
};
boardModel.js
/**
* 這個(gè)類(lèi)是負(fù)責(zé)保存/驗(yàn)證/返回當(dāng)前游戲的狀態(tài)
* 如當(dāng)前的玩家是誰(shuí)、每個(gè)單元格放的是什么球、
* 是不是誰(shuí)贏了
* @param cols number of columns in the board
* @param rows number of rows in the board
*/
function BoardModel(cols, rows) {
this._cols = cols || 7;
this._rows = rows || 6;
this._data = [];//用于記錄游戲當(dāng)前的游戲狀態(tài)——每個(gè)格子有什么球
this._currentPlayer = BoardModel.RED;
this._totalTokens = 0;
this.reset();
}
/**
* 0代表單元格為空,1代表單元格有紅色球,2代表單元格有綠色球
* 因?yàn)榕乱院笸涍@些數(shù)字代表什么,干脆把數(shù)字存到常量里,代碼看起來(lái)易懂,
* 但是這么多字,前端的js不是應(yīng)該越短越好嗎!?
* ps.變量名全大寫(xiě)表示這是常量,這是一個(gè)js程序員之間的約定,表達(dá)為 CAPITAL_CASED。
* 另外一個(gè)與變量(函數(shù))有關(guān)的約定是:變量名(函數(shù)名)前加"_"下橫杠,表示這是私有變量(函數(shù)),表達(dá)為 _underlinePrivateVariables
*/
BoardModel.EMPTY = 0;
BoardModel.RED = 1;
BoardModel.GREEN = 2;
/**
* Game state after the turn
*/
BoardModel.NONE = 0; // 沒(méi)有贏也沒(méi)有平局
BoardModel.WIN = 1; //剛剛著棋的玩家贏了
BoardModel.DRAW = 2; // 棋盤(pán)滿了,且平局
BoardModel.ILLEGAL_TURN = 3; // 剛剛著棋的玩家,走棋無(wú)效,再走一次
_h = BoardModel.prototype;
/**
* Resets the game board into the initial state: the
* board is empty and the starting player is RED.
*/
_h.reset = function() {
this._data = [];
for (var i = 0; i < this._rows; i++) {
this._data[i] = [];
for (var j = 0; j < this._cols; j++) {
this._data[i][j] = BoardModel.EMPTY;
}
}
this._currentPlayer = BoardModel.RED;
this._totalTokens = 0;
};
/**
* 把球放到指定列。 Board model itself takes care of
* tracking the current player.
* @param column the index of the column
* @param piece the ID of the piece (RED or YELLOW)
* @return the object {
* status: win condition
* x: the x coordinate of the new turn (undefined if turn was illegal)
* y: the y coordinate of the new turn (undefined if turn was illegal)
* piece: piece id (RED or GREEN)
* }
*/
_h.makeTurn = function(column) {
//正在放的球的顏色 The color of the piece that we"re dropping
var piece = this._currentPlayer;
//檢查這一列是否可以放球
if (column < 0 || column >= this._cols) {
return {
status: BoardModel.ILLEGAL_TURN
}
}
//檢查這一列上有空行沒(méi),如果沒(méi)有,則這回合無(wú)效
var row = this._getEmptyRow(column);
if (row == -1) {
return {
status: BoardModel.ILLEGAL_TURN
}
}
//放置球
this._totalTokens++;
this._data[row][column] = piece;
// 更換玩家
this._toggleCurrentPlayer();
// 返回回合成功的消息,包括新的游戲狀態(tài):none——可以繼續(xù)游戲、win、draw
return {
status: this._getGameState(column, row),
x: column,
y: row,
piece: piece
}
};
_h.getPiece = function(col, row) {
return this._data[row][col];
};
/**
* 返回這個(gè)游戲有多少列
*/
_h.getCols = function() {
return this._cols;
};
/**
* 返回這個(gè)游戲有多少行
*/
_h.getRows = function() {
return this._rows;
};
/**
* 返回指定列是否有空行,如果沒(méi)有 return -1.
* @param column the column index
*/
_h._getEmptyRow = function(column) {
for (var i = this._rows - 1; i >= 0; i--) {
if (!this.getPiece(column, i)) {
return i;
}
}
return -1;
};
/**
* Checks for the win condition, checks how many pieces of the same color are in each
* possible row: horizontal, vertical or both diagonals.
* @param column the column of the last move
* @param row the row of the last move
* @return the game state after this turn:
* NONE if the state wasn"t affected
* WIN if current player won the game with the last turn
* DRAW if there"s no emty cells in the board left
*/
_h._getGameState = function(column, row) {
if (this._totalTokens == this._cols*this._rows)
return BoardModel.DRAW;
for (var deltaX = -1; deltaX < 2; deltaX++) {
for (var deltaY = -1; deltaY < 2; deltaY++) {
if (deltaX == 0 && deltaY == 0)
continue;
var count = this._checkWinDirection(column, row, deltaX, deltaY)
+ this._checkWinDirection(column, row, -deltaX, -deltaY) + 1;
if (count >= 4) {
return BoardModel.WIN;
}
}
}
return BoardModel.NONE;
};
/**
* Calculates the number of pieces of the same color in the given direction, starting
* fromt the given point (last turn)
* @param column starting column
* @param row starting row
* @param deltaX the x direction of the check
* @param deltaY the y direction of the check
*/
_h._checkWinDirection = function(column, row, deltaX, deltaY) {
var pieceColor = this.getPiece(column, row);
var tokenCounter = 0;
var c = column + deltaX;
var r = row + deltaY;
while(c >= 0 && r >= 0 && c < this._cols && r < this._rows &&
this.getPiece(c, r) == pieceColor) {
c += deltaX;
r += deltaY;
tokenCounter++;
}
return tokenCounter;
};
/**
* 切換當(dāng)前玩家 - from red to green and back.
*/
_h._toggleCurrentPlayer = function() {
this._currentPlayer = (this._currentPlayer==BoardModel.RED)?BoardModel.GREEN:BoardModel.RED;
/*if (this._currentPlayer == BoardModel.RED)
this._currentPlayer = BoardModel.GREEN;
else
this._currentPlayer = BoardModel.RED;*/
};
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://www.hztianpu.com/yun/87677.html
摘要:所有依賴這個(gè)模塊的語(yǔ)句,都定義在一個(gè)回調(diào)函數(shù)中,等到所有依賴加載完成之后前置依賴,這個(gè)回調(diào)函數(shù)才會(huì)運(yùn)行。如果將前面的代碼改寫(xiě)成形式,就是下面這樣定義了一個(gè)文件,該文件依賴模塊,當(dāng)模塊加載完畢之后執(zhí)行回調(diào)函數(shù),這里并沒(méi)有暴露任何變量。 模塊化是我們?nèi)粘i_(kāi)發(fā)都要用到的基本技能,使用簡(jiǎn)單且方便,但是很少人能說(shuō)出來(lái)但是的原因及發(fā)展過(guò)程?,F(xiàn)在通過(guò)對(duì)比不同時(shí)期的js的發(fā)展,將JavaScript模...
摘要:參考精讀模塊化發(fā)展模塊化七日談前端模塊化開(kāi)發(fā)那點(diǎn)歷史本文先發(fā)布于我的個(gè)人博客模塊化開(kāi)發(fā)的演進(jìn)歷程,后續(xù)如有更新,可以查看原文。 Brendan Eich用了10天就創(chuàng)造了JavaScript,因?yàn)楫?dāng)時(shí)的需求定位,導(dǎo)致了在設(shè)計(jì)之初,在語(yǔ)言層就不包含很多高級(jí)語(yǔ)言的特性,其中就包括模塊這個(gè)特性,但是經(jīng)過(guò)了這么多年的發(fā)展,如今對(duì)JavaScript的需求已經(jīng)遠(yuǎn)遠(yuǎn)超出了Brendan Eich的...
摘要:再者,引入一大堆的文件也不美觀,而使用即可實(shí)現(xiàn)的模塊化異步加載。通過(guò)定義模塊的方式可分為以下兩類(lèi)。當(dāng)和這兩個(gè)模塊加載完成之后將會(huì)執(zhí)行回調(diào)函數(shù)。插件可以使回調(diào)函數(shù)在結(jié)構(gòu)加載完成之后再執(zhí)行。最好的方式是使用字符串但這很難管理尤其實(shí)在多行的時(shí)候。 什么是Require.js Require.js是一個(gè)AMD規(guī)范的輕量級(jí)js模塊化管理框架,最新版本require.js 2.1.11壓縮后只有1...
摘要:有幾個(gè)和模塊化相關(guān)的,,比較容易混淆。注意,我們并沒(méi)有引入。所以運(yùn)行的結(jié)果是。同時(shí),我們指定了變量。等于是在文件的最頂上,加上了。實(shí)際情況大致如此。把一個(gè)模塊導(dǎo)出并付給一個(gè)全局變量。假如中有代碼,那么后的值就為我們這里只討論瀏覽器環(huán)境。 Webpack有幾個(gè)和模塊化相關(guān)的loader,imports-loader,exports-loader,expose-loader,比較容易混淆。...
摘要:感謝感謝和在推動(dòng)模塊化發(fā)展方面做出的貢獻(xiàn)。與引用阮一峰老師的標(biāo)準(zhǔn)參考教程規(guī)范加載模塊是同步的,也就是說(shuō),只有加載完成,才能執(zhí)行后面的操作。規(guī)定了新的模塊加載方案。與引用阮一峰老師的入門(mén)它們有兩個(gè)重大差異。 前言 本篇我們重點(diǎn)介紹以下四種模塊加載規(guī)范: AMD CMD CommonJS ES6 模塊 最后再延伸講下 Babel 的編譯和 webpack 的打包原理。 require....
摘要:模塊化編程首先,我想說(shuō)說(shuō)模塊化編程這個(gè)概念當(dāng)我不清楚這個(gè)概念的時(shí)候,其實(shí)說(shuō)什么模塊化編程多好多好都是懵逼的而我一直不覺(jué)得有多好,其實(shí)也是因?yàn)槲覐拈_(kāi)始寫(xiě),就一直都在模塊化編程啊我們寫(xiě)一個(gè)文件然后我們?cè)谖募幸肴缓笳{(diào)用方法哈哈這樣已經(jīng)是模塊化 模塊化編程 首先,我想說(shuō)說(shuō)模塊化編程這個(gè)概念當(dāng)我不清楚這個(gè)概念的時(shí)候,其實(shí)說(shuō)什么模塊化編程多好多好都是懵逼的而我一直不覺(jué)得有多好,其實(shí)也是因?yàn)槲覐?..
閱讀 962·2021-10-13 09:39
閱讀 1572·2021-10-11 10:57
閱讀 2666·2019-08-26 13:53
閱讀 2641·2019-08-26 12:23
閱讀 3768·2019-08-23 18:30
閱讀 3828·2019-08-23 18:08
閱讀 2591·2019-08-23 18:04
閱讀 3018·2019-08-23 16:28