LOL의 미스포츈의 궁처럼 공을 날려 보내봐야겠다.

정해진 각도를 중심으로 퍼져서 날라가는 총알

결과물은 아래와 같다.

deuraegeuhan-banghyangeuro-gong-ssogi-p5js.bryanko555.repl.co

이번에는 p5.js를 써봤다. 

내가 경험한 바로 말하면, p5.js는 그래픽에 도움되는 여러 Javascript명령을 손쉽게 구현할 수 있는 명령으로 대신할 수 있게 해준다. 

예를 들어, 아래와 같은 식이다.

vanila Javascript 원 그리기 p5.js 원 그리기
ctx.beginPath();
ctx.arc(x좌표,y좌표,반지름,0,Math.PI*2)
ctx.stroke();
circle(x좌표,y좌표,반지름);

p5.js를 사용하더라도 Javascript의 기본 개념은 변함 없다. 

p5.js를 사용하려면, html  첫 머리에 코드를 삽입해준다.

<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.2.0/p5.min.js"></script>

 

위와 같이 공을 날리기 위해서 필요한 요소들이다. 

  - 드래그 시작점

  - 드래그 종료점

  - 시작점과 종료점의 거리 (이 거리의 길이를 공의 속도로 사용했다)

  - 시작점과 종료점의 각도 (이 각도를 중심으로 공이 랜덤하게 날라간다)

  - 공이 이동할 때의 x,y 변경 값

드래그 시작점과 종료점은 마우스가 눌려졌을 때(시작)와 마우스가 놓여졌을때(종료)의 x,y좌표를 기록한다. 

 

// 마우스를 클릭했을 때 x,y 저장

function mousePressed(){

      x2 = mouseX;

      y2 = mouseY;

    };

 

// 마우스를 뗐을때 x,y 저장하고, 간격을 두고 공을 생성하는 함수 init 호출

function mouseReleased(){

    x = mouseX;

    y = mouseY;

    if(abs(x - x2) <= 20 && abs(y - y2) <= 20){return} // 드래그를 너무 조금했을 때에는 무시

    num = 0;

    repeat = setInterval(function(){  // 공들이 한번에 다 날아가지 않도록 약간씩 시차를 두고 생성시켜준다.

        init(x,y);},100);

    draw();  // 애니메이션을 구현할 함수를 호출

    };

위의 마우스 관련 함수들도 p5.js로 간단히 구현했다.

 

그리고, 드래그 하는 동안에 직선을 그려줘야하니까, 

// 드래그할 때 붉은 선 그리기

function mouseDragged(){ // 마우스 버튼이 눌린 상태에서 움직일 때마다 한 번씩 호출

    stroke("red");

    strokeWeight(5);

    line(x2, y2, mouseX, mouseY);

};

 

공들을 생성하는 함수. 

공들이 날아가는 각종 속성을 정하기 때문에 가장 중요하겠다. 

function init(x,y){ // 공을 하나씩 생성하고 속성 부여

    p = sqrt(pow((x2-x),2) + pow((y2-y),2));

    radian = atan2((x2-x),(y2-y));

    dx = (p *sin(radian + ((random(20)-10)*PI/180))*0.05) ;

    dy = (p * cos(radian + ((random(20)-10)*PI/180))*0.05) ;

    c = 'rgb('+floor(random(255))+','+floor(random(255))+','+floor(random(255))+')';

    balls[num] = new Ball(x, y, x2, y2, dx, dy, p, c)

    if(num<ballNumber){num++} else {

        clearInterval(repeat);  // 공이 지정 숫자만큼 생성됬으면, init() 함수 호출을 중지.

        }    ;

}

 

위에서 dx,dy가 공들을 이동하는 x,y의 변화값인데, 

아래 그림의 c에다가 각도에서 랜덤하게 차이를 두고, 거기서 cos,sin을적용해서 dx,dy를 구했다.

a = c * cos(각도)

b = c * sin(각도)

물론 a = x - x2 , b = y - y2 로도 구할 수 있지만, 랜덤한 각도로 발사가 되어야 해서, 빙~ 돌아서 값을 구했다. (뭔가 더 좋은 방법이 있을 것 같기는 하다. ㅡㅡa)

 

마우스를 떼면 draw()함수를 실행시키는데, p5.js에서는 draw() 함수는 requestAnimationFrame이 없어도 기본적으로 프레임마다 호출되어 실행된다. 

 

짧게 드래그 했을 때 길게 드래그 했을 때

전체코드 (HTML)

    <div id="inputArea">
    <label for="ballNumberInput">공 갯수 : </label>
    <input type="text" id='inputBallNumber' name='ballNumberInput' size='3' value="10" onkeyup="setup()">
    </div>
    <div id="msg">마우스를 왼쪽클릭 후 드래그 했다가 놓으세요<br> 드래그 한 길이가 날라가는 힘이 됩니다.</div>
</body>
cs

전체코드 ( Javascript)

function setup() {
    createCanvas(windowWidth,windowHeight);
    background('white');
    num = 0;
    
    ballNumber = document.querySelector('#inputBallNumber').value; 
    balls = [];
    radius = 30;
}
 
class Ball {
    constructor(x,y,x2,y2,dx,dy,power,color){
        this.x = x; // 공이 발사되는 x
        this.y = y; // 공이 발사되는 y
        this.x2 = x2; // 드래그 시작점 x
        this.y2 = y2; // 드래그 시작점 y
        this.dx = dx; // 공이 이동하는 x 크기
        this.dy = dy; // 공이 이동하는 y 크기
        this.p = power; //마우스를 드래그한 길이, 공이 날라가는 힘(속도),
        this.c = color; // 공 색깔
    }
    
    update(){ // 공을 변화값만큼 이동
        this.x = this.x + this.dx;
        this.y = this.y + this.dy;
    }
    
    drawBall(){ // 프레임마다 변경된 위치로 공을 그려줌
        fill(this.c);
        stroke('black'); 
        strokeWeight(2);
        circle(this.x , this.y, radius);
    }
}
 
function draw(){ 
    fill("rgba(255,255,255,0.8)");
    rect(00, canvas.width, canvas.height);
    
    stroke('black');
    strokeWeight(2);
    for (i =0; i < num; i++) {
        balls[i].update();
        fill(balls[i].c);
        circle(balls[i].x, balls[i].y, radius);
        
        if (balls[num-1].x+radius*2 < 0 || balls[num-1].x - radius*2 > canvas.width || balls[num-1].y + radius*2 < 0 || balls[num-1- radius*2 > canvas.height) {
            return// 마지막 공이 완전히 캔버스 밖으로 나가면 공 그리기 종료, 
        } 
    } 
}
 
function init(x,y){ // 공을 하나씩 생성하고 속성 부여
    p = sqrt(pow((x2-x),2+ pow((y2-y),2));
    radian = atan2((x2-x),(y2-y));
    dx = (p *sin(radian + ((random(20)-10)*PI/180))*0.05) ;
    dy = (p * cos(radian + ((random(20)-10)*PI/180))*0.05) ;
    c = 'rgb('+floor(random(255))+','+floor(random(255))+','+floor(random(255))+')';
    balls[num] = new Ball(x, y, x2, y2, dx, dy, p, c)
    if(num<ballNumber){num++else {
        clearInterval(repeat);
        }    ;
}
 
// 마우스를 클릭했을 때 x,y 저장
function mousePressed(){
      x2 = mouseX;
      y2 = mouseY;
      print(mouseIsPressed)
    };
 
// 드래그할 때 붉은 선 그리기
function mouseDragged(){ // 마우스 버튼이 눌린 상태에서 움직일 때마다 한 번씩 호출
    stroke("red");
    strokeWeight(5);
    line(x2, y2, mouseX, mouseY);
};
 
// 마우스를 뗐을때 x,y 저장하고, 간격을 두고 공을 생성하는 함수 init 호출
function mouseReleased(){
    x = mouseX;
    y = mouseY;
    if(abs(x - x2) <= 20 && abs(y - y2) <= 20){return// 드래그를 너무 조금했을 때에는 무시
    num = 0;
    repeat = setInterval(function(){
        init(x,y);},100);
    draw();
    };
 
 
cs
 

자바스크립트를 깨우치다:객체로 풀어보는 JavaScript의 원리

COUPANG

www.coupang.com

이 포스팅은 쿠팡 파트너스 활동의 일환으로, 이에 따른 일정액의 수수료를 제공받을 수 있습니다.

+ Recent posts