오목 게임. 아이들이랑 놀 겸해서 만들어봤다.

완성본은 아래에서...

omog-geim.bryanko555.repl.co

 

 

(오목 이후 제작한 게임)

 

Javascript 리버시(Reversi) 게임 만들기

앞서 만들었던 오목에 자신감을 얻고 다음 프로젝트로 리버시를 만들기로 한다. Javascript 오목 게임 만들기 오목 게임. 아이들이랑 놀 겸해서 만들어봤다. 완성본은 아래에서... omog-geim.bryanko555.re

mrkool.tistory.com

 

 

HTML,CSS는 별거 없고, 게임승리 이미지를 안보이게 넣어뒀다가 오목이 만들어졌을 때 나타나게 했다.

 

큰 틀에서, 바둑판의 돌이 놓여지는 눈금 하나하나가 배열로 되어있고, 돌이 없는 곳은 -1, 검은 돌이 놓여지면 1, 하얀 돌이 놓여지면 2로 배열이 구성되는 식이다.

원래 아래처럼 보이는 배열인데, 콘솔창에 위 그림처럼 보이도록 해야 x,y좌표를 찾기 쉬워진다.

아래와 같이 콘솔창에 눈금열만큼 줄바꿈을 넣어서 실제 바둑판처럼 숫자가 나열되어 보여주게 해준다.

오목에서 고려해야 할 요소들이다.

] 돌의 위치 x,y를 배열의 위치로 바꿔주고, 반대로 배열의 위치를 x,y좌표로 바꿔주는 함수가 필요하다.

  19칸 실제 바둑판에서, x=3,y=1는 배열의 22번째 위치이고, 배열의 5번째 위치는 x=4,y=0이다. (첫 줄은 0)

] 마우스 클릭한 위치를 파악해서 돌을 그리는데, 대충 찍어도 정확한 눈금에 돌이 그려지도록 보정한다.

] 그 자리에 이미 돌이 놓여져 있으면(그 위치의 숫자가 -1이 아니면) 그림이 안그려지게 하고,

  비어져 있으면 차례에 따라서 흑이나 백 돌을 그린다.

] 무르기 기능.  돌을 놓을 때마다 그 차례의 바둑판 배열 전체를 또 다른 배열(여기서는 lastBoard[ ])에 넣어나가다가, 무르기가 실행되면 바로 직전의 바둑판 배열을 불러와서 그대로 바둑판을 그려준다.

] 이제 가장 중요한 승패 판정. 돌이 놓여질때 그 돌의 가로,세로,대각선 여덟 방향으로 돌의 색깔들을 파악해서 다섯 개가 놓여졌는지를 보면 되는데, 그냥하면 마지막 돌이 양쪽 끝에 놓여졌을 때만 인지하기 때문에, 

돌이 오목의 중간에 놓여지면서 오목이 완성되는 경우도 파악할 수 있도록 고려해야 한다.

재미로 '무르기'와 '다시하기'에 우리 아들 목소리를 녹음해서 활용했다. 

음악 재생은 읽어서 변수에 할당하고, 재생함수 실행.

let audio1 = new Audio('tik.mp3');

let audio2 = new Audio('beep.wav');

audio1.play();

audio2.play();

 

전체 코드는 아래 링크에서... 

repl.it/@BryanKo555/omog-geim

 

승패확인 함수에서 돌이 오목의 중간에 놓여졌을 때도 5개인지를 확인할 수 있도록 하는 것에서 나름 고민을 했고, 이런 고민의 과정과 그 해결 됬을 때의 기쁨이 코딩하는 즐거움이라고 생각한다.

 

 

생활코딩! HTML + CSS + 자바스크립트 : 처음 프로그래밍을 시작하는 입문자의 눈높이에 맞춘

COUPANG

www.coupang.com

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

 

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

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

 

지난 글에서 여러 공들이 화면 안에서 튕기게 만들었는데, 이제 여기다가 중력을 가미해보자.

 

 

Javascript 캔버스에서 튕기는 공들 (w/o 중력)

이전 글에서는 공 하나가 화면 안에서 생각없이 튕기는 내용이었다. Javascript 캔버스에서 움직이는 공 그리기 유튜브에서 브라우저에서 각종 도형의 움직임을 Javascript로 구현하는 걸 보고 반해

mrkool.tistory.com

이 공들에 중력이 더해지면 아래와 같이 실제와 비슷한 운동을 보인다.

https://repl.it/join/vtffyilt-bryanko555 

대부분 동일하고, 프레임마다 다르게 그려주는 update()함수에 가속도 요소를 넣어준다. 

 

update(){ // 프레임마다 속성들을 변화시킴

  this.y += this.weight; // y방향 움직임을 무게로 가정해서 설정

  this.x += this.directionX;

  this.weight += 0.1; // 프레임마다 떨어질때의 가속도 증가

  this.directionX *= 0.997; // 가로방향 속도 감소. 가장 자연스러운 움직임을 보이는 수치로 찾은 값 

  if(this.y+this.size>canvas.height || this.y-this.size<0){ // 세로 방향 바운드 처리

    this.weight *= -0.8; // y 방향을 바꿔주면서 점차 바운스가 감소하게

  if(Math.abs(this.weight)<0.9){this.y = canvas.height-this.size; // 바운드가 어느 정도 이하가 되면 더 이상 바운드 안하게, 즉, 바닥에 붙게 한다.

  this.weight =1;} else { this.y -=1 ;} //

  };

  if(this.x>canvas.width-this.size || this.x-this.size < 0 ) { // 가로 방향 바운드 처리

    this.directionX *= -1; // x 방향 전환. 

  }

}

 

전체 코드 :

 

window.onload = function () {
 
  const canvas = document.getElementById('canvas');
  const ctx = canvas.getContext('2d');
  canvas.width = window.innerWidth-15;
  canvas.height = window.innerHeight-15;
 
  balls=[];
  ballNumber = 50;
 
  class Ball{
    constructor(x,y){ // ball의 기본 속성들을 정의 
      this.x = x;
      this.y = y;
      this.c = 'rgba('+Math.random()*255+','+Math.random()*255+','+Math.random()*255+')';
      this.size = Math.random()*10+5;
      this.angle = (Math.random()*360)*((Math.PI*2)/360);
      this.power = Math.random()*3+2;
      this.directionX = this.power * Math.cos(this.angle);
      this.weight = this.power * Math.sin(this.angle);
    }
    update(){ // 프레임마다 속성들을 변화시킴 
      this.y += this.weight; 
      this.x += this.directionX;
      this.weight += 0.1// 프레임마다 떨어질때의 가속도 증가
      this.directionX *= 0.997// 가로방향 속도 감소. 
      if(this.y+this.size>canvas.height || this.y-this.size<0){ // 세로 방향 바운드 처리
        this.weight *= -0.8// y 방향을 바꿔주면서 점차 바운스가 감소하게
        if(Math.abs(this.weight)<0.9){this.y = canvas.height-this.size; // 바운드가 어느 정도 이하가 되면 더 이상 바운드 안하게, 즉, 바닥에 붙게 한다.
        this.weight =1;} else { this.y -=1 ;} // 
        };
      if(this.x>canvas.width-this.size || this.x-this.size < 0 ) { // 가로 방향 바운드 처리 
        this.directionX *= -1// x 방향 전환.  
      } 
    }
    draw(){ // 넘어온 속성값대로 캔버스에 그림을 그려줌
       ctx.fillStyle= this.c;
       ctx.beginPath();
       ctx.arc(this.x, this.y, this.size, 0, Math.PI*2true);
       ctx.closePath();
       ctx.fill();
       ctx.strokeStyle = 'black';
       ctx.strokeWidth = 4;
       ctx.stroke();
    }
  }
 
  function init(){
      for(i=0;i<ballNumber;i++){
        balls[i] = new Ball(canvas.width*0.5, canvas.height*0.5)
      }
  }
 
  function animate(){ // 매 프레임마다 벌어지는 일들
    ctx.fillStyle='rgba(255,255,255,0.51)';
    ctx.fillRect(0,0,canvas.width,canvas.height);
    for(i=0;i<ballNumber;i++){
      balls[i].update();
      balls[i].draw();
    }
 
    window.addEventListener('resize',function(){ // 화면 크기가 변하면 캔버스 크기도 변경해줌
      canvas.width=window.innerWidth;
      canvas.height=window.innerHeight;
    })
    requestAnimationFrame(animate);
  }
 
  init();
  animate();
 
  }
cs

여기다가 좀 변화를 줘서, 공들을 360도 회전하면서 발사되게 해봤다.

https://repl.it/join/zxxofqqj-bryanko555

공이 한꺼번에 생성되는 것이 아니라, 하나씩 생성되서 발사되야 하기 때문에 setInterval로 시간 간격을 두면서 공을 생성해야 한다. requestAnimationFrame으로는 공들이 순식간에 생성되서 그냥 동시에 터지는 것처럼 보인다.

setInterval이 호출될 때마다 공을 한개씩 생성한다.그리고 생성된 공이 시계방향으로 돌아가면서 발사되야하기 때문에, 공(ball)의 속성에 각도(angle)를 추가했다.

 

class Ball{

  constructor(x,y,angle){ // ball의 기본 속성들을 정의

    :

}

 

function init(){

  if(num < ballNumber){ num++;} // 호출될 때마다 공을 1개씩 생성한다.

  balls[num] = new Ball(canvas.width*0.5, canvas.height*0.5, Math.PI*2/360 + i) // 각도를 순차적으로 증가시키면서 공을 생성한다.

}

 

setInterval(init,100);

 

오늘은 여기까지....

 

 

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

COUPANG

www.coupang.com

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

이전 글에서는 공 하나가 화면 안에서 생각없이 튕기는 내용이었다.

 

 

Javascript 캔버스에서 움직이는 공 그리기

유튜브에서 브라우저에서 각종 도형의 움직임을 Javascript로 구현하는 걸 보고 반해서 바로 공부를 시작. 이제서야 조금씩 머리속에서 그림이 그려져가고 있다. bouncing-ball-3.bryanko555.repl.co 이건 그

mrkool.tistory.com

이번에는 컴퓨터의 강점을 살려, 공의 갯수를 확 늘리게되면 이제 좀 볼만해진다.

이전에는 ball 클래스를 만들어놓고 공을 하나만 만들었었는데, 이번에는 초기화 함수, init()에서 공을 여러개 생성하고,

animate() 함수에서 그 공들을 매 순간 업데이트 할 때마다 계산해준다.

 

function init(){ // 공의 갯수만큼 공의 객체 생성

  for(i=0;i<ballNumber;i++){

    balls[i] = new Ball(canvas.width*0.5, canvas.height*0.5)

   }

}

 

function animate(){ // 매 프레임마다 벌어지는 일들

   ctx.fillStyle='rgba(255,255,255,0.8)'; // 전체 화면 지우기. 하얀색의 alpha값을 변경함에 따라 공의 잔상이 달라진다.

   ctx.fillRect(0,0,canvas.width,canvas.height);

   for(i=0;i<ballNumber;i++){

      balls[i].update();

      balls[i].draw();

    }

}

 

위 데모에서는 30개의 공을 그렸는데, requestAnimationFrame()이 1초에 60번 동작하고, 그 때마다 30개 공의 좌표를 이동시키고 그림을 그리고 벽에 닿았는지 판단해준다. 문돌이에게는 놀라운 일이다. ㅎ

 

다양성을 주기 위해서 각 공마다 랜덤 특성을 부여했다.

시작할때 공이 랜덤한 방향으로 날라가고,

    this.angle = (Math.random()*(Math.PI*2));

공의 색깔이 랜덤하게 생성되고, 

    this.c = 'rgba('+Math.random()*255+','+Math.random()*255+','+Math.random()*255+')';

공의 크기를 다르게 하고,

    this.size = 10+Math.random()*20;

공이 날라가는 속도를 다르게 했다. 

    

this.power = Math.random()*3+2;

 

아예 공의 수를 200개로...

 

이 공이 움직이는 것처럼 보이는 이유가, 매 프레임마다 캔버스 전체를 하얀색 상자를 그려서 덮어버리고 각 공들을 이동한 좌표로 그려주고, 다음 프레임에서 다시 다 지우고, 공들을 다시 그리고 ... 이렇게 반복함으로써 공들이 움직이는 것처럼 보이는 것인데...

캔버스를 덮을 하얀색의 투명도(alpha값)을 다르게 함에 따라서 공의 궤적을 다르게 볼 수 있다.

alpha =1 

alpha = 0.5

alpha = 0.1

 

전체 코드 :

window.onload = function () {
 
  const canvas = document.getElementById('canvas');
  const ctx = canvas.getContext('2d');
  canvas.width = window.innerWidth-15;
  canvas.height = window.innerHeight-15;
 
  balls=[];
  ballNumber = 20;
 
  class Ball{
    constructor(x,y){ // ball의 기본 속성들을 정의 
      this.x = x;
      this.y = y;
      this.c = 'rgba('+Math.random()*255+','+Math.random()*255+','+Math.random()*255+')'// 공의 색깔을 random으로 설정
      this.size = 10+Math.random()*20;
      this.angle = (Math.random()*(Math.PI*2));
      this.power = Math.random()*3+2;
      this.directionX = this.power * Math.cos(this.angle);
      this.directionY = this.power * Math.sin(this.angle);
    }
    update(){ // 프레임마다 속성들을 변화시킴 
      this.y += this.directionY; 
      this.x += this.directionX;
      if(this.y+this.size>canvas.height || this.y-this.size<0){ // 바운드 처리
        this.directionY *= -1;
        }
      if(this.x>canvas.width-this.size ) {
        this.x = canvas.width-this.size;
        this.directionX *= -1;
      } else if (this.x-this.size < 0){
        this.directionX *= -1;
      }
    }
    draw(){ // 넘어온 속성값대로 캔버스에 그림을 그려줌
       ctx.fillStyle= this.c;
       ctx.beginPath();
       ctx.arc(this.x, this.y, this.size, 0, Math.PI*2true);
       ctx.closePath();
       ctx.fill();
       ctx.lineWidth = 2;
       ctx.strokeStyle= 'black';
       ctx.stroke();
    }
  }
 
  function init(){ // 공의 갯수만큼 공의 객체 생성
      for(i=0;i<ballNumber;i++){
        balls[i] = new Ball(canvas.width*0.5, canvas.height*0.5)
      }
  }
 
  function animate(){ // 매 프레임마다 벌어지는 일들
    ctx.fillStyle='rgba(255,255,255,0.1)'// 전체 화면 지우기. 하얀색의 alpha값을 변경함에 따라 공의 잔상이 달라진다.
    ctx.fillRect(0,0,canvas.width,canvas.height);
    for(i=0;i<ballNumber;i++){
      balls[i].update();
      balls[i].draw();
    }
 
    window.addEventListener('resize',function(){ // 화면 크기가 변하면 캔버스 크기도 변경해줌
      canvas.width=window.innerWidth;
      canvas.height=window.innerHeight;
    })
    requestAnimationFrame(animate);
  }
 
  init();
  animate();
 
  }
cs

다음에는 중력까지 가미해보자.

 

 

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

COUPANG

www.coupang.com

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

지난 글에서는 공이 상자안을 끝없이 튕기는 것을 그려봤는데, 이번에는 중력값을 넣어서 실제에서 공이 튕기는 것처럼 해보자. 

실제에서는 공이 튕기는 힘이 조금씩 줄어들고,

좌우로 움직일때도 속도가 줄어들어야 한다.

실제에서 공이 자유낙하를 한다면 아래와 같을 것이다.

중력이 있기 때문에 단위시간에 떨어지는 거리가 달라지고(0.2, 0.4, 0.6...)

반발해서 올라갈 때는 그와 반대로 올라갈 수록 단위시간의 이동거리가 줄어든다.

이것을 코딩에 반영해줘야 한다.

 

중요한 부분은 update() 이다.

아래에서는 gravity 변수가 매 프레임마다 0.2씩 더 늘어나게 해줬다.

그리고 바운드 될 때마다 gravity에 -1을 곱해서 움직이는 방향을 바꿔준다.

그런데, 바운드 될때마다 다시 올라가는 높이가 이전보다는 낮아져야 되기 때문에 -0.9로 수치를 정했다.

이 수치를 -1.1 이렇게 바꾸면 바운드 되서 이전보다 더 높이 올라간다.

 

x방향도 마찬가지로, 처음에는 5만큼 늘어나지만, 그 다음부터는 0.995를 곱해서 점점 늘어나는 속도가 줄어든다.

좌우 벽에 닿으면 -1을 곱해서 방향이 바뀐다. 

window.onload = function () { // 스크립트 로딩이 완료된 후부터 내용을 시작
 
  const canvas = document.getElementById('canvas');
  const ctx = canvas.getContext('2d');
  canvas.width = window.innerWidth;
  canvas.height = window.innerHeight;
 
  class Ball{
    constructor(x,y){ // ball의 기본 속성들을 정의 
      this.x = x; // x좌표
      this.y = y; // y좌표 
      this.c = 'red'// 시작할때 공의 색깔
      this.size = 20// 공의 반지름
      this.power = 5// 공의 움직임 세기
      this.gravity = this.power; // 공이 상하로 움직이는 값
      this.directionX = 5; // 공이 좌우로 움직이는 값
    }
 
    update(){ // 프레임마다 속성들을 변화시킴 
      // y값의 변동을 계산
      this.y += this.gravity; 
      this.gravity += 0.2 // 중력 값
      console.log(this.gravity)
      if(this.y+this.size >= canvas.height || this.y-this.size <= 0){ // 상하 바운드 처리
      this.gravity *= -0.9// 상하에 닿으면 방향을 전환
      }
 
      // x값의 변동을 계산
      this.x += this.directionX;
      this.directionX *= 0.995;
      if(this.x+this.size > canvas.width || this.x-this.size<0){
      this.directionX *= -1;
      }
    }
 
    draw(){ // 넘어온 속성값대로 캔버스에 원을 그려줌
       ctx.fillStyle= this.c;
       ctx.beginPath();
       ctx.arc(this.x, this.y, this.size, 0, Math.PI*2true);
       ctx.closePath();
       ctx.fill();
    }
    }
 
  function init(){ // 그려질 공의 초기 좌표 설정
      ball1 = new Ball(canvas.width*0.5, canvas.height*0.5)
  }
 
  function animate(){ // 매 프레임마다 벌어지는 일들
    ctx.fillStyle='rgba(255,255,255,0.5)';
    ctx.fillRect(0,0,canvas.width,canvas.height); // 캔버스 전체를 색칠해서 내용을 지워준다
    ball1.update(); // ball1의 좌표 등을 업데이트 한다
    ball1.draw(); // 업데이트된 내용으로 ball을 새로 그린다.
    requestAnimationFrame(animate);
  }
 
  init(); // 공의 초기 좌표를 설정하고, 
  animate(); // 프레임마다 공을 그려준다. 
 
  }
cs

 

혹시 몰라서 html 부분,

<body>
   <canvas id="canvas">   </canvas>
</body>
cs

 

이제 여기에서 배열을 사용해서 공의 수를 확 늘려주면, 좀 볼만한 그림이 나온다.

다음 시간에...

 

 

 

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

COUPANG

www.coupang.com

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

회사에서 날짜를 요일로 바꾸기를 달력을 보면서 하다가 '이건 아니다!'라는 생각이 들었다. 

찾아보니 바로 간단한 방법이 '짠~'

날짜에 '셀 서식'을 적용해서 요일로 보이게 하는 방법이다.

 

먼저 셀에 일반적인 날짜를 넣어주자.

아래의 경우에는 월,일이 나눠져있어서 date함수를 써서 날짜를 입력해줬다.

 = date(년도,월,일)

여기서 날짜를 전체 선택해서 '셀 서식' 선택. (단축키 : ctrl + 1)

여기서 맨 아래 '사용자 지정'을 선택하고 '형식'에 필요한 요일 형태로 입력을 해주면 끝.

 aaa  -> 수

 aaaa -> 수요일

 ddd  -> Wed

 dddd -> Wednesday

 

단, 이것은 '2020-12-02'라는 값을 '수요일' 형식으로 보여주는 것이지, 

'수요일'이라는 텍스트 값이 있는 것은 아니다. 

 

이런 간단한 팁이 모여서 내 실력이 되고, 내 시간을 절약해준다. 

모르면 찾아보고, 찾아보는 것도 해볼 수록 잘 찾을 수 있다.

 

 

 

직장인을 위한 실무 엑셀:실전! 비즈니스 엑셀 완전 정복

COUPANG

www.coupang.com

 

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

유튜브에서 브라우저에서 각종 도형의 움직임을 Javascript로 구현하는 걸 보고 반해서 바로 공부를 시작.

이제서야 조금씩 머리속에서 그림이 그려져가고 있다. 

 

브라우저 안에서 계속 튕기는 공

bouncing-ball-3.bryanko555.repl.co

 

이건 그냥 단순하지만, 여기에다 배열과 반복이 더해지면 그럴듯한 그림이 그려진다. 

bouncing-ball-1.bryanko555.repl.co

 

오늘은 첫번재 기본적인 바운드 되는 내용부터 정리한다. 

html에 canvas를 설정하고, css에서 화면 가득 채우는 건 기본.

바로 Javascript로 넘어가자.

window.onload = function () { // 스크립트 로딩이 완료된 후부터 내용을 시작
 
  const canvas = document.getElementById('canvas');
  const ctx = canvas.getContext('2d');
  canvas.width = window.innerWidth;
  canvas.height = window.innerHeight;
  class Ball{
    constructor(x,y){ // ball의 기본 속성들을 정의
      this.x = x;
      this.y = y;
      this.c = 'rgba('+Math.random()*255+','+Math.random()*255+','+Math.random()*255+')'
// 시작할때 공의 색깔을 랜덤하게 설정. 이거 많이 사용하게 된다.
      this.size = 20// 공의 반지름
      this.angle = (Math.random()*(Math.PI*2)); // 공이 출발할 각도
      this.power = 5// 공의 세기
      this.directionX = this.power * Math.cos(this.angle); // 공이 좌우로 움직이는 값
      this.weight = this.power * Math.sin(this.angle); // 공이 상하로 움직이는 값
    }
    update(){ // 프레임마다 속성들을 변화시키는 함수
      this.y += this.weight; // y값을 계속 증가/감소 시킨다
      this.x += this.directionX; // x값을 계속 증가/감소 시킨다.
 
     
      if(this.y+this.size>canvas.height || this.y-this.size<0){ // 상하 바운드 처리
        this.weight *= -1// 상하에 닿으면 방향을 전환
      }
      if(this.x>canvas.width-this.size || this.x-this.size < 0) { // 좌우 바운드 처리
        this.directionX *= -1// 좌우에 닿으면 방향을 전환
      }
    }
    draw(){ // 넘어온 속성값대로 캔버스에 원을 그려주는 함수
       ctx.fillStyle= this.c;
       ctx.beginPath();
       ctx.arc(this.x, this.y, this.size, 0, Math.PI*2true);
       ctx.closePath();
       ctx.fill();
    }
  }
 
  init = () => { // 그려질 공의 개체를 설정하는 함수
      ball1 = new Ball(canvas.width*0.5, canvas.height*0.5)
  }
  function animate(){ // 매 프레임마다 그림을 새로 그려주는 함수
    ctx.fillStyle='rgba(255,255,255,0.5)'; // 매 프레임마다 캔버스를 통째로 칠하는 색깔. 맨 마지막의 alpha값에 따라 공의 잔상이 남는 정도가 달라진다.
    ctx.fillRect(0,0,canvas.width,canvas.height); // 캔버스 전체를 색칠해서 내용을 지워준다
    ball1.update(); // ball1의 좌표 등을 업데이트 한다
    ball1.draw(); // 업데이트된 내용으로 ball을 새로 그린다.
    window.addEventListener('resize',function(){ // 화면 크기가 변하면 캔버스 크기도 변경해줌
      canvas.width=window.innerWidth;
      canvas.height=window.innerHeight;
    })
    requestAnimationFrame(animate);
  }
  init(); // 공의 초기 좌표를 설정하고,
  animate(); // 프레임마다 공을 그려준다.
 
  }
cs

구조를 간단히 말하자면, 

  ] 그려질 ball의 기본 속성을 정하는 부분 : Ball.constructor(x,y)

  ] ball이 움직일 때마다 x,y 값을 변경해주고, 테두리에 부딪치면 -1을 곱해서 반대로 움직이게 하는 부분 : Ball.update()

  ] 생성된 ball들을 canvas에 그려주는 부분 : Ball.draw()

  ] 위의 함수들을 약 1초에 60번씩 호출해서 반복시키는 부분 : animate()

 

위의 것이 기본적인 구조이고, 저 구조 안에서 공의 개수를 늘리고, 중력값을 주고, 색깔을 변하는 등의 변화를 주면 점점 그럴듯한 그림으로 변해간다. 

앞으로 계속 변형을 늘려가보자.

 

 

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

COUPANG

www.coupang.com

 

이 다음에는 공을 여러개로 늘려서 움직여보자.

 

Javascript 캔버스에서 튕기는 공들 (w/o 중력)

이전 글에서는 공 하나가 화면 안에서 생각없이 튕기는 내용이었다. Javascript 캔버스에서 움직이는 공 그리기 유튜브에서 브라우저에서 각종 도형의 움직임을 Javascript로 구현하는 걸 보고 반해

mrkool.tistory.com

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

sample.xlsx
0.01MB

실무에서 자주 발생하는 경우다.

아래와 같이 여러 셀에서 각 표의 첫번째 행의 값을 반복해서 입력해야 할 경우가 생긴다. 

이전에는 if 함수로, 빈 셀이면 윗 셀의 값을 넣고, 빈 셀이 아니면 그대로 놔두고 어쩌고. 복잡하게 했었는데, 간단한 방법이 있었다. 아래 그림처럼...

입력할 영역을 선택하고, '홈' 탭에서 '찾기 및 선택' -> '이동옵션(S)' -> '빈 셀(K)' 선택 -> 수식 입력 ( =(첫번째 셀의 바로 윗 셀)) -> ctrl+enter (중요!!) -> 전체 선택해서 값 복사로 수식 없애고 마무리

 

요약해서 말하면, 빈 셀들만 선택하고, 그 빈셀들이 모두 바로 위의 셀을 참조하게 하는 방법이다. 

 

단축키로 하자면, 영역선택 -> ctrl + G -> alt + S -> K -> enter -> '='입력 후 방향키 위로 한 번 -> ctrl + enter 

 

한 번 연습해두면 나중에 업무시간 절약에 도움 될 일이 분명히 생긴다. 

 

비슷하게 활용하면, 여러 곳의 빈 셀에 값을 채워넣을때도 활용 할 수 있겠다.

배우는 건 금방이지만, 그 잠깐의 시간은 앞으로 많은 시간을 절약해 줄 수 있다. 

 

예제 파일 첨부. 

 

 

직장인을 위한 실무 엑셀:실전! 비즈니스 엑셀 완전 정복

COUPANG

www.coupang.com

 

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

+ Recent posts