Pygame Ground Collision Detection and Position Reset - python

Assuming that my character is falling, and headed toward some sprite platform, and I flag that my character has landed once a collision is detected, what is the best way to reset my character's position - so that he is above the platform's rectangle or so that he is still clipping it?
My concerns are that if my character is above the platform's rectangle, than my function fall() will be called because he isn't touching anything, and if my character is clipping the platform's rectangle, than my jump() function may be hindered, because it may think he's landed as soon as he takes off. Obviously there are work arounds for either, but I'm really just looking for the convention, if there is one.
(I can post code if necessary, but the code isn't the issue. I'm really just looking for the right method)
Thanks,
Mike

I would have him touching the platform so that fall() is not called again.
and if my character is clipping the platform's rectangle, than my jump() function may be hindered, because it may think he's landed as soon as he takes off.
In the jump() function, when it moves the character make it so it cannot stop until it moves a minimum of x pixels.
You can do this by making a boolean to False at the beginning of jump() and having a counter to make it True after x pixels have been traversed. Make sure that x is just enough to get the character to stop clipping the platform, and not too much so it can collide with other things.
Once it has moved x pixels, then allow the collision testing to commence to see when the character hits something again.
So for example:
MINIMUM_DISTANCE = x
# ^ how many pixels you want to move to stop clipping
count = 0 #used for counting
def jump():
global count
in_air = False
#do your movements here, and increase count each time you move a pixel
if count >= MINIMUM_DISTANCE: in_air=True
if in_air:
#collision detection here
#once there is a collision:
if collision:
count = 0
return
And just for future reference, its better to post the code you have, even if it isn't a code related error. just so we can maybe see and get a feel for your approach
hope I could help

Related

Is there a way to keep an object in bounds in pygame, and make it move when you hold the directional keys down?

I am using pygame 1.9.6 and python 3.7.7. I am looking for a way to have something drawn by pygame(or maybe even an image) that stays inside the window border(and stops when I release the key. I started with the “if keys[]:” method:
if keys[pygame.K_LEFT] and x>0:
x-=speed
that made it stay in bounds, but it only moved a few pixels and then did not repeat.
Next I tried the “event.key” method:
if event.type==pygame.KEYDOWN:
if event.key==pygame.K_LEFT:
xchange=-speed
ychange=-0
but that just makes the object move forever. I tried putting “and x>0” on the same line right after the direction, an “if x>0:” before, an “if x<0:” after, but the event never updates to see that the coordinates are past the edge, even with update commands. It just keeps going and going. I also don’t know how to make the object stop moving when I release the key, since event.key’s have the event always on.
Thank you for all the help you can offer.
In order for something to stay within a frame, you must check if it's coordinates are not past the border before moving it.
keys = pygame.key.get_pressed()
if(keys[K_LEFT]):
if(square.left > 0):
square.left -= 10
if(keys[K_RIGHT]):
if(square.right < 600):
square.left += 10
if(keys[K_UP]):
if(square.top > 0):
square.top -= 10
if(keys[K_DOWN]):
if(square.bottom < 600):
square.bottom += 10
This is an example of how you would do this with a Rect object, it checks for border and then moves the object if its within those border and the appropriate key is being pressed. I can't apply this to your code as I cannot see enough of it but you just have to replace the coordinates. For example, you might have thing.x instead of square.left

Most efficient way to detect collisions between rectangle lists in pygame? [duplicate]

This question already has answers here:
rect collision with list of rects
(2 answers)
How do I detect collision in pygame?
(5 answers)
Closed 2 years ago.
I'm writing an asteroids clone in Pygame and I've tried a few different ways to detect collisions between 'asteroid' rectangles and 'projectile' rectangles (both of which inherit from Rect). I'd like to know which of them (or what other method of detecting collisions) will lead to the least amount of lag. Moreover, I'd like to know why they have the least lag (I tried looking at the source for the Rect class to see how collidelist, colliderect, and collidepoint worked, but it was compiled in bytecode or something of that nature, which I unfortunately don't know anything about). The asteroids and projectiles are in lists named 'asteroids' and 'projectiles' respectively.
I first tried iterating through my projectiles list and using pygame.rect.collidelist on the asteroids list to find collisions:
index = 0
for projectile in projectiles[:]: #copy so I can delete from original
index = projectile.collidelist(asteroids)
if index != -1:
del asteroids[index]
projectiles.remove(projectile)
Unfortunately, this is very laggy, probably because I'm checking all of the rectangles on the screen.
To minimize unnecessary checks, I tried defining a 10 by 10 grid using my screen WIDTH and HEIGHT, and both the projectile and asteroid classes have a method which sets their gridRect attribute to a tuple with the coordinates of the grid segment they are in. I then detect collisions with a nested for-each-in loop like this:
for projectile in projectiles[::-1]:
for asteroid in asteroids[::-1]:
if projectile.gridRect == asteroid.gridRect and projectile.colliderect(asteroid):
projectiles.remove(projectile)
asteroids.remove(asteroid)
This worked really well as long as there weren't more than 50 projectiles and asteroids, but if possible I'd like even better performance.
Finally, I tried creating an array, sorting the rects into it, and then detecting collisions:
gridRects = []
for i in range(GriddedRect.GRIDSIZE):
gridRects.append([])
for j in range(GriddedRect.GRIDSIZE):
gridRects[i].append({"Projectiles": [], "Asteroids": []})
for asteroid in asteroids:
gridRects[asteroid.gridRect[0]][asteroid.gridRect[1]]["Asteroids"].append(asteroid)
for projectile in projectiles:
gridRects[projectile.gridRect[0]][projectile.gridRect[1]]["Projectiles"].append(projectile)
for i in range(GriddedRect.GRIDSIZE):
for j in range(GriddedRect.GRIDSIZE):
for projectile in gridRects[i][j]["Projectiles"][::-1]:
index = projectile.collidelist(gridRects[i][j]["Asteroids"])
if not index == -1:
asteroids.remove(gridRects[i][j]["Asteroids"][index])
del gridRects[i][j]["Asteroids"][index]
projectiles.remove(projectile)
gridRects[i][j]["Projectiles"].remove(projectile)
This was probably more laggy than the first one, but I thought that it should be the least laggy because although it's more complex, it minimizes the amount of calls to check if a Rect should colllide.
I know that the second method is the least laggy, but an explanation of why would be really helpful.
Instead of the second method, I considered trying to only check asteroids within a certain distance of each projectile, but I can't see how I could do this in an efficient way, because for each projectile I would still have to check the distance of every asteroid.
I'm sure there must be a better way than these methods, so if you know of one please let me know. Also, if you need to see more of my code, let me know and I can edit it in. I think this is the minimum amount needed to get the idea though.

How to speed up or optimize for loop used for collision detection using pygame/pytmx?

I am using a for loop combined with .colliderect() for collision detection while attempting to make a game using pygame, the loop gets too slow with ~340 wall Rectangles, I was wondering if it could be faster somehow because it severely effects the game play loop?
I have tried using coordinate points on different places on every wall but only works if you're moving certain amounts of pixels at a time and every time you half the movement speed it quadruples the amount of coordinate points you save.
#disregard indent, this is all in an update function that is called every time that a player decides to move.
self._old_position = self.position
PlayerRectangle = pygame.Rect(self.position[0]+ x,self.position[1]+y,16,16)
cwd = os.getcwd()
tmxData = load_pygame(cwd+"\\Maps\\TestfileMap.tmx")
movement = True
for obj in self.walls:
if(pygame.Rect(obj[0],obj[1],16,16).colliderect(PlayerRectangle)):
movement = False
self.move_back()
else:
continue
if movement:
self.position[0] += x
self.position[1] += y
self.stats["position"]=self.position
self.rect.topleft = self.position
self.feet.midbottom = self.rect.midbottom
The provided code works, however it is too slow, I was wondering if there is a different method in collision detection or if there is a way to make what is shown faster, it bogs down things greatly. Thank you
EDIT:
So the solution was basically that I had load_pygame that ran literally every time it looped simply take out the line that does that and it clears things up a lot more, for further optimization change the line that makes a Rect for each object and just use a list of Rects that are already constructed, this limits function calls.
Without a minimal working example it is tough to give assertive advice.
As I stated in the comments, there is a spurious call to a "load_pygame" function that seems to read file data inside this code - that alone could be the cause of your slowdown. Moreover, the data read is not used in the collision detection.
The other advice I't have is to let your walls rectangles pre-calculated in a sprite group, instead of creating new rectangles for all walls in every check with:
pygame.Rect(obj[0],obj[1],16,16).colliderect(PlayerRectangle)). then you can use the sprite method "spritecollideany" - https://www.pygame.org/docs/ref/sprite.html#pygame.sprite.spritecollideany - that should optimize the rectangle-collision verification.
(This will also require your Player object to be a Sprite if it is not already).

Pygame Line of Sight from Fixed Position

I am currently working on a 2D game in which the player has to sneak up on a still person within a certain amount of time. There are various crates in the way (depending on which level it is), and I would like to make it so that the player can hide behind crates to sneak up on the still person.
I thought that I could use a cone-type vision for the person looking, but I'm not exactly sure how I would accomplish that. The player doesn't have to see the vision cone of the person looking either.
A similar effect to what I would like is in this sample code on github.
NOTE: The player cannot pass through the crates, and the people and crates are sprites.
You have to calculate the if the player is in line with the person, if it is you can check for every box if the 3 objects are ate the same position, if not you are in vision field person_looking. concidere player and person a list with coords.
def isInLine(player, person):
deltaX = person[0] - player[0]
deltaY = person[1] - player[1]
if (person[0] == player[0]) or (person[1] == player[1]) or (abs(deltaX) == abs(deltaY)):
return true
Like in a chess game, imagine you ahve to check if the king is in check by a queen. Its the same logic here.
I think you can create an invisible projectile of a size of one pixel which you launch at desired angle towards player. You make it have some travel speed (say 2 pixels at a time) but instead of actually allowing the projectile to travel every frame you just loop for its travel untill it collides with something (either player or crate or end of level). So the whole emmision and collision process is done outside of while True main game loop in some function. You can emit it every second or something instead of every frame. And also you can emmit it in a cone shape either by scailing it's size every loop or emiting new one at different angle. If any of those collide with player mask or rect -> you have established a line of sight. This idea actually came to me right now out of the blue...
;)
On the second thought... maybe not 1 pixel size projectile but just collidepoint function. Just move your point from emmision origin to target at desired resolution.

Creating DampedRotarySpring in pymunk between a dynamic body and a moving static body

I'm trying to do what the title says. I have a character with a gun constrained to its hand, and I'm trying to get the gun to point at the cursor. I figured that a DampedRotarySpring would be a nice way to do it, but it turns out not to be as simple as that. The gun is a dynamic body with a Segment shape, and for the cursor I create a static body whose position I set to the mouse location with pygame each step.
When I run the program, the gun simply does not move at all except for the effect of gravity or collisions.
Here is the relevant code:
# add crosshairs at the location of the mouse
pointer_body = pymunk.Body()
pointer_shape1 = pymunk.Segment(pointer_body, (0,CROSSHAIRS_SIZE), (0,-CROSSHAIRS_SIZE), 1) # vertical segment
pointer_shape2 = pymunk.Segment(pointer_body, (-CROSSHAIRS_SIZE,0), (CROSSHAIRS_SIZE,0), 1) # horizontal segment
# add a spring that will angle the gun toward the mouse
spring = pymunk.DampedRotarySpring(me.gun.body, pointer_body, 0, 0.01, 1)
space.add(pointer_shape1, pointer_shape2, spring)
while True:
# handle event queue
for event in pygame.event.get():
if event.type == pygame.MOUSEMOTION:
from math import atan2
# update location of pointer
pointer_body.position = flipy(pygame.mouse.get_pos())
pointer_body.angle = atan2( (pointer_body.position.y - me.gun.body.position.y), (pointer_body.position.x - me.gun.body.position.x) )
Edit:
Here is a Gist repository of all my code: https://gist.github.com/4470807.
The main loop is in ragdoll.py.
The problem with the code in the gist is that you have attached the gun to the hand with two joints to keep them in the same place and same rotation. However, the the hand is a rouge body and wont rotate. Therefor the gun wont rotate when its pulled by the spring between it and the cursor, because that other joint is stronger.
Im not sure exactly how you want the setup, but you can see that it all works if you remove the RotaryLimitJoint from the gun-hand.
Take a look at a fixed fork of the code for the exact details: https://gist.github.com/4505219
Some tips for future troubleshooting that I did to find the problem:
Make everything 10x bigger so its easy to see what happens. I know pymunk only draws in one size, but it was easy to just add a 0 on the end of all sizes in the code.
Make the hand not move so its easier to see how it rotates (removed all stuff in the update_hand_position method)
Disable collisions between all shapes in the scene so that the rotating gun is not hindered by some body part. (did a simple loop of space.shapes and ran shape.group=1)
Maybe your problem is with the spring parameters? The stiffness and damping looks very low unless the gun is extremely light.
Check out this code example I added to pymunk yesterday: http://code.google.com/p/pymunk/source/browse/trunk/examples/damped_rotary_spring_pointer.py
(There is one thing going on with the rotation when it flip over between positive and negative pi that I will look at)

Categories

Resources