From e45bc45ff4457c3feae14abaab6e8675707c8967 Mon Sep 17 00:00:00 2001 From: Eunchong Kim Date: Sun, 1 Aug 2021 13:43:06 +0900 Subject: [PATCH] Major change 1. seperated view 2. use object data to communicate with room 3. changed main view and room view --- src/index.js | 85 +-------- src/js/bot.js | 23 --- src/js/card.js | 17 +- src/js/human.js | 16 -- src/js/player.js | 81 --------- src/js/room.js | 268 ++++++++++++++-------------- src/js/rule.js | 15 ++ src/js/view.js | 372 +++++++++++++++++++++++++++++++++++++++ src/styles/uno-game.scss | 60 ++++++- uno_game.js | 58 +++--- 10 files changed, 619 insertions(+), 376 deletions(-) delete mode 100644 src/js/bot.js delete mode 100644 src/js/human.js delete mode 100644 src/js/player.js create mode 100644 src/js/rule.js create mode 100644 src/js/view.js diff --git a/src/index.js b/src/index.js index 6b8dcce..b8b4f08 100644 --- a/src/index.js +++ b/src/index.js @@ -1,8 +1,7 @@ // index.js /* Class */ -import BasicCanvas from './js/basic_canvas.js'; -import Room from './js/room.js'; +import View from './js/view.js'; /* SCSS */ import './styles/uno-game.scss'; /* Image */ @@ -16,84 +15,18 @@ global.uno_game_div; global.uno_game_w = window.innerWidth-1; global.uno_game_h = window.innerHeight-1; +const view = new View(); /* Main view */ document.addEventListener('DOMContentLoaded', () => { - // Get uno-game-div + console.log('UNO GAME') + // Get uno-game div global.uno_game_div = document.getElementById('uno-game'); - global.uno_game_div.classList.add('uno-game-div'); - - // Create background canv - const bkg = new BasicCanvas(0, 0, global.uno_game_w, global.uno_game_h); - bkg.canvas.style.backgroundImage = 'url(' + green_table +')'; - - // Create UNO title - const title = document.createElement('h1'); - title.innerHTML = 'UNO Game'; - title.classList.add('uno-game-title'); - title.style.fontSize = global.uno_game_h/6 + 'px'; - title.style.top = global.uno_game_h/3 + 'px'; - title.style.zIndex = global.canvas_count; - global.canvas_count++; - global.uno_game_div.appendChild( title ); - - // Create div for button group - const btn_group = document.createElement('div'); - btn_group.classList.add('uno-game-btn-div'); - btn_group.style.top = global.uno_game_h*2/3 + 'px'; - btn_group.style.zIndex = global.canvas_count; - global.canvas_count++; - global.uno_game_div.appendChild( btn_group ); - - // Create single player button - const sp_btn = document.createElement('button'); - sp_btn.classList.add('uno-game-btn'); - sp_btn.innerHTML = 'Single Player'; - sp_btn.style.fontSize = global.uno_game_h/16 + 'px'; - btn_group.appendChild( sp_btn ); - - // Create multi player button - const mp_btn = document.createElement('button'); - mp_btn.classList.add('uno-game-btn'); - mp_btn.innerHTML = 'Multi Player (not work)'; - mp_btn.style.fontSize = global.uno_game_h/16 + 'px'; - btn_group.appendChild( mp_btn ); - - // Add event - sp_btn.addEventListener("click", e => { - // Remove elements - title.remove(); - sp_btn.remove(); - btn_group.remove(); - createRoom(); - }); + global.uno_game_div.classList.add('uno-game-main-div'); + global.uno_game_div.style.height = global.uno_game_h +'px'; + // Set background to div + global.uno_game_div.style.backgroundImage = 'url(' + green_table +')'; + view.showMainMenu(); }); - - -/* Game start */ -async function createRoom() { - console.info('Game start'); - - const room = new Room('room1'); - - room.addHuman('newini'); - room.addBot(); - room.addBot(); - room.addBot(); - - await( room.initCards() ); - - await new Promise(resolve => setTimeout(resolve, 1000)); - - await( room.dealCards() ); - - await new Promise(resolve => setTimeout(resolve, 500)); - - await( room.startGame() ); -} - - - -console.log('Uno End') diff --git a/src/js/bot.js b/src/js/bot.js deleted file mode 100644 index e7f0f7f..0000000 --- a/src/js/bot.js +++ /dev/null @@ -1,23 +0,0 @@ -import Player from './player.js'; - -export default class Bot extends Player { - constructor(name, id) { - super(name+id, id); - this._type = 'bot'; - } - - changeColor() { - return Math.floor( Math.random() * 4 ); - } - - playCard(top_card) { - for (let i=0; i (a.num > b.num) ? 1 : -1 ); - this.reDeployCards(); - } - -} diff --git a/src/js/room.js b/src/js/room.js index ed5fe50..0b1e6f5 100644 --- a/src/js/room.js +++ b/src/js/room.js @@ -1,110 +1,135 @@ -import BasicCanvas from './basic_canvas.js'; -import Human from './human.js'; -import Bot from './bot.js'; -import Card from './card.js'; -/* Images */ +import Rule from './rule.js'; -export default class Room extends BasicCanvas { +export default class Room { constructor(name) { - super(0, 0, global.uno_game_w, global.uno_game_h/10); + this._rule = new Rule(); this._name = name; this._players = []; - this._cards = []; - this._used_cards = []; + this._remain_cards = []; + this._discard_piles = []; + this._discard_pile_top = {}; + this._current_player = {}; + this._game_status = 'ready'; + } - // Fill room name - this._ctx.font = Math.floor(this._h/3) + "px Arial"; - this._ctx.fillText(name, 10, 50); + receive(data) { + if (data.ctrl === 'addHuman') this.addHuman(data.name); + else if (data.ctrl === 'addBot') this.addBot(); + else if (data.ctrl === 'startGame') this.startGame(); + else if (data.ctrl === 'playCard') this.playCard(data.card); + else if (data.ctrl === 'changeColor') this.changeColor(data.color_n); + else if (data.ctrl === 'drawCard') this.drawCard(); } addHuman(name) { - this._players.push( new Human(name, this._players.length) ); + this._players.push( {type: 'human', name: name, id: this._players.length } ); console.log(this._players); } addBot() { - this._players.push( new Bot('bot', this._players.length) ); + this._players.push( {type: 'bot', name: 'bot'+this._players.length, id: this._players.length} ); console.log(this._players); } - initCards() { - 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++) { - if ( (num === 0) && (color_n >= 4) ) { // Skip blank card - continue; - } - if ( (num === 13) && (color_n >= 4) ) { // +4 cards - num = 14; - } - const card_index = index_arr.splice(Math.floor( Math.random() * index_arr.length), 1)[0]; - this._cards[ card_index ] = new Card(global.uno_game_w*6/16+card_index, global.uno_game_h/2, num, color_n%4); - } - } - // re-order z-index - for (let i=0; i { - for (let i=0; i<7; i++) { - player.addCard( this._cards.pop() ); - } - }); + respondData() { + return JSON.stringify( { + room: { + name: this._name + }, + players: this._players, + remain_cards: this._remain_cards, + discard_piles: this._discard_piles, + discard_pile_top: this._discard_pile_top, + current_player: this._current_player, + game_status: this._game_status + } ); } async startGame() { - console.log('Game start'); + console.log('[Room] Game start'); // Init - this._turn_count = 0; + this._game_status = 'init'; this._skip = false; this._reverse = false; this._draw2 = false; this._draw4 = false; - this._current_player = this._players[0]; + this._wild = false; + this._turn_count = 0, - await( this.initDiscardPile() ); + await ( this.initCards() ); + await new Promise(resolve => setTimeout(resolve, 100)); + await ( this.dealCards() ); + await new Promise(resolve => setTimeout(resolve, 100)); + await ( this.initDiscardPile() ); + await new Promise(resolve => setTimeout(resolve, 500)); + + this._current_player = this._players[0]; + await new Promise(resolve => setTimeout(resolve, 500)); + this._game_status = 'start'; this.initTurn(); } + initCards() { + console.log('[Room] Initialize cards') + + const index_arr = [...Array(108).keys()]; // Create index pool + for (let x=0; x<14; x++) { + let num = x; + for (let y=0; y<8; y++) { + const color_n = y%4; + if ( (x === 0) && (y >= 4) ) continue; // Skip blank card + if ( (x === 13) && (y >= 4) ) num = 14; // +4 cards + // Get random index + const card_index = index_arr.splice(Math.floor( Math.random() * index_arr.length), 1)[0]; + this._remain_cards[ card_index ] = {num: num, color_n: color_n, x: x, y: y}; + } + } + } + + dealCards(n_deal_cards=7) { + console.log('[Room] Deal cards') + this._players.forEach( (player) => { + player.cards = []; + for (let i=0; i (a.num > b.num) ? 1 : -1 ); + }); + } + // Not allow special card to be first discard pile initDiscardPile() { while (true) { - const card = this._cards.pop(); + const card = this._remain_cards.pop(); if (card.num <= 9) { this.changeTopCard( card ); break; } else { - this._cards.splice( Math.floor(Math.random()*this._cards.length), 0, card); + // push back to a random position + this._remain_cards.splice( Math.floor(Math.random()*this._remain_cards.length), 0, card); } } } async initTurn() { - console.log('Turn count: ' + this._turn_count + ', current player: ' + this._current_player.name); + console.log('[Room] Turn count: ' + this._turn_count + ', current player: ' + this._current_player.name); await new Promise(resolve => setTimeout(resolve, 500)); // check draw cards if (this._draw2) { this._draw2 = false; - for (let i=0; i<2; i++) this._current_player.addCard( this._cards.pop() ); + for (let i=0; i<2; i++) this._current_player.cards.push( this._remain_cards.pop() ); + this._current_player.cards.sort( (a, b) => (a.num > b.num) ? 1 : -1 ); this.finishTurn(); } else if (this._draw4) { this._draw4 = false; - for (let i=0; i<4; i++) this._current_player.addCard( this._cards.pop() ); + for (let i=0; i<4; i++) this._current_player.cards.push( this._remain_cards.pop() ); + this._current_player.cards.sort( (a, b) => (a.num > b.num) ? 1 : -1 ); this.finishTurn(); } else { if (this._current_player.type === 'bot') { this.botTurn(); - } else { - this.humanTurn(); } } } @@ -112,88 +137,61 @@ export default class Room extends BasicCanvas { async botTurn() { await new Promise(resolve => setTimeout(resolve, 500)); - const card = await( this._current_player.playCard(this._top_discard_pile) ); - if (card) { - console.log('played card num: ' + card.num + ', color: ' + card.color_n); - this.changeTopCard(card); - } else { - const card = this._cards.pop(); - console.log('drawed card num: ' + card.num + ', color: ' + card.color_n); - this._current_player.addCard(card); - } + const card = await ( this.botChooseCard() ); + if (card) { + this.playCard(card); + } else { + this.drawCard(); + } + } + + botChooseCard() { + for (let i=0; i= 13) { // Change color + this.changeColor( Math.floor( Math.random() * 4 ) ); + } + return card; + } + } + return null; + } + + playCard(card) { + console.log('[Room] played card num: ' + card.num + ', color: ' + card.color_n); + const player = this._current_player; + // Remove card from player cards + player.cards.splice(player.cards.findIndex(c => (c.x === card.x && c.y === card.y)), 1); + + this.changeTopCard(card); this.finishTurn(); } - humanTurn() { - this._top_draw_card = this._cards[ this._cards.length-1 ]; - this._top_draw_card.mouseEffect(); + changeColor(color_n) { + this._wild = true; + this._wild_color_n = color_n; + } - // Select card event - this._current_player.cards.forEach( (card) => { - if (this._top_discard_pile.isMatch(card)) { - card.mouseEffect(); + drawCard() { + const card = this._remain_cards.pop(); + console.log('[Room] drawed card num: ' + card.num + ', color: ' + card.color_n); - card.canvas.addEventListener('click', () => { - console.log('played card num: ' + card.num + ', color: ' + card.color_n); - this._current_player.removeCard(card); - - // Remove event listener - this._top_draw_card.resetEventListener(); - this._current_player.cards.forEach( (card) => { - card.resetEventListener(); - }); - - // 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(); - } - }); - } - }); - - // Draw card event - this._top_draw_card.canvas.addEventListener('click', () => { - const card = this._cards.pop(); - console.log('drawed card num: ' + card.num + ', color: ' + card.color_n); - - // Remove event listener - this._top_draw_card.resetEventListener(); - this._current_player.cards.forEach( (card) => { - card.resetEventListener(); - }); - - this._current_player.addCard(card); - this.finishTurn(); - }); + this._current_player.cards.push(card); + this._current_player.cards.sort( (a, b) => (a.num > b.num) ? 1 : -1 ); + this.finishTurn(); } async finishTurn() { - console.log('finish turn') + console.log('[Room] finish turn') - // re-deploy player's cards - await( this._current_player.reDeployCards() ); + await new Promise(resolve => setTimeout(resolve, 500)); // Check empty - if (this._current_player.isEmpty()) { - console.log('player: ' + this._current_player.name + ' has no card left. Game end'); + if (this._current_player.cards.length === 0) { + console.log('[Room] player: ' + this._current_player.name + ' has no card left. Game end'); + this._game_status = 'finish'; } else { this._turn_count++; await ( this.decideNextPlayer() ); @@ -221,15 +219,18 @@ export default class Room extends BasicCanvas { } changeTopCard(card) { - if (this._top_discard_pile) this._used_cards.push(this._top_discard_pile); - this._top_discard_pile = card; - this._top_discard_pile.drawImageFront(global.uno_game_w*8/16+this._turn_count, global.uno_game_h/2); - this._top_discard_pile.refresh(); + console.log('[Room] change top card num: ' + card.num + ', color_n: ' + card.color_n) + if (this._discard_pile_top.x) this._discard_piles.push(this._discard_pile_top); + this._discard_pile_top = card; + if (this._wild) { + this._wild = false; + this._discard_pile_top.color_n = this._wild_color_n; + } this.treatCard(); } async treatCard() { - switch (this._top_discard_pile.num) { + switch (this._discard_pile_top.num) { case 10: // skip card this._skip = true; console.log('skip'); @@ -243,23 +244,16 @@ export default class Room extends BasicCanvas { console.log('next player draw 2 cards'); break; case 13: // wild card (change color) - await ( this.changeColor() ); - console.log('change color: ' + this._top_discard_pile.color_n); + console.log('change color: ' + this._discard_pile_top.color_n); break; case 14: // wild draw 4 card (change color) this._draw4 = true; - await ( this.changeColor() ); console.log('next player draw 4 cards'); - console.log('change color: ' + this._top_discard_pile.color_n); + console.log('change color: ' + this._discard_pile_top.color_n); break; default: break; } } - changeColor() { - if (this._current_player.type === 'bot') this._top_discard_pile.color_n = this._current_player.changeColor(); - } - - } diff --git a/src/js/rule.js b/src/js/rule.js new file mode 100644 index 0000000..30a52e2 --- /dev/null +++ b/src/js/rule.js @@ -0,0 +1,15 @@ +export default class Rule { + constructor() { + + } + + checkCardsMatch(card1, card2) { + if ( (card2.num <= 12 && card1.num === card2.num) // Normal card + || (card2.num >= 13) // Change color card + || (card2.color_n === card1.color_n) ) { // Color match + return true; + } else { + return false; + } + } +} diff --git a/src/js/view.js b/src/js/view.js new file mode 100644 index 0000000..72aa889 --- /dev/null +++ b/src/js/view.js @@ -0,0 +1,372 @@ +// view.js + +/* Class */ +import BasicCanvas from './basic_canvas.js'; +import Room from './room.js'; +import Card from './card.js'; +import Rule from './rule.js'; + +export default class View { + constructor() { + this._data = {}; + this._rule = new Rule(); + this._is_initialized = false; + } + + showMainMenu() { + // Create div + const div = document.createElement('div'); + div.classList.add('uno-game-div'); + div.style.top = global.uno_game_h/4 + 'px'; + global.uno_game_div.appendChild( div ); + + // Create UNO title + const title = document.createElement('h1'); + title.innerHTML = 'UNO Game'; + title.classList.add('uno-game-main-title'); + div.appendChild( title ); + + // label for input name + const label_n = document.createElement('label'); + label_n.innerHTML = 'Input My Name'; + label_n.classList.add('uno-game-label'); + div.appendChild( label_n ); + + // Input name + const input_n = document.createElement('input'); + input_n.type = 'text'; + input_n.value = (this._my_name) ? this._my_name : ''; + input_n.className = 'uno-game-input'; + div.appendChild( input_n ); + + // Create find room button + const fr_btn = document.createElement('button'); + fr_btn.classList.add('uno-game-btn'); + fr_btn.innerHTML = 'Find Room'; + div.appendChild( fr_btn ); + + // Add event + //this._fr_btn.addEventListener("click", e => { + // this._my_name = input_n.value; + // this.clearMainMenu(); + // this.findRoom(); + // this._is_host = false; + //}); + + // Create create room button + const cr_btn = document.createElement('button'); + cr_btn.classList.add('uno-game-btn'); + cr_btn.innerHTML = 'Create Room'; + div.appendChild( cr_btn ); + + // Add event + cr_btn.addEventListener("click", e => { + this._my_name = input_n.value; + div.remove(); + this.showCreateRoomMenu(); + this._is_host = true; + }); + + } + + showCreateRoomMenu() { + // Create div + const div = document.createElement('div'); + div.classList.add('uno-game-div'); + div.style.top = global.uno_game_h/4 + 'px'; + global.uno_game_div.appendChild( div ); + + // Menu title + const title = document.createElement('h2'); + title.innerHTML = 'Create Room'; + title.classList.add('uno-game-menu-title'); + div.appendChild( title ); + + // label for input room name + const label_rn = document.createElement('label'); + label_rn.innerHTML = 'Input Room Name'; + label_rn.classList.add('uno-game-label'); + div.appendChild( label_rn ); + + // Input room name + const input_rn = document.createElement('input'); + input_rn.type = 'text'; + input_rn.className = 'uno-game-input'; + div.appendChild( input_rn ); + + // Confirm button + const cfm_btn = document.createElement('button'); + cfm_btn.classList.add('uno-game-btn'); + cfm_btn.innerHTML = 'Confirm'; + div.appendChild( cfm_btn ); + + cfm_btn.addEventListener('click', e => { + this._room = new Room( input_rn.value ); + this.send({ctrl: 'addHuman', name: this._my_name}); + this._data = JSON.parse( this._room.respondData() ); + this.showRoom(); + div.remove(); + }); + + // Back button + const back_btn = document.createElement('button'); + back_btn.classList.add('uno-game-btn'); + back_btn.innerHTML = 'Back'; + div.appendChild( back_btn ); + + back_btn.addEventListener('click', e => { + div.remove(); + this.showMainMenu(); + }); + } + + async showRoom() { + // Create div + this._div = document.createElement('div'); + this._div.classList.add('uno-game-div'); + this._div.style.top = global.uno_game_h/5 + 'px'; + global.uno_game_div.appendChild( this._div ); + + // Menu title + const title = document.createElement('h2'); + title.innerHTML = this._data.room.name; + title.classList.add('uno-game-menu-title'); + this._div.appendChild( title ); + + if (this._is_host) { + // Add bot button + const ab_btn = document.createElement('button'); + ab_btn.classList.add('uno-game-btn'); + ab_btn.innerHTML = 'Add Bot'; + this._div.appendChild( ab_btn ); + + ab_btn.addEventListener('click', e => { + this.send({ctrl: 'addBot'}); + }); + + // Start game button + const sg_btn = document.createElement('button'); + sg_btn.classList.add('uno-game-btn'); + sg_btn.innerHTML = 'Star Game'; + this._div.appendChild( sg_btn ); + + sg_btn.addEventListener('click', e => { + this.send({ctrl: 'startGame'}); + this._div.remove(); + }); + } + + // List players + const ul_pl = document.createElement('ul'); + ul_pl.classList.add('uno-game-ul'); + this._div.appendChild( ul_pl ); + + this._data.players.forEach( (player) => { + const li = document.createElement('li'); + li.classList.add('uno-game-li'); + li.innerHTML = player.name; + ul_pl.appendChild( li ); + }); + + if (!this._loop_started) { + this._loop_started = true; + this.loopReceiveData(); + } + } + + async loopReceiveData() { + let is_finished = false; + while(true) { + const data = await ( JSON.parse( this._room.respondData() ) ); + + switch (data.game_status) { + case 'ready': + if ( JSON.stringify(this._data.players) != JSON.stringify(data.players) ) { + this._data = data; + this._div.remove(); + this.showRoom(); + } + break; + case 'start': + if (!this._is_initialized) { + await ( this.initCards() ); + await new Promise(resolve => setTimeout(resolve, 500)); // Sleep .5 s + this._is_initialized = true; + } + if ( JSON.stringify(this._data.current_player) != JSON.stringify(data.current_player) ) { + console.log('current_player changed') + this._data = data; + await ( this.updateCards() ); + if (data.current_player.name === this._my_name) this.myTurn(); + } + break; + case 'finish': + this._data = data; + await ( this.updateCards() ); + is_finished = true; + this.gameFinish(); + break; + } + if (is_finished) break; + await new Promise(resolve => setTimeout(resolve, 500)); // Sleep .5 s + } + } + + send(data) { + this._room.receive(data); + } + + async initCards() { + console.log('init cards') + this._cards = []; + let count = 0 + for (let x=0; x<14; x++) { + this._cards[x] = []; + } + for (let x=0; x<14; x++) { + let num = x; + for (let y=0; y<8; y++) { + const color_n = y%4; + if ( (x === 0) && (y >= 4) ) { // Skip blank card + continue; + } + if ( (x === 13) && (y >= 4) ) { // +4 cards + num = 14; + } + this._cards[x][y] = new Card(global.uno_game_w*6/16+count, global.uno_game_h/2, num, color_n); + count++; + } + } + } + + updateCards() { + console.log('update cards view') + // Player Cards + const p_l = this._data.players.length; + let p_cnt = 0; + + this._data.players.forEach( player => { + const c_l = player.cards.length; + + for (let c=0; c { + const card = this._cards[card_data.x][card_data.y]; + if (this._rule.checkCardsMatch(this._data.discard_pile_top, card.data)) { + card.mouseEffect(); + + card.canvas.addEventListener('click', () => { + // Show color change blocks + if (card.num >= 13) { + 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', () => { + console.log('played card num: ' + card.num + ', color: ' + card.color_n); + + // Remove event listeners + this._top_draw_card.resetEventListener(); + this._data.current_player.cards.forEach( (card_data) => { + const card = this._cards[card_data.x][card_data.y]; + card.resetEventListener(); + }); + bc_colors.forEach( bc_color => bc_color.remove() ); + + this.send({ctrl: 'changeColor', color_n: i}); + this.send({ + ctrl: 'playCard', + card: {num: card.num, color_n: card.color_n, x: card_data.x, y: card_data.y} + }); + }); + bc_colors.push(bc); + } + } else { + console.log('played card num: ' + card.num + ', color_n: ' + card.color_n); + + // Remove event listener + this._top_draw_card.resetEventListener(); + this._data.current_player.cards.forEach( (card_data) => { + const card = this._cards[card_data.x][card_data.y]; + card.resetEventListener(); + }); + bc_colors.forEach( bc_color => bc_color.remove() ); + + this.send({ + ctrl: 'playCard', + card: {num: card.num, color_n: card.color_n, x: card_data.x, y: card_data.y} + }); + } + }); + } + }); + + // Draw card event + this._top_draw_card.canvas.addEventListener('click', () => { + console.log('drawed card'); + + // Remove event listener + this._top_draw_card.resetEventListener(); + this._data.current_player.cards.forEach( (card_data) => { + const card = this._cards[card_data.x][card_data.y]; + card.resetEventListener(); + }); + bc_colors.forEach( bc_color => bc_color.remove() ); + + this.send({ctrl: 'drawCard'}); + }); + } + + gameFinish() { + + } +} diff --git a/src/styles/uno-game.scss b/src/styles/uno-game.scss index 8efff3f..43f7b20 100644 --- a/src/styles/uno-game.scss +++ b/src/styles/uno-game.scss @@ -1,7 +1,9 @@ -.uno-game-div { +.uno-game-main-div { width: 100%; height: 100%; margin: 0; + padding: 0; + overflow: hidden; } /* Common */ @@ -10,15 +12,16 @@ display: block; } -/* Main view */ -.uno-game-title { - position: absolute; +/* View */ +// Title +.uno-game-main-title { left: 0; right: 0; font-family: 'Waiting for the Sunrise', cursive; font-weight: bold; text-align: center; + font-size: calc(16vh); overflow: hidden; /* Ensures the content is not revealed until the animation */ border-right: .15em solid orange; /* The typwriter cursor */ @@ -39,6 +42,25 @@ from, to { border-color: transparent } 50% { border-color: orange; } } +.uno-game-menu-title { + left: 0; + right: 0; + + font-family: 'Waiting for the Sunrise', cursive; + text-align: center; + font-size: calc(14vh); + + overflow: hidden; /* Ensures the content is not revealed until the animation */ + white-space: nowrap; /* Keeps the content on a single line */ + margin: 0 auto; /* Gives that scrolling effect as the typing happens */ +} +// Div +.uno-game-div { + position: absolute; + left: 0; + right: 0; +} +// Button .uno-game-btn-div { position: absolute; left: 0; @@ -53,8 +75,36 @@ color: white; cursor: pointer; /* Pointer/hand icon */ display: block; /* Make the buttons appear below each other */ + font-size: calc(6vh); } .uno-game-btn:hover { background-color: olive; } - +// Label +.uno-game-label { + padding: 15px 32px; + margin: auto; + display: block; + text-align: center; + font-size: calc(6vh); +} +// Input +.uno-game-input { + padding: 15px 32px; + margin: auto; + display: block; + font-size: calc(6vh); +} +// UL +.uno-game-ul { + padding: 15px 32px; + margin: auto; + //display: block; + //font-size: calc(6vh); +} +.uno-game-li { + padding: 15px 32px; + margin: auto; + display: block; + font-size: calc(4vh); +} diff --git a/uno_game.js b/uno_game.js index 936e29e..3c56417 100644 --- a/uno_game.js +++ b/uno_game.js @@ -16,7 +16,7 @@ \***************************************************************************************************************/ /***/ ((module, __webpack_exports__, __webpack_require__) => { -eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"default\": () => (__WEBPACK_DEFAULT_EXPORT__)\n/* harmony export */ });\n/* harmony import */ var _node_modules_css_loader_dist_runtime_api_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../../node_modules/css-loader/dist/runtime/api.js */ \"./node_modules/css-loader/dist/runtime/api.js\");\n/* harmony import */ var _node_modules_css_loader_dist_runtime_api_js__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(_node_modules_css_loader_dist_runtime_api_js__WEBPACK_IMPORTED_MODULE_0__);\n// Imports\n\nvar ___CSS_LOADER_EXPORT___ = _node_modules_css_loader_dist_runtime_api_js__WEBPACK_IMPORTED_MODULE_0___default()(function(i){return i[1]});\n// Module\n___CSS_LOADER_EXPORT___.push([module.id, \".uno-game-div {\\n width: 100%;\\n height: 100%;\\n margin: 0;\\n}\\n\\n/* Common */\\n.uno-game-canv-default {\\n position: absolute;\\n display: block;\\n}\\n\\n/* Main view */\\n.uno-game-title {\\n position: absolute;\\n left: 0;\\n right: 0;\\n font-family: \\\"Waiting for the Sunrise\\\", cursive;\\n font-weight: bold;\\n text-align: center;\\n overflow: hidden;\\n /* Ensures the content is not revealed until the animation */\\n border-right: 0.15em solid orange;\\n /* The typwriter cursor */\\n white-space: nowrap;\\n /* Keeps the content on a single line */\\n margin: 0 auto;\\n /* Gives that scrolling effect as the typing happens */\\n letter-spacing: 0.15em;\\n /* Adjust as needed */\\n animation: typing 3.5s steps(20, end), blink-caret 0.75s step-end infinite;\\n}\\n\\n/* The typing effect */\\n@keyframes typing {\\n from {\\n width: 0;\\n }\\n to {\\n width: 100%;\\n }\\n}\\n/* The typewriter cursor effect */\\n@keyframes blink-caret {\\n from, to {\\n border-color: transparent;\\n }\\n 50% {\\n border-color: orange;\\n }\\n}\\n.uno-game-btn-div {\\n position: absolute;\\n left: 0;\\n right: 0;\\n}\\n\\n.uno-game-btn {\\n padding: 15px 32px;\\n margin: auto;\\n background-color: Transparent;\\n border: none;\\n color: white;\\n cursor: pointer;\\n /* Pointer/hand icon */\\n display: block;\\n /* Make the buttons appear below each other */\\n}\\n\\n.uno-game-btn:hover {\\n background-color: olive;\\n}\", \"\"]);\n// Exports\n/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (___CSS_LOADER_EXPORT___);\n\n\n//# sourceURL=webpack://uno-game/./src/styles/uno-game.scss?./node_modules/css-loader/dist/cjs.js!./node_modules/sass-loader/dist/cjs.js"); +eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"default\": () => (__WEBPACK_DEFAULT_EXPORT__)\n/* harmony export */ });\n/* harmony import */ var _node_modules_css_loader_dist_runtime_api_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../../node_modules/css-loader/dist/runtime/api.js */ \"./node_modules/css-loader/dist/runtime/api.js\");\n/* harmony import */ var _node_modules_css_loader_dist_runtime_api_js__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(_node_modules_css_loader_dist_runtime_api_js__WEBPACK_IMPORTED_MODULE_0__);\n// Imports\n\nvar ___CSS_LOADER_EXPORT___ = _node_modules_css_loader_dist_runtime_api_js__WEBPACK_IMPORTED_MODULE_0___default()(function(i){return i[1]});\n// Module\n___CSS_LOADER_EXPORT___.push([module.id, \".uno-game-main-div {\\n width: 100%;\\n height: 100%;\\n margin: 0;\\n padding: 0;\\n overflow: hidden;\\n}\\n\\n/* Common */\\n.uno-game-canv-default {\\n position: absolute;\\n display: block;\\n}\\n\\n/* View */\\n.uno-game-main-title {\\n left: 0;\\n right: 0;\\n font-family: \\\"Waiting for the Sunrise\\\", cursive;\\n font-weight: bold;\\n text-align: center;\\n font-size: calc(16vh);\\n overflow: hidden;\\n /* Ensures the content is not revealed until the animation */\\n border-right: 0.15em solid orange;\\n /* The typwriter cursor */\\n white-space: nowrap;\\n /* Keeps the content on a single line */\\n margin: 0 auto;\\n /* Gives that scrolling effect as the typing happens */\\n letter-spacing: 0.15em;\\n /* Adjust as needed */\\n animation: typing 3.5s steps(20, end), blink-caret 0.75s step-end infinite;\\n}\\n\\n/* The typing effect */\\n@keyframes typing {\\n from {\\n width: 0;\\n }\\n to {\\n width: 100%;\\n }\\n}\\n/* The typewriter cursor effect */\\n@keyframes blink-caret {\\n from, to {\\n border-color: transparent;\\n }\\n 50% {\\n border-color: orange;\\n }\\n}\\n.uno-game-menu-title {\\n left: 0;\\n right: 0;\\n font-family: \\\"Waiting for the Sunrise\\\", cursive;\\n text-align: center;\\n font-size: calc(14vh);\\n overflow: hidden;\\n /* Ensures the content is not revealed until the animation */\\n white-space: nowrap;\\n /* Keeps the content on a single line */\\n margin: 0 auto;\\n /* Gives that scrolling effect as the typing happens */\\n}\\n\\n.uno-game-div {\\n position: absolute;\\n left: 0;\\n right: 0;\\n}\\n\\n.uno-game-btn-div {\\n position: absolute;\\n left: 0;\\n right: 0;\\n}\\n\\n.uno-game-btn {\\n padding: 15px 32px;\\n margin: auto;\\n background-color: Transparent;\\n border: none;\\n color: white;\\n cursor: pointer;\\n /* Pointer/hand icon */\\n display: block;\\n /* Make the buttons appear below each other */\\n font-size: calc(6vh);\\n}\\n\\n.uno-game-btn:hover {\\n background-color: olive;\\n}\\n\\n.uno-game-label {\\n padding: 15px 32px;\\n margin: auto;\\n display: block;\\n text-align: center;\\n font-size: calc(6vh);\\n}\\n\\n.uno-game-input {\\n padding: 15px 32px;\\n margin: auto;\\n display: block;\\n font-size: calc(6vh);\\n}\\n\\n.uno-game-ul {\\n padding: 15px 32px;\\n margin: auto;\\n}\\n\\n.uno-game-li {\\n padding: 15px 32px;\\n margin: auto;\\n display: block;\\n font-size: calc(4vh);\\n}\", \"\"]);\n// Exports\n/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (___CSS_LOADER_EXPORT___);\n\n\n//# sourceURL=webpack://uno-game/./src/styles/uno-game.scss?./node_modules/css-loader/dist/cjs.js!./node_modules/sass-loader/dist/cjs.js"); /***/ }), @@ -136,7 +136,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 import */ var _js_basic_canvas_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./js/basic_canvas.js */ \"./src/js/basic_canvas.js\");\n/* harmony import */ var _js_room_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./js/room.js */ \"./src/js/room.js\");\n/* harmony import */ var _styles_uno_game_scss__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./styles/uno-game.scss */ \"./src/styles/uno-game.scss\");\n/* harmony import */ var _images_green_table_jpg__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./images/green_table.jpg */ \"./src/images/green_table.jpg\");\n// index.js\n\n/* Class */\n\n\n/* SCSS */\n\n/* Image */\n\n\n// Global variables\n__webpack_require__.g.canvas_count = 0; // increment number to avoid the same canvas id\n\n// uno-game-div must be found\n__webpack_require__.g.uno_game_div;\n__webpack_require__.g.uno_game_w = window.innerWidth-1;\n__webpack_require__.g.uno_game_h = window.innerHeight-1;\n\n\n/* Main view */\ndocument.addEventListener('DOMContentLoaded', () => {\n // Get uno-game-div\n __webpack_require__.g.uno_game_div = document.getElementById('uno-game');\n __webpack_require__.g.uno_game_div.classList.add('uno-game-div');\n\n // Create background canv\n const bkg = new _js_basic_canvas_js__WEBPACK_IMPORTED_MODULE_0__.default(0, 0, __webpack_require__.g.uno_game_w, __webpack_require__.g.uno_game_h);\n bkg.canvas.style.backgroundImage = 'url(' + _images_green_table_jpg__WEBPACK_IMPORTED_MODULE_3__.default +')';\n\n // Create UNO title\n const title = document.createElement('h1');\n title.innerHTML = 'UNO Game';\n title.classList.add('uno-game-title');\n title.style.fontSize = __webpack_require__.g.uno_game_h/6 + 'px';\n title.style.top = __webpack_require__.g.uno_game_h/3 + 'px';\n title.style.zIndex = __webpack_require__.g.canvas_count;\n __webpack_require__.g.canvas_count++;\n __webpack_require__.g.uno_game_div.appendChild( title );\n\n // Create div for button group\n const btn_group = document.createElement('div');\n btn_group.classList.add('uno-game-btn-div');\n btn_group.style.top = __webpack_require__.g.uno_game_h*2/3 + 'px';\n btn_group.style.zIndex = __webpack_require__.g.canvas_count;\n __webpack_require__.g.canvas_count++;\n __webpack_require__.g.uno_game_div.appendChild( btn_group );\n\n // Create single player button\n const sp_btn = document.createElement('button');\n sp_btn.classList.add('uno-game-btn');\n sp_btn.innerHTML = 'Single Player';\n sp_btn.style.fontSize = __webpack_require__.g.uno_game_h/16 + 'px';\n btn_group.appendChild( sp_btn );\n\n // Create multi player button\n const mp_btn = document.createElement('button');\n mp_btn.classList.add('uno-game-btn');\n mp_btn.innerHTML = 'Multi Player (not work)';\n mp_btn.style.fontSize = __webpack_require__.g.uno_game_h/16 + 'px';\n btn_group.appendChild( mp_btn );\n\n // Add event\n sp_btn.addEventListener(\"click\", e => {\n // Remove elements\n title.remove();\n sp_btn.remove();\n btn_group.remove();\n createRoom();\n });\n\n\n});\n\n\n/* Game start */\nasync function createRoom() {\n console.info('Game start');\n\n const room = new _js_room_js__WEBPACK_IMPORTED_MODULE_1__.default('room1');\n\n room.addHuman('newini');\n room.addBot();\n room.addBot();\n room.addBot();\n\n await( room.initCards() );\n\n await new Promise(resolve => setTimeout(resolve, 1000));\n\n await( room.dealCards() );\n\n await new Promise(resolve => setTimeout(resolve, 500));\n\n await( room.startGame() );\n}\n\n\n\nconsole.log('Uno End')\n\n\n//# sourceURL=webpack://uno-game/./src/index.js?"); +eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _js_view_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./js/view.js */ \"./src/js/view.js\");\n/* harmony import */ var _styles_uno_game_scss__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./styles/uno-game.scss */ \"./src/styles/uno-game.scss\");\n/* harmony import */ var _images_green_table_jpg__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./images/green_table.jpg */ \"./src/images/green_table.jpg\");\n// index.js\n\n/* Class */\n\n/* SCSS */\n\n/* Image */\n\n\n// Global variables\n__webpack_require__.g.canvas_count = 0; // increment number to avoid the same canvas id\n\n// uno-game-div must be found\n__webpack_require__.g.uno_game_div;\n__webpack_require__.g.uno_game_w = window.innerWidth-1;\n__webpack_require__.g.uno_game_h = window.innerHeight-1;\n\nconst view = new _js_view_js__WEBPACK_IMPORTED_MODULE_0__.default();\n\n/* Main view */\ndocument.addEventListener('DOMContentLoaded', () => {\n console.log('UNO GAME')\n // Get uno-game div\n __webpack_require__.g.uno_game_div = document.getElementById('uno-game');\n __webpack_require__.g.uno_game_div.classList.add('uno-game-main-div');\n __webpack_require__.g.uno_game_div.style.height = __webpack_require__.g.uno_game_h +'px';\n\n // Set background to div\n __webpack_require__.g.uno_game_div.style.backgroundImage = 'url(' + _images_green_table_jpg__WEBPACK_IMPORTED_MODULE_2__.default +')';\n\n view.showMainMenu();\n});\n\n\n//# sourceURL=webpack://uno-game/./src/index.js?"); /***/ }), @@ -150,43 +150,13 @@ eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpac /***/ }), -/***/ "./src/js/bot.js": -/*!***********************!*\ - !*** ./src/js/bot.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 */ 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__.default;\n this._card_back_img = new Image();\n this._card_back_img.src = _images_card_back_svg__WEBPACK_IMPORTED_MODULE_2__.default;\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__.default);\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?"); - -/***/ }), - -/***/ "./src/js/human.js": -/*!*************************!*\ - !*** ./src/js/human.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 */ 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?"); - -/***/ }), - -/***/ "./src/js/player.js": -/*!**************************!*\ - !*** ./src/js/player.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 */ Player)\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\n\nclass Player extends _basic_canvas_js__WEBPACK_IMPORTED_MODULE_0__.default {\n constructor(name, id) {\n super();\n\n this._name = name;\n this._id = id;\n this._cards = [];\n this._type = '';\n }\n\n get id() {\n return this._id;\n }\n set id(id) {\n this._id = id;\n }\n\n get name() {\n return this._name;\n }\n set name(name) {\n this._name = name;\n }\n\n get type() {\n return this._type;\n }\n set type(type) {\n this._type = type;\n }\n\n get cards() {\n return this._cards;\n }\n set cards(cards) {\n this._cards = cards;\n }\n\n addCard(card) {\n this._cards.push(card);\n this.sortCards();\n if (this.type === 'human') {\n card.drawImageFront();\n }\n }\n\n removeCard(card) {\n this._cards.splice(this._cards.indexOf(card), 1);\n }\n\n isEmpty() {\n return (this._cards.length === 0);\n }\n\n ellipticalFormula(x, a, b) {\n return b * ( 1 - Math.sqrt( 1 - (x/a - 1)**2 ) );\n }\n\n reDeployCards() {\n for (let i=0; i (a.num > b.num) ? 1 : -1 );\n this.reDeployCards();\n }\n\n}\n\n\n//# sourceURL=webpack://uno-game/./src/js/player.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__.default;\n this._card_back_img = new Image();\n this._card_back_img.src = _images_card_back_svg__WEBPACK_IMPORTED_MODULE_2__.default;\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 set num(num) {\n this._num = num;\n }\n get num() {\n return this._num;\n }\n\n set color_n(color_n) {\n this._color_n = color_n;\n }\n get color_n() {\n return this._color_n;\n }\n\n set data(data) {\n this._num = data.num;\n this._color_n = data.color_n;\n }\n get data() {\n return {num: this._num, color_n: this._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__.default);\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 +166,27 @@ 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('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 }\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.initDiscardPile() );\n\n this.initTurn();\n }\n\n // Not allow special card to be first discard pile\n initDiscardPile() {\n while (true) {\n const card = this._cards.pop();\n if (card.num <= 9) {\n this.changeTopCard( card );\n break;\n } else {\n this._cards.splice( Math.floor(Math.random()*this._cards.length), 0, card);\n }\n }\n }\n\n async initTurn() {\n console.log('Turn count: ' + this._turn_count + ', current player: ' + this._current_player.name);\n await new Promise(resolve => setTimeout(resolve, 500));\n\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 await new Promise(resolve => setTimeout(resolve, 500));\n\n const card = await( this._current_player.playCard(this._top_discard_pile) );\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 this._top_draw_card = this._cards[ this._cards.length-1 ];\n this._top_draw_card.mouseEffect();\n\n // Select card event\n this._current_player.cards.forEach( (card) => {\n if (this._top_discard_pile.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_draw_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_draw_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_draw_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 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 _rule_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./rule.js */ \"./src/js/rule.js\");\n\n\nclass Room {\n constructor(name) {\n this._rule = new _rule_js__WEBPACK_IMPORTED_MODULE_0__.default();\n\n this._name = name;\n this._players = [];\n this._remain_cards = [];\n this._discard_piles = [];\n this._discard_pile_top = {};\n this._current_player = {};\n this._game_status = 'ready';\n }\n\n receive(data) {\n if (data.ctrl === 'addHuman') this.addHuman(data.name);\n else if (data.ctrl === 'addBot') this.addBot();\n else if (data.ctrl === 'startGame') this.startGame();\n else if (data.ctrl === 'playCard') this.playCard(data.card);\n else if (data.ctrl === 'changeColor') this.changeColor(data.color_n);\n else if (data.ctrl === 'drawCard') this.drawCard();\n }\n\n addHuman(name) {\n this._players.push( {type: 'human', name: name, id: this._players.length } );\n console.log(this._players);\n }\n\n addBot() {\n this._players.push( {type: 'bot', name: 'bot'+this._players.length, id: this._players.length} );\n console.log(this._players);\n }\n\n respondData() {\n return JSON.stringify( {\n room: {\n name: this._name\n },\n players: this._players,\n remain_cards: this._remain_cards,\n discard_piles: this._discard_piles,\n discard_pile_top: this._discard_pile_top,\n current_player: this._current_player,\n game_status: this._game_status\n } );\n }\n\n async startGame() {\n console.log('[Room] Game start');\n\n // Init\n this._game_status = 'init';\n this._skip = false;\n this._reverse = false;\n this._draw2 = false;\n this._draw4 = false;\n this._wild = false;\n this._turn_count = 0,\n\n await ( this.initCards() );\n await new Promise(resolve => setTimeout(resolve, 100));\n await ( this.dealCards() );\n await new Promise(resolve => setTimeout(resolve, 100));\n await ( this.initDiscardPile() );\n await new Promise(resolve => setTimeout(resolve, 500));\n\n this._current_player = this._players[0];\n await new Promise(resolve => setTimeout(resolve, 500));\n this._game_status = 'start';\n\n this.initTurn();\n }\n\n initCards() {\n console.log('[Room] Initialize cards')\n\n const index_arr = [...Array(108).keys()]; // Create index pool\n for (let x=0; x<14; x++) {\n let num = x;\n for (let y=0; y<8; y++) {\n const color_n = y%4;\n if ( (x === 0) && (y >= 4) ) continue; // Skip blank card\n if ( (x === 13) && (y >= 4) ) num = 14; // +4 cards\n // Get random index\n const card_index = index_arr.splice(Math.floor( Math.random() * index_arr.length), 1)[0];\n this._remain_cards[ card_index ] = {num: num, color_n: color_n, x: x, y: y};\n }\n }\n }\n\n dealCards(n_deal_cards=7) {\n console.log('[Room] Deal cards')\n this._players.forEach( (player) => {\n player.cards = [];\n for (let i=0; i (a.num > b.num) ? 1 : -1 );\n });\n }\n\n // Not allow special card to be first discard pile\n initDiscardPile() {\n while (true) {\n const card = this._remain_cards.pop();\n if (card.num <= 9) {\n this.changeTopCard( card );\n break;\n } else {\n // push back to a random position\n this._remain_cards.splice( Math.floor(Math.random()*this._remain_cards.length), 0, card);\n }\n }\n }\n\n async initTurn() {\n console.log('[Room] Turn count: ' + this._turn_count + ', current player: ' + this._current_player.name);\n await new Promise(resolve => setTimeout(resolve, 500));\n\n // check draw cards\n if (this._draw2) {\n this._draw2 = false;\n for (let i=0; i<2; i++) this._current_player.cards.push( this._remain_cards.pop() );\n this._current_player.cards.sort( (a, b) => (a.num > b.num) ? 1 : -1 );\n this.finishTurn();\n } else if (this._draw4) {\n this._draw4 = false;\n for (let i=0; i<4; i++) this._current_player.cards.push( this._remain_cards.pop() );\n this._current_player.cards.sort( (a, b) => (a.num > b.num) ? 1 : -1 );\n this.finishTurn();\n } else {\n if (this._current_player.type === 'bot') {\n this.botTurn();\n }\n }\n }\n\n async botTurn() {\n await new Promise(resolve => setTimeout(resolve, 500));\n\n const card = await ( this.botChooseCard() );\n\n if (card) {\n this.playCard(card);\n } else {\n this.drawCard();\n }\n }\n\n botChooseCard() {\n for (let i=0; i= 13) { // Change color\n this.changeColor( Math.floor( Math.random() * 4 ) );\n }\n return card;\n }\n }\n return null;\n }\n\n playCard(card) {\n console.log('[Room] played card num: ' + card.num + ', color: ' + card.color_n);\n const player = this._current_player;\n // Remove card from player cards\n player.cards.splice(player.cards.findIndex(c => (c.x === card.x && c.y === card.y)), 1);\n\n this.changeTopCard(card);\n this.finishTurn();\n }\n\n changeColor(color_n) {\n this._wild = true;\n this._wild_color_n = color_n;\n }\n\n drawCard() {\n const card = this._remain_cards.pop();\n console.log('[Room] drawed card num: ' + card.num + ', color: ' + card.color_n);\n\n this._current_player.cards.push(card);\n this._current_player.cards.sort( (a, b) => (a.num > b.num) ? 1 : -1 );\n this.finishTurn();\n }\n\n async finishTurn() {\n console.log('[Room] finish turn')\n\n await new Promise(resolve => setTimeout(resolve, 500));\n\n // Check empty\n if (this._current_player.cards.length === 0) {\n console.log('[Room] player: ' + this._current_player.name + ' has no card left. Game end');\n this._game_status = 'finish';\n } else {\n this._turn_count++;\n await ( this.decideNextPlayer() );\n this.initTurn();\n }\n }\n\n decideNextPlayer() {\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 { + +eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"default\": () => (/* binding */ Rule)\n/* harmony export */ });\nclass Rule {\n constructor() {\n\n }\n\n checkCardsMatch(card1, card2) {\n if ( (card2.num <= 12 && card1.num === card2.num) // Normal card\n || (card2.num >= 13) // Change color card\n || (card2.color_n === card1.color_n) ) { // Color match\n return true;\n } else {\n return false;\n }\n }\n}\n\n\n//# sourceURL=webpack://uno-game/./src/js/rule.js?"); + +/***/ }), + +/***/ "./src/js/view.js": +/*!************************!*\ + !*** ./src/js/view.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 */ View)\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 _room_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./room.js */ \"./src/js/room.js\");\n/* harmony import */ var _card_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./card.js */ \"./src/js/card.js\");\n/* harmony import */ var _rule_js__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./rule.js */ \"./src/js/rule.js\");\n// view.js\n\n/* Class */\n\n\n\n\n\nclass View {\n constructor() {\n this._data = {};\n this._rule = new _rule_js__WEBPACK_IMPORTED_MODULE_3__.default();\n this._is_initialized = false;\n }\n\n showMainMenu() {\n // Create div\n const div = document.createElement('div');\n div.classList.add('uno-game-div');\n div.style.top = __webpack_require__.g.uno_game_h/4 + 'px';\n __webpack_require__.g.uno_game_div.appendChild( div );\n\n // Create UNO title\n const title = document.createElement('h1');\n title.innerHTML = 'UNO Game';\n title.classList.add('uno-game-main-title');\n div.appendChild( title );\n\n // label for input name\n const label_n = document.createElement('label');\n label_n.innerHTML = 'Input My Name';\n label_n.classList.add('uno-game-label');\n div.appendChild( label_n );\n\n // Input name\n const input_n = document.createElement('input');\n input_n.type = 'text';\n input_n.value = (this._my_name) ? this._my_name : '';\n input_n.className = 'uno-game-input';\n div.appendChild( input_n );\n\n // Create find room button\n const fr_btn = document.createElement('button');\n fr_btn.classList.add('uno-game-btn');\n fr_btn.innerHTML = 'Find Room';\n div.appendChild( fr_btn );\n\n // Add event\n //this._fr_btn.addEventListener(\"click\", e => {\n // this._my_name = input_n.value;\n // this.clearMainMenu();\n // this.findRoom();\n // this._is_host = false;\n //});\n\n // Create create room button\n const cr_btn = document.createElement('button');\n cr_btn.classList.add('uno-game-btn');\n cr_btn.innerHTML = 'Create Room';\n div.appendChild( cr_btn );\n\n // Add event\n cr_btn.addEventListener(\"click\", e => {\n this._my_name = input_n.value;\n div.remove();\n this.showCreateRoomMenu();\n this._is_host = true;\n });\n\n }\n\n showCreateRoomMenu() {\n // Create div\n const div = document.createElement('div');\n div.classList.add('uno-game-div');\n div.style.top = __webpack_require__.g.uno_game_h/4 + 'px';\n __webpack_require__.g.uno_game_div.appendChild( div );\n\n // Menu title\n const title = document.createElement('h2');\n title.innerHTML = 'Create Room';\n title.classList.add('uno-game-menu-title');\n div.appendChild( title );\n\n // label for input room name\n const label_rn = document.createElement('label');\n label_rn.innerHTML = 'Input Room Name';\n label_rn.classList.add('uno-game-label');\n div.appendChild( label_rn );\n\n // Input room name\n const input_rn = document.createElement('input');\n input_rn.type = 'text';\n input_rn.className = 'uno-game-input';\n div.appendChild( input_rn );\n\n // Confirm button\n const cfm_btn = document.createElement('button');\n cfm_btn.classList.add('uno-game-btn');\n cfm_btn.innerHTML = 'Confirm';\n div.appendChild( cfm_btn );\n\n cfm_btn.addEventListener('click', e => {\n this._room = new _room_js__WEBPACK_IMPORTED_MODULE_1__.default( input_rn.value );\n this.send({ctrl: 'addHuman', name: this._my_name});\n this._data = JSON.parse( this._room.respondData() );\n this.showRoom();\n div.remove();\n });\n\n // Back button\n const back_btn = document.createElement('button');\n back_btn.classList.add('uno-game-btn');\n back_btn.innerHTML = 'Back';\n div.appendChild( back_btn );\n\n back_btn.addEventListener('click', e => {\n div.remove();\n this.showMainMenu();\n });\n }\n\n async showRoom() {\n // Create div\n this._div = document.createElement('div');\n this._div.classList.add('uno-game-div');\n this._div.style.top = __webpack_require__.g.uno_game_h/5 + 'px';\n __webpack_require__.g.uno_game_div.appendChild( this._div );\n\n // Menu title\n const title = document.createElement('h2');\n title.innerHTML = this._data.room.name;\n title.classList.add('uno-game-menu-title');\n this._div.appendChild( title );\n\n if (this._is_host) {\n // Add bot button\n const ab_btn = document.createElement('button');\n ab_btn.classList.add('uno-game-btn');\n ab_btn.innerHTML = 'Add Bot';\n this._div.appendChild( ab_btn );\n\n ab_btn.addEventListener('click', e => {\n this.send({ctrl: 'addBot'});\n });\n\n // Start game button\n const sg_btn = document.createElement('button');\n sg_btn.classList.add('uno-game-btn');\n sg_btn.innerHTML = 'Star Game';\n this._div.appendChild( sg_btn );\n\n sg_btn.addEventListener('click', e => {\n this.send({ctrl: 'startGame'});\n this._div.remove();\n });\n }\n\n // List players\n const ul_pl = document.createElement('ul');\n ul_pl.classList.add('uno-game-ul');\n this._div.appendChild( ul_pl );\n\n this._data.players.forEach( (player) => {\n const li = document.createElement('li');\n li.classList.add('uno-game-li');\n li.innerHTML = player.name;\n ul_pl.appendChild( li );\n });\n\n if (!this._loop_started) {\n this._loop_started = true;\n this.loopReceiveData();\n }\n }\n\n async loopReceiveData() {\n let is_finished = false;\n while(true) {\n const data = await ( JSON.parse( this._room.respondData() ) );\n\n switch (data.game_status) {\n case 'ready':\n if ( JSON.stringify(this._data.players) != JSON.stringify(data.players) ) {\n this._data = data;\n this._div.remove();\n this.showRoom();\n }\n break;\n case 'start':\n if (!this._is_initialized) {\n await ( this.initCards() );\n await new Promise(resolve => setTimeout(resolve, 500)); // Sleep .5 s\n this._is_initialized = true;\n }\n if ( JSON.stringify(this._data.current_player) != JSON.stringify(data.current_player) ) {\n console.log('current_player changed')\n this._data = data;\n await ( this.updateCards() );\n if (data.current_player.name === this._my_name) this.myTurn();\n }\n break;\n case 'finish':\n this._data = data;\n await ( this.updateCards() );\n is_finished = true;\n this.gameFinish();\n break;\n }\n if (is_finished) break;\n await new Promise(resolve => setTimeout(resolve, 500)); // Sleep .5 s\n }\n }\n\n send(data) {\n this._room.receive(data);\n }\n\n async initCards() {\n console.log('init cards')\n this._cards = [];\n let count = 0\n for (let x=0; x<14; x++) {\n this._cards[x] = [];\n }\n for (let x=0; x<14; x++) {\n let num = x;\n for (let y=0; y<8; y++) {\n const color_n = y%4;\n if ( (x === 0) && (y >= 4) ) { // Skip blank card\n continue;\n }\n if ( (x === 13) && (y >= 4) ) { // +4 cards\n num = 14;\n }\n this._cards[x][y] = new _card_js__WEBPACK_IMPORTED_MODULE_2__.default(__webpack_require__.g.uno_game_w*6/16+count, __webpack_require__.g.uno_game_h/2, num, color_n);\n count++;\n }\n }\n }\n\n updateCards() {\n console.log('update cards view')\n // Player Cards\n const p_l = this._data.players.length;\n let p_cnt = 0;\n\n this._data.players.forEach( player => {\n const c_l = player.cards.length;\n\n for (let c=0; c {\n const card = this._cards[card_data.x][card_data.y];\n if (this._rule.checkCardsMatch(this._data.discard_pile_top, card.data)) {\n card.mouseEffect();\n\n card.canvas.addEventListener('click', () => {\n // Show color change blocks\n if (card.num >= 13) {\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 console.log('played card num: ' + card.num + ', color: ' + card.color_n);\n\n // Remove event listeners\n this._top_draw_card.resetEventListener();\n this._data.current_player.cards.forEach( (card_data) => {\n const card = this._cards[card_data.x][card_data.y];\n card.resetEventListener();\n });\n bc_colors.forEach( bc_color => bc_color.remove() );\n\n this.send({ctrl: 'changeColor', color_n: i});\n this.send({\n ctrl: 'playCard',\n card: {num: card.num, color_n: card.color_n, x: card_data.x, y: card_data.y}\n });\n });\n bc_colors.push(bc);\n }\n } else {\n console.log('played card num: ' + card.num + ', color_n: ' + card.color_n);\n\n // Remove event listener\n this._top_draw_card.resetEventListener();\n this._data.current_player.cards.forEach( (card_data) => {\n const card = this._cards[card_data.x][card_data.y];\n card.resetEventListener();\n });\n bc_colors.forEach( bc_color => bc_color.remove() );\n\n this.send({\n ctrl: 'playCard',\n card: {num: card.num, color_n: card.color_n, x: card_data.x, y: card_data.y}\n });\n }\n });\n }\n });\n\n // Draw card event\n this._top_draw_card.canvas.addEventListener('click', () => {\n console.log('drawed card');\n\n // Remove event listener\n this._top_draw_card.resetEventListener();\n this._data.current_player.cards.forEach( (card_data) => {\n const card = this._cards[card_data.x][card_data.y];\n card.resetEventListener();\n });\n bc_colors.forEach( bc_color => bc_color.remove() );\n\n this.send({ctrl: 'drawCard'});\n });\n }\n\n gameFinish() {\n\n }\n}\n\n\n//# sourceURL=webpack://uno-game/./src/js/view.js?"); /***/ })