import { Ball } from "./Ball.js"; import { Slot } from "./Slot.js"; import { Point } from "../libraries/spatial/Point.js"; import { Rectangle } from "../libraries/spatial/Rectangle.js"; export class Board { constructor() { this.slots = []; this.balls = []; /* Design and color pallet by @kateradeg */ this.heldBall = null; this.removedFromSlot = null; this.game = null; this.levelData = ""; this.canvasBounds = null; } init(game) { this.game = game; this.reset(); } reset() { this.loadLevel(); // this.generateRandomLevel(); } generateRandomLevel() { this.balls = []; this.slots = []; let slotCount = 2; let level = this.game.playerData.current; switch(level) { case 1: case 2: slotCount = 2; break; case 3: case 4: case 5: case 6: slotCount = 4; break; case 7: case 8: case 9: case 10: case 11: slotCount = 6; break; case 12: case 13: case 14: case 15: case 16: slotCount = 8; break; case 17: case 18: case 19: case 20: case 21: case 22: slotCount = 10; break; default: slotCount = 12; break; } for(let i = 0; i < slotCount; i++){ for(let j = 0; j < 4; j++) { this.balls.push(new Ball(i)); } } this.balls = this.shuffle(this.balls); for(let i = 0; i < slotCount; i++){ let slot = new Slot(i); for(let j = 0; j < 4; j++) { slot.addBall(this.balls[4*i+j]); } this.slots.push(slot); } this.slots.push(new Slot(slotCount)); //two empties this.slots.push(new Slot(slotCount+1)); //this.levelData += "\t" + JSON.stringify({slots: this.slots.length, balls:this.balls.map(b => b.colorId)}) +",\n"; } shuffle(a) { var j, x, i; for (i = a.length - 1; i > 0; i--) { j = Math.floor(Math.random() * (i + 1)); x = a[i]; a[i] = a[j]; a[j] = x; } return a; } loadLevel() { this.balls = []; this.slots = []; let level = this.game.playerData.current; let levelData = this.game.getLevel(level); if(!levelData) { this.generateRandomLevel(); return; } this.balls = levelData.balls.map(colorId => new Ball(colorId)); for(let i = 0; i < levelData.slots-2; i++){ let slot = new Slot(i); for(let j = 0; j < 4; j++) { slot.addBall(this.balls[4*i+j]); } this.slots.push(slot); } this.slots.push(new Slot(levelData.slots-2)); this.slots.push(new Slot(levelData.slots-1)); } draw(ctx, scaledCanvas) { this.canvasBounds = scaledCanvas.bounds; ctx.strokeStyle = "rgba(255,255,255,0.5)"; ctx.fillStyle = "rgba(255,255,255,0.3)"; ctx.lineWidth = 3; for(let i = 0; i < this.slots.length; i++) { let slotBounds = this.getSlotBounds(this.slots[i]); ctx.save(); ctx.translate(slotBounds.x, slotBounds.y); this.slots[i].draw(ctx, scaledCanvas); ctx.restore(); } if(this.heldBall) { let bounds = this.getSlotBounds(this.removedFromSlot); ctx.save(); let radiusPadding = Ball.radius + Ball.radiusPadding; ctx.translate(bounds.x + Slot.width / 2, bounds.y - radiusPadding); this.heldBall.draw(ctx, scaledCanvas); ctx.restore(); } } update(delta) { } mouseDown(event) { let mousePoint = new Point(event.clientX, event.clientY); for(let i = 0; i < this.slots.length; i++) { let slot = this.slots[i]; if(this.getSlotBounds(slot).pointWithin(mousePoint)) { if(!this.heldBall) { this.heldBall = slot.removeBall(); this.removedFromSlot = slot; } else { if(slot.canAddBall(this.heldBall) || slot == this.removedFromSlot) { this.game.trackMove(this.removedFromSlot, slot); this.placeHeldBallInSlot(slot); this.checkForWin(); } } } } } mouseMove(event) { let mousePoint = new Point(event.clientX, event.clientY); for(let i = 0; i < this.slots.length; i++) { let slot = this.slots[i]; if(this.getSlotBounds(slot).pointWithin(mousePoint)) { document.body.style.cursor = "pointer"; } } } placeHeldBallInSlot(slot) { slot.addBall(this.heldBall); this.heldBall = null; this.removedFromSlot = null; } getSlotBounds(slot) { let widthPadding = Slot.width + Slot.widthPadding; let heightPadding = Slot.height + Slot.heightPadding; let radiusPadding = Ball.radius + Ball.radiusPadding; let maxSlotsPerRow = Math.floor((this.canvasBounds.width - 40) / widthPadding); let slotsInFirstRow = Math.min(this.slots.length, maxSlotsPerRow); if(slotsInFirstRow < this.slots.length) { slotsInFirstRow = this.slots.length / 2; } let slotsTotalWidth = slotsInFirstRow * widthPadding; let offsetX = (this.canvasBounds.width - slotsTotalWidth - 40 + widthPadding) / 2 return new Rectangle( offsetX + (slot.id % slotsInFirstRow) * widthPadding, Math.floor(slot.id / slotsInFirstRow) * heightPadding + Math.max((2 * radiusPadding), this.canvasBounds.height < 660 ? 10 : this.canvasBounds.height / 4), Slot.width, Slot.height + radiusPadding, ); } checkForWin() { if(this.hasWon()) { this.game.win(); } } hasWon() { for(let i = 0; i < this.slots.length; i++) { let slot = this.slots[i]; if(!slot.colorsAllMatch()) { return false; } } return true; } initDemo() { //this.levelData = "[\n"; //for(let i = 1; i< 256; i++) { this.game = {playerData: {current: 15}}; this.generateRandomLevel(); //} //this.levelData += "]\n"; //console.log(this.levelData); } drawDemo(ctx, scaledCanvas) { this.draw(ctx,scaledCanvas); } getBounds() { let firstSlotBounds = this.getSlotBounds(this.slots[0]); let lastSlotBounds = this.getSlotBounds(this.slots[this.slots.length - 1]); return new Rectangle( firstSlotBounds.x, firstSlotBounds.y, lastSlotBounds.x - firstSlotBounds.x + lastSlotBounds.width, lastSlotBounds.y - firstSlotBounds.y + lastSlotBounds.height, ) } }