extend canvas to class, added human click
This commit is contained in:
parent
be5a129b14
commit
d3ee297812
40
src/index.js
40
src/index.js
@ -19,37 +19,24 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||
global.uno_game_div = document.getElementById('uno-game');
|
||||
global.uno_game_div.classList.add('uno-game-div');
|
||||
|
||||
// Create canvas
|
||||
const basic_canvas = new BasicCanvas();
|
||||
// Create background canv
|
||||
const bkg = new BasicCanvas(0, 0, global.uno_game_w, global.uno_game_h);
|
||||
bkg.canvas.classList.add('uno-game-canv-bkg');
|
||||
|
||||
// Set canvas
|
||||
basic_canvas.canvas.classList.add('uno-game-canv-main');
|
||||
|
||||
// Add game start button with bitmap
|
||||
const btn_width = global.uno_game_w/8;
|
||||
const start_game_box_text = new BoxText(basic_canvas.ctx, global.uno_game_w*5/12, global.uno_game_h*3/4,
|
||||
global.uno_game_w/7, global.uno_game_w/8/1.6, 'Start Game');
|
||||
// Create room button
|
||||
const create_room_box_text = new BoxText(global.uno_game_w*5/12, global.uno_game_h*3/4,
|
||||
global.uno_game_w/6, global.uno_game_w/12, 'Create Game');
|
||||
|
||||
/* Canvas click */
|
||||
basic_canvas.canvas.addEventListener("click", e => {
|
||||
const rect = basic_canvas.canvas.getBoundingClientRect();
|
||||
const point = {
|
||||
x: e.clientX - rect.left,
|
||||
y: e.clientY - rect.top
|
||||
};
|
||||
|
||||
console.log(point);
|
||||
if ( start_game_box_text.isClicked(point) ) {
|
||||
basic_canvas.clear();
|
||||
startGame();
|
||||
}
|
||||
create_room_box_text.canvas.addEventListener("click", e => {
|
||||
create_room_box_text.remove();
|
||||
createRoom();
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
|
||||
/* Game start */
|
||||
function startGame() {
|
||||
async function createRoom() {
|
||||
console.info('Game start');
|
||||
|
||||
const room = new Room('room1');
|
||||
@ -59,7 +46,12 @@ function startGame() {
|
||||
room.addBot();
|
||||
room.addBot();
|
||||
|
||||
room.startGame();
|
||||
await( room.initCards() );
|
||||
|
||||
//setTimeout( ()=>{ room.dealCards(); }, 2000 );
|
||||
await( room.dealCards() );
|
||||
|
||||
await( room.startGame() );
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -1,13 +1,25 @@
|
||||
export default class BasicCanvas {
|
||||
constructor() {
|
||||
constructor(x, y, w, h) {
|
||||
this._x = x;
|
||||
this._y = y;
|
||||
this._w = w;
|
||||
this._h = h;
|
||||
|
||||
// Create canvas
|
||||
this._canvas = document.createElement("CANVAS");
|
||||
global.uno_game_div.appendChild( this._canvas );
|
||||
global.canvas_count++;
|
||||
console.debug(global.canvas_count);
|
||||
this._canvas.width = global.uno_game_w;
|
||||
this._canvas.height = global.uno_game_h;
|
||||
this._canvas.width = w;
|
||||
this._canvas.height = h;
|
||||
this._canvas.classList.add('uno-game-canv-default');
|
||||
this._canvas.style += 'z-index: ' + global.canvas_count + ';';
|
||||
|
||||
// Canvas style
|
||||
this._z_index = global.canvas_count;
|
||||
global.canvas_count++;
|
||||
this._canvas.style = `left: ${x}px; top: ${y}px; z-index: ${this._z_index};`;
|
||||
|
||||
// Add to div
|
||||
global.uno_game_div.appendChild( this._canvas );
|
||||
|
||||
// Get ctx
|
||||
this._ctx = this._canvas.getContext('2d');
|
||||
}
|
||||
|
||||
@ -28,4 +40,18 @@ export default class BasicCanvas {
|
||||
clear() {
|
||||
this._ctx.clearRect(0, 0, global.uno_game_w, global.uno_game_h);
|
||||
}
|
||||
|
||||
move(x, y) {
|
||||
this._canvas.style.left = x + 'px';
|
||||
this._canvas.style.top = y + 'px';
|
||||
}
|
||||
|
||||
refresh() {
|
||||
this._canvas.style.zIndex = global.canvas_count;
|
||||
global.canvas_count++;
|
||||
}
|
||||
|
||||
remove() {
|
||||
this._canvas.remove();
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,24 +1,18 @@
|
||||
export default class BoxText {
|
||||
constructor(ctx, x, y, w, h, text) {
|
||||
this._ctx = ctx;
|
||||
this._x = x;
|
||||
this._y = y;
|
||||
this._w = w;
|
||||
this._h = h;
|
||||
import BasicCanvas from './basic_canvas.js';
|
||||
|
||||
export default class BoxText extends BasicCanvas {
|
||||
constructor(x, y, w, h, text) {
|
||||
super(x, y, w, h);
|
||||
|
||||
this._text = text;
|
||||
|
||||
ctx.lineWidth = 4;
|
||||
ctx.fillStyle = "#abc";
|
||||
ctx.fillRect(x, y, w, h);
|
||||
ctx.font = Math.floor(h/3)+"px Arial";
|
||||
ctx.textAlign="center";
|
||||
ctx.textBaseline = "middle";
|
||||
ctx.fillStyle = "#000000";
|
||||
ctx.fillText(text, x+w/2, y+h/2);
|
||||
}
|
||||
|
||||
isClicked(point) {
|
||||
return ( (this._x <= point.x && point.x <= this._x + this._w)
|
||||
&& (this._y <= point.y && point.y <= this._y + this._h) )
|
||||
this._ctx.lineWidth = 4;
|
||||
this._ctx.fillStyle = "#abc";
|
||||
this._ctx.fillRect(0, 0, w, h);
|
||||
this._ctx.font = Math.floor(h/3)+"px Arial";
|
||||
this._ctx.textAlign="center";
|
||||
this._ctx.textBaseline = "middle";
|
||||
this._ctx.fillStyle = "#000000";
|
||||
this._ctx.fillText(text, w/2, h/2);
|
||||
}
|
||||
}
|
||||
|
||||
@ -4,19 +4,32 @@ import cards_img from '../images/cards.svg';
|
||||
import card_back from '../images/card_back.svg';
|
||||
|
||||
export default class Card extends BasicCanvas {
|
||||
constructor(num, color_n) {
|
||||
super();
|
||||
|
||||
this._num = num;
|
||||
this._color_n = color_n;
|
||||
constructor(x, y, num, color_n) {
|
||||
super(x, y, global.uno_game_w/16, global.uno_game_w/16*360/240);
|
||||
|
||||
this._c_w = 240;
|
||||
this._c_h = 360;
|
||||
|
||||
this._num = num;
|
||||
this._color_n = color_n;
|
||||
this._event_is_set = false;
|
||||
|
||||
this._cards_img = new Image();
|
||||
this._cards_img.src = cards_img;
|
||||
this._card_back_img = new Image();
|
||||
this._card_back_img.src = card_back;
|
||||
|
||||
// Add border
|
||||
this._canvas.style.border = '1px solid #000000';
|
||||
|
||||
// Add transition
|
||||
this._canvas.style.transition = '0.5s';
|
||||
|
||||
// Fill
|
||||
this._card_back_img.addEventListener('load', () => {
|
||||
this._ctx.drawImage(this._card_back_img, 0, 0, this._w, this._h);
|
||||
this._is_front = false;
|
||||
});
|
||||
}
|
||||
|
||||
get num() {
|
||||
@ -32,6 +45,13 @@ export default class Card extends BasicCanvas {
|
||||
this._color_n = color_n;
|
||||
}
|
||||
|
||||
get event_is_set() {
|
||||
return this._event_is_set;
|
||||
}
|
||||
set event_is_set(event_is_set) {
|
||||
this._event_is_set = event_is_set;
|
||||
}
|
||||
|
||||
isMatch(card) {
|
||||
if ( (this._num <= 12 && this._num === card.num)
|
||||
|| (this._num >= 13)
|
||||
@ -42,22 +62,33 @@ export default class Card extends BasicCanvas {
|
||||
}
|
||||
}
|
||||
|
||||
drawImageFront(x, y) {
|
||||
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;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
drawImageFront(x, y) {
|
||||
this._canvas.style.left = x + 'px';
|
||||
this._canvas.style.top = y + 'px';
|
||||
this.clear();
|
||||
this._x = x;
|
||||
this._y = y;
|
||||
this._w = global.uno_game_w/16;
|
||||
this._h = this._w * this._c_h / this._c_w;
|
||||
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,
|
||||
x, y, this._w, this._h);
|
||||
0, 0, this._w, this._h);
|
||||
}
|
||||
|
||||
drawImageBack(x, y) {
|
||||
this._canvas.style.left = x + 'px';
|
||||
this._canvas.style.top = y + 'px';
|
||||
this.clear();
|
||||
this._x = x;
|
||||
this._y = y;
|
||||
this._w = global.uno_game_w/16;
|
||||
this._h = this._w * this._c_h / this._c_w;
|
||||
this._ctx.drawImage(this._card_back_img, x, y, this._w, this._h);
|
||||
this._ctx.drawImage(this._card_back_img, 0, 0, this._w, this._h);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -3,10 +3,12 @@ import Player from './player.js';
|
||||
export default class Human extends Player {
|
||||
constructor(name, id) {
|
||||
super(name, id);
|
||||
|
||||
this._type = 'human';
|
||||
}
|
||||
|
||||
playCard(top_card) {
|
||||
return this._cards.splice(0, 1)[0];
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -40,9 +40,29 @@ export default class Player extends BasicCanvas {
|
||||
|
||||
addCard(card) {
|
||||
this._cards.push(card);
|
||||
this.sortCards();
|
||||
if (this.type === 'human') {
|
||||
card.flip();
|
||||
}
|
||||
}
|
||||
|
||||
removeCard(card) {
|
||||
this._cards.splice(this._cards.indexOf(card), 1);
|
||||
}
|
||||
|
||||
isEmpty() {
|
||||
return (this._cards.length === 0) ? true : false;
|
||||
}
|
||||
|
||||
refreshCards() {
|
||||
for (let i=0; i<this._cards.length; i++) {
|
||||
this._cards[i].move(global.uno_game_w*(i+1)/16, global.uno_game_h*(5-this.id-1)/5);
|
||||
}
|
||||
}
|
||||
|
||||
sortCards() {
|
||||
this._cards.sort( (a, b) => (a.num > b.num) ? 1 : -1 );
|
||||
this.refreshCards();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
160
src/js/room.js
160
src/js/room.js
@ -6,7 +6,7 @@ import Card from './card.js';
|
||||
|
||||
export default class Room extends BasicCanvas {
|
||||
constructor(name) {
|
||||
super();
|
||||
super(0, 0, global.uno_game_w, global.uno_game_h/10);
|
||||
|
||||
this._name = name;
|
||||
this._players = [];
|
||||
@ -14,8 +14,8 @@ export default class Room extends BasicCanvas {
|
||||
this._used_cards = [];
|
||||
|
||||
// Fill room name
|
||||
this._ctx.font = "32px Arial";
|
||||
this._ctx.fillText(name, 10, 10);
|
||||
this._ctx.font = Math.floor(this._h/3) + "px Arial";
|
||||
this._ctx.fillText(name, 10, 50);
|
||||
}
|
||||
|
||||
addHuman(name) {
|
||||
@ -28,95 +28,129 @@ export default class Room extends BasicCanvas {
|
||||
console.log(this._players);
|
||||
}
|
||||
|
||||
initDeck() {
|
||||
for (let x=0; x<14; x++) {
|
||||
for (let y=0; y<8; y++) {
|
||||
if ( (x === 0) && (y >= 4) ) { // Skip blank card
|
||||
initCards() {
|
||||
console.log('Init')
|
||||
const index_arr = [...Array(108).keys()];
|
||||
let cnt = 0;
|
||||
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 ( (x === 13) && (y >= 4) ) { // +4 cards
|
||||
x = 14;
|
||||
if ( (num === 13) && (color_n >= 4) ) { // +4 cards
|
||||
num = 14;
|
||||
}
|
||||
this._cards.push( new Card(x, y%4) );
|
||||
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);
|
||||
cnt++;
|
||||
}
|
||||
}
|
||||
for (let i=0; i<this._cards.length; i++) {
|
||||
this._cards[i].refresh();
|
||||
}
|
||||
console.log(this._cards);
|
||||
}
|
||||
|
||||
shuffleDeck() {
|
||||
dealCards() {
|
||||
console.log('Deal cards')
|
||||
this._players.forEach( (player) => {
|
||||
for (let i=0; i<7; i++) {
|
||||
player.addCard( this.draw() );
|
||||
player.addCard( this._cards.pop() );
|
||||
}
|
||||
});
|
||||
console.log(this._players);
|
||||
}
|
||||
draw() {
|
||||
/* Draw randomly */
|
||||
const card_i = Math.floor( Math.random() * this._cards.length );
|
||||
return this._cards.splice(card_i, 1)[0];
|
||||
|
||||
async startGame() {
|
||||
console.log('Game start');
|
||||
|
||||
this._current_player = 0;
|
||||
this._turn_count = 0;
|
||||
|
||||
this._top_card = this._cards.pop();
|
||||
this._top_card.flip();
|
||||
this._top_card.move(global.uno_game_w*8/16+this._turn_count, global.uno_game_h/2);
|
||||
//this._top_card.drawImageFront(global.uno_game_w*8/16+this._turn_count, global.uno_game_h/2);
|
||||
|
||||
this.humanTurn(this._players[this._current_player]);
|
||||
|
||||
// if (player.isEmpty()) {
|
||||
// console.log('player: ' + player.name + ' has no card left. Game end');
|
||||
// break
|
||||
// }
|
||||
}
|
||||
|
||||
updateView() {
|
||||
const inner_w = window.innerWidth;
|
||||
const inner_h = window.innerHeight;
|
||||
async botPlay(player) {
|
||||
console.log('Turn count: ' + this._turn_count + ', current player: ' + player.name);
|
||||
await new Promise(resolve => setTimeout(resolve, 1000));
|
||||
|
||||
// Drw top card
|
||||
this._top_card.drawImageFront(inner_w/2, inner_h/2);
|
||||
const card = player.playCard(this._top_card);
|
||||
if (card) {
|
||||
console.log('player: ' + player.name + ' played card num: ' + card.num + ', color: ' + card.color_n);
|
||||
this.changeTopCard(card);
|
||||
} else {
|
||||
const card = this._cards.pop();
|
||||
console.log('player: ' + player.name + ' drawed card num: ' + card.num + ', color: ' + card.color_n);
|
||||
player.addCard(card);
|
||||
}
|
||||
|
||||
// Draw players card
|
||||
this._players.forEach( (player) => {
|
||||
for (let i=0; i<player.cards.length; i++) {
|
||||
const card = player.cards[i];
|
||||
card.clear();
|
||||
if (player.type == 'bot') {
|
||||
card.drawImageBack(inner_w*(i+1)/16, inner_h*player.id/5);
|
||||
} else {
|
||||
card.drawImageFront(inner_w*(i+1)/16, inner_h*4/5);
|
||||
}
|
||||
player.refreshCards();
|
||||
|
||||
this._turn_count++;
|
||||
const next_player = this.getNextPlayer();
|
||||
if (next_player.type === 'human') {
|
||||
this.humanTurn(next_player);
|
||||
} else {
|
||||
this.botPlay(next_player);
|
||||
}
|
||||
}
|
||||
|
||||
humanTurn(player) {
|
||||
player.cards.forEach( (card) => {
|
||||
if (!card.event_is_set) {
|
||||
card.canvas.addEventListener('click', ()=>{
|
||||
this.humanPlay(player, card);
|
||||
player.removeCard(card);
|
||||
});
|
||||
card.event_is_set = true;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
async startGame() {
|
||||
await( this.initDeck() );
|
||||
await( this.shuffleDeck() );
|
||||
async humanPlay(player, card) {
|
||||
console.log('Turn count: ' + this._turn_count + ', current player: ' + player.name);
|
||||
|
||||
let count = 0;
|
||||
let current_turn = 0;
|
||||
this._top_card = this.draw();
|
||||
this.changeTopCard(card);
|
||||
|
||||
console.log('Game start');
|
||||
console.log('player: ' + player.name + ' played card num: ' + card.num + ', color: ' + card.color_n);
|
||||
player.refreshCards();
|
||||
|
||||
while (true) {
|
||||
console.log('count: ' + count + ', current player: ' + this._players[current_turn].name);
|
||||
const player = this._players[current_turn];
|
||||
|
||||
const card = await( player.playCard(this._top_card) );
|
||||
if (card) {
|
||||
console.log('player: ' + player.name + ' played card num: ' + card.num + ', color: ' + card.color_n);
|
||||
card.clear();
|
||||
this._used_cards.push(this._top_card);
|
||||
this._top_card = card;
|
||||
this._turn_count++;
|
||||
this.botPlay( this.getNextPlayer() );
|
||||
}
|
||||
|
||||
getNextPlayer() {
|
||||
if (this._reverse) {
|
||||
if (this._current_player === 0) {
|
||||
this._current_player = this._players.length-1;
|
||||
} else {
|
||||
const card = this.draw();
|
||||
console.log('player: ' + player.name + ' drawed card num: ' + card.num + ', color: ' + card.color_n);
|
||||
player.addCard(card);
|
||||
this._current_player--;
|
||||
}
|
||||
|
||||
this.updateView();
|
||||
//await Promise.all([
|
||||
// timeout(1000)
|
||||
//]);
|
||||
await new Promise(resolve => setTimeout(resolve, 1000));
|
||||
|
||||
if (player.isEmpty()) {
|
||||
console.log('player: ' + player.name + ' has no card left. Game end');
|
||||
break
|
||||
} else {
|
||||
if (this._current_player === this._players.length-1) {
|
||||
this._current_player = 0;
|
||||
} else {
|
||||
this._current_player++;
|
||||
}
|
||||
|
||||
current_turn = (current_turn >= this._players.length-1) ? 0 : ++current_turn;
|
||||
count++;
|
||||
}
|
||||
return this._players[this._current_player];
|
||||
}
|
||||
|
||||
changeTopCard(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();
|
||||
}
|
||||
}
|
||||
|
||||
@ -7,14 +7,8 @@
|
||||
.uno-game-canv-default {
|
||||
position: absolute;
|
||||
display: block;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.uno-game-canv-main {
|
||||
.uno-game-canv-bkg {
|
||||
background-image: url('../images/green_table.jpg');
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user