Walls logic in Pygame - python

I'm making a game with Pygame, and now I stuck on how to process collision between player and wall. This is 2D RPG with cells, where some of them are walls. You look on world from top, like in Pacman.
So, I know that i can get list of collisions by pygame.spritecollide() and it will return me list of objects that player collides. I can get "collide rectangle" by player.rect.clip(wall.rect), but how I can get player back from the wall?
So, I had many ideas. The first was push player back in opposite direction, but if player goes, as example, both right and bottom directions and collide with vertical wall right of itself, player stucks, because it is needed to push only left, but not up.
The second idea was implement diagonally moving like one left and one bottom. But in this way we don't now, how move first: left or bottom, and order becomes the most important factor.
So, I don't know what algorithm I should use.

If you know the location of the centre of the cell and the location of the player you can calculate the x distance and the y distance from the wall at that point in time. Would it be possible at that point to take the absolute value of each distance and then take the largest value as the direction to push the player in.
e.g. The player collides with the right of the wall so the distance from the centre of the wall in the y direction should be less than the distance in x.
Therefore you know that the player collided with the left or the right of the wall and not the top, this means the push should be to the right or the left.
If the player's movement is stored as in the form [x, y] then knowing whether to push left or right isn't important since flipping the direction of movement in the x axis gives the correct result.
The push should therefore be in the x direction in this example
e.g. player.vel_x = -player.vel_x.
This would leave the movement in the y axis unchanged so hopefully wouldn't result in the problem you mentioned.
Does that help?

Related

Ping Pong game problem with x and y cords

ok so I created a game with python its like 2d ping pong, the problem comes when I made that if the ball_y == racket_y it doesnt apply to the while racket it only apply on the Lowest cord of the racket and not on the whole racket
This is because the y value of a rectangle in pygame is determined by a point. Usually it's the top left, but I guess in your case the racket_y is it's bottom left. A better way to do the collisions is to use the racket itself and the colliderect function, which checks for collisions between the entirety of the ball and the entirety of the racket. Note, to use it you have to call the function on the object's rect you want to start at, and in parenthesis you state the rectangle of the other object. Then you invert the direction of the ball.

Is there a way to get the co-ordinates of the point of collision?

I am making a game in which the change in velocity of a ball depends on the point at which it collides with an object. I looked up the documentation but was unable to find something to do the job.
Is there any way to get the coordinates of the point of collision in Pygame?
Yes, work out the difference in the x and y co-ordinates of your ball and object. Then use mask.overlap from pygame to return a tuple of the point of collision. An example would be:
def collide(obj1, obj2):
offset_x = obj2.x - obj1.x
offset_y = obj2.y - obj1.y
return obj1.mask.overlap(obj2.mask, (offset_x, offset_y))
You can find the docs for 'mask.overlap()' here.
I support the answer given by Abishake Srithar. This is not meant to displace that answer, just add information to it.
A slight caution about the result of this mask.overlap() call. It does not give you the center of where the point of contact might be.
As you can see in the description in the docs here, the overlap is searched for by proceeding top to bottom in columns moving left to right. Which means that overlap() returns the leftmost, upper (sort of) point of the overlap.
So if your update/move of the objects causes the objects to overlap over an area (which is likely), the point returned by overlap() is the leftmost, upper point of that overlap. It is not the center of the area, or the point where the two objects might have first touched if they were not overlapping.
An example is if this were two spheres colliding, it will give you the edge of the overlap and not actually the centerpoint of the collision. This could change your angles of reflection.
This difference can affect the collision physics.
It is likely good enough for most games but I thought it worth pointing out.

Getting the distance and the direction of the nearest detected obstacle

Is there a way to get the distance and the direction of the nearest detected obstacle?
I have tried with this "Navigation/AvoidanceNavigator/ObstacleDetected" event, but it never triggers event if I position the robot next to the wall and tell him to go 5 meters long in the wall direction.
There's no API for the "nearest obstacle, but the ALMotion/MoveFailed event may be what you want - it will tell you where the obstacle is and why it failed.
During navigation you can use the ObstacleDetected event to notify you of obstacles. The position i given in robotframe.
You will get the x,y coordinates so you will have to calculate distance yourself.

Ball-Line Segment Collision on End-Point of Line

So I have a program where a ball subject to gravity bounces off of lines created by a user with mouse clicks. These lines are normally sloped. My collision bounces work perfectly EXCEPT in the case where ball does approximately this:
->O ------
My code works by finding the normal vector of the line such that the scalar product of the incident velocity vec of the ball and the normal of the line is negative (this means the vector have opposite directions).
Then I decompose the velocity into terms parallel and perpendicular to the normal,
and the reverse the direction of the parallel component.
During the edge case described above ball moves basically along the line. How can I account for this? Any advice?>
Possible Solutions:
Instead of using a single 1D 'line', you could construct a 2D rectangle (that is as this as you want/need it to be) --- composed of 4 separate 'lines'. I.e. you can have collisions with any of the 4 faces of the rectangle object. Would that work?
Do some sort of corner collision -- if the ball is 'hits' the start or end of a line, have it bounce off appropriately. I think the way this would be done is as follows:
i. Collision occurs if the corner falls within the radius of the ball.
ii. Define a line between the corner and the center of the ball.
iii. Reverse the component of the ball's velocity along this line.

Collide detection and masks in python 3.2.2

Me and my friend are currently trying to make a game. In this game we wish to have nice collision detection. But we cannot seem to find the way to update the masks in the definiton while loop. :S We have tested it alot of times, with different values and even some really unlogical stuff.
Each time we move the player, the game crashes when it collides with the mask. Its like the loop goes on forever, even though the player and the bush should be going away from eachother when we move the mask and the background.
def check_collision():
while pygame.sprite.collide_mask(player, rock):
bg.x -= 1 #the x-value of the background
rock.x -=1 #the x-value of the object
This is just collision when going left using the button "a".
We also move the background and all the sprites instead of the player.
We need to use masks.
We know that it checks the collision, but the mask wont update after bg.x and rock.x are changed.
We assume that this is because the images aren't moved on the screen. And therefore we have tried putting a blit inside the while loop. It still would not work.
Thank you for helping, and a final question, is there any way to manually move a mask/object?
First of all, collision detection using masks is very time-intensive. Whether or not your game has entered an infinite loop, the processing requirements of a bitmask-bitmask overlap check will make your game run far too slowly.
A simple optimization exists, however:
Any object which is able to collide with things must have some maximum size -- that is, you can find a rectangle which will always contain your player, and your boulder can fit inside another. Therefore, if your player's box doesn't collide with the boulder's box, they can't possibly overlap. Since you insist on collision masking, (which can add some realism to any pixelart game), you can compute the per-pixel collision whenever (and only whenever) the bounding boxes collide.
Now, on to your coding style: >:O
It is never a good idea to put a potentially infinite loop within a function which should ideally compute an instant collision check. In the best-case scenario (which is certainly achievable), you would have one function to check whether two objects collide, and tell you some more useful information (the position of one relative to the other, etcetera); while a separate method of every moving object would fix the collisions.
This would translate to something like:
class CollidingObject:
#This class controls an object which can move and fix collisions
def __init__(self):
self.x = 0 #add relevant initialization code here
self.y = 0
self.xVel = 0 # X and Y velocity (for movement)
self.yVel = 0
self.xSize = 0 # the width of the object in pixels
self.ySize = 0 # the height of the object in pixels
def iscolliding(self, other):
# using x and y as the center of the object,
# this returns an empty tuple if they don't collide
if ((self.xSize + other.xSize) / 2 <= abs(self.x - other.x)) and
((self.ySize + other.ySize) / 2 <= abs(self.y - other.y)): return ()
"""
use pygame collidemask here to compute whether they collide.
if they do, return a vector of 'other's' position relative to self.
(this can be used to decide how to separate the objects)
"""
def restitute(self, overlaps_with, distances):
"""
Given some objects which overlap, and a list of 2D vectors of their
relative distances, this separates them however much you like.
"""
pass
As to where your colision checking is done, that depends upon your implementation of object management basics. I will heretofore assume that all of your in-game objects are contained within an iterable; and that on every frame you iterate through your objects, once to render, once to move them -- a structure something like this:
while NOT_QUIT:
for object in objects:
object.draw_to_screen()
object.move() # moves the object -- collisions, etc in here
event_handling_stuff() # handles events
In this case, every object can compute collision checking for anything which follows it in objects. In doing so, each object can collect how far it has to move from each. Afterwards, each object can move to be as far from each collider as possible.
In a few games I've written, I'd make objects move farther apart the more overlapped they are, giving collisions an elastic quality which makes even very rough restitution algorithms look very sexy. Generally, you can tinker with constants once you have a working check going and that would be the least of your worries.
Hopefully this will have helped you two a little (I realize now I went off a bit on a tangent, but you were asking about how to do the wrong things more efficiently :P).
tl;dr: Don't try to fix collisions within your collision check function. Instead, separate it into one which finds all collisions to other objects, and another which fixes all collisions for an object at the same time.
Add other questions and I'll update (:.
UPDATE 1
Expanding here on the "vector of other to self" bit (which was explained a tad crudely:/)
Generally when two objects collide in real life, they bounce back somewhat in the direction they came from (when you drop a rubber bouncy ball on the floor, it bounces back from whence it came -- it doesn't just phaze through the floor). In most programming applications, you'd want to make bouncy balls (and other colliding things) behave in the same way (well, sometimes you might want the ball to phaze though the floor, but that's even easier than bouncing IMHO :P).
To know which way an object must bounce back, you have to know the direction from which it came. More strictly, you have to know the angle at which it collided. This is very easily found if you compare the distance and direction between the centers of each object during the collision. This will provide a pretty accurate representation of two objects bouncing, if the centers you are using are close enough to their centers of mass (in most games the middle of an object is an easy and good approximation).
So, since we don't need to worry about center of mass and all that, we just measure the vector distance between object positions:
#Continuing the previous example, we put some code like this in 'iscolliding' :)
if they collide (pygame mask stuff) :
x_distance = self.x - other.x
y_distance = self.y - other.y
return (x_distance, y_distance)
This code can give you the line along which each object should move to resolve the collision as fast as possible. The rest is a matter of accelerating each object along this line, making sure they don't go closer together (pay attention to signs), and tweaking constants to create a realistic effect.

Categories