Project/01 Cannon Game

Cannon Game_day7 (2021.10.03) 스테이지 클리어와 게임 초기화면

devyoseph 2021. 10. 4. 01:41
일정 목표를 달성했을 때 새로운 스테이지를 불러와야 한다
그래서 Constructor에서 한 번만 호출해주었던 Stage 인스턴스 정의를 animate로 조건문 안에 집어넣었다
1) 먼저 논리 변수를 true로 시작해 바로 stage1이 시작하도록 했다(당연히 사용된 stage_clear은 false(off)가 된다
2) 그리고 클리어 조건을 달성하면 stage_clear의 값을 true로 만들어 다음 스테이지가 로드된다
let stage_clear = true; //처음에 true값을 주어 시작

class App{
//animate내부에 if문에서 stage_clear가 켜지면 stage_level에 맞는 스테이지를 불러온다
animate(t){
		window.requestAnimationFrame(this.animate.bind(this));
        this.ctx.clearRect(0,0,this.stageWidth,this.stageHeight);
	if(stage_clear === true){
                //스테이지 로드
                this.stage = new Stage(stage_level, this.stageWidth, this.stageHeight);
                this.walls = this.stage.walls;
                this.walls_hor_X = this.stage.walls_hor_X;
                this.walls_hor_Y = this.stage.walls_hor_Y;
                
                //벽돌 배열 생성
                for(let i = 0; i < this.walls.length; i++){
                    for(let j = 0; j < this.walls[i].length; j++){
                        var brick = new Brick(this.walls[i][j],this.walls_hor_X[i][j],this.walls_hor_Y[i][j],
                                    this.stageWidth,this.stageHeight, balls, brick_touch);
                    bricks.push(brick);
                    }
                }
     stage_clear = false;
        }
 }
 }
//모든 블럭이 사라지는 경우를 클리어 조건으로 설정했다(임시)
if(bricks.length == 0){
            stage_clear = true;
        }

 

게임을 시작하기 전 초기화면을 만든다
처음에는 자바스크립트 내에서만 해결하려고 했다
1) 맨 처음 Constructor에서 Start class를 인스턴스하고 draw로 초기화면을 보여준다
2) addEventListener를 통해 'mousemove', 'click'을 활용해 hover시 색이 변하고 누르면 게임이 시작되도록 한다
3) 위 두개의 느낌을 주기 위해 메소드를 각각 만드는데, 게임을 시작해도 메소드들은 실행 중이며
4) 메소드에 정해준 범위를 클릭하면 다시 처음으로 돌아가 게임이 시작되는 문제가 발생했다 (draw는 없어도 기능은 남음)
5) 이것을 극복하기 위해 게임중이 아닐 때만(onGame = false) 초기화면이 나오고 메소드가 실행되도록 했다
export class Start{
    constructor(stageWidth, stageHeight){
        this.stageWidth = stageWidth;
        this.stageHeight = stageHeight;
        this.width = this.stageWidth/3;
        this.height = this.stageHeight/10;
        this.x = (this.stageWidth-this.width)/2;
        this.y = (this.stageHeight-this.height)/2;
        this.centerX = this.x + this.width/2;
        this.centerY = this.y + this.height/2;
    }
//onGame을 통해 게임을 시작했는지 안했는지 알 수 있다
//start_hover를 통해 hover시 서로 다른 그림이 그려진다
    draw(ctx, onGame, start_hover){
        this.start_hover = start_hover;
        
        if(onGame == false){

        if(start_hover == false){
        ctx.fillStyle = 'ivory';
        ctx.fillRect(0, 0, this.stageWidth, this.stageHeight);
        
        ctx.fillStyle = 'gray';
        ctx.fillRect(this.x, this.y, this.width, this.height);
		 }
        }
        
        if(start_hover == true){
            ctx.fillStyle = 'ivory';
            ctx.fillRect(0, 0, this.stageWidth, this.stageHeight);
    
            ctx.fillStyle = 'black';
            ctx.fillRect(this.x, this.y, this.width, this.height);}

        }
    }

}
let start_hover = false;
let onGame= false;

class App{
    constructor(){
  	  //시작
        this.start = new Start(this.stageWidth, this.stageHeight);
        document.addEventListener('mousemove', this.start_hover.bind(this), false);
        document.addEventListener('click', this.start_click.bind(this), false);
        }

animate(t){
        window.requestAnimationFrame(this.animate.bind(this));
        this.ctx.clearRect(0,0,this.stageWidth,this.stageHeight);
        //시작
        if(onGame == false){
            this.start.draw(this.ctx, onGame, start_hover);
        }
//addEventListener의 특성상 항상 메소드는 켜지지만 if문을 통해 onGame이 false일 때만 실행된다
start_hover(e){
        if(onGame == false && (e.clientX >= this.start.x && e.clientX <= this.start.x + this.start.width)
            && (e.clientY >= this.start.y && e.clientY <= this.start.y + this.start.height)){ 
                start_hover = true;
        } else{start_hover =false;}
    }
    start_click(e){
        if(onGame == false && (e.clientX >= this.start.x && e.clientX <= this.start.x + this.start.width)
        && (e.clientY >= this.start.y && e.clientY <= this.start.y + this.start.height) ){
           onGame = true;
        }
    }         
        }

 

자바스크립트로 초기화면을 구현하지 않은 이유
1) CSS의 hover기능을 굳이 이렇게 복잡하게 구현해야하나 고민했고
2) ctx의 텍스트 그리기는 세로 정렬이 복잡했다
3) 또한 비율로 모든 것을 만들고 있는 지금 시점에서 ctx의 텍스트의 크기는 함수화할 수 없었다 (디바이스마다 변형된다)
start.html과 같이 html문서를 하나 더 만든다
app.js와 같이 기본 세팅을 해주지 않고 화면과 링크만 걸어두기로 했다
세로정렬: 디바이스 화면크기에 영향받지 않는 정렬
세로정렬에는 크게 두 가지 방법이 있었다
1) diaplay 속성을 inline-block, line-height를 지정해 기준점을 만들고 vertical-align: middle;
2) 부모태그의 display 속성을 table, 자식태그의 display 속성을 table-cell
*1번의 경우 line-height를 px로 적어줘야하는 단점이 있다. 비율로 조정할 수 없기에 아쉬웠다
*2번의 경우 table-cell은 가운데 정렬은 쉽지만 부모태그와 자식태그의 범위가 같아져 span내부의 hover를 사용해야하는 내 구상과 맞지 않았다
3) 그냥 div를 두 개 만들고 글자 위치를 조정하는 방식을 택했다

 

HTML

<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=Edge">
<meta name="viewport" content="width=device-width", initial-scale=1.0, maximum-scale=1, user-scalable=0">
<link href="style.css" rel="stylesheet">
</head>
<body id="start_background">
  <div id="start_blank">높이 40%</div>
 <div id="start">START</div>
</body>
</html>

 

CSS

#start_background{
    display: inline-block;
    background-color: ivory;
    width: 100%;
    height: 100%;
    vertical-align: middle;
    text-align: center;
    border: 10px solid;
}
#start_blank{
    height: 40%;
    border: 1px solid;
}
#start{
    border: 1px solid;
    color: black;
    display: inline;
    text-align: center;
    font-size: 70px;
}
#start:hover{
    color: red;
}

*hover까지 넣어준다

 

html과 html을 링크로 연결한다
div태그를 a태그로 교체하고 링크의 밑줄을 지워준다
//html에서 start 태그를 a로 변경
<a href="index.html" id = "start">START<a>

//css에서 밑줄제거
#start{
    color: black;
    display: inline;
    text-align: center;
    font-size: 70px;
    
    text-decoration: none;
}