After a few hours of looking for code to reference. I failed i tried to re-write the collision code but it failed. Now my Question is
How can i fix my code to make it delete the Enemy ship when the bullet hits him
Note: Im not asking for you to do it, i just need it further explained what the problem or where im making a mistake
The Code Segment
for bullet in Bullets:
Hit_list = pygame.sprite.Group()
if pygame.sprite.collide_rect(bullet, Enemy_list):
Hit_list.add(hit)
for hit in Hit_list:
Bullets.remove(bullet)
All.remove(bullet)
All.remove(hit)
Enemy_list.remove(hit)
# If the bullet goes off the screen it deletes
if bullet.rect.y < 0:
Bullets.remove(bullet)
All.remove(bullet)
The Error
Traceback (most recent call last):
File "C:\Users\jb127996\Desktop\Invaders in Space\Space Shooter.py", line 92, in <module>
if pygame.sprite.collide_rect(bullet, Enemy_list):
File "C:\Python32\lib\site-packages\pygame\sprite.py", line 1290, in collide_rect
return left.rect.colliderect(right.rect)
AttributeError: 'Group' object has no attribute 'rect'
Entire Code
import pygame
import Player_func
import AI
from pygame.locals import *
#Background
Background = pygame.image.load('Tempback.png')
Background_size = Background.get_size()
Background_rect = Background.get_rect()
# Screens Resoultion
Width = 640
Height = 480
Scr = pygame.display.set_mode((Width,Height))
# Fps Clock Vars( Clock.tick(FPS) )
Clock = pygame.time.Clock()
FPS = 60
# Colors
White = (255, 255, 255)
Black = (0, 0, 0)
Green = (0, 255, 0)
Red = (255, 0, 0)
Blue = (0, 0, 255)
Orange = (255, 140, 0)
Default = White
# Sprite Lists
Bullets = pygame.sprite.Group()
Enemy_list = pygame.sprite.Group()
All = pygame.sprite.Group()
# Shorting the Class files
AI = AI.Enemy()
Ply = Player_func.Player()
# CORDS for Player
AI.rect.x, AI.rect.y = 100, 50
AI_pos = (AI.rect.x, AI.rect.y)
Ply.rect.x, Ply.rect.y = 580, 425
P_pos = (Ply.rect.x, Ply.rect.y)
# True false statements and Vars
running = True
Gun_Overload = 0
Fire = 20
while running:
Enemy_list.add(AI)
All.add(AI)
All.add(Ply)
# Collision Detection for walls on the spaceship
if Ply.rect.x <= 0:
Ply.rect.x += 5.5
elif Ply.rect.x >= 590:
Ply.rect.x -= 5.5
# Events
for event in pygame.event.get():
if event.type == QUIT:
running = False
elif event.type == KEYDOWN:
if event.key == K_SPACE and Gun_Overload == Fire:
bullet = Player_func.Bullet()
bullet.rect.x = (Ply.rect.x +15)
bullet.rect.y = Ply.rect.y
Bullets.add(bullet)
All.add(bullet)
Gun_Overload = 0
#Cool Down
if Gun_Overload < Fire:
Gun_Overload += 1
AI.movement()
Ply.Controls()
# Updates the Sprite lists so they can all be drawn
All.update()
# Checks if a bullet hits the enemy on the list
for bullet in Bullets:
Hit_list = pygame.sprite.Group()
if pygame.sprite.collide_rect(bullet, Enemy_list):
Hit_list.add(hit)
for hit in Hit_list:
Bullets.remove(bullet)
All.remove(bullet)
All.remove(hit)
Enemy_list.remove(hit)
# If the bullet goes off the screen it deletes
if bullet.rect.y < 0:
Bullets.remove(bullet)
All.remove(bullet)
Scr.blit(Background, Background_rect)
All.draw(Scr)
pygame.display.flip()
# FPS Clock Loaded in
Clock.tick(FPS)
pygame.quit()
Your If condition uses collide_rect:
pygame.sprite.collide_rect()
Collision detection between two sprites, using rects.
collide_rect(left, right) -> bool
You pass 2 parameters - a Bullet, and a SpriteGroup. The error is telling you that a SpriteGroup does not have a Rect attribute.
I think you wanted to use:
pygame.sprite.spritecollide()
Find sprites in a group that intersect another sprite.
spritecollide(sprite, group, dokill, collided = None) -> Sprite_list
Apart from this, I would change all the variable names to lowercase. I have also noticed that your if bullet.rect.y < 0: is under the collide test. I think you want to remove a Bullet from the screen even if there is no collision.
Related
I've been trying to create a short code to use for a project that can fade in and from black, but for some reason only the function that fades in is working while the fade out function is being skipped more or less. By giving them parameters I confirmed that the problem is in the second function and that the transparency isn't changing at all. Here's my code-
import pygame
screen = pygame.display.set_mode((800,600))
image = pygame.image.load_extended('Map.png').convert_alpha()
image = pygame.transform.scale(image,(530,300))
image.set_alpha(0)
x = 0
y = 255
def fade_in(x):
while True:
screen.blit(image,(0,0))
pygame.display.update()
image.set_alpha(x)
pygame.time.delay(100)
if x < 255:
x += 5
else:
pygame.time.delay(500)
x = 0
fade_out(y)
def fade_out(y):
while True:
screen.blit(image,(0,0))
pygame.display.update()
image.set_alpha(y)
pygame.time.delay(100)
if y > 0:
y -= 5
else:
pygame.time.delay(500)
y = 255
fade_in(x)
while True:
fade_in(x)
Does anyone have an idea of what the problem might be?
When you draw a transparent surface on the screen, the surface is blended with the current contents of the screen. Hence you need to clear the screen before drawing the fading background with screen.fill(0).
Do not try to control the application recursively or with loops within the application loop. Do not delay the game. delay causes the game to stop responding.
Use the application loop and use pygame.time.Clock to control the frames per second and thus the game speed.
The method tick() of a pygame.time.Clock object, delays the game in that way, that every iteration of the loop consumes the same period of time. See pygame.time.Clock.tick():
This method should be called once per frame.
That means that the loop:
clock = pygame.time.Clock()
run = True
while run:
clock.tick(60)
Example:
import pygame
pygame.init()
screen = pygame.display.set_mode((400,300))
clock = pygame.time.Clock()
try:
image = pygame.image.load_extended('Map.png').convert_alpha()
image = pygame.transform.scale(image,(530,300))
except:
image = pygame.Surface(screen.get_size())
pygame.draw.circle(image, (255, 0, 0), screen.get_rect().center, min(*screen.get_size()) // 2 - 20)
alpha = 0
alpha_change = 1
run = True
while run:
clock.tick(60)
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
alpha += alpha_change
if not 0 <= alpha <= 255:
alpha_change *= -1
alpha = max(0, min(alpha, 255))
screen.fill(0)
alpha_image = image.copy()
alpha_image.set_alpha(alpha)
screen.blit(alpha_image, (0, 0))
pygame.display.flip()
pygame.quit()
exit()
making a square move in a grid
import pygame
from pygame.locals import *
pygame.init()
clock = pygame.time.Clock()
w = 1008
h = 640
left = 16
top = 16
width = 16
height = 16
YELLOW = (255, 255, 55)
BLUE = (0, 0, 255)
BLACK = (0, 0, 0)
bg = (255, 255, 255)
x = 0
y = 0
screen = pygame.display.set_mode((w, h))
gameExit = False
while not gameExit:
for event in pygame.event.get():
if event.type == pygame.QUIT:
gameExit = True
if event.type == KEYDOWN:
if event.key == K_DOWN:
top += 16
if event.key == K_UP:
top -= 16
if event.key == K_RIGHT:
left += 16
if event.key == K_LEFT:
left -= 16
x += 16
y += 16
screen.fill(BLACK)
pygame.draw.rect(screen, [255, 255, 55], [left, top, width, height], 0)
pygame.draw.line(screen, bg, (w - 16, y), (16, y), 1)
pygame.draw.line(screen, bg, (x, h - 16), (y, 16), 1)
pygame.display.flip()
pygame.quit()
at the moment if I # out screen.fill() grid appears on the screen and the rect moves with a tail behind, if I take away the # from the screen.fill() grid disappears but rect moves correct with no tail I want both to happen.
The issue with your code is that it isn't doing what you might expect. Every time you iterate through your while loop, you increment the x and y values by 16 and draw a single horizontal and vertical line. This appears to draw a grid, because the screen is NOT cleared automatically between your while loop iterations. However, as a result, after a while, your x and y values increase to the point that you start drawing more and more grid lines that are off the screen (try to print out the start and end points for these lines in your loop if this is unclear)!
When you add the screen.fill(BLACK) call before you start drawing grid lines, you basically clear the entire screen. Since you do not redraw your old grid lines, only the next pair of grid lines are drawn and the rest are lost. Since the new pair of grid lines eventually goes off the screen (as described in the first paragraph), your code does not appear to draw any grid lines.
When you comment out screen.fill(BLACK) instead, previous drawings are not cleared. All of the grid is drawn over multiple while loop iterations (in addition to wastefully drawing new grid lines off screen), as is all of the previously positions your player is drawn at.
To solve this, your game drawing loop should be structured like this:
Clear the screen.
Draw the entire grid, not just two lines at a time. Do this in a function (e.g. draw_grid).
Draw the rectangle at the new player position. Do this in a function as well (e.g. draw_player).
Rinse and repeat next iteration!
Implementing these small changes, your code could look like this:
import pygame
from pygame.locals import *
def draw_grid():
screen.fill(BLACK)
for y in range(height, h, height):#horizontal lines
pygame.draw.line(screen, bg, (width, y), (w - width, y), 1)
for x in range(width, w, width):#vertical lines
pygame.draw.line(screen, bg, (x, height), (x, h - height), 1)
def draw_player():
pygame.draw.rect(screen, [255, 255, 55], [left, top, width, height], 0)
pygame.init()
clock = pygame.time.Clock()
w = 1008
h = 640
left = 16
top = 16
width = 16
height = 16
YELLOW = (255, 255, 55)
BLUE = (0, 0, 255)
BLACK = (0, 0, 0)
bg = (255, 255, 255)
x = 0
y = 0
screen = pygame.display.set_mode((w, h))
gameExit = False
while not gameExit:
for event in pygame.event.get():
if event.type == pygame.QUIT:
gameExit = True
if event.type == KEYDOWN:
if event.key == K_DOWN:
top += 16
if event.key == K_UP:
top -= 16
if event.key == K_RIGHT:
left += 16
if event.key == K_LEFT:
left -= 16
draw_grid()
draw_player()
pygame.display.flip()
pygame.quit()
That being said, there is plenty of room for improvement for this code, which I will leave up to you. The big issue is that you are using a bunch of global variables. These are basically all of the variables listed before your while loop. Use of such global variables is "evil" when they are mutable. As your code gets bigger, it will become more difficult to reason what functions are changing these variables, since every function could potentially have access to these variables.
I'm trying to make a animation of projection movement but it does't work.
Just a black window appear.
import math
import time
import pygame
V0 = int(input("please enter initial speed(m/s)"))
angle = int(input("please enter throwing angle"))
BLACK = (0, 0, 0)
WHITE = (255, 255, 255)
pygame.init()
screen = pygame.display.set_mode((400, 300))
done = False
clock = pygame.time.Clock()
while not done:
T = time.clock()
x = int(math.cos(angle)*V0*T)
y = int((math.sin(angle)*V0*T)-1/2*(9.8*T*T))
for event in pygame.event.get():
if event.type == pygame.QUIT:
done = True
screen.fill(BLACK)
pygame.draw.circle(screen, WHITE, (x, y), 5, 0)
pygame.display.flip()
clock.tick(10)
pygame.quit()
I think the problem is my formula statement, but I don't know how to fix it.
Read the comments. I've changed the way you calculated time and angle.
import math
import time
import pygame
V0 = int(input("please enter initial speed(m/s)"))
angle = int(input("please enter throwing angle"))
BLACK = (0, 0, 0)
WHITE = (255, 255, 255)
pygame.init()
screen = pygame.display.set_mode((400, 300))
done = False
clock = pygame.time.Clock()
T = 0 #initialize
while not done:
#T = time.clock() #don't use
x = int(math.cos(math.radians(angle))*V0*T) #use math.radians(degree). Don't just provide degrees. cos() and sin() needs input in radians
y = 300 - int((math.sin(math.radians(angle))*V0*T)-(0.5*9.8*T*T)) #looks better. projectile starts from the ground.
for event in pygame.event.get():
if event.type == pygame.QUIT:
done = True
screen.fill(BLACK)
pygame.draw.circle(screen, WHITE, (x,y), 5, 0)
milliseconds = clock.tick(60) #try this. count ms. add to s. calculate total time passed.
seconds = milliseconds / 1000.0
T += seconds
pygame.display.flip()
pygame.quit()
Ye i know this is quite noob question but problem is this.
i'm making a game and i wanna randomize stars to a huge space area
But results that i get are:
The space keeps recaculating places of stars so everything moves.
It Shows only 1 star on the upper left corner of window.
Here is the full code:
import os
import pygame
from pygame.locals import *
import random
gstars = 500
gstarmax = 0
red = (255,0,0)
yellow = (240,250,60)
timer = 0
size = [1600, 1000]
screen = pygame.display.set_mode((1600, 1000), HWSURFACE | DOUBLEBUF | RESIZABLE)
pygame.display.set_caption('planet system test')
clock = pygame.time.Clock()
area = pygame.image.load("screenMonitor.png")
done = False
while done == False:
pygame.event.pump()
mouse_x, mouse_y = pygame.mouse.get_pos()
timer += 1
if timer > 99:
timer = 0
screen.fill((0,0,0))
pygame.draw.rect(screen, red, (20, 20, 1350, 480), 2)
pygame.draw.rect(screen,yellow,(2,2,2,2),2)
go = True
if go == True:
for i in range(gstars):
s1 = random.randrange(1,1600)
s2 = random.randrange(1,1000)
colorSelect = random.randrange(0,5)
if colorSelect == 1:
yellow = (240,250,60)
if colorSelect == 2:
yellow = (249,173,60)
if colorSelect == 3:
yellow = (226,43,68)
if colorSelect == 4:
yellow = (52,173,84)
go = False
pygame.draw.rect(screen,yellow,(2+s1,2+s2,2,2),2)
pygame.display.flip()
clock.tick(30)
pygame.quit()
The trouble is in the main/event loop.
You put the code for position your stars inside the main loop. Since it is randomize at every iteration, it will move.
I remove the go = False that probably cause the error to display only one star.
In the following code, I create a list of star that have the position in indices 0 and 1, and the tuple of the color in 2.
The tuple of color is randomly choose using the random.choice(Sequence) function. https://docs.python.org/2/library/random.html
import pygame
from pygame import *
import random
gstars = 500
gstarmax = 0
red = (255,0,0)
yellow = (240,250,60)
timer = 0
size = [1600, 1000]
pygame.init()
pygame.display.set_caption('planet system test')
screen = pygame.display.set_mode((size[0], size[1]))
clock = pygame.time.Clock()
area = pygame.image.load("screenMonitor.png")
color = ((240,250,60),(249,173,60),(226,43,68),(52,173,84))
stars = []
for i in range(gstars):
s1 = random.randrange(1,1600)
s2 = random.randrange(1,1000)
starcolor = random.choice(color)
stars.append([s1, s2, starcolor])
done = False
while done == False:
for event in pygame.event.get():
if event.type == pygame.QUIT: #Quit the game if X
done = False
screen.fill(0)
pygame.draw.rect(screen, red, (20, 20, 1350, 480), 2)
pygame.draw.rect(screen,yellow,(2,2,2,2),2)
for star in stars:
pygame.draw.rect(screen,star[2],(2+star[0],2+star[1],2,2),2)
pygame.display.flip()
clock.tick(30)
EDIT : Correct the code following the advice of Ted Klein Bergman.
I am trying to make a very simple game, here is my full code:
import pygame
from pygame.locals import *
pygame.init()
#define variables
width, height = 940, 780
screen = pygame.display.set_mode((width, height))
grey = 87, 87, 87
white = 255, 255, 255
player = pygame.image.load("Pics\goodcar.jpeg")
keys = [False, False, False, False]
playerpos = [0,40]
green = 0,255,0
red = 255,0,0
color = red
x1 = 0
x2 = 40
y1 = 940
y2 = 100
#main program
while 1:
screen.fill(0)
road = pygame.draw.rect(screen, grey, (x1,x2,y1,y2), 0)
traffic_light = pygame.draw.circle(screen, white, (640,90), 40, 1)
screen.blit(player, playerpos)
car_rect = player.get_rect()
if traffic_light.colliderect(car_rect):
print("Its working")
for event in pygame.event.get():
if event.type==pygame.QUIT:
pygame.quit()
exit(0)
if event.type == pygame.KEYDOWN:
if event.key==K_RIGHT:
keys[0]=True
elif event.key==K_LEFT:
keys[1]=True
elif event.key==K_DOWN:
keys[2]=True
elif event.key==K_UP:
keys[3]=True
if event.type == pygame.KEYUP:
if event.key==pygame.K_RIGHT:
keys[0]=False
elif event.key==pygame.K_LEFT:
keys[1]=False
elif event.key==pygame.K_DOWN:
keys[2]=False
elif event.key==pygame.K_UP:
keys[3]=False
if keys[0]==True:
playerpos[0]+=3
elif keys[1]==True:
playerpos[0]-=3
elif keys[2]==True:
playerpos[1]+=3
elif keys[3]==True:
playerpos[1]-=3
pygame.display.update()
at the part where it checks if the car collided with the traffic light, it doesn't do anything.
Iv'e tried using a try statement, still doesn't work
Look at the documentation what Surface.get_rect() does:
Returns a new rectangle covering the entire surface. This rectangle will always start at 0, 0 with a width. and height the same size as the image.
So the Rects never collide, since the Rect for the car always starts at 0, 0. An easy fix is to simply set the starting position (top and left) of the car Rect while calling get_rect().
Change
car_rect = player.get_rect()
to:
car_rect = player.get_rect(left=playerpos[0], top=playerpos[1])
(Another way is to use the Sprite class, which basically combines a Surface and a Rect.)