2010-02-11 5 views
1

충돌 감지에 문제가 있습니다. 기본적으로 단단한 타일을 칠 때 캐릭터의 몸은 이미 타일의 절반 정도입니다. 여기 내 코드가있다.타일 기반 환경에서 충돌 감지

속성 wY와 wX는 내 게임 세계 위치입니다. 무대 위치가 아닙니다. dx와 dy는 캐릭터가 이동하는 속도입니다. 이 첫 번째 코드 스 니펫은 게임 루프 내에 있습니다. 내 캐릭터의 초점 포인트는 x 축 여기

package com.objects 
{ 
    import flash.display.MovieClip; 
    import com.eapi.EngineApi; 
    import flash.events.Event; 

    /** 
    * ... 
    * @author Anthony Gordon 
    */ 
    public class Engine extends EngineApi 
    { 
     public var friction:Number = 0.93; 
     protected var Heros:Array; 

     public function Engine(w:Number = 540,h:Number = 360, tw:Number = 50, th:Number = 50) 
     { 
      super(w, h, tw, th); 
      Heros = new Array(); 
     } 

     override protected function loop(e:Event):void 
     { 
      UpdateObjects(); 
      Rules(); 
      CheckHero(); 
      UpDateMap(); 
     } 

     public function AddHero(g:GameObject):void 
     { 
      Heros.push(g); 
     } 

     protected function Rules():void 
     { 
      //Everything Has friction 
      for (var i:Number = 0; i < gameObjects.length; i++) 
      { 
       var char:GameObject = GameObject(gameObjects[i]); 
       char.dx *= friction; 
       //char.dy *= friction; 

       //Below is the tile positioning of my character 
       var cgridx:Number = Math.floor(char.wX/tileW); 
       var cgridy:Number = Math.floor(char.wY/ tileH); 

       //This is the tile in front of the character 
       var nextx:Number = Math.floor((char.wX + char.dx)/tileW); 
       var nexty:Number = Math.floor((char.wY + char.dy)/tileH); 

       //We assume the character is in the air before we figure it to be false 
       char.onGround = false; 

       //I am about to remove the vars from cgrid below. Keep a look out for issues in the future 
       if (mapHolder[currentMap][nexty][cgridx] == 0 || mapHolder[currentMap][nexty][cgridx] == 2) 
       { 
        //If character is falling down 
        if (char.dy > 0) 
        { 
         char.wY = (nexty * tileH) - 1; 
         cgridy = Math.floor(char.wY/tileH); 
         char.dy = 0; 
         char.onGround = true; 
        } 
        else if (char.dy < 0)//If character is going up 
        { 
         char.wY = (nexty * tileH) + (tileH + 1); 
         cgridy = Math.floor(char.wY/tileH); 
         char.dy = 0; 
        } 
       } 

       //mapHolder is a array that holds an array of maps and their tile numbers 
       if (mapHolder[currentMap][cgridy][nextx] == 2) 
       { 
        if (char.dx > 0)//if character is going right 
        { 
         char.wX = ((nextx * tileW) - 1); 
        } 
        else if (char.dx < 0)// if character is going left 
        { 
         char.wX = (nextx * tileW) + (tileW + 1); 
        } 

        char.dx = 0; 
       } 
       //if character is not on ground then keep faling 
       if (char.onGround == false) 
       { 
        char.dy += .9; 
        if (char.dy > 30) char.dy = 5; 
       } 
      } 
     } 

     protected function CheckHero():void 
     { 
      var char:Hero = Heros[0]; 
      char.x = char.wX - offsX; 
      char.y = char.wY - offsY; 

      if (char.wX < 0) 
      { 
       char.wX = 0; 
       char.dx = 0; 
      } 

      if (char.wY < 0) 
      { 
       char.wY = 0; 
       char.dy = 0; 
      } 

      offsX = char.wX - (vWidth/2); 
      offsY = char.wY - (vHeight/2); 

      if (offsX < 0) 
      { 
       offsX = 0; 
      } 

      if (offsY < 0) 
      { 
       offsY = 0; 
      } 

      //If screen hits the world END STOP!!! 
      if ((offsX + vWidth) > wWidth) 
      { 
       offsX = (wWidth - vWidth); 
      } 

      if ((offsY + vHeight) > wHeight) 
      { 
       offsY = (wHeight - vHeight); 
      } 
      ///// 

      //If char hits the end, Stop!! 
      if (char.wX > wWidth) 
      { 
       char.wX = char.wX - wWidth; 
       char.wX = wWidth; 
      } 

     } 


    } 

} 

을 중심으로하는 내 문자 클래스

package com.objects 
{ 
    import flash.display.MovieClip; 
    import flash.events.*; 
    /** 
    * ... 
    * @author Anthony Gordon 
    */ 
    [Embed(source='../../../bin/Assets.swf', symbol='Hero')] 
    public class Hero extends GameObject 
    { 
     private var aKeyPress:Array; 
     private var jumpDisabled:Boolean = false; 

     public function Hero() 
     { 
      wY = 150; 
      wX = 90; 
      speed = .5; 
      aKeyPress = new Array(); 
      TheGame.sr.addEventListener(KeyboardEvent.KEY_DOWN, keyDownListener); 
      TheGame.sr..addEventListener(KeyboardEvent.KEY_UP,keyUpListener); 
     } 

     private function keyDownListener(e:KeyboardEvent):void { 
      //trace("down e.keyCode=" + e.keyCode);   
      aKeyPress[e.keyCode]=true; 
     } 

     private function keyUpListener(e:KeyboardEvent):void { 
      //trace("up e.keyCode=" + e.keyCode); 
      aKeyPress[e.keyCode]=false; 
     } 

     override public function UpdateObject():void 
     { 
      Controls(); 
      updatePosition(); 
     } 

     private function Controls():void 
     { 
      wX += dx; 
      wY += dy; 

      if (aKeyPress[38])//Key press up 
       ;//vy -= speed;   
      else if (aKeyPress[40])//Key press down 
       ;//dy += speed; 

      if (aKeyPress[37])//left 
       dx -= speed; 
      else if (aKeyPress[39])//Right 
       dx += speed; 

      if (aKeyPress[32]){//space 
       jump(); 
      }     
     }//End Controls 

     private function jump():void 
     { 
      if (!jumpDisabled) 
      { 
       if (onGround) 
       { 
        dy = -15; 
        jumpDisabled = true; 
       } 
      } 
      else 
      { 
       jumpDisabled = false;    
      } 
     } 
    } 

} 

답변

0

글쎄, 문제가 해결되었습니다. 그것은 가장 큰 것은 아니지만 그 10 배나 더 좋았습니다. 여기에 내가 무슨 짓을 ..

내가 변경

... 이것에

if (mapHolder[currentMap][cgridy][nextx] == 2) 
       { 
        if (char.dx > 0)//if character is going right 
        { 
         char.wX = ((nextx * tileW) - 1); 
        } 
        else if (char.dx < 0)// if character is going left 
        { 
         char.wX = (nextx * tileW) + (tileW + 1); 
        } 

        char.dx = 0; 
       } 

...

if (mapHolder[currentMap][cgridy][right] == 2) 
       { 
        char.wX = right * (tileW) - (tileW/2); 
        char.dx = 0; 
       } 
       else if (mapHolder[currentMap][cgridy][left] == 2) 
       { 
        char.wX = right * (tileW) + (tileW/2); 
        char.dx = 0; 
       } 

내 문자 중심점

이 y 축과 X 모두에서 중간에 중심선. 이렇게하려면 다음을 수행했습니다.

if (mapHolder[currentMap][cgridy][left] == 2) 
       { 
        char.wX = (left + 1) * (tileW) + (tileW/2); 
        char.dx = 0; 
       } 

       if (mapHolder[currentMap][cgridy][right] == 2) 
       { 
        char.wX = right * (tileW) - (tileW/2); 
        char.dx = 0; 
       } 

왼쪽과 오른쪽은 영웅의 왼쪽과 오른쪽에있는 타일입니다. 왼쪽에 대해 내가 한 일은이 작업을 수행하여 오른쪽에있는 다음 타일을 얻었습니다 (왼쪽 + 1). 그때 나는 그것 (왼쪽 + 1) * (tileW)에 의해 그것의 픽셀 위치를 multiplling tileW로 얻었다. 내 타일 초점 포인트는 모두 왼쪽 상단에 있습니다. 그래서 캐릭터를 오른쪽에 배치하십시오. 타일 ​​절반을 추가해야했습니다. 그렇지 않으면 내 영웅의 중심점이 왼쪽 타일과 오른쪽 타일 (왼쪽 + 1) 사이에 위치합니다. 권리는 거의 같았습니다. 그러나 당신은 그림을 얻는다. ... 나는 희망한다.

1

글쎄,이가없이 디버깅하기 어려운 일이지만, 여기 붙어 뭔가입니다 나에게.

이 두 선 사이의 차이는 홀수로 저를 친다 :

온 왜해야합니까 (tileW + 1)

char.wX = (nextx * tileW) + (tileW + 1); 

을 왼쪽으로가는 적합한

char.wX = ((nextx * tileW) - 1); 

진행을 위해 두 번째 끝? 나는이 선들이 같을 것이라고 생각할 것이다. 첫 번째 줄에 -1이 왜 있는지도 모르겠지만이 줄은 적어도 내 의견으로는 같아야합니다.

타일 기반 일 때 사람이 처음으로 dx와 dy를 망치는 이유는 사람이 한 타일 만 이동할 수 있기 때문입니다. 네가하는 방식이 내게 아주 이상해 보일거야.

+0

char.wX = (nextx * tileW) + (tileW + 1); 나는 책에서 그것을 참조했다. 나는 왜 그가 그것을 사용하는지 모르겠습니다. 아마 나의 초점 포인트는 영웅의 왼쪽에 있어야한다. 그리고, 영웅은 규칙적인 픽셀 단위로 움직일 수 있습니다. 코드를 업데이트했습니다. Wx와 Wy는 게임 세계에서의 포지셔닝입니다. 그들은 여전히 ​​픽셀과 같습니다. – numerical25

2

이동하기 전에 테스트를 받아야합니다.

위의 코드에서 파싱 할 수있는 내용부터 플레이어를 이동 한 다음 충돌을 테스트합니다. 그렇다면 아무 것도 치지 않으면 이동을 취소 할 준비가되어 있어야합니다 (재미도 디버그도되지 않습니다).

간단히 말해서 플레이어가 움직일 방향으로 앉아있는 타일을 보는 IsBlocked() 메서드를 호출 할 수 있습니다.

if (!player.IsBlocked()) 
{ 
    player.Move(); 
} 
else 
{ 
    player.HandleCollision(); 
} 
+0

나는 아주 잘못 될 수는 있지만, 나는 그가 움직이기 전에 확인하고 있다고 생각한다. 그것이 mapHolder에 대한 검사입니다. 그렇다면 다시, 그의 코드는 나에게 특히 명확하지 않다. 아마도 나는 틀렸다. –

+0

도움을 주셔서 감사합니다. 나는 더 노력하고있는 코드에 대해 더 자세히 설명했다. 엔진 클래스에는 객체를 검사하는 순서를 보여주는 루프가 있습니다. – numerical25

+0

영웅의 오른쪽이나 왼쪽에 초점을 맞 춥니 다. 그런 다음 초점 지점이있는면에는 정확한 충돌이 있습니다. 그것은 완벽하게 작동합니다. 내가 중심에 놓으면 반쯤 지나갈 때입니다. 초점 포인트가 어디에 있든 큰 효과가있는 것 같습니다. 하지만 캐릭터의 양쪽에서 작동하는 방식을 고치는 방법을 모릅니다. – numerical25

2

나는 코드를 실제로 이해할 수 없지만 내 메가맨 엔진을 만들면서 내가 공유 할 수있는 몇 가지 사실을 알게되었습니다. 내 충돌 처리 방법에는 이동을 시도한 다음 필요한 양만큼 뒤로 이동하는 것이 포함되었습니다. 또한 어느 방향에서 블록에 접근했는지 알 필요가 있습니다. 이는 사소한 것이 아닙니다.

1) 이동을 시도하십시오. player.position += player.velocity

2) 경계 상자의 교차로

2A)가 플레이어의의 교회법 및 블록의 경계 사각형을 찾기를 사용하여 충돌이 있는지 확인합니다. 나는 이것을위한 공식을주지 않을 것이고, 그것은 거의 사소한 것이다. 2b) 요점 : 반드시 높이 0 또는 너비 0 (교차가 아닌) 교차를 충돌로 간주해야합니다! 그렇지 않으면 플레이어가 충돌 표면을 "진동"시킵니다.

3) 교차 직사각형을 사용하여 접근 방향을 찾습니다. 이를위한 알고리즘은 접근 속도의 경사와 교차 직사각형의 대각선을 비교하는 것을 포함합니다.

4) 접근 방향 (수평 또는 수직)을 기반으로 이동의 x 또는 y 구성 요소를 취소할지 여부를 결정합니다. 되 돌리는 양으로 교차점의 높이 또는 너비를 사용하십시오.

5) 이제 플레이어가 그 방향으로 차단되었다는 사실을 저장하십시오. 이제 블록을 만지고 있지만 블록에 포함되어 있지 않습니다. 이것이 0 크기의 교차점이 여전히 충돌 인 이유입니다. 그렇지 않은 경우 다음 프레임에서는 충돌하지 않고 다시 넘어져서 "진동하는"효과를냅니다.

"이미 타일의 중간에"있는 한 실수로 플레이어의 중심점을 타일의 가장자리와 비교하고 있습니까?

+0

나는 당신의 말을 듣습니다. 나는 책에서 말하는 것 대신에 이것을 시도 할 것이다. 내가 가서 그걸 시험해 보겠다. – numerical25