From 62f1f2fe4737dd5ddc4876217090f62cccdce26d Mon Sep 17 00:00:00 2001 From: Eunchong Kim Date: Sun, 25 Jul 2021 00:39:26 +0900 Subject: [PATCH] Added color change --- README.md | 5 +++ js/uno_game.js | 10 ++--- src/js/basic_canvas.js | 10 +++++ src/js/bot.js | 4 ++ src/js/card.js | 36 +++++++---------- src/js/human.js | 2 + src/js/room.js | 88 +++++++++++++++++++++++++++--------------- 7 files changed, 96 insertions(+), 59 deletions(-) diff --git a/README.md b/README.md index 38e057d..453ff53 100644 --- a/README.md +++ b/README.md @@ -51,3 +51,8 @@ or npm run build ``` This command will generate `dist/main.js` + + + +## TODO +- multiplay diff --git a/js/uno_game.js b/js/uno_game.js index e5b76eb..d512eba 100644 --- a/js/uno_game.js +++ b/js/uno_game.js @@ -156,7 +156,7 @@ eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _js_ \********************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { -eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"default\": () => (/* binding */ BasicCanvas)\n/* harmony export */ });\nclass BasicCanvas {\n constructor(x, y, w, h) {\n this._x = x;\n this._y = y;\n this._w = w;\n this._h = h;\n\n // Create canvas\n this._canvas = document.createElement(\"CANVAS\");\n this._canvas.width = w;\n this._canvas.height = h;\n this._canvas.classList.add('uno-game-canv-default');\n\n // Canvas style\n this._z_index = __webpack_require__.g.canvas_count;\n __webpack_require__.g.canvas_count++;\n this._canvas.style = `left: ${x}px; top: ${y}px; z-index: ${this._z_index};`;\n\n // Add to div\n __webpack_require__.g.uno_game_div.appendChild( this._canvas );\n\n // Get ctx\n this._ctx = this._canvas.getContext('2d');\n }\n\n get canvas() {\n return this._canvas;\n }\n set canvas(canvas) {\n this._canvas = canvas;\n }\n\n get ctx() {\n return this._ctx;\n }\n set ctx(ctx) {\n this._ctx = ctx;\n }\n\n clear() {\n this._ctx.clearRect(0, 0, __webpack_require__.g.uno_game_w, __webpack_require__.g.uno_game_h);\n }\n\n resetEventListener() {\n // clone canvas and replace w/o event listener\n const canvas = this._canvas.cloneNode(true);\n const ctx = canvas.getContext('2d');\n this._canvas.parentNode.replaceChild(canvas, this._canvas);\n ctx.drawImage(this._canvas, 0, 0)\n this._canvas.remove();\n this._canvas = canvas;\n this._ctx = ctx;\n }\n\n move(x, y) {\n this._x = x;\n this._y = y;\n this._canvas.style.left = x + 'px';\n this._canvas.style.top = y + 'px';\n this.refresh();\n }\n\n scale(scale) {\n this._canvas.style.width = this._w * scale + 'px';\n this._canvas.style.height = this._h * scale + 'px';\n }\n\n refresh() {\n this._canvas.style.zIndex = __webpack_require__.g.canvas_count;\n __webpack_require__.g.canvas_count++;\n }\n\n remove() {\n this._canvas.remove();\n }\n\n}\n\n\n//# sourceURL=webpack://uno-game/./src/js/basic_canvas.js?"); +eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"default\": () => (/* binding */ BasicCanvas)\n/* harmony export */ });\nclass BasicCanvas {\n constructor(x, y, w, h) {\n this._x = x;\n this._y = y;\n this._w = w;\n this._h = h;\n\n // Create canvas\n this._canvas = document.createElement(\"CANVAS\");\n this._canvas.width = w;\n this._canvas.height = h;\n this._canvas.classList.add('uno-game-canv-default');\n\n // Canvas style\n this._z_index = __webpack_require__.g.canvas_count;\n __webpack_require__.g.canvas_count++;\n this._canvas.style = `left: ${x}px; top: ${y}px; z-index: ${this._z_index};`;\n\n // Add to div\n __webpack_require__.g.uno_game_div.appendChild( this._canvas );\n\n // Get ctx\n this._ctx = this._canvas.getContext('2d');\n }\n\n get canvas() {\n return this._canvas;\n }\n set canvas(canvas) {\n this._canvas = canvas;\n }\n\n get ctx() {\n return this._ctx;\n }\n set ctx(ctx) {\n this._ctx = ctx;\n }\n\n clear() {\n this._ctx.clearRect(0, 0, __webpack_require__.g.uno_game_w, __webpack_require__.g.uno_game_h);\n }\n\n fillColor(i) {\n const colors = { 0: 'red', 1: 'yellow', 2: 'green', 3: 'blue' };\n this._ctx.fillStyle = colors[i];\n this._ctx.rect(0, 0, this._w, this._h);\n this._ctx.fill();\n }\n\n resetEventListener() {\n // clone canvas and replace w/o event listener\n const canvas = this._canvas.cloneNode(true);\n const ctx = canvas.getContext('2d');\n this._canvas.parentNode.replaceChild(canvas, this._canvas);\n ctx.drawImage(this._canvas, 0, 0)\n this._canvas.remove();\n this._canvas = canvas;\n this._ctx = ctx;\n }\n\n move(x, y) {\n this._x = x;\n this._y = y;\n this._canvas.style.left = x + 'px';\n this._canvas.style.top = y + 'px';\n this.refresh();\n }\n\n scale(scale) {\n this._canvas.style.width = this._w * scale + 'px';\n this._canvas.style.height = this._h * scale + 'px';\n }\n\n refresh() {\n this._canvas.style.zIndex = __webpack_require__.g.canvas_count;\n __webpack_require__.g.canvas_count++;\n }\n\n remove() {\n console.log('remove canvas')\n this._canvas.parentNode.removeChild( this._canvas );\n this._canvas.remove();\n //delete this._canvas;\n }\n\n}\n\n\n//# sourceURL=webpack://uno-game/./src/js/basic_canvas.js?"); /***/ }), @@ -166,7 +166,7 @@ eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpac \***********************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { -eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"default\": () => (/* binding */ Bot)\n/* harmony export */ });\n/* harmony import */ var _player_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./player.js */ \"./src/js/player.js\");\n\n\nclass Bot extends _player_js__WEBPACK_IMPORTED_MODULE_0__.default {\n constructor(name, id) {\n super(name+id, id);\n this._type = 'bot';\n }\n\n playCard(top_card) {\n for (let i=0; i (/* binding */ Bot)\n/* harmony export */ });\n/* harmony import */ var _player_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./player.js */ \"./src/js/player.js\");\n\n\nclass Bot extends _player_js__WEBPACK_IMPORTED_MODULE_0__.default {\n constructor(name, id) {\n super(name+id, id);\n this._type = 'bot';\n }\n\n changeColor() {\n return Math.floor( Math.random() * 4 );\n }\n\n playCard(top_card) {\n for (let i=0; i { -eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"default\": () => (/* binding */ Card)\n/* harmony export */ });\n/* harmony import */ var _basic_canvas_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./basic_canvas.js */ \"./src/js/basic_canvas.js\");\n/* harmony import */ var _images_cards_svg__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../images/cards.svg */ \"./src/images/cards.svg\");\n/* harmony import */ var _images_card_back_svg__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../images/card_back.svg */ \"./src/images/card_back.svg\");\n\n/* Images */\n\n\n\nclass Card extends _basic_canvas_js__WEBPACK_IMPORTED_MODULE_0__.default {\n constructor(x, y, num, color_n) {\n super(x, y, __webpack_require__.g.uno_game_w/16, __webpack_require__.g.uno_game_w/16*360/240);\n\n this._c_w = 240;\n this._c_h = 360;\n\n this._num = num;\n this._color_n = color_n;\n\n this._cards_img = new Image();\n this._cards_img.src = _images_cards_svg__WEBPACK_IMPORTED_MODULE_1__;\n this._card_back_img = new Image();\n this._card_back_img.src = _images_card_back_svg__WEBPACK_IMPORTED_MODULE_2__;\n\n // Add border\n this._canvas.style.border = '1px solid #000000';\n\n // Add transition\n this._canvas.style.transition = '0.5s';\n\n // Fill\n this._card_back_img.addEventListener('load', () => {\n this._ctx.drawImage(this._card_back_img, 0, 0, this._w, this._h);\n this._is_front = false;\n });\n }\n\n get num() {\n return this._num;\n }\n set num(num) {\n this._num = num;\n }\n get color_n() {\n return this._color_n;\n }\n set color_n(color_n) {\n this._color_n = color_n;\n }\n\n isMatch(card) {\n if ( (this._num <= 12 && this._num === card.num)\n || (this._num >= 13)\n || (this._color_n === card.color_n) ) {\n return true;\n } else {\n return false;\n }\n }\n\n flip() {\n this.clear();\n if (this._is_front) {\n this._ctx.drawImage(this._card_back_img, 0, 0, this._w, this._h);\n this._is_front = false;\n } else {\n this._cards_img.addEventListener('load', () => {\n this._ctx.drawImage(this._cards_img, 1+this._c_w*this._num, 1+this._c_h*this._color_n, this._c_w, this._c_h,\n 0, 0, this._w, this._h);\n this._is_front = true;\n });\n }\n }\n\n async drawImageFront(x, y) {\n if (x && y) {\n this.move(x, y);\n }\n this.clear();\n this._cards_img.src = await (_images_cards_svg__WEBPACK_IMPORTED_MODULE_1__);\n this._ctx.drawImage(this._cards_img, 1+this._c_w*this._num, 1+this._c_h*this._color_n, this._c_w, this._c_h,\n 0, 0, this._w, this._h);\n }\n\n drawImageBack(x, y) {\n this.move(x, y);\n this.clear();\n this._ctx.drawImage(this._card_back_img, 0, 0, this._w, this._h);\n }\n\n mouseEffect() {\n this._canvas.addEventListener('mouseenter', () => {\n this._canvas.style.top = this._y - this._h/4 + 'px';\n });\n this._canvas.addEventListener('mouseleave', () => {\n this._canvas.style.top = this._y + 'px';\n });\n }\n\n}\n\n\n//# sourceURL=webpack://uno-game/./src/js/card.js?"); +eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"default\": () => (/* binding */ Card)\n/* harmony export */ });\n/* harmony import */ var _basic_canvas_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./basic_canvas.js */ \"./src/js/basic_canvas.js\");\n/* harmony import */ var _images_cards_svg__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../images/cards.svg */ \"./src/images/cards.svg\");\n/* harmony import */ var _images_card_back_svg__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../images/card_back.svg */ \"./src/images/card_back.svg\");\n\n/* Images */\n\n\n\nclass Card extends _basic_canvas_js__WEBPACK_IMPORTED_MODULE_0__.default {\n constructor(x, y, num, color_n) {\n super(x, y, __webpack_require__.g.uno_game_w/16, __webpack_require__.g.uno_game_w/16*360/240);\n\n this._c_w = 240;\n this._c_h = 360;\n\n this._num = num;\n this._color_n = color_n;\n\n this._cards_img = new Image();\n this._cards_img.src = _images_cards_svg__WEBPACK_IMPORTED_MODULE_1__;\n this._card_back_img = new Image();\n this._card_back_img.src = _images_card_back_svg__WEBPACK_IMPORTED_MODULE_2__;\n\n // Add border\n this._canvas.style.border = '1px solid #000000';\n\n // Add transition\n this._canvas.style.transition = '0.5s';\n\n // Fill\n this._card_back_img.addEventListener('load', () => {\n this._ctx.drawImage(this._card_back_img, 0, 0, this._w, this._h);\n this._is_front = false;\n });\n }\n\n get num() {\n return this._num;\n }\n set num(num) {\n this._num = num;\n }\n get color_n() {\n return this._color_n;\n }\n set color_n(color_n) {\n this._color_n = color_n;\n }\n\n isMatch(card) {\n if ( (card.num <= 12 && this._num === card.num) // Normal card\n || (card.num >= 13) // Change color card\n || (card.color_n === this._color_n) ) { // Color match\n return true;\n } else {\n return false;\n }\n }\n\n async drawImageFront(x, y) {\n if (x && y) this.move(x, y);\n this.clear();\n this._cards_img.src = await (_images_cards_svg__WEBPACK_IMPORTED_MODULE_1__);\n // Treat +4 card\n let num = this._num, color_n = this._color_n;\n if (num === 14) {\n num = 13;\n color_n += 4;\n }\n this._ctx.drawImage(this._cards_img, 1+this._c_w*num, 1+this._c_h*color_n, this._c_w, this._c_h,\n 0, 0, this._w, this._h);\n this._is_front = true;\n }\n\n drawImageBack(x, y) {\n if (x && y) this.move(x, y);\n this.clear();\n this._ctx.drawImage(this._card_back_img, 0, 0, this._w, this._h);\n this._is_front = false;\n }\n\n mouseEffect() {\n this._canvas.addEventListener('mouseenter', () => {\n this._canvas.style.top = this._y - this._h/4 + 'px';\n });\n this._canvas.addEventListener('mouseleave', () => {\n this._canvas.style.top = this._y + 'px';\n });\n }\n\n}\n\n\n//# sourceURL=webpack://uno-game/./src/js/card.js?"); /***/ }), @@ -196,7 +196,7 @@ eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpac \*************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { -eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"default\": () => (/* binding */ Human)\n/* harmony export */ });\n/* harmony import */ var _player_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./player.js */ \"./src/js/player.js\");\n\n\nclass Human extends _player_js__WEBPACK_IMPORTED_MODULE_0__.default {\n constructor(name, id) {\n super(name, id);\n\n this._type = 'human';\n }\n\n playCard(top_card) {\n return this._cards.splice(0, 1)[0];\n }\n\n}\n\n\n//# sourceURL=webpack://uno-game/./src/js/human.js?"); +eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"default\": () => (/* binding */ Human)\n/* harmony export */ });\n/* harmony import */ var _player_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./player.js */ \"./src/js/player.js\");\n/* harmony import */ var _basic_canvas_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./basic_canvas.js */ \"./src/js/basic_canvas.js\");\n\n\n\nclass Human extends _player_js__WEBPACK_IMPORTED_MODULE_0__.default {\n constructor(name, id) {\n super(name, id);\n\n this._type = 'human';\n }\n\n\n playCard(top_card) {\n return this._cards.splice(0, 1)[0];\n }\n\n}\n\n\n//# sourceURL=webpack://uno-game/./src/js/human.js?"); /***/ }), @@ -216,7 +216,7 @@ eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpac \************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { -eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"default\": () => (/* binding */ Room)\n/* harmony export */ });\n/* harmony import */ var _basic_canvas_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./basic_canvas.js */ \"./src/js/basic_canvas.js\");\n/* harmony import */ var _human_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./human.js */ \"./src/js/human.js\");\n/* harmony import */ var _bot_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./bot.js */ \"./src/js/bot.js\");\n/* harmony import */ var _card_js__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./card.js */ \"./src/js/card.js\");\n\n\n\n\n/* Images */\n\nclass Room extends _basic_canvas_js__WEBPACK_IMPORTED_MODULE_0__.default {\n constructor(name) {\n super(0, 0, __webpack_require__.g.uno_game_w, __webpack_require__.g.uno_game_h/10);\n\n this._name = name;\n this._players = [];\n this._cards = [];\n this._used_cards = [];\n\n // Fill room name\n this._ctx.font = Math.floor(this._h/3) + \"px Arial\";\n this._ctx.fillText(name, 10, 50);\n }\n\n addHuman(name) {\n this._players.push( new _human_js__WEBPACK_IMPORTED_MODULE_1__.default(name, this._players.length) );\n console.log(this._players);\n }\n\n addBot() {\n this._players.push( new _bot_js__WEBPACK_IMPORTED_MODULE_2__.default('bot', this._players.length) );\n console.log(this._players);\n }\n\n initCards() {\n console.log('Init')\n const index_arr = [...Array(108).keys()];\n for (let num=0; num<14; num++) {\n for (let color_n=0; color_n<8; color_n++) {\n if ( (num === 0) && (color_n >= 4) ) { // Skip blank card\n continue;\n }\n if ( (num === 13) && (color_n >= 4) ) { // +4 cards\n num = 14;\n }\n const card_index = index_arr.splice(Math.floor( Math.random() * index_arr.length), 1)[0];\n this._cards[ card_index ] = new _card_js__WEBPACK_IMPORTED_MODULE_3__.default(__webpack_require__.g.uno_game_w*6/16+card_index, __webpack_require__.g.uno_game_h/2, num, color_n%4);\n }\n }\n // re-order z-index\n for (let i=0; i {\n for (let i=0; i<7; i++) {\n player.addCard( this._cards.pop() );\n }\n });\n console.log(this._players);\n }\n\n async startGame() {\n console.log('Game start');\n\n // Init\n this._turn_count = 0;\n this._skip = false;\n this._reverse = false;\n this._draw2 = false;\n this._draw4 = false;\n this._current_player = this._players[0];\n\n await( this.changeTopCard( this._cards.pop() ) );\n\n this.initTurn();\n }\n\n initTurn() {\n // check draw cards\n if (this._draw2) {\n this._draw2 = false;\n for (let i=0; i<2; i++) this._current_player.addCard( this._cards.pop() );\n this.finishTurn();\n } else if (this._draw4) {\n this._draw4 = false;\n for (let i=0; i<4; i++) this._current_player.addCard( this._cards.pop() );\n this.finishTurn();\n } else {\n if (this._current_player.type === 'bot') {\n this.botTurn();\n } else {\n this.humanTurn();\n }\n }\n }\n\n async botTurn() {\n console.log('Turn count: ' + this._turn_count + ', current player: ' + this._current_player.name);\n await new Promise(resolve => setTimeout(resolve, 1000));\n\n const card = await( this._current_player.playCard(this._top_card) );\n if (card) {\n console.log('played card num: ' + card.num + ', color: ' + card.color_n);\n this.changeTopCard(card);\n this.treatCard(card);\n } else {\n const card = this._cards.pop();\n console.log('drawed card num: ' + card.num + ', color: ' + card.color_n);\n this._current_player.addCard(card);\n }\n\n this.finishTurn();\n }\n\n humanTurn() {\n console.log('Turn count: ' + this._turn_count + ', current player: ' + this._current_player.name);\n\n this._top_back_card = this._cards[ this._cards.length-1 ];\n this._top_back_card.mouseEffect();\n\n // Select card event\n this._current_player.cards.forEach( (card) => {\n if (this._top_card.isMatch(card)) {\n card.mouseEffect();\n\n card.canvas.addEventListener('click', () => {\n console.log('played card num: ' + card.num + ', color: ' + card.color_n);\n this._current_player.removeCard(card);\n\n // Remove event listener\n this._top_back_card.resetEventListener();\n this._current_player.cards.forEach( (card) => {\n card.resetEventListener();\n });\n\n this.changeTopCard(card);\n this.treatCard(card);\n this.finishTurn();\n });\n }\n });\n\n // Draw card event\n this._top_back_card.canvas.addEventListener('click', () => {\n const card = this._cards.pop();\n console.log('drawed card num: ' + card.num + ', color: ' + card.color_n);\n\n // Remove event listener\n this._top_back_card.resetEventListener();\n this._current_player.cards.forEach( (card) => {\n card.resetEventListener();\n });\n\n this._current_player.addCard(card);\n this.finishTurn();\n });\n\n }\n\n treatCard(card) {\n console.log('treat card num:' + card.num)\n switch (card.num) {\n case 10: // skip card\n this._skip = true;\n break;\n case 11: // reverse card\n this._reverse = (this._reverse) ? false : true;\n break;\n case 12: // +2 card\n this._draw2 = true;\n break;\n case 13: // change color card\n card.color_n = 0; // TODO\n break;\n case 14: // +4 card\n this._draw4 = true;\n break;\n default:\n break;\n }\n }\n\n async finishTurn() {\n console.log('finish turn')\n\n // re-deploy player's cards\n await( this._current_player.reDeployCards() );\n\n // Check empty\n if (this._current_player.isEmpty()) {\n console.log('player: ' + player.name + ' has no card left. Game end');\n } else {\n this._turn_count++;\n await ( this.decideNextPlayer() );\n this.initTurn();\n }\n }\n\n decideNextPlayer() {\n console.log('decide next player')\n\n let current_player_id = this._current_player.id;\n let loop_cnt = 1;\n if (this._skip) {\n this._skip = false;\n loop_cnt++;\n }\n for (let i=0; i (/* binding */ Room)\n/* harmony export */ });\n/* harmony import */ var _basic_canvas_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./basic_canvas.js */ \"./src/js/basic_canvas.js\");\n/* harmony import */ var _human_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./human.js */ \"./src/js/human.js\");\n/* harmony import */ var _bot_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./bot.js */ \"./src/js/bot.js\");\n/* harmony import */ var _card_js__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./card.js */ \"./src/js/card.js\");\n\n\n\n\n/* Images */\n\nclass Room extends _basic_canvas_js__WEBPACK_IMPORTED_MODULE_0__.default {\n constructor(name) {\n super(0, 0, __webpack_require__.g.uno_game_w, __webpack_require__.g.uno_game_h/10);\n\n this._name = name;\n this._players = [];\n this._cards = [];\n this._used_cards = [];\n\n // Fill room name\n this._ctx.font = Math.floor(this._h/3) + \"px Arial\";\n this._ctx.fillText(name, 10, 50);\n }\n\n addHuman(name) {\n this._players.push( new _human_js__WEBPACK_IMPORTED_MODULE_1__.default(name, this._players.length) );\n console.log(this._players);\n }\n\n addBot() {\n this._players.push( new _bot_js__WEBPACK_IMPORTED_MODULE_2__.default('bot', this._players.length) );\n console.log(this._players);\n }\n\n initCards() {\n console.log('Initialize cards')\n const index_arr = [...Array(108).keys()];\n for (let num=0; num<14; num++) {\n for (let color_n=0; color_n<8; color_n++) {\n if ( (num === 0) && (color_n >= 4) ) { // Skip blank card\n continue;\n }\n if ( (num === 13) && (color_n >= 4) ) { // +4 cards\n num = 14;\n }\n const card_index = index_arr.splice(Math.floor( Math.random() * index_arr.length), 1)[0];\n this._cards[ card_index ] = new _card_js__WEBPACK_IMPORTED_MODULE_3__.default(__webpack_require__.g.uno_game_w*6/16+card_index, __webpack_require__.g.uno_game_h/2, num, color_n%4);\n }\n }\n // re-order z-index\n for (let i=0; i {\n for (let i=0; i<7; i++) {\n player.addCard( this._cards.pop() );\n }\n });\n console.log(this._players);\n }\n\n async startGame() {\n console.log('Game start');\n\n // Init\n this._turn_count = 0;\n this._skip = false;\n this._reverse = false;\n this._draw2 = false;\n this._draw4 = false;\n this._current_player = this._players[0];\n\n await( this.changeTopCard( this._cards.pop() ) );\n\n this.initTurn();\n }\n\n initTurn() {\n // check draw cards\n if (this._draw2) {\n this._draw2 = false;\n for (let i=0; i<2; i++) this._current_player.addCard( this._cards.pop() );\n this.finishTurn();\n } else if (this._draw4) {\n this._draw4 = false;\n for (let i=0; i<4; i++) this._current_player.addCard( this._cards.pop() );\n this.finishTurn();\n } else {\n if (this._current_player.type === 'bot') {\n this.botTurn();\n } else {\n this.humanTurn();\n }\n }\n }\n\n async botTurn() {\n console.log('Turn count: ' + this._turn_count + ', current player: ' + this._current_player.name);\n await new Promise(resolve => setTimeout(resolve, 1000));\n\n const card = await( this._current_player.playCard(this._top_card) );\n if (card) {\n console.log('played card num: ' + card.num + ', color: ' + card.color_n);\n this.changeTopCard(card);\n } else {\n const card = this._cards.pop();\n console.log('drawed card num: ' + card.num + ', color: ' + card.color_n);\n this._current_player.addCard(card);\n }\n\n this.finishTurn();\n }\n\n humanTurn() {\n console.log('Turn count: ' + this._turn_count + ', current player: ' + this._current_player.name);\n\n this._top_back_card = this._cards[ this._cards.length-1 ];\n this._top_back_card.mouseEffect();\n\n // Select card event\n this._current_player.cards.forEach( (card) => {\n if (this._top_card.isMatch(card)) {\n card.mouseEffect();\n\n card.canvas.addEventListener('click', () => {\n console.log('played card num: ' + card.num + ', color: ' + card.color_n);\n this._current_player.removeCard(card);\n\n // Remove event listener\n this._top_back_card.resetEventListener();\n this._current_player.cards.forEach( (card) => {\n card.resetEventListener();\n });\n\n // Show color change blocks\n if (card.num === 13 || card.num === 14) {\n const bc_colors = [];\n for (let i=0; i<4; i++) {\n const w = __webpack_require__.g.uno_game_w;\n const bc = new _basic_canvas_js__WEBPACK_IMPORTED_MODULE_0__.default(w/2+w*i/16, __webpack_require__.g.uno_game_h*3/4, w/16, w/16);\n bc.fillColor(i);\n bc.canvas.addEventListener('click', () => {\n bc_colors.forEach( bc_color => bc_color.remove() );\n // Change card color\n card.color_n = i;\n // Process\n this.changeTopCard(card);\n this.finishTurn();\n });\n bc_colors.push(bc);\n }\n } else {\n this.changeTopCard(card);\n this.finishTurn();\n }\n });\n }\n });\n\n // Draw card event\n this._top_back_card.canvas.addEventListener('click', () => {\n const card = this._cards.pop();\n console.log('drawed card num: ' + card.num + ', color: ' + card.color_n);\n\n // Remove event listener\n this._top_back_card.resetEventListener();\n this._current_player.cards.forEach( (card) => {\n card.resetEventListener();\n });\n\n this._current_player.addCard(card);\n this.finishTurn();\n });\n }\n\n async finishTurn() {\n console.log('finish turn')\n\n // re-deploy player's cards\n await( this._current_player.reDeployCards() );\n\n // Check empty\n if (this._current_player.isEmpty()) {\n console.log('player: ' + this._current_player.name + ' has no card left. Game end');\n } else {\n this._turn_count++;\n await ( this.decideNextPlayer() );\n this.initTurn();\n }\n }\n\n decideNextPlayer() {\n console.log('decide next player')\n\n let current_player_id = this._current_player.id;\n let loop_cnt = 1;\n if (this._skip) {\n this._skip = false;\n loop_cnt++;\n }\n for (let i=0; i= 13) - || (this._color_n === card.color_n) ) { + if ( (card.num <= 12 && this._num === card.num) // Normal card + || (card.num >= 13) // Change color card + || (card.color_n === this._color_n) ) { // Color match return true; } else { return false; } } - flip() { - this.clear(); - if (this._is_front) { - this._ctx.drawImage(this._card_back_img, 0, 0, this._w, this._h); - this._is_front = false; - } else { - this._cards_img.addEventListener('load', () => { - this._ctx.drawImage(this._cards_img, 1+this._c_w*this._num, 1+this._c_h*this._color_n, this._c_w, this._c_h, - 0, 0, this._w, this._h); - this._is_front = true; - }); - } - } - async drawImageFront(x, y) { - if (x && y) { - this.move(x, y); - } + if (x && y) this.move(x, y); this.clear(); this._cards_img.src = await (cards_img); - this._ctx.drawImage(this._cards_img, 1+this._c_w*this._num, 1+this._c_h*this._color_n, this._c_w, this._c_h, + // Treat +4 card + let num = this._num, color_n = this._color_n; + if (num === 14) { + num = 13; + color_n += 4; + } + this._ctx.drawImage(this._cards_img, 1+this._c_w*num, 1+this._c_h*color_n, this._c_w, this._c_h, 0, 0, this._w, this._h); + this._is_front = true; } drawImageBack(x, y) { - this.move(x, y); + if (x && y) this.move(x, y); this.clear(); this._ctx.drawImage(this._card_back_img, 0, 0, this._w, this._h); + this._is_front = false; } mouseEffect() { diff --git a/src/js/human.js b/src/js/human.js index a837c51..9a34acf 100644 --- a/src/js/human.js +++ b/src/js/human.js @@ -1,4 +1,5 @@ import Player from './player.js'; +import BasicCanvas from './basic_canvas.js'; export default class Human extends Player { constructor(name, id) { @@ -7,6 +8,7 @@ export default class Human extends Player { this._type = 'human'; } + playCard(top_card) { return this._cards.splice(0, 1)[0]; } diff --git a/src/js/room.js b/src/js/room.js index 0e509fc..d7b58e8 100644 --- a/src/js/room.js +++ b/src/js/room.js @@ -29,7 +29,7 @@ export default class Room extends BasicCanvas { } initCards() { - console.log('Init') + console.log('Initialize cards') const index_arr = [...Array(108).keys()]; for (let num=0; num<14; num++) { for (let color_n=0; color_n<8; color_n++) { @@ -103,7 +103,6 @@ export default class Room extends BasicCanvas { if (card) { console.log('played card num: ' + card.num + ', color: ' + card.color_n); this.changeTopCard(card); - this.treatCard(card); } else { const card = this._cards.pop(); console.log('drawed card num: ' + card.num + ', color: ' + card.color_n); @@ -134,9 +133,27 @@ export default class Room extends BasicCanvas { card.resetEventListener(); }); - this.changeTopCard(card); - this.treatCard(card); - this.finishTurn(); + // Show color change blocks + if (card.num === 13 || card.num === 14) { + const bc_colors = []; + for (let i=0; i<4; i++) { + const w = global.uno_game_w; + const bc = new BasicCanvas(w/2+w*i/16, global.uno_game_h*3/4, w/16, w/16); + bc.fillColor(i); + bc.canvas.addEventListener('click', () => { + bc_colors.forEach( bc_color => bc_color.remove() ); + // Change card color + card.color_n = i; + // Process + this.changeTopCard(card); + this.finishTurn(); + }); + bc_colors.push(bc); + } + } else { + this.changeTopCard(card); + this.finishTurn(); + } }); } }); @@ -155,30 +172,6 @@ export default class Room extends BasicCanvas { this._current_player.addCard(card); this.finishTurn(); }); - - } - - treatCard(card) { - console.log('treat card num:' + card.num) - switch (card.num) { - case 10: // skip card - this._skip = true; - break; - case 11: // reverse card - this._reverse = (this._reverse) ? false : true; - break; - case 12: // +2 card - this._draw2 = true; - break; - case 13: // change color card - card.color_n = 0; // TODO - break; - case 14: // +4 card - this._draw4 = true; - break; - default: - break; - } } async finishTurn() { @@ -225,12 +218,43 @@ export default class Room extends BasicCanvas { } changeTopCard(card) { - if (this._top_card) { - this._used_cards.push(this._top_card); - } + if (this._top_card) this._used_cards.push(this._top_card); this._top_card = card; this._top_card.drawImageFront(global.uno_game_w*8/16+this._turn_count, global.uno_game_h/2); this._top_card.refresh(); + this.treatCard(); } + async treatCard() { + console.log('treat card num:' + this._top_card.num) + switch (this._top_card.num) { + case 10: // skip card + this._skip = true; + break; + case 11: // reverse card + this._reverse = (this._reverse) ? false : true; + break; + case 12: // +2 card + this._draw2 = true; + break; + case 13: // change color card + await ( this.changeColor() ); + break; + case 14: // +4 color change card + this._draw4 = true; + await ( this.changeColor() ); + break; + default: + break; + } + } + + changeColor() { + if (this._current_player.type === 'bot') { + this._top_card.color_n = this._current_player.changeColor(); + console.log('change color' + this._top_card.color_n); + } + } + + }