I need help with my programming assignment. I need to make it so the blocks in the game bounce off of each other when the collide. The code below uses Pygame. I've been trying to do this for a couple hours now and keep running into walls.
import pygame
from pygame.locals import *
import time
class Block:
def __init__(self,win,left,top,
width,height,color,velocity):
self.win = win
self.rect = pygame.Rect(left,top,
width,height)
self.color = color
self.velocity = velocity
def move(self):
self.rect = self.rect.move(
self.velocity[0],self.velocity[1])
if ((self.rect.top < 0) or
(self.rect.bottom > self.win.height)):
self.velocity[1] = -self.velocity[1]
if ((self.rect.left < 0) or
(self.rect.right > self.win.width)):
self.velocity[0] = -self.velocity[0]
def tupleRep(block):
return ((block.rect.left, block.rect.top),(block.rect.right, block.rect.bottom))
colliderect()
def draw(self):
pygame.draw.rect(self.win.surface,
self.color, self.rect,0)
class BlockWindow:
def __init__(self,width,height,caption):
self.surface = pygame.display.set_mode((width,height))
self.caption = caption
pygame.display.set_caption(self.caption)
self.height = height
self.width = width
self.blocks = [ ]
self.blocks.append(Block(self,300,80,50,
100,RED,[BASESPEED,-BASESPEED]))
self.blocks.append(Block(self,200,200,20,
20,GREEN,[-BASESPEED,-BASESPEED]))
self.blocks.append(Block(self,100,150,60,
60,BLUE,[-BASESPEED,BASESPEED]))
self.blocks.append(Block(self,100,100,70,
200,PURPLE,[BASESPEED,BASESPEED]))
self.blocks.append(Block(self,300,70,50,
60,TEAL,[-BASESPEED,BASESPEED]))
Quit = False
while not Quit:
self.surface.fill(BLACK)
for b in self.blocks:
b.move()
b.draw()
pygame.display.update()
time.sleep(0.02) #import what for this?
for event in pygame.event.get():
if event.type == QUIT:
Quit = True
# set up the colors
BLACK = (0, 0, 0)
RED = (255, 0, 0)
GREEN = (0, 255, 0)
BLUE = (0, 0, 255)
PURPLE= (200,0,200)
TEAL = (0,200,200)
BASESPEED = 2
# set up pygame
pygame.init()
win = BlockWindow(800,800,'Animation with Objects')
pygame.quit()
Here is the most I can help you without preventing you from learning anything:
http://www.pygame.org/docs/ref/sprite.html
http://www.pygame.org/docs/ref/sprite.html#pygame.sprite.spritecollide
http://www.pygame.org/docs/ref/sprite.html#pygame.sprite.collide_rect
http://www.pygame.org/docs/ref/sprite.html#pygame.sprite.collide_circle
Also try the book "Hello World!" by Carter and Warren Sande.
Related
This question already has answers here:
How do I detect collision in pygame?
(5 answers)
Closed 1 year ago.
My problem: I am trying to create a vertical ball drop game, and I am testing for collision, which does work. But how would I reset my ball when it hits the hoop? Instead of it detecting and then hitting the bottom of the screen which results in a Game over screen because you lose. Any help is appreciated.
import time, random
from pygame.locals import *
import pygame, sys
pygame.init()
FPS = 60
FramePerSec = pygame.time.Clock()
BLUE = (0, 0, 255)
RED = (255, 0, 0)
GREEN = (0, 255, 0)
BLACK = (0, 0, 0)
WHITE = (255, 255, 255)
SCREEN_WIDTH = 400
SCREEN_HEIGHT = 600
SCREEN_BOTTOM = 0
SPEED = 5
SCORE = 0
font = pygame.font.SysFont("Verdana", 60)
font_small = pygame.font.SysFont("Verdana", 20)
game_over = font.render("Game Over", True, BLACK)
background = pygame.image.load("background.jpg")
DISPLAYSURF = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT))
DISPLAYSURF.fill(WHITE)
pygame.display.set_caption("Ball Drop")
class Ball(pygame.sprite.Sprite):
def __init__(self):
super().__init__()
self.image = pygame.image.load("Ball.png")
self.rect = self.image.get_rect()
self.rect.center = (random.randint(40, SCREEN_WIDTH - 40), 0)
def move(self):
global SCORE
self.rect.move_ip(0, SPEED)
if (self.rect.bottom > 600):
self.rect.top = 0
self.rect.center = (random.randint(30, 380), 0)
# Need to check PNG for hit detection
class Basket(pygame.sprite.Sprite):
def __init__(self):
super().__init__()
self.image = pygame.image.load("Basket.png")
self.rect = self.image.get_rect()
self.rect.center = (160, 520)
def move(self):
pressed_keys = pygame.key.get_pressed()
if(self.rect.x >= (SCREEN_WIDTH - 145)):
self.rect.x -= 5;
elif(self.rect.x <= -5):
self.rect.x += 5;
else:
if pressed_keys[pygame.K_a]:
self.rect.move_ip(-SPEED, 0)
if pressed_keys[pygame.K_d]:
self.rect.move_ip(SPEED, 0)
class Wall(pygame.sprite.Sprite):
def __init__(self):
super().__init__()
self.image = pygame.image.load("wall.png")
self.rect = self.image.get_rect()
self.rect.center = (0, 670)
B2 = Basket()
B1 = Ball()
W1 = Wall()
balls = pygame.sprite.Group()
balls.add(B1)
# Need to fix wall sprite group
walls = pygame.sprite.Group()
walls.add(W1)
all_sprites = pygame.sprite.Group()
all_sprites.add(B2)
all_sprites.add(B1)
INC_SPEED = pygame.USEREVENT + 1
pygame.time.set_timer(INC_SPEED, 1000)
while True:
for event in pygame.event.get():
if event.type == INC_SPEED:
SPEED += 0.3
if event.type == QUIT:
pygame.quit()
sys.exit()
DISPLAYSURF.blit(background, (0, 0))
scores = font_small.render(str(SCORE), True, BLACK)
DISPLAYSURF.blit(scores, (10, 10))
for entity in all_sprites:
DISPLAYSURF.blit(entity.image, entity.rect)
entity.move()
# NEed to fix collison and Counting stats
if pygame.sprite.spritecollideany(W1, balls):
DISPLAYSURF.fill(RED)
DISPLAYSURF.blit(game_over, (30, 250))
pygame.display.update()
for entity in all_sprites:
entity.kill()
time.sleep(2)
pygame.quit()
sys.exit()
if pygame.sprite.spritecollideany(B2, balls):
print("Hit")
SCORE += 1
pygame.display.update()
pygame.display.update()
FramePerSec.tick(FPS)
pygame.sprite.spritecollideany() returns the hit Sprite (ball) object. Change the position of this ball:
while True:
# [...]
ball_hit = pygame.sprite.spritecollideany(B2, balls)
if ball_hit:
ball_hit.rect.center = (random.randint(30, 380), 0)
SCORE += 1
print("Hit")
# [...]
im currently learning to program in python (first language) and im trying to create a clicker game, however, while doing the click function i got this error:
line 73, in <module>
if player.collidepoint(event.pos):
AttributeError: 'Player' object has no attribute 'collidepoint'
it seems that my "player" object (the clickable object) doesnt have a rect ? but after looking it up for hours i could not find an answer
this is my game code
import pygame
from os import path
img_dir = path.join(path.dirname(__file__), "img")
width = 500
height = 600
fps = 30
# Cores
white = (255, 255, 255)
black = (0, 0, 0)
red = (255, 0 ,0)
green = (0, 255, 0)
blue = (0, 0, 255)
yellow = (255, 255, 0)
# Iniciar o game
pygame.init()
pygame.mixer.init()
screen = pygame.display.set_mode((width, height))
pygame.display.set_caption("Trojan Clicker")
clock = pygame.time.Clock()
font_name = pygame.font.match_font("arial")
def draw_text(surf, text, size, x , y):
font = pygame.font.Font(font_name, size)
text_surface = font.render(text, True, white)
text_rect = text_surface.get_rect()
text_rect.midtop = (x, y)
surf.blit(text_surface, text_rect)
class Player(pygame.sprite.Sprite):
def __init__(self):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.Surface((75, 75))
self.image.fill(red)
self.rect = self.image.get_rect()
self.screen_rect = screen.get_rect()
self.rect.centerx = width / 2
self.rect.bottom = height / 2
self.speedx = 0
def update(self):
self.speedx = 0
all_sprites = pygame.sprite.Group()
player = Player()
all_sprites.add(player)
clicks = 0
# Loop
running = True
while running:
# Fps
clock.tick(fps)
# Eventos
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
elif event.type == pygame.MOUSEBUTTONDOWN:
# 1 is the left mouse button, 2 is middle, 3 is right.
if event.button == 1:
# `event.pos` is the mouse position.
if player.collidepoint(event.pos):
# Increment the number.
number += 1
# Updates
all_sprites.update()
# Draw / render X
screen.fill(black)
all_sprites.draw(screen)
draw_text(screen, str(clicks), 18, width / 2, 10)
# Depois de desenhar tudo, "flip" o display
pygame.display.flip()
pygame.quit()
Some comments are in portuguese btw, sorry about that
Thanks in advance for everyone who helps
Change the line
if player.collidepoint(event.pos):
to
if player.rect.collidepoint(event.pos):
this program makes boxes move, but i need to make them move randomly and indepensent of each other,
by calling the method "rect.move()" for each of the boxes but i don't know how to do that can u help me.
ex. of how it should not look like: https://youtu.be/D7rkcA0-BR0
import pygame
import random
# Define some colors
BLACK = (0, 0, 0)
WHITE = (255, 255, 255)
GREEN = (0, 255, 0)
RED = (255, 0, 0)
class Rect():
def __init__(self):
self.rectXPos = 0
self.rectYPos = 0
self.height = 0
self.width = 0
self.changeX = 0
self.changeY = 0
self.x = 0
self.y = 0
def move(self):
self.x += self.changeX
self.y += self.changeY
def draw(self,screen):
pygame.draw.rect(screen,RED,[self.x + self.rectXPos, self.y + self.rectYPos, self.height,self.width])
pygame.init()
# Set the width and height of the screen [width, height]
size = (700, 500)
screen = pygame.display.set_mode(size)
pygame.display.set_caption("My Game")
# Loop until the user clicks the close button.
done = False
# Used to manage how fast the screen updates
clock = pygame.time.Clock()
myList =[]
for i in range(10):
rect = Rect()
rect.rectXPos = random.randrange(0,700)
rect.rectYPos = random.randrange(0,500)
rect.height = random.randrange(20,70)
rect.width = random.randrange(20,70)
rect.changeX = random.randrange(-3,3)
rect.changeY = random.randrange(-3,3)
myList.append([rect.rectXPos , rect.rectYPos, rect.height, rect.width, rect.changeX, rect.changeY])
# -------- Main Program Loop -----------
while not done:
# --- Main event loop
for event in pygame.event.get():
if event.type == pygame.QUIT:
done = True
# --- Game logic should go here
# --- Screen-clearing code goes here
# Here, we clear the screen to white. Don't put other drawing commands
# above this, or they will be erased with this command.
# If you want a background image, replace this clear with blit'ing the
# background image.
screen.fill(WHITE)
for i in range(10):
rect.rectXPos = myList[i][0]
rect.rectYPos = myList[i][1]
rect.height = myList[i][2]
rect.width = myList[i][3]
rect.changeX = myList[i][4]
rect.changeY= myList[i][5]
rect.draw(screen)
rect.move()
# --- Drawing code should go here
# --- Go ahead and update the screen with what we've drawn.
pygame.display.flip()
# --- Limit to 60 frames per second
clock.tick(60)
# Close the window and quit.
pygame.quit()
this is premade code from http://programarcadegames.com/
What you need is for the Rect attributes to be randomly generated with the random module. I have modified the code you gave an made some changes.
Firstly I changed the draw method so that it just draws at the x and y values.
The biggest change was that instead of the big complicated myList list in your code, I just stored 10 Rect objects in a list called myRects which I think is much simpler.
You can fiddle around some more with the number generation from around Line 45-52. You can read a bit more on the random.randrange() function here: https://docs.python.org/3/library/random.html#functions-for-integers
I hope this answer helped you! If you have any further questions please post a comment below!
import pygame
import random
# Define some colors
BLACK = (0, 0, 0)
WHITE = (255, 255, 255)
GREEN = (0, 255, 0)
RED = (255, 0, 0)
class Rect():
def __init__(self):
self.x = 0
self.y = 0
self.height = 0
self.width = 0
self.changeX = 0
self.changeY = 0
def move(self):
self.x += self.changeX
self.y += self.changeY
def draw(self, screen):
pygame.draw.rect(screen, RED, [self.x, self.y, self.width, self.height], 0)
pygame.init()
size = (700, 500)
screen = pygame.display.set_mode(size)
pygame.display.set_caption("My Game")
done = False
clock = pygame.time.Clock()
myRects = []
for i in range(10):
rect = Rect()
rect.x = random.randrange(0, 700)
rect.y = random.randrange(0, 700)
rect.width = random.randrange(20, 70)
rect.height = random.randrange(20, 70)
rect.changeX = random.randrange(-3, 3)
rect.changeY = random.randrange(-3, 3)
myRects.append(rect)
print(myRects)
while not done:
for event in pygame.event.get():
if event.type == pygame.QUIT:
done = True
screen.fill(WHITE)
for rect in myRects:
rect.draw(screen)
rect.move()
pygame.display.update()
clock.tick(10)
pygame.quit()
quit()
I'm trying to learn OOP with pygame and make a simple game, I'm loosely following a tutorial, but have tried to modify it to fit my own needs and now it's not working. I'm trying to draw a white rectangle onto a black window, the tutorial draws a blue circle on a black window and when I replace the circle to a rectangle it doesn't work.
My code is sepereated into 2 different files heres the first file:
import pygame
import LanderHandler
black = (0, 0, 0)
white = (255, 255, 255)
green = (0, 255, 0)
red = (255, 0, 0)
class MainLoop(object):
def __init__(self, width=640, height=400):
pygame.init()
pygame.display.set_caption("Lander Game")
self.width = width
self.height = height
self.screen = pygame.display.set_mode((self.width, self.height), pygame.DOUBLEBUF)
self.background = pygame.Surface(self.screen.get_size()).convert()
def paint(self):
lander = LanderHandler.Lander()
lander.blit(self.background)
def run(self):
self.paint()
running = True
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_ESCAPE:
running = False
pygame.display.flip()
pygame.quit()
if __name__ == '__main__':
# call with width of window and fps
MainLoop().run()
And my second file:
import pygame
black = (0, 0, 0)
white = (255, 255, 255)
green = (0, 255, 0)
red = (255, 0, 0)
class Lander(object):
def __init__(self, height=10, width=10, color=white, x=320, y=240):
self.x = x
self.y = y
self.height = height
self.width = width
self.surface = pygame.Surface((2 * self.height, 2 * self.width))
self.color = color
pygame.draw.rect(self.surface, white, (self.height, self.height, self.width, self.width))
def blit(self, background):
"""blit the Ball on the background"""
background.blit(self.surface, (self.x, self.y))
def move(self, change_x, change_y):
self.change_x = change_x
self.change_y = change_y
self.x += self.change_x
self.y += self.change_y
if self.x > 300 or self.x < 0:
self.change_x = -self.change_x
if self.y > 300 or self.y < 0:
self.change_y = -self.change_y
Any help or pointing me in the right direction would be amazing thank you.
P.S. I get no running errors and a black window does pop up, but without a white rectangle.
Problem is because you draw rectangle on surface self.background
lander.blit(self.background)
but you never blit self.background on self.screen which is main buffer and which is send on monitor when you do
pygame.display.flip()
So you can draw directly on self.screen
lander.blit(self.screen)
or you have to blit self.background on self.screen
lander.blit(self.background)
self.screen.blit(self.background, (0,0))
You shouldn't create a function with the name blit because it might get in the way of the actual blit function. Also right here in the second code:
pygame.draw.rect(self.surface, white, (self.height, self.height, self.width, self.width))
you should use surface
I can't get to move a polygon with the function move_ip() in pygame, the code works good if I draw a rectangle, but not with polygon. It doesn't respond when I press any arrow key.
I think I don't need spaceship rectangle because polygons are rects with pygame, but it seems not right, I don't know, i've got a mess.
This is my pygame code:
import sys, os
import pygame
from pygame.locals import *
import numpy as np
if sys.platform in ["win32","win64"]: os.environ["SDL_VIDEO_CENTERED"]='1'
width_screen = 600
height_screen = 480
screen_size = (width_screen, height_screen)
positionx_screen = 0
positiony_screen = 32
title_window = 'ASTEROIDS'
BLACK = (0, 0, 0)
WHITE = (255, 255, 255)
RED = (255, 0, 0)
GREEN = (0, 255, 0)
BLUE = (0, 0, 255)
spaceship = pygame.Rect(200, 475, 120, 20)
def quit_screen(event):
if event.type == QUIT:
pygame.quit()
sys.exit()
class Spaceship():
def __init__(self, x, y, width, height):
self.x = x
self.y = y
self.width = width
self.height = height
self.colour = WHITE
self.thickness = 0
self.movex = 20
def draw_nave(self):
vertices = np.array([[screen_size[0]/2, screen_size[1] /2 - 30],[screen_size[0]/2 + 15, screen_size[1]/2],
[screen_size[0]/2-15, screen_size[1] / 2]])
pygame.draw.polygon(screen_game, self.colour, vertices, self.thickness)
def move_spaceship_right(self):
spaceship.move_ip(self.movex, 0)
def move_spaceship_left(self):
spaceship.move_ip(- self.movex, 0)
def game():
pygame.init()
running = True
global screen_game
screen_game = pygame.display.set_mode(screen_size,
positionx_screen, positiony_screen)
pygame.display.set_caption(title_window)
clock = pygame.time.Clock()
my_spaceship = Spaceship(200, 475, 120, 20)
screen_game.fill(BLACK)
while running:
screen_game.fill(BLACK)
for event in pygame.event.get():
quit_screen(event)
if event.type == pygame.KEYDOWN:
if event.key == K_RIGHT:
my_spaceship.move_spaceship_right()
if event.key == K_LEFT:
my_spaceship.move_spaceship_left()
my_spaceship.draw_nave()
pygame.display.flip()
clock.tick(60)
if __name__ == "__main__":
try:
game()
except:
pygame.quit()
Thanks
The problem is that your Rect is in no way related to the polygon you draw. You simply draw it at the same position every time.
Better create a Surface once, draw your polygon on that Surface once, and use spaceship as position when drawing that new Surface.
I recommend subclassing from Sprite, create that Surface in the __init__ function, and save the Rect in self.rect instead of the spaceship variable.
Then either use the draw function of Sprite or put your Sprite into a Group.