Interactive(HTML Canvas ・three.js ・game)/CSS・Canvas ・ p5.js ・ Pixi.js
p5.js) 스네이크 게임 구현하기
Bumang
2024. 6. 15. 13:29
게임을 구현한다는건 언제나 복잡한 과제인거 같다.
모든 task를 절차적으로 하기보단 모듈화하여 적재적소에 활용하는 능력이 매우 중요하다는 것을 느꼈고,
이를 p5.js에서 어떻게 사용하는지를 알 수 있는 좋은 튜토리얼이었다.
let cols; let rows;
let size = 25;
let board = [];
let food; let head;
let dir; // head의 진행방향
let length = 1;
let gameOver = false;
function setup() {
createCanvas(400, 400);
frameRate(5); // 너무 빠르지 않게 프레임을 낮춰줌
cols = width/size;
rows = height/size;
for (let i=0; i<cols; i++){
board[i] = [];
for (let j=0; j<rows; j++){
board[i][j] = 0; // 0이 꽉 차있는 2차월 배열을 생성
}
}
food = createVector(int(random(0, cols)), int(random(0, rows))); // 0 ~ 칸 갯수 사이의 난수로 x,y 음식 좌표 생성. int는 p5.js 내장 함수인가 봄..
head = createVector(int(random(0, cols)), int(random(0, rows))); // 0 ~ 칸 갯수 사이의 난수로 x,y head 시작위치 좌표 생성.
dir = createVector(0, 0);
}
function draw() {
background(220);
update();
displayBoard();
board[food.x][food.y] = -1;
if (gameOver == true) {
textAlign(CENTER,CENTER);
fill(0);
textSize(50);
text("GAME OVER", width/2, height/2);
}
}
function update(){ // 5프레임마다 업데이트를 함
head.add(dir);
if(dist(head.x, head.y, food.x, food.y) == 0){ // Food를 먹었으면
length += 1; // length를 +1
generateFood(); // 랜덤 좌표에 food 다시 생성
}
if (head.x < 0 || head.x > cols-1 || head.y < 0 || head.y > rows-1){ // head가 board 바깥으로 넘어갔다면 게임오버
console.log("Game Over: Run Into Border");
gameOver = true;
} else if (board[head.x][head.y] > 1) { // head가 닿은 곳이 1 이상이면 자기 몸체에 닿은거기 때문에 게임오버
console.log("Game Over: Run Into Itself");
gameOver = true;
dir.set(0, 0); // 진행 멈추기
} else {
board[head.x][head.y] = 1 + length; // 현재 head에다가 length + 1을 더함
removeTail(); // 모든 board칸에서 -1을 해주는 함수
}
}
function displayBoard(){ // 0일 때, -1일 때, 1일 때 각각 칸 색상을 다르게 지정
for (let i=0; i<cols; i++){
for (let j=0; j<rows; j++){
if (board[i][j] == 0){
fill(255); // Color the board white
} else if(board[i][j] == -1){
fill(255, 0, 0); // Color the food red
} else {
fill(255, 255, 0); // Color the snake yellow
}
rect(i*size, j*size, size, size);
// displayText(i, j);
}
}
}
function generateFood(){ // food를 랜덤 좌표에 생성
while(true){
food = createVector(int(random(0, cols-1)), int(random(0, rows-1)));
if (board[food.x][food.y] == 0){ // food.x, food.y가 0이라면 ok
break;
}
}
}
function removeTail(){ // 모든 칸에 -1을 해주는 함수
for (let i=0; i<cols; i++){
for (let j=0; j<rows; j++){
if(board[i][j] > 0){
board[i][j] -= 1;
}
}
}
}
function displayText(x, y){ // gameover 텍스트를 띄워줌
textAlign(CENTER, CENTER);
fill(0);
textSize(10);
text(board[x][y], x*size+size/2, y*size+size/2);
}
function keyPressed(){ // 키보드 입력에 따라 vector 방향을 바꿔줌
if (keyCode === LEFT_ARROW) {
dir = createVector(-1, 0);
} else if (keyCode === RIGHT_ARROW) {
dir = createVector(1, 0);
} else if (keyCode === DOWN_ARROW) {
dir = createVector(0, 1);
} else if (keyCode === UP_ARROW) {
dir = createVector(0, -1);
}
}