2011-12-12 2 views
1

를 메쉬, 내 원하는 동작은 다음과 같습니다XNA 모델 구가

  • 구가 무대의 중앙에서 시작
  • 는 그것의 4 개의 벽 중 하나와 충돌 할 때
  • 은 0과 45도

간의 임의의 각도에서 반대 방향으로 다시 반송하는 임의의 방향으로 이동 Enter 키를 누르면 아래 그림에 나와 있지 않은 문제는 충돌하거나 튀는 대신 벽을 통과하는 것입니다.

볼 구형의 모델 위치를 업데이트 해 보았지만 여전히 절단하지 않았습니다. 나는 공의 반경을 100과 같이 큰 숫자로 설정하려고 시도했다. 그러나 움직임이 시작되어 벽에 부딪 치고 진동하기 전에 충돌한다.

Visual Screenshot Of World Space

소스 코드 (Ball.cs) : 나는 충돌 감지 문제를 해결할 때까지

using System; 
using System.Collections.Generic; 
using System.Linq; 
using Microsoft.Xna.Framework; 
using Microsoft.Xna.Framework.Audio; 
using Microsoft.Xna.Framework.Content; 
using Microsoft.Xna.Framework.GamerServices; 
using Microsoft.Xna.Framework.Graphics; 
using Microsoft.Xna.Framework.Input; 
using Microsoft.Xna.Framework.Media; 

namespace _3D_Pong 
{ 
    class Ball 
    { 
     private Model model; 
     private Vector3 modelpos; 
     private Random random = new Random(); 
     public Vector3 ModelPosition { get; set; } 
     private Vector3 FowardDirection { get; set; } 
     private float randomangle; 
     private int direction = 0; 
     private bool start = false; 
     private int v; 
     public Ball(Model m, Vector3 initial_position, int velocity = 30) 
     { 
      v = velocity; 
      model = m; 
      modelpos = initial_position; 
      randomangle = MathHelper.ToRadians(random.Next(0, 45)); 
      direction = random.Next(1); 
      FowardDirection = Matrix.CreateRotationY(randomangle).Forward; 

     } 
     public void BeginMoving() 
     { 
      start = true; 
     } 
     private BoundingSphere BallsBounds() 
     { 
      Matrix worldTransform = Matrix.CreateTranslation(modelpos); 
      Vector3 min = new Vector3(float.MaxValue, float.MaxValue, float.MaxValue); 
      Vector3 max = new Vector3(float.MinValue, float.MinValue, float.MinValue); 

      ModelMesh mesh = model.Meshes[0]; 
      foreach (ModelMeshPart meshPart in mesh.MeshParts) 
      { 
       int vertexStride = meshPart.VertexBuffer.VertexDeclaration.VertexStride; 
       int vertexBufferSize = meshPart.NumVertices * vertexStride; 

       float[] vertexData = new float[vertexBufferSize/sizeof(float)]; 
       meshPart.VertexBuffer.GetData<float>(vertexData); 

       for (int i = 0; i < vertexBufferSize/sizeof(float); i += vertexStride/sizeof(float)) 
       { 
        Vector3 transformedPosition = Vector3.Transform(new Vector3(vertexData[i], vertexData[i + 1], vertexData[i + 2]), worldTransform); 
        min = Vector3.Min(min, transformedPosition); 
        max = Vector3.Max(max, transformedPosition); 
       } 
      } 

      BoundingSphere sphere = BoundingSphere.CreateFromBoundingBox(new BoundingBox(min, max)); 
      return sphere; 
     } 
     public void Draw(Camera camera, ArenaRenderer arena) 
     { 
      if (start) 
      { 


       bool predicate1, predicate2, predicate3, predicate4; 
       predicate1 = BallsBounds().Intersects(arena.FirstWall()); 
       predicate2 = BallsBounds().Intersects(arena.SecondWall()); 
       predicate3 = BallsBounds().Intersects(arena.ThirdWall()); 
       predicate4 = BallsBounds().Intersects(arena.FourthWall()); 
       if (predicate1 || predicate2 || predicate3 || predicate4) 
       { 
        if (direction == 0) 
        { 
         direction = 1; 
         randomangle = MathHelper.ToRadians(random.Next(0, 45)); 
         FowardDirection = Matrix.CreateRotationY(randomangle).Forward; 

        } 
        else if (direction == 1) 
        { 
         direction = 0; 
         randomangle = MathHelper.ToRadians(random.Next(0, 45)); 
         FowardDirection = Matrix.CreateRotationY(randomangle).Forward; 
        } 
       } 
       if (direction == 1) 
       { 
        modelpos += FowardDirection * v; 
       } 
       else 
       { 
        modelpos -= FowardDirection * v; 
       } 
      } 
      model.Draw(Matrix.CreateTranslation(modelpos), camera.View, camera.Projection); 
     } 
    } 
} 

소스 (Arena.cs)

using System; 
using System.Collections.Generic; 
using System.Linq; 
using Microsoft.Xna.Framework; 
using Microsoft.Xna.Framework.Audio; 
using Microsoft.Xna.Framework.Content; 
using Microsoft.Xna.Framework.GamerServices; 
using Microsoft.Xna.Framework.Graphics; 
using Microsoft.Xna.Framework.Input; 
using Microsoft.Xna.Framework.Media; 

namespace _3D_Pong 
{ 
    class ArenaRenderer 
    { 
     private Model model; 
     public ArenaRenderer(Model m) 
     { 
      model = m; 
     } 
     public BoundingBox FirstWall() 
     { 
      Matrix worldTransform = Matrix.CreateTranslation(Vector3.Zero); 
      // Initialize minimum and maximum corners of the bounding box to max and min values 
      Vector3 min = new Vector3(float.MaxValue, float.MaxValue, float.MaxValue); 
      Vector3 max = new Vector3(float.MinValue, float.MinValue, float.MinValue); 

      ModelMesh mesh = model.Meshes[0]; 
      foreach (ModelMeshPart meshPart in mesh.MeshParts) 
      { 
       // Vertex buffer parameters 
       int vertexStride = meshPart.VertexBuffer.VertexDeclaration.VertexStride; 
       int vertexBufferSize = meshPart.NumVertices * vertexStride; 

       // Get vertex data as float 
       float[] vertexData = new float[vertexBufferSize/sizeof(float)]; 
       meshPart.VertexBuffer.GetData<float>(vertexData); 

       // Iterate through vertices (possibly) growing bounding box, all calculations are done in world space 
       for (int i = 0; i < vertexBufferSize/sizeof(float); i += vertexStride/sizeof(float)) 
       { 
        Vector3 transformedPosition = Vector3.Transform(new Vector3(vertexData[i], vertexData[i + 1], vertexData[i + 2]), worldTransform); 

        min = Vector3.Min(min, transformedPosition); 
        max = Vector3.Max(max, transformedPosition); 
       } 
      } 


      // Create and return bounding box 
      return new BoundingBox(min, max); 
     } 
     public BoundingBox SecondWall() 
     { 
      Matrix worldTransform = Matrix.CreateTranslation(Vector3.Zero); 
      // Initialize minimum and maximum corners of the bounding box to max and min values 
      Vector3 min = new Vector3(float.MaxValue, float.MaxValue, float.MaxValue); 
      Vector3 max = new Vector3(float.MinValue, float.MinValue, float.MinValue); 

      ModelMesh mesh = model.Meshes[1]; 
      foreach (ModelMeshPart meshPart in mesh.MeshParts) 
      { 
       // Vertex buffer parameters 
       int vertexStride = meshPart.VertexBuffer.VertexDeclaration.VertexStride; 
       int vertexBufferSize = meshPart.NumVertices * vertexStride; 

       // Get vertex data as float 
       float[] vertexData = new float[vertexBufferSize/sizeof(float)]; 
       meshPart.VertexBuffer.GetData<float>(vertexData); 

       // Iterate through vertices (possibly) growing bounding box, all calculations are done in world space 
       for (int i = 0; i < vertexBufferSize/sizeof(float); i += vertexStride/sizeof(float)) 
       { 
        Vector3 transformedPosition = Vector3.Transform(new Vector3(vertexData[i], vertexData[i + 1], vertexData[i + 2]), worldTransform); 

        min = Vector3.Min(min, transformedPosition); 
        max = Vector3.Max(max, transformedPosition); 
       } 
      } 


      // Create and return bounding box 
      return new BoundingBox(min, max); 
     } 
     public BoundingBox ThirdWall() 
     { 
      Matrix worldTransform = Matrix.CreateTranslation(Vector3.Zero); 
      // Initialize minimum and maximum corners of the bounding box to max and min values 
      Vector3 min = new Vector3(float.MaxValue, float.MaxValue, float.MaxValue); 
      Vector3 max = new Vector3(float.MinValue, float.MinValue, float.MinValue); 

      ModelMesh mesh = model.Meshes[2]; 
      foreach (ModelMeshPart meshPart in mesh.MeshParts) 
      { 
       // Vertex buffer parameters 
       int vertexStride = meshPart.VertexBuffer.VertexDeclaration.VertexStride; 
       int vertexBufferSize = meshPart.NumVertices * vertexStride; 

       // Get vertex data as float 
       float[] vertexData = new float[vertexBufferSize/sizeof(float)]; 
       meshPart.VertexBuffer.GetData<float>(vertexData); 

       // Iterate through vertices (possibly) growing bounding box, all calculations are done in world space 
       for (int i = 0; i < vertexBufferSize/sizeof(float); i += vertexStride/sizeof(float)) 
       { 
        Vector3 transformedPosition = Vector3.Transform(new Vector3(vertexData[i], vertexData[i + 1], vertexData[i + 2]), worldTransform); 

        min = Vector3.Min(min, transformedPosition); 
        max = Vector3.Max(max, transformedPosition); 
       } 
      } 


      // Create and return bounding box 
      return new BoundingBox(min, max); 
     } 
     public BoundingBox FourthWall() 
     { 
      Matrix worldTransform = Matrix.CreateTranslation(Vector3.Zero); 
      // Initialize minimum and maximum corners of the bounding box to max and min values 
      Vector3 min = new Vector3(float.MaxValue, float.MaxValue, float.MaxValue); 
      Vector3 max = new Vector3(float.MinValue, float.MinValue, float.MinValue); 

      ModelMesh mesh = model.Meshes[3]; 
      foreach (ModelMeshPart meshPart in mesh.MeshParts) 
      { 
       // Vertex buffer parameters 
       int vertexStride = meshPart.VertexBuffer.VertexDeclaration.VertexStride; 
       int vertexBufferSize = meshPart.NumVertices * vertexStride; 

       // Get vertex data as float 
       float[] vertexData = new float[vertexBufferSize/sizeof(float)]; 
       meshPart.VertexBuffer.GetData<float>(vertexData); 

       // Iterate through vertices (possibly) growing bounding box, all calculations are done in world space 
       for (int i = 0; i < vertexBufferSize/sizeof(float); i += vertexStride/sizeof(float)) 
       { 
        Vector3 transformedPosition = Vector3.Transform(new Vector3(vertexData[i], vertexData[i + 1], vertexData[i + 2]), worldTransform); 

        min = Vector3.Min(min, transformedPosition); 
        max = Vector3.Max(max, transformedPosition); 
       } 
      } 


      // Create and return bounding box 
      return new BoundingBox(min, max); 
     } 

     public void Draw(Camera camera) 
     { 

      model.Draw(Matrix.CreateTranslation(Vector3.Zero), camera.View, camera.Projection); 
     } 
    } 
} 

은 내가 패를 구현하지 않은 . 정보가 누락 된 경우 의견을 남기십시오. 나는 내가 생각할 수있는 모든 것을 시도했습니다.

각 벽의 경계에 대해 하나의 기능이 있으므로 변경했습니다.

1) 번 이상 동일한 기능 이상을 작성해야 두 번째 중지하고 재고 :)

팁,

public BoundingBox GetWallBounds(int index) 
     { 
      Matrix worldTransform = Matrix.CreateTranslation(Vector3.Zero); 
      // Initialize minimum and maximum corners of the bounding box to max and min values 
      Vector3 min = new Vector3(float.MaxValue, float.MaxValue, float.MaxValue); 
      Vector3 max = new Vector3(float.MinValue, float.MinValue, float.MinValue); 

      ModelMesh mesh = model.Meshes[index]; 
      foreach (ModelMeshPart meshPart in mesh.MeshParts) 
      { 
       // Vertex buffer parameters 
       int vertexStride = meshPart.VertexBuffer.VertexDeclaration.VertexStride; 
       int vertexBufferSize = meshPart.NumVertices * vertexStride; 

       // Get vertex data as float 
       float[] vertexData = new float[vertexBufferSize/sizeof(float)]; 
       meshPart.VertexBuffer.GetData<float>(vertexData); 

       // Iterate through vertices (possibly) growing bounding box, all calculations are done in world space 
       for (int i = 0; i < vertexBufferSize/sizeof(float); i += vertexStride/sizeof(float)) 
       { 
        Vector3 transformedPosition = Vector3.Transform(new Vector3(vertexData[i], vertexData[i + 1], vertexData[i + 2]), worldTransform); 

        min = Vector3.Min(min, transformedPosition); 
        max = Vector3.Max(max, transformedPosition); 
       } 
      } 


      // Create and return bounding box 
      return new BoundingBox(min, max); 
     } 

답변

2

일반 팁 : XNA에서는 Draw 메서드에서 충돌 감지를해서는 안됩니다. 이 방법은 초당 60 프레임보다 적은 시간이라고 할 수 있습니다. 클래스의 Update 메서드에서이 작업을 수행해야합니다. 자세한 설명은 here을 참조하십시오.

충돌 감지가 잘못되었다고 생각합니다. 임의의 방향을 선택하는 것뿐만 아니라 방향 각도를 반영해야합니다.

또한 현재 위치에 추가 할 속도 벡터를 추가해야합니다. 직위로 직접 작업하는 대신 벡터로 작업하는 것이 훨씬 쉽습니다.

C#에서 Pong을 구현하는 데 필요한 수 많은 튜토리얼이 있습니다.하나는 위치와 다른 하나는 위치 각 업데이트에 추가됩니다 속도를 나타내며,

http://www.freewebs.com/campelmxna/XNATutorials/XNATut4.htm

참고가 두 개의 다른 회원이 : 이건 그냥 샘플입니다.

그 외에는 매번 공 위치에 추가 할 델타가 너무 많아 경계 벽을 "건너 뛰고"있을 수 있습니다. 1) 델타를 줄이거 나 2) 경계 벽을 더 넓게 만들 수 있습니다.

+0

좋은 서면 답변에 대한 제안 +1. –

2

나에게 학교/대학 과제처럼 보인다. 함수가 하나 또는 소수의 변수/값에 의해서만 변하는 경우 변수를 변수로 받아들이는 함수 하나를 작성하십시오. 2) 위의 1)을 수행하면 코드를 단계별로 실행하고 히트 테스트 계산이 실패하는 이유를 쉽게 찾아 낼 수 있습니다. 그런 다음 수정 프로그램을 한 곳에서 적용 할 수 있습니다.

+0

취미 프로젝트는 저를 신뢰합니다. 당신은 맞습니다. 나는 각 벽에 경계를 잡는 하나의 기능을 가져야 만합니다. 나는 그것을 고쳤지 만 여전히 공이 충돌하지 않는 이유에 대해서는 대답하지 않는다. 경계 영역에 대한 모델의 위치를 ​​업데이트하고 디버깅 값을 살펴 봅니다. 그러나 모든 것이 정상적으로 보입니다. 아마 반경은 작지만 0보다 클 것입니다. –

+0

+1은 과부하를 제안합니다. 그들은 정말로 코드를 정리하고 디버깅을 훨씬 쉽게 만듭니다. – piebie

+1

경계 상자 접근 방식은 공이 벽을 가로막는 지 여부를 신속하고 저렴하게 테스트 할 수있는 좋은 방법입니다. 볼이 벽 근처에있을 때 디버거를 깨고 코드를 단계별로 실행하여 볼의 경계 상자가 벽을 가로 챌 때를 결정해야합니다. 프로젝트를 압축하여 첨부하면 코드 실행 및 디버깅을 시도 할 수 있습니다. –

관련 문제