From 1da50c2fb442afa7f1a93bfe2cc9a1c776419713 Mon Sep 17 00:00:00 2001 From: Nathan Date: Fri, 4 Oct 2024 22:01:38 +0100 Subject: [PATCH 01/23] Board seperation, Shape changes, and event handler Split front-end JS into seperate files Change shape into a class that can do rect/circle rendering Add basic event handler for player deck. --- public/board.js | 149 ++++++++++++++++++++++++++++++++++++++++++++++ public/index.html | 13 ++-- public/main.js | 39 +++--------- public/shapes.js | 63 ++++++++++++-------- public/style.css | 6 ++ 5 files changed, 210 insertions(+), 60 deletions(-) create mode 100644 public/board.js diff --git a/public/board.js b/public/board.js new file mode 100644 index 0000000..1d5afec --- /dev/null +++ b/public/board.js @@ -0,0 +1,149 @@ +const ctx = canvas.getContext('2d'); +const canvasLeft = canvas.offsetLeft + canvas.clientLeft; +const canvasTop = canvas.offsetTop + canvas.clientTop; + +const cardWidth = 240; +const cardHeight = 360; + +const cards = new Image(); +const back = new Image(); + + +let clickableItems = []; +console.log(clickableItems); + + +class Board{ + constructor(){ + console.log('initBoard'); + ctx.font = "12px Arial"; + canvas.style.backgroundColor = 'rgb(143 153 150)'; + cards.src = 'images/deck.svg'; + back.src = 'images/uno.svg'; + ctx.fillStyle = '#000'; + } + + drawBoard(){ + console.log('drawBoard'); + ctx.clearRect(0, 0, canvas.width, canvas.height); + // Room Name + ctx.fillText(name, 0, 10); + + this.drawDeck(); + this.drawDeckOpponent(); + + + this.drawPlayerNames('Nathan', 'Evil Nathan'); + } + + drawPlayerNames(playerName, opponentName = false){ + console.log('drawPlayerNames'); + + // Player Name + ctx.fillText(playerName, 50, canvas.height - 110); + + // Opponent's Name + if(!opponentName){ + // Just clear the name + }else{ + ctx.fillText(opponentName, canvas.width - (ctx.measureText(opponentName).width + 50), 110); + } + } + + drawDeck(){ + // Deck + clickableItems['deckSprite'] = new Shape({ + name: 'deck', + x: canvas.width-cardWidth/2-40, + y: canvas.height-cardHeight/2-60, + width: cardWidth/2, + height: cardHeight/2, + fillStyle: "#0000FF" + }); + clickableItems['deckSprite'].draw(); + let deckCounterSprite = new Circle({ + name: 'deckCounter', + x: canvas.width-cardWidth/5, + y: canvas.height-cardHeight/5, + width: cardWidth/8, + height: cardHeight/8, + fillStyle: "#FFF" + }); + deckCounterSprite.draw(); + let cardsInDeck = 60; + // TODO: Center in the circle + ctx.fillText(cardsInDeck, canvas.width-cardWidth/5 - (ctx.measureText(cardsInDeck).width) + 7, canvas.height-cardHeight/5 + 5); + //ctx.fillRect(canvas.width-cardWidth/2-60, canvas.height/2-cardHeight/4, cardWidth/2, cardHeight/2); + } + drawDeckOpponent(){ + // Opponent's Deck + let deckSprite = new Shape({ + name: 'deckOpponent', + x: 40, + y: 60, + width: cardWidth/2, + height: cardHeight/2, + fillStyle: "#FF0000" + }); + deckSprite.draw(); + let deckCounterSprite = new Shape({ + shape: 'circle', + name: 'deckCounterOpponent', + x: cardWidth/2+(cardWidth/8), + y: cardHeight/2+(cardHeight/8), + width: cardWidth/8, + height: cardHeight/8, + fillStyle: "#FFF" + }); + deckCounterSprite.draw(); + let cardsInDeck = 60; + // TODO: Center in the circle + ctx.fillStyle = '#000'; + ctx.strokeStyle = '#000'; + ctx.fillText(cardsInDeck, cardWidth/2 + (ctx.measureText(cardsInDeck).width) + 10, cardHeight/1.58); + } + + // Naming's getting awkward here... + // Draw the card + drawCardSprites(){ + + } + + drawCardSpritesOpponent(){ + + } + // Draw a card, traditional TCG + drawACard(){ + + } + drawACardOpponent(){ + + } +} + +// Run board commands here for testing +let board = new Board; +//board.initBoard(); + +board.drawBoard(); + +canvas.addEventListener('mousemove', function(event) { + var x = event.pageX - canvasLeft, + y = event.pageY - canvasTop; + + console.log('X: '+x+' Y: '+y); + + // Collision detection between clicked offset and clickableItems + // https://stackoverflow.com/a/9880302 + clickable = clickableItems['deckSprite']; + console.log(clickableItems['deckSprite']); + + if ( + y > clickable.y && y < clickable.y + clickable.height + && x > clickable.x && x < clickable.x + clickable.width + ) { + console.log('HUUUH'); + } + +}, false); + diff --git a/public/index.html b/public/index.html index d53294d..0cd06c6 100644 --- a/public/index.html +++ b/public/index.html @@ -8,15 +8,18 @@ -

Rooms will not be HTML buttons eventually, but for now...

- - - +
+

Rooms will not be HTML buttons eventually, but for now...

+ + + +
+ diff --git a/public/main.js b/public/main.js index 1086031..53be0b7 100644 --- a/public/main.js +++ b/public/main.js @@ -1,12 +1,5 @@ const socket = io({autoConnect: false}); const canvas = document.getElementById('canvas');; -const ctx = canvas.getContext('2d'); - -const cardWidth = 240; -const cardHeight = 360; - -const cards = new Image(); -const back = new Image(); let room; let hand = []; @@ -18,10 +11,7 @@ init(); function init() { console.log('init'); - ctx.font = "12px Arial"; - canvas.style.backgroundColor = 'rgb(143 153 150)'; - cards.src = 'images/deck.svg'; - back.src = 'images/uno.svg'; + // Init board here? Or keep in board JS? document.addEventListener('touchstart', onclick, false); document.addEventListener('click', onclick, false); @@ -125,11 +115,14 @@ function requestCreateRoom(){ socket.emit('requestCreateRoom', playerName); } function returnCreateRoom(data){ - + console.log(data); + if(!data.success){ + alert(data.message); + } } socket.on('returnCreateRoom', function (data) { console.log('<< returnCreateRoom'); - console.log(data); + returnCreateRoom(data); }); @@ -147,24 +140,8 @@ socket.on('responseJoinRoom', function (name) { if (name != 'error') { room = name; console.log('<< Room Response: ' + name); - - // Room Name - ctx.fillText(name, 0, 10); - - // Deck - deck = new Rectangle({ - name: 'deck', - x: canvas.width-cardWidth/2-40, - y: canvas.height-cardHeight/2-60, - width: cardWidth/2, - height: cardHeight/2, - fillStyle: "#FF0000" - }); - deck.draw(); - //ctx.fillRect(canvas.width-cardWidth/2-60, canvas.height/2-cardHeight/4, cardWidth/2, cardHeight/2); - - // Player Name - ctx.fillText(playerName, 100, 390); + alert('Commented out draw board, for UI stuff'); + //board.drawBoard(); } else { socket.disconnect(); alert('Rooms are full! Try again later'); diff --git a/public/shapes.js b/public/shapes.js index ec7cd21..10c4f68 100644 --- a/public/shapes.js +++ b/public/shapes.js @@ -3,31 +3,46 @@ context = document.getElementById("canvas").getContext("2d"); defaultFillStyle = '#000'; -function Rectangle(params) { - this.name = params.name; - this.x = params.x || 0; - this.y = params.y || 0; - this.width = params.width || 0; - this.height = params.height || 0; - this.fillStyle = params.fillStyle || "#FFFFFF"; - this.strokeStyle = params.strokeStyle || "#000000"; - this.lineWidth = params.lineWidth || 0; -} - -Rectangle.prototype.draw = function () { - if (this.fillStyle) { - console.log('X: '+this.x+' Y: '+this.y); - console.log('W: '+this.width+' H: '+this.height); +class Shape extends Path2D{ + constructor(params){ + super(); + this.shape = params.shape || 'rectangle'; + this.name = params.name; + this.x = params.x || 0; + this.y = params.y || 0; + this.width = params.width || 0; + this.height = params.height || 0; + this.fillStyle = params.fillStyle || "#FFFFFF"; + this.strokeStyle = params.strokeStyle || "#000000"; + this.lineWidth = params.lineWidth || 0; } - if (this.fillStyle) { - context.fillStyle = this.fillStyle; - context.fillRect(this.x, this.y, this.width, this.height); - context.fillStyle = defaultFillStyle; // Reset back to default - } - if (this.strokeStyle && this.lineWidth) { - context.strokeStyle = this.strokeStyle; - context.lineWidth = this.lineWidth; - context.strokeRect(this.x, this.y, this.width, this.height); + draw(){ + //console.log('X: '+this.x+' Y: '+this.y); + //console.log('W: '+this.width+' H: '+this.height); + + if (this.fillStyle) { + context.fillStyle = this.fillStyle; + if(this.shape == 'circle'){ + // X,Y,Radius, start, end + context.arc(this.x, this.y, this.width/2, 0, 2 * Math.PI); + context.fill(); + }else if (this.shape == 'rectangle'){ + context.fillRect(this.x, this.y, this.width, this.height); + } + context.fillStyle = defaultFillStyle; // Reset back to default + } + if (this.strokeStyle && this.lineWidth) { + context.strokeStyle = this.strokeStyle; + context.lineWidth = this.lineWidth; + if(this.shape == 'circle'){ + // X,Y,Radius, start, end + context.arc(this.x, this.y, this.width/2, 0, 2 * Math.PI); + context.stroke(); + }else if (this.shape == 'rectangle'){ + context.strokeRect(this.x, this.y, this.width, this.height); + } + context.strokeStyle = defaultFillStyle; + } } } diff --git a/public/style.css b/public/style.css index 926e58b..a9f53d6 100644 --- a/public/style.css +++ b/public/style.css @@ -9,6 +9,12 @@ canvas{ display: block; } +.wrap{ + margin: auto; + display: block; + width: 1000px; +} + .dib{display: inline-block; margin: 0; margin-bottom: 8px;} .joinRoomButtons li{ From 9dbb06dfb2420faded9d9687a11a02ca0f3a76c2 Mon Sep 17 00:00:00 2001 From: Nathan Date: Fri, 4 Oct 2024 22:09:49 +0100 Subject: [PATCH 02/23] FIX deck counter using old Class 'Rectangle' --- public/board.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/public/board.js b/public/board.js index 1d5afec..7e24484 100644 --- a/public/board.js +++ b/public/board.js @@ -61,7 +61,8 @@ class Board{ fillStyle: "#0000FF" }); clickableItems['deckSprite'].draw(); - let deckCounterSprite = new Circle({ + let deckCounterSprite = new Shape({ + shape: 'circle', name: 'deckCounter', x: canvas.width-cardWidth/5, y: canvas.height-cardHeight/5, From 0479a3ef8eaac77ed955996476a00bfb4928be82 Mon Sep 17 00:00:00 2001 From: Nathan Date: Sat, 5 Oct 2024 23:55:03 +0100 Subject: [PATCH 03/23] Add event listeners to decks --- public/board.js | 28 ++++++++++++++++++++-------- 1 file changed, 20 insertions(+), 8 deletions(-) diff --git a/public/board.js b/public/board.js index 7e24484..a11d31a 100644 --- a/public/board.js +++ b/public/board.js @@ -32,7 +32,6 @@ class Board{ this.drawDeck(); this.drawDeckOpponent(); - this.drawPlayerNames('Nathan', 'Evil Nathan'); } @@ -78,7 +77,7 @@ class Board{ } drawDeckOpponent(){ // Opponent's Deck - let deckSprite = new Shape({ + clickableItems['deckOpponentSprite'] = new Shape({ name: 'deckOpponent', x: 40, y: 60, @@ -86,7 +85,7 @@ class Board{ height: cardHeight/2, fillStyle: "#FF0000" }); - deckSprite.draw(); + clickableItems['deckOpponentSprite'].draw(); let deckCounterSprite = new Shape({ shape: 'circle', name: 'deckCounterOpponent', @@ -128,22 +127,35 @@ let board = new Board; board.drawBoard(); -canvas.addEventListener('mousemove', function(event) { +canvas.addEventListener('click', function(event) { var x = event.pageX - canvasLeft, y = event.pageY - canvasTop; - console.log('X: '+x+' Y: '+y); - // Collision detection between clicked offset and clickableItems // https://stackoverflow.com/a/9880302 + + // # PLAYER DECK clickable = clickableItems['deckSprite']; - console.log(clickableItems['deckSprite']); + + // Want to loop clickables ideally, and call a function + // that's set to them for click, hover, etc. + + // For now this will be fine, as it functions + if ( + y > clickable.y && y < clickable.y + clickable.height + && x > clickable.x && x < clickable.x + clickable.width + ) { + console.log('click Event: '+clickable.name); + } + + // # OPPONENT DECK + clickable = clickableItems['deckOpponentSprite']; if ( y > clickable.y && y < clickable.y + clickable.height && x > clickable.x && x < clickable.x + clickable.width ) { - console.log('HUUUH'); + console.log('click Event: '+clickable.name); } }, false); From abb744365830dc979c0ce1c4cfdce08fca85d72f Mon Sep 17 00:00:00 2001 From: Nathan Date: Sun, 6 Oct 2024 20:44:16 +0100 Subject: [PATCH 04/23] Add basic player draw/card discard --- public/board.js | 198 ++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 176 insertions(+), 22 deletions(-) diff --git a/public/board.js b/public/board.js index a11d31a..c1b7972 100644 --- a/public/board.js +++ b/public/board.js @@ -10,9 +10,24 @@ const back = new Image(); let clickableItems = []; -console.log(clickableItems); +clickableItems['hand'] = []; +clickableItems['opponentHand'] = []; +// TODO: Uniform the arrays to player and opponent/different playesr +let playerHand = []; +let opponentHand = []; +let playerBoard = []; +let opponentBoard = []; +let deckCount = 60; +let deckCountOpponent = 60; + +let cardsInOpponentsHand = 0; +const maxHandSize = 4; +const maxBoardSize = 3; + + +// Gonna need lots of refactoring, and sorting class Board{ constructor(){ console.log('initBoard'); @@ -24,7 +39,7 @@ class Board{ } drawBoard(){ - console.log('drawBoard'); + // Reset board ctx.clearRect(0, 0, canvas.width, canvas.height); // Room Name ctx.fillText(name, 0, 10); @@ -32,12 +47,13 @@ class Board{ this.drawDeck(); this.drawDeckOpponent(); + this.drawHand(); + this.drawOpponentHand(); + this.drawPlayerNames('Nathan', 'Evil Nathan'); } drawPlayerNames(playerName, opponentName = false){ - console.log('drawPlayerNames'); - // Player Name ctx.fillText(playerName, 50, canvas.height - 110); @@ -59,6 +75,7 @@ class Board{ height: cardHeight/2, fillStyle: "#0000FF" }); + //ctx.fillRect(canvas.width-cardWidth/2-60, canvas.height/2-cardHeight/4, cardWidth/2, cardHeight/2); clickableItems['deckSprite'].draw(); let deckCounterSprite = new Shape({ shape: 'circle', @@ -70,10 +87,8 @@ class Board{ fillStyle: "#FFF" }); deckCounterSprite.draw(); - let cardsInDeck = 60; // TODO: Center in the circle - ctx.fillText(cardsInDeck, canvas.width-cardWidth/5 - (ctx.measureText(cardsInDeck).width) + 7, canvas.height-cardHeight/5 + 5); - //ctx.fillRect(canvas.width-cardWidth/2-60, canvas.height/2-cardHeight/4, cardWidth/2, cardHeight/2); + ctx.fillText(deckCount, canvas.width-cardWidth/5 - (ctx.measureText(deckCount).width) + 7, canvas.height-cardHeight/5 + 5); } drawDeckOpponent(){ // Opponent's Deck @@ -96,27 +111,122 @@ class Board{ fillStyle: "#FFF" }); deckCounterSprite.draw(); - let cardsInDeck = 60; - // TODO: Center in the circle + ctx.fillStyle = '#000'; ctx.strokeStyle = '#000'; - ctx.fillText(cardsInDeck, cardWidth/2 + (ctx.measureText(cardsInDeck).width) + 10, cardHeight/1.58); + // TODO: Center in the circle + ctx.fillText(deckCountOpponent, cardWidth/2 + (ctx.measureText(deckCount).width) + 10, cardHeight/1.58); } // Naming's getting awkward here... // Draw the card - drawCardSprites(){ + drawHand(){ + // Player Hand/Cards in Hand + for (let i = 0; i < playerHand.length; i++) { + + let name = 'cardInHand_'+(i+1); + + let cardPadding = 10; + let fill = '#'+i+i+'FF00'; + + // TODO: fix positionX, actually have some maffs + let positionX = canvas.width/2 - ((cardWidth/4 * 2) * (playerHand.length - (i+1)) - (cardPadding * (i+1))); + console.log('drawHand: cardsInHand: '+(i+1)+' / '+playerHand.length); + + clickableItems['hand'][name] = new Shape({ + name: name, + x: positionX, + y: canvas.height - cardHeight/2-20, + width: cardWidth/2, + height: cardHeight/2, + fillStyle: fill + }); + playerHand[i]['clickable'] = clickableItems['hand'][name]; + playerHand[i]['clickable'].draw(); + } } - drawCardSpritesOpponent(){ + drawOpponentHand(){ + // Opponents Hand/Cards in Hand + for (let i = 0; i < opponentHand.length; i++) { + + let name = 'cardInOpponentsHand_'+(i+1); + + let cardPadding = 10; + let fill = '#'+i+i+'DD00'; + + // TODO: fix positionX, actually have some maffs + let positionX = canvas.width/2 - ((cardWidth/4 * 2) * (opponentHand.length - (i+1)) - (cardPadding * (i+1))); + console.log('drawOpponentHand: cardsInHand: '+(i+1)+' / '+opponentHand.length); + + clickableItems['opponentHand'][name] = new Shape({ + name: name, + x: positionX, + y: 20, + width: cardWidth/2, + height: cardHeight/2, + fillStyle: fill + }); + clickableItems['opponentHand'][name].draw(); + } } + + drawCards(){} + // Draw a card, traditional TCG drawACard(){ + if(playerHand.length >= maxHandSize){ + alert('Hand full '+playerHand.length+'/'+maxHandSize); + return 0; + } + playerHand.push({'name':'CardName', 'cost':1, 'atk':1, 'def':1, 'rarity': 'common', 'effect':null, 'type':'human'}); + this.drawBoard(); } drawACardOpponent(){ + if(opponentHand.length >= maxHandSize){ + alert('Hand full '+opponentHand.length+'/'+maxHandSize); + return 0; + } + this.drawBoard(); + } + + + drawCardsOnBoard(){ + // DUPER OF DRAW PLAYER HAND FOR NOW!!! + for (let i = 0; i < playerHand.length; i++) { + + let name = 'cardInHand_'+(i+1); + + let cardPadding = 10; + let fill = '#'+i+i+'FF00'; + + // TODO: fix positionX, actually have some maffs + let positionX = canvas.width/2 - ((cardWidth/4 * 2) * (playerHand.length - (i+1)) - (cardPadding * (i+1))); + console.log('drawHand: cardsInHand: '+(i+1)+' / '+playerHand.length); + + clickableItems['hand'][name] = new Shape({ + name: name, + x: positionX, + y: canvas.height - cardHeight/2-20, + width: cardWidth/2, + height: cardHeight/2, + fillStyle: fill + }); + playerHand[i]['clickable'] = clickableItems['hand'][name]; + playerHand[i]['clickable'].draw(); + } + + + } + + drawCardsOnBoardOpponent(){ + + } + + playCardToBoard(){ } } @@ -139,24 +249,68 @@ canvas.addEventListener('click', function(event) { // Want to loop clickables ideally, and call a function // that's set to them for click, hover, etc. + // TODO: potentially loop all clickables, and do a check on clickable.name to differ event handling per-item // For now this will be fine, as it functions - if ( - y > clickable.y && y < clickable.y + clickable.height - && x > clickable.x && x < clickable.x + clickable.width - ) { - console.log('click Event: '+clickable.name); + if(clickableCheck(x,y,clickable)){ + board.drawACard(); } // # OPPONENT DECK clickable = clickableItems['deckOpponentSprite']; - if ( - y > clickable.y && y < clickable.y + clickable.height - && x > clickable.x && x < clickable.x + clickable.width - ) { - console.log('click Event: '+clickable.name); + if(clickableCheck(x,y,clickable)){ + board.drawACardOpponent(); } + // # PLAYER HAND + clickableHand = clickableItems['hand']; + let handLength = Object.keys(clickableHand).length; + + playerHand.forEach(function(card, index){ + console.log(card); + console.log(card.clickable); + + let clickable = card.clickable; + + if(clickableCheck(x,y,clickable)){ + + console.log('Clicked Hand item: '+ clickable.name); + + // Remove from hand + playerHand.splice(index, 1); + + // This would actually fire off a socketIO doodad, that would then return + // data, and redraw. But for now (UI test) + + // Add to board + board.drawBoard(); + } + }); + + + }, false); +function clickableCheck(x,y,clickable){ + + console.log('click Event: '+clickable.name); + // Debug Stuff + let debug = false + if(debug){ + console.log(clickable.y+' <'); + console.log(y+ '<') + console.log(clickable.y+clickable.height); + } + + if( + y > clickable.y && y < clickable.y + clickable.height + && x > clickable.x && x < clickable.x + clickable.width) + { + return true; + } + + return false; + +} + From 5fd58fd654cdd4064ab6190aecdf6c95a8cec89e Mon Sep 17 00:00:00 2001 From: Nathan Date: Mon, 7 Oct 2024 10:36:52 +0100 Subject: [PATCH 05/23] Add playerDeck, and draw from playerDeck --- public/board.js | 47 +++++++++++++++++++++++++++++++++++++++-------- public/shapes.js | 16 ++++++++++++++-- 2 files changed, 53 insertions(+), 10 deletions(-) diff --git a/public/board.js b/public/board.js index c1b7972..563a6ea 100644 --- a/public/board.js +++ b/public/board.js @@ -8,7 +8,6 @@ const cardHeight = 360; const cards = new Image(); const back = new Image(); - let clickableItems = []; clickableItems['hand'] = []; clickableItems['opponentHand'] = []; @@ -18,6 +17,8 @@ let playerHand = []; let opponentHand = []; let playerBoard = []; let opponentBoard = []; +let playerDeck = []; +let opponentDeck = []; let deckCount = 60; let deckCountOpponent = 60; @@ -87,8 +88,10 @@ class Board{ fillStyle: "#FFF" }); deckCounterSprite.draw(); + // TODO: Center in the circle - ctx.fillText(deckCount, canvas.width-cardWidth/5 - (ctx.measureText(deckCount).width) + 7, canvas.height-cardHeight/5 + 5); + ctx.fillStyle = '#000'; + ctx.fillText(playerDeck.length, canvas.width-cardWidth/5 - (ctx.measureText(playerDeck.length).width) + 7, canvas.height-cardHeight/5 + 5); } drawDeckOpponent(){ // Opponent's Deck @@ -101,7 +104,7 @@ class Board{ fillStyle: "#FF0000" }); clickableItems['deckOpponentSprite'].draw(); - let deckCounterSprite = new Shape({ + let deckCounterOpponentSprite = new Shape({ shape: 'circle', name: 'deckCounterOpponent', x: cardWidth/2+(cardWidth/8), @@ -110,12 +113,11 @@ class Board{ height: cardHeight/8, fillStyle: "#FFF" }); - deckCounterSprite.draw(); + deckCounterOpponentSprite.draw(); ctx.fillStyle = '#000'; - ctx.strokeStyle = '#000'; // TODO: Center in the circle - ctx.fillText(deckCountOpponent, cardWidth/2 + (ctx.measureText(deckCount).width) + 10, cardHeight/1.58); + ctx.fillText(opponentDeck.length, cardWidth/2 + (ctx.measureText(opponentDeck.length).width) + 10, cardHeight/1.58); } // Naming's getting awkward here... @@ -131,18 +133,27 @@ class Board{ // TODO: fix positionX, actually have some maffs let positionX = canvas.width/2 - ((cardWidth/4 * 2) * (playerHand.length - (i+1)) - (cardPadding * (i+1))); + let positionY = canvas.height - cardHeight/2-20; console.log('drawHand: cardsInHand: '+(i+1)+' / '+playerHand.length); clickableItems['hand'][name] = new Shape({ name: name, x: positionX, - y: canvas.height - cardHeight/2-20, + y: positionY, width: cardWidth/2, height: cardHeight/2, fillStyle: fill }); playerHand[i]['clickable'] = clickableItems['hand'][name]; playerHand[i]['clickable'].draw(); + + // Add card text + ctx.fillStyle = '#000'; + ctx.fillText( + playerHand[i]['name'] + , positionX + (ctx.measureText(playerHand[i]['name']/2).width) + , positionY+20 + ); } } @@ -182,7 +193,14 @@ class Board{ return 0; } - playerHand.push({'name':'CardName', 'cost':1, 'atk':1, 'def':1, 'rarity': 'common', 'effect':null, 'type':'human'}); + // Random card from deck, remove from deck, add to hand + let cardToDraw = Math.floor(Math.random() * deckCount); + let cardDrawn = playerDeck[cardToDraw]; + console.log(cardDrawn); + // Remove from deck + playerDeck.splice(cardToDraw, 1); + // Add to hand + playerHand.push(cardDrawn); this.drawBoard(); } drawACardOpponent(){ @@ -231,6 +249,11 @@ class Board{ } } +// TEMP!! +createDeckList(playerDeck, deckCount); +createDeckList(opponentDeck, deckCountOpponent); +console.log(playerDeck); + // Run board commands here for testing let board = new Board; //board.initBoard(); @@ -314,3 +337,11 @@ function clickableCheck(x,y,clickable){ } +// TEMP: Create a deck of X different cards that can be drawn/played +// for UI development, will be done on server and not shown to clients +function createDeckList(deck, deckCount){ + for(let i = 0; i < deckCount; i++){ + deck.push({'name':'CardName '+(i+1), 'cost':1, 'atk':1, 'def':1, 'rarity': 'common', 'effect':null, 'type':'human'}); + } +} + diff --git a/public/shapes.js b/public/shapes.js index 10c4f68..df42eef 100644 --- a/public/shapes.js +++ b/public/shapes.js @@ -1,7 +1,9 @@ // https://stackoverflow.com/a/29676404 context = document.getElementById("canvas").getContext("2d"); -defaultFillStyle = '#000'; +let defaultFillStyle = '#000'; +let shapeDebug = true; +let shapeDebugColour = '#FF00FF'; class Shape extends Path2D{ constructor(params){ @@ -17,27 +19,37 @@ class Shape extends Path2D{ this.lineWidth = params.lineWidth || 0; } draw(){ + //console.log('Draw Shape: '+this.name); //console.log('X: '+this.x+' Y: '+this.y); //console.log('W: '+this.width+' H: '+this.height); + //console.log(''); if (this.fillStyle) { context.fillStyle = this.fillStyle; if(this.shape == 'circle'){ // X,Y,Radius, start, end + context.beginPath(); context.arc(this.x, this.y, this.width/2, 0, 2 * Math.PI); context.fill(); + context.closePath(); }else if (this.shape == 'rectangle'){ context.fillRect(this.x, this.y, this.width, this.height); } context.fillStyle = defaultFillStyle; // Reset back to default } - if (this.strokeStyle && this.lineWidth) { + if (this.strokeStyle && this.lineWidth || shapeDebug) { context.strokeStyle = this.strokeStyle; context.lineWidth = this.lineWidth; + if(shapeDebug){ + context.strokeStyle = shapeDebugColour; + context.lineWidth = 2; + } if(this.shape == 'circle'){ // X,Y,Radius, start, end + context.beginPath(); context.arc(this.x, this.y, this.width/2, 0, 2 * Math.PI); context.stroke(); + context.closePath(); }else if (this.shape == 'rectangle'){ context.strokeRect(this.x, this.y, this.width, this.height); } From 794fd15d528061f680575d64e85f6ceaebe12920 Mon Sep 17 00:00:00 2001 From: Nathan Date: Mon, 7 Oct 2024 10:50:17 +0100 Subject: [PATCH 06/23] Fix opponentDeck and draw to hand --- public/board.js | 28 +++++++++++++++++++++------- 1 file changed, 21 insertions(+), 7 deletions(-) diff --git a/public/board.js b/public/board.js index 563a6ea..fc06c29 100644 --- a/public/board.js +++ b/public/board.js @@ -169,17 +169,28 @@ class Board{ // TODO: fix positionX, actually have some maffs let positionX = canvas.width/2 - ((cardWidth/4 * 2) * (opponentHand.length - (i+1)) - (cardPadding * (i+1))); + let positionY = 20; console.log('drawOpponentHand: cardsInHand: '+(i+1)+' / '+opponentHand.length); clickableItems['opponentHand'][name] = new Shape({ name: name, x: positionX, - y: 20, + y: positionY, width: cardWidth/2, height: cardHeight/2, fillStyle: fill }); - clickableItems['opponentHand'][name].draw(); + + opponentHand[i]['clickable'] = clickableItems['opponentHand'][name]; + opponentHand[i]['clickable'].draw(); + + // Add card text + ctx.fillStyle = '#000'; + ctx.fillText( + opponentHand[i]['name'] + , positionX + (ctx.measureText(opponentHand[i]['name']/2).width) + , positionY+20 + ); } } @@ -208,6 +219,14 @@ class Board{ alert('Hand full '+opponentHand.length+'/'+maxHandSize); return 0; } + // Random card from deck, remove from deck, add to hand + let cardToDraw = Math.floor(Math.random() * deckCountOpponent); + let cardDrawn = opponentDeck[cardToDraw]; + console.log(cardDrawn); + // Remove from deck + opponentDeck.splice(cardToDraw, 1); + // Add to hand + opponentHand.push(cardDrawn); this.drawBoard(); } @@ -287,9 +306,6 @@ canvas.addEventListener('click', function(event) { } // # PLAYER HAND - clickableHand = clickableItems['hand']; - let handLength = Object.keys(clickableHand).length; - playerHand.forEach(function(card, index){ console.log(card); console.log(card.clickable); @@ -312,12 +328,10 @@ canvas.addEventListener('click', function(event) { }); - }, false); function clickableCheck(x,y,clickable){ - console.log('click Event: '+clickable.name); // Debug Stuff let debug = false if(debug){ From 4b041062fd7fe0f496795c6b2ce1c56c5ec43d52 Mon Sep 17 00:00:00 2001 From: Nathan Date: Mon, 7 Oct 2024 15:42:25 +0100 Subject: [PATCH 07/23] Add play card from hand to board --- public/board.js | 43 ++++++++++++++++++++++++++++++++----------- 1 file changed, 32 insertions(+), 11 deletions(-) diff --git a/public/board.js b/public/board.js index fc06c29..af0ddde 100644 --- a/public/board.js +++ b/public/board.js @@ -9,6 +9,9 @@ const cards = new Image(); const back = new Image(); let clickableItems = []; +// Make all clickableItems sit in the same clickableItems array +// Not needed in a child, as loops will be on arrays below +clickableItems['board'] = []; clickableItems['hand'] = []; clickableItems['opponentHand'] = []; @@ -45,6 +48,9 @@ class Board{ // Room Name ctx.fillText(name, 0, 10); + this.drawCardsOnBoard(); + this.drawCardsOnBoardOpponent(); + this.drawDeck(); this.drawDeckOpponent(); @@ -233,27 +239,28 @@ class Board{ drawCardsOnBoard(){ // DUPER OF DRAW PLAYER HAND FOR NOW!!! - for (let i = 0; i < playerHand.length; i++) { + for (let i = 0; i < playerBoard.length; i++) { - let name = 'cardInHand_'+(i+1); + let name = 'cardOnBoard_'+(i+1); let cardPadding = 10; - let fill = '#'+i+i+'FF00'; + let fill = '#'+i+i+'CC00'; // TODO: fix positionX, actually have some maffs - let positionX = canvas.width/2 - ((cardWidth/4 * 2) * (playerHand.length - (i+1)) - (cardPadding * (i+1))); + let positionX = canvas.width/2 - ((cardWidth/4 * 2) * (playerBoard.length - (i+1)) - (cardPadding * (i+1))); + let positionY = canvas.height - cardHeight/2-20; console.log('drawHand: cardsInHand: '+(i+1)+' / '+playerHand.length); - clickableItems['hand'][name] = new Shape({ + clickableItems['board'][name] = new Shape({ name: name, x: positionX, - y: canvas.height - cardHeight/2-20, + y: positionY-cardHeight/2, width: cardWidth/2, height: cardHeight/2, fillStyle: fill }); - playerHand[i]['clickable'] = clickableItems['hand'][name]; - playerHand[i]['clickable'].draw(); + playerBoard[i]['clickable'] = clickableItems['board'][name]; + playerBoard[i]['clickable'].draw(); } @@ -263,8 +270,23 @@ class Board{ } - playCardToBoard(){ + playCardToBoard(index){ + // Get the card data + let cardPlayed = playerHand[index]; + // Check if there's space on board to play + // TODO: Check this in back-end + if(playerBoard.length >= maxBoardSize){ + alert('No space on board to play card. '+playerBoard.length+'/'+maxBoardSize); + return 0; + } + + // Remove from hand + playerHand.splice(index, 1); + // Add to board + playerBoard.push(cardPlayed); + + this.drawBoard(); } } @@ -316,8 +338,7 @@ canvas.addEventListener('click', function(event) { console.log('Clicked Hand item: '+ clickable.name); - // Remove from hand - playerHand.splice(index, 1); + board.playCardToBoard(index); // This would actually fire off a socketIO doodad, that would then return // data, and redraw. But for now (UI test) From 154dc249a852b7426b748ef72003a8bc6c42fc38 Mon Sep 17 00:00:00 2001 From: Nathan Date: Mon, 7 Oct 2024 18:12:19 +0100 Subject: [PATCH 08/23] Add drawCard method to remove dupe code Draws a card, when passed x/y/width/height, etc. Replaced duplicated code --- public/board.js | 109 +++++++++++++++++++----------------------------- 1 file changed, 42 insertions(+), 67 deletions(-) diff --git a/public/board.js b/public/board.js index af0ddde..8447787 100644 --- a/public/board.js +++ b/public/board.js @@ -72,6 +72,30 @@ class Board{ } } + // Draw Invidual Cards, called by other deck stuff + // Might be put into a card class, makes sense, eh. + drawCard(array, arrayKey, name, positionX, positionY, width, height, fill){ + var cardClickable = new Shape({ + name: name, + x: positionX, + y: positionY, + width: cardWidth/2, + height: cardHeight/2, + fillStyle: fill + }); + + array[arrayKey]['clickable'] = cardClickable; + array[arrayKey]['clickable'].draw(); + + // Add card text + ctx.fillStyle = '#000'; + ctx.fillText( + array[arrayKey]['name'] + , positionX + (ctx.measureText(array[arrayKey]['name']/2).width) + , positionY+20 + ); + } + drawDeck(){ // Deck clickableItems['deckSprite'] = new Shape({ @@ -127,7 +151,7 @@ class Board{ } // Naming's getting awkward here... - // Draw the card + // Draw the cards in hand drawHand(){ // Player Hand/Cards in Hand for (let i = 0; i < playerHand.length; i++) { @@ -138,28 +162,12 @@ class Board{ let fill = '#'+i+i+'FF00'; // TODO: fix positionX, actually have some maffs - let positionX = canvas.width/2 - ((cardWidth/4 * 2) * (playerHand.length - (i+1)) - (cardPadding * (i+1))); - let positionY = canvas.height - cardHeight/2-20; - console.log('drawHand: cardsInHand: '+(i+1)+' / '+playerHand.length); - - clickableItems['hand'][name] = new Shape({ - name: name, - x: positionX, - y: positionY, - width: cardWidth/2, - height: cardHeight/2, - fillStyle: fill - }); - playerHand[i]['clickable'] = clickableItems['hand'][name]; - playerHand[i]['clickable'].draw(); - - // Add card text - ctx.fillStyle = '#000'; - ctx.fillText( - playerHand[i]['name'] - , positionX + (ctx.measureText(playerHand[i]['name']/2).width) - , positionY+20 - ); + let positionX = canvas.width/2 - ((cardWidth/4 * 2) * (playerHand.length - (i+1)) - (cardPadding * (i+1))); + let positionY = canvas.height - cardHeight/2-20; + let width = cardWidth/2; + let height = cardHeight/2; + + this.drawCard(playerHand, i, name, positionX, positionY, width, height, fill); } } @@ -176,27 +184,10 @@ class Board{ // TODO: fix positionX, actually have some maffs let positionX = canvas.width/2 - ((cardWidth/4 * 2) * (opponentHand.length - (i+1)) - (cardPadding * (i+1))); let positionY = 20; - console.log('drawOpponentHand: cardsInHand: '+(i+1)+' / '+opponentHand.length); - - clickableItems['opponentHand'][name] = new Shape({ - name: name, - x: positionX, - y: positionY, - width: cardWidth/2, - height: cardHeight/2, - fillStyle: fill - }); - - opponentHand[i]['clickable'] = clickableItems['opponentHand'][name]; - opponentHand[i]['clickable'].draw(); - - // Add card text - ctx.fillStyle = '#000'; - ctx.fillText( - opponentHand[i]['name'] - , positionX + (ctx.measureText(opponentHand[i]['name']/2).width) - , positionY+20 - ); + let width = cardWidth/2; + let height = cardHeight/2; + + this.drawCard(opponentHand, i, name, positionX, positionY, width, height, fill); } } @@ -213,7 +204,6 @@ class Board{ // Random card from deck, remove from deck, add to hand let cardToDraw = Math.floor(Math.random() * deckCount); let cardDrawn = playerDeck[cardToDraw]; - console.log(cardDrawn); // Remove from deck playerDeck.splice(cardToDraw, 1); // Add to hand @@ -228,7 +218,6 @@ class Board{ // Random card from deck, remove from deck, add to hand let cardToDraw = Math.floor(Math.random() * deckCountOpponent); let cardDrawn = opponentDeck[cardToDraw]; - console.log(cardDrawn); // Remove from deck opponentDeck.splice(cardToDraw, 1); // Add to hand @@ -238,7 +227,7 @@ class Board{ drawCardsOnBoard(){ - // DUPER OF DRAW PLAYER HAND FOR NOW!!! + // DUPE OF DRAW PLAYER HAND FOR NOW!!! for (let i = 0; i < playerBoard.length; i++) { let name = 'cardOnBoard_'+(i+1); @@ -248,28 +237,19 @@ class Board{ // TODO: fix positionX, actually have some maffs let positionX = canvas.width/2 - ((cardWidth/4 * 2) * (playerBoard.length - (i+1)) - (cardPadding * (i+1))); - let positionY = canvas.height - cardHeight/2-20; - console.log('drawHand: cardsInHand: '+(i+1)+' / '+playerHand.length); - - clickableItems['board'][name] = new Shape({ - name: name, - x: positionX, - y: positionY-cardHeight/2, - width: cardWidth/2, - height: cardHeight/2, - fillStyle: fill - }); - playerBoard[i]['clickable'] = clickableItems['board'][name]; - playerBoard[i]['clickable'].draw(); - } - + let positionY = canvas.height - cardHeight/2-20-(cardHeight/2); + let width = cardWidth/2; + let height = cardHeight/2; + this.drawCard(playerBoard, i, name, positionX, positionY, width, height, fill); + } } drawCardsOnBoardOpponent(){ } + // Currently only functionality in hand playCardToBoard(index){ // Get the card data let cardPlayed = playerHand[index]; @@ -293,7 +273,6 @@ class Board{ // TEMP!! createDeckList(playerDeck, deckCount); createDeckList(opponentDeck, deckCountOpponent); -console.log(playerDeck); // Run board commands here for testing let board = new Board; @@ -329,15 +308,11 @@ canvas.addEventListener('click', function(event) { // # PLAYER HAND playerHand.forEach(function(card, index){ - console.log(card); - console.log(card.clickable); let clickable = card.clickable; if(clickableCheck(x,y,clickable)){ - console.log('Clicked Hand item: '+ clickable.name); - board.playCardToBoard(index); // This would actually fire off a socketIO doodad, that would then return From 3a174aed84324c7dc0bc3eb6b869dd86d20b78f1 Mon Sep 17 00:00:00 2001 From: Nathan Date: Mon, 7 Oct 2024 18:38:01 +0100 Subject: [PATCH 09/23] Add playCard/drawCard to opponentBoard --- public/board.js | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/public/board.js b/public/board.js index 8447787..2fb7155 100644 --- a/public/board.js +++ b/public/board.js @@ -246,7 +246,21 @@ class Board{ } drawCardsOnBoardOpponent(){ + for (let i = 0; i < opponentBoard.length; i++) { + let name = 'cardOnBoardOpponent_'+(i+1); + + let cardPadding = 10; + let fill = '#'+i+i+'AA00'; + + // TODO: fix positionX, actually have some maffs + let positionX = canvas.width/2 - ((cardWidth/4 * 2) * (opponentBoard.length - (i+1)) - (cardPadding * (i+1))); + let positionY = cardHeight/2; + let width = cardWidth/2; + let height = cardHeight/2; + + this.drawCard(opponentBoard, i, name, positionX, positionY, width, height, fill); + } } // Currently only functionality in hand @@ -266,6 +280,24 @@ class Board{ // Add to board playerBoard.push(cardPlayed); + this.drawBoard(); + } + playCardToBoardFromDeckOpponent(){ + + // Random card from deck + let cardToDraw = Math.floor(Math.random() * deckCount); + let cardPlayed = opponentDeck[cardToDraw]; + + if(opponentBoard.length >= maxBoardSize){ + alert('No space on board to play card. '+opponentBoard.length+'/'+maxBoardSize); + return 0; + } + + // Remove from deck + opponentDeck.splice(cardToDraw, 1); + // Add to board + opponentBoard.push(cardPlayed); + this.drawBoard(); } } @@ -278,6 +310,9 @@ createDeckList(opponentDeck, deckCountOpponent); let board = new Board; //board.initBoard(); +// TEMP: Play a card on opponents board (from their deck) +board.playCardToBoardFromDeckOpponent(); + board.drawBoard(); canvas.addEventListener('click', function(event) { From 3e71a1cfb0694d05ab6bbf76f280a5d6ccde881a Mon Sep 17 00:00:00 2001 From: Nathan Date: Mon, 7 Oct 2024 19:45:41 +0100 Subject: [PATCH 10/23] Fix drawCard method. Used passed W/H --- public/board.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/public/board.js b/public/board.js index 2fb7155..18d9b89 100644 --- a/public/board.js +++ b/public/board.js @@ -79,8 +79,8 @@ class Board{ name: name, x: positionX, y: positionY, - width: cardWidth/2, - height: cardHeight/2, + width: width, + height: height, fillStyle: fill }); From 558a452d29aa44d2221db128688f829524788236 Mon Sep 17 00:00:00 2001 From: Nathan Date: Mon, 7 Oct 2024 20:11:44 +0100 Subject: [PATCH 11/23] Change base cardsize to fit on board --- public/board.js | 68 ++++++++++++++++++++++++------------------------- 1 file changed, 34 insertions(+), 34 deletions(-) diff --git a/public/board.js b/public/board.js index 18d9b89..fa745af 100644 --- a/public/board.js +++ b/public/board.js @@ -2,8 +2,8 @@ const ctx = canvas.getContext('2d'); const canvasLeft = canvas.offsetLeft + canvas.clientLeft; const canvasTop = canvas.offsetTop + canvas.clientTop; -const cardWidth = 240; -const cardHeight = 360; +const cardWidth = 80; +const cardHeight = 120; const cards = new Image(); const back = new Image(); @@ -91,7 +91,7 @@ class Board{ ctx.fillStyle = '#000'; ctx.fillText( array[arrayKey]['name'] - , positionX + (ctx.measureText(array[arrayKey]['name']/2).width) + , positionX + (ctx.measureText(array[arrayKey]['name']/2).width) - width/4 , positionY+20 ); } @@ -100,10 +100,10 @@ class Board{ // Deck clickableItems['deckSprite'] = new Shape({ name: 'deck', - x: canvas.width-cardWidth/2-40, - y: canvas.height-cardHeight/2-60, - width: cardWidth/2, - height: cardHeight/2, + x: canvas.width-cardWidth*1.5-40, + y: canvas.height-cardHeight*1.5-60, + width: cardWidth*1.5, + height: cardHeight*1.5, fillStyle: "#0000FF" }); //ctx.fillRect(canvas.width-cardWidth/2-60, canvas.height/2-cardHeight/4, cardWidth/2, cardHeight/2); @@ -111,17 +111,17 @@ class Board{ let deckCounterSprite = new Shape({ shape: 'circle', name: 'deckCounter', - x: canvas.width-cardWidth/5, - y: canvas.height-cardHeight/5, - width: cardWidth/8, - height: cardHeight/8, + x: canvas.width-cardWidth*.6, + y: canvas.height-cardHeight*.6, + width: cardWidth*.375, + height: cardHeight*.375, fillStyle: "#FFF" }); deckCounterSprite.draw(); // TODO: Center in the circle ctx.fillStyle = '#000'; - ctx.fillText(playerDeck.length, canvas.width-cardWidth/5 - (ctx.measureText(playerDeck.length).width) + 7, canvas.height-cardHeight/5 + 5); + ctx.fillText(playerDeck.length, canvas.width-cardWidth*.6 - (ctx.measureText(playerDeck.length).width) + 7, canvas.height-cardHeight*.6 + 5); } drawDeckOpponent(){ // Opponent's Deck @@ -129,25 +129,25 @@ class Board{ name: 'deckOpponent', x: 40, y: 60, - width: cardWidth/2, - height: cardHeight/2, + width: cardWidth*1.5, + height: cardHeight*1.5, fillStyle: "#FF0000" }); clickableItems['deckOpponentSprite'].draw(); let deckCounterOpponentSprite = new Shape({ shape: 'circle', name: 'deckCounterOpponent', - x: cardWidth/2+(cardWidth/8), - y: cardHeight/2+(cardHeight/8), - width: cardWidth/8, - height: cardHeight/8, + x: cardWidth*1.5+(cardWidth*.375), + y: cardHeight*1.5+(cardHeight*.375), + width: cardWidth*.375, + height: cardHeight*.375, fillStyle: "#FFF" }); deckCounterOpponentSprite.draw(); ctx.fillStyle = '#000'; // TODO: Center in the circle - ctx.fillText(opponentDeck.length, cardWidth/2 + (ctx.measureText(opponentDeck.length).width) + 10, cardHeight/1.58); + ctx.fillText(opponentDeck.length, cardWidth*1.5 + (ctx.measureText(opponentDeck.length).width) + 10, cardHeight*1.9); } // Naming's getting awkward here... @@ -162,10 +162,10 @@ class Board{ let fill = '#'+i+i+'FF00'; // TODO: fix positionX, actually have some maffs - let positionX = canvas.width/2 - ((cardWidth/4 * 2) * (playerHand.length - (i+1)) - (cardPadding * (i+1))); - let positionY = canvas.height - cardHeight/2-20; - let width = cardWidth/2; - let height = cardHeight/2; + let positionX = canvas.width/2 - (cardWidth * (playerHand.length - (i+1)) - (cardPadding * (i+1))); + let positionY = canvas.height-cardWidth*1.5-20; + let width = cardWidth; + let height = cardHeight; this.drawCard(playerHand, i, name, positionX, positionY, width, height, fill); } @@ -182,10 +182,10 @@ class Board{ let fill = '#'+i+i+'DD00'; // TODO: fix positionX, actually have some maffs - let positionX = canvas.width/2 - ((cardWidth/4 * 2) * (opponentHand.length - (i+1)) - (cardPadding * (i+1))); + let positionX = canvas.width/2 - (cardWidth * (opponentHand.length - (i+1)) - (cardPadding * (i+1))); let positionY = 20; - let width = cardWidth/2; - let height = cardHeight/2; + let width = cardWidth; + let height = cardHeight; this.drawCard(opponentHand, i, name, positionX, positionY, width, height, fill); } @@ -236,10 +236,10 @@ class Board{ let fill = '#'+i+i+'CC00'; // TODO: fix positionX, actually have some maffs - let positionX = canvas.width/2 - ((cardWidth/4 * 2) * (playerBoard.length - (i+1)) - (cardPadding * (i+1))); - let positionY = canvas.height - cardHeight/2-20-(cardHeight/2); - let width = cardWidth/2; - let height = cardHeight/2; + let positionX = canvas.width/2 - (cardWidth * (playerBoard.length - (i+1)) - (cardPadding * (i+1))); + let positionY = canvas.height - cardHeight-30-(cardHeight); + let width = cardWidth; + let height = cardHeight; this.drawCard(playerBoard, i, name, positionX, positionY, width, height, fill); } @@ -254,10 +254,10 @@ class Board{ let fill = '#'+i+i+'AA00'; // TODO: fix positionX, actually have some maffs - let positionX = canvas.width/2 - ((cardWidth/4 * 2) * (opponentBoard.length - (i+1)) - (cardPadding * (i+1))); - let positionY = cardHeight/2; - let width = cardWidth/2; - let height = cardHeight/2; + let positionX = canvas.width/2 - (cardWidth * (opponentBoard.length - (i+1)) - (cardPadding * (i+1))); + let positionY = cardHeight + 30; + let width = cardWidth; + let height = cardHeight; this.drawCard(opponentBoard, i, name, positionX, positionY, width, height, fill); } From 74353eac5ca05d2b481db64e0fc511a25ba04f7c Mon Sep 17 00:00:00 2001 From: Nathan Date: Tue, 8 Oct 2024 11:08:48 +0100 Subject: [PATCH 12/23] Add basic inspect card click --- public/board.js | 59 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 59 insertions(+) diff --git a/public/board.js b/public/board.js index fa745af..cd1e4ab 100644 --- a/public/board.js +++ b/public/board.js @@ -30,6 +30,8 @@ let cardsInOpponentsHand = 0; const maxHandSize = 4; const maxBoardSize = 3; +let inspectCard = null; + // Gonna need lots of refactoring, and sorting class Board{ @@ -58,6 +60,8 @@ class Board{ this.drawOpponentHand(); this.drawPlayerNames('Nathan', 'Evil Nathan'); + + this.drawInspectedCard(); } drawPlayerNames(playerName, opponentName = false){ @@ -300,6 +304,23 @@ class Board{ this.drawBoard(); } + inspectOpponentBoard(index){ + // Get the card data + inspectCard = [opponentBoard, index]; + + this.drawBoard(); + } + drawInspectedCard(){ + if(inspectCard != null){ + let positionX = canvas.width/2 - cardWidth; + let positionY = canvas.height/2 - cardHeight; + let width = cardWidth*2; + let height = cardHeight*2; + + this.drawCard(inspectCard[0], inspectCard[1], name, positionX, positionY, width, height, '#D1D100'); + console.log('inspect'); + } + } } // TEMP!! @@ -316,12 +337,31 @@ board.playCardToBoardFromDeckOpponent(); board.drawBoard(); canvas.addEventListener('click', function(event) { + console.log('EVENT LISTENER'); + console.log(''); + var x = event.pageX - canvasLeft, y = event.pageY - canvasTop; // Collision detection between clicked offset and clickableItems // https://stackoverflow.com/a/9880302 + if(inspectCard != null){ + console.log(inspectCard); + clickable = inspectCard[0][inspectCard[1]].clickable; + console.log(clickable); + + if(clickableCheck(x,y,clickable)){ + console.log('clicked inspect card'); + + }else{ + console.log('not inspected card'); + // Stop inspecting card if player clicks off it + inspectCard = null; + board.drawBoard(); + } + } + // # PLAYER DECK clickable = clickableItems['deckSprite']; @@ -358,6 +398,25 @@ canvas.addEventListener('click', function(event) { } }); + // # PLAYER BOARD + playerBoard.forEach(function(card, index){ + let clickable = card.clickable; + + if(clickableCheck(x,y,clickable)){ + board.startAttack(index); + board.drawBoard(); + } + }); + + // # OPPONENT BOARD + opponentBoard.forEach(function(card, index){ + let clickable = card.clickable; + + if(clickableCheck(x,y,clickable)){ + board.inspectOpponentBoard(index); + board.drawBoard(); + } + }); }, false); From 233fee3d65191c681e81f4f7a364e9e0c84655a9 Mon Sep 17 00:00:00 2001 From: Nathan Date: Tue, 8 Oct 2024 12:20:42 +0100 Subject: [PATCH 13/23] Add other card info to cardDraw --- public/board.js | 72 ++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 69 insertions(+), 3 deletions(-) diff --git a/public/board.js b/public/board.js index cd1e4ab..60baec3 100644 --- a/public/board.js +++ b/public/board.js @@ -79,6 +79,12 @@ class Board{ // Draw Invidual Cards, called by other deck stuff // Might be put into a card class, makes sense, eh. drawCard(array, arrayKey, name, positionX, positionY, width, height, fill){ + // Card Colour + console.log('drawCard card: '+JSON.stringify(array[arrayKey])); + let colourId = array[arrayKey].colour; + if(colourId == 0){ fill = '#EEE' } + else if(colourId == 1){ fill = '#0033EE' } + var cardClickable = new Shape({ name: name, x: positionX, @@ -91,13 +97,59 @@ class Board{ array[arrayKey]['clickable'] = cardClickable; array[arrayKey]['clickable'].draw(); - // Add card text + // Add image + // half circle for unit Set start angle to 0 and end angle to Math.PI. + // Ellipse for token (near full size) + // Octagon for spell + let cardImageContainer = new Shape({ + shape: 'semi', + name: 'cardImageContainer_'+name, + x: positionX+cardHeight/3, + y: positionY+cardWidth/2, + width: cardWidth*.9, + height: cardHeight*.9, + fillStyle: "#BBB" + }); + cardImageContainer.draw(); + + // Add card name + ctx.font = "bold 10pt Arial"; ctx.fillStyle = '#000'; ctx.fillText( array[arrayKey]['name'] , positionX + (ctx.measureText(array[arrayKey]['name']/2).width) - width/4 - , positionY+20 + , positionY+cardHeight*.25 ); + + // Add card type + ctx.fillText( + array[arrayKey]['type'] + , positionX + (ctx.measureText(array[arrayKey]['type']/2).width) - width/4 + , positionY+cardHeight*.7 + ); + // Add text/effect area + if(array[arrayKey]['effect'] !== null){ + ctx.fillText( + array[arrayKey]['effect'] + , positionX + (ctx.measureText(array[arrayKey]['effect']/2).width) - width/4 + , positionY+cardHeight*.8 + ); + } + // Attack + ctx.fillText( + array[arrayKey]['atk'] + , positionX + (ctx.measureText(array[arrayKey]['atk']).width) + , positionY+cardHeight*.95 + ); + // Add cost + ctx.fillText( + array[arrayKey]['cost'] + , positionX + (ctx.measureText(array[arrayKey]['cost']).width) + , positionY+cardHeight*.1 + ); + + // Unbold font for other draws + ctx.font = "10pt Arial"; } drawDeck(){ @@ -445,7 +497,21 @@ function clickableCheck(x,y,clickable){ // for UI development, will be done on server and not shown to clients function createDeckList(deck, deckCount){ for(let i = 0; i < deckCount; i++){ - deck.push({'name':'CardName '+(i+1), 'cost':1, 'atk':1, 'def':1, 'rarity': 'common', 'effect':null, 'type':'human'}); + // Randomise colour + let colour = Math.floor(Math.random() * 2); + let effect = Math.floor(Math.random() * 5); + if(effect == 0){ effect = 'effect here'; } else{ effect = null } + + deck.push({ + 'name':'CardName '+(i+1) + , 'cost':1 + , 'atk':1 + , 'def':1 + , 'rarity': 'common' + , 'effect':effect + , 'type':'human' + , 'colour':colour + }); } } From dbb38b96b2bc4a488606b68b5930391176ce1cd1 Mon Sep 17 00:00:00 2001 From: Nathan Date: Tue, 8 Oct 2024 13:52:10 +0100 Subject: [PATCH 14/23] Add attack and 'specialEvent' to eventListener Attack is simple, cards can attack cards. specialEvent is to check an attack,inspect, spell target etc isn't happening, this prevent drawing while attacking, etc. --- public/board.js | 78 +++++++++++++++++++++++++++++++++++++++++------- public/shapes.js | 17 +++++++++-- 2 files changed, 82 insertions(+), 13 deletions(-) diff --git a/public/board.js b/public/board.js index 60baec3..e47e4b5 100644 --- a/public/board.js +++ b/public/board.js @@ -31,7 +31,7 @@ const maxHandSize = 4; const maxBoardSize = 3; let inspectCard = null; - +let attackingCard = null; // Gonna need lots of refactoring, and sorting class Board{ @@ -78,9 +78,9 @@ class Board{ // Draw Invidual Cards, called by other deck stuff // Might be put into a card class, makes sense, eh. - drawCard(array, arrayKey, name, positionX, positionY, width, height, fill){ + drawCard(array, arrayKey, name, positionX, positionY, width, height, fill, border){ // Card Colour - console.log('drawCard card: '+JSON.stringify(array[arrayKey])); + //console.log('drawCard card: '+JSON.stringify(array[arrayKey])); let colourId = array[arrayKey].colour; if(colourId == 0){ fill = '#EEE' } else if(colourId == 1){ fill = '#0033EE' } @@ -91,7 +91,8 @@ class Board{ y: positionY, width: width, height: height, - fillStyle: fill + fillStyle: fill, + strokeStyle: border }); array[arrayKey]['clickable'] = cardClickable; @@ -296,8 +297,12 @@ class Board{ let positionY = canvas.height - cardHeight-30-(cardHeight); let width = cardWidth; let height = cardHeight; + let border = false; - this.drawCard(playerBoard, i, name, positionX, positionY, width, height, fill); + if(attackingCard !== null && playerBoard[i].name == attackingCard[0].name){ + border = '#FF0000'; + } + this.drawCard(playerBoard, i, name, positionX, positionY, width, height, fill, border); } } @@ -373,6 +378,37 @@ class Board{ console.log('inspect'); } } + + // Selects the card that will be attacking + // Stop other actions besides selecting opponent/opponent unit + // Can cancel, will do later + startAttack(index){ + // Can probably combine attacking/inspect, and set another array element to 'attacking', 'inspecting', etc. + attackingCard = [playerBoard[index], index]; + this.drawBoard(); + } + // Do the attack + makeAttack(index){ + // If card attacked + // Compare attackingCard and defendingCard + let defendingCard = opponentBoard[index]; + if(defendingCard.atk <= attackingCard[0].atk){ + opponentBoard.splice(index, 1); + // Need to push to grave, etc. here in future too + } + if(attackingCard[0].atk <= defendingCard.atk){ + playerBoard.splice(attackingCard[1], 1); + } + console.log('attacking'); + this.endAttack(); + + // If player attacked + // Compare life/remove life cards 5/10/15,1/2/3? + } + endAttack(){ + attackingCard = null; + this.drawBoard(); + } } // TEMP!! @@ -392,13 +428,21 @@ canvas.addEventListener('click', function(event) { console.log('EVENT LISTENER'); console.log(''); + // specialEvent used to prevent eventTriggers if something specific + // is being done, attack needs to be made, inspecting card. + // Prevents user from doing other actions until completed or cancelled event + let specialEvent = false; + if(inspectCard !== null || attackingCard !== null){ + specialEvent = true; + } + var x = event.pageX - canvasLeft, y = event.pageY - canvasTop; // Collision detection between clicked offset and clickableItems // https://stackoverflow.com/a/9880302 - if(inspectCard != null){ + if(inspectCard !== null){ console.log(inspectCard); clickable = inspectCard[0][inspectCard[1]].clickable; console.log(clickable); @@ -422,14 +466,14 @@ canvas.addEventListener('click', function(event) { // TODO: potentially loop all clickables, and do a check on clickable.name to differ event handling per-item // For now this will be fine, as it functions - if(clickableCheck(x,y,clickable)){ + if(clickableCheck(x,y,clickable) && !specialEvent){ board.drawACard(); } // # OPPONENT DECK clickable = clickableItems['deckOpponentSprite']; - if(clickableCheck(x,y,clickable)){ + if(clickableCheck(x,y,clickable) && !specialEvent){ board.drawACardOpponent(); } @@ -438,7 +482,7 @@ canvas.addEventListener('click', function(event) { let clickable = card.clickable; - if(clickableCheck(x,y,clickable)){ + if(clickableCheck(x,y,clickable) && !specialEvent){ board.playCardToBoard(index); @@ -455,7 +499,12 @@ canvas.addEventListener('click', function(event) { let clickable = card.clickable; if(clickableCheck(x,y,clickable)){ - board.startAttack(index); + if(attackingCard !== null && card == attackingCard[0]){ + board.endAttack(); + } + if(!specialEvent){ + board.startAttack(index); + } board.drawBoard(); } }); @@ -465,7 +514,14 @@ canvas.addEventListener('click', function(event) { let clickable = card.clickable; if(clickableCheck(x,y,clickable)){ - board.inspectOpponentBoard(index); + // Check if card if getting attacked + if(attackingCard !== null){ + board.makeAttack(index); + } + + if(!specialEvent){ + board.inspectOpponentBoard(index); + } board.drawBoard(); } }); diff --git a/public/shapes.js b/public/shapes.js index df42eef..0412f78 100644 --- a/public/shapes.js +++ b/public/shapes.js @@ -15,7 +15,7 @@ class Shape extends Path2D{ this.width = params.width || 0; this.height = params.height || 0; this.fillStyle = params.fillStyle || "#FFFFFF"; - this.strokeStyle = params.strokeStyle || "#000000"; + this.strokeStyle = params.strokeStyle || false; this.lineWidth = params.lineWidth || 0; } draw(){ @@ -32,6 +32,11 @@ class Shape extends Path2D{ context.arc(this.x, this.y, this.width/2, 0, 2 * Math.PI); context.fill(); context.closePath(); + }else if(this.shape == 'semi'){ + context.beginPath(); + context.arc(this.x, this.y, this.width/2, Math.PI, 0); + context.fill(); + context.closePath(); }else if (this.shape == 'rectangle'){ context.fillRect(this.x, this.y, this.width, this.height); } @@ -40,16 +45,24 @@ class Shape extends Path2D{ if (this.strokeStyle && this.lineWidth || shapeDebug) { context.strokeStyle = this.strokeStyle; context.lineWidth = this.lineWidth; - if(shapeDebug){ + if(!this.strokeStyle && shapeDebug){ context.strokeStyle = shapeDebugColour; context.lineWidth = 2; } + if(this.strokeStyle){ + context.lineWidth = 2; + } if(this.shape == 'circle'){ // X,Y,Radius, start, end context.beginPath(); context.arc(this.x, this.y, this.width/2, 0, 2 * Math.PI); context.stroke(); context.closePath(); + }else if(this.shape == 'semi'){ + context.beginPath(); + context.arc(this.x, this.y, this.width/2, Math.PI, 0); + context.stroke(); + context.closePath(); }else if (this.shape == 'rectangle'){ context.strokeRect(this.x, this.y, this.width, this.height); } From b6d92ce85e7a440edea09b7af5a68f85e97f61ce Mon Sep 17 00:00:00 2001 From: Nathan Date: Tue, 8 Oct 2024 14:07:46 +0100 Subject: [PATCH 15/23] Add cardsToDraw loop to cardDraw methods --- public/board.js | 56 +++++++++++++++++++++++++++---------------------- 1 file changed, 31 insertions(+), 25 deletions(-) diff --git a/public/board.js b/public/board.js index e47e4b5..a10e9ec 100644 --- a/public/board.js +++ b/public/board.js @@ -252,34 +252,39 @@ class Board{ drawCards(){} // Draw a card, traditional TCG - drawACard(){ - if(playerHand.length >= maxHandSize){ - alert('Hand full '+playerHand.length+'/'+maxHandSize); - return 0; - } + drawACard(cardsToDraw = 1){ + // For loop so that animations will play each time (when they exist) + for(let draw = 0; draw < cardsToDraw; draw++){ + if(playerHand.length >= maxHandSize){ + alert('Hand full '+playerHand.length+'/'+maxHandSize); + return 0; + } - // Random card from deck, remove from deck, add to hand - let cardToDraw = Math.floor(Math.random() * deckCount); - let cardDrawn = playerDeck[cardToDraw]; - // Remove from deck - playerDeck.splice(cardToDraw, 1); - // Add to hand - playerHand.push(cardDrawn); - this.drawBoard(); + // Random card from deck, remove from deck, add to hand + let cardToDraw = Math.floor(Math.random() * deckCount); + let cardDrawn = playerDeck[cardToDraw]; + // Remove from deck + playerDeck.splice(cardToDraw, 1); + // Add to hand + playerHand.push(cardDrawn); + this.drawBoard(); + } } - drawACardOpponent(){ - if(opponentHand.length >= maxHandSize){ - alert('Hand full '+opponentHand.length+'/'+maxHandSize); - return 0; + drawACardOpponent(cardsToDraw = 1){ + for(let draw = 0; draw < cardsToDraw; draw++){ + if(opponentHand.length >= maxHandSize){ + alert('Hand full '+opponentHand.length+'/'+maxHandSize); + return 0; + } + // Random card from deck, remove from deck, add to hand + let cardToDraw = Math.floor(Math.random() * deckCountOpponent); + let cardDrawn = opponentDeck[cardToDraw]; + // Remove from deck + opponentDeck.splice(cardToDraw, 1); + // Add to hand + opponentHand.push(cardDrawn); + this.drawBoard(); } - // Random card from deck, remove from deck, add to hand - let cardToDraw = Math.floor(Math.random() * deckCountOpponent); - let cardDrawn = opponentDeck[cardToDraw]; - // Remove from deck - opponentDeck.splice(cardToDraw, 1); - // Add to hand - opponentHand.push(cardDrawn); - this.drawBoard(); } @@ -423,6 +428,7 @@ let board = new Board; board.playCardToBoardFromDeckOpponent(); board.drawBoard(); +board.drawACard(3); canvas.addEventListener('click', function(event) { console.log('EVENT LISTENER'); From 8f2a93f58f35cbdd13ae20c8b205328b5fe163b3 Mon Sep 17 00:00:00 2001 From: Nathan Date: Tue, 8 Oct 2024 15:45:08 +0100 Subject: [PATCH 16/23] Add sheild cards --- public/board.js | 120 +++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 108 insertions(+), 12 deletions(-) diff --git a/public/board.js b/public/board.js index a10e9ec..33e770b 100644 --- a/public/board.js +++ b/public/board.js @@ -22,6 +22,8 @@ let playerBoard = []; let opponentBoard = []; let playerDeck = []; let opponentDeck = []; +let playerShield = []; +let opponentShield = []; let deckCount = 60; let deckCountOpponent = 60; @@ -29,6 +31,7 @@ let deckCountOpponent = 60; let cardsInOpponentsHand = 0; const maxHandSize = 4; const maxBoardSize = 3; +const maxShield = 4; let inspectCard = null; let attackingCard = null; @@ -56,6 +59,9 @@ class Board{ this.drawDeck(); this.drawDeckOpponent(); + this.drawShield(); + this.drawShieldOpponent(); + this.drawHand(); this.drawOpponentHand(); @@ -66,13 +72,13 @@ class Board{ drawPlayerNames(playerName, opponentName = false){ // Player Name - ctx.fillText(playerName, 50, canvas.height - 110); + ctx.fillText(playerName, 50, canvas.height - 50); // Opponent's Name if(!opponentName){ // Just clear the name }else{ - ctx.fillText(opponentName, canvas.width - (ctx.measureText(opponentName).width + 50), 110); + ctx.fillText(opponentName, canvas.width - (ctx.measureText(opponentName).width + 50), 50); } } @@ -105,48 +111,49 @@ class Board{ let cardImageContainer = new Shape({ shape: 'semi', name: 'cardImageContainer_'+name, - x: positionX+cardHeight/3, - y: positionY+cardWidth/2, - width: cardWidth*.9, - height: cardHeight*.9, + x: positionX+height/3, + y: positionY+width/2, + width: width*.9, + height: height*.9, fillStyle: "#BBB" }); cardImageContainer.draw(); // Add card name - ctx.font = "bold 10pt Arial"; + let fontSize = width/cardWidth*10; // 10 = baseFontSize of 10pt + ctx.font = "bold "+fontSize+"pt Arial"; ctx.fillStyle = '#000'; ctx.fillText( array[arrayKey]['name'] , positionX + (ctx.measureText(array[arrayKey]['name']/2).width) - width/4 - , positionY+cardHeight*.25 + , positionY+height*.25 ); // Add card type ctx.fillText( array[arrayKey]['type'] , positionX + (ctx.measureText(array[arrayKey]['type']/2).width) - width/4 - , positionY+cardHeight*.7 + , positionY+height*.7 ); // Add text/effect area if(array[arrayKey]['effect'] !== null){ ctx.fillText( array[arrayKey]['effect'] , positionX + (ctx.measureText(array[arrayKey]['effect']/2).width) - width/4 - , positionY+cardHeight*.8 + , positionY+height*.8 ); } // Attack ctx.fillText( array[arrayKey]['atk'] , positionX + (ctx.measureText(array[arrayKey]['atk']).width) - , positionY+cardHeight*.95 + , positionY+height*.95 ); // Add cost ctx.fillText( array[arrayKey]['cost'] , positionX + (ctx.measureText(array[arrayKey]['cost']).width) - , positionY+cardHeight*.1 + , positionY+height*.1 ); // Unbold font for other draws @@ -414,6 +421,91 @@ class Board{ attackingCard = null; this.drawBoard(); } + + // Like everything else, need to consolidate into one function that + // can work for both players, and even more for 2v2 3v1 combats, etc. + playShield(shieldsToPlay = 4){ + for(let shieldNo = 0; shieldNo < shieldsToPlay; shieldNo++){ + if(playerShield.length >= maxShield){ + alert('Shield zone full '+playerShield.length+'/'+maxShield); + return 0; + } + + // Random card from deck, remove from deck, add to hand + let cardToDraw = Math.floor(Math.random() * deckCount); + let cardDrawn = playerDeck[cardToDraw]; + // Remove from deck + playerDeck.splice(cardToDraw, 1); + // Add to shield zone + playerShield.push(cardDrawn); + this.drawBoard(); + } + } + playShieldOpponent(shieldsToPlay = 4){ + for(let shieldNo = 0; shieldNo < shieldsToPlay; shieldNo++){ + if(opponentShield.length >= maxShield){ + alert('Shield zone full '+opponentShield.length+'/'+maxShield); + return 0; + } + + // Random card from deck, remove from deck, add to hand + let cardToDraw = Math.floor(Math.random() * deckCount); + let cardDrawn = opponentDeck[cardToDraw]; + // Remove from deck + opponentDeck.splice(cardToDraw, 1); + // Add to shield zone + opponentShield.push(cardDrawn); + this.drawBoard(); + } + } + drawShield(){ + for (let i = 0; i < playerShield.length; i++) { + + let name = 'playerShield_'+(i+1); + + let shieldMargin = 10; + let fromX = 60; + let fromY = 300; + let fill = '#'+i+i+'0000'; + let cWidth = cardWidth*.8; + let cHeight = cardHeight*.8; + let split = 0; + if(i>=2){ split = 1; } + + // i%2 0 = 0, 1 = 1, 2 = 0, 3 = 1 to prevent margin from X/Y axis, and just between cards + let positionX = (fromX+((i%2)*shieldMargin)) +(i%2*cWidth); + let positionY = canvas.height-fromY+(split*cHeight+(shieldMargin*split)); + let width = cWidth; + let height = cHeight; + console.log('i: '+i+' X: '+positionX+' Y: '+positionY); + + this.drawCard(playerShield, i, name, positionX, positionY, width, height, fill); + } + } + drawShieldOpponent(){ + for (let i = 0; i < opponentShield.length; i++) { + + let name = 'opponentShield_'+(i+1); + + let shieldMargin = 10; + let fromX = canvas.width-60; + let fromY = 300; + let fill = '#'+i+i+'0000'; + let cWidth = cardWidth*.8; + let cHeight = cardHeight*.8; + let split = 0; + if(i>=2){ split = 1; } + + // i%2 0 = 0, 1 = 1, 2 = 0, 3 = 1 to prevent margin from X/Y axis, and just between cards + let positionX = (fromX+((i%2)*shieldMargin))+(i%2*cWidth)-(cWidth*2); + let positionY = fromY+(split*cHeight+(shieldMargin*split))-(cHeight*2 + shieldMargin); + let width = cWidth; + let height = cHeight; + console.log('i: '+i+' X: '+positionX+' Y: '+positionY); + + this.drawCard(opponentShield, i, name, positionX, positionY, width, height, fill); + } + } } // TEMP!! @@ -428,6 +520,10 @@ let board = new Board; board.playCardToBoardFromDeckOpponent(); board.drawBoard(); + +board.playShield(4); +board.playShieldOpponent(4); + board.drawACard(3); canvas.addEventListener('click', function(event) { From bb7c87f1310ce6bf934dc9408206ee3fee5a7916 Mon Sep 17 00:00:00 2001 From: Nathan Date: Tue, 8 Oct 2024 16:07:15 +0100 Subject: [PATCH 17/23] Add attackShield functionality, and win screen --- public/board.js | 47 +++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 43 insertions(+), 4 deletions(-) diff --git a/public/board.js b/public/board.js index 33e770b..f18bc21 100644 --- a/public/board.js +++ b/public/board.js @@ -35,6 +35,7 @@ const maxShield = 4; let inspectCard = null; let attackingCard = null; +let gameWin = 0; // Gonna need lots of refactoring, and sorting class Board{ @@ -67,9 +68,31 @@ class Board{ this.drawPlayerNames('Nathan', 'Evil Nathan'); + if(gameWin){ + this.drawWin(); + } + this.drawInspectedCard(); } + drawWin(){ + var winBoard = new Shape({ + name: name, + x: 0, + y: canvas.height/2 - (canvas.height/4)/2, + width: canvas.width, + height: canvas.height/4, + fillStyle: '#CCC', + strokeStyle: '#00EEAA' + }); + winBoard.draw(); + + ctx.fillStyle = '#000'; + ctx.font = "bold 50pt Arial"; + ctx.fillText('WINNER', 200, 300); + ctx.font = "10pt Arial"; + } + drawPlayerNames(playerName, opponentName = false){ // Player Name ctx.fillText(playerName, 50, canvas.height - 50); @@ -400,12 +423,13 @@ class Board{ this.drawBoard(); } // Do the attack - makeAttack(index){ + makeAttack(index, array = null){ + if(array == null){ array = opponentBoard; } // If card attacked // Compare attackingCard and defendingCard - let defendingCard = opponentBoard[index]; + let defendingCard = array[index]; if(defendingCard.atk <= attackingCard[0].atk){ - opponentBoard.splice(index, 1); + array.splice(index, 1); // Need to push to grave, etc. here in future too } if(attackingCard[0].atk <= defendingCard.atk){ @@ -419,6 +443,9 @@ class Board{ } endAttack(){ attackingCard = null; + if(opponentShield.length <= 0){ + gameWin = 1; + } this.drawBoard(); } @@ -534,7 +561,7 @@ canvas.addEventListener('click', function(event) { // is being done, attack needs to be made, inspecting card. // Prevents user from doing other actions until completed or cancelled event let specialEvent = false; - if(inspectCard !== null || attackingCard !== null){ + if(inspectCard !== null || attackingCard !== null || gameWin){ specialEvent = true; } @@ -627,6 +654,18 @@ canvas.addEventListener('click', function(event) { board.drawBoard(); } }); + // # OPPONENT SHIELD + opponentShield.forEach(function(card, index){ + let clickable = card.clickable; + + if(clickableCheck(x,y,clickable)){ + // Check if card if getting attacked + if(attackingCard !== null){ + board.makeAttack(index, opponentShield); + } + board.drawBoard(); + } + }); }, false); From c273b66bc3c929e4eaede3a2182139449af4a033 Mon Sep 17 00:00:00 2001 From: Nathan Date: Tue, 8 Oct 2024 16:25:57 +0100 Subject: [PATCH 18/23] Add opponentdrawCard from shield on destroy --- public/board.js | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/public/board.js b/public/board.js index f18bc21..4d69c74 100644 --- a/public/board.js +++ b/public/board.js @@ -423,11 +423,24 @@ class Board{ this.drawBoard(); } // Do the attack - makeAttack(index, array = null){ - if(array == null){ array = opponentBoard; } + makeAttack(index, array = null, name = null){ + if(array == null){ array = opponentBoard; name = 'opponentBoard' } + console.log(name); // If card attacked // Compare attackingCard and defendingCard + let defendingCard = array[index]; + + // If hitting shield, don't calc combat damage + if(name == 'opponentShield'){ + // This should tap the card first, then after all shields + // are tapped, THEN attacking destroys them + array.splice(index, 1); + opponentHand.push(array[index]); + this.endAttack(); + return 1; + } + if(defendingCard.atk <= attackingCard[0].atk){ array.splice(index, 1); // Need to push to grave, etc. here in future too @@ -661,7 +674,7 @@ canvas.addEventListener('click', function(event) { if(clickableCheck(x,y,clickable)){ // Check if card if getting attacked if(attackingCard !== null){ - board.makeAttack(index, opponentShield); + board.makeAttack(index, opponentShield, 'opponentShield'); } board.drawBoard(); } From bc70a3d0d861576fc76b16fd838a26f4569aa470 Mon Sep 17 00:00:00 2001 From: Nathan Date: Tue, 8 Oct 2024 21:51:15 +0100 Subject: [PATCH 19/23] Add mana and basic mana tap/summon cons --- public/board.js | 88 +++++++++++++++++++++++++++++++++++++++++++++--- public/shapes.js | 6 ++-- 2 files changed, 85 insertions(+), 9 deletions(-) diff --git a/public/board.js b/public/board.js index 4d69c74..a5d1999 100644 --- a/public/board.js +++ b/public/board.js @@ -24,6 +24,8 @@ let playerDeck = []; let opponentDeck = []; let playerShield = []; let opponentShield = []; +let playerMana = []; +let opponentManaZone = []; let deckCount = 60; let deckCountOpponent = 60; @@ -66,6 +68,8 @@ class Board{ this.drawHand(); this.drawOpponentHand(); + this.drawMana(); + this.drawPlayerNames('Nathan', 'Evil Nathan'); if(gameWin){ @@ -114,6 +118,18 @@ class Board{ if(colourId == 0){ fill = '#EEE' } else if(colourId == 1){ fill = '#0033EE' } + if(name == 'playerMana_1'){ + console.log(playerMana); + console.log(array); + console.log(array[arrayKey]); + console.log(array[arrayKey].tapped); + console.log(name); + } + if(array[arrayKey].tapped){ + border = '#E0BC00'; + console.log('drawCard tapped'); + } + var cardClickable = new Shape({ name: name, x: positionX, @@ -371,6 +387,25 @@ class Board{ return 0; } + if(cardPlayed.cost > playerMana.length){ + alert('Not enough mana'); + return 0; + }else{ + let canPlay = false; + playerMana.forEach(function(manaCard, key){ + if(cardPlayed.colour == manaCard.colour && manaCard.tapped == false){ + canPlay = true; + playerMana[key].tapped = true; + } + }); + + if(!canPlay){ + alert('Mana conditions not met'); + return 0; + } + } + console.log(playerMana); + // Remove from hand playerHand.splice(index, 1); // Add to board @@ -447,6 +482,8 @@ class Board{ } if(attackingCard[0].atk <= defendingCard.atk){ playerBoard.splice(attackingCard[1], 1); + }else{ + playerBoard[attackingCard[1]].tapped = true; } console.log('attacking'); this.endAttack(); @@ -517,7 +554,6 @@ class Board{ let positionY = canvas.height-fromY+(split*cHeight+(shieldMargin*split)); let width = cWidth; let height = cHeight; - console.log('i: '+i+' X: '+positionX+' Y: '+positionY); this.drawCard(playerShield, i, name, positionX, positionY, width, height, fill); } @@ -541,11 +577,50 @@ class Board{ let positionY = fromY+(split*cHeight+(shieldMargin*split))-(cHeight*2 + shieldMargin); let width = cWidth; let height = cHeight; - console.log('i: '+i+' X: '+positionX+' Y: '+positionY); + //console.log('i: '+i+' X: '+positionX+' Y: '+positionY); this.drawCard(opponentShield, i, name, positionX, positionY, width, height, fill); } } + + playMana(index, fromDeck = 0){ + let manaCard = null; + if(fromDeck){ + let cardToDraw = Math.floor(Math.random() * deckCount); + manaCard = playerDeck[cardToDraw]; + // Remove from deck + playerDeck.splice(cardToDraw, 1); + }else{ + manaCard = playerHand[index]; + playerHand.splice(index, 1); + } + + playerMana.push(manaCard); + + this.drawBoard(); + } + drawMana(){ + for (let i = 0; i < playerMana.length; i++) { + + let name = 'playerMana_'+(i+1); + + let manaMargin = 10; + let fromX = 60; + let fromY = 60; + let fill = '#BBB'; + let cWidth = cardWidth*.5; + let cHeight = cardHeight*.5; + let split = 0; + + // i%2 0 = 0, 1 = 1, 2 = 0, 3 = 1 to prevent margin from X/Y axis, and just between cards + let positionX = (fromX+manaMargin)+(i*cWidth-manaMargin); + let positionY = canvas.height-fromY; + let width = cWidth; + let height = cHeight; + + this.drawCard(playerMana, i, name, positionX, positionY, width, height, fill); + } + } } // TEMP!! @@ -585,9 +660,7 @@ canvas.addEventListener('click', function(event) { // https://stackoverflow.com/a/9880302 if(inspectCard !== null){ - console.log(inspectCard); clickable = inspectCard[0][inspectCard[1]].clickable; - console.log(clickable); if(clickableCheck(x,y,clickable)){ console.log('clicked inspect card'); @@ -626,7 +699,11 @@ canvas.addEventListener('click', function(event) { if(clickableCheck(x,y,clickable) && !specialEvent){ - board.playCardToBoard(index); + if(confirm("Play as unit or mana. OK = unit, cancel = mana. No actual cancel...")){ + board.playCardToBoard(index); + }else{ + board.playMana(index); + } // This would actually fire off a socketIO doodad, that would then return // data, and redraw. But for now (UI test) @@ -721,6 +798,7 @@ function createDeckList(deck, deckCount){ , 'effect':effect , 'type':'human' , 'colour':colour + , 'tapped':false }); } } diff --git a/public/shapes.js b/public/shapes.js index 0412f78..d8db346 100644 --- a/public/shapes.js +++ b/public/shapes.js @@ -45,12 +45,10 @@ class Shape extends Path2D{ if (this.strokeStyle && this.lineWidth || shapeDebug) { context.strokeStyle = this.strokeStyle; context.lineWidth = this.lineWidth; + context.lineWidth = 2; + if(!this.strokeStyle && shapeDebug){ context.strokeStyle = shapeDebugColour; - context.lineWidth = 2; - } - if(this.strokeStyle){ - context.lineWidth = 2; } if(this.shape == 'circle'){ // X,Y,Radius, start, end From 562535234a09b0ac819a67c3bd47449db0f09fa0 Mon Sep 17 00:00:00 2001 From: Nathan Date: Thu, 10 Oct 2024 12:37:05 +0100 Subject: [PATCH 20/23] Add extremely basic untap --- public/board.js | 11 +++++++++++ public/index.html | 1 + 2 files changed, 12 insertions(+) diff --git a/public/board.js b/public/board.js index a5d1999..209166d 100644 --- a/public/board.js +++ b/public/board.js @@ -803,3 +803,14 @@ function createDeckList(deck, deckCount){ } } +function untap(array){ + console.log(array); + array.forEach(function(card, key){ + array[key].tapped = false; + }); + board.drawBoard(); +} +function untapAll(){ + untap(playerMana); +} + diff --git a/public/index.html b/public/index.html index 0cd06c6..3a95905 100644 --- a/public/index.html +++ b/public/index.html @@ -16,6 +16,7 @@ + From 5b5b0bde86421eac3319b0bf58a3e220e56930b4 Mon Sep 17 00:00:00 2001 From: Nathan Date: Thu, 10 Oct 2024 15:40:24 +0100 Subject: [PATCH 21/23] Add card and shield tapping --- public/board.js | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/public/board.js b/public/board.js index 209166d..7aadc16 100644 --- a/public/board.js +++ b/public/board.js @@ -470,8 +470,18 @@ class Board{ if(name == 'opponentShield'){ // This should tap the card first, then after all shields // are tapped, THEN attacking destroys them - array.splice(index, 1); - opponentHand.push(array[index]); + if(array[index].tapped){ + // Untap + array[index].tapped = false; + // Add to hand + opponentHand.push(array[index]); + // Remove from shield zone + array.splice(index, 1); + }else{ + array[index].tapped = true; + } + + playerBoard[attackingCard[1]].tapped = true; this.endAttack(); return 1; } @@ -721,7 +731,7 @@ canvas.addEventListener('click', function(event) { if(attackingCard !== null && card == attackingCard[0]){ board.endAttack(); } - if(!specialEvent){ + if(!specialEvent && card.tapped != true){ board.startAttack(index); } board.drawBoard(); @@ -812,5 +822,7 @@ function untap(array){ } function untapAll(){ untap(playerMana); + untap(playerBoard); + untap(opponentShield); } From 9de71b7676e7a994e568d2281a4df38b48fc18b0 Mon Sep 17 00:00:00 2001 From: Nathan Date: Thu, 10 Oct 2024 15:52:09 +0100 Subject: [PATCH 22/23] Fix multiple mana tap when play card --- public/board.js | 27 +++++++++++++++++---------- 1 file changed, 17 insertions(+), 10 deletions(-) diff --git a/public/board.js b/public/board.js index 7aadc16..453705a 100644 --- a/public/board.js +++ b/public/board.js @@ -118,13 +118,6 @@ class Board{ if(colourId == 0){ fill = '#EEE' } else if(colourId == 1){ fill = '#0033EE' } - if(name == 'playerMana_1'){ - console.log(playerMana); - console.log(array); - console.log(array[arrayKey]); - console.log(array[arrayKey].tapped); - console.log(name); - } if(array[arrayKey].tapped){ border = '#E0BC00'; console.log('drawCard tapped'); @@ -378,7 +371,8 @@ class Board{ // Currently only functionality in hand playCardToBoard(index){ // Get the card data - let cardPlayed = playerHand[index]; + let cardPlayed = playerHand[index]; + let manaUsed = []; // Check if there's space on board to play // TODO: Check this in back-end @@ -392,10 +386,17 @@ class Board{ return 0; }else{ let canPlay = false; + let needsMana = 1; + let usedMana = 0; playerMana.forEach(function(manaCard, key){ - if(cardPlayed.colour == manaCard.colour && manaCard.tapped == false){ + if(cardPlayed.colour == manaCard.colour && manaCard.tapped == false && needsMana > usedMana){ + console.log(manaCard); + // Needs changing for multiple colour usage + // 2 red, 1 red + 1 blue, etc. + // Currently only gets one mana of the cards colour + manaUsed.push(key); + usedMana++; canPlay = true; - playerMana[key].tapped = true; } }); @@ -404,6 +405,12 @@ class Board{ return 0; } } + + // Tap mana to be used + manaUsed.forEach(function(cardKey, key){ + playerMana[cardKey].tapped = true; + }); + console.log(playerMana); // Remove from hand From 68faeb37277c5118661b7c997ece9e3aec654e45 Mon Sep 17 00:00:00 2001 From: Nathan Date: Thu, 10 Oct 2024 16:06:59 +0100 Subject: [PATCH 23/23] Add rightclick/contextmenu event handler --- public/board.js | 34 ++++++++++++++++++++++++++++------ 1 file changed, 28 insertions(+), 6 deletions(-) diff --git a/public/board.js b/public/board.js index 453705a..dc20c75 100644 --- a/public/board.js +++ b/public/board.js @@ -401,7 +401,7 @@ class Board{ }); if(!canPlay){ - alert('Mana conditions not met'); + alert('Mana conditions not met, right click hand unit to play as mana'); return 0; } } @@ -658,6 +658,32 @@ board.playShieldOpponent(4); board.drawACard(3); +canvas.addEventListener('contextmenu', function(event) { + event.preventDefault(); + + let specialEvent = false; + if(inspectCard !== null || attackingCard !== null || gameWin){ + specialEvent = true; + } + + var x = event.pageX - canvasLeft, + y = event.pageY - canvasTop; + + // # PLAYER HAND + playerHand.forEach(function(card, index){ + + let clickable = card.clickable; + + if(clickableCheck(x,y,clickable) && !specialEvent){ + board.playMana(index); + board.drawBoard(); + } + }); + // Return false to prevent context opening: https://stackoverflow.com/a/4236294 + return false; + +}, false); + canvas.addEventListener('click', function(event) { console.log('EVENT LISTENER'); console.log(''); @@ -716,11 +742,7 @@ canvas.addEventListener('click', function(event) { if(clickableCheck(x,y,clickable) && !specialEvent){ - if(confirm("Play as unit or mana. OK = unit, cancel = mana. No actual cancel...")){ - board.playCardToBoard(index); - }else{ - board.playMana(index); - } + board.playCardToBoard(index); // This would actually fire off a socketIO doodad, that would then return // data, and redraw. But for now (UI test)