Collision detection variable always output "True"? [duplicate] - python

This question already has answers here:
How to detect collisions between two rectangular objects or images in pygame
(1 answer)
Why is my collision test always returning 'true' and why is the position of the rectangle of the image always wrong (0, 0)?
(1 answer)
How do I detect collision in pygame?
(5 answers)
Closed 2 years ago.
I apologise if you have seen a post of mine regarding this issue already, I am desperate to solve this.
I am creating a 2-player top down racing game and need to create a way for the program to know when the users have completed a lap. I have chosen to do this by placing sprites on the track, with the same texture as the track, so that they blend in. The idea is to create a list for each player's vehicle, containing boolean variables, one variable for each checkpoint. Every boolean variable in the list has to equal "True" in order for a lap to be counted.
Before I attempt this, I want to figure out how it can be done by detecting when the player's vehicles collide with each other. I have attempted, with help from a previous post, to do this.
My vehicle class can be seen, with my checkCollision function, below.
class Vehicle(pygame.sprite.Sprite):
'Base class for all vehicles (Cars and Motorbikes) in the game'
vehicleCount = 0
def __init__(self, max_speed, acceleration, turning_radius, image):
#pygame.sprite.Sprite.__init__(self)
self.max_speed = max_speed
self.acceleration = acceleration
self.turning_radius = turning_radius
self.image = image
self.rect = self.image.get_rect()
Vehicle.vehicleCount = Vehicle.vehicleCount + 1
def displayAmount():
print ("Total number of Vehicle enteries: ", Vehicle.vehicleCount)
def displayVehicle(self):
print ("max speed: ", self.max_speed, "acceleration: ", self.acceleration, "turning radius: ", self.turning_radius)
def checkCollision(self, sprite2):
col = pygame.sprite.collide_rect(self, sprite2)
if col == True:
print ("True")
Here is an example of one of my vehicle objects being defined:
sportscar = Vehicle(4.5, 0.2, 2.01, sportsimage)
I am checking if the vehicles have intersecting by running the following line in the main game loop:
choice1.checkCollision(choice2)
However, when I run the program, the console outputs "True" constantly, even when the vehicles aren't touching. Does anyone know where I have gone wrong with this? Thanks.

Related

Optimising pygame

For my project in AH Computing I'm recreating my version of Nidhogg. Everything runs smoothly until the blood starts spraying. Im not too sure how i can make the code more efficient as i am still fairly new to python.
This is the class for the the spraying blood:
class bloodmaker():
def __init__(self,xv,yv,colour,x,y):
self.gravity = 2
self.air_resistance = 0.25
self.xv = xv
self.yv = yv
self.x = x
self.y = y
self.pastx = 0
self.pasty = 0
self.colour = colour
def move(self):
if self.y < 400:
self.pastx = self.x
self.pasty = self.y
#so that it doesnt curve backwards
if self.xv > 0:
self.xv -= self.air_resistance
self.yv += self.gravity
self.x += self.xv
self.y += self.yv
#so that the drawn line doesnt go over the edge
if self.y > 400:
self.y = 400
if self.colour is "o":
py.draw.line(screen, (255, 165, 0), (self.pastx-backgroundx, self.pasty), (self.x-backgroundx, self.y),5)
else:
py.draw.line(screen, (255, 255, 0), (self.pastx-backgroundx, self.pasty), (self.x-backgroundx, self.y),5)
else:
global bloodgrid
try:
#the bloodgrid are squares 5 pixels wide, covering the bottom section, so we we divide by 5 to find where to put the blood
bloodgrid[int(self.x/5)].insert(0,self.colour)
except:
pass
#deleting this object as it is no longer required
return True
[Here is an image of the blood spraying][1]
(excuse the incomplete sprite)
[1]: https://i.stack.imgur.com/hXiAa.png
Underneath there is a floor of blood that works using an array of stacks, which is added above code when it the blood reaches the floor.
bloodgrid = [[] for x in range(512)]
Here is the code for destroying the flying blood object and blitzing the blood floor to the screen.
def blood():
for i in range(len(bloodarray)):
killyourself = bloodarray[i].move()
if killyourself is True:
kill.append(i)
#appends to a kill list as if i popped here the list would get shorter while the for loop stays the same giving an out of index error
for i in range(len(kill)):
bloodarray.pop(kill[0]-i)
kill.pop(0)
#printing the entire bloodgrid
for i in range(512):
for ii in range(len(bloodgrid[i])):
try:
if bloodgrid[i][ii] is "o":
py.draw.rect(screen, (255, 165, 0), ((i*5)-backgroundx, ii*5+400, 5, 5))
else:
py.draw.rect(screen, (255, 255, 0), ((i*5)-backgroundx, ii*5+400, 5, 5))
except:
pass
I don't think it is possible to only update parts of the screen as the camera moves about and the blood on the floor moves too.
As more blood accumulates on the floor the game framerate starts to drop and it gets especially choppy when the blood sprays. Is there any ways I could make this more efficient? I don't want to hand in a choppy game but I really like how the blood looks. Thanks.
A couple of points that are hopefully helpful.
(This isn't directly related to speeding up your code, but...) Try to get away from using global variables. Just pass them into your functions. Several of the ones you posted are difficult to figure out because you are accessing variables that are outside the scope of the function.
First reason things are bogging down here: You are using insert() to insert new elements at the start of a list, and you are doing that inside of a loop where you call the move() function. Inserting anywhere into a list (except the end) is horribly slow for reasons beyond the scope of this post. You should consider putting a deque from collections in there, which can be inserted front or back efficiently. If that is daunting, you could also "do a little math" and insert at the end of your list and draw it backwards by counting down from the last element, which is also efficient.
Also in the same notion, as mentioned in the comments, poping things out of the middle of lists or arrays is also horribly slow. Figure out a different way or look at a different data structure. It is tough to give advice on this point because bloodarray is not defined in your code.
Basically: things are bogging down because you are choosing the wrong data structures. tweak a couple of them and you'll get better results.

How to dynamically instantiate objects from a certain class [duplicate]

This question already has answers here:
How do I create variable variables?
(17 answers)
Closed 2 years ago.
I'm making a simple ball game using a 2D map. The amount of balls on the map is variable. When starting the game I load the map and look for balls (The balls are unique letters). I append these ball names to a list.
I also have a Ball class. __init__ contains the coordinates of the ball and the class contains a couple of methods.
Here comes the problem:
I want to create objects of each ball using the Ball class, with the object name corresponding to the letter belonging to the ball.
I tried this:
(The map is a txt file looking like this:)
0 0 0 0
0 0 X 0
0 A 0 B
Where the zero's represent empty tiles.
class Ball:
def __init__( self, x, y):
self.x = x
self.y = y
map_data = np.genfromtxt('map.txt', dtype=str)
ball_names = []
for row in variables.map_data:
for i in row:
if i.isalpha():
ball_names.append(i)
for ball in ball_names:
coordinates = np.where(map_data == ball)
ball = Ball(coordinates[0], coordinates[1])
But then I want the object to be named after the string contained by the variable ball, not 'ball'.
I know this can be done using exec(), but I've been told to avoid that function.
Generating variables dynamically with exec is a bad idea. As in fact variables will be totally hidden from developer. Supporting such code will be a nightmare and it's going to be a giant source of problems.
Instead, why don't you create a dict of balls?
my_balls = dict()
for ball in ball_names:
coordinates = np.where(map_data == ball)
my_balls[ball] = Ball(coordinates[0], coordinates[1])
But if you really want to create a variable, then:
exec(f'{ball} = Ball({coordinates[0]}, {coordinates[1]})')

why does this code only register certain collisions and not all?

Hi i have a code for a game where there are multiple fruits falling from the sky and the frog at the bottom has to try and catch them. When he catches one the score goes up. This only happens when the frog collides with some of the fruit and not all of them. And the score randomly starts increasing unstoppably for no reason after a certain point. Here is most of the code as im not sure where the error would be :
import pygame, sys, time, random
from pygame.locals import *
from math import fabs
######### constants ##########
jumpvel=20
fallingspeed=1
running= True
blue= [129,183 ,253]
pink=[255,174,201]
textcolour= [255,255,255]
x=700//2
y=1000//2
score=0
thingylist= ['fruit1.bmp','fruit2.bmp','fruit3.bmp','fruit4.bmp','fruit5.bmp','fruit1.bmp','fruit2.bmp','fruit3.bmp','fruit4.bmp','fruit5.bmp','naughty1.bmp','naughty2.bmp','naughty3.bmp',]
all_things=[]
for i in range (12):
new_thing_image=pygame.image.load(thingylist[(random.randrange(0,12))])
new_thing_image.set_colorkey(pink)
new_thing_rect=new_thing_image.get_rect()
new_thing_rect.x=random.randrange(0,950)
new_thing_rect.y=-random.randrange(50,500)
all_things.append([new_thing_image,new_thing_rect])
def checkCollision (frog_rect,all_things,score):
collides_with=None
for thing_image, thing_rect in all_things:
if frog_rect.colliderect(thing_rect):
collides_with=True
if collides_with == True:
score= score+100
return collides_with,score
######## initialising screen#########
pygame.init()
gamedisplay=pygame.display.set_mode((1000,600)) #making the screen
pygame.display.set_caption('frog')
clock=pygame.time.Clock()# frames per second
bg=pygame.image.load('actual clouds.bmp').convert()
############ initialising sprites##############
frog= pygame.image.load('actual frog.bmp')
frog.set_colorkey(blue)
frog_rect=frog.get_rect()
frog_rect.centerx=(x)
frog_rect.centery=(y)
##########drawing things#############
def drawThings (all_things):
for item in all_things:
new_thing_image, new_thing_rect= item
gamedisplay.blit(new_thing_image, (new_thing_rect.x, new_thing_rect.y))
#########update display function###########
def update(x,y,all_things,score):
gamedisplay.blit(bg,[0,0])
gamedisplay.blit(frog,(x,y))
for thing in range (len(all_things)):
new_thing_rect=all_things[i][1]
#thing_rect.y=thing_rect.y+fallingspeed
new_thing_rect.y+= fallingspeed
drawThings(all_things)
label=font.render("score "+ str(score) ,1,textcolour)
gamedisplay.blit(label,(750,10))
gamedisplay.blit(heart1,(750,50))
gamedisplay.blit(heart2,(850,50))
gamedisplay.blit(heart2,(800,50))
pygame.display.update()
pygame.time.delay(50)
while running == True:
gamedisplay.blit(bg,[0,0])
gamedisplay.blit(frog,(x,y))
drawThings(all_things)
label=font.render("score "+ str(score) ,1,textcolour)
gamedisplay.blit(label,(750,10))
pygame.display.flip()
pygame.event.pump()
key=pygame.key.get_pressed()
for item in all_things:
new_thing_image, new_thing_rect= item
new_thing_rect.y+= fallingspeed
if new_thing_rect.y >450:
new_thing_rect.x=random.randrange(0,950)
new_thing_rect.y=-random.randrange(50,500)
############collision detection##########
detect,score =checkCollision (frog_rect, all_things,score)
update(x,y,all_things,score)
The score should increase every time it collides with any of the falling friuts not just certain ones and not just start increasing randomly non-stop. Any help would be appreciated thankyou !
Based on the code snippet - which does not include the frog-position updating code, I would guess that the problems of:
Score randomly increasing
Collisions not always working
Are caused by the collision rectangle being defined once for the frog's starting position, but then never being updated with changes in the frog's position.
############ initialising sprites##############
frog= pygame.image.load('actual frog.bmp')
frog.set_colorkey(blue)
frog_rect=frog.get_rect()
frog_rect.centerx=(x) # <-- rect only ever updated here!
frog_rect.centery=(y)
This would lead to the described symptoms, since scoring-objects (fruit?) falling through the collision rectangle would add to the score (seemingly randomly), and when the frog was still over it's original position, collision would work perfectly. If the frog was partially over the rect it would somewhat work, and not at all once the frog moved away that start-position rect.
The solution to the problem is to update the co-ordinates of the rectangle frog_rect whenever the x & y of the frog's position is updated. This can be achieved by setting the frog_rect.centerx and frog_rect.centery inside the update() function:
def update(x, y, all_things, score ):
frog_rect.x = x
frog_rect.y = y
The frog's rect is initialised with .centerx, .centery co-ordinates, but the frog is draw at x,y, so the collision rect begins a little off-centre too. Thus it would be best to update the initialisation function as well:
frog_rect=frog.get_rect()
frog_rect.x = x
frog_rect.y = y

Python: How do I detect visible shape detection in Tkinter

I am new to Python and I have a program that has 2 classes, one is essentially a rectangle and the other is essentially a circle. I am drawing them using the Canvas in Tkinter in the way below:
def draw(self):
self.canvas.delete("all")
self.rect.draw(self.canvas)
self.ball.draw(self.canvas)
The Ball class has its location variables and diameter variables and the Rect class has its location and dimension variables.
I am wondering how I detect the collision between these two "shapes". I know that one was is to treat the Ball as a square and do basic rectangle collision but I would like to know how to be precise.
I was also wondering if there was anything similar in Python to the way shape collision can be done in Java. In my Java game I use the following code to detect collision between any 2 Shapes:
public boolean collisionCheck(Shape a, Shape b) {
Area aA = new Area(a);
Area aB = new Area(b);
aA.intersect(aB);
return !aA.isEmpty();
}
Is there anything similar to this simple solution in Python?
And if not how would I go about circle-rectangle collision in Python?
Thank you for any help
I managed to figure this out using a method that Tkinter's Canvas object has. Every time something is drawn using Canvas it is given an ID. So as long as you record that ID somewhere you can use the find_overlapping method that the Canvas object has.
Say you have an object, in my case a custom Platform object, that keeps the ID stored in a variable. I did so like this:
def draw_platform(self, canvas): #Located in the Platform Class
self.ID = canvas.create_rectangle(self.x, self.y, self.x+self.w, self.y+self.h)
Now I can use this ID to determine if there are any object overlapping it.
def check_collision(self, plat, other_plat):
result = self.canvas.find_overlapping(plat.x, plat.y, plat.x + plat.w, plat.y + plat.h)
for i in result:
if i == other_plat.ID:
return True
return False
result returns a tuple of the ID's that are located within the rectangle bounds entered into find_overlapping. You can than loop through the tuple to see if any of the ID's match your other shape.
This works great for Rectangle-Rectangle collision and Circle-Rectangle collision.

Game ai Line of Sight Python

How would I check to see whether the player is within range of a mob? (I am making a top down game in pyglet) I am making it so that the mobs follow and attack the player if he is within a certain distance of them but I am unsure how to efficiently do this. Would I need to do an "if" statement to see if x > mob.x - 50 and x < mob.x + 50 etc?
I have a class for the mobs
class zombie(pyglet.sprite.Sprite):
def __init__(self, image, x, y, batch,trees):
pyglet.sprite.Sprite.__init__(self, image, x, y, batch=None)
I then used several functions as the different actions they could be doing
def move(self):
...
def idle(self):
...
The player's position is "player.x" and "player.y" (the same for the mobs but with "zombie instead of player)
As Joran said, I think finding the distance betweens the mob and the player's coordinates is the best approach and I will make another function to check the distance.
Sorry if this was unclear
you would probably need to calculate the distance between the monster and the player
sqrt((mob.x-player.x)**2 + (mob.y-player.y)**2)
you could probably simplify it and get rid of the sqrt ...

Categories

Resources