摘要:另外一個與變量函數有關的約定是變量名函數名前加下橫杠,表示這是私有變量函數,表達為沒有贏也沒有平局剛剛著棋的玩家贏了棋盤滿了,且平局剛剛著棋的玩家,走棋無效,再走一次把球放到指定列。
最近在看一本書,里面提到js的模塊化,覺得很有必要,所以記錄下來
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();//實例化類 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); //生成回合并檢查結果 var turn = this._boardModel.makeTurn(column); // 如果回合有效,更新游戲盤并繪制新球 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();//拿到畫棋盤的3個重要參數 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();//這個游戲的列數 var rows = this._boardModel.getRows();//這個游戲的行數 var cellSize = Math.floor(Math.min(this._canvas.width/cols, this._canvas.height/rows));//每個單元格的長 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 } }; /** * 清除畫布的方法居然是直接在畫布上面畫一個白色的矩形!不需要使用clearRect()... * 但是如果背景是一張圖片,直接就可以用這個方法 */ _h._clearCanvas = function() { this._ctx.fillStyle = "white"; this._ctx.fillRect(0, 0, this._canvas.width, this._canvas.height); };
boardRenderer.js
/** * 這個類負責繪制,棋盤,球 * @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(); //游戲盤左上角的位置 this._x = 0; this._y = 0; //游戲盤矩形的寬度和高度 this.width = 0; this.height = 0; //游戲盤單元格的最佳大小 this._cellSize = 0; } _h = boardRenderer.prototype; /** * 重新繪制整個畫板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); } } }; /** * 畫背景 * */ _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(); } /** * 畫網格. */ _h._drawGrid = function() { var ctx = this._ctx; ctx.beginPath(); //畫橫線 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) } //畫豎線 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(); }; /** * 在指定的地方畫上指定顏色的標記 * @param cellX 單元格的x坐標 * @param cellY 單元格的y坐標 */ _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; } //標記的圓心位置 var x = this._x + (cellX + 0.5)*cellSize; var y = this._y + (cellY + 0.5)*cellSize; ctx.save(); ctx.translate(x, y); //標記的半徑 var radius = cellSize*0.4; //漸變的中心 var gradientX = cellSize*0.1; var gradientY = -cellSize*0.1; var gradient = ctx.createRadialGradient( gradientX, gradientY, cellSize*0.1, // 內圓 (炫光) gradientX, gradientY, radius*1.2); // 外圓 gradient.addColorStop(0, "yellow"); // “光線”的顏色 gradient.addColorStop(1, colorCode); // 標記的顏色 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
/** * 這個類是負責保存/驗證/返回當前游戲的狀態 * 如當前的玩家是誰、每個單元格放的是什么球、 * 是不是誰贏了 * @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 = [];//用于記錄游戲當前的游戲狀態——每個格子有什么球 this._currentPlayer = BoardModel.RED; this._totalTokens = 0; this.reset(); } /** * 0代表單元格為空,1代表單元格有紅色球,2代表單元格有綠色球 * 因為怕以后忘記這些數字代表什么,干脆把數字存到常量里,代碼看起來易懂, * 但是這么多字,前端的js不是應該越短越好嗎!? * ps.變量名全大寫表示這是常量,這是一個js程序員之間的約定,表達為 CAPITAL_CASED。 * 另外一個與變量(函數)有關的約定是:變量名(函數名)前加"_"下橫杠,表示這是私有變量(函數),表達為 _underlinePrivateVariables */ BoardModel.EMPTY = 0; BoardModel.RED = 1; BoardModel.GREEN = 2; /** * Game state after the turn */ BoardModel.NONE = 0; // 沒有贏也沒有平局 BoardModel.WIN = 1; //剛剛著棋的玩家贏了 BoardModel.DRAW = 2; // 棋盤滿了,且平局 BoardModel.ILLEGAL_TURN = 3; // 剛剛著棋的玩家,走棋無效,再走一次 _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 } } //檢查這一列上有空行沒,如果沒有,則這回合無效 var row = this._getEmptyRow(column); if (row == -1) { return { status: BoardModel.ILLEGAL_TURN } } //放置球 this._totalTokens++; this._data[row][column] = piece; // 更換玩家 this._toggleCurrentPlayer(); // 返回回合成功的消息,包括新的游戲狀態:none——可以繼續游戲、win、draw return { status: this._getGameState(column, row), x: column, y: row, piece: piece } }; _h.getPiece = function(col, row) { return this._data[row][col]; }; /** * 返回這個游戲有多少列 */ _h.getCols = function() { return this._cols; }; /** * 返回這個游戲有多少行 */ _h.getRows = function() { return this._rows; }; /** * 返回指定列是否有空行,如果沒有 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; }; /** * 切換當前玩家 - 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;*/ };
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/87677.html
摘要:所有依賴這個模塊的語句,都定義在一個回調函數中,等到所有依賴加載完成之后前置依賴,這個回調函數才會運行。如果將前面的代碼改寫成形式,就是下面這樣定義了一個文件,該文件依賴模塊,當模塊加載完畢之后執行回調函數,這里并沒有暴露任何變量。 模塊化是我們日常開發都要用到的基本技能,使用簡單且方便,但是很少人能說出來但是的原因及發展過程?,F在通過對比不同時期的js的發展,將JavaScript模...
摘要:參考精讀模塊化發展模塊化七日談前端模塊化開發那點歷史本文先發布于我的個人博客模塊化開發的演進歷程,后續如有更新,可以查看原文。 Brendan Eich用了10天就創造了JavaScript,因為當時的需求定位,導致了在設計之初,在語言層就不包含很多高級語言的特性,其中就包括模塊這個特性,但是經過了這么多年的發展,如今對JavaScript的需求已經遠遠超出了Brendan Eich的...
摘要:再者,引入一大堆的文件也不美觀,而使用即可實現的模塊化異步加載。通過定義模塊的方式可分為以下兩類。當和這兩個模塊加載完成之后將會執行回調函數。插件可以使回調函數在結構加載完成之后再執行。最好的方式是使用字符串但這很難管理尤其實在多行的時候。 什么是Require.js Require.js是一個AMD規范的輕量級js模塊化管理框架,最新版本require.js 2.1.11壓縮后只有1...
摘要:有幾個和模塊化相關的,,比較容易混淆。注意,我們并沒有引入。所以運行的結果是。同時,我們指定了變量。等于是在文件的最頂上,加上了。實際情況大致如此。把一個模塊導出并付給一個全局變量。假如中有代碼,那么后的值就為我們這里只討論瀏覽器環境。 Webpack有幾個和模塊化相關的loader,imports-loader,exports-loader,expose-loader,比較容易混淆。...
摘要:感謝感謝和在推動模塊化發展方面做出的貢獻。與引用阮一峰老師的標準參考教程規范加載模塊是同步的,也就是說,只有加載完成,才能執行后面的操作。規定了新的模塊加載方案。與引用阮一峰老師的入門它們有兩個重大差異。 前言 本篇我們重點介紹以下四種模塊加載規范: AMD CMD CommonJS ES6 模塊 最后再延伸講下 Babel 的編譯和 webpack 的打包原理。 require....
摘要:模塊化編程首先,我想說說模塊化編程這個概念當我不清楚這個概念的時候,其實說什么模塊化編程多好多好都是懵逼的而我一直不覺得有多好,其實也是因為我從開始寫,就一直都在模塊化編程啊我們寫一個文件然后我們在文件中引入然后調用方法哈哈這樣已經是模塊化 模塊化編程 首先,我想說說模塊化編程這個概念當我不清楚這個概念的時候,其實說什么模塊化編程多好多好都是懵逼的而我一直不覺得有多好,其實也是因為我從...
閱讀 895·2021-10-13 09:39
閱讀 1485·2021-10-11 10:57
閱讀 2597·2019-08-26 13:53
閱讀 2542·2019-08-26 12:23
閱讀 3694·2019-08-23 18:30
閱讀 3754·2019-08-23 18:08
閱讀 2527·2019-08-23 18:04
閱讀 2963·2019-08-23 16:28