20243197 #12

Closed
20243197 wants to merge 30 commits from 20243197/20243197:20243197 into 20243197
16 changed files with 7364 additions and 19 deletions

View File

@ -7,23 +7,7 @@ URL: http://git.prototyping.id/20243197/20243197
## Game : BABA is YOU ## Game : BABA is YOU
Game Link: [link(steam)](https://store.steampowered.com/app/736260/Baba_Is_You/) Game Link: [link(steam)](https://store.steampowered.com/app/736260/Baba_Is_You/)
Genra: Word Puzzle Game Genra: Word Puzzle Game
### Elements User Contol: ASDW
- Objects (Sprite)
- Baba![(character)](assets/Baba.webp)
- Rock![rock](assets/Rock.webp)
- Flag![Flag](assets/Flag.webp)
- Terrain (Blocking)
- Tile(floor) ![tile](assets/Tile.webp)
- Wall(initailly blocking)![wall](assets/Wall.webp)
- lava ![(lava)](assets/Lava.webp)
- Water ![(water)](assets/Water.webp)
- etc..
- Properties (Action)
- You ![you](assets/You.webp)
- Move ![Move](assets/Move.webp)
- Stop ![Stop](assets/Stop.webp)
- Win ![win](assets/Win.webp)
- etc
### What does the players have to do? ---> Win! ### What does the players have to do? ---> Win!
![Play](assets/BabaPlayEx.gif) ![Play](assets/BabaPlayEx.gif)
@ -34,7 +18,55 @@ Genra: Word Puzzle Game
You make the rules by combining the objects and words (properties). You make the rules by combining the objects and words (properties).
And according to the rules you play the game(*move around and touch the 'win'.*) And according to the rules you play the game(*move around and touch the 'win'.*)
move baba and push the words to make rules. Then within the rules you made, reach the 'win' object and win the stage.
### Elements
| Objects | Image | Instructions |
| :------ | :---: | :----------- |
| Baba | <img src="assets/Baba.webp" width="40px"> | initial main caracter. Moves with ASDW |
| Rock | <img src="assets/Rock.webp" width="40px"> | |
| Flag | <img src="assets/Flag.webp" width="40px"> | |
### Terrain (Blocking)
| Objects | Image | Instructions |
| :------ | :---: | :----------- |
| Tile(floor) | <img src="assets/Tile.webp" width="40px"> | |
| Wall(initailly blocking) | <img src="assets/Wall.webp" width="40px"> | |
| lava | <img src="assets/Lava.webp" width="40px"> | |
| Water | <img src="assets/Water.webp" width="40px"> | |
| etc.. |
### Properties (Indicator)
| Objects | Image | Instructions |
| :------ | :---: | :----------: |
| BABA | <img src="assets/Text_BABA.webp" width="40px"> | <img src="assets/Baba.webp" width="40px"> |
| Rock | <img src="assets/Text_ROCK.webp" width="40px"> | <img src="assets/Rock.webp" width="40px"> |
| Flag | <img src="assets/Text_FLAG.webp" width="40px"> | <img src="assets/Flag.webp" width="40px"> |
| Wall | <img src="assets/Text_WALL.webp" width="40px"> | <img src="assets/Wall.webp" width="40px"> |
| Lava | <img src="assets/Text_LAVA.webp" width="40px"> | <img src="assets/Lava.webp" width="40px"> |
| Water | <img src="assets/Text_WATER.webp" width="40px"> | <img src="assets/Water.webp" width="40px"> |
| etc...
### Properties (Operator)
| Objects | Image | Instructions |
| :------ | :---: | :----------- |
| IS | <img src="assets/Text_IS.webp" width="40px"> | Operator |
### Properties (Action)
| Objects | Image | Instructions |
| :------ | :---: | :----------- |
| You | <img src="assets/You.webp" width="40px"> | |
| Move | <img src="assets/Move.webp" width="40px"> | |
| Win | <img src="assets/Win.webp" width="40px"> | |
| Stop | <img src="assets/Stop.webp" width="40px"> | |
| Hot | <img src="assets/Hot.webp" width="40px"> | |
| Sink | <img src="assets/Sink.webp" width="40px"> | if something goes to this tile, it sinks and the tile becomes 'tile'. |
| etc...
### How will the game look like? ### How will the game look like?
Environment: tile based.
To build the scene described above, I plan to develop the game using modular rules, where each interaction and game logic is handled through well-structured functions. To build the scene described above, I plan to develop the game using modular rules, where each interaction and game logic is handled through well-structured functions.
`+`...If I can AI generate the stages of 'baba is you', that will be my final goal of this project. `+`...If I can AI generate the stages of 'baba is you', that will be my final goal of this project.
@ -43,3 +75,27 @@ Genra: Word Puzzle Game
1. Make the rules work. 1. Make the rules work.
2. Make the elements to be interchangeable. 2. Make the elements to be interchangeable.
3. Make the World. (can I AI generate this?) 3. Make the World. (can I AI generate this?)
### Documentations
- Tile based
### LOG
| DATE | Updates |
| :--: | :-------------- |
| 2025.04.14 | Updated the Markdown, initial creation of the project |
| 2025.04.15 | Create the folders and js files. Create the HTML, CSS for the projects. |
| 2025.04.19 | Put sprites, make initial stage. |
| 2025.04.20 | Done with initial stage, but no move rock. |
### TODO
- Add Move Script
- Add Sprite Combination Script
- Make Rules Modul-able
- Make sprites as animation
- Put in Sound Effects
- Add 'Start Game', 'Pause Game'
- Make 'Game Over', 'Congrats' good looking
### Reference
https://youtu.be/M5St-vvohzs

Binary file not shown.

BIN
assets/Hot.webp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 552 B

BIN
assets/Sink.webp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 742 B

BIN
assets/Text_BABA.webp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 420 B

BIN
assets/Text_FLAG.webp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 398 B

BIN
assets/Text_IS.webp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 296 B

BIN
assets/Text_LAVA.webp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 410 B

BIN
assets/Text_ROCK.webp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 420 B

BIN
assets/Text_WALL.webp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 382 B

BIN
assets/Text_WATER.webp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 416 B

26
index.html Normal file
View File

@ -0,0 +1,26 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<link rel="stylesheet" href="./style.css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.5.0/p5.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.5.0/addons/p5.sound.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/p5.play@3/p5play.js"></script>
<script src="https://cdn.jsdelivr.net/npm/planck@latest/dist/planck.min.js"></script>
<!-- <script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.11.2/p5.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.11.2/addons/p5.sound.min.js"></script> -->
<!-- <script src="lib/p5.play.js" type="text/javascript"></script> -->
<!-- <script src="https://cdn.jsdelivr.net/gh/molleindustria/p5.play/lib/p5.play.js"></script> -->
<script src="./main.js"></script>
</head>
<body>
</body>
</html>

6764
lib/p5.play.js Normal file

File diff suppressed because it is too large Load Diff

489
main.js Normal file
View File

@ -0,0 +1,489 @@
// alert("hello world");
const tileSize = 24;
// Sprites
let baba_img;
let tile_img, wall_img, rock_img, water_img, lava_img, flag_img;
let win_img, you_img, move_img, stopText_img;
let is_img;
// Map
let tileMap = [
' ',
'wwwwwwwwwwwwwwww',
'w,,,,,,,,,,,,,,w',
'w,,,,,,,,,(ih,,w',
'w,$im,,,,,,,,,,w',
'w,,,,,,,,,)ik,,w',
'w,,,,r,,,,,,,,,w',
'w, ,,w,,,,,,,,,w',
'w,,,,r,,,ll,,r,w',
'w,,,,,,,,ll,rfrw',
'w,,,,aa,,,w,,r,w',
'w,,,,aa,,,w,,,,w',
'w,,,,,,,,,,,,,,w',
'w,*i@,,,,,^i#,,w',
'w,%is,,,,,,,,,,w',
'wwwwwwwwwwwwwwww',
];
// let rules = [
// ["rock", "is", "push"],
// ["wall", "is", "stop"],
// ["water", "is", "sink"],
// ["lava", "is", "hot"]
// ]
let rules = [];
// CaracterMove
let babaX = 0;
let babaY = 0;
// Sounds
let bgm, winSound;
let isPlaying = false;
// Game State
let isGameOver = false;
let isWin = false;
function preload(){
// BGM
bgm = loadSound("/assets/Baba Is You OST - Baba Is You Theme.mp3");
// Spritesd
baba_img = loadImage("/assets/Baba.webp");
tile_img = loadImage("/assets/Tile.webp");
wall_img = loadImage("/assets/Wall.webp");
rock_img = loadImage("/assets/Rock.webp");
water_img = loadImage("/assets/Water.webp");
lava_img = loadImage("/assets/Lava.webp");
flag_img = loadImage("/assets/Flag.webp");
is_img = loadImage("/assets/Text_IS.webp");
win_img = loadImage("/assets/Win.webp");
you_img = loadImage("/assets/You.webp");
stop_img = loadImage("/assets/Stop.webp");
move_img = loadImage("/assets/Move.webp");
hot_img = loadImage("/assets/Hot.webp");
sink_img = loadImage("/assets/Sink.webp");
wall_text_img = loadImage("/assets/Text_WALL.webp");
water_text_img = loadImage("/assets/Text_WATER.webp");
lava_text_img = loadImage("/assets/Text_LAVA.webp");
stopText_img = loadImage("/assets/Stop.webp");
baba_text_img = loadImage("/assets/Text_BABA.webp");
flag_text_img = loadImage("/assets/Text_FLAG.webp");
rock_text_img = loadImage("/assets/Text_ROCK.webp");
}
function setup(){
createCanvas(400, 400);
// new World();
background(51);
textAlign(CENTER);
let startButton = createButton("▶ PLAY");
startButton.position(width / 2 - 30, height / 2 - 20);
startButton.mousePressed(() => {
isPlaying = true;
bgm.loop();
startButton.remove();
setGame();
});
}
function setGame(){
rules = [];
allSprites.removeAll();
// Floor - Tile
let tile = new Group();
tile.img = tile_img;
tile.collider = 'none';
tile.tile = ",";
tile.scale = tileSize/tile_img.width;
tile.layer = 0;
tile.label = 'tile';
// Flag
let flag = new Group();
flag.img = flag_img;
flag.collider = 'none';
flag.tile = "f";
flag.scale = tileSize/flag_img.width;
flag.layer = 1;
flag.label = 'flag';
// WALL
let wall = new Group();
wall.img = wall_img;
wall.collider = 'static';
wall.tile = "w";
wall.scale = tileSize/wall_img.width;
wall.layer = 1;
wall.label = 'wall';
// ROCK
let rock = new Group();
rock.img = rock_img;
rock.collider = 'dynamic';
rock.tile = "r";
rock.label = 'rock';
rock.scale = tileSize/rock_img.width;
rock.layer = 2;
// Water
let water = new Group();
water.img = water_img;
water.collider = 'none';
water.tile = 'a';
water.label = 'water';
water.scale = tileSize/water_img.width;
water.layer = 1;
// Lava
let lava = new Group();
lava.img = lava_img;
lava.collider = 'none';
lava.tile = 'l';
lava.label = 'lava';
lava.scale = tileSize/lava_img.width;
lava.layer = 1;
// TEXTS
// is
let is = new Group();
is.img = is_img;
is.collider = 'static';
is.tile = 'i';
is.scale = tileSize/is_img.width;
is.label = 'is';
// flag_text
let flag_text = new Group();
flag_text.img = flag_text_img;
flag_text.collider = 'dynamic';
flag_text.tile = '^';
flag_text.scale = tileSize/flag_text_img.width;
flag_text.layer = 2;
flag_text.label = 'flag';
// baba_text
let baba_text = new Group();
baba_text.img = baba_text_img;
baba_text.collider = 'dynamic';
baba_text.tile = '*';
baba_text.scale = tileSize/baba_text_img.width;
baba_text.layer = 2;
baba_text.label = 'baba';
// rock_text
let rock_text = new Group();
rock_text.img = rock_text_img;
rock_text.collider = 'dynamic';
rock_text.tile = '$';
rock_text.scale = tileSize/rock_text_img.width;
rock_text.layer = 2;
rock_text.label = 'rock';
// lava_text
let lava_text = new Group();
lava_text.img = lava_text_img;
lava_text.collider = 'dynamic';
lava_text.tile = '(';
lava_text.scale = tileSize/lava_text_img.width;
lava_text.layer = 2;
lava_text.label = 'lava';
// water_text
let water_text = new Group();
water_text.img = water_text_img;
water_text.collider = 'dynamic';
water_text.tile = ')';
water_text.scale = tileSize/water_text_img.width;
water_text.layer = 2;
water_text.label = 'water';
// wall_text
let wall_text = new Group();
wall_text.img = wall_text_img;
wall_text.collider = 'dynamic';
wall_text.tile = '%';
wall_text.scale = tileSize/wall_text_img.width;
wall_text.layer = 2;
wall_text.label = 'wall';
// you
let you = new Group();
you.img = you_img;
you.collider = 'dynamic';
you.tile = '@';
you.scale = tileSize/you_img.width;
you.layer = 2;
you.label = 'you_text';
// win
let win_text = new Group();
win_text.img = win_img;
win_text.collider = 'dynamic';
win_text.tile = '#';
win_text.scale = tileSize/win_img.width;
win_text.layer = 2;
win_text.label = 'win';
// stop
let stop = new Group();
stop.img = stop_img;
stop.collider = 'dynamic';
stop.tile = 's';
stop.scale = tileSize/stop_img.width;
stop.layer = 2;
stop.label = 'stop';
// move
let move = new Group();
move.img = move_img;
move.collider = 'dynamic';
move.tile = 'm';
move.scale = tileSize/move_img.width;
move.layer = 2;
move.label = 'move';
// hot
let hot = new Group();
hot.img = hot_img;
hot.collider = 'dynamic';
hot.tile = 'h';
hot.scale = tileSize/hot_img.width;
hot.layer = 2;
hot.label = 'hot';
// sink
let sink = new Group();
sink.img = sink_img;
sink.collider = 'dynamic';
sink.tile = 'k';
sink.scale = tileSize/sink_img.width;
sink.layer = 2;
sink.label = 'sink';
new Tiles(tileMap, tileSize/2, tileSize/2, tileSize, tileSize);
//BABA
respawn();
}
function drawMessageBox(msg){
const boxWidth = 300;
const boxHeight = 100;
const x = width / 2 - boxWidth / 2;
const y = height / 2 - boxHeight / 2;
fill(0, 0, 0, 200);
noStroke();
rect(x, y, boxWidth, boxHeight, 20);
fill(255);
textSize(20);
textAlign(CENTER, CENTER);
textLeading(26);
text(msg, width / 2, height / 2);
}
function draw(){
background(10);
drawSprites();
if (isGameOver) {
drawMessageBox("Game Over! Press R to Restart");
} else if (isWin) {
drawMessageBox("Congratulations! Press R to Restart");
}
}
// Background Music & Soundeffects
function backgroundMusic(){
}
// Move ASDW
function keyPressed(){
console.log(`key ${key} is pressed.`)
if(key=='r'||key=='R'){
resetGame();
}
if(isGameOver || isWin){
if(key=='r'||key=='R'){
resetGame();
}
return;
}
let dx = 0;
let dy = 0;
if (key === 'a' || key === 'A') dx = -tileSize;
if (key === 'd' || key === 'D') dx = tileSize;
if (key === 'w' || key === 'W') dy = -tileSize;
if (key === 's' || key === 'S') dy = tileSize;
if (dx !== 0 || dy !== 0) {
allSprites
.filter(s => s.label === 'you')
.forEach(sprite => isMove(sprite, dx, dy));
}
}
function getSpriteAt(i, j) {
const x = i * tileSize + tileSize / 2;
const y = j * tileSize + tileSize / 2;
return allSprites.find(s => dist(s.x, s.y, x, y) < tileSize / 2);
}
function ruleMaker(){
rules = [];
allSprites.forEach(s => {
if(s.tile == 'i'){
const i = floor(s.x / tileSize);
const j = floor(s.y / tileSize);
const left = getSpriteAt(i-1, j);
const right = getSpriteAt(i+1, j);
if(left && right){
const noun = left.label;
const verb = right.label;
rules.push([noun, "is", verb]);
console.log("left : " + noun);
console.log("right : " + verb);
}
}
})
console.log("rules : " + JSON.stringify(rules));
}
function runRules(sprite){
const overlapSprite = allSprites.filter(s => s !== sprite && dist(s.x, s.y, sprite.x, sprite.y) < tileSize/2);
overlapSprite.forEach(other => {
rules.forEach(rule => {
const [noun, is, verb] = rule;
if(noun == other.label && verb == "sink"){
other.remove();
if(sprite.label == "you"){
sprite.remove();
gameOver();
} else {
sprite.remove();
}
}
if(noun == other.label && verb == "hot"){
if(sprite.label == "you"){
sprite.remove();
gameOver();
} else {
sprite.remove();
}
}
if(noun == other.label && verb == "win" && sprite.label == "you"){
win();
}
});
});
}
// move only to the opened place
function isOpen(x, y){
let i = floor(x / tileSize);
let j = floor(y / tileSize);
if (j < 0 || j >= tileMap.length || i < 0 || i >= tileMap[0].length) {
return false;
}
let tile = tileMap[j][i];
if (tile == ' ' || tile == ',' || tile == 'a' || tile == 'l' || tile == 'f'){
return true;
} else {
console.log('blocked');
return false;
}
}
function isMove(sprite, dx, dy){
const tx = sprite.x + dx;
const ty = sprite.y + dy;
const targets = allSprites.filter(s => dist(s.x, s.y, tx, ty) < tileSize / 2);
for (let t of targets) {
if (t === sprite) continue;
if (t.collider === 'static') return false;
if (t.collider === 'dynamic') {
const pushed = isMove(t, dx, dy);
if (!pushed) return false;
}
}
sprite.x += dx;
sprite.y += dy;
ruleMaker();
runRules(sprite);
return true;
}
function win(){
isWin = true;
isPlaying = false;
baba.remove();
}
function gameOver(){
isGameOver = true;
isPlaying = false;
baba.remove();
}
function resetGame(){
isGameOver = false;
isWin = false;
allSprites.removeAll();
bgm.stop();
setup();
// respawn();
}
function respawn(){
baba = new Sprite((tileSize*5)/2, (tileSize*15)/2, tileSize, tileSize);
baba.img = baba_img;
baba.scale = tileSize / baba_img.width;
baba.label = 'you';
}

10
style.css Normal file
View File

@ -0,0 +1,10 @@
body{
background-color: aquamarine;
margin: 0;
padding: 0;
overflow: hidden;
}
canvas {
display: block;
}