diff --git a/public/assets/flag.png b/public/assets/flag.png new file mode 100644 index 0000000..093ab9b Binary files /dev/null and b/public/assets/flag.png differ diff --git a/src/Flag.js b/src/Flag.js new file mode 100644 index 0000000..d4e895c --- /dev/null +++ b/src/Flag.js @@ -0,0 +1,57 @@ +export class Flag { + constructor(x, y, targetSize) { + // props + this.x = x; + this.y = y; + this.targetSize = targetSize; + this.sprite = null; + this.loaded = false; + + this.size = 0; + + // Load the flag image + loadImage('assets/flag.png', (img) => { + this.size = img.height; + this.sprite = new Sprite( + this.x, + this.y - this.size * 0.8, + this.size, + this.size, + "dynamic" + ); + this.sprite.layer = -1; + this.sprite.spriteSheet = img; + this.sprite.addAnis({ + default: { row: 0, frames: 5 }, + }); + this.sprite.anis.frameDelay = 8; + this.sprite.changeAni("default"); + + // Scale the sprite to match target size + const scale = this.targetSize / img.height; + this.sprite.scale = scale; + + // Set sprite properties + this.sprite.collider = 'static'; + this.loaded = true; + }); + } + + update() { + if (this.isLoaded) { + this.sprite.position.x = this.x; + this.sprite.position.y = this.y; + } + } + + draw() { + if (this.isLoaded) { + drawSprite(this.sprite); + } + } + + debug() { + console.log(`Flag position: x=${this.x}, y=${this.y}`); + console.log(`Flag loaded: ${this.isLoaded}`); + } +} \ No newline at end of file diff --git a/src/cat.js b/src/cat.js index 9998d21..23b8048 100644 --- a/src/cat.js +++ b/src/cat.js @@ -2,7 +2,6 @@ export class Cat { constructor(x, y, targetSize, groundRef, obstacleRefs, worldBlockSize) { this.x = x; this.y = y; - // this.size = 171; this.size = 0; this.targetSize = targetSize; this.sprite = null; @@ -19,21 +18,18 @@ export class Cat { this.currentStepIndex = 0; this.isMoving = false; this.stepTimer = 0; - this.stepDuration = 40; // frames to complete one movement + this.stepDuration = 40; this.moveDirection = null; this.lastDirection = null; this.hasJumped = false; loadImage('assets/cat.webp', (img) => { - // debugging - // console.log(`loaded image size: ${img.width} x ${img.height}`); - // console.log(`one sprite size: ${img.height / 5}`); this.size = img.height / 5; this.sprite = new Sprite(this.x, this.y, this.size, this.size, 'dynamic'); this.sprite.rotationLock = true; - this.sprite.bounciness = 0; + this.sprite.bounciness = 0.1; this.sprite.spriteSheet = img; this.sprite.anis.offset.y = 3; this.sprite.anis.frameDelay = 8; @@ -51,9 +47,8 @@ export class Cat { this.sprite.scale = scaleFactor; this.shiftOffset = this.targetSize - this.sprite.width * this.sprite.scale; - this.sprite.anis.offset.x = this.shiftOffset + 50; - // this.sprite.anis.offset.x = 100; - + this.sprite.anis.offset.x = this.shiftOffset + this.targetSize / 4; + // this.sprite.anis.offset.x = this.targetSize / 4; this.loaded = true; }); @@ -72,17 +67,6 @@ export class Cat { this._handleInput(); }; - // update() { - // if (!this.sprite || this.steps.length === 0) return; - - // if (this.isMoving) { - // this._continueMovement(); - // } else if (this.currentStepIndex < this.steps.length) { - // this._startMovement(this.steps[this.currentStepIndex]); - // } - // } - - run(steps) { this.steps = steps.map(e => e.direction); this.currentStepIndex = 0; @@ -90,7 +74,6 @@ export class Cat { } _startMovement(direction) { - // const blockSize = 100; this.moveDirection = direction; this.stepTimer = 0; this.isMoving = true; @@ -141,7 +124,6 @@ export class Cat { _checkPlatform() { if (!this.sprite) return false; - // if (this.ground && this.sprite.colliding(this.ground)) return true; if (this.ground && Array.isArray(this.ground)) { for (let block of this.ground) { @@ -156,59 +138,6 @@ export class Cat { } return false; } - - // _continueMovement() { - // this.stepTimer++; - - // // let isOnPlatform = false; - // let isOnPlatform = this._checkPlatform(); // Use existing _checkPlatform method instead - - - // if (this.ground && this.sprite.colliding(this.ground)) { - // isOnPlatform = true; - // } - - // if (this.obstacles && Array.isArray(this.obstacles)) { - // for (let block of this.obstacles) { - // if (this.sprite.colliding(block)) { - // isOnPlatform = true; - // break; - // } - // } - // } - - // if (this.moveDirection === 'right') { - // this.sprite.vel.x = 3; - // this.lastDirection = 'right'; - // } - - // if (this.moveDirection === 'left') { - // this.sprite.vel.x = -3; - // this.lastDirection = 'left'; - // } - - // if (this.moveDirection === 'up' && isOnPlatform && !this.hasJumped) { - // this.sprite.vel.y = -20; - - // // use lastDirection to add horizontal push - // if (this.lastDirection === 'right') { - // this.sprite.vel.x = 3; - // } else if (this.lastDirection === 'left') { - // this.sprite.vel.x = -3; - // } else { - // this.sprite.vel.x = 0; // jump straight up - // } - // } - - // this.hasJumped = true; - - // if (this.stepTimer >= this.stepDuration) { - // this.isMoving = false; - // this.currentStepIndex++; - // this.sprite.vel.x = 0; - // this.changeAni('i'); - // } - // } _continueMovement() { this.stepTimer++; @@ -260,15 +189,11 @@ export class Cat { if (!this.sprite) return null; - // Reset position to initial coordinates (from constructor) this.sprite.x = this.x; this.sprite.y = this.y; - - // Reset velocities this.sprite.vel.x = 0; this.sprite.vel.y = 0; - // Reset movement states this.steps = []; this.currentStepIndex = 0; this.isMoving = false; @@ -277,7 +202,6 @@ export class Cat { this.targetX = null; this.targetY = null; - // Reset animation this.changeAni('i'); setTimeout(() => { @@ -299,15 +223,12 @@ export class Cat { noFill(); stroke(255); strokeWeight(1); - // let w = this.sprite.width * this.sprite.scale; - // let h = this.sprite.height * this.sprite.scale; let w = this.sprite.width; let h = this.sprite.height; - // console.log(`sprite's actual dimension: ${w}x${h}`); rectMode(CENTER); - // rect(this.sprite.x, this.sprite.y, w, h); + rect(this.sprite.x, this.sprite.y, w, h); }; changeAni(key) { diff --git a/src/main.js b/src/main.js index 1a260d3..97aaada 100644 --- a/src/main.js +++ b/src/main.js @@ -1,8 +1,10 @@ import { colors } from './utils/theme.js'; import { Arrow } from './components/Arrow.js'; +import { ClickableArrow } from './components/ClickableArrow.js'; import StartScene from './scenes/startScene.js'; import GameScene from './scenes/gameScene.js'; -import { ClickableArrow } from './components/ClickableArrow.js'; +import Level1 from './scenes/lvl1.js'; + let mgr; @@ -16,7 +18,8 @@ function setup(){ mgr = new SceneManager(); mgr.addScene(StartScene); mgr.addScene(GameScene); - mgr.showScene(GameScene); + mgr.addScene(Level1); + mgr.showScene(Level1); }; function draw(){ diff --git a/src/scenes/gameScene.js b/src/scenes/gameScene.js index 1ea7a80..e6a376a 100644 --- a/src/scenes/gameScene.js +++ b/src/scenes/gameScene.js @@ -1,20 +1,19 @@ import { colors } from '../utils/theme.js'; import { Cat } from '../cat.js'; -import { buttonS } from '../utils/theme.js'; +import { buttonS, buttonM, buttonL } from '../utils/theme.js'; import { MyButton } from '../utils/components.js'; import { ClickableArrow } from '../components/ClickableArrow.js'; import { ControlPanel } from '../components/controlPanel.js'; +import { Flag } from "../Flag.js"; export default function GameScene() { - // for ground - let ground; let blocksGround = []; let blockSprites = []; let restart = false; - const catSize = 150; + const catSize = 155; const worldBlockSize = 125; const groundHeight = worldBlockSize; // const worldHeight = windowHeight - groundHeight; @@ -31,13 +30,20 @@ export default function GameScene() { ]; let cat; + let flag; + let runButton; + let nextButton; + let exitButton; + let blocks; let steps; - let loops; - let clickArrow; + // let loops; + // let clickArrow; - let clicked; + // let clicked; + + let levelFinished = false; let selectedStepIndex = null; @@ -50,9 +56,6 @@ export default function GameScene() { let selectedSteps; let selectedBlock; - // selectedSteps = ['up', 'right', 'up', 'up', 'right', 'down']; - // selectedSteps = selectedSteps.map((e) => new ClickableArrow(e, true)); - const slots = { blocks: 2, steps: 8, @@ -71,6 +74,15 @@ export default function GameScene() { onPress: () => this.startGame(), }); + nextButton = new MyButton({ + x: width / 2, + y: height / 2.5, + text: "next", + mode: "CENTER", + style: buttonM, + onPress: () => console.log(`redirect to next game`), + }); + blocks = new ControlPanel({ name: 'blocks', x: width / 32 * 7, @@ -94,12 +106,14 @@ export default function GameScene() { // numBoxes: slots.loops, // }); + flag = new Flag(12 * worldBlockSize, height - worldBlockSize * 4, catSize * 0.75); + for (let i = 0; i < width; i += worldBlockSize) { let b = new Sprite( - i + worldBlockSize / 2, // x position for each block - height - groundHeight / 2, // y position - worldBlockSize, // width of each block - worldBlockSize, // height of each block + i + worldBlockSize / 2, + height - groundHeight / 2, + worldBlockSize, + worldBlockSize, 'static' ); const i_cnt = Math.floor(i / worldBlockSize); @@ -126,8 +140,7 @@ export default function GameScene() { } } - // Cat sprite - // cat = new Cat(width / 4, height - catSize * 13/12, catSize, blocksGround, blockSprites); + // Sprites cat = new Cat(2.25 * worldBlockSize, height - catSize * 13/12, catSize, blocksGround, blockSprites, worldBlockSize); }; @@ -142,10 +155,36 @@ export default function GameScene() { text('lvl.1', width / 32, height /32 - 4); runButton.draw(); + flag.draw(); blocks.draw(); steps.draw(); // loops.draw(); cat.draw(); + + if (cat.sprite && flag.sprite) { + if (cat.sprite.overlaps(flag.sprite)) { + levelFinished = true; + }; + }; + + if (!levelFinished) { + // draw the overlay + push(); + fill(35, 20, 45, 190); + rectMode(CORNER); + rect(0, 0, width, height); + + textAlign(CENTER, CENTER); + textSize(128) + fill(colors.tertiary); + stroke(colors.secondary); + strokeWeight(10); + text("~lvl 1 DONE!~", width / 2, height / 4); + + // draw button + nextButton.draw(); + pop(); + } }; this.onResize = () => { @@ -203,4 +242,28 @@ export default function GameScene() { cat.run(steps.contents); restart = true; } + + this.exit = function () { + // Remove cat sprite + if (cat) { + cat.remove(); + } + + // Remove flag sprite + if (flag && flag.sprite) { + flag.sprite.remove(); + } + + // Remove ground blocks + blocksGround.forEach(block => { + if (block) block.remove(); + }); + blocksGround = []; + + // Remove obstacle blocks + blockSprites.forEach(block => { + if (block) block.remove(); + }); + blockSprites = []; + }; } diff --git a/src/scenes/lvl1.js b/src/scenes/lvl1.js new file mode 100644 index 0000000..be558fb --- /dev/null +++ b/src/scenes/lvl1.js @@ -0,0 +1,270 @@ +import { colors } from '../utils/theme.js'; +import { Cat } from '../cat.js'; +import { buttonS, buttonM, buttonL } from '../utils/theme.js'; +import { MyButton } from '../utils/components.js'; +import { ClickableArrow } from '../components/ClickableArrow.js'; +import { ControlPanel } from '../components/controlPanel.js'; +import { Flag } from "../Flag.js"; +import Level2 from "./lvl2.js"; + + +export default function Level1() { + let blocksGround = []; + let blockSprites = []; + + let restart = false; + + const catSize = 155; + const worldBlockSize = 125; + const groundHeight = worldBlockSize; + // const worldHeight = windowHeight - groundHeight; + const maxIdx = { + x: Math.ceil(windowWidth / worldBlockSize), + y: Math.floor(windowHeight / worldBlockSize) + } + + const obstacle = [ + ...Array(maxIdx.y - 3 - 1).fill(...Array(maxIdx.x).fill(0)), + [...Array(9).fill(0), ...Array(maxIdx.x - 9).fill(1)], + [...Array(7).fill(0), ...Array(maxIdx.x - 7).fill(1)], + [...Array(5).fill(0), ...Array(maxIdx.x - 5).fill(1)], + ]; + + let cat; + let flag; + + let runButton; + let nextButton; + let exitButton; + + let blocks; + let steps; + // let loops; + // let clickArrow; + + // let clicked; + + let levelFinished = false; + + let selectedStepIndex = null; + + const buildingBlocks = [ + new ClickableArrow('up', false), + new ClickableArrow('right', false), + ]; + + // changed on user input + let selectedSteps; + let selectedBlock; + + const slots = { + blocks: 2, + steps: 8, + loop: 3, + } + + this.name = "GameScene"; + + this.setup = () => { + runButton = new MyButton({ + x: (width / 32) * 28.5, + y: height / 32, + text: "run >>", + mode: "CORNER", + style: buttonS, + onPress: () => this.startGame(), + }); + + nextButton = new MyButton({ + x: width / 2, + y: height / 2.5, + text: "next", + mode: "CENTER", + style: buttonM, + onPress: () => this.sceneManager.showScene(Level2), + }); + + blocks = new ControlPanel({ + name: 'blocks', + x: width / 32 * 7, + y: height / 32, + numBoxes: slots.blocks, + }); + blocks.setContents(buildingBlocks); + + steps = new ControlPanel({ + name: 'steps', + x: width / 32 * 7 + 48 * (slots.blocks + 1), + y: height / 32, + numBoxes: slots.steps, + }); + + + // loops = new ControlPanel({ + // name: 'loop', + // x: width / 32 * 7 + 48 * (slots.blocks + slots.steps + 2.75), + // y: height / 32, + // numBoxes: slots.loops, + // }); + + flag = new Flag(12 * worldBlockSize, height - worldBlockSize * 4, catSize * 0.75); + + for (let i = 0; i < width; i += worldBlockSize) { + let b = new Sprite( + i + worldBlockSize / 2, + height - groundHeight / 2, + worldBlockSize, + worldBlockSize, + 'static' + ); + const i_cnt = Math.floor(i / worldBlockSize); + + b.color = (i_cnt % 2) === 0 ? color(colors.secondary) : color(colors.darkRed); + b.strokeWeight = 5; + b.stroke = (i_cnt % 2) === 0 ? color(colors.darkRed) : color(colors.darkRed); + blocksGround.push(b); + } + + // Obstacles (physical) + for (let y = windowHeight - groundHeight - 2; y > 0; y -= worldBlockSize) { + for (let x = 0; x < width; x += worldBlockSize) { + const x_cnt = Math.floor(x / worldBlockSize); + const y_cnt = Math.floor(y / worldBlockSize); + const isObs = obstacle[y_cnt] && obstacle[y_cnt][x_cnt]; + + if (isObs) { + let b = new Sprite(x + worldBlockSize / 2, y + worldBlockSize / 2, worldBlockSize, worldBlockSize, 'static'); + b.color = (x_cnt + y_cnt) % 2 === 0 ? color(colors.tertiary) : color(colors.accent); + b.strokeWeight = 0; + blockSprites.push(b); + } + } + } + + // Sprites + cat = new Cat(2.25 * worldBlockSize, height - catSize * 13/12, catSize, blocksGround, blockSprites, worldBlockSize); + }; + + this.draw = () => { + background(colors.primary); + + fill(colors.tertiary); + textSize(128); + stroke(colors.secondary); + strokeWeight(7); + textAlign(LEFT, TOP); + text('lvl.1', width / 32, height /32 - 4); + + runButton.draw(); + flag.draw(); + blocks.draw(); + steps.draw(); + // loops.draw(); + cat.draw(); + + if (cat.sprite && flag.sprite) { + if (cat.sprite.overlaps(flag.sprite)) { + levelFinished = true; + }; + }; + + if (levelFinished) { + // draw the overlay + push(); + fill(35, 20, 45, 190); + rectMode(CORNER); + rect(0, 0, width, height); + + textAlign(CENTER, CENTER); + textSize(128) + fill(colors.tertiary); + stroke(colors.secondary); + strokeWeight(10); + text("~lvl 1 DONE!~", width / 2, height / 4); + + // draw button + nextButton.draw(); + pop(); + } + }; + + this.onResize = () => { + cat.setPosition(width / 2, height - 177.5); + runButton.setPosition((width / 16) * 15, height / 16); + blocks.setPosition(width / 32, height / 32); + steps.setPosition((width / 32) * 4, height / 32); + } + + this.keyPressed = () => { + console.log(`key: ${key}, keyCode: ${keyCode}`); + + const _key = key; + console.log(`key passed: ${_key}`); + + if (keyCode === ESCAPE) { + // Deselect the currently selected arrow if any + if (selectedStepIndex !== null && steps.contents[selectedStepIndex]) { + steps.contents[selectedStepIndex].selected = false; + } + selectedStepIndex = null; + } else { + cat.keyPressed(key); + } + } + + this.mousePressed = function() { + // console.log(`canvas clicked at ${mouseX}, ${mouseY}`); + + steps.contents.forEach((arrow, index) => { + if (arrow._isMouseOver(mouseX, mouseY)) { + selectedStepIndex = index; + steps.contents.forEach(a => a.selected = false); + arrow.select(); + } + }); + + blocks.contents.forEach((arrow) => { + if (arrow._isMouseOver(mouseX, mouseY)) { + // console.log("Clicked arrow", arrow.direction); + if (selectedStepIndex !== null) { + const selectedArrow = steps.contents[selectedStepIndex]; + selectedArrow.set(arrow.direction); + selectedArrow.clickable = true; + selectedArrow.selected = false; + selectedStepIndex = null; + } + } + }); + + }; + + this.startGame = () => { + if (restart) cat.restart(); + cat.run(steps.contents); + restart = true; + }; + + this.exit = function () { + // Remove cat sprite + if (cat) { + cat.remove(); + } + + // Remove flag sprite + if (flag && flag.sprite) { + flag.sprite.remove(); + } + + // Remove ground blocks + blocksGround.forEach(block => { + if (block) block.remove(); + }); + blocksGround = []; + + // Remove obstacle blocks + blockSprites.forEach(block => { + if (block) block.remove(); + }); + blockSprites = []; + }; +} diff --git a/src/scenes/lvl2.js b/src/scenes/lvl2.js new file mode 100644 index 0000000..a64179e --- /dev/null +++ b/src/scenes/lvl2.js @@ -0,0 +1,269 @@ +import { colors } from '../utils/theme.js'; +import { Cat } from '../cat.js'; +import { buttonS, buttonM, buttonL } from '../utils/theme.js'; +import { MyButton } from '../utils/components.js'; +import { ClickableArrow } from '../components/ClickableArrow.js'; +import { ControlPanel } from '../components/controlPanel.js'; +import { Flag } from "../Flag.js"; + + +export default function Level2() { + let blocksGround = []; + let blockSprites = []; + + let restart = false; + + const catSize = 155; + const worldBlockSize = 125; + const groundHeight = worldBlockSize; + // const worldHeight = windowHeight - groundHeight; + const maxIdx = { + x: Math.ceil(windowWidth / worldBlockSize), + y: Math.floor(windowHeight / worldBlockSize) + } + + const obstacle = [ + ...Array(maxIdx.y - 3 - 1).fill(...Array(maxIdx.x).fill(0)), + [...Array(9).fill(0), ...Array(maxIdx.x - 9).fill(1)], + [...Array(7).fill(0), ...Array(maxIdx.x - 7).fill(1)], + [...Array(5).fill(0), ...Array(maxIdx.x - 5).fill(1)], + ]; + + let cat; + let flag; + + let runButton; + let nextButton; + let exitButton; + + let blocks; + let steps; + // let loops; + // let clickArrow; + + // let clicked; + + let levelFinished = false; + + let selectedStepIndex = null; + + const buildingBlocks = [ + new ClickableArrow('up', false), + new ClickableArrow('right', false), + ]; + + // changed on user input + let selectedSteps; + let selectedBlock; + + const slots = { + blocks: 2, + steps: 8, + loop: 3, + } + + this.name = "GameScene"; + + this.setup = () => { + runButton = new MyButton({ + x: (width / 32) * 28.5, + y: height / 32, + text: "run >>", + mode: "CORNER", + style: buttonS, + onPress: () => this.startGame(), + }); + + nextButton = new MyButton({ + x: width / 2, + y: height / 2.5, + text: "next", + mode: "CENTER", + style: buttonM, + onPress: () => console.log(`redirect to next game`), + }); + + blocks = new ControlPanel({ + name: 'blocks', + x: width / 32 * 7, + y: height / 32, + numBoxes: slots.blocks, + }); + blocks.setContents(buildingBlocks); + + steps = new ControlPanel({ + name: 'steps', + x: width / 32 * 7 + 48 * (slots.blocks + 1), + y: height / 32, + numBoxes: slots.steps, + }); + + + // loops = new ControlPanel({ + // name: 'loop', + // x: width / 32 * 7 + 48 * (slots.blocks + slots.steps + 2.75), + // y: height / 32, + // numBoxes: slots.loops, + // }); + + flag = new Flag(12 * worldBlockSize, height - worldBlockSize * 4, catSize * 0.75); + + for (let i = 0; i < width; i += worldBlockSize) { + let b = new Sprite( + i + worldBlockSize / 2, + height - groundHeight / 2, + worldBlockSize, + worldBlockSize, + 'static' + ); + const i_cnt = Math.floor(i / worldBlockSize); + + b.color = (i_cnt % 2) === 0 ? color(colors.secondary) : color(colors.darkRed); + b.strokeWeight = 5; + b.stroke = (i_cnt % 2) === 0 ? color(colors.darkRed) : color(colors.darkRed); + blocksGround.push(b); + } + + // Obstacles (physical) + for (let y = windowHeight - groundHeight - 2; y > 0; y -= worldBlockSize) { + for (let x = 0; x < width; x += worldBlockSize) { + const x_cnt = Math.floor(x / worldBlockSize); + const y_cnt = Math.floor(y / worldBlockSize); + const isObs = obstacle[y_cnt] && obstacle[y_cnt][x_cnt]; + + if (isObs) { + let b = new Sprite(x + worldBlockSize / 2, y + worldBlockSize / 2, worldBlockSize, worldBlockSize, 'static'); + b.color = (x_cnt + y_cnt) % 2 === 0 ? color(colors.tertiary) : color(colors.accent); + b.strokeWeight = 0; + blockSprites.push(b); + } + } + } + + // Sprites + cat = new Cat(2.25 * worldBlockSize, height - catSize * 13/12, catSize, blocksGround, blockSprites, worldBlockSize); + }; + + this.draw = () => { + background(colors.primary); + + fill(colors.tertiary); + textSize(128); + stroke(colors.secondary); + strokeWeight(7); + textAlign(LEFT, TOP); + text('lvl.2', width / 32, height /32 - 4); + + runButton.draw(); + flag.draw(); + blocks.draw(); + steps.draw(); + // loops.draw(); + cat.draw(); + + if (cat.sprite && flag.sprite) { + if (cat.sprite.overlaps(flag.sprite)) { + levelFinished = true; + }; + }; + + if (levelFinished) { + // draw the overlay + push(); + fill(35, 20, 45, 190); + rectMode(CORNER); + rect(0, 0, width, height); + + textAlign(CENTER, CENTER); + textSize(128) + fill(colors.tertiary); + stroke(colors.secondary); + strokeWeight(10); + text("~lvl 2 DONE!~", width / 2, height / 4); + + // draw button + nextButton.draw(); + pop(); + } + }; + + this.onResize = () => { + cat.setPosition(width / 2, height - 177.5); + runButton.setPosition((width / 16) * 15, height / 16); + blocks.setPosition(width / 32, height / 32); + steps.setPosition((width / 32) * 4, height / 32); + } + + this.keyPressed = () => { + console.log(`key: ${key}, keyCode: ${keyCode}`); + + const _key = key; + console.log(`key passed: ${_key}`); + + if (keyCode === ESCAPE) { + // Deselect the currently selected arrow if any + if (selectedStepIndex !== null && steps.contents[selectedStepIndex]) { + steps.contents[selectedStepIndex].selected = false; + } + selectedStepIndex = null; + } else { + cat.keyPressed(key); + } + } + + this.mousePressed = function() { + // console.log(`canvas clicked at ${mouseX}, ${mouseY}`); + + steps.contents.forEach((arrow, index) => { + if (arrow._isMouseOver(mouseX, mouseY)) { + selectedStepIndex = index; + steps.contents.forEach(a => a.selected = false); + arrow.select(); + } + }); + + blocks.contents.forEach((arrow) => { + if (arrow._isMouseOver(mouseX, mouseY)) { + // console.log("Clicked arrow", arrow.direction); + if (selectedStepIndex !== null) { + const selectedArrow = steps.contents[selectedStepIndex]; + selectedArrow.set(arrow.direction); + selectedArrow.clickable = true; + selectedArrow.selected = false; + selectedStepIndex = null; + } + } + }); + + }; + + this.startGame = () => { + if (restart) cat.restart(); + cat.run(steps.contents); + restart = true; + }; + + this.exit = function () { + // Remove cat sprite + if (cat) { + cat.remove(); + } + + // Remove flag sprite + if (flag && flag.sprite) { + flag.sprite.remove(); + } + + // Remove ground blocks + blocksGround.forEach(block => { + if (block) block.remove(); + }); + blocksGround = []; + + // Remove obstacle blocks + blockSprites.forEach(block => { + if (block) block.remove(); + }); + blockSprites = []; + }; +} diff --git a/src/utils/components.js b/src/utils/components.js index 0b10163..d3a3d62 100644 --- a/src/utils/components.js +++ b/src/utils/components.js @@ -1,5 +1,5 @@ export class MyButton { - constructor({ x, y, text, mode = "CORNER", style = {}, onPress = null }) { + constructor({ x, y, text, mode = "CORNER", style = {}, onPress = null, size = 'small' }) { this.button = new Clickable(); // Apply layout @@ -36,5 +36,4 @@ export class MyButton { setPosition(x, y) { this.button.locate(x, y); } -}; - \ No newline at end of file +}; \ No newline at end of file diff --git a/src/utils/theme.js b/src/utils/theme.js index 4df1761..7a58fc3 100644 --- a/src/utils/theme.js +++ b/src/utils/theme.js @@ -21,6 +21,13 @@ const buttonL = { textSize: 32, }; +const buttonM = { + ...button, + width: 200, + height: 60, + textSize: 26, + strokeWeight: 3, +}; const buttonS = { ...button, @@ -30,4 +37,4 @@ const buttonS = { strokeWeight: 3, }; -export { colors, buttonL, buttonS }; +export { colors, buttonL, buttonM, buttonS };