SGC GUI and Pygame Widget implementation - python

Hi I am trying to code a simple application with Pygame. I have made various searches and found that best way to get an user input is to use a 3rd Party GUI.
I have found Simple Game Code for this aim. Below, you can find my base code, it looks for the images inside same path of script and replaces them in order at screen.
But I have no experience with this kind of applications. I am trying to understand from the documentation of SGC: https://github.com/codetricity/sgc/blob/master/example/test.py
It is not an easy task for me. I could develop this far, my code is running. But I couldn't understand the button implementation part.
Can you help me implement a "Scale Widget" at beginning to get user input between a range of integers. Also, a "Button Widget" to pass starting screen and begin my main code I will share with you.
Thanks for your time
import glob
import time
import numpy as np
import timeit
import pygame
import sgc
from sgc.locals import *
start = timeit.default_timer()
maxnote = 10
maxduration = 10
pygame.init()
white = (255, 255, 255)
path = r'C:\Path'
mylistname = [f for f in sorted(glob.glob("*.png"))]
mylistpath = [f for f in sorted(glob.glob(path + "/*.png"))]
for i in range(len(mylistname)):
mylistname[i] = mylistname[i].replace(".png", "")
mylistname[i] = mylistname[i].replace("h", ".")
mylistname[i] = float(mylistname[i])
imgname = []
for i in range(len(mylistname)):
imgname.append(str("img" + str(mylistname[i])))
imglist = []
for i in range(len(mylistpath)):
name = str(imgname[i])
name = pygame.image.load(mylistpath[i])
imglist.append(name)
current_image = 0
display_surface = pygame.display.set_mode((400, 400))
while (timeit.default_timer() - start < maxduration) | (current_image < maxnote):
#for imj in range(len(imglist)+1):
print(str(current_image) + "s")
if current_image < len(imglist):
print(str(current_image) + "0")
while True:
print(str(current_image) + "p")
display_surface.fill(white)
display_rect = display_surface.get_rect()
image_rect = imglist[current_image].get_rect()
image_rect.center = display_rect.center
display_surface.blit(imglist[current_image],image_rect)
pygame.display.update()
pygame.display.flip()
time.sleep(5)
current_image = current_image + 1
print(str(current_image) + "n")
break
else:
font = pygame.font.Font('freesansbold.ttf', 32)
text = font.render('GeeksForGeeks', True, (0, 255, 0), (0, 0, 128))
textRect = text.get_rect()
textRect.center = display_rect.center
display_surface.blit(text, textRect)
pygame.display.update()
pygame.display.flip()
time.sleep(5)
pygame.display.quit()
print("the end")

Using your code I added SGC button which is displayed on images and it display text in console when it is clicked.
I had two problems:
SGC is old and works only with Python 2. For Python 3 it would need relative imports. But later it may need other changes.
time.sleep() was blocking loop which checks key/mouse events, updates widgets, runs function when button is clicked, etc. sleep makes this problem with all GUI frameworks (tkinter, PyQt, wxpython, etc.) and in PyGame loop which has to run all time to check and update widgets and other elements. I use clock to check if it is time to change image. This way loop can works all time and it can update Button when mouse move on button and click it.
Tested on Python 2.7, Linux Mint 19.2
import glob
import pygame
import time
import sgc
from sgc.locals import *
# --- constants --- (UPPER_CASE)
WHITE = (255, 255, 255)
MAXNOTE = 10
MAXDURATION = 10
PATH = r'C:\Path'
# --- functions --- (lower_case_names)
def on_click_button():
print('on_click_button')
# --- main ---
filenames = sorted(glob.glob(PATH + "/*.png"))
print('len:', len(filenames))
names = []
images = []
for item in filenames:
names.append("img" + item.replace(".png", "").replace("h", "."))
images.append(pygame.image.load(item))
current_image = 0
# ---
pygame.init()
display_surface = sgc.surface.Screen((400, 400))
#display_surface = pygame.display.set_mode((400, 400))
display_rect = display_surface.get_rect()
font = pygame.font.Font('freesansbold.ttf', 32)
# add button
btn = sgc.Button(label="Clicky", pos=(10, 10))#, label_font=font)
btn.add(0)
# assign function to button
btn.on_click = on_click_button
# ---
clock = pygame.time.Clock()
current_time = pygame.time.get_ticks()
end_time = current_time + MAXDURATION*1000
end_slide = current_time
running = True
while running and ((current_time < end_time) or (current_image < MAXNOTE)):
ticks = clock.tick(30)
for event in pygame.event.get():
# send events to SGC so it can check if button was clicke
sgc.event(event)
if event.type == pygame.QUIT:
running = False
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_ESCAPE:
running = False
current_time = pygame.time.get_ticks()
if (end_slide <= current_time) and (current_image < len(images)):
image = images[current_image]
image_rect = image.get_rect()
image_rect.center = display_rect.center
end_slide = current_time + 2000 # 2000ms (2s)
current_image += 1
display_surface.fill(WHITE)
display_surface.blit(image, image_rect)
# draw all widgets
sgc.update(ticks)
pygame.display.flip() # doesn't need pygame.display.update() because both do the same
# ---
display_surface.fill(WHITE)
text = font.render('GeeksForGeeks', True, (0, 255, 0), (0, 0, 128))
text_rect = text.get_rect()
text_rect.center = display_rect.center
display_surface.blit(text, text_rect)
#pygame.display.update() # no need it
pygame.display.flip()
time.sleep(5)
# --- end ---
pygame.display.quit()
print("the end")

Related

Is there a way to get pygame to detect what color my cursor is on

I'm trying to make a game where it spawns another circle every time you click on a circle. And the error i'm getting is "TypeError: 'bool' object is not callable". I'm looking for a solution that doesn't completly change the code since i'm new and want to understand the code myself. But at this point i'll take any help.
import pygame
import random
import time
from pygame.math import Vector2
# Define some colors
BLACK = (0, 0, 0)
WHITE = (247, 247, 247)
GREEN = (0, 255, 0)
RED = (255, 0, 0)
YELLOW = (225,225,0)
tuple1 = (247, 247, 247, 255)
# Setup
pygame.init()
# Set the width and height of the screen [width,height]
surface = pygame.display.set_mode( (2560, 1440) )
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()
# Hide the mouse cursor
pygame.mouse.set_visible(0)
# Speed in pixels per frame
x_speed = 0
y_speed = 0
# Current position
cursor = pygame.image.load('cursor.png').convert_alpha()
pygame.image.load("pattern.jpg")
background_image = pygame.image.load("pattern.jpg").convert()
circposy = 770
circposx = 1280
# -------- Main Program Loop -----------
while done ==False:
# --- Event Processing
for event in pygame.event.get():
if event.type == pygame.QUIT:
done = True
if event.type == pygame.MOUSEBUTTONDOWN:
done = True
for event in pygame.event.get():
if event.type == pygame.QUIT:
done = True
# --- Drawing Code
surface.fill(WHITE)
# First, clear the screen to WHITE. Don't put other drawing commands
# above this, or they will be erased with this command.\
player_position = pygame.mouse.get_pos()
a = 0
b = 1
p=player_position[a]
o=player_position[b]
player_position = (p,o)
pygame.draw.circle(surface,RED,[circposx,circposy], 40)
tuple2 = surface.get_at(pygame.mouse.get_pos())
print (tuple2)
q = p - 2545
w = o - 2545
surface.blit( cursor, (q, w) )
a=0
result = tuple(map(int, tuple2)) > tuple1
print (result)
while event.type == pygame.MOUSEBUTTONDOWN:
done = True
if result == True():
a+1
surface.fill(WHITE)
pygame.draw.circle(surface,RED,[circposx + randint, circposy+randint],40)
print (a)
# Go ahead and update the screen with what we've drawn.
pygame.display.flip()
# Limit frames per second
clock.tick(144)
# Close the window and quit.
pygame.quit()
cursor.png
The short answer is that the code is trying to call True(), which isn't a function.
while event.type == pygame.MOUSEBUTTONDOWN:
done = True
if result == True(): # <<-- HERE
a+1
surface.fill(WHITE)
pygame.draw.circle(surface,RED,[circposx + randint, circposy+randint],40)
Simply change this to True.
But you will also need to define what randint is a few lines lower. Did you mean random.randint( 0, 500 ) or suchlike? And fixing this leads to another error, because the surrounding loop to this code, is an infinite loop:
while event.type == pygame.MOUSEBUTTONDOWN: # <<-- HERE
done = True
if result == True:
a+1
surface.fill(WHITE)
rand_x = random.randint( 0, 500 )
rand_y = random.randint( 0, 500 )
pygame.draw.circle(surface,RED,[circposx + rand_x, circposy+rand_y],40)
Because there is no way event.type can ever change inside that loop. This should probably read:
if event.type == pygame.MOUSEBUTTONDOWN:
If I may make some suggestions:
Put all your event handling to a single place.
There's some doubling-up of event handling, and it would have prevented that infinite loop.
Move your screen dimensions into variables
SCREEN_WIDTH = 2560
SCREEN_HEIGHT = 1440
Instead of having constant numbers through the code (e.g.: 2545) make these functions of the screen size.
SCREEN_MARGIN = SCREEN_WIDTH - round( SCREEN_WIDTH * 0.10 )
q = p - SCREEN_MARGIN
If you want to detect what color your cursor is on, you can use pyautogui. Make sure you have pyautogui installed. type pip install pyautogui. If it doesn't install successfully, you already have it installed.
# Import everything
import pygame
import pyautogui
from pyautogui import *
# Initialize
pygame.init()
# Get mouse position
mouse_pos = pygame.mouse.get_pos()
x = mouse_pos[0]
y = mouse_pos[1]
# Get Color
r = pyautogui.pixel(x,y)[0]
g = pyautogui.pixel(x,y)[1]
b = pyautogui.pixel(x,y)[2]
color = [r,g,b]
Hopefully, you found this helpful!

pygame.time.wait() crashes the program

In a pygame code I wannted to do a title that changes colors.
I tried to do a simple title that changes colors, but it not even turned the color to blue (or do it for a second), and the program crash. The code:
title_font = pygame.font.SysFont("monospace", TITLE_SIZE)
while True:
title = title_font.render("game", 5, RED)
game_display.blit(title, TITLE_POS)
pygame.display.update()
pygame.time.wait(2000)
title = title_font.render("game", 5, BLUE)
game_display.blit(title, TITLE_POS)
pygame.display.update()
pygame.time.wait(3000)
title = title_font.render("game", 5, RED)
game_display.blit(title, TITLE_POS)
pygame.display.update()
pygame.time.wait(2000)
It also happens with pygame.time.delay(), and I don't know where is the problem...
Don't use pygame.time.wait or delay because these functions make your program sleep for the given time and the window becomes unresponsive. You also need to handle the events (with one of the pygame.event functions) each frame to avoid this.
Here are some timer examples which don't block: Countdown timer in Pygame
To switch the colors, you can just assign the next color to a variable and use it to render the text.
import pygame
pygame.init()
screen = pygame.display.set_mode((640, 480))
clock = pygame.time.Clock()
title_font = pygame.font.SysFont('monospace', 50)
BACKGROUND_COLOR = pygame.Color('gray12')
BLUE = pygame.Color('blue')
RED = pygame.Color('red')
# Assign the current color to the color variable.
color = RED
timer = 2
dt = 0
done = False
while not done:
# Handle the events.
for event in pygame.event.get():
# This allows the user to quit by pressing the X button.
if event.type == pygame.QUIT:
done = True
timer -= dt # Decrement the timer by the delta time.
if timer <= 0: # When the time is up ...
# Swap the colors.
if color == RED:
color = BLUE
timer = 3
else:
color = RED
timer = 2
screen.fill(BACKGROUND_COLOR)
title = title_font.render('game', 5, color)
screen.blit(title, (200, 50))
pygame.display.flip()
# dt is the passed time since the last clock.tick call.
dt = clock.tick(60) / 1000 # / 1000 to convert milliseconds to seconds.
pygame.quit()

Blit user text input to screen

I want to blit text that is input by the user to the screen. Each time the user presses Return, the typed text should be blitted to the screen. For text input I use this [text_input module] (https://github.com/Nearoo/pygame-text-input).
Here is the code I came up with so far:
import pygame_textinput
import pygame
pygame.init()
# Set some parameters
duration = 5.0
time = pygame.time.get_ticks()/1000
screen = pygame.display.set_mode((400, 400))
clock = pygame.time.Clock()
yoffset = 5
# Function that positions user input rects on screen
def renderInput(text, xoffset, yoffset):
font = pygame.font.SysFont("arial", 20)
renderText = font.render(text, False, (0, 0, 0))
rectText = renderText.get_rect()
rectText = rectText.move((0 + xoffset), (screen.get_height()/2 + yoffset))
return renderText, rectText
# Fills the screen once at the beginning
screen.fill((225, 225, 225))
while (pygame.time.get_ticks()/1000) < time + duration:
# creat new text input object on every trial
textinput = pygame_textinput.TextInput()
while True:
# Fills the surface after each keypress
screen.fill((225, 225, 225))
# Check events
events = pygame.event.get()
for event in events:
if event.type == pygame.QUIT:
exit()
# Feed with events every frame
# This evaluates to True once Return is pressed
if textinput.update(events):
userInput = textinput.get_text()
yoffset += 20
break
# Blit surface onto the screen
screen.blit(textinput.get_surface(), (10, 10))
# Update screen
pygame.display.update()
clock.tick(30)
# Blits user input to screen each time "Return" is pressed
# First get input text and the rectangle of the text
text, textrect = renderInput(userInput, 5, yoffset)
# Then blit it to the screen
screen.blit(text, textrect)
pygame.display.update()
My problem is, that the blitting only works if I do not fill the screen after each keypress within the while-loop that handles the input. If I do that, then the text input, however, is not cleared after each time the user presses Return.
So is there a way to have both, redraw after each keypress and have the text displayed below after each time Return is pressed by the user.
Thanks.
If I understand you correctly, the text in the input field should be cleared and it should be blit in the main area of the screen. I'd assign the text to the user_input variable if the user presses enter and then create a new pygame_textinput.TextInput() instance to clear the input field.
I've tried to simplify your code, because the two while loops are a bit confusing and I'm not sure what their purpose is. There should usually be only one while loop in a game.
import pygame
import pygame_textinput
pygame.init()
screen = pygame.display.set_mode((400, 400))
clock = pygame.time.Clock()
font = pygame.font.SysFont("arial", 20)
textinput = pygame_textinput.TextInput()
user_input = ''
done = False
while not done:
events = pygame.event.get()
for event in events:
if event.type == pygame.QUIT:
done = True
if textinput.update(events):
user_input = textinput.get_text()
textinput = pygame_textinput.TextInput()
# Draw everything.
screen.fill((225, 225, 225))
screen.blit(textinput.get_surface(), (10, 10))
user_input_surface = font.render(user_input, True, (30, 80, 100))
screen.blit(user_input_surface, (10, 50))
pygame.display.update()
clock.tick(30)
pygame.quit()
Edit: In this version I append the rendered text surfaces to a list and blit them with an offset.
import pygame
import pygame_textinput
pygame.init()
screen = pygame.display.set_mode((400, 400))
clock = pygame.time.Clock()
font = pygame.font.SysFont("arial", 20)
textinput = pygame_textinput.TextInput()
user_inputs = []
done = False
while not done:
events = pygame.event.get()
for event in events:
if event.type == pygame.QUIT:
done = True
if textinput.update(events):
user_inputs.append(
font.render(textinput.get_text(), True, (30, 80, 100)))
textinput = pygame_textinput.TextInput()
screen.fill((225, 225, 225))
screen.blit(textinput.get_surface(), (10, 10))
for y, text_surf in enumerate(user_inputs):
screen.blit(text_surf, (10, 50+30*y))
pygame.display.update()
clock.tick(30)
pygame.quit()
Edit2: To get a table, you can use modulo for the row offset and floor division for the column offset. The problem with this example is that the text surfaces can overlap if they are too wide.
for n, text_surf in enumerate(user_inputs):
# 5 rows. Offset = 30 pixels.
y_pos = 50 + (n%5) * 30
# After 5 rows add a new column. Offset = 100 pixels.
x_pos = 10 + n // 5 * 100
screen.blit(text_surf, (x_pos, y_pos))
I have edited my code containing your suggestions. Thanks a lot, this really seems to solve my problem. Here is the current version including a timer:
import pygame_textinput
import pygame
pygame.init()
# Set some parameters
duration = 5.0
time = pygame.time.get_ticks()/1000
xoffset = 5
yoffset = 5
screen = pygame.display.set_mode((400, 400))
font = pygame.font.SysFont("arial", 20)
clock = pygame.time.Clock()
# Creates textinput instance and an empty list to store inputs
textinput = pygame_textinput.TextInput()
userInputs = []
# Fills the screen once at the beginning
screen.fill((225, 225, 225))
while (pygame.time.get_ticks()/1000) < time + duration:
# Check events
events = pygame.event.get()
for event in events:
if event.type == pygame.QUIT:
exit()
# Feed with events every frame
# This evaluates to True once Return is pressed
if textinput.update(events):
userInputs.append(font.render(textinput.get_text(), True, (30, 80, 100)))
textinput = pygame_textinput.TextInput()
# Fill screen
screen.fill((225, 225, 225))
# Blit its surface onto the screen
screen.blit(textinput.get_surface(), (screen.get_rect().centerx, screen.get_rect().height/5))
for y, text_surf in enumerate(userInputs):
screen.blit(text_surf, (10, (screen.get_rect().height/4)+30*y))
# Update screen
pygame.display.update()
clock.tick(30)
I do not want to bother you to much, but now I have one more issue left that I am having trouble solving. Is it possible to render the text inputs in a second column once it exits the bottom border of the screen? So for example, if the user types a lot of words, that do not fit under each other, is it possible to move the next text input to the right and make it start next to the first input (create a second column so to speak). Thanks for your help so far, I really apreciatie it.

Typewriter Effect Pygame

This question is really difficult to ask, but I know you guys here at Stack Overflow are the brightest minds.
I'm totally blinded by why this issue happens (I'm fairly at Python and Pygame, so any suggestions on how to improve the code will be received with the love of improving my skills).
What I'm creating:
It's really a gimmick project, I have a little 2.5" screen (PiTFT) attached to a Raspberry Pi and the code is creating a typewriter effect with a moving cursor in front of the text as it's being written.
Challenge 1 was that every time you move a sprite in pygame, you must redraw everything, otherwise you will see a trail, and since the cursor is moving in front of the text, the result would look like this:
I managed to solve this issue by blackening / clearing the screen. But then I lost all the previously written letters.
So I created a list (entireword), which I'm populing with all the previously written characters. I use this list every time I cycle through the loop to redraw all the previous written text.
So now:
As you can see, the text looks funny.
It's supposed to read:
[i] Initializing ...
[i] Entering ghost mode ... []
I've been spending hours and hours getting to this point - and the code ALMOST works perfectly! The magic happens in the function print_screen(), but WHAT in my code is causing the text to include a letter from the other line in the end? :>
Help is GREATLY appreciated <3
Here's the entire code:
import pygame
import time
import os
import sys
from time import sleep
from pygame.locals import *
positionx = 10
positiony = 10
entireword = []
entireword_pos = 10
counter = 0
entire_newline = False
#Sets the width and height of the screen
WIDTH = 320
HEIGHT = 240
speed = 0.05
#Importing the external screen
os.putenv('SDL_FBDEV', '/dev/fb1')
os.putenv('SDL_MOUSEDRV', 'TSLIB')
os.putenv('SDL_MOUSEDEV', '/dev/input/touchscreen')
#Initializes the screen - Careful: all pygame commands must come after the init
pygame.init()
#Sets mouse cursor visibility
pygame.mouse.set_visible(False)
#Sets the screen note: must be after pygame.init()
screen = pygame.display.set_mode((WIDTH, HEIGHT))
# initialize font; must be called after 'pygame.init()' to avoid 'Font not Initialized' error
myfont = pygame.font.SysFont("monospace", 18)
#Class
class cursors(pygame.sprite.Sprite):
def __init__(self):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.Surface((10, 20))
self.image.fill((0,255,0))
self.rect = self.image.get_rect()
self.rect.center = (positionx + 10, positiony + 10)
def update(self):
self.rect.x = positionx + 10
self.rect.y = positiony
#Functions
#Prints to the screen
def print_screen(words, speed):
rel_speed = speed
for char in words:
#speed of writing
if char == ".":
sleep(0.3)
else:
sleep(rel_speed)
#re-renders previous written letters
global entireword
# Old Typewriter functionality - Changes position of cursor and text a newline
#Makes sure the previous letters are rendered and not lost
#xx is a delimter so the program can see when to make a newline and ofcourse ignore writing the delimiter
entireword.append(char)
if counter > 0:
loopcount = 1
linecount = 0 # This is to which line we are on
for prev in entireword:
if prev == 'xx':
global linecount
global positiony
global loopcount
linecount = linecount + 1
positiony = 17 * linecount
loopcount = 1
if prev != 'xx': #ignore writing the delimiter
pchar = myfont.render(prev, 1, (255,255,0))
screen.blit(pchar, (loopcount * 10, positiony))
loopcount = loopcount + 1
if char != 'xx':
# render text
letter = myfont.render(char, 1, (255,255,0))
#blits the latest letter to the screen
screen.blit(letter, (positionx, positiony))
# Appends xx as a delimiter to indicate a new line
if entire_newline == True:
entireword.append('xx')
global entire_newline
entire_newline = False
global positionx
positionx = positionx + 10
all_sprites.update()
all_sprites.draw(screen)
pygame.display.flip()
screen.fill((0,0,0)) # blackens / clears the screen
global counter
counter = counter + 1
#Positions cursor at new line
def newline():
global positionx
global positiony
positionx = 10
positiony = positiony + 17
all_sprites = pygame.sprite.Group()
cursor = cursors()
all_sprites.add(cursor)
#Main loop
running = True
while running:
global speed
global entire_newline
words = "[i] Initializing ..."
entire_newline = True
newline()
print_screen(words,speed)
words = "[i] Entering ghost mode ..."
entire_newline = True
newline()
print_screen(words,speed)
#Stops the endless loop if False
running = False
sleep(10)
Sorry if I don't answer your question directly, because your code is too confusing for me now, so I took the liberty to rewrite your code to get done what you want.
The idea is to have two sprites:
the cursor, which is a) displayed on the screen and b) keeps track of what text to write and where
the board, which is basically just a surface that the text is rendered on
Note how all the writing logic is on the Cursor class, and we have a nice, simple and dumb main loop.
import pygame
import os
#Sets the width and height of the screen
WIDTH = 320
HEIGHT = 240
#Importing the external screen
os.putenv('SDL_FBDEV', '/dev/fb1')
os.putenv('SDL_MOUSEDRV', 'TSLIB')
os.putenv('SDL_MOUSEDEV', '/dev/input/touchscreen')
#Initializes the screen - Careful: all pygame commands must come after the init
pygame.init()
clock = pygame.time.Clock()
#Sets mouse cursor visibility
pygame.mouse.set_visible(False)
#Sets the screen note: must be after pygame.init()
screen = pygame.display.set_mode((WIDTH, HEIGHT))
class Board(pygame.sprite.Sprite):
def __init__(self):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.Surface((WIDTH, HEIGHT))
self.image.fill((13,13,13))
self.image.set_colorkey((13,13,13))
self.rect = self.image.get_rect()
self.font = pygame.font.SysFont("monospace", 18)
def add(self, letter, pos):
s = self.font.render(letter, 1, (255, 255, 0))
self.image.blit(s, pos)
class Cursor(pygame.sprite.Sprite):
def __init__(self, board):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.Surface((10, 20))
self.image.fill((0,255,0))
self.text_height = 17
self.text_width = 10
self.rect = self.image.get_rect(topleft=(self.text_width, self.text_height))
self.board = board
self.text = ''
self.cooldown = 0
self.cooldowns = {'.': 12,
'[': 18,
']': 18,
' ': 5,
'\n': 30}
def write(self, text):
self.text = list(text)
def update(self):
if not self.cooldown and self.text:
letter = self.text.pop(0)
if letter == '\n':
self.rect.move_ip((0, self.text_height))
self.rect.x = self.text_width
else:
self.board.add(letter, self.rect.topleft)
self.rect.move_ip((self.text_width, 0))
self.cooldown = self.cooldowns.get(letter, 8)
if self.cooldown:
self.cooldown -= 1
all_sprites = pygame.sprite.Group()
board = Board()
cursor = Cursor(board)
all_sprites.add(cursor, board)
text = """[i] Initializing ...
[i] Entering ghost mode ...
done ...
"""
cursor.write(text)
#Main loop
running = True
while running:
for e in pygame.event.get():
if e.type == pygame.QUIT:
running = False
all_sprites.update()
screen.fill((0, 0, 0))
all_sprites.draw(screen)
pygame.display.flip()
clock.tick(60)
Use the pygame.event module. Use pygame.time.set_timer() to repeatedly create a USEREVENT in the event queue. The time has to be set in milliseconds. e.g.:
typewriter_event = pygame.USEREVENT+1
pygame.time.set_timer(typewriter_event, 100)
Add a new letter to the text, when the timer event occurs:
while run:
for event in pygame.event.get():
# [...]
if event.type == typewriter_event:
text_len += 1
See also Typewriter
Minimal example:
repl.it/#Rabbid76/PyGame-Typewriter
import pygame
pygame.init()
window = pygame.display.set_mode((500, 150))
clock = pygame.time.Clock()
font = pygame.font.SysFont(None, 100)
background = pygame.Surface(window.get_size())
ts, w, h, c1, c2 = 50, *window.get_size(), (32, 32, 32), (64, 64, 64)
tiles = [((x*ts, y*ts, ts, ts), c1 if (x+y) % 2 == 0 else c2) for x in range((w+ts-1)//ts) for y in range((h+ts-1)//ts)]
for rect, color in tiles:
pygame.draw.rect(background, color, rect)
text = 'Hello World'
text_len = 0
typewriter_event = pygame.USEREVENT+1
pygame.time.set_timer(typewriter_event, 100)
text_surf = None
run = True
while run:
clock.tick(60)
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
if event.type == typewriter_event:
text_len += 1
if text_len > len(text):
text_len = 0
text_surf = None if text_len == 0 else font.render(text[:text_len], True, (255, 255, 128))
window.blit(background, (0, 0))
if text_surf:
window.blit(text_surf, text_surf.get_rect(midleft = window.get_rect().midleft).move(40, 0))
pygame.display.flip()
pygame.quit()
exit()

PyGame Conway's Game of Life, redraw sprites

When I update my array of which image the program should use for each location, I can place alive cells over dead, but the original doesn't go away and I can't add dead cells over live ones. Does anyone have a fix?
Original File
import pygame, pygamehandle, standard, sys
from pygame.locals import *
loader = pygamehandle.load()
pygame.mixer.music.load('music1.ogg')
pygame.mixer.music.play(-1, 0.0)
SCREEN_SIZE = (600, 400)
fps = 24
fpsClock = pygame.time.Clock()
imgs = ["live.png", "dead.png", "background.png"]
icon = "icon.png"
screen = loader.loadScreen(SCREEN_SIZE, "Game of Life", icon)
lImgs = loader.listImgLoad(imgs)
objects, grid = loader.grid(SCREEN_SIZE, lImgs[1])
loader.blit(objects, grid)
pygame.display.update()
while True:
mouseClicked = False
fpsClock.tick(fps)
for i in pygame.event.get():
if i.type == MOUSEBUTTONDOWN:
if i.button == 1:
mouseposx, mouseposy = pygame.mouse.get_pos()
mouseposx = (mouseposx // 20) * 20
mouseposy = (mouseposy // 20) * 20
mousepos = (mouseposx, mouseposy)
index = grid.index(mousepos)
objects[index] = lImgs[0]
if i.button == 2:
mouseposx, mouseposy = pygame.mouse.get_pos()
mouseposx = (mouseposx // 20) * 20
mouseposy = (mouseposy // 20) * 20
mousepos = (mouseposx, mouseposy)
index = grid.index(mousepos)
objects[index] = lImgs[1]
if i.type == QUIT:
pygame.quit()
sys.exit()
pygame.Surface.fill(screen, [0, 0, 0])
loader.blit(objects, grid)
pygame.display.flip()
I also used these functions from the pygamehandle file.
import pygame, standard
class load(object):
pygame.init()
def loadScreen(self, size, text, icon):
pygame.display.set_caption(text, icon)
pygame.display.set_icon(pygame.image.load(icon))
screen = pygame.display.set_mode(size)
self.screen = screen
return screen
def listImgLoad(self, list):
img = []
for i in range (0, len(list)):
img.append(pygame.image.load(list[i]).convert())
return img
def blit(self, items, locations):
for i in range (0, len(items)):
self.screen.blit(items[i], locations[i])
def grid(self, size, object):
objects =[]
locations = []
x, y = size
for xT in range (0, int(x / 20)):
for yT in range(0, int(y / 20)):
objects.append(object)
locations.append((xT * 20, yT * 20))
return objects, locations
A better way to do this is make a Sprite class for each cell, add a bool to deteermine if the cell is dead or alive and blit accordingly.
If you are familiar with Sprites here is the docs, It may be confusing at first but they will help in making more complex games, also here is a link to my version of The Game of Life
Goodluck

Categories