i was following a tutorial and i'm trying to get my text to appear in the screen, here is my code but the text won't appear:
from __future__ import division
import math
import sys
import pygame
class MyGame(object):
def __init__(self):
pygame.mixer.init()
pygame.mixer.pre_init(44100, -16, 2, 2048)
pygame.init()
self.width = 800
self.height = 600
self.screen = pygame.display.set_mode((self.width, self.height))
self.bg_color = 0, 0, 0
font = pygame.font.Font(None, 100)
text = font.render("text that should appear", True, 238, 58, 140)
self.FPS = 30
self.REFRESH = pygame.USEREVENT+1
pygame.time.set_timer(self.REFRESH, 1000//self.FPS)
def run(self):
running = True
while running:
event = pygame.event.wait()
if event.type == pygame.QUIT:
running = False
elif event.type == self.REFRESH:
self.draw()
else:
pass
def draw(self):
self.screen.fill(self.bg_color)
screen.blit(text, [400,300])
pygame.display.flip()
MyGame().run()
pygame.quit()
sys.exit()
any idea why is this happening? am i forgetting to import a library or is there something off with my draw method?
It looks like you're passing the three RGB values of color in as three separate values to render. They should be passed in as a single tuple.
You're also missing some selfs. screen.blit(text, [400,300]) should be self.screen.blit(text, [400,300]), and you need to make all instances of text into self.text if you want it to be accessible in both __init__ and draw.
from __future__ import division
import math
import sys
import pygame
class MyGame(object):
def __init__(self):
pygame.mixer.init()
pygame.mixer.pre_init(44100, -16, 2, 2048)
pygame.init()
self.width = 800
self.height = 600
self.screen = pygame.display.set_mode((self.width, self.height))
self.bg_color = 0, 0, 0
font = pygame.font.Font(None, 100)
self.text = font.render("text that should appear", True, (238, 58, 140))
self.FPS = 30
self.REFRESH = pygame.USEREVENT+1
pygame.time.set_timer(self.REFRESH, 1000//self.FPS)
def run(self):
running = True
while running:
event = pygame.event.wait()
if event.type == pygame.QUIT:
running = False
elif event.type == self.REFRESH:
self.draw()
else:
pass
def draw(self):
self.screen.fill(self.bg_color)
self.screen.blit(self.text, [400,300])
pygame.display.flip()
MyGame().run()
pygame.quit()
sys.exit()
Result:
Related
I am creating a space Invaders game and have asked the stackoverflow community about it. But this time things are a bit more complicated. There is no visible error but the window just pops up and closes which is not supposed to happen. I created a loop and for some reason it isnt working
import pygame
import os
import time
import random
pygame.font.init()
WIDTH, HEIGHT = 750, 750
WIN = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption("Space Invaders")
# Load Images
RED_SPACE_SHIP = pygame.image.load(os.path.join("assets", "pixel_ship_red_small.png"))
GREEN_SPACE_SHIP = pygame.image.load(os.path.join("assets", "pixel_ship_green_small.png"))
BLUE_SPACE_SHIP = pygame.image.load(os.path.join("assets", "pixel_ship_blue_small.png"))
# Player Ship
RED_SPACE_SHIP = pygame.image.load(os.path.join("assets", "pixel_ship_yellow.png"))
# Lasers
RED_LASER = pygame.image.load(os.path.join("assets", "pixel_laser_red.png"))
GREEN_LASER = pygame.image.load(os.path.join("assets", "pixel_laser_green.png"))
BLUE_LASER = pygame.image.load(os.path.join("assets", "pixel_laser_blue.png"))
YELLOW_LASER = pygame.image.load(os.path.join("assets", "pixel_laser_yellow.png"))
# Background
BG = pygame.transform.scale(pygame.image.load(os.path.join("assets", "background-black.png")), (WIDTH, HEIGHT))
class Ship:
def __init__(self, x, y, health = 100):
self.x = x
self.y = y
self.health = health
self.ship_img = None
self.laser_img = None
self.lasers = []
self.cool_down_counter = 0
def draw(self, window):
pygame.draw.rect(window, (255,0,0), (self.x, self.y, 50, 50))x
def main():
run = True
FPS = 60
level = 1
lives = 5
main_font = pygame.font.SysFont("comicsans", 50)
ship = Ship(300, 650)
clock = pygame.time.Clock()
def redraw_window():
WIN.blit(BG, (0,0))
# draw text
lives_label = main_font.render(f"Lives: {lives}", 1, (255,255,255))
level_label = main_font.render(f"Level: {level}", 1, (255,255,255))
WIN.blit(lives_label, (10, 10))
WIN.blit(level_label,(WIDTH - level_label.get_width() - 10, 10))
ship.draw(WIN)
pygame.display.update()
while run:
clock.tick(FPS)
redraw_window()
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
main()
I tried reviewing my code but I couldn't see anything.
The problem is that your infinite while loop doesn't do anything, and runs forever doing that. Your loop needs to be:
while run:
clock.tick(FPS)
redraw_window()
pygame.display.update()
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
I'm really new to pygame and Python classes. I tried to create a game with different layers.
Layer 1: gameplay
Layer 2: HP: Position:...
It looks a little bit like this:
I think the problem with my code is that i did not know how to use class properly. And I use the wrong method to create a layer for my game.
import pygame
from pygame.locals import *
import sys
pygame.init()
colors = [(255, 255, 255), (204, 229, 255), (0, 0, 0)] #white, light_blue, black
X_AXIS = [x for x in range(11)]
Y_AXIS = ("X A B C D E F G H I").split()
class character:
pass
class Gameplay:
def __init__(self, width, height):
self.width = width
self.height = height
self.display = pygame.display.set_mode((self.width, self.height))
logo = pygame.image.load(r'logo.png')
pygame.display.set_caption("Battle Royale")
pygame.display.set_icon(logo)
def background_layer(self):
self.game_surf = pygame.surface.Surface((800,600))
game_surf.fill(colors[0])
display.blit(game_surf, (0, 0))
gameplay = Gameplay(1300, 760)
while True:
gameplay.background_layer()
for event in pygame.event.get():
if event.type == MOUSEBUTTONDOWN:
pass
elif event.type == QUIT:
pygame.quit()
sys.exit()
First few mistakes:
You forgot self. in few places and it should gives you error messages (but you didn't mention it).
You forgot pygame.display.flip() to send from buffer to screen.
If you want other layers then you should add other functions to draw them.
At this moment I see only def background_layer() but you could add other functions for other layers and later execute them in loop - like this:
while True:
self.draw_background()
self.draw_player()
self.draw_grid()
self.draw_info()
pygame.display.flip()
for event in pygame.event.get():
# ... code ...
Minimal working code with other changes.
import sys
import pygame
# --- constants ---- # PEP8: `UPPER_CASE_NAMES` for constants
COLORS = [(255, 255, 255), (204, 229, 255), (0, 0, 0)] #white, light_blue, black
X_AXIS = list(range(11))
Y_AXIS = list("XABCDEFGHI")
# --- classes --- # PEP8: `CamelCaseNames` for classes
class Character:
pass
class Game:
def __init__(self, width, height):
self.width = width
self.height = height
pygame.init()
self.display = pygame.display.set_mode((self.width, self.height))
#self.display_rect = self.display.get_rect()
pygame.display.set_caption("Battle Royale")
#logo = pygame.image.load(r'logo.png')
#pygame.display.set_icon(logo)
self.layer_background = pygame.surface.Surface((800, 600))
self.layer_background.fill(COLORS[0])
self.layer_background_rect = self.layer_background.get_rect()
self.pos = 'X0'
self.hp = 100
self.font = pygame.font.SysFont(None, 40)
def draw_background(self):
self.display.blit(self.layer_background, self.layer_background_rect)
def draw_grid(self):
for x in range(0, 800, 50):
pygame.draw.line(self.display, COLORS[2], (x, 0), (x, 600))
for y in range(0, 600, 50):
pygame.draw.line(self.display, COLORS[2], (0, y), (800, y))
def draw_info(self):
text_image = self.font.render(f"POS: {self.pos}", False, COLORS[0])
text_rect = text_image.get_rect(x=880, y=350)
self.display.blit(text_image, text_rect)
text_image = self.font.render(f"HP: {self.hp}", False, COLORS[0])
text_rect = text_image.get_rect(x=880, y=450)
self.display.blit(text_image, text_rect)
def run(self):
while True:
self.draw_background()
#self.draw_player()
self.draw_grid()
self.draw_info()
pygame.display.flip()
for event in pygame.event.get():
if event.type == pygame.MOUSEBUTTONDOWN:
pass
elif event.type == pygame.QUIT:
pygame.quit()
sys.exit()
# --- functions --- # PEP8: `lower_case_names` for functions
# empty
# --- main ---
game = Game(1300, 760)
game.run()
I have been following this tutorial about animated buttons in pygame. It worked perfectly until I created a button outside of the main loop in another function.
Here is my code:
import pygame
from pygame.locals import *
import sys
import random
# Constants
SCREEN = pygame.display.set_mode((1280, 720), 0, 32)
# Colours
WHITE = (255, 255, 255)
BLACK = (0, 0, 0)
GREY = (100, 100, 100)
LIGHT_BLUE = (66, 233, 245)
# Button Class
class Button:
def __init__(self, text, width, height, pos, elevation):
# Core attributes
self.pressed = False
self.elevation = elevation
self.dynamicElevation = elevation
self.originalYPos = pos[1]
# Top Rectangle
self.topRectangle = pygame.Rect(pos, (width, height))
self.topColor = '#457B9D'
# Bottom Rectangle
self.bottomRectangle = pygame.Rect(pos, (width, elevation))
self.bottomColor = '#1D3557'
# Text
self.textSurface = gui_font.render(text, True, '#FFFFFF')
self.textRectangle = self.textSurface.get_rect(center = self.topRectangle.center)
def draw(self):
# Elevation Logic
self.topRectangle.y = self.originalYPos - self.dynamicElevation
self.textRectangle.center = self.topRectangle.center
self.bottomRectangle.midtop = self.topRectangle.midtop
self.bottomRectangle.height = self.topRectangle.height + self.dynamicElevation
bottom =pygame.draw.rect(SCREEN, self.bottomColor, self.bottomRectangle, border_radius = 12)
top = pygame.draw.rect(SCREEN, self.topColor, self.topRectangle, border_radius = 12)
pygame.draw.rect(SCREEN, '#000000', top, 1, border_radius = 12)
pygame.draw.rect(SCREEN, '#000000', bottom, 1, border_radius = 12)
SCREEN.blit(self.textSurface, self.textRectangle)
self.check_click()
def check_click(self):
mousePosition = pygame.mouse.get_pos()
if self.topRectangle.collidepoint(mousePosition):
self.topColor = '#F1FAEE'
if pygame.mouse.get_pressed()[0]:
self.dynamicElevation = 0
self.pressed = True
else:
self.dynamicElevation = self.elevation
if self.pressed == True:
print("Click")
self.pressed = False
else:
self.topColor = '#457B9D'
class GameState():
def __init__(self):
self.state = "welcome"
def welcomeScreen(self):
SCREEN.fill(WHITE)
for event in pygame.event.get():
if event.type == QUIT:
exit()
if event.type == KEYDOWN:
if event.key == K_ESCAPE:
exit()
if event.key == K_F1:
self.state = "mainGame"
pygame.display.update()
def mainGame(self):
SCREEN.fill(GREY)
buttonBack = Button("Back to Main Screen", 250, 30, (1000, 650), 8)
for event in pygame.event.get():
if event.type == QUIT:
exit()
if event.type == KEYDOWN:
if event.key == K_ESCAPE:
exit()
if event.key == K_F2:
self.state = "welcome"
buttonBack.draw()
pygame.display.update()
def stateManager(self):
if self.state == "welcome":
self.welcomeScreen()
if self.state == "mainGame":
self.mainGame()
pygame.init()
clock = pygame.time.Clock()
gameState = GameState()
pygame.display.set_caption("Button Test")
gui_font = pygame.font.Font(None, 30)
while True:
gameState.stateManager()
clock.tick(60)
I have tried to play around with putting the button in a different screen or at different stages of the loop. Is there a logic error I cannot see or lies my mistake somewhere else?
You are actually creating the button inside the main loop since you create it each time mainGame is called. mainGame is called by stateManager if the state is "mainGame", and that's called at each frame in your while True loop. So as you are recreating your button at each frame I think your problems might come from there.
I suggest you create your button in the parent's class constructor instead:
class GameState():
def __init__(self):
self.state = "welcome"
# Create the button here to make the object persistent.
self.buttonBack = Button("Back to Main Screen", 250, 30, (1000, 650), 8)
# ...
def mainGame(self):
SCREEN.fill(GREY)
for event in pygame.event.get():
if event.type == QUIT:
exit()
if event.type == KEYDOWN:
if event.key == K_ESCAPE:
exit()
if event.key == K_F2:
self.state = "welcome"
self.buttonBack.draw() # <- use your button with self.buttonBack
pygame.display.update()
# ...
I have recently started learning pygame, and I'd like to have an FPS counter displayed in the top left of the screen. I have that already done but when I start my game the FPS counter displays this, which is not what I'd like. I'd like the counter to display just two numbers, which would be 60 in that picture. This is my code so far:
class FPSCounter:
def __init__(self, surface, font, clock, color, pos):
self.surface = surface
self.font = font
self.clock = clock
self.pos = pos
self.color = color
self.fps_text = self.font.render(str(int(self.clock.get_fps())) + "FPS", False, self.color)
self.fps_text_rect = self.fps_text.get_rect(center=(self.pos[0], self.pos[1]))
def render(self):
self.surface.blit(self.fps_text, self.fps_text_rect)
def update(self):
self.fps_text = self.font.render(str(self.clock.get_fps()) + "FPS", False, self.color)
self.fps_text_rect = self.fps_text.get_rect(center=(self.pos[0], self.pos[1]))
And this is how I'd display it in my game:
import pygame, sys
from fps_counter import FPSCounter
pygame.init()
clock = pygame.time.Clock()
black = (0, 0, 0)
green = (0, 0, 255)
width = 640
height = 480
screen = pygame.display.set_mode((width, height))
pygame.display.set_caption("FPS Test")
font = pygame.font.Font(None, 36)
fps_counter = FPSCounter(screen, font, clock, green, (150, 10))
while True:
screen.fill(black)
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
sys.exit()
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_ESCAPE:
pygame.quit()
sys.exit()
fps_counter.render()
fps_counter.update()
pygame.display.update()
clock.tick(60)
Thank you in advance. :)
All you need to do is to format the text. See Format String Syntax:
class FPSCounter:
# [...]
def update(self):
text = f"{self.clock.get_fps():2.0f} FPS"
self.fps_text = self.font.render(text, False, self.color)
self.fps_text_rect = self.fps_text.get_rect(center=(self.pos[0], self.pos[1]))
I'm new to python. I programmed with vb2010, but it's time to try something new. I want to hide a action after 5 seconds after mouse down event(like in start()).
import pygame
import sys
from pygame.locals import *
from time import gmtime, strftime
import threading
import time
white = (255,255,255)
black = (0,0,0)
blue = (0,0,255)
width = 600
height = 400
channel = '0001'
name = 'Channel 3'
class screen(object):
def __init__(self):
pygame.init()
self.font = pygame.font.SysFont('Arial', 25)
pygame.display.set_caption('PyTV')
self.screen = pygame.display.set_mode((width,height), 0, 32)
self.screen.fill((black))
pygame.display.update()
def printData(self):
self.rect = pygame.draw.rect(self.screen, (blue), (0, 0, width, height - 350), 0)
self.screen.blit(self.font.render(channel, True, white), (width - 590, 0))
self.screen.blit(self.font.render(name, True, white), (height - 335, 0))
self.screen.blit(self.font.render(strftime("%H:%M %d/%m/%Y", gmtime()), True, white), (width - 590, height - 377))
pygame.display.update()
def clean(self):
self.screen.fill((black))
pygame.display.update()
if __name__ == '__main__':
def start():
Pan3.printData()
time.sleep(5)
Pan3.clean()
Pan3 = screen()
threading.Thread(target=start).start()
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit(); sys.exit();
if event.type == pygame.MOUSEBUTTONDOWN:
print 'Event! Mouse Down! Code here....'
A timer may suit your needs, given that you also use threading.
EDIT: Addressing your needs for a more detailed explanation as to how to get it to work, here's some pseudo-code.
if event.type == pygame.MOUSEBUTTONDOWN:
if active_timer:
timer.cancel()
timer = Timer(5.0, show_info_things)
timer.start()
I hope this gets you going well enough.
When you click left mouse first time then it shows date, when you click second time then it hides date. If you don't click second time then it hides automatically after 5 seconds.
The same with key SPACE - first press shows, second hides. If you don't press second time then it hides automatically after 5 seconds.
Key ESC and right click hides too.
import pygame
import sys
import time
# --- constants --- (UPPER_CASE names)
WHITE = (255,255,255)
BLACK = ( 0, 0, 0)
BLUE = ( 0, 0,255)
WIDTH = 600
HEIGHT = 400
# --- classes --- (CamelCase names)
class Screen(object):
def __init__(self):
pygame.init()
self.screen = pygame.display.set_mode((WIDTH, HEIGHT), 0, 32)
pygame.display.set_caption('PyTV')
self.font = pygame.font.SysFont('Arial', 25)
self.channel = '0001'
self.name = 'Channel 3'
self.show_data = None
self.current_time = pygame.time.get_ticks()
def draw_data(self):
self.rect = pygame.draw.rect(self.screen, BLUE, (0, 0, WIDTH, HEIGHT-350), 0)
self.screen.blit(self.font.render(self.channel, True, WHITE), (WIDTH-590, 0))
self.screen.blit(self.font.render(self.name, True, WHITE), (HEIGHT-335, 0))
self.screen.blit(self.font.render(time.strftime("%H:%M:%S %d/%m/%Y", time.gmtime()), True, WHITE), (WIDTH-590, HEIGHT-377))
def events(self):
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
return False
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_ESCAPE:
self.show_data = None
elif event.key == pygame.K_SPACE:
if self.show_data:
self.show_data = None
else:
self.show_data = self.current_time + 5000
if event.type == pygame.MOUSEBUTTONDOWN:
if event.button == 1:
if self.show_data:
self.show_data = None
else:
self.show_data = self.current_time + 5000
elif event.button == 3:
# hide on right click
self.show_data = None
def update(self):
# if displayed
if self.show_data:
# check time
if self.current_time >= self.show_data:
# hide after time
self.show_data = None
def draw(self):
self.screen.fill(BLACK)
if self.show_data:
self.draw_data()
pygame.display.update()
def run(self): # mainloop
while True:
self.current_time = pygame.time.get_ticks()
if self.events() is False:
break
self.update()
self.draw()
#sys.exit()
# --- fucntions --- (lower_case names)
# empty
# --- main ---
if __name__ == '__main__':
Screen().run()