Problem with simple rectangle collison in OpenGL - kotlin

I try to implement collision detection and collision effects. This is my code for collision detection:
fun collisionDetection(objcect : Renderable?, object2 : Renderable?) : Boolean {
var collisionX : Boolean = objcect?.getPosition()?.x?.plus(quadSizeX)!! >= object2?.getPosition()?.x!! && object2?.getPosition()?.x?.plus(quadSizeX)!! >= objcect?.getPosition()?.x!!
var collisionY : Boolean = objcect?.getPosition()?.y?.plus(quadSizeY)!! >= object2?.getPosition()?.y!! && object2?.getPosition()?.y?.plus(quadSizeY)!! >= objcect?.getPosition()?.y!!
var collisionZ : Boolean = objcect?.getPosition()?.z?.plus(quadSizeZ)!! >= object2?.getPosition()?.z!! && object2?.getPosition()?.z?.plus(quadSizeZ)!! >= objcect?.getPosition()?.z!!
return collisionX && collisionY && collisionZ }
This seems to work, when used with overlapping objects set to overlapping values by transformations. This way
wall.translateLocal(Vector3f(0.0f, 1.0f, -8.0f))
and
wall2.translateLocal(Vector3f(0.0f, 2.0f, -8.0f))
collisionDetection is true.
When moving wall2 on the z-axis with a different starting point and speed, but x and y position are the same, the effect of the collision should be that wall2 stops moving, when z position of both objects is equal. I tried it this way in the main loop (and many other ways...), but it is still not working:
fun render(dt: Float, t: Float) {
glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT)
staticShader.use()
camera.bind(staticShader)
wall.render(staticShader)
wall2.render(staticShader)
if (collisionDetection(wall, wall2) == true) {
wall2.getPosition()
}
else {wall2.translateLocal(Vector3f(0.0f, 0.0f, -t.toFloat()* 0.001f))}
}
I have no idea now, what is wrong and how to fix it. It seems like the collisionDetection function doesn't get information about the changing positions on the z-axis of the wall2. Or maybe I need a different approach.

Everything works fine now. Forgot to calculate QuadSize for the second object. This results in two objects on the same z.coordinate.Nothing has been wrong with the function for detecting collisions.

Related

Calculating the 2D turn movement required given an incoming and outgoing direction

Consider a 2D square tiled grid (chess board like) which contains conveyor belt like structures that can curve and move game pieces around.
I need to calculate the turn movement (TURN_LEFT, TURN_RIGHT or STAY), depending on
the direction from which a piece moves onto the field
the direction from which the underlying belt exits the field
Example:
1 2
1 |>X>|>v |
2 | | v |
The belt makes a RIGHT turn. As such, the result of calcTurn(LEFT, DOWN) should be TURN_RIGHT. Meaning the X game piece will be rotated 90Ā° right when it moves over the curve at (1,2).
I already implemented a function but it only works on some of my test cases.
enum class Direction {
NONE,
UP,
RIGHT,
DOWN,
LEFT;
fun isOpposite(other: Direction) = this == UP && other == DOWN
|| this == DOWN && other == UP
|| this == LEFT && other == RIGHT
|| this == RIGHT && other == LEFT
}
data class Vec2(val x: Float, val y: Float)
fun Direction.toVec2() = when (this) {
Direction.NONE -> Vec2(0f, 0f)
Direction.UP -> Vec2(0f, 1f)
Direction.RIGHT -> Vec2(1f, 0f)
Direction.DOWN -> Vec2(0f, -1f)
Direction.LEFT -> Vec2(-1f, 0f)
}
fun getTurnMovement(incomingDirection: Direction, outgoingDirection: Direction): Movement {
if (incomingDirection.isOpposite(outgoingDirection) || incomingDirection == outgoingDirection) {
return Movement.STAY
}
val incVec = incomingDirection.toVec2()
val outVec = outgoingDirection.toVec2()
val angle = atan2(
incVec.x * outVec.x - incVec.y * outVec.y,
incVec.x * outVec.x + incVec.y * outVec.y
)
return when {
angle < 0 -> Movement.TURN_RIGHT
angle > 0 -> Movement.TURN_LEFT
else -> Movement.STAY
}
}
I can't quite figure out what's going wrong here, especially not because some test cases work (like DOWN+LEFT=TURN_LEFT) but others don't (like DOWN+RIGHT=STAY instead of TURN_LEFT)
You're trying to calculate the angle between two two-dimensional vectors, but are doing so incorrectly.
Mathematically, given two vectors (x1,y1) and (x2,y2), the angle between them is the angle of the second to the x-axis minus the angle of the first to the x-axis. In equation form: arctan(y2/x2) - arctan(y1/x1).
Translating that to Kotlin, you should instead use:
val angle = atan2(outVec.y, outVec.x) - atan2(incVec.y, incVec.x)
I'd note that you could achieve also your overall goal by just delineating the cases in a when statement as you only have a small number of possible directions, but perhaps you want a more general solution.
It's not answering your question of why your code isn't working, but here's another general approach you could use for wrapping ordered data like this:
enum class Direction {
UP, RIGHT, DOWN, LEFT;
companion object {
// storing thing means you only need to generate the array once
private val directions = values()
private fun getPositionWrapped(pos: Int) = directions[(pos).mod(directions.size)]
}
// using getters here as a general example
val toLeft get() = getPositionWrapped(ordinal - 1)
val toRight get() = getPositionWrapped(ordinal + 1)
val opposite get() = getPositionWrapped(ordinal + 2)
}
It's taking advantage of the fact enums are ordered, with an ordinal property to pull out the position of a particular constant. It also uses the (x).mod(y) trick where if x is negative, putting it in parentheses makes it wrap around
x| 6 5 4 3 2 1 0 -1 -2 -3 -4 -5
mod 4| 2 1 0 3 2 1 0 3 2 1 0 3
which makes it easy to grab the next or previous (or however far you want to jump) index, acting like a circular array.
Since you have a NONE value in your example (which obviously doesn't fit into this pattern) I'd probably represent that with a null Direction? instead, since it's more of a lack of a value than an actual type of direction. Depends what you're doing of course!

Godot Inversing selected rectangle area made up of two Vector2 objects

This seems like a really simple question but I've been at this for a couple of hours and need an outsiders perspective.
I'm migrating a start of a game to Godot from Unity.
I'm selecting an area of tiles (startDragPosition, endDragPosition, both Vector2 objects) from a TileMap and setting them to a certain tile. Currently the dragging only works if the direction is top->bottom and left->right, so if the ending x and y are larger than the starting x and y
In Unity(C#) I had a few simple lines to flip the rectangle values if it was dragged in reverse.
if (end_x < start_x) {
int tmp = end_x;
end_x = start_x;
start_x = tmp;
}
if (end_y < start_y) {
int tmp = end_y;
end_y = start_y;
start_y = tmp;
}
However in when I try a similar approach in Godot it is not working for some reason. I'm thinking that I'm messing up somewhere earlier and any help would be appreciated. If there is an easier way of doing this please tell me I'm fairly new to Godot itself.
Here is the function responsible for dragging in my Godot script(GD)
func Drag():
if(Input.is_action_just_pressed("click")):
startDragPosition=get_global_mouse_position()
if(Input.is_action_pressed("click")):
endDragPosition=get_global_mouse_position()
print("01 START: "+String(stepify(startDragPosition.x-8,16)/16)+"_"+String(stepify(startDragPosition.y-8,16)/16))
print("01 END: "+String(stepify(endDragPosition.x-8,16)/16)+"_"+String(stepify(endDragPosition.y-8,16)/16))
if(endDragPosition.x<startDragPosition.x):
var temp = endDragPosition.x
endDragPosition.x=startDragPosition.x
startDragPosition.x=temp
if(endDragPosition.y<startDragPosition.y):
var temp = endDragPosition.y
endDragPosition.y=startDragPosition.y
startDragPosition.y=temp
for x in range(startDragPosition.x,endDragPosition.x):
for y in range(startDragPosition.y,endDragPosition.y):
get_node("../DragPreview").set_cell((stepify(x-8,16))/16,(stepify(y-8,16))/16,0)
#get_node("../DragPreview").update_bitmask_area(Vector2((stepify(x-8,16))/16,(stepify(y-8,16))/16))
if(Input.is_action_just_released("click")):
print("START: "+String(stepify(startDragPosition.x-8,16)/16)+"_"+String(stepify(startDragPosition.y-8,16)/16))
print("END: "+String(stepify(endDragPosition.x-8,16)/16)+"_"+String(stepify(endDragPosition.y-8,16)/16))
startDragPosition=null
endDragPosition=null
When you drag, you always write to endDragPosition.
When you drag to the left or drag up, and you update endDragPosition, it will have smaller coordinates than it had before. Because of that you swap the coordinates with startDragPositionā€¦ And then you keep dragging left or up, and that updates endDragPosition again. The original startDragPosition is lost.
Either you work with a copy when you are deciding the start and end:
var start = startDragPosition
var end = endDragPosition
if(end.x<start.x):
var temp = end.x
end.x=start.x
start.x=temp
if(end.y<start.y):
var temp = end.y
end.y=start.y
start.y=temp
for x in range(start.x,end.x):
for y in range(start.y,end.y):
# whatever
pass
Or you forget this swapping shenanigans, and give the loops a step:
var start = startDragPosition
var end = endDragPosition
for x in range(start.x,end.x,sign(end.x-start.x)):
for y in range(start.y,end.y,sign(end.y-start.y)):
# whatever
pass

CGAL: What is join_facet() really doing with circulators?

I'm trying to use join_facet() iteratively to grow a single facet starting from a given facet_handle. However, I'm running into trouble when using the Halfedge_around_facet_circulator in combination with join_facet(). My while-loop does not become false anymore which works fine if I don't use join_facet() and the circulator seems to point to something else.
I assume that the join operation is somehow changing that Halfedge_around_facet_circulator. But why and how to solve this?
Polyhedron P_out; // is a valid pure triangle Polyhedron
bool merge_next = true;
while (merge_next == true) {
Polyhedron::Halfedge_around_facet_circulator hit = facet_handle->facet_begin(); // facet_handle pointing to facet of P_out
merge_next = false;
do {
if(!(hit->is_border_edge())) {
if (coplanar(hit->facet(), hit->opposite()->facet())) {
if (CGAL::circulator_size(hit->opposite()->vertex_begin()) >= 3 && CGAL::circulator_size(hit->vertex_begin()) >= 3
&& hit->facet()->id() != hit->opposite()->facet()->id()) {
Polyhedron::Halfedge_handle hit2 = hit;
P_out->join_facet(hit2);
merge_next = true;
}
}
}
} while (++hit != facet_handle->facet_begin());
}
What this code should do:
Given the facet_handle, iterate over the corresponding halfedges of facet and merge if possible. Then taking facet_handle of created new facet again and doing the same until no neighboring facets are left to merge.
Edit:
There are areas on which the code runs fine and others where it crashes at hit->is_border_edge() after the first join_facet().

Hit detection implementation for Processing JS

I am having some trouble with programming hit detection in Processing.JS. I have tried to make a function that checks if something is touching an object and returns true and otherwise returns false. This is that here.
`Box.prototype.checkTouching = function(v){
if(v.position.x > this.position.x - this.width/2 && v.position <
this.position.x + this.width/2 && v.position.y > this.positon.y -
this.height/2 && v.position.y < this.position.y + this.height/2){
return true;
}else{
return false;
}
};`
I am implementing it by creating a new variable "b" in my draw function that holds the value the function returned then using an if statement to check if the value "b" is holding is true. Like so
var b = box3.checkTouching(mos);
if(b === true){
println("It works");
}
What should happen when the two objects touch is that a message saying "it works" gets printed in to the console. Unfortunately even when the object the function is running on is touching the object that is running it nothing happens. I have already checked to see if the logic works and it is valid so I know it has to be my implementation I just can not seem to find out what is wrong with my implementation. Can anyone tell what I am doing wrong? Full program here
You need to check whether the rectangles overlap. You'd do this by checking each side, like this:
if(rectOneRight > rectTwoLeft && rectOneLeft < rectTwoRight && rectOneBottom > rectTwoTop && rectOneTop < rectTwoBottom){
//collision
}
Shameless self-promotion: I've written a tutorial on collision detection in Processing (including rectangle-rectangle collision) available here.
To build on what Kevin posted, say I want to hover my mouse over a rectangle. processing has the built in variables mouseX, mouseY that return the coordinates of the mouse.
so I would check if the mouse X position was greater then the rect X pos, and less than the rect X pos + the rect width. the, do the same with the mouseY, rect Y and rect height
if (mouseX > rectXpos &&
mouseX < rectXpos + rectWidth &&
mouseY > rectYpos &&
mouseY < rectYpos + rectHeight) {
// the button is being hovered over
}

Collision response for rectangles

I've been working on a physics engine for about a week now, being stuck for several days trying to work out how to resolve collisions.
My problem is that if there's a box stuck in the middle of 2 other boxes, or between a box and a wall, my application will get stuck in a while loop. It wont resolve the collisions.
This is my code (note: if collision is right side, it means that object A is colliding against object B with its right side. Distance is negative because the objects are inside eachother, and it's in x or y axis depending on side of collision. If you need more code, for example the collision class, which is simply a container of the 2 objects, i can provide that.):
edit: Code edited with new way of dealing with collisions:
//Move colliding objects so they don't collide anymore.
while (getCollidingAmount(objectVector)){
for (int i = 0; i < objectVector.size(); i++){
PhysicsObject* A = objectVector[i];
if (objectVector[i]->getPhysicsType() != PhysicsType::staticT && A->_collision.size() > 0){
Collision collision = A->_collision[A->getDeepestPenetrationCollisionIndex(A->_collision)];
PhysicsObject* B = collision.getObject();
switch (collision.getSide()){
case SideOfCollision::left:
case SideOfCollision::top:
//Opposite velocity
if (A->_saveVelocity.x < 0 && B->_saveVelocity.x > 0){
long double percentageOfVelocity = std::min(abs(B->_saveVelocity.x), abs(A->_saveVelocity.x)) /
std::max(abs(B->_saveVelocity.x), abs(A->_saveVelocity.x));
A->_position.x -= percentageOfVelocity*collision.getVectorPenetration().x;
A->_position.y -= percentageOfVelocity*collision.getVectorPenetration().y;
}
else{
A->_position.x -= collision.getVectorPenetration().x;
A->_position.y -= collision.getVectorPenetration().y;
}
break;
case SideOfCollision::right:
case SideOfCollision::bottom:
//Opposite velocity
if (A->_saveVelocity.x > 0 && B->_saveVelocity.x < 0){
long double percentageOfVelocity = 1 - std::min(abs(B->_saveVelocity.x), abs(A->_saveVelocity.x)) /
std::max(abs(B->_saveVelocity.x), abs(A->_saveVelocity.x));
A->_position.x -= percentageOfVelocity*collision.getVectorPenetration().x;
A->_position.y -= percentageOfVelocity*collision.getVectorPenetration().y;
}
else{
A->_position.x -= collision.getVectorPenetration().x;
A->_position.y -= collision.getVectorPenetration().y;
}
break;
}
updateCollisions(objectVector);
}
}
}
Update
Something wrong with my trigonometry in bottom and top collisions:
sf::Vector2<long double> Collision::getVectorPenetration() const{
long double x;
long double y;
long double velX = _object->getVelocity().x;
long double velY = _object->getVelocity().y;
long double angle = atan2(velY, velX);
if (_side == SideOfCollision::left || _side == SideOfCollision::right){
x = getDistance();
y = x * tan(angle);
return sf::Vector2<long double>(x, y);
}
else if (_side == SideOfCollision::top || _side == SideOfCollision::bottom){
y = getDistance();
x = y / tan(angle);
return sf::Vector2<long double>(x, y);
}
}
Update 2
Thanks to Aiman, i solved my issue. Updated my collisionResponse code aswell to match my new way of dealing with collisions. I'm having another issue now where gravity makes it so i can't move in X direction when touching another object. If anyone familiar with this issue wants to give any tips to solve it, i appreciate it :).
Update 3
So it seems gravity is not actually the problem since i can swap gravity to the x axis, and then be able to slide boxes along the walls. There seems to still be something wrong with the trigonometry.
I can think of many ways to approach the problem.
1-**The more complicated one is to **introduce friction. Here is how I'd implement it, though this is untested and there is a chance I missed something in my train of thought.
Every shape gets a friction constant, and according to those your objects slide when they collide.
First, you need to get the angle that is perpendicular to your surface. To do this, you just get the arctan of the the surface's normal slope. The normal is simply -1/m, where m is the slope of your surface (which you is the ratio/quotient of how much the surface extends in y to/by how much it extends in x). Let's call this angle sNormal for "surface normal". We may also need sAngle-"surface angle" for later (you find that by arctan(m)). There remains some ambiguity in the angle that has to do with whether you're talking about the 'front' or the 'back' of the surface. You'll have to deal with that manually.
Next, you need the angle of the trajectory your object flies in, which you already know how to find (atan2(y,x)). We'll call this angle oAngle for "object's surface angle". Next, you calculate deltaAngle = sNormal - oAngle. This angle represents how much momentum was not blocked completely by the surface. A deltaAngle of 0 means all momentum is gone, and a value of PI/2 or 90 means the 2 surfaces are in parallel touching each other not blocking any momentum at all. Anything in between, we interpolate:
newSpeed = objectSpeed * deltaAngle/(PI/2);
newVelocity.x = cos(sAngle) * objectSpeed;
newVelocity.y = sin(sAngle) * objectSpeed;
Now this assumes 0 friction. If we let a friction of 1 be the maximum friction which doesn't allow the object to "slide", we modify the newSpeed before we apply the newVelocity values, like so: newSpeed *= (1-friction);.
And there we have it! Just give your platform a friction value of less than 1 and your box will be able to slide. If you're dealing with upright boxes, then the surface angle is PI for top wall, 0 for the bottom, PI/2 for the right and -PI/2 for the left wall.
2-The simpler option is to subtract gravity from the object's y-velocity in the solver's calculation.