본문 바로가기
자바스크립트와 캔버스

빗소리 스크립트를 공개합니다.

https://itadventure.tistory.com/524 게시글에 사용된
빗소리 스크립트를 공개합니다.

배경이미지, 배경음악은 크레이의 홈페이지에 올려둔 것을 링크하였는데요.
여러분의 입맛에 맞는 걸 어딘가에 업로드하시고 적용하셔도 좋습니다.

아래는 홈페이지용,

<!DOCTYPE html>
<html lang="ko">
<head>
	<meta charset="UTF-8">
	<title>캔바스로 느껴봐~ ASMR 빗소리</title>
</head>
<body style='background-color:black'>
<a href='http://itadventure.tistory.com/category/자바스크립트와%20캔버스' 
  target='_blank'>
  https://itadventure.tistory.com
</a>
/ 크레이의 IT탐구<br/>
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
<script>
  const loadImage = path => {
    return new Promise((resolve, reject) => {
      const img = new Image()
      img.crossOrigin = 'Anonymous';
      img.src = path;
      img.onload = () => {
        resolve(img)
      }
      img.onerror = e => {
        reject(e)
      }
    })
  }
  
  function rand(start, end)
  {
    return Math.floor((Math.random() * (end-start+1)) + start);
  }
  
  let GameManager = new Object();
  GameManager.clicked=false;
  GameManager.mousedown=false;

  $(document).ready(function(){
    Init(GameManager);
  });
  
  $(document).click(function( event ){
    GameManager.clicked=true;
  });
  
  $(document).mousedown(function( event ){
    GameManager.mousedown=true;
  });
  
  $(document).mouseup(function( event ){
    GameManager.mousedown=false;
  });
  
  // 초기화
  async function Init(gm)
  {
    try{
      gm.Canvas=document.getElementById("MyCanvas");
      gm.ctx=gm.Canvas.getContext("2d");
      gm.Canvas.onmousemove = function(evt) {
        let rect = gm.Canvas.getBoundingClientRect();
        gm.mousex = evt.clientX - rect.left;
        gm.mousey = evt.clientY - rect.top;
      }
      
      // 배경
      gm.bgImage = 
        await loadImage("http://dreamplan7.cafe24.com/canvas7/city.jpg");

      // 배경
      gm.speakerImage = 
        await loadImage("http://dreamplan7.cafe24.com/canvas7/speaker.png");
        
      // 배경음악
      gm.bgSound = new Audio();
      gm.bgSound.src = "http://dreamplan7.cafe24.com/canvas7/rain.mp3";        
      gm.bgSound.volume=0;
      gm.bgSound.playbackRate=1.0;
      gm.bgSound.loop = true;
      gm.bgSound.autoplay = true;
      gm.bgOn=true;
      
      // 비
      gm.rainCount = 200; // 비의 갯수
      gm.rainDoing = 1; // 처음에 작동할 비의 갯수
      gm.rainRandom_x1 = -20; // 비의 랜덤 발생 x축
      gm.rainRandom_x2 = 820;
      gm.rainRandom_y1 = -200; // 비의 랜덤 발생 y축
      gm.rainRandom_y2 = -100;
      gm.rainRandom_vx1 = -3; // 비의 랜덤 이동 방향 x축
      gm.rainRandom_vx2 = 3;
      gm.rainRandom_vy1 = 40; // 비의 랜덤 이동 방향 y축
      gm.rainRandom_vy2 = 100;
      gm.rainObj = Array();      
      for(let i=0;i<gm.rainCount;++i)
      {
        gm.rainObj.push(
          {
            x1: rand(gm.rainRandom_x1, gm.rainRandom_x2),
            y1: rand(gm.rainRandom_y1, gm.rainRandom_y2),
            velocity_x: rand(gm.rainRandom_vx1, gm.rainRandom_vx2),
            velocity_y: rand(gm.rainRandom_vy1, gm.rainRandom_vy2)
          }
        );
      }
      
      // 애니메이션 시작
      requestAnimationFrame(Repeat);
    }catch(e){
      console.log(e)
    }
  }
  
  function Repeat()
  {
    Play(GameManager);
    requestAnimationFrame(Repeat);
  }
  
  function Play(gm)
  {
    
    try{
      let ctx = gm.ctx;
      // 배경
      ctx.drawImage(
        gm.bgImage, 
        0, 0
      );
      
      // 비 움직임
      for(let i=0;i<gm.rainDoing;++i)
      {
        gm.rainObj[i].x1 += 
          gm.rainObj[i].velocity_x / 10;
        gm.rainObj[i].y1 += 
          gm.rainObj[i].velocity_y / 10;
        if( gm.rainObj[i].y1 > 300 )
        {
          gm.rainObj[i].x1 = 
            rand(gm.rainRandom_x1, gm.rainRandom_x2),
          gm.rainObj[i].y1 = 
            rand(gm.rainRandom_y1, gm.rainRandom_y2),
          gm.rainObj[i].velocity_x = 
            rand(gm.rainRandom_vx1, gm.rainRandom_vx2),
          gm.rainObj[i].velocity_y = 
            rand(gm.rainRandom_vy1, gm.rainRandom_vy2)
        }
      }
      
      // 비 갯수 늘어남
      if(gm.rainDoing < gm.rainCount )
      {
        if(rand(0, 100)<= 5){
          gm.rainDoing++;
          gm.bgSound.volume = 
            ( gm.rainDoing / gm.rainCount ) * 0.8;
          if(gm.bgOn==true)
          {
            if(gm.bgSound.paused)
            {
              gm.bgSound.play();
            }
          }
        }
      }
      
      
      
      // 클릭에 따라 스피커 온/오프
      if(gm.clicked==true)
      {
        gm.clicked=false;
        if(gm.mousex > 750 && gm.mousex < 750 + 30 &&
          gm.mousey > 220 && gm.mousey < 220 + 30)
        {
          gm.bgOn = !gm.bgOn;
          if(gm.bgOn==true)
          {
            gm.bgSound.play();
          }
          else
          {
            gm.bgSound.pause();
          }
        }
      }
        
      // 비
      ctx.strokeStyle='rgba(255, 255, 255, 0.2)';
      ctx.beginPath();        
      for(let i=0;i<gm.rainCount;++i)
      {
        ctx.moveTo(
          gm.rainObj[i].x1 - gm.rainObj[i].velocity_x,
          gm.rainObj[i].y1 - gm.rainObj[i].velocity_y
        );
        ctx.lineTo(
          gm.rainObj[i].x1,
          gm.rainObj[i].y1
        );
      }
      ctx.stroke();
      
      // 스피커
      ctx.drawImage(
        gm.speakerImage, 
        750, 220
      );
      
    }catch(e){
      console.log(e)
    }
  }

</script>

<canvas id="MyCanvas" width=800 height=273></canvas>
</body>
</html>

 

아래는 티스토리 게시글용인데요.
티스토리에서는
HTML 모드 글쓰기로 전환하신 다음에 글을 써주셔야 해요.

 

<script>
  const loadImage = path => {
    return new Promise((resolve, reject) => {
      const img = new Image()
      img.crossOrigin = 'Anonymous';
      img.src = path;
      img.onload = () => {
        resolve(img)
      }
      img.onerror = e => {
        reject(e)
      }
    })
  }
  
  function rand(start, end)
  {
    return Math.floor((Math.random() * (end-start+1)) + start);
  }
  
  let GameManager = new Object();
  GameManager.clicked=false;
  GameManager.mousedown=false;

  $(document).ready(function(){
    Init(GameManager);
  });
  
  $(document).click(function( event ){
    GameManager.clicked=true;
  });
  
  $(document).mousedown(function( event ){
    GameManager.mousedown=true;
  });
  
  $(document).mouseup(function( event ){
    GameManager.mousedown=false;
  });
  
  // 초기화
  async function Init(gm)
  {
    try{
      gm.Canvas=document.getElementById("MyCanvas");
      gm.ctx=gm.Canvas.getContext("2d");
      gm.Canvas.onmousemove = function(evt) {
        let rect = gm.Canvas.getBoundingClientRect();
        gm.mousex = evt.clientX - rect.left;
        gm.mousey = evt.clientY - rect.top;
      }
      
      // 배경
      gm.bgImage = 
        await loadImage("http://dreamplan7.cafe24.com/canvas7/city.jpg");

      // 배경
      gm.speakerImage = 
        await loadImage("http://dreamplan7.cafe24.com/canvas7/speaker.png");
        
      // 배경음악
      gm.bgSound = new Audio();
      gm.bgSound.src = "http://dreamplan7.cafe24.com/canvas7/rain.mp3";        
      gm.bgSound.volume=0;
      gm.bgSound.playbackRate=1.0;
      gm.bgSound.loop = true;
      gm.bgSound.autoplay = true;
      gm.bgOn=true;
      
      // 비
      gm.rainCount = 200; // 비의 갯수
      gm.rainDoing = 1; // 처음에 작동할 비의 갯수
      gm.rainRandom_x1 = -20; // 비의 랜덤 발생 x축
      gm.rainRandom_x2 = 820;
      gm.rainRandom_y1 = -200; // 비의 랜덤 발생 y축
      gm.rainRandom_y2 = -100;
      gm.rainRandom_vx1 = -3; // 비의 랜덤 이동 방향 x축
      gm.rainRandom_vx2 = 3;
      gm.rainRandom_vy1 = 40; // 비의 랜덤 이동 방향 y축
      gm.rainRandom_vy2 = 100;
      gm.rainObj = Array();      
      for(let i=0;i<gm.rainCount;++i)
      {
        gm.rainObj.push(
          {
            x1: rand(gm.rainRandom_x1, gm.rainRandom_x2),
            y1: rand(gm.rainRandom_y1, gm.rainRandom_y2),
            velocity_x: rand(gm.rainRandom_vx1, gm.rainRandom_vx2),
            velocity_y: rand(gm.rainRandom_vy1, gm.rainRandom_vy2)
          }
        );
      }
      
      // 애니메이션 시작
      requestAnimationFrame(Repeat);
    }catch(e){
      console.log(e)
    }
  }
  
  function Repeat()
  {
    Play(GameManager);
    requestAnimationFrame(Repeat);
  }
  
  function Play(gm)
  {
    
    try{
      let ctx = gm.ctx;
      // 배경
      ctx.drawImage(
        gm.bgImage, 
        0, 0
      );
      
      // 비 움직임
      for(let i=0;i<gm.rainDoing;++i)
      {
        gm.rainObj[i].x1 += 
          gm.rainObj[i].velocity_x / 10;
        gm.rainObj[i].y1 += 
          gm.rainObj[i].velocity_y / 10;
        if( gm.rainObj[i].y1 > 300 )
        {
          gm.rainObj[i].x1 = 
            rand(gm.rainRandom_x1, gm.rainRandom_x2),
          gm.rainObj[i].y1 = 
            rand(gm.rainRandom_y1, gm.rainRandom_y2),
          gm.rainObj[i].velocity_x = 
            rand(gm.rainRandom_vx1, gm.rainRandom_vx2),
          gm.rainObj[i].velocity_y = 
            rand(gm.rainRandom_vy1, gm.rainRandom_vy2)
        }
      }
      
      // 비 갯수 늘어남
      if(gm.rainDoing < gm.rainCount )
      {
        if(rand(0, 100)<= 5){
          gm.rainDoing++;
          gm.bgSound.volume = 
            ( gm.rainDoing / gm.rainCount ) * 0.8;
          if(gm.bgOn==true)
          {
            if(gm.bgSound.paused)
            {
              gm.bgSound.play();
            }
          }
        }
      }
      
      
      
      // 클릭에 따라 스피커 온/오프
      if(gm.clicked==true)
      {
        gm.clicked=false;
        if(gm.mousex > 750 && gm.mousex < 750 + 30 &&
          gm.mousey > 220 && gm.mousey < 220 + 30)
        {
          gm.bgOn = !gm.bgOn;
          if(gm.bgOn==true)
          {
            gm.bgSound.play();
          }
          else
          {
            gm.bgSound.pause();
          }
        }
      }
        
      // 비
      ctx.strokeStyle='rgba(255, 255, 255, 0.2)';
      ctx.beginPath();        
      for(let i=0;i<gm.rainCount;++i)
      {
        ctx.moveTo(
          gm.rainObj[i].x1 - gm.rainObj[i].velocity_x,
          gm.rainObj[i].y1 - gm.rainObj[i].velocity_y
        );
        ctx.lineTo(
          gm.rainObj[i].x1,
          gm.rainObj[i].y1
        );
      }
      ctx.stroke();
      
      // 스피커
      ctx.drawImage(
        gm.speakerImage, 
        750, 220
      );
      
    }catch(e){
      console.log(e)
    }
  }

</script>

<canvas id="MyCanvas" width=800 height=273></canvas>

 

배경이미지를 바꾸고 싶어요!

 

배경이미지를 바꾸고 싶으신가요?
어딘가에 마음에 드는 그림파일을 업로드하신 다음에, 아래 소스를 수정해 주시면 됩니다.
해상도는 화면에 걸맞는 사이즈로 편집해 주세요

// 배경
gm.bgImage = 
  await loadImage("배경이미지");


이 때 그림의 해상도크기에 맞게 아래 소스도 함께 수정해 주셔야 해요.

<canvas id="MyCanvas" width=가로해상고픽셀 height=세로해상도픽셀></canvas>

 

빗소리를 바꾸고 싶어요!

 

빗소리는 사실 배경음악인데요. 베경음악을 바꾸시려면 역시 어딘가에 파일을 업로드해주신 다음에
아래 소스를 수정해 주시면 됩니다.

gm.bgSound.src = "배경음악 URL";

 

빗줄기를 조절하고 싶어요!

 

아래 값들을 자유롭게 조절해 보세요. 
처음에는 빗줄기가 1개(gm.rainDoing)로 시작,
200개(gm.rainCount)까지 불어납니다.

gm.rainCount = 200; // 비의 갯수
gm.rainDoing = 1; // 처음에 작동할 비의 갯수
gm.rainRandom_x1 = -20; // 비의 랜덤 발생 x축
gm.rainRandom_x2 = 820;
gm.rainRandom_y1 = -200; // 비의 랜덤 발생 y축
gm.rainRandom_y2 = -100;
gm.rainRandom_vx1 = -3; // 비의 랜덤 이동 방향 x축
gm.rainRandom_vx2 = 3;
gm.rainRandom_vy1 = 40; // 비의 랜덤 이동 방향 y축
gm.rainRandom_vy2 = 100;


그 밖에도 궁금하신 건 질문 주세요 :)


방문해주시는 모든 분들께 늘 감사드립니다.

도움이 되셨다면 공감 한방, 댓글은 굿잡!
감사합니다~