쓸만한 주저리

자바스크립트로 Shooting Game 만들기

봄돌73 2009. 4. 2. 17:47


test.html



시작



현재 아래 네모(우주선?)를 좌우로 움직일 수 있고, 무기를 발사할 수 있다.

여기까지의 문제는 무기를 몇 번만 연달아 발사해도 느려지는 속도다.

무언가 다른 방법으로 무기 궤적을 계산해야 할 것 같은데 딱히 생각나는 것이 없다.

다음은 적 네모를 만들어서 무기가 적 네모에 닿으면 둘 다 사라지게 하는 것을 구현할 계획이다.

아래는 source, 〈를 <로 바꾸면 정상 작동한다.


적 등장까지 해결.

다음은 무기와 적이 마주치면 사라지는 것.

그 다음은 적과 우주선이 마주치면 사라지는 것.

그 다음은 적이 무기를 쏘는 것? 가능할까?


화면이 보이자마자 시작되니까 시스템 자원을 낭비하는 것 같다.

시작 버튼을 달았다.

레벨 개념 탑재.

10마리 마다 1레벨 상승.

1레벨 상승 마다 적 등장이 0.1초씩 짧아짐.

적 등장 속도를 무작위로 설정했는데 setInterval로는 무작위 설정이 안되서 setTimeout으로 재귀호출함.

무한정 적이 등장하면 결국 너무 느려지는 현상 때문에 적 등장 속도가 최초로 0.01초 이하가 되는 순간 종료.


드디어 적을 무기로 쏴서 없애는 기능까지 완료.


무기 이동 단위를 5px로 바꿔서 난이도를 낮췄다.

무기를 쏠 때와 적 네모를 맞출 때 소리가 난다.

소리가 한 박자 늦게 나긴 하지만 뭐...

실제 구현하는 화면은 다음 Blog에서 적용이 안되서 못 바꿨다.

Source는 아래를 보라.


〈div id=space style=width:500px;height:500px;position:absolute;top:0px;left:0px;background:tan onmousedown=shoot()>
  〈div id=craft style=width:10px;height:10px;position:absolute;top:480px;background:black>〈/div>
  〈div name=enemy id=enemy style=width:10px;height:10px;position:absolute;top:480px;background:red;display:none>〈/div>
〈/div>
〈div name=bullet id=bullet style=width:3px;height:3px;background:blue;position:absolute;display:none>〈/div>
〈div>
  〈span id=level style=position:absolute;top:500px;left:30px>〈/span>
  〈span id=shootcount style=position:absolute;top:500px;left:60px>〈/span>
  〈span id=enemycount style=position:absolute;top:500px;left:120px>〈/span>
  〈span id=crashcount style=position:absolute;top:500px;left:180px>〈/span>
  〈span onclick="i=j=k=0;enemy_appear()" style="position: absolute; top: 500px; left: 240px; cursor: pointer;">시작〈/span>
〈/div>
〈div id=debug style=position:absolute;top:500px;left:0px;display:none>debug〈/div>
〈script>
  if(-1!=navigator.userAgent.indexOf("MSIE")){
    document.write('〈OBJECT id="playsound"')
    document.write(' classid="clsid:6BF52A52-394A-11d3-B153-00C04F79FAA6"')
    document.write(' width=0 height=0>〈/OBJECT>')
  }
  else if(-1!=navigator.userAgent.indexOf("Firefox")){
    document.write('〈OBJECT id="playsound"')
    document.write(' type="application/x-ms-wmp"')
    document.write(' width=0 height=0>〈/OBJECT>')
  }

  var i=0
  function shoot(){
    //발사 소리
    if(-1!=navigator.userAgent.indexOf("MSIE")){
      playsound.URL='https://t1.daumcdn.net/cfile/blog/153CC40D49DB147B98?download'
    }
    else if(-1!=navigator.userAgent.indexOf("Firefox")){
      playsound.URL='https://t1.daumcdn.net/cfile/blog/153CC40D49DB147B98?download'
      playsound.controls.play()
    }
    var space=document.getElementById('space')
    var craft=document.getElementById('craft')
    var bullet=document.getElementById('bullet').cloneNode(true)
    bullet.style.display=''
    bullet.style.left=craft.offsetLeft+craft.offsetWidth/2
    bullet.style.top=480
    bullet.id='bullet'+i++
    space.appendChild(bullet)
    document.getElementById('shootcount').innerHTML=i
    movebullet(bullet.id,space.id)
  }

  var c_count=0
  var crash_count=0
  function movebullet(obj1id,obj2id){
    var obj1=document.getElementById(obj1id)
    var obj2=document.getElementById(obj2id)
    if(obj1!=null){
      //무기 좌표 계산(중앙점)
      var bullet_x=obj1.offsetLeft+obj1.offsetWidth/2
      var bullet_y=obj1.offsetTop+obj1.offsetHeight/2
      //적 좌표와 무기 좌표가 겹치는지 확인
      for(c_count=j;c_count>=0;c_count--){
        var enemy_obj=document.getElementById('enemy'+c_count)
        if(enemy_obj!=null){
          var enemy_x1=enemy_obj.offsetLeft
          var enemy_x2=enemy_obj.offsetLeft+enemy_obj.offsetWidth
          var enemy_y1=enemy_obj.offsetTop
          var enemy_y2=enemy_obj.offsetTop+enemy_obj.offsetHeight
          //document.getElementById('debug').innerHTML=c_count+'/'+enemy_x1+'/'+enemy_x2+'/'+enemy_y1+'/'+enemy_y2
          if(bullet_x>=enemy_x1 && bullet_x〈=enemy_x2 && bullet_y>=enemy_y1 && bullet_y〈=enemy_y2){
            //격추 소리
            if(-1!=navigator.userAgent.indexOf("MSIE")){
              playsound.URL='https://t1.daumcdn.net/cfile/blog/183C130D49DB14754D?download'
            }
            else if(-1!=navigator.userAgent.indexOf("Firefox")){
              playsound.URL='https://t1.daumcdn.net/cfile/blog/183C130D49DB14754D?download'
              playsound.controls.play()
            }
            obj2.removeChild(enemy_obj)
            obj2.removeChild(obj1)
            document.getElementById('crashcount').innerHTML=++crash_count
            return
          }
        }
      }
      if(parseInt(obj1.offsetTop)〈1){
        obj2.removeChild(obj1)
      }
      else{
        obj1.style.top=parseInt(obj1.style.top.replace('px',''))-5
      }
      setTimeout('movebullet(\''+obj1id+'\',\''+obj2id+'\')',10)
    }
  }

  var x=0,y=0
  function movecraft(e){
    var craft=document.getElementById('craft')
    if(craft!=null){
      if(e){
        //불여우용
        x=e.pageX
        y=e.pageY
      }
      else{
        //ie용
        x=window.event.clientX
        y=window.event.clientY
      }
      //document.getElementById('debug').innerHTML=x
      //세로 이동
      //craft.style.top=y-craft.offsetHeight/2
      //가로 이동
      craft.style.left=x-craft.offsetWidth/2
    }
  }

  document.getElementById('space').onmousemove=movecraft

  //적 나오게 하기
  var j=0 //적 출현 누적 횟수
  var k=0 //레벨
  function enemy_appear(){
    //적 10마리에 레벨 1 상승
    if((j % 10)==0 && j>0){
      k++
    }
    var space=document.getElementById('space')
    var enemy=document.getElementById('enemy').cloneNode(true)
    enemy.style.display=''
    enemy.style.top=0
    enemy.style.left=parseInt(Math.random()*490)  //등장 위치 무작위 설정
    enemy.id='enemy'+j++
    space.appendChild(enemy)
    move_enemy(enemy.id,space.id)
    document.getElementById('enemycount').innerHTML=j
    //0레벨에서는 2~3초 사이에 하나씩, 1레벨이 올라갈 수록 0.1초씩 짧아진다.
    //1레벨일 때는 1.9~2.9초 사이에 하나씩.
    var appear_time=Math.random()*3000-(k*100)
    if(appear_time〈(2000-(k*100))){
      appear_time+=1000
    }
    //다음 적 출현 시간 0.01초 이하가 되면 종료
    if(appear_time>10){
      setTimeout('enemy_appear()',appear_time)
    }
  }

  function move_enemy(obj1id,obj2id){
    var obj1=document.getElementById(obj1id)
    var obj2=document.getElementById(obj2id)
    //document.getElementById('debug').innerHTML=obj1.style.top
    if(obj1!=null){
      if(parseInt(obj1.offsetTop)>490){
        obj2.removeChild(obj1)
      }
      else{
        obj1.style.top=parseInt(obj1.style.top.replace('px',''))+1
      }
      setTimeout('move_enemy(\''+obj1id+'\',\''+obj2id+'\')',10)
    }
  }
〈/script>


test.html
0.01MB