*Solved* Polygons not colliding

Here's the place to get help and discuss features. The focus is on the C++ version, but generic questions are welcome.
dleksen
Posts: 3
Joined: Fri Mar 31, 2017 6:54 am

*Solved* Polygons not colliding

Postby dleksen » Fri Mar 31, 2017 7:14 am

**************Solved, see third post************
[Edit: If I add a second triangle and have it fall into the other triangle, both triangles do not collide with anything else.. I have used Box2D to do this in the past. This is the simplest example I can come up with, and I'm frustrated.. This is quite embarassing, having used Box2D before. Does anyone have simple code of two triangles bouncing for sdl2 and opengl? Much appreciated.]

[Edit: I started a brand new visual studio project, with all other game specific code removed, and cleaned it up and re-posted the code below. I am still getting the same problem.. The two balls bounce off each other, but the triangle goes through both balls without colliding.]

When two circles hit each other, they bounce off. But one polygon and one circle go right through each other. I looked at their positions and verified that they indeed do occupy the same spot at one time and go through each other. I did not set any filters, so they are all default. I am stumped.. Here is the relevant code:

Code: Select all

#ifndef TESTAPP_H
#define TESTAPP_H
#include "d2d.h"

namespace Space
{
   class TestApp : public d2d::Application
   {
   protected:
      bool Init();
      bool Tick();
      void Shutdown();

      d2d::Timer m_timer;
      b2World* m_b2WorldPtr{ nullptr };
      b2Body* m_circle1Ptr{ nullptr };
      b2Body* m_circle2Ptr{ nullptr };
      b2Body* m_polyPtr{ nullptr };
      float m_timeAccumulator{ 0.0f };
      const float m_timeStep{ 1.0f / 60.0f };
      const int m_velocityIterations{ 10 };
      const int m_positionIterations{ 8 };
   };
}
#endif //TESTAPP_H

Code: Select all

#include "stdafx.h"
#include "TestApp.h"
#include "d2d.h"

namespace Space
{
   bool TestApp::Init()
   {
      d2d::ScreenDef settings;
      d2d::InitD2D(settings);

      // Timer
      m_timer.Start();

      b2Vec2 b2Gravity{ 0.0f,0.0f };
      m_b2WorldPtr = new b2World(b2Gravity);

      b2CircleShape circle;
      circle.m_radius = 75.0f;

      b2FixtureDef fixtureDef;
      fixtureDef.restitution = 1.0f;
      fixtureDef.friction = 1.0f;
      fixtureDef.density = 2.0f;
      fixtureDef.shape = &circle;

      b2BodyDef b2Def;
      b2Def.type = b2_dynamicBody;
      b2Def.position.Set(-300.0f, 0.0f);
      b2Def.linearVelocity.Set(50.0f, 0.0f);

      m_circle1Ptr = m_b2WorldPtr->CreateBody(&b2Def);
      m_circle1Ptr->CreateFixture(&fixtureDef);

      circle.m_radius = 50.0f;
      fixtureDef.shape = &circle;
      b2Def.position.Set(600.0f, 0.0f);
      b2Def.linearVelocity.Set(-90.0f, 0.0f);
      
      m_circle2Ptr = m_b2WorldPtr->CreateBody(&b2Def);
      m_circle2Ptr->CreateFixture(&fixtureDef);

      b2PolygonShape poly;
      poly.m_count = 3;
      poly.m_vertices[0].Set(20.0f, 0.0f);
      poly.m_vertices[1].Set(-20.0f, 0.0f);
      poly.m_vertices[2].Set(0.0f, 20.0f);
      

      fixtureDef.shape = &poly;
      b2Def.position.Set(200.0, 0.0f);
      b2Def.linearVelocity.Set(-10.0f, 0.0f);
      m_polyPtr = m_b2WorldPtr->CreateBody(&b2Def);
      m_polyPtr->CreateFixture(&fixtureDef);

      return true;
   }
   void TestApp::Shutdown()
   {
      delete m_b2WorldPtr;
      d2d::QuitD2D();
   }
   bool TestApp::Tick()
   {
      // Handle events
      SDL_Event event;
      while (SDL_PollEvent(&event) != 0)
      {
         switch (event.type)
         {
         case SDL_QUIT:
            return nullptr;
         case SDL_KEYDOWN:
            if (event.key.keysym.sym == SDLK_ESCAPE)
               return false;
            break;
         }
      }

      // Update timer
      m_timer.Tick();
      float deltaSeconds = m_timer.GetDeltaSeconds();

      
      if (m_b2WorldPtr)
      {
         // Update physics
         m_timeAccumulator += deltaSeconds;
         while (m_timeAccumulator > m_timeStep)
         {
            m_b2WorldPtr->Step(m_timeStep, m_velocityIterations, m_positionIterations);
            m_timeAccumulator -= m_timeStep;
         }

         // Set Camera
         float cameraWidth = 2000.0f;
         float cameraHeight = cameraWidth / d2d::Renderer::GetXYAspectRatio();
         d2d::Renderer::SetCamera(b2Vec2(200.0f, 0.0f), b2Vec2(cameraWidth, cameraHeight));
         d2d::Renderer::SetColor(d2d::Color(1.0f, 1.0f, 1.0f));

         // Draw x and y axes
         d2d::Renderer::DrawLine(b2Vec2(0.0f, -3000.0f), b2Vec2(0.0f, 3000.0f));
         d2d::Renderer::DrawLine(b2Vec2(-3000.0f, 0.0f), b2Vec2(3000.0f, 0.0f));

         // Draw shapes
         for (b2Body* b = m_b2WorldPtr->GetBodyList(); b; b = b->GetNext())
         {
            for (b2Fixture* f = b->GetFixtureList(); f; f = f->GetNext())
            {
               if (f->GetType() == b2Shape::e_circle)
               {
                  b2CircleShape* circlePtr = (b2CircleShape*)f->GetShape();
                  if (circlePtr)
                  {
                     const b2Vec2 transformedLocalCenter = b2Mul(b->GetTransform(), circlePtr->m_p);
                     d2d::Renderer::DrawCircle(transformedLocalCenter, circlePtr->m_radius, false);
                  }
               }
               else if (f->GetType() == b2Shape::e_polygon)
               {
                  b2PolygonShape* polygonPtr = (b2PolygonShape*)f->GetShape();
                  if (polygonPtr)
                  {
                     d2d::Renderer::DrawPolygon(b->GetTransform(), polygonPtr->m_vertices, polygonPtr->m_count, false);
                  }
               }
            }
         }
      }
      d2d::Renderer::PresentScene();
      return true;
   }
}


Code: Select all

      ///-----------------------------\------------------------------------------------------
      //| Name: DrawCircle    |
      //\-----------------------------/
      // PostCondition: A circle with radius is rendered at center.
      //      If radius is negative, its absolute value is used.
      //      If fill is true, the circle is solid. Otherwise, it is an outline.
      //      The color of the circle is determined by the last call to SetColor().
      //-------------------------------------------------------------------------------------
      void DrawCircle(const b2Vec2& center, float radius, bool fill)
      {
         std::cout << "circle " << center.x << " " << center.y << " " << radius << std::endl;
         int numVertices;
         float radiansPerVertex;
         float angle;

         // Make sure the radius is positive
         if (radius < 0.0f)
            radius *= -1;

         // Primitives need textures off and blending on
         DisableTextures();
         EnableBlending();

         // Save transformation
         glMatrixMode(GL_MODELVIEW);
         glPushMatrix();

         // Move to the local origin
         glTranslatef(center.x, center.y, 0.0f);

         // Begin rendering the circle
         if (fill)
         {
            // Triangle fans for filled mode
            glBegin(GL_TRIANGLE_FAN);
            glVertex2f(0.0f, 0.0f);
         }
         else
         {
            // Line loop for outline mode
            glBegin(GL_LINE_LOOP);
         }

         // Number of vertices is proportional to how big it is
         numVertices = (int)(16.0f + radius * 2.0f);

         // Angle between adjacent vertex pairs
         radiansPerVertex = (b2_pi * 2.0f) / numVertices;

         // Specify vertices
         for (int i = 0; i < numVertices; i++)
         {
            angle = i * radiansPerVertex;
            glVertex2f(cosf(angle) * radius,
               sinf(angle) * radius);
         }

         // The triangle fan needs to close the loop
         if (fill)
         {
            glVertex2f(radius, 0.0f);
         }
         glEnd();

         // Restore transformation
         glPopMatrix();
      }
      ///-----------------------------\------------------------------------------------------
      //| Name: DrawPolygon    |
      //\-----------------------------/
      // PreCondition: transform specifies the position in world coordinates and the rotation matrix.
      //      vertices is a valid pointer to an array of the polygon's vertices.
      //      vertexCount is the number of vertices in the array.
      //
      // PostCondition: If the vertex array contains garbage, that's what will be drawn.
      //      The color of the polygon is determined by the last call to SetColor().
      //-------------------------------------------------------------------------------------
      void DrawPolygon(const b2Transform& transform,
         const b2Vec2* vertices, int vertexCount, bool fill)
      {
         // Check input
         if (vertices == nullptr || vertexCount < 1)
            return;

         // Primitives need textures off and blending on
         DisableTextures();
         EnableBlending();

         // Draw a list of vertices
         b2Vec2 vertex;
         if (fill)
            glBegin(GL_POLYGON);
         else
            glBegin(GL_LINE_LOOP);
         for (int i = 0; i < vertexCount; i++)
         {
            // Apply transform
            vertex = b2Mul(transform, vertices[i]);

            // Specify vertex
            std::cout << vertex.x << " " << vertex.y << std::endl;
            glVertex2f(vertex.x, vertex.y);
         }
         glEnd();
      }
      
Last edited by dleksen on Sun Apr 02, 2017 12:04 am, edited 1 time in total.

dleksen
Posts: 3
Joined: Fri Mar 31, 2017 6:54 am

Re: Polygons not colliding

Postby dleksen » Sat Apr 01, 2017 10:08 pm

Here's my init code:

Code: Select all

   bool InitD2D(const ScreenDef& settings)
   {
      // Log
      FILE *file;
      file = new FILE;
      if(freopen_s(&file, "log.txt", "w", stdout))
         std::cout << "Failed to redirect stdout to log.txt" << std::endl;

      // SDL
      if(SDL_Init(SDL_INIT_EVERYTHING) != 0)
      {
         std::cout << "Error: Failed to initialize SDL " << SDL_GetError() << std::endl;
         return false;
      }

      // Window
      if(!Renderer::CreateScreen(settings))
      {
         std::cout << "Error: Unable to initialize screen: " << SDL_GetError() << std::endl;
         return false;
      }
      return true;
   }

Code: Select all

      ///-----------------------------\------------------------------------------------------
      //| Name: CreateScreen           |
      //\-----------------------------/
      // PostCondition: Creates a new window and drawing context
      //-------------------------------------------------------------------------------------
      bool CreateScreen(const ScreenDef& settings)
      {
         // Make sure SDL video subsystem is initialized
         if (!SDL_WasInit(SDL_INIT_VIDEO))
         {
            std::cout << "Error: Aborting screen initialization. SDL must be initialized first." << std::endl;
            return false;
         }

         // If there is already a window, get rid of it
         DestroyScreen();

         // Use OpenGL 2.1
         SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);
         SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 2);
         SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 1);
         SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8);
         SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 8);
         SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 8);
         SDL_GL_SetAttribute(SDL_GL_ALPHA_SIZE, 8);
         SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
         if (settings.samples > 1)
         {
            int clampedSamples = settings.samples;
            d2d::Clamp(clampedSamples, m_minSamples, m_maxSamples);
            SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, 1);
            SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, clampedSamples);
         }

         // Create window
         Uint32 windowFlags = SDL_WINDOW_OPENGL;
         if (settings.fullscreen)
         {
            if (settings.width < 1 || settings.height < 1)
               windowFlags |= SDL_WINDOW_FULLSCREEN_DESKTOP;
            else
               windowFlags |= SDL_WINDOW_FULLSCREEN;
         }
         m_windowPtr = SDL_CreateWindow(settings.title.c_str(),
            SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,
            settings.width, settings.height, windowFlags);
         if (m_windowPtr == nullptr)
         {
            std::cout << "Error: Failed to create SDL window" << std::endl;
            return false;
         }

         // Create context
         m_glContext = SDL_GL_CreateContext(m_windowPtr);
         if (m_glContext == nullptr)
         {
            std::cout << "Error: Failed to create SDL OpenGL context" << std::endl;
            return false;
         }

         // Set vsync
         int swapInterval;
         if (settings.vsync)
            swapInterval = 1;
         else
            swapInterval = 0;
         if (SDL_GL_SetSwapInterval(swapInterval) != 0)
         {
            std::cout << "Warning: Failed to enable vsync" << std::endl;
         }

         EnableTextures();
         EnableBlending();

         // Set Camera to some initial value, even though it will be changed by the user
         SetCameraBounds(b2Vec2(0.0f, 0.0f), GetScreenResolution());

         glMatrixMode(GL_MODELVIEW);
         glLoadIdentity();

         // OpenGL settings
         glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
         glDisable(GL_DEPTH_TEST);
         glDisable(GL_CULL_FACE);
         glShadeModel(GL_SMOOTH);
         glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
         //glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
         //glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
         glPointSize(1.0f);
         glLineWidth(1.0f);

         // Initialize FPS counter
         m_timer.Start();
         m_fpsDelaySeconds = settings.fpsDelaySeconds;
         m_secondsSinceFPSUpdate = 0.0;
         m_frames = 0;
         m_fps = 0.0;

         // Record our success
         m_screenInitialized = true;
         return true;
      }

dleksen
Posts: 3
Joined: Fri Mar 31, 2017 6:54 am

Re: *Solved* Polygons not colliding

Postby dleksen » Sun Apr 02, 2017 12:13 am

Solution: Populate a b2Vec2 array and pass it to b2PolygonShape::Set rather than setting b2PolygonShape::m_count and b2PolygonShape::m_vertices directly.

Incorrect:

Code: Select all

      b2PolygonShape poly;
      poly.m_count = 4;
      poly.m_vertices[0].Set(-40.0f, -40.0f);
      poly.m_vertices[1].Set(40.0f, -40.0f);
      poly.m_vertices[2].Set(40.0f, 40.0f);
      poly.m_vertices[3].Set(-40.0f, 40.0f);

Correct:

Code: Select all

      const int numVertices = 4;
      b2Vec2 vertices[numVertices];
      vertices[0].Set(-40.0f, -40.0f);
      vertices[1].Set(40.0f, -40.0f);
      vertices[2].Set(40.0f, 40.0f);
      vertices[3].Set(-40.0f, 40.0f);

      b2PolygonShape poly;
      poly.Set(vertices, numVertices);


Return to “General Discussion”



Who is online

Users browsing this forum: No registered users and 3 guests