2 minute read

Matrix Code Rain 을 구현해보려고 한다.

구성

  1. 초당 8-10회 종방향으로 좌표를 이동시키면서, 글자를 찍는다.

  setInterval(()=>{
    // 글자를 찍기전에, 이 전 실행으로 그렸던, 폰트들을 지운다.
    app.clearRect();
    app.write();

  },120)

  app = {
    write: function(){
      for(let i=0; i< coord_x.length; i++){
        const _x = coord_x[i];
        const _y = coord_y[i];
        const charLength = characterLength[i];
        const _fontSize = randomFontSize[i];
        app.context.font = `${_fontSize}px sans-serif`;

        // 문자열 출력 함수
        app.context.fillText("A", _x, _y)

        if(coord_y[i]>convasHeight){
          coord_y[i]=-150;
        }else coord_y[i]+=100; // 항목 3에서, 이부분에서 속도의 변화를 주려고 한다.
      }
    }
  }


예시

  1. 이동된 좌표에, 문자열을 그린다.

const characters = ["ヲ","ァ","ィ","ゥ","9"]
app={
  ...app,

  // 문자열을 찍는 함수, 시작할 좌표값고, 문자열의 길이를 넘겨받아서, 랜덤한 문자열을 찍는다.(characters 라는 문자열 배열이 이미 있음, 랜덤한 인덱스로 값을 가져오기만 하면 됨)
  verticalCharacterWrite: function(x, y, length){
    let chars = "";
    // randomNumber(maxNumber)는 랜덤한 정수형 숫자 반환함수
    const rand_length = randomNumber(rainCharacterLength);
    let dy = y;

    // 문자열을 그린다. 문자열을 그리면서, 문자들이 겹치지 않게 y좌표를 이동해주면서, 한글자씩, 주어진 length만큼 찍는다.
    for(let i=0; i< length; i++){
      const rand_index = randomNumber(characters.length-1);
      const rand_char =  characters[rand_index];
      app.context.fillText(rand_char, x, dy);
      const diff = app.context.measureText(rand_char).actualBoundingBoxAscent;
      dy+=diff;
    };
  },
}

예시

  1. 문자열이 떨어지는 속도, 폰트의 색상 등에서 변화를 준다.
// 앞서 항목 1에서 설명한 write함수에서, 폰트가 비처럼 떨어질 때, 떨어지는 속도에 대한 변화를 만들어준다.

write: function(){
  for(let i=0; i< coord_x.length; i++){
    const _x = coord_x[i];
    const _y = coord_y[i];
    const charLength = characterLength[i];
    const _fontSize = randomFontSize[i];
    app.context.font = `${_fontSize}px sans-serif`;

    // 문자열 출력 함수 [수정] -> verticalCharacterWrite
    // app.context.fillText("A", _x, _y);
    app.verticalCharacterWrite(_x, _y, charLength);

    if(coord_y[i]>convasHeight){
      coord_y[i]=-150;
    }else coord_y[i]+= rainSpeed[i]; // 항목 3에서, 이부분에서 속도의 변화를 주려고 한다.
  }
}


// 앞서 항목 2에서 설명한, verticalCharacterWrite에서 폰트 스타일에 변화를 준다.
verticalCharacterWrite: function(x, y, length){
    let chars = "";
    const rand_length = randomNumber(rainCharacterLength);
    let dy = y;
    for(let i=0; i< length; i++){
      const rand_index = randomNumber(characters.length-1);
      const rand_char =  characters[rand_index];
      console.log("context" , app.context);
      if(i %2 == 1)app.setCharstyle("#2ba64f",2, "#1ca344");
      if(i %2 == 0)app.setCharstyle("#2ba64f",2, "#0b752a");
      if(i <= 6){
        if(i %3 == 1)app.setCharstyle("#2ba64f",2, "#174d27");
        if(i %3 == 2)app.setCharstyle("#2ba64f",0, "#095921");
        if(i %3 == 0)app.setCharstyle("#2ba64f",0, "#095921");
      }
      if(i == length - 1) app.setCharstyle("#eee",0, "#92e0a9");
      if(i == length - 1) app.setCharstyle("#eee",0, "#e3ffeb");
      if(i == length - 2) app.setCharstyle("#eee",3, "#66cc84");
      app.context.fillText(rand_char, x, dy);
      const diff = app.context.measureText(rand_char).actualBoundingBoxAscent;
      dy+=diff;
    };
  },

예시

번외

최초 계획은, transform으로 글자를 변형시켜서 비처럼 떨어지게 할 생각이었으나, 그렇게 되면, 글자 한글자 한글자 마다 수시로 바뀌어야 하는, 모션 특성상 부하가 많아질 것 같아서, canvas 에서 구현하는 방향으로 변경. but 다음의 내용을 알게 되었다.

  • text glowing 효과 -> text-shadow
  • text gradation 효과 -> background-image, background-clop, web-kit-text-fill-color, background-size 콤비네이션 이용
// 예제
2. background-image, webkit-background-clip,web-kit-text-fill-color, background-size 콤비네이션을 사용한다.(transform: rotation과 궁합이 좋지 않다.)

  background-image: gradation();

  // 브라우저가 webkit 계열이 아닌경우에는, 속성이 안먹으니까, 그냥 컬러로 단색 톤으로 나오게 처리를 해둔다.
  background-clip(fallback)
  color:green(fallback);



  // webkit브라우저에서만 작동
  web-kit-text-fill-color: transparent;
  web-kit-background-clip: text;

마무리

위 코드는 실제 소스의 일부이지만, 위 코드만으로는 구현이 충분하지가 않습니다. 이 글은, 대략적인 아이디어의 전달을 목적으로 하고 있습니다.

혼자서 구현해보시다가, 막히시는 부분이 있을 때, 어떤 아이디어로 접근을 해야 문제를 풀수 있는 지 정도로 참고하시는 게 좋을 것 같습니다.

아래 깃허브 저장소 링크를 걸어놓을 테니, 소스 전체를 확인하시고 싶은 분들은, 아래 링크에서 확인하시면 될 것 같습니다.

구현내용: codepen
구현내용: https://github.com/jimyeong/animations

Leave a comment