Pygame - creating a rotating projectile arount the center [duplicate] - python

This code is mostly just the generic start up of a pygame window but I'm trying to make it so the object moves (the planet object I've made) in the orbit around the sun object I've made for the coordinates I've given it. I know the x and y values are updating but I don't understand why the object doesn't move.
#import the library
import pygame
import math
#classes
class button:
def _init_ (self,screen, colour, x, y, width,height, letter):
self.screen = screen
self.colour = colour
self.x = x
self.y = y
self.width = width
self.height = height
self.letter = letter
self.radius = radius
def draw(self):
pygame.draw.rect(self.screen, self.colour,(self.x,self.y, self.width, self.height))
if self.letter!= '+' and self.letter!= '-':
font = pygame.font.SysFont('agencyfb',15,True,False)
else:
font = pygame.font.SysFont('agencyfb',25,True,False)
text = font.render(self.letter, True, black)
text_rect = text.get_rect(center=(self.x+self.width/2,self.y+self.height/2))
screen.blit(text, text_rect)
class orbit:
def __init__(self,screen,colour,x,y,radius,width):
self.screen = screen
self.colour = colour
self.x = x
self.y = y
self.width = width
self.radius = radius
def draw_circle(self):
pygame.draw.circle(self.screen,self.colour,(self.x,self.y),self.radius,self.width)
#define colours
##Sun = pygame.draw.circle(screen,Sun,[1000,450],100,0)
Black = (0,0,0)
White = (255,255,255)
Green = (0,255,0)
Red = (255,0,0)
Blue = (0,0,255)
Sun = (255,69,0)
Sun = []
Planet = []
#initialise the engine
pygame.init()
#Opening a window
size = (1920,1080)
screen = pygame.display.set_mode(size)
#set window title
pygame.display.set_caption("Orbit Simulator")
#loop unti the user clicks the close button
done = False
#
x=1000
y=450
Sun.append(orbit(screen,Red,1000,450,100,0))
Planet.append(orbit(screen,White,x,y,50,0))
#
#used to manage how fast the screen updates
clock = pygame.time.Clock()
#------ Main program Loop ------
while not done:
#--- Main event loop
for event in pygame.event.get(): #user did something
if event.type == pygame.QUIT: #if user clicked close
done = True #flag that we are done and exit the loop
#------ Game logic should go here ------
#------ Drawing code should go here -------
#first, clear the screen to white. Don't put other drawing commands above this or they will be erased with this command.
screen.fill(Black)
for i in Sun:
i.draw_circle()
for i in Planet:
r=150
angle=0
count = 0
while angle <= 360:
angle_radians = math.radians(angle)
x = int(math.cos(angle_radians)*r)
y = int(math.sin(angle_radians)*r)
angle +=1
count +=1
print(count)
x+=1000
y+=450
pygame.draw.circle(screen,White,[x,y],10,0)
print("Position [",x,",",y,"]")
#update the screen
pygame.display.flip()
#------ Limit to 60 frames per second ------
clock.tick(60)
#------ When the loop ends, quit ------
pygame.quit()

You can make an object rotate around another by using trigonometry or vectors. With vectors you just have to rotate a vector which defines the offset from the rotation center each frame and add it to the position vector (self.pos which is the rotation center) to get the desired self.rect.center coordinates of the orbiting object.
import pygame as pg
from pygame.math import Vector2
class Planet(pg.sprite.Sprite):
def __init__(self, pos, *groups):
super().__init__(*groups)
self.image = pg.Surface((40, 40), pg.SRCALPHA)
pg.draw.circle(self.image, pg.Color('dodgerblue'), (20, 20), 20)
self.rect = self.image.get_rect(center=pos)
self.pos = Vector2(pos)
self.offset = Vector2(200, 0)
self.angle = 0
def update(self):
self.angle -= 2
# Add the rotated offset vector to the pos vector to get the rect.center.
self.rect.center = self.pos + self.offset.rotate(self.angle)
def main():
pg.init()
screen = pg.display.set_mode((640, 480))
screen_rect = screen.get_rect()
clock = pg.time.Clock()
all_sprites = pg.sprite.Group()
planet = Planet(screen_rect.center, all_sprites)
yellow = pg.Color('yellow')
while True:
for event in pg.event.get():
if event.type == pg.QUIT:
return
all_sprites.update()
screen.fill((30, 30, 30))
pg.draw.circle(screen, yellow, screen_rect.center, 60)
all_sprites.draw(screen)
pg.display.flip()
clock.tick(60)
if __name__ == '__main__':
main()
pg.quit()

Related

Sprites don't blit onto surface PyGame

I'm making chess in pygame, but the pieces don't blit onto the surface for them. How could I fix this?
import pygame
pygame.init()
size = (600,600)
screen = pygame.display.set_mode(size)
pygame.display.set_caption("chess")
clock = pygame.time.Clock()
chessboard = pygame.image.load("chess_board.png")
whitepawn = pygame.image.load("whitepawn.png")
blackpawn = pygame.image.load("blackpawn.png")
class pawn(pygame.sprite.Sprite):
def __init__(self,colour,x,y):
self.x = x
self.y = y
moved = False
self.colour = colour
pygame.sprite.Sprite.__init__(self)
self.im = pygame.surface.Surface((75,75))
def showpiece(self):
if self.colour == "white":
pygame.Surface.blit(self.im,whitepawn,(self.x,self.y))
elif self.colour == "black":
pygame.Surface.blit(self.im,blackpawn,(self.x,self.y))
num1 = 0
pawns = []
for i in range (8):
pawns.append(pawn("black",0+num1,75))
pawns.append(pawn("white",0+num1,450))
num1 += 75
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
screen.blit(chessboard,[0,0])
for n in range (len(pawns)):
pawns[n].showpiece()
pygame.display.flip()
clock.tick(60)
Also what is the point in clock.tick? I know it controls fps, but why does that need limiting?
You have to blit the Sprites on the display Surface (screen):
class pawn(pygame.sprite.Sprite):
# [...]
def showpiece(self):
if self.colour == "white":
screen.blit(whitepawn, (self.x,self.y))
elif self.colour == "black":
ecreen.blit(blackpawn, (self.x,self.y))
I suggest to use pygame.Rect to store the positions of the pieces:
import pygame
pygame.init()
size = (600,600)
screen = pygame.display.set_mode(size)
pygame.display.set_caption("chess")
clock = pygame.time.Clock()
chessboard = pygame.image.load("chess_board.png")
whitepawn = pygame.image.load("whitepawn.png")
blackpawn = pygame.image.load("blackpawn.png")
class pawn(pygame.sprite.Sprite):
def __init__(self, colour, image, x, y):
pygame.sprite.Sprite.__init__(self)
self.colour = colour
self.image = image
self.rect = self.image.get_rect(topleft = (x, y))
def showpiece(self, surf):
surf.blit(self.image, self.rect)
pawns = []
for i in range(8):
pawns.append(pawn("black", blackpawn, i*75, 75))
pawns.append(pawn("white", whitepawn, i*75, 450))
run = True
while run :
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
screen.blit(chessboard, (0, 0))
for p in pawns:
p.showpiece(screen)
pygame.display.flip()
clock.tick(60)
pygame.quit()

How do my make my image (rect) collide with my randomly generated circles to end the game? [duplicate]

This question already has answers here:
How do I detect collision in pygame?
(5 answers)
Closed 1 year ago.
I have been trying to solve this for weeks. This is a free-falling pit game, where my character (in this case a chimpanzee png) falls from the top of the screen to the bottom while trying to dodge the random black circles. I have tried so many angles at tackling this, I have tried the standard collision I was taught (pygame.sprite.groupcollide(Group1, Group2, False, True, collided = None) I have tried doing collisions with the colour black only, different formats of spawning my image and all that, and I haven't been able to find anything that works with my code. It has resulted in the code being very messy. I have tried to clean it up for this, but it still might be hard to understand, but if anybody has any solution to this, please let me know as I have been stumped for weeks. I just want the game to close or "game over" when they touch a circle Code:
import sys
import pygame as pg
RED = (255, 0, 0)
GRAY = (150, 150, 150)
GREEN =(34, 177, 76)
BLACK = (0,0,0)
import random
import math
def main():
width, height = 1024, 768
hbox, vbox = 80, 80
w, h = 640, 240
screen = pg.display.set_mode((width, height))
BG = pg.image.load('jungle.jpg').convert()
img = pg.image.load('MONKEY.png')
img = pg.transform.scale(img, (80, 80))
img.convert()
rect = img.get_rect()
rect.center = w//2, h//2
clock = pg.time.Clock()
Score = 0
class Circle(pg.sprite.Sprite):
def __init__(self):
#You can initialise the size to a random value
self.pos = [random.randint(0, 1000), random.randint(180, 600)]
self.color = (0,0, 0)
self.radius = 20
def draw(self):
pg.draw.circle(screen, self.color, (self.pos[0], self.pos[1]), self.radius)
circles = []
for i in range(20):
circles.append(Circle())
def checkIntersection(c1, c2):
dx = c1.pos[0] - c2.pos[0]
dy = c1.pos[1] - c2.pos[1]
d = math.hypot(dx, dy)
if d < c1.radius + c2.radius:
return True
return False
for i in range(19):
while checkIntersection(circles[i], circles[i + 1]):
circles[i].pos = random.randint(0, 1000), random.randint(0, 700)
velocity = (0, 0)
done = False
while not done:
for event in pg.event.get():
if event.type == pg.QUIT:
done = True
keys = pg.key.get_pressed()
# booster
move = 8 if keys[pg.K_LSHIFT] else 4
if keys[pg.K_a]: #to move left
rect.x -= move
if rect.x < 0 : rect.x = 0
if keys[pg.K_d]: #to move right
rect.x += move
if rect.x > width-hbox : rect.x = width - hbox
Score += 1
rect.y += 2.5
screen.blit(BG, (0,0))
screen.blit(img,rect)
pg.draw.rect(screen, RED, rect, 1)
pg.draw.polygon(screen, GREEN, ((1024,768), (0,768), (0,640),(1024,640)))
font = pg.font.SysFont("comicsansms", 45)
text = font.render (" " + str(Score), 1, BLACK)
screen.blit(text,(480,700))
pg.event.get()
for circle in circles:
circle.draw()
pg.display.update()
clock.tick(30)
if __name__ == '__main__':
pg.init()
main()
pg.quit()
sys.exit()
Use a "mask" collision. See How can I made a collision mask? and Pygame mask collision
Create a Sprite class with mask (see pygame.mask.from_surface):
class Circle(pg.sprite.Sprite):
def __init__(self):
super().__init__()
self.pos = [random.randint(0, 1000), random.randint(180, 600)]
self.color = (0,0, 0)
self.radius = 20
self.image = pg.Surface((self.radius*2, self.radius*2), pg.SRCALPHA)
pg.draw.circle(self.image , self.color, (self.radius, self.radius), self.radius)
self.rect = self.image.get_rect(center = self.pos)
self.mask = pg.mask.from_surface(self.image)
Create a Sprite class for the player (also with a mask)
class Player(pg.sprite.Sprite):
def __init__(self, x, y):
super().__init__()
self.image = pg.image.load('MONKEY.png')
self.image = pg.transform.scale(self.image, (80, 80)).convert()
self.rect = self.image.get_rect()
self.rect.center = x, y
self.mask = pg.mask.from_surface(self.image)
Manage the Sprites in pygame.sprite.Group and use pygame.sprite.spritecollide and pygame.sprite.collide_mask() for the collision test:
if pg.sprite.spritecollide(player, circles, False, collided = pg.sprite.collide_mask):
done = True
Complete example:
import sys
import pygame as pg
RED = (255, 0, 0)
GRAY = (150, 150, 150)
GREEN =(34, 177, 76)
BLACK = (0,0,0)
import random
import math
class Circle(pg.sprite.Sprite):
def __init__(self):
super().__init__()
self.pos = [random.randint(0, 1000), random.randint(180, 600)]
self.color = (0,0, 0)
self.radius = 20
self.image = pg.Surface((self.radius*2, self.radius*2), pg.SRCALPHA)
pg.draw.circle(self.image , self.color, (self.radius, self.radius), self.radius)
self.rect = self.image.get_rect(center = self.pos)
self.mask = pg.mask.from_surface(self.image)
class Player(pg.sprite.Sprite):
def __init__(self, x, y):
super().__init__()
self.image = pg.image.load('MONKEY.png')
self.image = pg.transform.scale(self.image, (80, 80)).convert()
self.rect = self.image.get_rect()
self.rect.center = x, y
self.mask = pg.mask.from_surface(self.image)
def main():
width, height = 1024, 768
hbox, vbox = 80, 80
w, h = 640, 240
screen = pg.display.set_mode((width, height))
BG = pg.image.load('jungle.jpg').convert()
clock = pg.time.Clock()
Score = 0
player = Player(w//2, h//2)
all_sprites = pg.sprite.Group(player)
circles = pg.sprite.Group()
for i in range(20):
circle = Circle()
circles.add(circle)
all_sprites.add(circle)
def checkIntersection(c1, c2):
dx = c1.pos[0] - c2.pos[0]
dy = c1.pos[1] - c2.pos[1]
d = math.hypot(dx, dy)
if d < c1.radius + c2.radius:
return True
return False
c = circles.sprites()
for i in range(19):
while checkIntersection(c[i], c[i + 1]):
c[i].pos = random.randint(0, 1000), random.randint(0, 700)
velocity = (0, 0)
done = False
while not done:
for event in pg.event.get():
if event.type == pg.QUIT:
done = True
keys = pg.key.get_pressed()
# booster
move = 8 if keys[pg.K_LSHIFT] else 4
if keys[pg.K_a]: #to move left
player.rect.x -= move
if player.rect.x < 0 : player.rect.x = 0
if keys[pg.K_d]: #to move right
player.rect.x += move
if player.rect.x > width-hbox : player.rect.x = width - hbox
Score += 1
player.rect.y += 2.5
screen.blit(BG, (0,0))
pg.draw.rect(screen, RED, player.rect, 1)
pg.draw.polygon(screen, GREEN, ((1024,768), (0,768), (0,640),(1024,640)))
font = pg.font.SysFont("comicsansms", 45)
text = font.render (" " + str(Score), 1, BLACK)
screen.blit(text,(480,700))
pg.event.get()
all_sprites.draw(screen)
pg.display.update()
clock.tick(30)
if pg.sprite.spritecollide(player, circles, False, collided = pg.sprite.collide_mask):
done = True
if __name__ == '__main__':
pg.init()
main()
pg.quit()
sys.exit()

Extremely poor performance in my simulation made in PyGame

I followed a PyGame tile-based tutorial for a project in school, but I never intended to make a game, but a simulation of an ecosystem. Unfortunately, when I run my program the performance is very bad and it only manages to run for a few seconds, before the windows to stop answering.
The only thing I want to do at the moment is to place a new patch of grass, when the energy of a grass patch reaches 80.
What is there to do? Is it bad that everything is inside of the update method? Can I use events or something to make the checks happen with a greater interval? I know there is a lot of maths going on each frame, but don't know how to do it another way.
Here is my code:
main.py:
#!/usr/bin/python3
#Importing necessary libraries
import pygame as pg, sys, random
from settings import *
from sprites import *
class Sim:
#Initialize the game window, etc.
def __init__(self):
pg.init()
self.screen = pg.display.set_mode((WIDTH, HEIGHT))
pg.display.set_caption(TITLE)
self.clock = pg.time.Clock()
self.running = True
def new_grass(self, pos):
for g in self.grass:
if pos != g.pos:
Grass(self, pos)
#Start a new generation
def new(self):
self.all_sprites = pg.sprite.Group()
self.grass = pg.sprite.Group()
Grass(self, (10, 15))
self.run()
#Main loop
def run(self):
self.simulating = True
while self.simulating:
self.clock.tick(FPS)
self.events()
self.update()
self.draw()
#Update things on screen
def update(self):
self.all_sprites.update()
#Draw a grid on screen
def draw_grid(self):
for x in range(0, WIDTH, TILESIZE):
pg.draw.line(self.screen, BLACK, (x, 0), (x, HEIGHT))
for y in range(0, HEIGHT, TILESIZE):
pg.draw.line(self.screen, BLACK, (0, y), (WIDTH, y))
#Draw things on screen
def draw(self):
pg.display.set_caption("{:.2f}".format(self.clock.get_fps()))
self.screen.fill(DARK_GREEN)
self.draw_grid()
self.all_sprites.draw(self.screen)
#After drawing everything, flip the display
pg.display.flip()
#Events that might happen
def events(self):
for event in pg.event.get():
#Check for the user closing the window
if event.type == pg.QUIT:
if self.simulating:
self.simulating = False
self.running = False
s = Sim()
while s.running:
s.new()
pg.quit()
sprites.py:
#!/usr/bin/python3
import pygame as pg, random
from settings import *
vec = pg.math.Vector2
class Grass(pg.sprite.Sprite):
def __init__(self, sim, cord):
self.groups = sim.all_sprites, sim.grass
pg.sprite.Sprite.__init__(self, self.groups)
self.sim = sim
self.image = pg.Surface((TILESIZE/2, TILESIZE/2))
self.image.fill(GREEN)
self.cord = cord
self.rect = self.image.get_rect()
self.pos = vec(cord) * TILESIZE / 2
self.rect.topleft = self.pos
self.spread = vec(random.randint(-1, 1), random.randint(-1, 1))
self.energy = 20
def update(self):
if self.energy <= 80:
self.energy += 10
if self.energy >= 80:
self.sim.new_grass((self.cord + self.spread))
settings.py:
#Options/settings
TITLE = "EcoSim"
WIDTH = 480
HEIGHT = 600
FPS = 30
TILESIZE = 32
GRID_WIDTH = WIDTH / TILESIZE
GRID_HEIGHT = HEIGHT / TILESIZE
#Colors
WHITE = (255, 255, 255)
BLACK = (0, 0, 0)
GREEN = (0, 255, 0)
DARK_GREEN = (0, 100, 0)
BROWN = (150,75,0)
The problem is here:
def new_grass(self, pos):
for g in self.grass:
if pos != g.pos:
Grass(self, pos)
This is because you'll add a Grass object for every time there is a grass that already exists on another position. I think you meant to add one if the position isn't present at all.
You have a few bugs in your program, mainly the one mentioned above, but also, the parameter pos should actually be coord. I've highlighted your code with some comments on improvements:
#!/usr/bin/python3
import pygame as pg, random
TITLE = "EcoSim"
WIDTH = 480
HEIGHT = 600
FPS = 30
TILESIZE = 32
GRID_WIDTH = WIDTH / TILESIZE
GRID_HEIGHT = HEIGHT / TILESIZE
WHITE = (255, 255, 255)
BLACK = (0, 0, 0)
GREEN = (0, 255, 0)
DARK_GREEN = (0, 100, 0)
BROWN = (150,75,0)
vec = pg.math.Vector2
class Grass(pg.sprite.Sprite):
# This creates the image just once!
IMAGE = pg.Surface((TILESIZE/2, TILESIZE/2))
IMAGE.fill(GREEN)
def __init__(self, cord): # Remove 'sim'.
# self.groups = sim.all_sprites, sim.grass
# pg.sprite.Sprite.__init__(self, self.groups)
# self.sim = sim
super().__init__()
self.image = Grass.IMAGE # All reference the same image.
self.cord = cord
self.rect = self.image.get_rect()
self.pos = vec(cord) * TILESIZE / 2
self.rect.topleft = self.pos
self.energy = 20
self.spread = vec(random.randint(-1, 1), random.randint(-1, 1))
def update(self):
if self.energy <= 80:
self.energy += 10
# Make Sim check for this.
# if self.energy >= 80:
# self.sim.new_grass((self.cord + self.spread))
class Sim:
def __init__(self):
pg.init()
pg.display.set_caption(TITLE)
self.screen = pg.display.set_mode((WIDTH, HEIGHT))
self.clock = pg.time.Clock()
self.all_sprites = pg.sprite.Group() # Create *ALL* attributes in `__init__`
self.grass = pg.sprite.Group()
self.running = True
self.simulating = False
# You're passing coord here, not pos! And you also want to add
# the grass only if the coord is not already present in the list.
def new_grass(self, coord):
if coord not in (x.cord for x in self.grass):
grass = Grass(coord)
self.grass.add(grass)
self.all_sprites.add(grass)
def new(self):
self.all_sprites = pg.sprite.Group()
self.grass = pg.sprite.Group()
grass = Grass((10, 15)) # Grass is now pure and doesn't have any side-effects, which makes the code much clearer.
self.grass.add(grass)
self.all_sprites.add(grass)
self.run()
def run(self):
self.simulating = True
while self.simulating:
self.clock.tick(FPS)
self.events()
self.update()
self.draw()
def update(self):
self.all_sprites.update()
# Let Sim decide the fate of the grass. Don't let Grass add
# itself.
for grass in self.grass:
if grass.energy >= 80:
self.new_grass((grass.cord + grass.spread))
def draw_grid(self):
for x in range(0, WIDTH, TILESIZE):
pg.draw.line(self.screen, BLACK, (x, 0), (x, HEIGHT))
for y in range(0, HEIGHT, TILESIZE):
pg.draw.line(self.screen, BLACK, (0, y), (WIDTH, y))
def draw(self):
pg.display.set_caption("{:.2f}".format(self.clock.get_fps()))
self.screen.fill(DARK_GREEN)
self.draw_grid()
self.all_sprites.draw(self.screen)
pg.display.flip()
def events(self):
for event in pg.event.get():
if event.type == pg.QUIT:
self.simulating = False # There was an unnecessary if here.
self.running = False
s = Sim()
while s.running:
s.new()
pg.quit()
The major issue is the method Sim.new_grass:
class Sim:
# [...]
def new_grass(self, pos):
for g in self.grass:
if pos != g.pos:
Grass(self, pos)
The method generates many more Grass objects than expected. It event generates multiple grass objects at the same location. For every object (g) where pos != g.pos a new instance of Grass is constructed.
You need to create a new instance of Grass if there is not any Grass object in the desired location:
class Sim:
# [...]
def new_grass(self, pos):
if not any(pos == g.pos for g in self.grass):
Grass(self, pos)

How to output text to a screen, while also outputting Object Orientated buttons - Pygame

#Importing Modules
import pygame
import sys
import random
#All pygame stuff under here
pygame.init()
#Font definitions
backFont = pygame.font.SysFont("monospace",40)
titleFont = pygame.font.SysFont("garamond", 100)
buttonFont = pygame.font.SysFont("garamond", 25)
bigFont = pygame.font.SysFont("garamond",100)
#Colour definitions
BackGray = pygame.Color('gray60')
screenGray = pygame.Color('gray80')
buttonGray1 = pygame.Color('gray40')
buttonGray2 = pygame.Color('gray50')
buttonGray3 = pygame.Color('gray30')
textColour = pygame.Color('navy')
#Screen size set
screen = pygame.display.set_mode((800, 600))
#Class for the buttons set here
class Button:
def __init__(self, x, y, width, height, colour, surface):
self.x = x
self.y = y
self.height = height
self.width = width
self.colour = colour
self.surface = surface
def isPressed(self):
mouse_position = pygame.mouse.get_pos()
mouse_x = mouse_position[0]
mouse_y = mouse_position[1]
if mouse_x > self.x:
if mouse_x < self.x + self.width:
if mouse_y > self.y:
if mouse_y < self.y + self.height:
mouse_click = pygame.mouse.get_pressed()
left_click = mouse_click[0]
if left_click:
self.colour = (0,0,0)
return True
self.colour = (230, 230, 230)
return False
def drawButton(self):
pygame.draw.rect(self.surface, self.colour, (self.x, self.y, self.width, self.height))
pygame.display.flip()
def FrontPage():
#Back screen
screen.fill(screenGray)
#The background is defined here
BinaryPage = []
for i in range(0,15):
BinaryString = ""
for j in range(0,33):
BinaryString += random.choice(["0","1"])
BinaryPage.append(BinaryString)
for i in range(0,15):
screen.blit(backFont.render(BinaryPage[i], 1, BackGray), (0,i * 40))
#The title is defined and printed here
Title1 = titleFont.render("The Six", 10, textColour)
Title2 = titleFont.render("Cipher", 10, textColour)
Title3 = titleFont.render("Simulator", 10, textColour)
screen.blit(Title1, (100, 100))
screen.blit(Title2, (100, 200))
screen.blit(Title3, (100, 300))
#Text for the button
buttonText = buttonFont.render("Continue", 10, textColour)
screen.blit(buttonText, (115,405))
#Where the buttons are defined and drawn
ButtonBig = Button(100, 450, 120, 60, buttonGray1, screen)
ButtonSmall = Button(105, 455, 110, 50, buttonGray2, screen)
ButtonBig.drawButton()
ButtonSmall.drawButton()
#Pygame While loop
clock = pygame.time.Clock()
while True:
for event in pygame.event.get():
if ButtonBig.isPressed():
print("Hello")
break
if event.type == pygame.QUIT:
pygame.quit()
sys.exit()
clock.tick(60)
The above code runs a window that has 0's and 1's in a random order as the background, with the title of my program in the middle.
Then, there should be a button at the bottom, or a grey rectangle. However, when I try to .blit, or print, something onto the button frame, after I have drawn the button onto the screen, it does not appear.
Can anybody tell me why and how to fix it?
Or any alternatives of how to output text onto the buttons.
Thanks in advance
I'd first create a separate background surface and blit all the background graphics which never change onto it (the numbers in the following example). In the main loop you can just blit this background to clear the screen.
To blit text onto a button:
Pass the text to the __init__ method
create the button image (a pygame.Surface)
render the text
create rects for the image and the text (pass the center of the image rect to the text rect to center the text)
blit the text surface onto the image.
For the buttons I'd use sprites and put them into a sprite group, so that you can draw them simply by calling sprite_group.draw(screen). Sprites need an image and a rect attribute to work. Pygame rects have collision detection methods that you should use instead of writing your own. In this case we can use the collidepoint method and pass the event.pos to it.
import random
import pygame as pg
pg.init()
screen = pg.display.set_mode((800, 600))
FONT = pg.font.SysFont('garamond', 25)
SCREEN_GRAY = pg.Color('gray80')
BUTTON_GRAY = pg.Color('gray40')
TEXT_COLOUR = pg.Color('navy')
# Inherit from pg.sprite.Sprite. That will allow you to
# put the instances into a sprite group.
class Button(pg.sprite.Sprite):
def __init__(self, text, x, y, width, height, colour):
super().__init__()
# Create the image of the button.
self.image = pg.Surface((width, height))
self.image.fill(colour)
# A pygame.Rect will serve as the blit position.
self.rect = self.image.get_rect()
# Render the text.
txt = FONT.render(text, True, TEXT_COLOUR)
# This txt_rect is used to center the text on the image.
txt_rect = txt.get_rect(center=self.rect.center)
self.image.blit(txt, txt_rect)
# Set the position of the image rect.
self.rect.topleft = x, y
def is_pressed(self, event):
if event.type == pg.MOUSEBUTTONDOWN:
# MOUSE... events have an event.pos attribute (the mouse position)
# which you can pass to the collidepoint method of the rect.
if self.rect.collidepoint(event.pos):
return True
return False
def main():
button_big = Button('big button', 100, 250, 120, 60, BUTTON_GRAY)
button_small = Button('small button', 105, 455, 120, 50, BUTTON_GRAY)
buttons_group = pg.sprite.Group(button_big, button_small)
background = pg.Surface(screen.get_size())
background.fill(SCREEN_GRAY)
for i in range(screen.get_height()//40):
for j in range(screen.get_width()//40):
n = random.choice(['0', '1'])
background.blit(FONT.render(n, True, BUTTON_GRAY), (j*40, i*40))
clock = pg.time.Clock()
while True:
for event in pg.event.get():
if event.type == pg.QUIT:
return
if button_big.is_pressed(event):
print('big')
elif button_small.is_pressed(event):
print('small')
screen.blit(background, (0, 0))
# Blit the images of the contained sprites onto the screen.
buttons_group.draw(screen)
pg.display.flip()
clock.tick(60)
if __name__ == '__main__':
main()
pg.quit()

PyGame Mouse Cursor Center of Player Image

Have just started using PyGame in Python. I have managed to set the player_image to follow the mouse cursor, but the image is not centred over the position of the cursor. The cursor always seems to be in the top left corner of the image. Could anyone help me with getting it so that the image is over the centre of the mouse cursor? I can then turn the mouse cursor off and the image track the movement correctly.
I have the below section of code so far, with a background set in the pygame window:
player_image = pygame.image.load("spaceship.png").convert_alpha()
player_image_rect = player_image.get_rect()
player_image_rect.centerx = player_image.get_rect().centerx
player_image_rect.centery = player_image.get_rect().centery
screen.blit(player_image, player_image_rect)
pygame.mouse.set_visible(True)
Thanks
Full code (I've slowly been adding in mixture of features):
import sys
import pygame
import random
black = (0, 0, 0)
white = (255, 255, 255)
# Initialise PyGame
pygame.init()
#Set screen dimensions and title
width = 802
height = 585
screen=pygame.display.set_mode([width, height])
pygame.display.set_caption("Space Attack Game v1")
#Load and set up graphics position
background_position = [0, 0]
background_image = pygame.image.load("solarsystem.jpg").convert()
#Set game title on screen text
basicfont = pygame.font.SysFont(None, 68)
text = basicfont.render('Space Attack', True, white).convert_alpha()
text_rect = text.get_rect()
#textrect.centerx = screen.get_rect().centerx
#textrect.centery = screen.get_rect().centery
#Set player mouse control image
player_image = pygame.image.load("spaceship.png").convert_alpha()
player_image_rect = player_image.get_rect()
pos = pygame.mouse.get_pos()
player_image_rect.center = pos
#player_image_rect.centerx = player_image.get_rect().centerx
#player_image_rect.centery = player_image.get_rect().centery
screen.blit(player_image, player_image_rect.center)
pygame.mouse.set_visible(True)
#Load star
star_image = pygame.image.load("star.png").convert_alpha()
screen.blit(star_image, (random.randint(0,width),random.randint(0,height)) )
#star_image_rect = star_image.get_rect()
pygame.display.flip()
#######################################################
done = False
while not done:
for event in pygame.event.get():
if event.type == pygame.QUIT:
done = True
screen.blit(star_image, (random.randint(0,width),random.randint(0,height)))
class ball:
def __init__(self,X,Y):
self.velocity = [1,1]
self.ball_image = pygame.image.load('alien.png').convert()
self.ball_image.set_colorkey(black)
self.ball_boundary = self.ball_image.get_rect (center=(X,Y))
self.screen = pygame.display.get_surface()
#self.sound = pygame.mixer.Sound ('Collide.wav')
if __name__ =='__main__':
num_balls = 5
ball_list = []
for i in range(num_balls):
ball_list.append( ball(random.randint(0, width),random.randint(0, height)) )
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
sys.exit(0)
for ball in ball_list:
if ball.ball_boundary.left < 0 or ball.ball_boundary.right > width:
#ball.sound.play()
ball.velocity[0] = -1 * ball.velocity[0]
if ball.ball_boundary.top < 0 or ball.ball_boundary.bottom > height:
#ball.sound.play()
ball.velocity[1] = -1 * ball.velocity[1]
ball.ball_boundary = ball.ball_boundary.move (ball.velocity)
screen.blit (ball.ball_image, ball.ball_boundary)
player_position = pygame.mouse.get_pos()
x = player_position[0]
y = player_position[1]
pygame.display.flip()
screen.blit(background_image, background_position)
screen.blit(text, text_rect)
screen.blit(player_image, [x,y])
pygame.quit()
Just set the center of your Rect to the mouse position, like
pos = pygame.mouse.get_pos()
player_image_rect.center = pos

Categories

Resources