diff --git a/public/board.js b/public/board.js index 8a237f9..a1383b6 100644 --- a/public/board.js +++ b/public/board.js @@ -5,8 +5,8 @@ const canvasTop = canvas.offsetTop + canvas.clientTop; const cardWidth = 80; const cardHeight = 120; -const cards = new Image(); -const back = new Image(); +const cardArt = new Image(); +const cardBackArt = new Image(); // Counters to keep track of players, and boardElements, may be changed in future // But once game starts, will be const anyway, so shouldn't need passing @@ -26,6 +26,8 @@ let size = {}; let cardStatus = {}; // tapped, attacking, inspected, untargettable (TODO:maybe used this instead of inEvent later) let player = {}; let listPosition = {}; +let cardFace = {}; +let cardSprite = {}; let inEvent = null; // To disable drawing each time something changes @@ -43,8 +45,8 @@ class Board{ console.log('initBoard'); ctx.font = "12px Arial"; canvas.style.backgroundColor = 'rgb(143 153 150)'; - cards.src = 'images/deck.svg'; - back.src = 'images/uno.svg'; + cardArt.src = 'images/cardArt.jpg'; + cardBackArt.src = 'images/cardBack.jpg'; ctx.fillStyle = '#000'; } @@ -164,10 +166,16 @@ class Board{ }); shape.draw(); - if(boardElement[itemKey] != 'realDeck'){ // TODO: isset, or differ between types - this.printCardImage(itemKey); + // Draw the card face-up + if(this.isFaceUp(itemKey)){ + this.addCardImage(itemKey); this.printCardDetails(itemKey); - }else{ + } + if(!this.isFaceUp(itemKey)){ + this.addCardBack(itemKey); + } + // If it's the deck, draw the circle surrounding it + if(boardElement[itemKey] == 'realDeck'){ // TODO: For realDeck only atm, also janked in. Seperate this... let counterx= positionX; let countery= positionY; @@ -194,33 +202,75 @@ class Board{ ctx.fillStyle = '#000'; ctx.fillText(deckLength, textx, texty); } - - + } + isFaceUp(itemKey){ + if(cardFace[itemKey] == 1){ + return true; + } + return false; + } + flipCard(itemKey){ + if(cardFace[itemKey] == 1){ + cardFace[itemKey] = 0; + }else{ + cardFace[itemKey] = 1; + } + // TODO:Activate any flip effects, etc. } printCardImage(itemKey){ - let name = itemKey; // Not needed really anymore, but keeping for now let positionX = position[itemKey][0]; let positionY = position[itemKey][1]; let width = size[itemKey][0]; let height = size[itemKey][1]; - let fill = '#BBB'; - let shape = 'semi'; // Will be decided based on cardData.something? (for unit, spell, etc) + // Draw the image into the clipping mask + // image, dx,dy,dw,dh + // image, sx,sy, sw,sh,dx,dy,dw,dh + let spriteSheetX = 80*cardSprite[itemKey][0]; + let spriteSheetY = 120*cardSprite[itemKey][1]; + ctx.drawImage(cardArt, spriteSheetX,spriteSheetY, 80,120,positionX,positionY,width,height); + } + addCardImage(itemKey){ + + let positionX = position[itemKey][0]; + let positionY = position[itemKey][1]; + let width = size[itemKey][0]; + let height = size[itemKey][1]; - // Add 'image' shape, will need to blitz sprite here in the future (based on cardData.id) + // Create the clipping shape let cardImageContainer = new Shape({ - shape: 'semi', + shape: 'unit', name: 'cardImageContainer_'+name, x: positionX+height/3, y: positionY+width/2, width: width*.9, - height: height*.9, - fillStyle: fill + height: height*.9 }); - cardImageContainer.draw(); + // Save canvas drawing, start the clip + cardImageContainer.startClip(); + + // Print the image to canvas, within the clipping mask + this.printCardImage(itemKey); - // Draw the actual image too + // Restore the canvas draw post clip applied, to get everything else back too + cardImageContainer.endClip(); + } + addCardBack(itemKey){ + let positionX = position[itemKey][0]; + let positionY = position[itemKey][1]; + let width = size[itemKey][0]; + let height = size[itemKey][1]; + // Print the sleeve image to cardPosition + this.printCardBack(itemKey); + } + printCardBack(itemKey){ + let positionX = position[itemKey][0]; + let positionY = position[itemKey][1]; + let width = size[itemKey][0]; + let height = size[itemKey][1]; + // TODO: CardBack/Sleeves as spritesheet like cardArt + ctx.drawImage(cardBackArt, 0,0, 80,120,positionX,positionY,width,height); } printCardDetails(itemKey){ let name = itemKey; // Not needed really anymore, but keeping for now @@ -425,8 +475,10 @@ class Board{ alert('Hand full '+elementLength+'/'+maxHandSize); return false; } + let card = this.getItemKey('deck', 1, playerId); // Move from players deck to hand, from position 1 (bottom deck) this.addFromBoardElement(playerId, 1, 'deck', 'hand', null, null); + this.flipCard(card); } } @@ -759,7 +811,11 @@ for(let currentPlayer = 0; currentPlayer <= players-1; currentPlayer++){ } // Draw the graphics of the board/game -board.drawBoard(true); +// Wait for the cardArt to load on first load +// Otherwise it'll be boxes, and art will flash in on first click event triggered +cardArt.onload = function(){ + board.drawBoard(true); +}; // Right Click, Rightclick, rightclick, right click @@ -961,6 +1017,7 @@ function createDecks(){ // In future want to remove, and add isset checks for non-used data cardStatus[itemCount] = null; listPosition[itemCount] = null; + cardFace[itemCount] = 0; // Deck is facedown, as there's no cardArt itemCount++; } @@ -994,6 +1051,26 @@ function createDeckList(playerId){ player[itemCount] = playerId; // Set the position in the deck (as was added), will be shuffled on game start listPosition[itemCount] = deckItem+1; + cardFace[itemCount] = 0; // Start with all cards face down + cardSprite[itemCount] = [0,0]; + // Temp sprite set based on colour TODO: Change to set correct sprite from DB + console.log(cardData[itemCount].colour); + switch (cardData[itemCount].colour){ + case 0: // White + cardSprite[itemCount] = [0,0]; + break; + case 1: // Blue + cardSprite[itemCount] = [0,1]; + break; + case 2: // Red + cardSprite[itemCount] = [1,0]; + break; + case 3: // Green + cardSprite[itemCount] = [1,1]; + break; + default: + break; + } // Increment the itemCount to prevent overwriting stuff itemCount++; @@ -1220,13 +1297,15 @@ function printECSData(items){ for(let item = 0; item < items.length; item++){ let itemKey = items[item]; console.log( + 'itemId: '+itemKey+"\n"+ 'boardElement: '+boardElement[itemKey]+"\n"+ 'cardData: '+cardData[itemKey]+"\n"+ 'position: '+position[itemKey]+"\n"+ 'size: '+size[itemKey]+"\n"+ 'cardStatus: '+cardStatus[itemKey]+"\n"+ 'player: '+player[itemKey]+"\n"+ - 'listPosition: '+listPosition[itemKey] + 'listPosition: '+listPosition[itemKey]+"\n"+ + 'cardFace: '+cardFace[itemKey] ); } } diff --git a/public/images/cardArt.jpg b/public/images/cardArt.jpg new file mode 100644 index 0000000..490d648 Binary files /dev/null and b/public/images/cardArt.jpg differ diff --git a/public/images/cardBack.jpg b/public/images/cardBack.jpg new file mode 100644 index 0000000..307fbe7 Binary files /dev/null and b/public/images/cardBack.jpg differ diff --git a/public/shapes.js b/public/shapes.js index d8db346..8313964 100644 --- a/public/shapes.js +++ b/public/shapes.js @@ -64,8 +64,67 @@ class Shape extends Path2D{ }else if (this.shape == 'rectangle'){ context.strokeRect(this.x, this.y, this.width, this.height); } + else if (this.shape == 'unit'){ + context.beginPath(); + context.arc(this.x, this.y, this.width/2, Math.PI, 0); + + // Start at bottom left of the semi + context.moveTo(this.x-this.width/2, this.y); + // Draw accross to bottom right of semi + context.lineTo(this.x+this.width/2, this.y); + // Draw down to the desired height + context.lineTo(this.x+this.width/2, this.y+this.height/3); + // Draw accross to that height, but aligned to left of semi + context.lineTo(this.x-this.width/2, this.y+this.height/3); + + context.stroke(); + context.closePath(); + } context.strokeStyle = defaultFillStyle; } } + startClip(shape = null){ + // https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/clip#creating_a_complex_clipping_region + 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 == '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); + } + // This is one of the shapes for the card images to sit it + // TODO: Will be: unit,token,spell, etc. ALSO will have each shape for UI elements too + else if (this.shape == 'unit'){ + + context.beginPath(); + context.arc(this.x, this.y, this.width/2, Math.PI, 0); + + // Start at bottom left of the semi + context.moveTo(this.x-this.width/2, this.y); + // Draw accross to bottom right of semi + context.lineTo(this.x+this.width/2, this.y); + // Draw down to the desired height + context.lineTo(this.x+this.width/2, this.y+this.height/3); + // Draw accross to that height, but aligned to left of semi + context.lineTo(this.x-this.width/2, this.y+this.height/3); + + context.fill(); + context.closePath(); + + } + + ctx.save(); // Save the canvas draw before the clip is applied + context.clip(); + } + endClip(){ + ctx.restore(); // Restore the canvas draw post clip applied, to get everything else back too + } }