I have a 3D elastic collision simulation. I'd like to clear all of the sphere objects from my program from a button press. The documentation indicates that I should do the following:
def clear_balls():
for ball in balls:
ball.visible = False
del ball
This successfully makes the balls invisible in the scene, but they still take up memory and collide with balls that still exist. I want it completely removed. Trying this with a unique ball name this isn't part of a list as some have suggested still results in the same issue.
del ball is not doing what you think because balls still holds a reference to the object. You need to empty the balls list:
def clear_balls():
for ball in balls:
ball.visible = False
balls[:] = []
Related
I'm currently trying to make 3d graphics using Turtle.
I have a list of objects that have inherited the Turtle class and each one has an attribute frontFactor - this value is the distance of the turtle to the camera.
How can I make the turtles closer to the camera render on top of the other turtles behind it?
My current code trying to do this:
finished = []
highestIndex = 0
print("FRAME")
for object in objects:
for i in range(len(object.particles)):
curHighest = 0
for j in range(len(object.particles)):
if object.particles[j].frontFactor > curHighest and (not (j in finished)):
curHighest = object.particles[j].frontFactor
highestIndex = j
object.particles[highestIndex].move(0,0,0)
print(object.particles[highestIndex].frontFactor)
finished.append(highestIndex)
where objects has an attribute of particles which is a list,
and every item in this list has a value frontFactor that determines the distance to the virtual camera.
This function goes through each particle on the screen (currently i only have one object), starting from the particles farthest away from the camera and ending at the particles nearest the camera.
This is what I want to happen,
but this is what it looks like instead. (darker particles are further away)
I've heard of a rule which states "last to move is on top" although I don't know how to implement that in this situation.
I am trying to make my sprite move according to the astar pathfinding algorithm. However, after I implemented it, I realised that the movement of the sprite is only in accordance to the top left pixel. That means that if the algorithm tells it to move up after crossing a boundary, it will do so once the top left pixel crosses that boundary. However, this means that the entire sprite has not actually crossed, resulting in a collision if there is an obstacle just above it. Is there any way to tell it to move left more before moving up]1
def astar_ghost(pac,ghost):
maze=astar.create_maze(screen_width,screen_height,obstacles) #creates a maze of 0s and 1s. The 1s represent the obstacles
start=(ghost.gridloc[0],ghost.gridloc[1])
end=(ghost.goal_node[0],ghost.goal_node[1])
goal_node=astar.astar(maze,start,end)
if goal_node==None:
pass
else:
ghost.goal_node=goal_node
game=True
if ghost.goal_node[0]<ghost.gridloc[0]:#left
print('move left')
game=collision(pac,ghost) #collision is another function that checks for collision and returns True or False. If False, the game will be over
ghost.left=True
ghost.right=False
ghost.up=False
ghost.down=False
elif ghost.goal_node[0]>ghost.gridloc[0]:#right
print('move right')
game=collision(pac,ghost)
ghost.left=False
ghost.right=True
ghost.up=False
ghost.down=False
elif ghost.goal_node[1]<ghost.gridloc[1]:#up
print('move up')
game=collision(pac,ghost)
ghost.left=False
ghost.right=False
ghost.up=True
ghost.down=False
elif ghost.goal_node[1]>ghost.gridloc[1]:#down
print('move down')
game=collision(pac,ghost)
ghost.left=False
ghost.right=False
ghost.up=False
ghost.down=True
You are asking a few different questions here. I'll answer here to what I think you're trying to ask: Is there a way to check if an entire sprite has crossed a boundary, instead of just the top-left corner?. So, my answer (note this will only work if your boundary line is linear): You need to check each of the corners individually, then, if all of them have returned True, then you move on. Example:
def collision(sprite1, boundary):
def internal_collision(point, boundary):
... # The actual math happens here, returns True/False
corners = []
for h in [0, 1]:
for j in [0, 1]:
corners.append([sprite1.rect.x+(h*sprite1.rect.width),
sprite1.rect.y+(j*sprite1.rect.height)])
corner_check = []
for corner in corners:
corner_check.append(internal_collision(corner, boundary))
return all(corner_check)
I don't know how your code works, so I've tried to keep this as malleable and understandable as possible, so you can re-implement it in your own code.
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
my first question here and begginer in python
i want to make simple shooter game(Chicken Invaders type). List of rectangles(enemies) and smaller rectangles(ammo) who should 'kill' enemies on collision. I created list of rectangles on random positions on screen.
enemies = []
for i in range(ENEMYCOUNT):
enemySize = random.randint(ENEMYMINSIZE, ENEMYMAXSIZE)
newEnemy = pygame.Rect(random.randint(0, WINDOWWIDTH - enemySize),
random.randint(0, WINDOWWIDTH-200), enemySize, enemySize)
enemies.append(newEnemy)
My 'ammo' are list of invisible rectangles who appear on mouse click and then they move up
ammo = []
for i in range(1, 5):
ammo.append(pygame.Rect(0, 0, 0, 0))
I did for single enemy and single ammo and it is working as intended.
Now i want to make for more enemies and check if any of enemy is hit by ammo
for e in enemies:
for a in ammo:
if e.colliderect(a):
enemies.remove(e)
But i keep getting
if e.colliderect(a):
AttributeError: 'NoneType' object has no attribute 'colliderect'
I am studying from 'inventwithpython' book and copying parts of code that i need but i could not solve this. I cant see the problem since both of my lists are made of Rect objects.
Any help would be appreciated
Problem can be because you remove from list which you use in for statement.
Solution: create new list with not-removed elements and later assign it to enemies
But Pygame has class Group to keep Sprites and
pygame.sprite.spritecollide(sprite, group, dokill, collided = None)
which:
Return a list containing all Sprites in a Group that intersect with another Sprite. Intersection is determined by comparing the Sprite.rect attribute of each Sprite.
The dokill argument is a bool. If set to True, all Sprites that collide will be removed from the Group.
I just started programming in OOP style last week when deciding to make a small game. But now I seem to be stuck. I'll explain what I have so far:
When the player hits a button, a bullet object is created next to the player and the bullet object is added to the bullets[] list. The bullet then travels horizontally across the screen in the designated direction. If the bullet collides with a player or a wall, it is removed from the bullets[] list. So far, so good.
Now I just cant seem to figure out how to remove the bullet from the bullets[] list when it leaves the screen (screen is defined between 0 and xmax). Also, after I remove the bullet from the list, should I also remove the object itsself, or is this done automatically?
Code so far:
class BULLET(object):
#Constructor for the bullet, bullets are stored into array 'bullets'
# The direction is stored to keep track of which player fired the bullet
def __init__(self,location,direction,color):
self.rect = pg.Rect(location[0],location[1],xmax/160,xmax/160)
self.bullet_type="normal"
self.direction=direction
self.color=color
bullets.append(self)
#Moves the bullet horizontally across the screen, in the specified direction
# The move function also checks for collision with any walls or players
# The move function removes the bullet object from the list and destroys it
# when it leaves the left or right side of the screen
def move(self,bullet_speed):
self.rect.x += bullet_speed
for wall in walls:
if self.rect.colliderect(wall.rect):
index=wall.rect.collidelist(bullets)
del bullets[index]
#Do I need to delete the object too? or just the list item?
for player in players:
if self.rect.colliderect(player.rect):
index=player.rect.collidelist(bullets)
if player.immune_timer <= 0:
del bullets[index]
player.immunity(500)
player.life -= 1
if self.rect.centerx > xmax or self.rect.centerx <0:
#This is where I would like this instance of the bullet object to be deleted
# and to have the object removed from the bullets[] list
What I suggest you do is in your main loop:
bullets = [bullet for bullet in bullets if 0 < bullet.rect.centerx < xmax]
This will only keep the items that should be in the list.