Compare commits

...

10 Commits

Author SHA1 Message Date
nadiarvi
65e326f97e fix readme 2025-05-11 17:55:01 +09:00
nadiarvi
640ffc4dd8 fix uml diagram 2025-05-11 17:53:28 +09:00
nadiarvi
f234dce49b add UML class 2025-05-11 17:49:08 +09:00
nadiarvi
86f603a14d fix readme 2025-05-11 17:30:33 +09:00
nadiarvi
04f1b42193 fix starting scene 2025-05-11 10:18:31 +09:00
nadiarvi
21be8cceb9 fix README 2025-05-10 23:36:19 +09:00
nadiarvi
bf7e50f846 add README 2025-05-10 23:26:10 +09:00
nadiarvi
6376e6a6d5 fix: shift world to the left 2025-05-10 21:48:57 +09:00
nadiarvi
025b4f1da2 feat: connect lvl 3 to start screen 2025-05-10 18:47:05 +09:00
nadiarvi
b797f7be41 fix: cat jump bug @ restart 2025-05-10 18:21:26 +09:00
17 changed files with 302 additions and 382 deletions

161
README.md
View File

@ -1,2 +1,159 @@
# run-the-cat
ID311 Individual Game Project
![Run The Cat Banner](public/assets/docs/header.webp)
<div style="display: flex; justify-content: center; align-items: center; gap: 8px;">
<a href="https://github.com/nadiarvi/run-the-cat">
<img src="https://img.shields.io/badge/github-repo?logo=github&label=Project%20Repository" alt="Github Repo">
</a>
<a href="https://youtu.be/VV65VTHZCwg">
<img src="https://img.shields.io/badge/YouTube-Game%20Demo-FF0000?logo=youtube&logoColor=white" alt="Game Demo">
</a>
</div>
# 🐱 Run The Cat
## 👩‍💻 Student Information
Name : Nadia Azzahra Putri Arvi
Student ID : 20210747
Email : nadia.arvi@kaist.ac.kr
## 📃 Table of Contents
- [🐱 Run The Cat](#-run-the-cat)
- [👩‍💻 Student Information](#-student-information)
- [📃 Table of Contents](#-table-of-contents)
- [🎮 Game Description](#-game-description)
- [🕹️ How It Works](#-how-it-works)
- [⚙️ Installing \& Running The Game](#-installing--running-the-game)
- [🔧 Code Structure](#-code-structure)
- [🐙💻 Repository Structure](#-repository-structure)
- [🧩 Key Modules and Responsibilities](#-key-modules-and-responsibilities)
- [📦 Tech Stack \& Resources](#-tech-stack--resources)
- [🔧 Built With](#-built-with)
- [🕹️ Game Framework \& Libraries](#-game-framework--libraries)
- [🎨 Assets Used](#-assets-used)
- [🐛 Known Issues](#-known-issues)
- [✨ Special Features](#-special-features)
- [🙏 Acknowledgements](#-acknowledgements)
## 🎮 Game Description
Run The Cat is a puzzle-platformer game where players guide a cat through various levels using coding-like commands. The game teaches basic programming concepts through interactive gameplay.
### 🕹️ How It Works
<div align="center">
<img src="public/assets/docs/game_snippets.png" alt="Snippet of the Game" width="80%"/>
<p>Figure 1. A snapshot of the game interface showing key UI components.<br>
</div>
In this game, players must:
1. Select commands from the `blocks` panel — only these available blocks can be used.
2. Arrange the selected blocks into a sequence using the `steps` panel.
3. Define macro commands in the `loop` panel to optimize and reduce repetition.
4. Execute the move using the `run` button to guide the cat.
5. Collect keys and reach the flag to complete the level.
## ⚙️ Installing & Running The Game
To play the game, follow these steps:
1. Clone the repository
```bash
git clone https://github.com/nadiarvi/run-the-cat.git
```
2. Navigate to the project directory:
```bash
cd run-the-cat
```
3. Install dependencies and start the game:
```bash
npm install
npm run dev
```
## 🔧 Code Structure
<div align="center">
<img src='./public/assets/docs/uml.png' width="90%"/>
<p>Figure 2. UML Diagram and Class Relations<br>
</div>
### 🐙💻 Repository Structure
```bash
run-the-cat/
├── README.md
├── index.html # Main HTML file to load the game
├── lib/ # External libraries (p5.js, SceneManager, etc.)
│ ├── p5.clickable.js
│ ├── p5.js
│ ├── scenemanager.js
│ └── scenemanager_.js
├── package.json # Project metadata and dependencies
├── public/
│ └── assets/ # Images, sprites, and other media assets
└── src/ # Main source code
├── components/ # Reusable game components (Cat, Flag, etc.)
├── main.js # Game entry point
├── scenes/ # Level or scene logic
├── style.css # Styles for the game UI
└── utils/ # Utility functions and UI helpers
```
### 🧩 Key Modules and Responsibilities
- index.html: Entry point of the application; initializes canvas and loads all scripts.
- lib/: Contains external libraries such as p5.js, p5.clickable, and p5.SceneManager for rendering, UI, and scene handling.
- public/assets/: Includes all images, sprites, and media used in the game and README visuals.
- src/components/: Contains constructors for individual game elements such as:
- Cat: Handles player character movement, physics, and animation.
- Key and Flag: Interactive objects related to level progression.
- src/scenes/: Implements level logic using SceneManager.
- src/utils/: Includes styling helpers, themes, and reusable UI logic.
- main.js: Boots up the game and loads the initial scene.
- style.css: Provides global styling for in-game UI and layout.
## 📦 Tech Stack & Resources
### 🔧 Built With
| Tech | Description |
|------|-------------|
| ![HTML5](https://img.shields.io/badge/HTML5-E34F26?logo=html5&logoColor=white) | Markup structure |
| ![CSS3](https://img.shields.io/badge/CSS3-1572B6?logo=css3&logoColor=white) | Styling and layout |
| ![JavaScript](https://img.shields.io/badge/JavaScript-F7DF1E?logo=javascript&logoColor=black) | Game logic and interactivity |
| ![Node.js](https://img.shields.io/badge/Node.js-339933?logo=node.js&logoColor=white) | Development tooling |
### 🕹️ Game Framework & Libraries
| Library | Purpose |
|---------|---------|
| [![p5.js](https://img.shields.io/badge/p5.js-EA4AAA?logo=p5.js&logoColor=white)](https://p5js.org/) | Core game rendering and animation |
| [p5.SceneManager](https://github.com/mveteanu/p5.SceneManager) | Manage different game scenes and levels |
| [p5.clickable](https://github.com/Lartu/p5.clickable) | Create clickable UI elements (i.e. buttons) |
| [p5.play](https://p5play.org/) | Sprite handling and physics engine |
### 🎨 Assets Used
| Asset | Source & Credits |
|-------|------------------|
| 🐱 **Cat Sprite** | [Free Street Animal Pixel Art Asset Pack](https://craftpix.net/freebies/free-street-animal-pixel-art-asset-pack/?num=1&count=301&sq=cat&pos=4) by [CraftPix.net](https://craftpix.net) |
| 🚩 **Flag Animation** | [Free Flag with Animation](https://ankousse26.itch.io/free-flag-with-animation) by [ankousse26](https://ankousse26.itch.io) |
| 🔑 **Key Sprite** | [FREE Pixel Art Key Pack Animated](https://karsiori.itch.io/pixel-art-key-pack-animated) by [karsiori](https://karsiori.itch.io) |
## 🐛 Known Issues
- **Restart Bug**
After restarting a level, the cat's movement becomes slightly jittery, unlike on a fresh load. This is likely due to the sprite or state not being fully reset. A temporary fix is in place, but it may still cause minor visual glitches.
- **Clickable Background After Completion**
When a level is completed and the overlay is displayed, the background remains interactive. This allows players to accidentally trigger cat movement even though the game should not be playable.
- **Sprite Can Move Outside the Frame**
When the Cat sprite moves beyond the visible frame, it becomes unresponsive to controls. Currently, there is no boundary-checking logic implemented to prevent the sprite from leaving the playable area.
## ✨ Special Features
_No additional features beyond the core requirements were implemented._
## 🙏 Acknowledgements
All assets and libraries used have been credited in the [📦 Tech Stack & Resources](#-tech-stack--resources) section above. Code examples were referenced from the official documentation of the respective libraries. LLMs were used for debugging assistance.

View File

@ -1,185 +0,0 @@
const STYLE_DEFAULT = {
background: '#eee',
color: '#111',
border_color: '',
border_width: 0,
border_radius: 5,
text_font: 'sans-serif',
text_size: 12,
}
const STYLE_HOVER = {
background: '#ccc',
color: '#111',
}
const STYLE_PRESSED = {
background: '#aaa',
color: '#000',
}
const STYLE_DISABLED = {
background: '#777',
color: '#333',
}
export default class Button {
#was_pressed = false;
#was_hovering = false;
#props = { };
#bounds = { minx: null, miny: null, maxx: null, maxy: null, centerx: null, centery: null };
#cstyles = { default: STYLE_DEFAULT, hover: STYLE_HOVER, pressed: STYLE_PRESSED, disabled: STYLE_DISABLED };
constructor(properties) {
this.#props = Object.assign({
content: '',
x: null, y: null,
w: null, h: null,
width: null,
height: null,
style_default: STYLE_DEFAULT,
style_hover: STYLE_HOVER,
style_pressed: STYLE_PRESSED,
style_disabled: STYLE_DISABLED,
on_mouse_enter: null,
on_mouse_exit: null,
on_press: null,
on_release: null,
align_x: -1,
align_y: -1,
enabled: true,
}, properties);
if ( this.#props.x === null || this.#props.y === null || this.#props.width === null || this.#props.height === null )
throw( '"x", "y", "width", and "height" must all be defined in the button properties!' );
Object.seal(this.#props);
this.#calculateStyles();
this.#calculateBounds();
}
#calculateBounds() {
const offset_x = (this.#props.align_x-1)*this.#props.width/2,
offset_y = (this.#props.align_y-1)*this.#props.height/2;
this.#bounds.minx = this.#props.x + offset_x,
this.#bounds.miny = this.#props.y + offset_y,
this.#bounds.maxx = this.#props.x + this.#props.width + offset_x,
this.#bounds.maxy = this.#props.y + this.#props.height + offset_y,
this.#bounds.centerx = this.#props.x + this.#props.width/2 + offset_x,
this.#bounds.centery = this.#props.y + this.#props.height/2 + offset_y;
}
#calculateStyles() {
this.#cstyles.default = Object.assign({}, STYLE_DEFAULT, this.#props.style_default);
this.#cstyles.hover = Object.assign({}, STYLE_DEFAULT, this.#props.style_default, this.#props.style_hover);
this.#cstyles.pressed = Object.assign({}, STYLE_DEFAULT, this.#props.style_default, this.#props.style_pressed);
this.#cstyles.disabled = Object.assign({}, STYLE_DEFAULT, this.#props.style_default, this.#props.style_disabled);
}
update(properties) {
try {
Object.assign(this.#props, properties);
} catch(e) {console.warn( `Encountered an unrecognized property! Original error: ${e.message}` )}
if ( 'x' in properties || 'y' in properties || 'width' in properties || 'height' in properties || 'align_x' in properties || 'align_y' in properties )
this.#calculateBounds();
if ( 'style_default' in properties || 'style_hover' in properties || 'style_pressed' in properties || 'style_disabled' in properties )
this.#calculateStyles();
}
/** Shorthand for .update({ x: <value>, y: <value>, ... }) */
place( x, y, width=null, height=null ) {
this.#props.x = x,
this.#props.y = y;
if ( width !== null ) this.#props.width = width;
if ( height !== null ) this.#props.height = height;
this.#calculateBounds();
}
/** Shorthand for .update({ style_<stylename>: <value> }) */
style( stylename, style ) {
if (!( 'style_'+stylename in this.#props ))
throw( `Style name must be either "default", "hover", "pressed", or "disabled". Received "${stylename}" instead.` );
this.#props['style_'+stylename] = style;
this.#calculateStyles();
}
/** Shorthand for .update({ content: <value> }) */
text( content ) { this.#props.content = content }
/** Shorthand for .update({ enabled: true }) */
enable() { this.#props.enabled = true }
/** Shorthand for .update({ enabled: false }) */
disable() { this.#props.enabled = false }
/**
* Returns whether the specified point (by default the mouse's position) is hovering over the button.
* @param {number} x (optional) x override.
* @param {number} y (optional) y override.
* @returns {boolean}
*/
isHovering(x=mouseX, y=mouseY) {
return x > this.#bounds.minx && x < this.#bounds.maxx && y > this.#bounds.miny && y < this.#bounds.maxy;
}
/**
* Returns whether the button is currently being pressed.
* @returns {boolean}
*/
isPressed() {
return this.isHovering() && mouseIsPressed;
}
#getCurrentStyle( hovering, pressed ) {
if ( !this.#props.enabled ) return this.#cstyles.disabled;
if ( pressed ) return this.#cstyles.pressed;
if ( hovering ) return this.#cstyles.hover;
return this.#cstyles.default;
}
/**
* Draws the button on the specified canvas, or the global canvas by default.
* @param context (optional) The p5 canvas to draw to.
*/
draw( context=globalThis ) {
const is_hovering = this.isHovering();
const is_pressed = mouseIsPressed && (is_hovering || this.#was_pressed);
const style = this.#getCurrentStyle( is_hovering, is_pressed );
if ( style.background ) context.fill( style.background );
else context.noFill();
if ( style.border_color && style.border_radius ) {
context.stroke( style.border_color );
context.strokeWeight( style.border_width );
} else context.noStroke();
context.rect( this.#bounds.minx, this.#bounds.miny, this.#props.width, this.#props.height, style.border_radius );
noStroke();
context.fill( style.color );
context.textAlign( CENTER, CENTER );
context.textSize( style.text_size );
context.textFont( style.text_font );
context.text( this.#props.content, this.#bounds.centerx, this.#bounds.centery );
if ( !this.#was_pressed && is_pressed && this.#props.on_press ) this.#props.on_press();
if ( this.#was_pressed && !is_pressed && this.#props.on_release ) this.#props.on_release();
if ( !this.#was_hovering && is_hovering && this.#props.on_mouse_enter ) this.#props.on_mouse_enter();
if ( this.#was_hovering && !is_hovering && this.#props.on_mouse_exit ) this.#props.on_mouse_exit();
this.#was_pressed = is_pressed;
this.#was_hovering = is_hovering;
}
}

71
package-lock.json generated
View File

@ -7,6 +7,9 @@
"": {
"name": "run-the-cat",
"version": "0.0.0",
"dependencies": {
"badge-maker": "^4.1.0"
},
"devDependencies": {
"vite": "^6.3.1"
}
@ -723,6 +726,74 @@
"dev": true,
"license": "MIT"
},
"node_modules/anafanafo": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/anafanafo/-/anafanafo-2.0.0.tgz",
"integrity": "sha512-Nlfq7NC4AOkTJerWRIZcOAiMNtIDVIGWGvQ98O7Jl6Kr2Dk0dX5u4MqN778kSRTy5KRqchpLdF2RtLFEz9FVkQ==",
"license": "MIT",
"dependencies": {
"char-width-table-consumer": "^1.0.0"
}
},
"node_modules/badge-maker": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/badge-maker/-/badge-maker-4.1.0.tgz",
"integrity": "sha512-qYImXoz0WZRMaauqSMo6QNurKp26K3RcOhefuGfno50xmAzHEJsgHbP4gnHs6Ps53KgQgFi4MJKB6Rq8H7siww==",
"license": "CC0-1.0",
"dependencies": {
"anafanafo": "2.0.0",
"css-color-converter": "^2.0.0"
},
"bin": {
"badge": "lib/badge-cli.js"
},
"engines": {
"node": ">=16"
}
},
"node_modules/binary-search": {
"version": "1.3.6",
"resolved": "https://registry.npmjs.org/binary-search/-/binary-search-1.3.6.tgz",
"integrity": "sha512-nbE1WxOTTrUWIfsfZ4aHGYu5DOuNkbxGokjV6Z2kxfJK3uaAb8zNK1muzOeipoLHZjInT4Br88BHpzevc681xA==",
"license": "CC0-1.0"
},
"node_modules/char-width-table-consumer": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/char-width-table-consumer/-/char-width-table-consumer-1.0.0.tgz",
"integrity": "sha512-Fz4UD0LBpxPgL9i29CJ5O4KANwaMnX/OhhbxzvNa332h+9+nRKyeuLw4wA51lt/ex67+/AdsoBQJF3kgX2feYQ==",
"license": "MIT",
"dependencies": {
"binary-search": "^1.3.5"
}
},
"node_modules/color-convert": {
"version": "0.5.3",
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-0.5.3.tgz",
"integrity": "sha512-RwBeO/B/vZR3dfKL1ye/vx8MHZ40ugzpyfeVG5GsiuGnrlMWe2o8wxBbLCpw9CsxV+wHuzYlCiWnybrIA0ling=="
},
"node_modules/color-name": {
"version": "1.1.4",
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
"license": "MIT"
},
"node_modules/css-color-converter": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/css-color-converter/-/css-color-converter-2.0.0.tgz",
"integrity": "sha512-oLIG2soZz3wcC3aAl/7Us5RS8Hvvc6I8G8LniF/qfMmrm7fIKQ8RIDDRZeKyGL2SrWfNqYspuLShbnjBMVWm8g==",
"license": "MIT",
"dependencies": {
"color-convert": "^0.5.2",
"color-name": "^1.1.4",
"css-unit-converter": "^1.1.2"
}
},
"node_modules/css-unit-converter": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/css-unit-converter/-/css-unit-converter-1.1.2.tgz",
"integrity": "sha512-IiJwMC8rdZE0+xiEZHeru6YoONC4rfPMqGm2W85jMIbkFvv5nFTwJVFHam2eFrN6txmoUYFAFXiv8ICVeTO0MA==",
"license": "MIT"
},
"node_modules/esbuild": {
"version": "0.25.3",
"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.3.tgz",

View File

@ -10,5 +10,8 @@
},
"devDependencies": {
"vite": "^6.3.1"
},
"dependencies": {
"badge-maker": "^4.1.0"
}
}

BIN
public/assets/_icon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 728 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 106 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 145 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 170 KiB

BIN
public/assets/docs/uml.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 197 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 728 B

After

Width:  |  Height:  |  Size: 5.4 KiB

View File

@ -1,159 +0,0 @@
export class Cat {
constructor(x, y, targetSize) {
this.x = x;
this.y = y;
this.size = 171;
this.targetSize = targetSize;
this.sprite = null;
this.loaded = false;
this.velocity = 24;
this.count = 0;
loadImage('assets/cat.webp', (img) => {
this.sprite = new Sprite(this.x, this.y, this.size, this.size);
this.sprite.spriteSheet = img;
this.sprite.anis.offset.y = 3;
this.sprite.anis.frameDelay = 8;
this.sprite.friction = 0;
this.sprite.addAnis({
jump: { row: 0, frames: 4 },
death: { row: 1, frames: 4 },
hurt: { row: 2, frames: 2 },
idle: { row: 3, frames: 4 },
walk: { row: 4, frames: 6 }
});
this.sprite.changeAni('idle');
const scaleFactor = this.targetSize / 171;
this.sprite.scale = scaleFactor;
this.loaded = true;
});
}
update() {
if (!this.sprite) return;
console.log(`updating sprite...`);
this.sprite.position.x = this.x;
this.sprite.position.y = this.y;
if (kb.pressing('left')) {
console.log("accepting pressed kb");
this.sprite.vel.x = -1;
} else if (kb.pressing('right')) {
this.sprite.vel.x = 1;
} else {
this.sprite.vel.x = 0; // Stop the hero if no keys are pressed
}
};
draw() {
if (!this.sprite) return;
// this.sprite.draw();
this.sprite.update();
};
changeAni(key) {
if (!this.sprite) return;
switch (key) {
case 'w':
this.sprite.changeAni("walk");
break;
case 'j':
this.sprite.changeAni("jump");
break;
case 'i':
this.sprite.changeAni("idle");
break;
case 'h':
this.sprite.changeAni("hurt");
break;
case 'd':
this.sprite.changeAni("death");
break;
default:
break;
};
};
setPosition(x, y) {
if (this.sprite) {
this.sprite.position.x = x;
this.sprite.position.y = y;
};
};
keyPressed(key) {
if (key === 'ArrowRight') {
this.moveRight();
}
}
remove() {
if (!this.sprite) return;
this.sprite.remove();
this.sprite = null;
}
/// i want to add this part to move sprite across the canvas when user presses right arrow
// if (kb.presses('right')) {
// this.move(30, 'right', 3)
// }
move(direction){
if (!direction) return;
console.log(`entered move method`);
if (direction == "right") this.moveRight();
if (direction == "up") this.moveUp();
}
moveRight(){
console.log(`${this.count}`);
this.changeAni('w')
this.sprite.vel.x = 1;
this.count += 1;
}
moveUp(){
console.log(`sprite should move up...`);
this.changeAni('j')
}
runCat(steps){
steps.forEach(element => {
setTimeout(() => {
console.log(element)
}, 1000);
});
}
// helper
_getSpritePosition(){
console.log(`sprite's actual position: ${this.sprite.x}, ${this.sprite.y}`);
return (this.sprite.x, this.sprite.y);
}
_translate(step){
switch (step) {
case 'up':
console.log('move: up');
return 'jump'
break;
case 'right':
console.log('move: down');
return 'walk'
break;
case 'down':
console.log('move: up');
return 'jump'
break;
default:
break;
}
}
}

View File

@ -28,7 +28,7 @@ export class Cat {
this.size = img.height / 5;
this.sprite = new Sprite(this.x, this.y, this.size, this.size, 'dynamic');
console.log(`sprite made at ${this.x}, ${this.y}`);
//console.log(`sprite made at ${this.x}, ${this.y}`);
this.sprite.rotationLock = true;
this.sprite.bounciness = 0.1;
this.sprite.spriteSheet = img;
@ -52,12 +52,14 @@ export class Cat {
// this.sprite.anis.offset.x = this.targetSize / 4;
this.loaded = true;
this._debug();
});
}
update() {
if (!this.sprite || this.steps.length === 0) return;
// console.log(`updating sprite...`);
// //console.log(`updating sprite...`);
if (this.isMoving) {
this._continueMovement();
@ -75,6 +77,8 @@ export class Cat {
}
_startMovement(direction) {
//console.log('start');
//console.log(`[startMovement] called with direction: ${direction}`);
this.moveDirection = direction;
this.stepTimer = 0;
this.isMoving = true;
@ -123,6 +127,8 @@ export class Cat {
}
_continueMovement() {
//console.log('continue');
//console.log(`[startMovement] called with direction: ${this.moveDirection}`);
this.stepTimer++;
let isOnPlatform = this._checkPlatform();
@ -142,6 +148,7 @@ export class Cat {
}
if (this.moveDirection === 'up' && isOnPlatform && !this.hasJumped) {
//console.log(`up called with direction: ${this.moveDirection}. inside the handler`);
this.changeAni('j');
this.sprite.vel.y = -20;
@ -152,9 +159,11 @@ export class Cat {
} else {
this.sprite.vel.x = 0;
}
this.hasJumped = true;
}
this.hasJumped = true;
if (this.stepTimer >= this.stepDuration) {
this.isMoving = false;
@ -182,22 +191,15 @@ export class Cat {
}
restart() {
console.log('resetting initial position.....');
//console.log('resetting initial position.....');
if (!this.sprite) return null;
this.sprite.x = this.x;
this.sprite.y = this.y;
console.log(`sprite re-made at ${this.x}, ${this.y}`);
//console.log(`sprite re-made at ${this.x}, ${this.y}`);
this.sprite.vel.x = 0;
this.sprite.vel.y = 0;
// this.sprite.scale = this.targetSize / this.size;
// this.sprite.mirror.x = false;
// this.sprite.rotation = 0;
// this.sprite.rotationSpeed = 0;
// this.sprite.anis.offset.x = this.shiftOffset + this.targetSize / 4;
this.steps = [];
this.currentStepIndex = 0;
@ -206,13 +208,19 @@ export class Cat {
this.moveDirection = null;
// this.targetX = null;
// this.targetY = null;
// TRIAL PLS WORK
this.lastDirection = null;
this.hasJumped = false;
this.changeAni('i');
this._debug();
}
keyPressed(key) {
console.log(`receiving keyboard input: ${key}`);
//console.log(`receiving keyboard input: ${key}`);
}
draw() {
@ -271,22 +279,22 @@ export class Cat {
// helper
_getSpritePosition(){
console.log(`sprite's actual position: ${this.sprite.x}, ${this.sprite.y}`);
//console.log(`sprite's actual position: ${this.sprite.x}, ${this.sprite.y}`);
return (this.sprite.x, this.sprite.y);
}
_translate(step){
switch (step) {
case 'up':
console.log('move: up');
//console.log('move: up');
return 'jump'
break;
case 'right':
console.log('move: down');
//console.log('move: down');
return 'walk'
break;
case 'down':
console.log('move: up');
//console.log('move: up');
return 'jump'
break;
default:
@ -295,7 +303,41 @@ export class Cat {
}
_handleInput(){
// console.log('assume i have something....');
// //console.log('assume i have something....');
}
_debug() {
//console.log("===== CAT DEBUG INFO =====");
//console.log(`Position: (${this.x}, ${this.y})`);
//console.log(`Target Size: ${this.targetSize}`);
//console.log(`Current Size: ${this.size}`);
//console.log(`Velocity: ${this.velocity}`);
//console.log(`Block Size: ${this.blockSize}`);
//console.log(`Step Duration: ${this.stepDuration}`);
//console.log(`Current Step Index: ${this.currentStepIndex}`);
//console.log(`Is Moving: ${this.isMoving}`);
//console.log(`Move Direction: ${this.moveDirection}`);
//console.log(`Last Direction: ${this.lastDirection}`);
//console.log(`Has Jumped: ${this.hasJumped}`);
//console.log(`Loaded: ${this.loaded}`);
//console.log(`Shift Offset: ${this.shiftOffset}`);
//console.log(`Ground Ref:`, this.ground);
//console.log(`Obstacles Ref:`, this.obstacles);
if (this.sprite) {
//console.log("Sprite Info:");
//console.log(` Sprite Position: (${this.sprite.x}, ${this.sprite.y})`);
//console.log(` Sprite Size: ${this.sprite.width} x ${this.sprite.height}`);
//console.log(` Sprite Scale: ${this.sprite.scale}`);
//console.log(` Sprite Rotation Locked: ${this.sprite.rotationLock}`);
//console.log(` Sprite Bounciness: ${this.sprite.bounciness}`);
//console.log(` Sprite Friction: ${this.sprite.friction}`);
//console.log(` Sprite Ani Offset: x=${this.sprite.anis.offset.x}, y=${this.sprite.anis.offset.y}`);
//console.log(` Current Animation: ${this.sprite.animation.name}`);
} else {
//console.log("Sprite not yet loaded.");
}
//console.log("===========================");
};
}

View File

@ -7,7 +7,6 @@ import Level1 from './scenes/lvl1.js';
import Level2 from './scenes/lvl2.js';
import Level3 from './scenes/lvl3.js';
let mgr;
function setup(){
@ -19,7 +18,6 @@ function setup(){
mgr = new SceneManager();
mgr.addScene(StartScene);
// mgr.addScene(GameScene);
mgr.addScene(Level1);
mgr.addScene(Level2);
mgr.addScene(Level3);

View File

@ -6,6 +6,7 @@ import { ClickableArrow } from '../components/ClickableArrow.js';
import { ControlPanel } from '../components/controlPanel.js';
import { Flag } from "../components/Flag.js";
import { Key } from '../components/Key.js';
import StartScene from './startScene.js';
export default function Level3() {
@ -18,15 +19,15 @@ export default function Level3() {
const worldBlockSize = 125;
const groundHeight = worldBlockSize;
const maxIdx = {
x: Math.ceil(windowWidth / worldBlockSize),
x: Math.ceil(windowWidth / worldBlockSize) + 1,
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)],
[...Array(8).fill(0), ...Array(maxIdx.x - 9).fill(1)],
[...Array(6).fill(0), ...Array(maxIdx.x - 7).fill(1)],
[...Array(4).fill(0), ...Array(maxIdx.x - 5).fill(1)],
];
let cat;
@ -81,7 +82,7 @@ export default function Level3() {
text: "next",
mode: "CENTER",
style: buttonM,
onPress: () => console.log(`redirect to next game`),
onPress: () => this.sceneManager.showScene(StartScene),
});
blocks = new ControlPanel({
@ -113,8 +114,8 @@ export default function Level3() {
numBoxes: slots.keys,
});
flag = new Flag(11 * worldBlockSize, height - worldBlockSize * 4, catSize * 0.75, true);
key = new Key(13 * worldBlockSize, height - worldBlockSize * 4.3, catSize * 0.35);
flag = new Flag(10 * worldBlockSize, height - worldBlockSize * 4, catSize * 0.75, true);
key = new Key(12 * worldBlockSize, height - worldBlockSize * 4.3, catSize * 0.35);
for (let i = 0; i < width; i += worldBlockSize) {
let b = new Sprite(
@ -149,7 +150,7 @@ export default function Level3() {
}
// Sprites
cat = new Cat(2.25 * worldBlockSize, height - catSize * 13/12, catSize, blocksGround, blockSprites, worldBlockSize);
cat = new Cat(1.25 * worldBlockSize, height - catSize * 13/12, catSize, blocksGround, blockSprites, worldBlockSize);
};
this.draw = () => {

View File

@ -1,8 +0,0 @@
import { colors } from './utils/theme.js';
export const groundHeight = 100;
export function draw(p, groundHeight) {
fill(colors.secondary);
rect(0, height - groundHeight, width, groundHeight);
}