Another not working 2D collision system

As many before me, I’m trying to make a 2D platformer. The current problem is the collision system. I tried to be smart and use sweeping and line segments to implement this, which ended up somewhat working, but not quite.

Here’s what I’m trying to do:

  1. The player is made of four vertices
  2. The map is made of axis-aligned line segments creating polygons
  3. Calculate the next frame’s position of all four points
  4. Create four line segments from the before/after positions, one for each vert
  5. Intersect these segments with the map
  6. Move the player to the collision point on the axis perpendicular to the wall only

Here’s what happens:

  1. Some walls work just fine
  2. Some walls have collision from the "wrong" side
  3. Some walls have no collision
  4. Some walls stop having collisions when sliding on them
  5. Some walls can’t be moved away from

Here’s the relevant excerpts of my code. Subject to be refactored, I wanted to get this working first.

// Player public class Player extends Sprite {      private PlayScreen scr;      public Vector2 vel;     public Vector2 lastMove;      public Vector2[] verts = new Vector2[2];           public Player(PlayScreen s, float x, float y) {         this.scr = s;         this.setPosition(x, y);         this.setSize(8, 16);         vel = new Vector2(0, 0);         lastMove = new Vector2(0, 0);                  Rectangle r = this.getBoundingRectangle();         float x1 = r.x;         float x2 = r.x + r.width;         float y1 = r.y;          float y2 = r.y + r.height;                  verts[0] = new Vector2(x1,y1);         verts[1] = new Vector2(x2,y2);     }      public void update(float delta) {         float xpos = this.getX();         float ypos = this.getY();          float dx = vel.x * delta;         float dy = vel.y * delta;          this.setPosition(xpos + dx, ypos + dy);         this.lastMove.set(dx, dy);     }      public Vector2 getTR() {         return new Vector2(this.getVertices()[Batch.X3],this.getVertices()[Batch.Y3]);     }      public Vector2 getBR() {         return new Vector2(this.getVertices()[Batch.X4],this.getVertices()[Batch.Y4]);     }          public Vector2 getTL() {         return new Vector2(this.getVertices()[Batch.X2],this.getVertices()[Batch.Y2]);     }          public Vector2 getBL() {         return new Vector2(this.getVertices()[Batch.X1],this.getVertices()[Batch.Y1]);     }      } 
// PlayScreen public class PlayScreen implements Screen {      private OrthogonalTiledMapRenderer renderer;     private Player player;     private Collision collision;      public PlayScreen(MovementGame mg) {                  // omitted cam/viewport setup         // omitted map loading         this.renderer = new OrthogonalTiledMapRenderer(map, 1);         cam.position.set(viewport.getWorldWidth() / 2, viewport.getWorldHeight() / 2, 0);          player = new Player(this, -50, -50);         collision = new Collision();          for (PolygonMapObject obj : this.map.getLayers().get(2).getObjects().getByType(PolygonMapObject.class)) {             collision.addObj(obj);         }     }      @Override     public void render(float delta) {         Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);          player.vel.x = 0;         player.vel.y = 0;          // omitted input handling. sets player.vel to +-100 x/y on arrow key press          player.update(delta);          // omitted debug player drawing         // omitted debug player drawing for next position          collision.doCollision(player, cam);         cam.position.lerp(new Vector3(player.getX(), player.getY(), 0),1f);          cam.update();         renderer.setView(cam);          // omitted debug map drawing     } }  
public class Collision {      public ArrayList<Vector2[]> lines;      public Collision() {         lines = new ArrayList<>();     }      // convert polygon verts to lines and add to list     public void addObj(PolygonMapObject obj) {         float[] a = obj.getPolygon().getTransformedVertices();         ArrayList<Vector2> verts = new ArrayList<>();         for (int i = 0; i < obj.getPolygon().getVertices().length; i += 2) {             verts.add(new Vector2(a[i + 0], a[i + 1]));         }          for (int i = 0; i < verts.size() - 1; i++) {             lines.add(new Vector2[] { verts.get(i), verts.get(i + 1) });         }         lines.add(new Vector2[] { verts.get(0), verts.get(verts.size() - 1) });     }      // detect and resolve collision. camera is for debug drawing     public void doCollision(Player p, Camera cam) {         Vector2 col;         float dx = 0;         float dy = 0;         // try to intersect with every line         for (Vector2[] line : lines) {             dx = dy = 0;             // create the movement line for each vert of the player              // try to intersect it with the currect line             // there HAS to be a better way...             if ((col = getLineIntersection(p.getBL(), p.getBL().sub(p.lastMove), line[0], line[1])) != null) {                 dx = p.getBL().x - col.x;                 dy = p.getBL().y - col.y;             }             if ((col = getLineIntersection(p.getTL(), p.getTL().sub(p.lastMove), line[0], line[1])) != null) {                 dx = p.getTL().x - col.x;                 dy = p.getTL().y - col.y;             }             if ((col = getLineIntersection(p.getBR(), p.getBR().sub(p.lastMove), line[0], line[1])) != null) {                 dx = p.getBR().x - col.x;                 dy = p.getBR().y - col.y;             }             if ((col = getLineIntersection(p.getTR(), p.getTR().sub(p.lastMove), line[0], line[1])) != null) {                 dx = p.getTR().x - col.x;                 dy = p.getTR().y - col.y;             }             // something collided. resolve             if (col != null) {                                  if (line[0].y == line[1].y) {                 // line is horizontal. push player up/down only                     p.vel.x = 0;                     dx = 0;                 } else {                 // line is vertical. push player left/right only                     p.vel.y=0;                     dy = 0;                 }                  // omitted debug drawing                 // finally, update the player pos                 p.setPosition(p.getX() - dx, p.getY() - dy);             }         }     }      private Vector2 getLineIntersection(Vector2 p0, Vector2 p1, Vector2 p2, Vector2 p3) {         Vector2 res = new Vector2();         if (Intersector.intersectSegments(p0, p1, p2, p3, res)) {             return res;         } else {             return null;         }     } } 

Any ideas or tips on how this could be turned into something working? Or should I give up on this and do grid AABB-collision instead?

Finally, here’s a rare screenshot of the code doing what it should. Blue is the player’s position before the movement, red the intended position, yellow the resolved position and white the distance the player moved too far. screenshot

Same colors, but issue #5. The collision gets resolved onto the wall instead of away.
screenshot2

Thank you in advance for your help! Please excuse the form of this question, this is making me lose my mind…