Javascript 탈출 게임 (1)

정종찬·2022년 4월 26일

const canvas = document.getElementById('myCanvas');
const context = canvas.getContext('2d');


document.addEventListener('keydown', keyPush);

const fieldWidth = 40;
const fieldHeight = 40;
const fieldColumn = 10;
const fieldRow = 10;
const fields = [];
const charRadius = 20;
let charPosX = charRadius;
let charPosY = canvas.height - charRadius;
let charMoveDirX = -1;
let charMoveDirY = -1;
let charMoveSpd = 2;

let fieldColor = ["lightpink", "lightsalmon", "gold", "lightgreen", "lightblue", "powderblue", "violet"];

class Field {
    constructor(left, top, right, bottom, column, row, color, charstat) {
        this.left = left; 
        this.top = top;
        this.right = right;
        this.bottom = bottom;
        this.column = column;
        this.row = row;
        this.color = color;
        this.charstat = charstat
    }
    draw() {
        context.beginPath();
        context.rect(this.left, this.top, fieldWidth, fieldHeight);
        context.fillStyle = fieldColor[this.color%7];
        context.fill();
        context.closePath();
    }
}

class Exit extends Field{
}
let exit = new Exit(
    380 - (fieldWidth) / 2 ,        // left 380 - 20    360
    20 - (fieldHeight) / 2,          // top 20 - 20     0
    380 + (fieldWidth) / 2,        // right 380 + 20    400
    20 + (fieldHeight) / 2,       // bottom 20 + 20     40
    1,                        
    1,
)

class Char extends Field{
    constructor(left, top, right, bottom, hp, money) {
        super(left, top, right, bottom)
        this.hp = hp;
        this.money = money;
    }
        drawChar()
        {
            context.beginPath();

            context.arc(charPosX, charPosY, charRadius, 0, 2 * Math.PI);
            context.fillStyle = 'aqua';
            context.fill();

            context.closePath();
        }
}
let char = new Char(
    charPosX-20,        // left: ;          20 -20
    charPosY-20,          // top: ;         400 - 20 - 20
    charPosX+20,       // right             20 + 20
    charPosY+20,       // bottom            400 - 20 + 20 
    10,                             // hp
    0,                              // money
)


function keyPush(evt){
    switch(evt.keyCode) {
        case 37: // 왼쪽
            if(charPosX - 20 > 0) {
                charPosX += -40;
                charPosY += 0;
                char.left = charPosX - charRadius;
                char.right = charPosX + charRadius ;
            }
            break;
        case 38: // 윗키
            if(charPosY - 20 > 0) {
                charPosX += 0;
                charPosY += -40;
                char.top = charPosY - charRadius;
                char.bottom = charPosY + charRadius;
            }            
            break;
        case 39: // 오른쪽
            if(charPosX + 20 < canvas.width){
                charPosX += 40;
                charPosY += 0;
                char.left = charPosX - charRadius;
                char.right = charPosX + charRadius;
            }            
            break;
        case 40: // 아래
            if(charPosY + 20 < canvas.height){
                charPosX += 0;
                charPosY += 40;
                char.top = charPosY - charRadius;
                char.bottom = charPosY + charRadius;
            }            
            break;
        default:
            break;
    }
}


function draw()
{
     // 화면 클리어    
     context.clearRect(0, 0, canvas.width-40, canvas.height);
     context.clearRect(360, 40, 40, canvas.height-40);
    //  drawCanavs(); 
     // 그리기     
     drawFields();
     char.drawChar();
}

function drawExit(){
    var img_exit = new Image();
    img_exit.src = "exit.png";
    img_exit.onload = function() 
    {
                context.drawImage(img_exit, exit.left, exit.top, fieldWidth, fieldHeight)
    } 
}

function drawFields()
{   
    let gaming = false;    
    for(let i = 0; i < fieldRow; i++) 
    { 
        for(let j = 0; j < fieldColumn; j++) 
        {              
            if(i != 9 || j != 0 )
            fields[i][j].draw();         
            if(fields[i][j].charstat > 0) gaming = true;
        }
    }
    if(!gaming){
       /*  clear(); */
    }
}

function update()
{
    
    // 충돌확인 어떤경우에도 안부딪히는 상황    
    if(isCollisionExitToChar(char, exit)) // right left top bottom 
    {   
        console.log("충돌!")
        setTimeout(() => {
            window.location.reload();
        alert("clear")
        }, 300);
        
    }    
}

function isCollisionExitToChar(charA, exitB)
{
    // a의 완쪽과 b의 오른쪽
    // a의 오른쪽과 b의 왼쪽
    // a의 아래쪽과 b의 위쪽
    // a의 위쪽과 b의 아래쪽
    if (charA.left >= exitB.right ||     // a의 왼쪽이 더 클때
        charA.right <= exitB.left ||     // b의 왼쪽이 더 클때
        charA.top >= exitB.bottom ||     // a의 탑이 더 클때
        charA.bottom <= exitB.top )      // b의 탑이 더 클때
        {
            return false;
        }
    return true;
}


function setFields()
{       
    for(let i = 0; i < fieldRow; i++) 
    { 
        fields[i] = [];
        for(let j = 0; j < fieldColumn; j++) 
        {              
            fields[i][j] = new Field(
                0 + i * 40,
                0 + j * 40,
                0 + (1+i) * 40,
                0 + (1+j) * 40,
                i,
                j,
                Math.floor((Math.random()*7)+1)
            )            
        }
    }
}

function setExit()
{
    for(let i = 0; i < fieldRow; i++) 
    { 
        exit[i] = [];
        for(let j = 0; j < fieldColumn; j++) 
        {              
            exit[i][j] = new Exit(
                0 + i * 30,
                0 + j * 30,
                0 + (1+i) * 30,
                0 + (1+j) * 30,
                i,
                j,                
            )            
        }
    }
}

// function drawCanavs(){
//     context.beginPath();
//     context.rect(0, 0, canvas.width, canvas.height);
//     context.fillStyle = "rgba(10, 10, 10, 0.1)";
//     context.fill();

//     context.closePath();
// } // 어쩌다보니 암전효과 ㅋㅋ

setExit();
setFields();
drawExit(); 
setInterval(draw, 1000 / 15);
setInterval(update, 1000 / 15);

1차 버전

1. 맵 제작 - 이차원 배열 10 X 10
2. 맵타일 - 오브젝트 or 클래스
3. 플레이어, 탈출구 - 오브젝트 - 클래스
4. 키 입력 처리 - 상하좌우 1칸씩 이동 가능
5. 플레이어가 탈출구에 도착하면 게임 클리어

2차 버전

  1. 몬스터 등장 - 플레이어가 이동할 때 마다 일정 확률로 만날 수 있다.
  2. 전투 - 몬스터와 만나면 가위, 바위, 보 버튼이 생기고 가위, 바위, 보 시스템을 사용해서 전투가 벌어진다.
  3. 전투 - 이기면 0 ~ 100골드 사이에서 랜덤하게 보상 획득
  4. 전투 - 지면 HP 1감소

3차 버전

  1. 맵타일 종류 추가 - 땅, 숲, 늪 등등
  2. 맵타일 종류에 따라 다른 표현 (색, 모양)
  3. 몬스터 종류 추가 - 맵타일 종류에 따라 등장하는 몬스터 변경
  4. 상점 추가 - 맵에 상점 1개 존재
  5. 상점 기능 - 골드를 소모해서 HP회복

4차 버전

  1. 맵 표현 추가(시야 개념)
    1-1. 안가본 영역 - 검은색
    1-2. 기본 영역 - 회색 (탈출구, 상점 표시)
    1-3. 현재 시야 - 밝은 회색 (탈출구, 상점 표시)
  2. 전투시 몬스터 프로필 추가 - 몬스터 종류에 따라 이미지 출력
profile
dalssenger

0개의 댓글