Im building a game in processing python. It is similar to pong except the paddles can rotate thus changing the direction of the ball. There is also supposed to be a feature where if you hit a smaller ball, triangles pop up on each the top and botton making it harder to get the ball through to the other side. So the ball is supposed to bounce off of the triangle and and make a 45 degree angle in reference to the x and y axels. Im having a hard time solving this problem. picture of game, white circle is the ball that I that is supposed to bounce on the triangle. My initial thought was to make an if statement containing two mx + c functions as follows.
if triangle_score == 1 and ball_y >= (ball_x * -1) + 350 and ball_y >= (ball_x - 450):
ball_dx = ball_dx * -1
ball_dy = ball_dy * -1
Needless to say it didn't work very well. Does anyone know processing. Would be sooo thankful for any help I can get.
Related
I am successfully detecting collisions between my player sprite and platform sprites using masks in pygame, but my issue is stopping the player from falling through a platform when jumping to it.
I tried solving the issue with mask.overlap(). Using this, I'm able to identify the point on my player sprite that has come into contact with the platform during a collision. When the bottom of the player sprite (her shoes) is colliding with a platform, she should stop falling. I can get this point from mask.overlap() and I hard-coded the y-coordinate of this point (which is a point on the sprite itself, not the screen) y = 155 in the program:
hits = pygame.sprite.spritecollide(player, platform_group, False)
if hits:
hits = pygame.sprite.spritecollide(player, platform_group, False, pygame.sprite.collide_mask)
for platform in hits:
offset = (platform.rect.x - player.rect.x), (platform.rect.y - player.rect.y)
if player.mask.overlap(platform.mask, offset):
x = player.mask.overlap(platform.mask, offset)[0]
y = player.mask.overlap(platform.mask, offset)[1]
pygame.draw.circle(display, s.RED, (x + player.rect.x, y + player.rect.y), 2)
print('Sprite pixel coll y: ' + str(y), 'Platform rect y top: ' + str(platform.rect.top))
if y == 155:
player.v_y = 0
player.rect.y = platform.rect.y - y
The red dot is the point at which collision on the player sprite has been detected.
The problem with the current code (apart from it being a very ugly solution) is that it doesn't work for all cases. When the player falls too fast, the detected collision point will not be her feet (i.e. not when y = 155´) and she will fall through the platform since the if-condition will not be fulfilled.
I could try a limit like if y >= 145 and y <= 160: but that still doesn't cover all cases and can cause her to "bounce" up when landing.
I'm currently stuck and wondering if anyone has any suggestions. I know I can use sprite Rects and go with colliderect but that will not give me the desired effect.
Thanks alot
you could check to see if the character is touching the platform ( using the mask.overlap method) and then set the velocity to 0 and gradually increase the y value until they are no longer colliding then continue with the rest of the game loop. (this is how I checked for collision but I used images instead of sprites) hope this helps.
I am trying to get a ball to bounce off of the walls of my bounds. Currently, my circle is supposed to hit the wall and then change velocities and move in the opposite direction but this is not happening. I would appreciate some help :) Thank you
from graphics import*
from random import*
from time import*
win = GraphWin('My Program', 600, 600)
win.setBackground('pink')
my_circle = Circle(Point(200,300),30)
my_circle.setFill('blue')
my_circle.setOutline('darkorchid1')
my_circle.draw(win)
key = win.checkKey()
while key == '':
vel_x = randint(-30,30)
vel_y = randint(-30,30)
my_circle.move(vel_x, vel_y)
sleep(0.1)
for bounce in range(600):
find_center = my_circle.getCenter()
center_x = find_center.getX()
center_y = find_center.getY()
if center_x == 600 or center_y == 600:
vel_x = -randint(30,-30)
vel_y = -randint(30,-30)
my_circle.move(vel_x, vel_y)
sleep(0.1)
key = win.checkKey()
Several things that may affect the problem.
You should set your velocities once, as you're doing in the first lines in the while loop. Whenever it bounces you should move in the opposite direction using vel_x = -vel_x and vel_y = -vel_y.
Right now you're updating both of velocities which might lead to some wierd bounces when only one of the centeres hits a wall.
It might be more logical to check wether the distance from the center to the wall is less than the radius of the circle. This will prevent the issue when the ball moves from x=599 to x=601 in one iteration, skipping the if statement. (This would also make it so that the circle bounces when its edge hits the wall instead of the center)
Currently you're only checking 2 walls, unless you meant to do this you should add the if statements for the other walls aswell.
Small other thing, the second time you draw the random velocities you draw from the range 30 to -30, which is invalid.
Here is my code
import pygame, sys
pygame.init() #load pygame modules
size = width, height = 800, 600 #size of window
speed = [25,25] #speed and direction
x= 100
y= 100
screen = pygame.display.set_mode(size) #make window
s=pygame.Surface((50,50)) #create surface 50px by 50px
s.fill((33,66,99)) #color the surface blue
r=s.get_rect() #get the rectangle bounds for the surface
r[0] = x #changes initial x position
r[1] = y #changes initial y position
clock=pygame.time.Clock() #make a clock
while 1: #infinite loop
clock.tick(30) #limit framerate to 30 FPS
for event in pygame.event.get(): #if something clicked
if event.type == pygame.QUIT:#if EXIT clicked
pygame.quit()
sys.exit() #close cleanly
r=r.move(speed) #move the box by the "speed" coordinates
#if we hit a wall, change direction
if r.left <= 0 or r.right >= width:
speed[0] = -(speed[0])*0.9 #reduce x axis "speed" by 10% after hitting
if r.top <= 0 or r.bottom >= height:
speed[1] = -speed[1]*0.9 #reduce y axis "speed" by 10% after hitting
screen.fill((0,0,0)) #make redraw background black
screen.blit(s,r) #render the surface into the rectangle
pygame.display.flip() #update the screen
It's a simple window that shows a square moving, hitting the edges and bouncing back. However, in this particular example (speed set to 25 on both axis) and speed reduction set to 0.9 after bouncing back (less 10%), my square seems to get stuck on the left side of the window (I suggest you to copy and paste it and see for yourself)
If I change the speed to a lower value or set no speed reduction whatsoever after bouncing everything works fine.
Any reason on why this is happening?
Let's step through this code one by one:
speed = [25,25] #speed and direction
if r.left <= 0 or r.right >= width:
speed[0] = -(speed[0])*0.9
Let's just look at what happens at the x axis.
Let's assume the position before this check is 1. In the next frame, the value of position is 1-25 = -24. Since the condition is now fulfilled, the speed becomes 25 * 0.9 = 22.5.
The rectangle moves to position -1.5 and we are still on the wrong side of the wall. Since you change the direction of speed on each frame, the rectangle will be stuck there.
There are 2 solutions to the problem, the first one is already described by Alex.
The second one, is to move the rectangle first, and if the rectangle moves out of bounds, return it to before the wall.
Right! To make the square move and bounce freely without getting potentially stuck in an edge what you need to do is to reverse the speed (and decrease it by 10%) before you actually move the ball! This is my simple suggestion
if r.left + speed[0] <= 0 or r.right + speed[0] >= width:
speed[0] = - (speed[0])*0.9
if r.top + speed[1] <= 0 or r.bottom + speed[1] >= height:
speed[1] = -(speed[1])*0.9
What the above modifications manages, is that it essentialy does not allow the square to go out of bounds at any time! As far as to what caused your above issue, after doing some debugging, it is apparent that the square manages to move outside the screen! (i.e. negative x,negative y etc), While it might seem harmless, this behaviour especially at lower speeds can cause the square to rapidly reverse and at the same time lower it's speed by 10%!
For example if at any point the square is at position x = - 1 with an xspeed of 1. Due to this condition: if r.left + speed[0] <= 0 or r.right + speed[0] >= width: it's speed will reverse multiple times back and forth and decrease at the same time not allowing the square to escape this edge!
Phew! Sorry for the long answer and I hope I helped!
Cheers!,
Alex
I am making a game with pygame and i want the player the face the cross hair, this is the code I have, I made it print out the angle in my idle and I noticed that the angles where all wrong and the player didnt rotate at all anyway. I've seen some other questions like this and I've followed them but i still get the wrong angle and the image dosnt rotate anyway
here is my code for the angle and rotating image:
mouse_x, mouse_y = pygame.mouse.get_pos()
mouse_x -= crosshair.get_width() / 2
mouse_y -= crosshair.get_height() / 2
player_atan = math.atan2(player_x-player_y, mouse_x-mouse_y)
player_angle = degrees(player_atan)
pygame.transform.rotate(screen, player_angle)
You have to subtract the same components from the different points.
player_atan = math.atan2(mouse_y - player_y, mouse_x - player_x)
You should check out the python docs: it has some valuable info.
The reason why your sprite does not rotate is because rotate returns a new rotated surface.
A link to the docs:docs
I'm making a game in which balls bounce around the inside of a much larger circle. The larger circle doesn't move.
Here's the code that I'm currently using for these collisions:
def collideCircle(circle, ball):
"""Check for collision between a ball and a circle"""
dx = circle.x - ball.x
dy = circle.y - ball.y
distance = math.hypot(dx, dy)
if distance >= circle.size + ball.size:
# We don't need to change anything about the circle, just the ball
tangent = math.atan2(dy, dx)
ball.angle = 2 * tangent - ball.angle
ball.speed *= elasticity + 0.251
angle = 0.5 * math.pi + tangent
ball.x -= math.sin(angle)
ball.y += math.cos(angle)
It is based on the wonderful tutorial by Peter Collingridge over here.
The circle and ball objects are both classes, with (x,y), radius, angle and speed.
I am having two problems with this method, however:
The ball bounces from (what I suspect) is its "anchor point", which seems to be in the top right corner of the circle.
When colliding with the bottom 5% of the circle, is fails to bounce high enough and therefore "sinks" out of the screen. I am guessing that this is because the bounce is not high enough to move the ball above its (incorrectly placed) "anchor point"?
Having looked at possible solutions already on here, notably "Fast circle collision detection" [Link deleted due to spam link limit], which, although in Java is using the same method, these all deal with external collisions, whereas I am looking at bouncing a ball around the interior of a circle.
Here is also the class definitions of the Ball() and the Circle():
class Ball():
def __init__(self, (x,y), size):
"""Setting up the new instance"""
self.x = x
self.y = y
self.size = size
self.colour = (0,128,255)
self.thickness = 0
self.speed = 0.01
self.angle = math.pi/2
def display(self):
"""Draw the ball"""
pygame.draw.circle(screen, self.colour, (int(self.x), int(self.y)), self.size, self.thickness)
def move(self):
"""Move the ball according to angle and speed"""
self.x += math.sin(self.angle) * self.speed
self.y -= math.cos(self.angle) * self.speed
(self.angle, self.speed) = addVectors((self.angle, self.speed), gravity)
self.speed *= drag
class Circle():
def __init__(self, (x,y), size):
"""Set up the new instance of the Circle class"""
self.x = x
self.y = y
self.size = size
self.colour = (236, 236, 236)
self.thickness = 0
self.angle = 0 # Needed for collision...
self.speed = 0 # detection against balls
def display(self):
"""Draw the circle"""
pygame.draw.circle(screen, self.colour, (int(self.x), int(self.y)), self.size, self.thickness
Thanks in advance, Nathan
Without answering your question, I'd like to comment on your implementation strategy and recommend a new approach. You represent the velocity of the ball in polar coordinate form, as ball.angle and ball.speed.
I think that this is going to be generally inconvenient for you. For example, in your collision code you end up calling atan2 to turn the vector (dx, dy) into an angle, and then you call sin and cos to turn the angle back into a vector again. (Also, should you ever try to generalize your code to three dimensions, you will find yourself in a world of pain.) So, unless you have particular requirements that necessitate polar coordinates, I recommend that you do what everyone else does, namely represent the velocity of the ball in Cartesian coordinates as the vector (vx, vy).
I also recommend changing your physics approach from a static one ("is object A currently colliding with object B?") to a dynamic one ("will object A collide with object B during its next movement step?"). In a static physics system you often end up with objects intersecting each other at the end of a movement step, and then you have to figure out the best way to get them to separate again, which is hard to get right.
If you do both of these, it is straightforward to bounce the ball without any trigonometry.
Step 1. Transform circle/circle collision into point/circle collision using Minkowski addition:
Step 2. Consider a time segment in which the ball starts at p = (px,py) and moves by v = (vx,vy). Does it intersect with the circle? You can use a standard line segment/circle test for this except that the sense of the test is reversed.
Step 3. Find the point of collision c = (cx,cy). The ball bounces off the circle in the same way as it would bounce off the line t tangent to the circle at this point. For a circle centred at the origin, the tangent vector is just (−cy,cx) and I'm sure you can work out how to compute it for other circles.
See this answer for how to calculate the new path of the ball based on coefficients of friction and restitution.
Step 4. Don't forget that the ball may still have some distance to move along the new vector w. If the time step is large enough or the velocity high enough it may collide again during the same time segment.
I'm glad you liked my tutorial. I like your variation, it should actually be simpler.
First, I think you need change the test for collision to:
if distance >= circle.size - ball.size:
Because the larger the ball size, the smaller the distance between its centre and the centre of the circle can be. This should make the balls bounce at the right place (inside the circle).
Then I think you just need to swap the signs for the x and y and everything should work.
ball.x += math.sin(angle)
ball.y -= math.cos(angle)
To move the ball by the correct distance you can calculate the overlap:
overlap = math.hypot(dx, dy) - (circle.size - ball.size)
if overlap >= 0:
tangent = math.atan2(dy, dx)
ball.angle = 2 * tangent - ball.angle
ball.speed *= elasticity
angle = 0.5 * math.pi + tangent
ball.x += math.sin(angle)*overlap
ball.y -= math.cos(angle)*overlap
Good luck
Most graphics packages use upper-left as start for drawing code. You most likely want 2 sets of coordinates, the one's you collide/move/etc with and the one's for drawing (x-radius, y-radius).
Also, without having thought about it too much, should the check for intersection be distance + ball.size >= circle.size? The balls distance from the center plus its radius should be less than the circle's radius, if I understood the setup correctly.