Jump to content
  • Advertisement

Seer

Member
  • Content Count

    88
  • Joined

  • Last visited

Community Reputation

279 Neutral

1 Follower

About Seer

  • Rank
    Member

Personal Information

  • Interests
    Programming

Recent Profile Visitors

The recent visitors block is disabled and is not being shown to other users.

  1. Yes that's correct, I am calculating a Minimum Translation Vector and using it to move the objects out of collision so that they are resting against one another. What I would like to know is if the way in which I calculate this displacement vector is valid. As part of this calculation I look at each objects position to determine the direction of displacement. Is comparing positions like this a valid way of calculating the MTV or is it a flawed approach?
  2. Yes, these variables are member variables so that I do not instantiate new vectors each time the resolveCollision() function is called, which may be many times per frame. It is for performance reasons. I do not understand what you mean about the need to take velocity into account. Would you please expand on that? Yes that's right I do handle collisions discretely, they are resolved after the collisions have already occurred. In terms of potential object tunneling this is not a problem for me as if it does occur I will adjust the objects dimensions and speed so that it does not. Is my approach to resolving collisions flawed or is it acceptable? I'm not sure if it is a problem but I have a feeling that taking the objects positions into account to determine the direction of displacement out of collision is wrong somehow or a bad way of doing it. It works of course but is it "proper"?
  3. I have written an algorithm which resolves collisions between axis aligned rectangles so that they are resting against one another after collision resolution. The code is in Java using LibGDX public class Rectangle { public Vector2 position; public float halfW, halfH; private Vector2 restingDistance, currentDistance, overlap; public Rectangle(Vector2 position, float halfW, float halfH) { this.position = position; this.halfW = halfW; this.halfH = halfH; this.restingDistance = new Vector2(); this.currentDistance = new Vector2(); this.overlap = new Vector2(); } public boolean intersects(Rectangle rectangle) { return (position.x - halfW < rectangle.position.x + rectangle.halfW && position.x + halfW > rectangle.position.x - rectangle.halfW && position.y - halfH < rectangle.position.y + rectangle.halfH && position.y + halfH > rectangle.position.y - rectangle.halfH); } public void resolveCollision(Rectangle rectangle) { // Calculate the resting distance of the two rectangles restingDistance.set(halfW + rectangle.halfW, halfH + rectangle.halfH); // Calculate the current distance between the two rectangles currentDistance.set(position.x - rectangle.position.x, position.y - rectangle.position.y); // Calculate the overlap between the two rectangles overlap.set(restingDistance.x - Math.abs(currentDistance.x), restingDistance.y - Math.abs(currentDistance.y)); // Remove the overlap of the axis with the greater overlap overlap.set(overlap.x < overlap.y ? overlap.x : 0, overlap.y < overlap.x ? overlap.y : 0); // Reverse the direction of the overlap depending on the positions of the rectangles overlap.set(position.x < rectangle.position.x ? -overlap.x : overlap.x, position.y < rectangle.position.y ? -overlap.y : overlap.y); // Add the overlap to the rectangles position position.add(overlap); } } The code is used like this if(rectangle1.intersects(rectangle2)) { rectangle1.resolveCollision(rectangle2); } From my testing the code works. Colliding rectangles are moved out of collision so that they are resting against one another. Are there any problems with the way the code resolves collisions? Can the collision resolution code be improved and if so how? Thank you.
  4. Currently if I was to program a game using C++ with SFML or Java with LibGDX I would render game objects by calling "object.render()" on the game object. Although this makes it easy to access the information necessary to render the game object, it also couples rendering to the game logic which is something I would like to move away from. How can rendering be implemented so that it is decoupled from the game objects? I wish to know how this can be done in the standard object oriented paradigm, so please don't suggest that I use an ECS. Thank you.
  5. I suppose I'm thinking of the bounding rectangle of the polygon. When a polygon object is made, vertices are placed around the polygon according to the sin and cos of the rotation given and its half width and half height. I just want to make it so that no matter the rotation affecting the initial placement of the vertices, that the width and height of the polygon (along the X and Y axes) are the same as those given in the constructor. Can you see a way to do this?
  6. Does anyone have any ideas as to how to fix the width and height of the polygons when their vertices are given an initial rotation?
  7. If you would like to see the full picture (three .pde files), you can view the code at my GitHub repository here. If interested you can also run the program yourself if you have Processing installed. Here though is the code which implements the SAT to detect collisions and create the MTV. Please tell me if you see any mistakes. class CollisionHandler { PVector detectCollision(PShape shape1, PShape shape2) { float magnitude = 999999; PVector direction = new PVector(); ArrayList<PVector> axes = new ArrayList<PVector>(); axes.addAll(getAxes(shape1)); axes.addAll(getAxes(shape2)); for(int i = 0; i < axes.size(); ++i) { PVector axis = axes.get(i); PVector p1 = project(shape1, axis); PVector p2 = project(shape2, axis); if(isOverlap(p1, p2)) { float overlap = getOverlap(p1, p2); if(overlap < magnitude) { magnitude = overlap; direction = axis; } } else { return null; } } return direction.mult(magnitude); } ArrayList<PVector> getAxes(PShape shape) { ArrayList<PVector> axes = new ArrayList<PVector>(); for(int i = 0; i < shape.getVertexCount(); ++i) { PVector v1 = shape.getVertex(i); PVector v2 = shape.getVertex(i + 1 == shape.getVertexCount() ? 0 : i + 1); PVector edge = v2.sub(v1); PVector axis = new PVector(-edge.y, edge.x); axis.normalize(); axes.add(axis); } return axes; } PVector project(PShape shape, PVector axis) { float min = axis.dot(shape.getVertex(0)); float max = min; for(int i = 1; i < shape.getVertexCount(); ++i) { float projection = axis.dot(shape.getVertex(i)); if(projection < min) { min = projection; } else if(projection > max) { max = projection; } } return new PVector(min, max); } boolean isOverlap(PVector p1, PVector p2) { return p1.x < p2.y && p1.y > p2.x; } float getOverlap(PVector p1, PVector p2) { return p1.x < p2.y ? p1.y - p2.x : p2.y - p1.x; } }
  8. Here are two videos showing the collision handling between polygons. The collisions between the hexagon and the triangle are resolved as you would expect, with the hexagon being moved back by the MTV such that it is resting against the triangle. The collisions between the two triangles however are not resolved correctly, with the moving triangle jumping back a small distance upon collision resolution. I would like some help understanding why this happens and how it might be resolved. Also attached is an image showing two rectangles, both specified as being of width 200 pixels and height 140 pixels. One is made using the Processing rect() function and the other is a Polygon object constructed as described in my last post. As you can see, there is a noticeable disparity between their respective dimensions, with the Polygon object having smaller width and height. I would like some help understanding how to create the polygon such that its width and height are those specified by the parameters of its constructor, regardless of initial vertex rotation. Thank you. polygoncollision1.mp4 polygoncollision2.mp4
  9. I have programmed an implementation of the Separating Axis Theorem to handle collisions between 2D convex polygons. It is written in Processing and can be viewed on Github here. There are a couple of issues with it that I would like some help in resolving. In the construction of Polygon objects, you specify the width and height of the polygon and the initial rotation offset by which the vertices will be placed around the polygon. If the rotation offset is 0, the first vertex is placed directly to the right of the object. If higher or lower, the first vertex is placed clockwise or counter-clockwise, respectively, around the circumference of the object by the rotation amount. The rest of the vertices follow by a consistent offset of TWO_PI / number of vertices. While this places the vertices at the correct angle around the polygon, the problem is that if the rotation is anything other than 0, the width and height of the polygon are no longer the values specified. They are reduced because the vertices are placed around the polygon using the sin and cos functions, which often return values other than 1 or -1. Of course, when the half width and half height are multiplied by a sin or cos value other than 1 or -1, they are reduced. This is my issue. How can I place an arbitrary number of vertices at an arbitrary rotation around the polygon, while maintaining both the intended shape specified by the number of vertices (triangle, hexagon, octagon), and the intended width and height of the polygon as specified by the parameter values in the constructor? The Polygon code: class Polygon { PVector position; PShape shape; int w, h, halfW, halfH; color c; ArrayList<PVector> vertexOffsets; Polygon(PVector position, int numVertices, int w, int h, float rotation) { this.position = position; this.w = w; this.h = h; this.halfW = w / 2; this.halfH = h / 2; this.c = color(255); vertexOffsets = new ArrayList<PVector>(); if(numVertices < 3) numVertices = 3; shape = createShape(); shape.beginShape(); shape.fill(255); shape.stroke(255); for(int i = 0; i < numVertices; ++i) { PVector vertex = new PVector(position.x + cos(rotation) * halfW, position.y + sin(rotation) * halfH); shape.vertex(vertex.x, vertex.y); rotation += TWO_PI / numVertices; PVector vertexOffset = vertex.sub(position); vertexOffsets.add(vertexOffset); } shape.endShape(CLOSE); } void move(float x, float y) { position.set(x, y); for(int i = 0; i < shape.getVertexCount(); ++i) { PVector vertexOffset = vertexOffsets.get(i); shape.setVertex(i, position.x + vertexOffset.x, position.y + vertexOffset.y); } } void rotate(float angle) { for(int i = 0; i < shape.getVertexCount(); ++i) { PVector vertexOffset = vertexOffsets.get(i); vertexOffset.rotate(angle); shape.setVertex(i, position.x + vertexOffset.x, position.y + vertexOffset.y); } } void setColour(color c) { this.c = c; } void render() { shape.setFill(c); shape(shape); } } My other issue is that when two polygons with three vertices each collide, they are not always moved out of collision smoothly by the Minimum Translation Vector returned by the SAT algorithm. The polygon moved out of collision by the MTV does not rest against the other polygon as it should, it instead jumps back a small distance. I find this very strange as I have been unable to replicate this behaviour when resolving collisions between polygons of other vertex quantities and I cannot find the flaw in the implementation, though it must be there. What could be causing this incorrect collision resolution, which from my testing appears to only occur between polygons of three vertices? Any help you can provide on these issues would be greatly appreciated. Thank you.
  10. Seer

    Issue re-arranging equation

    Thanks very much for the help everyone. The problem was that I had never heard of the notion of reciprocals. After looking into them it all became clear. It really is amazing just how many ways you can manipulate expressions in mathematics. Below are the full workings. Our initial equation: To bring t over to the left hand side, multiply both sides by t: This results in: To get rid of the x on the left hand side, divide both sides by x: This initially results in: This is where I was stuck before, but after looking into reciprocals I understood that the expression could be rewritten as: Thanks to the associative and commutative properties of multiplication, this can be rewritten as: Which is the same as our end goal: Thanks again everyone, I really appreciate your help.
  11. Seer

    Issue re-arranging equation

    Okay, I understand reordering terms when multiplying, I just didn't know what you meant by associative. However, I don't understand how you got from: t = (4*sin(theta)^2) / x to t = 4 * sin(theta)^2 * (1 / x) Let's just take the right hand side. I understand that 4 / x is equal to 4 * (1 / x) because: 4 * (1 / x) = (4 / 1) * (1 / x) = 4 * 1 / 1 * x => 4 / x However, the right hand side of the equation isn't 4 / x, if it was it would already be solved. sin(theta)^2 is part of the numerator. This must be where my knowledge fails, because as I understand it everything in the numerator must be divided by the denominator. This would mean that both 4 and sin(theta)^2 must each be divided by x. Am I incorrect in thinking that? Can you pick and choose which term in a set of terms in the numerator to divide by the denominator?
  12. Seer

    Issue re-arranging equation

    Would you mind explaining how? Obviously I'm wrong but to my mind t = (4 * sin(theta)^2) / x is the same as t = (4 / x) * (sin(theta)^2 / x), since both 4 and sin(theta)^2 are divided by the x. This makes sense to me, but I'm not making the logical connection between this and the equation. I don't understand. Would you mind explaining further? Maths is not my strong point. It was just recently that I learned how to solve for variables in an equation and to re-arrange equations. It's incredible really, I feel like I have unlocked so many doors with this knowledge. No longer is it a mystery to me how expressions like "y = sin(theta) * radius" are arrived at. I had always understood through SOHCAHTOA that sin(theta) = y / radius, but I never understood how it was that people could re-arrange that to the equation above. It really is a great feeling when you make logical connections in your brain and finally understand what you did not before. Hopefully you can help me to make the connections to demystify my mystified brain on this issue.
  13. Seer

    Issue re-arranging equation

    Ah, sorry you're right that's not very clear, it should be: x = (4 / t) * sin(theta)^2 is the same as t = (4 / x) * sin(theta)^2 x = (4 / t) * sin(theta)^2 t * x = (4 / t) * t * sin(theta)^2 - (Multiply both sides by t to bring t over to the LHS) t * x = 4 * sin(theta)^2 - (The ts on the RHS cancel out) (t * x) / x = (4 * sin(theta)^2) / x - (Now divide both sides by x to remove the x from the LHS) t = (4 * sin(theta)^2) / x - (This is what I have ended up with)
  14. In the Introduction section of Ian Millingtons book "Game Physics Engine Development", he assumes that you have a certain level of mathematical knowledge. An example of what you are expected to understand is that x = 4 / t * sin(theta)^2 is the same as t = 4 / x * sin(theta)^2. I have tried to work this out but I cannot seem to resolve it at the last step. Here are my workings: x = 4 / t * sin(theta)^2 t * x = 4 / t * t * sin(theta)^2 - (Multiply both sides by t to bring t over to the LHS) t * x = 4 * sin(theta)^2 - (The ts on the RHS cancel out) t * x / x = 4 * sin(theta)^2 / x - (Now divide both sides by x to remove the x from the LHS) t = 4 * sin(theta)^2 / x - (This is what I have ended up with) What I have ended up with is the whole of the right hand side of the equation over x. Ian Millington ends with only the 4 being divided by x. What am I misunderstanding here? My current understanding is that what is done to one side of the equation must be done to the other in order for it to remain true. Therefore, if all of the left hand side is divided by x then all of the right hand side must be divided by x, not just 4. If this is true, then does that not mean that sin(theta)^2 must also be divided by x? If so, how can this be resolved? Thanks. Apologies for the formatting, I cannot figure out how to use the formatter.
  15. What books, tutorials or other resources would you recommend for learning good architecture design for 2D games, where the concepts are well explained with clear implementation details and if possible where an actual game is developed using these design principles, being gradually built up in a step-by-step manner?
  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

GameDev.net is your game development community. Create an account for your GameDev Portfolio and participate in the largest developer community in the games industry.

Sign me up!