본문 바로가기

JS - 허들넘기 / canvas태그 본문

개발/JavaScript

JS - 허들넘기 / canvas태그

자전하는명왕성 2023. 1. 5. 19:16

 

유튜브에서 흥미로운 걸 발견해서 따라해보았다.

본 영상은 공룡이 선인장을 피하는 게임이지만, 이미지만 바꿨다.

 

어쨌든 오늘 해본 클론 코딩에서 흥미로운 점이 있다면, HTML에 무언가를 그려낼 수 있다는 점이었다.

 

 

캔버스 태그는 기본적으로, 자바스크립트 등을 이용하여 그래픽 콘텐츠를 그릴 때 활용한다.

사실 태그 자체로 무언가를 한다고 하기보다는, HTML 내에 도화지를 제공한다는 개념에 가깝다.

canvas 의 사이즈는 이렇게 잡았다. 이 정도가 딱 보기 편했다.

let canvas = document.querySelector("canvas");
canvas.width = window.innerWidth - 200; // 네이게이션 창을 제외한 너비
canvas.height = window.innerHeight - 200; // 네이게이션 창을 제외한 높이
let ctx = canvas.getContext("2d"); // '2d' 그리기 가능

추가로 getContext() 메서드를 활용해서 '그리기 함수'를 사용할 수 있는데, 2d 그래픽의 경우 '2d'라고 지정해 줄 수 있다.

let person = {
    // 사람 등장 좌표
    x: 10, 
    y: 200,
    width: 50,
    height: 50,
    draw() {
        ctx.drawImage(personImg, this.x, this.y , this.width, this.height)
        // ctx.fillStyle = "green"; // 색상 지정 가능
        // 10px 10px 위치 // 100 * 100 사이즈
        // ctx.fillRect(this.x, this.y, this.width, this.height); // fillRect 사각형 만들어주는 함수
    },
}

 

HTML 내 구현한 '사람'에 대해 얘기하자면 위와 같다.

등장 좌표는 x축 10px, y축 200px. 그리고 길이와 높이를 모두 50px로 지정해 사각형 모양을 만들었다.

'허들'도 비슷한 방식이다.

 

허들에서 중요한 점은 프레임에 따라 허들의 좌표가 변경된다는 점인데, 이는 아래와 같이 구현했다.

let timer = 0; // 프레임마다 타이머 증가, 허들 규칙적인 허들을 만들기 위해 활용
let hurdleArr = [];
let animation;

function render() {
    animation = requestAnimationFrame(render); // 애니메이션을 프레임마다 동작시켜주는 메서드
    timer++;
    // clearRect 를 통해 프레임마다 이동시키며 지우는 것이 가능
    ctx.clearRect(0, 0, canvas.width, canvas.height);

    if (timer % 200 == 0) { // 200프레임마다 허들이 만들어짐
        let hurdle = new Hurdle();
        hurdleArr.push(hurdle);
    }
    hurdleArr.forEach((a, i, o) => {
        // x좌표가 0 미만이면 제거
        if(a.x < 0){
            o.splice(i,1)
            catchMe.textContent++ // 허들이 x축 끝에 도착해 사라지면, HTML내 통과한 횟수로 기록
        }
        // 프레임마다 hurdleArr가 x축으로 -1.5만큼 1프레임마다 이동
        a.x-= 1.5;

        accident(person, a) // 충돌에 대한 함수, 이후 설명

        a.draw()
    })

 

다음은 캐릭터가 허들을 넘기 위한 점프에 관한 부분이다.

// Z키를 눌렀을 시 점프 // window.event를 'e'라는 약어로 쓸 수 있음
let jumping = false;
document.addEventListener('keydown',function(e){
    if(e.keyCode === 90){
        jumping = true
    }
})

let jumpTimer = 0;

function render() {

	// 중략 // 
    // 점프를 눌렀을 경우
    if(jumping == true){
        person.y--; // person 의 y좌표 --. 점프.
        jumpTimer++;
    }
    // y좌표 200미만시 내려가지 않음
    if (jumping == false){
        if(person.y < 200) // person의 최고 점프력 200으로 제한
        person.y++ // 점프 y축 -200 도달 시 추락
    }
    if(jumpTimer > 100){
        jumping = false
        jumpTimer = 0
    }
}

 

다음은 캐릭터와 허들이 충돌했을 경우 게임을 멈추게 하는 함수이다.

이때, accident() 는 person과 허들 배열(hurdleArr)인 a를 전달인자로 받는다.

// 충돌 확인
function accident (person, hurdle){
    let xDiffer = hurdle.x - (person.x + person.width) // 허들과 사람의 x축 차이
    let yDiffer = hurdle.y - (person.y + person.height) // y축 차이
    if(xDiffer < -20 && yDiffer < -20) { // 난이도를 위해 히트박스에 여유를 두었다
        ctx.clearRect(0,0, canvas.width, canvas.height)
        cancelAnimationFrame(animation) // 충돌 시 멈춤
    }
}

 

마지막 재시작하는 함수

const reGameStart = function () {
    hurdleArr = [] // 진행되고 있던 허들 배열을 비우고
    window.requestAnimationFrame(render) // render()를 새로 시작한다.
}

Comments