This question already has answers here:
How to detect collisions between two rectangular objects or images in pygame
(1 answer)
How do I detect collision in pygame?
(5 answers)
Closed 2 years ago.
I am working on a game and I needed to make collision detection. I decided to use the function pygame.Rect.colliderect(). However, it is giving me the error:
pygame 2.0.0.dev6 (SDL 2.0.10, python 3.7.2)
Hello from the pygame community. https://www.pygame.org/contribute.html
Traceback (most recent call last):
File "C:/Users/admin/PycharmProjects/ProgrammingLearn/SpaceInvaders.py", line 185, in <module>
main()
File "C:/Users/admin/PycharmProjects/ProgrammingLearn/SpaceInvaders.py", line 112, in main
if pygame.Rect.colliderect(blue_enemy_rect):
TypeError: Argument must be rect style object
I will "Bookmark" the place where I have used pygame.Rect.colliderect() with #Bookmark
# importing packages
import pygame
import random
import time
import sys
# Initializing Pygame
pygame.init()
# Setting a display width and height and then creating it
display_width = 700
display_height = 500
display_size = [display_width, display_height]
game_display = pygame.display.set_mode(display_size)
intro_display = pygame.display.set_mode(display_size)
# Setting a display caption
pygame.display.set_caption("Space Bugs")
spaceship = pygame.image.load("spaceship2.png")
blue_enemy = pygame.image.load("blue_enemy.png")
green_enemy = pygame.image.load("green_enemy.png")
orange_enemy = pygame.image.load("orange_enemy.png")
pink_enemy = pygame.image.load("pink_enemy.png")
yellow_enemy = pygame.image.load("yellow_enemy.png")
# Creating a font
pygame.font.init()
font = pygame.font.SysFont("consolas", 30)
large_font = pygame.font.SysFont("consolas", 60)
small_font = pygame.font.SysFont("consolas", 20)
# Creating a way to add text to the screen
def message(sentence, color, x, y, font_type, display):
sentence = font_type.render(str.encode(sentence), True, color)
display.blit(sentence, [x, y])
def main():
global white
global black
global clock
# Spaceship coordinates
spaceship_x = 300
spaceship_y = 375
spaceship_x_change = 0
blue_enemy_health = 5
green_enemy_health = 5
orange_enemy_health = 5
pink_enemy_health = 5
yellow_enemy_health = 5
blue_enemy_rect = pygame.Rect(30, 35, 80, 70)
# Initializing pygame
pygame.init()
# Creating colors
red = (255, 0, 0)
blue = (0, 0, 255)
# clock stuff
clock = pygame.time.Clock()
time_elapsed_since_last_action = 0
time_elapsed_since_last_action2 = 0
# Creating a loop to keep the program running
while True:
# --- Event Processing and controls
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
sys.exit()
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_RIGHT:
spaceship_x_change = 10
elif event.key == pygame.K_LEFT:
spaceship_x_change = -10
elif event.type == pygame.KEYUP:
spaceship_x_change = 0
spaceship_x += spaceship_x_change
# Preventing the ship from going off the screen
if spaceship_x > display_width - 140:
spaceship_x -= 10
if spaceship_x < 1:
spaceship_x += 10
laser_coords = [70, 209, 348, 505, 630]
random_x_coord = random.choice(laser_coords)
dt = clock.tick()
time_elapsed_since_last_action += dt
if time_elapsed_since_last_action > 500:
pygame.draw.rect(game_display, blue, [random_x_coord, 85, 6, 305])
time_elapsed_since_last_action = 0
time_elapsed_since_last_action2 += dt
# Setting Display color
game_display.fill(black)
message(str(blue_enemy_health), white, 65, 10, font, game_display)
game_display.blit(blue_enemy, (20, 25))
blue_hit_box = pygame.draw.rect(game_display, white, blue_enemy_rect, 1)
# Bookmark
if pygame.Rect.colliderect(blue_enemy_rect):
blue_enemy_health = blue_enemy_health - 1
message(str(green_enemy_health), white, 203, 10, font, game_display)
game_display.blit(green_enemy, (160, 25))
green_hit_box = pygame.draw.rect(game_display, white, [180, 35, 60, 70], 1)
message(str(orange_enemy_health), white, 341, 10, font, game_display)
game_display.blit(orange_enemy, (300, 25))
orange_hit_box = pygame.draw.rect(game_display, white, [315, 43, 65, 70], 1)
message(str(pink_enemy_health), white, 496, 10, font, game_display)
game_display.blit(pink_enemy, (440, 25))
pink_hit_box = pygame.draw.rect(game_display, white, [460, 35, 90, 70], 1)
message(str(yellow_enemy_health), white, 623, 10, font, game_display)
game_display.blit(yellow_enemy, (580, 25))
yellow_hit_box = pygame.draw.rect(game_display, white, [590, 40, 85, 70], 1)
# Creating a spaceship, lasers, and enemies
laser = pygame.draw.rect(game_display, red, [spaceship_x + 69, 100, 4, 300])
game_display.blit(spaceship, (spaceship_x, spaceship_y))
health = 10
message("Spaceship durability: " + str(health), white, 20, 480, small_font, game_display)
# Updating Screen so changes take places
pygame.display.flip()
# Setting FPS
FPS = pygame.time.Clock()
FPS.tick(60)
# Executing the function
if __name__ == "__main__":
main()
I don't see what is wrong here, as I believe this is how colliderect is used.
I am really close to finishing this program, and any help is appreciated. Thanks.
colliderect is an instance method (see Method Objects). The method tests whether 2 rectangles overlap. It needs to be called with 2 rectangles.
Either
if pygame.Rect.colliderect(rect1, rect2):
# [...]
or
if rect1.colliderect(rect2):
# [...]
This means that you can do the following:
blue_enemy_rect = pygame.Rect(30, 35, 80, 70)
green_enemy_rect = pygame.Rect(180, 35, 60, 70])
# [...]
while True:
# [...]
if green_enemy_rect.colliderect(blue_enemy_rect):
blue_enemy_health = blue_enemy_health - 1
Related
I'm making a pygame game.When I click on the tanks button and then click on the screen(play area) a tank is blitted on that coordinate. Along with the tank a bullet is also blitted. I'm able to make my tank move but the bullets are not shooting. I want the tanks to keep shooting automatically after the bullet gets reset after travelling, say 40 pixels.
This is the function that gives the tanks and the bullets the coordinates
tank_pos_list = []
bullet_list = []
def spawn_tank():
global tank_pos_list
global bullet_list
qx, qy = pygame.mouse.get_pos()
tankxy = [(qx - 35), (qy - 35)]
tank_pos_list.append(tankxy)
bullet_list.append(tankxy)
This is my movement class for tanks and bullets.
class MovementClass:
global bullet_list
global tank_pos_list
tank_surf = pygame.image.load("tank.png")
bullet = pygame.image.load("bullet.png")
def movetank(self, tankimg):
for tank_pos in tank_pos_list:
screen.blit(tankimg, (tank_pos[0], tank_pos[1]))
tank_pos[0] += 0.2
def movebullet(self, bulletimg):
for j in range(len(bullet_list)):
newx = (bullet_list[j][0] + 35)
screen.blit(bulletimg, (newx, (bullet_list[j][1] + 34)))
newx += 1
This is my main function
def main():
global new_tanks
global spawner
global tank_pos_list
global fire_bullet_tank
run = True
fps = 90
tanks = Button((59, 255, 140), 100, 610, 80, 80, text="Tanks")
tanks_over = Button((0, 255, 0), 100, 610, 80, 80, text="Tanks")
towers = Button((59, 255, 140), 510, 610, 150, 80, text="Towers")
towers_over = Button((0, 255, 0), 510, 610, 150, 80, text="Towers")
blue = pygame.image.load("blue_base.png")
red = pygame.image.load("red_base.png")
spawner = False
while run:
mx, my = pygame.mouse.get_pos()
pos = (mx, my)
x = pos[0]
y = pos[1]
mouse_pos = (mx, my)
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
quit()
if event.type == pygame.MOUSEBUTTONDOWN:
if spawner and my < 550 and mx < 500:
spawn_tank()
spawner = False
if tanks.isOver(mouse_pos):
spawner = True
screen.fill((50, 168, 66))
if len(tank_pos_list) >= 11:
tank_pos_list.pop(-1)
pygame.draw.rect(screen, (201, 142, 47), (0, 600, 1000, 100))
pygame.draw.line(screen, (0, 0, 0), (500, 0), (500, 600))
if tanks.isOver(mouse_pos):
tanks_over.draw(screen)
else:
tanks.draw(screen)
if towers.isOver(mouse_pos):
towers_over.draw(screen)
else:
towers.draw(screen)
screen.blit(blue, (0, 100))
screen.blit(red, (800, 100))
#movement()
movingtank = MovementClass()
movingtank.movetank(pygame.image.load("tank.png"))
movingbullet = MovementClass()
movingbullet.movebullet(pygame.image.load("bullet.png"))
pygame.display.flip()
clock.tick(fps)
When you run
for tank_pos in tank_pos_list:
...
tank_pos[0] += 0.2
you're changing the first value in a list inside the tank_pos_list list. Note that you add tankxy to both lists in spawn_tank so you can see the change in tank_pos_list and bullet_list. It's the same list in both lists you're changing here.
But when you run
for j in range(len(bullet_list)):
newx = (bullet_list[j][0] + 35)
...
newx += 1
you just create a new variable newx and change its value; but you never change any values of the lists in bullet_list.
Some more notes:
The MovementClass has no internal state; it's basically useless that you create 2 new instances every frame. Use global functions instead (without a class) or just inline those functions.
You load "tank.png" and "bullet.png" every frame from disk. You should just load the images once outside your main loop. Otherwise, it becomes a major performance killer soon.
Try to create a class or multiple classes that represents the different actors of your game (pygame offers the Sprite class for this) and implement the behaviour and state in that class. While that's not the most advanced technique it is the right way to go IMHO for small games.
For an example, maybe take a look at this answer I did for another questions, which is pretty much a step-by-step guide on how I would create such a game.
I'm wondering how to speed up the smoothness of my code written in Python using pygam. I'm guessing I have to make this more efficient somehow? When this is run, some balls move around randomly in a set area, however, the new position of each ball is not smooth at all, there is a jump between each movement as the cycle is very slow. How do I fix this? Or is there any suggestions on how to improve it?
This is my code so far:
import pygame
from pygame import *
import random
pygame.init()
size = width, height = 800, 600
screen = display.set_mode(size)
pygame.display.set_caption("Year 12: Ideal Gas Simulation")
BLACK = (0, 0, 0)
RED = (255, 0, 0)
BLUE = (0, 0, 255)
WHITE=(255,255,255)
GREEN = (0, 255, 0)
BALLX = 0
BALLY = 1
BALLSPEEDX = 2
BALLSPEEDY = 3
List=[]
radius=5
running=True
myClock=time.Clock()
myClock.tick(60)
def initBall():
for n in range(40):
ballx = random.randint(0, 800) # randomly setting the x position
bally = random.randint(0, 600) # randomly setting the y position
dirx = random.randint(-5,5) # randomly setting the x speed
diry = random.randint(-5,5) # randomly setting the y speed
data=[ballx, bally, dirx, diry]
List.append(data)
# returning a list with all the data the ball needs
return List # returning the list
def drawScreen(List):
draw.rect(screen, WHITE, (0, 0, 800, 600))
for x in range(40):
BALLX=List[x][0]
BALLY=List[x][1]
draw.circle(screen, GREEN, (BALLX,BALLY),radius)
display.flip()
pygame.draw.rect(screen, BLACK, (100-radius,100-radius,600+(2*radius),400+(2*radius)), 1)
f=pygame.font.SysFont(None,60)
text=f.render("PV=nRT",True,(0,0,0))
screen.blit(text,(300,height/20))
def moveBall(List):
for x in range(40):
BALLX=List[x][0]
BALLY=List[x][1]
SPEEDX=List[x][2]#####data[BALLX]== the first index of each list [x][0]
SPEEDY=List[x][3]##data[BALLSPEEDX]= List[x][2]
age=SPEEDX+BALLX
List[x][0]=age
# increases the position of the ball
plus=SPEEDY+BALLY
List[x][1]=plus
# checks to see if the ball is hitting the walls in the x direction
if BALLX > 700:
List[x][0] = 700#NORMALLY 800
third=List[x][2]
answer=third*-1
List[x][2]=answer
elif BALLX < 100:#NORMALLY 0
List[x][0] = 100
third=List[x][2]
answer=third*-1
List[x][2]=answer
# checks to see if the ball is hitting the walls in the y direction
if BALLY < 100:
List[x][1] = 100#NORMALLY 0
third=List[x][3]
answer=third*-1
List[x][3]=answer
elif BALLY > 500:
List[x][1] = 500#NORMALLY 600
third=List[x][3]
answer=third*-1
List[x][3]=answer
return List#return updated list
List=initBall()
while running==True:
for evnt in event.get():
if evnt.type==QUIT:
running=False
quit()
if evnt.type==MOUSEBUTTONDOWN:
mx,my=evnt.pos
button=evnt.button
drawScreen(List)
List=moveBall(List)
In addition to skrx's answer, you can also refactor the code and avoid a lot of duplicate calls. Also, indexing the BALLS array directly might improve performance slightly.
Generally, avoid naming variables inside functions with uppercase. These names are typically given to constants defined at the top of your file.
The version I came up with is below:
import array
import pygame
pygame.init()
import random
from pygame import *
size = WIDTH, HEIGHT = 800, 600
screen = display.set_mode(size)
pygame.display.set_caption("Year 12: Ideal Gas Simulation")
BLACK = (0, 0, 0)
RED = (255, 0, 0)
BLUE = (0, 0, 255)
WHITE = (255,255,255)
GREEN = (0, 255, 0)
BALLX = 0
BALLY = 1
BALLSPEEDX = 2
BALLSPEEDY = 3
RADIUS = 5
BALLS = []
myClock = time.Clock()
myClock.tick(60)
def initBalls():
for n in range(40):
props = array.array('i', [
random.randint(0, WIDTH),
random.randint(0, HEIGHT),
random.randint(-5, 5),
random.randint(-5, 5),
])
BALLS.append(props)
def drawScreen():
draw.rect(screen, WHITE, (0, 0, 800, 600))
props = (100-RADIUS, 100-RADIUS, 600+(2*RADIUS), 400+(2*RADIUS))
pygame.draw.rect(screen, BLACK, props, 1)
f = pygame.font.SysFont(None, 60)
text = f.render("PV=nRT", True,(0, 0, 0))
screen.blit(text,(300, HEIGHT / 20))
for i in range(len(BALLS)):
draw.circle(screen, GREEN, BALLS[i][:2],RADIUS)
display.flip()
def moveBalls():
for i in range(len(BALLS)):
if BALLS[i][0] > 700:
BALLS[i][0] = 700
BALLS[i][2] *= -1
elif BALLS[i][0] < 100:
BALLS[i][0] = 100
BALLS[i][2] *= -1
else:
BALLS[i][0] += BALLS[i][2]
if BALLS[i][1] < 100:
BALLS[i][1] = 100
BALLS[i][3] *= -1
elif BALLS[i][1] > 500:
BALLS[i][1] = 500
BALLS[i][3] *= -1
else:
BALLS[i][1] += BALLS[i][3]
def main():
initBalls()
while True:
for evnt in event.get():
if evnt.type == QUIT:
pygame.quit()
return
elif evnt.type == MOUSEBUTTONDOWN:
mx, my = evnt.pos
button = evnt.button
drawScreen()
moveBalls()
if __name__ == "__main__":
main()
Call pygame.display.flip() only once per frame.
def drawScreen(List):
draw.rect(screen, WHITE, (0, 0, 800, 600))
for x in range(40):
BALLX=List[x][0]
BALLY=List[x][1]
draw.circle(screen, GREEN, (BALLX,BALLY),radius)
# display.flip() # Don't call `display.flip()` here.
pygame.draw.rect(screen, BLACK, (100-radius,100-radius,600+(2*radius),400+(2*radius)), 1)
screen.blit(text,(300,height/20))
pygame.display.flip() # Call it here.
I also recommend to use a pygame.time.Clock to limit the frame rate.
# Define the font object as a global constant.
FONT = pygame.font.SysFont(None, 60)
# If the text doesn't change you can also define it here.
TEXT = FONT.render("PV=nRT", True, (0,0,0))
# Instantiate a clock to limit the frame rate.
clock = pygame.time.Clock()
running = True
while running: # `== True` is not needed.
for evnt in event.get():
if evnt.type == QUIT:
running = False
# Better use `pygame.quit` and `sys.exit` to quit.
pygame.quit()
sys.exit()
drawScreen(List)
List = moveBall(List)
clock.tick(30) # Limit frame rate to 30 fps.
I'm trying to find out if a user has clicked on a .rect(). I've read a bunch of tutorials, but I'm still running into problems. I have two files: One that is the main python file, and one that defines the .rect().
#main.py
import pygame,os,TextBox
from pygame.locals import *
pygame.init()
myTextBox = TextBox.TextBox()
WHITE = (255, 255, 255)
size = (400, 200)
screen = pygame.display.set_mode(size)
done = False
boxes = [myTextBox]
while not done:
for event in pygame.event.get(): # User did something
if event.type == pygame.QUIT: # If user clicked close
done = True
elif event.type == MOUSEMOTION: x,y = event.pos
for box in boxes:
if myTextBox.rect.collidepoint(x,y): print ('yay')
screen.fill(WHITE)
myTextBox.display(screen, 150, 150, 20, 100)
pygame.display.flip()
pygame.quit()
#TextBox.py
import pygame
from pygame.locals import *
class TextBox:
def __init__(self):
self.position_x = 100
self.position_y = 100
self.size_height = 10
self.size_width = 50
self.outline_color = ( 0, 0, 0)
self.inner_color = (255, 255, 255)
def display(self, screen, x, y, height, width):
self.position_x = x
self.position_y = y
self.size_height = height
self.size_width = width
pygame.draw.rect(screen, self.outline_color, Rect((self.position_x - 1, self.position_y - 1, self.size_width + 2, self.size_height + 2)))
pygame.draw.rect(screen, self.inner_color, Rect((self.position_x, self.position_y, self.size_width, self.size_height)))
The error I get is AttributeError: 'TextBox' object has no attribute 'rect'
How do I solve this?
You're TextBox class doesn't have a rect. Add this somewhere at the bottom of the __init__ method of the TextBox class:
self.rect = pygame.Rect(self.position_x,self.position_y,self.size_width,self.size_height)
Do the same in the update method.
This question already exists:
Need Help Creating A Stop Light Event In Pygame (Python 3) [closed]
Closed 9 years ago.
I'm trying to create the last example in lab # 8 for the Program Arcade Games Book.
The last thing I'm trying to implement is a stoplight that changes colors based on three events and timers.
I understand that I have to use pygame.time.set_timer() at one point, but I haven't been exposed to event handling in Pygame yet. I don't know how I should go about making three separate events that would turn each corresponding traffic light its bright color.
This is what I have so far, and if you omit the line 258 to 266, the animation works using Pygame and Python 3 (I tried concatenating the "events" but its just not working obviously).
Here's a revised version where I tried to use timers to literally just change the color instead of making separate events but its not working in this case either ;(
import random
import math
# Requirements:
# Modify the prior Create-a-Picture lab, or start a new one.
# Animate the image. Try one or more of the following:
# Move an item across the screen.
# Move an item back and forth.
# Move up/down/diagonally.
# Move in circles.
# Have a person wave his/her arms.
# Create a stoplight that changes colors.
# import statement
import pygame
# Define colors:
BLACK = (0, 0, 0)
WHITE = (255, 255, 255)
RED = (255, 0, 0)
DULLRED = (153, 50, 51)
GREEN = (0, 255, 0)
DULLGREEN = (55, 154, 54)
BLUE = (0, 0, 255)
LIGHTBLUE = (103, 255, 246)
YELLOW = (252, 255, 31)
DULLYELLOW = (156, 157, 50)
# initialize pygame:
pygame.init()
# screen:
size = (700, 500)
screen = pygame.display.set_mode(size)
# Set the caption:
pygame.display.set_caption("Chapter 8 Lab")
# Clock:
clock = pygame.time.Clock()
# FPS:
FPS = 60
# boolean variable for game:
done = False
# For loop for white circles:
whiteCircleList = []
for i in range(25):
x = random.randrange(0, 700)
y = random.randrange(0, 50)
whiteCircleList.append([x,y])
# For Loop for Blue Circles:
blueCircleList = []
for i in range(100):
circleX = random.randrange(0, 500)
circleY = random.randrange(0, 700)
blueCircleList.append([circleX, circleY])
# Light Blue Circle For Loop:
lightBlueCircleList = []
for i in range(100):
circleX = random.randrange(0, 500)
circleY = random.randrange(0, 700)
lightBlueCircleList.append([circleX, circleY])
# Surfboard's Rectangle (x-pos, y-pos, x-length, y-length):
surfboardRect = pygame.Rect(325, 225, 50, 150)
boardY = 255.
rectYChange = -5
phase = 0
# Diagonal Rectangle in Top Left Corner:
topLeftDiagonalRect = pygame.Rect(0, 0, 10, 10)
# Diagonal Rectangle in Top Right Corner:
topRightDiagonalRect = pygame.Rect(500, 1, 10, 10)
# Diagonal Rectangle Vectors for Top Left Rectangle:
topLeftDiagonalRectXChange = 5
topLeftDiagonalRectYChange = 5
# Diagonal Rectangle Vectors for Top Right Rectangle:
topRightDiagonalRectXChange = -5
topRightDiagonalRectYChange = -5
# Angle for Hand Rotation
handAngle = 0
# Variable for Traffic Light Cover:
currentTopColor = DULLRED
currentMiddleColor = DULLYELLOW
currentBottomColor = GREEN
while not done:
for event in pygame.event.get():
if event.type == pygame.QUIT:
done = True
# Game Logic:
phase += 1
if phase > 180:
phase = phase * -1
# Save exact position as a float to avoid floating point errors:
boardY += math.cos(math.radians(phase))*2
surfboardRect.y = int(boardY)
# Clear the screen:
screen.fill(RED)
# Drawing Code:
# Falling Down circles:
for i in range(len(whiteCircleList)):
pygame.draw.circle(screen, WHITE, [whiteCircleList[i][0], whiteCircleList[i][1]], 3)
whiteCircleList[i][1] += 5
# If the rectangles have hit the bottom of the screen, make them appear 10 pixels above the top:
if whiteCircleList[i][1] > 450:
x = random.randrange(0, 700)
whiteCircleList[i][0] = x
y = random.randrange(-50, -10)
whiteCircleList[i][1] = y
# Red Falling Up Circles:
for i in range(len(blueCircleList)):
pygame.draw.circle(screen, BLUE, [blueCircleList[i][0], blueCircleList[i][1]], 5, 5)
blueCircleList[i][1] -= 5
if blueCircleList[i][1] < 50:
circleX = random.randrange(0,700)
circleY = random.randrange(400, 500)
blueCircleList[i][0] = circleX
blueCircleList[i][1] = circleY
# Light Blue Falling Up Circles:
for i in range(len(lightBlueCircleList)):
pygame.draw.circle(screen, LIGHTBLUE, [lightBlueCircleList[i][0], lightBlueCircleList[i][1]], 3, 3)
lightBlueCircleList[i][1] -= 5
if lightBlueCircleList[i][1] < 50:
circleX = random.randrange(0, 700)
circleY = random.randrange(400, 450)
lightBlueCircleList[i][0] = circleX
lightBlueCircleList[i][1] = circleY
# Revised Surfboard Rectangle Code:
pygame.draw.rect(screen, BLACK, surfboardRect, 0)
# Top Left Diagonal Rectangle Code:
pygame.draw.rect(screen, BLACK, topLeftDiagonalRect, 0)
# Add The Top Left Diagonal Rectangle Change Vectors
topLeftDiagonalRect.x += topLeftDiagonalRectXChange
topLeftDiagonalRect.y += topLeftDiagonalRectYChange
# Top and Bottom Screen Collision:
if topLeftDiagonalRect.y >= 500 or topLeftDiagonalRect.y <= 0:
topLeftDiagonalRectYChange = topLeftDiagonalRectYChange * -1
# Left and Right Screen Collision:
if topLeftDiagonalRect.x <= 0 or topLeftDiagonalRect.x >= 700:
topLeftDiagonalRectXChange = topLeftDiagonalRectXChange * -1
# Draw the top right rectangle:
pygame.draw.rect(screen, BLACK, topRightDiagonalRect, 0)
# Add the change vectors for the Top Right Rectangle:
topRightDiagonalRect.x += topRightDiagonalRectXChange
topRightDiagonalRect.y += topRightDiagonalRectYChange
# Top and Bottom Screen Collision:
if topRightDiagonalRect.y <= 0 or topRightDiagonalRect.y >= 500:
topRightDiagonalRectYChange = topRightDiagonalRectYChange * -1
# Left and Right Screen Collision:
if topRightDiagonalRect.x <= 0 or topRightDiagonalRect.x >= 700:
topRightDiagonalRectXChange = topRightDiagonalRectXChange * -1
# Person Waving His Arms:
# Head:
pygame.draw.circle(screen, WHITE, [575, 300], 15)
# Body:
pygame.draw.rect(screen, BLUE, [560, 315, 30, 60], 0)
# Left Rotating Hand:
# Left Hand's Original Dimensions:
# pygame.draw.line(screen, WHITE, [560, 315], [540, 295], 5)
# Original Hand's x position based on the rotating circle idea:
# handX = 40 * math.sin(handAngle) + 560
# Original Hand's y position based on the rotating circle idea:
# handY = 40 * math.cos(handAngle) + 315
handPosition = (40 * math.sin(handAngle) + 560, 40 * math.cos(handAngle) + 315)
pygame.draw.line(screen, WHITE, [560, 315], handPosition, 4)
# Increase the hand angle by 0.05 Radians:
handAngle = handAngle + 0.05
# Reset the angle after a full sweep:
pi = 3.141592653
if handAngle > 2 * pi:
handAngle = handAngle - 2*pi
# Right Immobile Hand:
pygame.draw.line(screen, WHITE, [590, 315], [590, 340], 4)
# Left Leg:
pygame.draw.rect(screen, WHITE, [560, 375, 10, 20], 0)
# Right Leg:
pygame.draw.rect(screen, WHITE, [580, 375, 10, 20], 0)
# Left Shoe Ellipse
# Ellipse Notes: ellipse(Surface, color, Rect, width=0) -> Rect
pygame.draw.ellipse(screen, BLACK, [550, 390, 20, 15], 0)
# Right Shoe Ellipse:
pygame.draw.ellipse(screen, BLACK, [580, 390, 20, 15], 0)
# Add in a changing traffic light
# Rectangle for Traffic Light:
pygame.draw.rect(screen, WHITE, [50, 350, 50, 100], 0)
# Traffic Light Post:
pygame.draw.rect(screen,BLACK, [65, 450, 20, 40], 0)
# Top light:
pygame.draw.circle(screen, currentTopColor, [75, 370], 12)
# Second light:
pygame.draw.circle(screen, currentMiddleColor, [75, 400], 12)
# Third light:
pygame.draw.circle(screen, currentBottomColor, [75, 430], 12)
# Three events must be cycled to change each of the traffic light colors
# from their dull versions to their fullest color forms
# The question is, can this be achieved through a timer?
# 60 frames per second is on the timer itself so every 180 frames would mean
# 3 seconds, or every 300 frames would mean 5 seconds
# DOCS on set timer: set_timer(eventid, milliseconds)
## turnRedLightOn = pygame.draw.circle(screen, RED, [75, 370], 12)
## + pygame.draw.circle(screen, DULLYELLOW, [75, 400], 12)
## + pygame.draw.circle(screen, DULLGREEN, [75, 430], 12)
# Turn the top light red and all other lights dull every three seconds
pygame.time.set_timer(currentTopColor = RED, 3000)
pygame.time.set_timer(currentMiddleColor = DULLYELLOW, 3000)
pygame.time.set_timer(currentBottomColor = DULLGREEN, 3000)
# Turn the middle light yellow and all other lights dull every six seconds
pygame.time.set_timer(currentTopColor = DULLRED, 6000)
pygame.time.set_timer(currentMiddleColor = YELLOW, 6000)
pygame.time.set_timer(currentBottomColor = DULLGREEN, 6000)
# Turn the bottom light green and all other lights dull every nine seconds
pygame.time.set_timer(currentTopColor = DULLRED, 9000)
pygame.time.set_timer(currentMiddleColor = DULLYELLOW, 9000)
pygame.time.set_timer(currentBottomColor = GREEN, 9000)
# Update the screen:
pygame.display.flip()
# Clock FPS:
clock.tick(FPS)
# Quit after main game loop ends:
pygame.quit()
The set_timer shouldn't execute in every cycle of the main loop, you can call it outside and it will repeat itself every 3000ms.
# Current Light
light_on = 0 # 0-red 1-yellow 2-green
LIGHTS_EVENT = pygame.USERVENT + 0 # Event code for Lights change
pygame.time.set_timer(LIGHTS_EVENT, 3000)
while not done:
for event in pygame.event.get():
if event.type == pygame.QUIT:
done = True
if event.type == LIGHTS_EVENT:
light_on += 1
if light_on == 3:
light_on = 0
currentTopColor = DULLRED
currentMiddleColor = DULLYELLOW
currentBottomColor = DULLGREEN
if light_on == 0:
currentTopColor = RED
if light_on == 1:
currentMiddleColor = YELLOW
if light_on == 2:
currentBottomColor = GREEN
# Top light:
...
So like I said before my code (Or my current project that I am working on) is riddled with errors. So far I have at least solved a dozen errors or more and honestly I just give up. I mean God knows how many more there are.
The current problem that I am having is an AttributeError which is in my opinion one of the easiest errors to fix however I seem to have gone in to complete spaghetti mode and I have no clue on how to fix the problem.
{The error itself:
Traceback (most recent call last):
File "C:\Users\Burak\Desktop\boxtrial.py", line 87, in <module>
myScreen.addPane("1")
File "C:\Users\Burak\Desktop\boxtrial.py", line 67, in addPane
myPane.drawPane()
File "C:\Users\Burak\Desktop\boxtrial.py", line 19, in drawPane
self.Screen.blit(self.font.render(textToDisplay, True, (black)), (250, 115))
AttributeError: 'Pane' object has no attribute 'Screen'
}
I will list the code below but I feel as if I should explain what I am trying to do so you have some sort of understanding of the code.
Basically in the main loop I call upon the "Class Screen" which helps to create a PyGame screen that comes up once run. On that screen I am trying to get rectangles to appear on the screen in fixed positions (The coordinates are specific but the ones I use on the code are just for test purposes). I then have another class that is called "Pane" and this class is there so that I can draw many instances of the class pane within screen (If that makes sense).
If someone can help me get rid of the error that would be of grate help, but if you think that this is not a good way of solving the problem then please be my guest to come up with or teach me of a better way to do the same thing.
{The code:
import pygame
import sys
from pygame.locals import *
white = (255,255,255)
black = (0,0,0)
objs = []
MAIN_BUTTON = 1
class Pane():
def __init__(self, textToDisplay, coordinates, screen):
self.textToDisplay = textToDisplay
self.coordinates = coordinates
self.screen = screen
def drawPane(self):
self.Screen.blit(self.font.render(textToDisplay, True, (black)), (250, 115))
pygame.draw.rect(self.screen, (black), self.coordinates, 2)
pygame.display.update()
class Screen():
#constants/array(?) outlining the x,y boundaries of each of x10 panes
#Note to self - Remember to change co-ordinate values
NoOfPanes = 0
Panes = []
def __init__(self):
pygame.init()
pygame.display.set_caption('Box Test')
self.font = pygame.font.SysFont('Arial', 25)
Screen = pygame.display.set_mode((1000,600), 0, 32)
self.screen = Screen
self.screen.fill((white))
pygame.display.update()
def addPane(self, textToDisplay):
paneLocs = [(175, 75, 200, 100),
(0, 0, 200, 100),
(600, 400, 200, 100),
(175, 75, 200, 100),
(175, 75, 200, 100),
(175, 75, 200, 100),
(175, 75, 200, 100),
(175, 75, 200, 100),
(175, 75, 200, 100),
(175, 75, 200, 100)
]
if self.NoOfPanes > 10:
print("Limit Reached")
else:
myPane = Pane(textToDisplay, paneLocs[self.NoOfPanes], Screen)
myPane.drawPane()
self.NoOfPanes = self.NoOfPanes + 1
pygame.display.update()
def mousePosition(self):
global clickPos
global releasePos
for event in pygame.event.get():
if event.type == MAIN_BUTTON:
self.Pos = pygame.mouse.get_pos()
return MAIN_BUTTON
else:
return False
if __name__ == '__main__':
myScreen = Screen()
myScreen.addPane("1")
myScreen.addPane("2")
myScreen.addPane("3")
myScreen.addPane("4")
while True:
ev = pygame.event.get()
for event in ev:
if event.type == pygame.MOUSEBUTTONUP:
posx,posy = pygame.mouse.get_pos()
if (posx >= 175 and posx <= 375) and (posy >= 75 and posy <= 175):
print("BOB") #Bob was there just for test purposes
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit(); sys.exit();
Fix your case.
class Pane():
def __init__(self, textToDisplay, coordinates, screen):
...
self.screen = screen
def drawPane(self):
self.Screen.... # <<< HERE