How to STOP generating numbers - python

I have made a code that renders 2 different random numbers on screen, but it justs keep updating the numbers. I want the program to stop updating those numbers once the first 2 appear on screen. Here is the code:
import pygame
import random
pygame.init()
clock = pygame.time.Clock()
surface = pygame.display.set_mode((600, 400))
pygame.display.set_caption("Projecte MatZanfe")
font = pygame.font.SysFont('comicsans', 50)
base_font = pygame.font.Font(None, 32)
user_text = ''
color_active = pygame.Color('lightskyblue3')
def start_the_game():
# Variables
is_correct = False
points = 0
x = random.randint(0,10)
y = random.randint(0,10)
z = x + y
surface.fill((255,70,90))
text = font.render (str(x) + "+" + str(y), True, (255,255,255))
input_rect = pygame.Rect(200,200,180,50)
pygame.draw.rect(surface,color_active,input_rect)
text_surface = base_font.render(user_text,True,(255,255,255))
surface.blit(text_surface, input_rect)
surface.blit(text,(260,120))
input_rect.w = max(100,text_surface.get_width()+10)
running = True
while running:
clock.tick(60)
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
start_the_game()
pygame.display.update()
pygame.quit()
Maybe using an if statement would be the solution, but I can't figure out where and what should I introduce to the code. How would you do it?

As #jasonharper suggested, you probably are better off with two functions, one to initialize things and another to display the game:
def start_the_game():
x = random.randint(0, 10)
y = random.randint(0, 10)
return x, y
def display_the_game(x, y):
# Variables
is_correct = False
points = 0
z = x + y
surface.fill((255, 70, 90))
text = font.render(str(x) + "+" + str(y), True, (255, 255, 255))
input_rect = pygame.Rect(200, 200, 180, 50)
pygame.draw.rect(surface, color_active, input_rect)
text_surface = base_font.render(user_text, True, (255, 255, 255))
surface.blit(text_surface, input_rect)
surface.blit(text, (260, 120))
input_rect.w = max(100, text_surface.get_width() + 10)
x, y = start_the_game()
while running:
clock.tick(60)
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
display_the_game(x, y)
pygame.display.update()
pygame.quit()
By putting random.randint in a function outside the loop, it will only be called once.

Related

Duplicates of squares going in the wrong direction pygame

The program is supposed to make 3 squares and move them to the right. That works well. However, there are 2 squares that move down even though there are no functions to do that. there are only 3 square creating functions but there are 2 more that appear
import pygame
import random
import time
enemyCoordList = []
pygame.init()
rand = random.Random()
screen = pygame.display.set_mode((1000, 600))
px = 30
py = 30
def enemy(x, y, sizex=30, sizey=30, health=0, speed=6,):
# pygame.draw.rect(screen, (0, 255, 0), pygame.Rect(x, y, sizex, sizey))
enemyCoordList.append(x)
enemyCoordList.append(y)
def drawEnemy():
for l in range(len(enemyCoordList)-1):
# print(range(len(enemyCoordList)))
pygame.draw.rect(screen, (0, 255, 0), pygame.Rect(enemyCoordList[l], enemyCoordList[l+1], 50, 50))
enemy(30, 30)
enemy(50, 50)
enemy(100,100)
print(enemyCoordList)
run = True
while run:
time.sleep(0.05)
screen.fill((9, 68, 43))
drawEnemy()
for i in range(len(enemyCoordList)):
#print(i)
if i % 2 != 0:
#print(i)
continue
# print(enemyCoordList)
#print(i)
enemyCoordList[i] += 1
# for i in enemyCoordList:
pygame.display.update()
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
pygame.quit()
A coordinate has 2 components so:
for l in range(len(enemyCoordList)-1):
for l in range(0, len(enemyCoordList), 2):
Correct drawEnemy function:
def drawEnemy():
for l in range(0, len(enemyCoordList), 2):
pygame.draw.rect(screen, (0, 255, 0), pygame.Rect(enemyCoordList[l], enemyCoordList[l+1], 50, 50))
However, it would be much easier to work with a list of coordinate pairs (list of lists):
import pygame
import random
import time
pygame.init()
rand = random.Random()
screen = pygame.display.set_mode((1000, 600))
def enemy(x, y, sizex=30, sizey=30, health=0, speed=6):
enemyCoordList.append([x, y])
def drawEnemy():
for x, y in enemyCoordList:
pygame.draw.rect(screen, (0, 255, 0), pygame.Rect(x, y, 50, 50))
enemyCoordList = []
enemy(30, 30)
enemy(50, 50)
enemy(100,100)
print(enemyCoordList)
run = True
while run:
time.sleep(0.05)
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
for pos in enemyCoordList:
pos[0] += 1
screen.fill((9, 68, 43))
drawEnemy()
pygame.display.update()
pygame.quit()

I can't draw all functions with my script

I made a script, which should take the user input of a mathematical function (f(x)=...) and draw it. I used pygame for that because I want to use that mechanic for a game.
I have to run the code of a function once without any output once, but after that, it flawlessly works
heres the code:
import pygame
def replace_x(function):
f = lambda x: eval(function)
return f
def convert_y(y_coords):
y_coords = 540 - y_coords
return y_coords
def convert_x(x_coord):
x_coord = x_coord + 960
return x_coord
# variables
background_colour = (255, 255, 255)
screen = pygame.display.set_mode((1920, 1080))
running = True
current_y = 0
previous_y = 0
pygame.init()
pygame.display.set_caption('Mathe Kreativarbeit')
screen.fill(background_colour)
pygame.display.flip()
function_input = input("Funktion: ")
function_input = function_input.replace("^", "**")
pygame.display.flip()
for x_coords in range(-15, 17):
f = replace_x(function_input)
current_y = convert_y(f(x_coords))
previous_y = convert_y(f(x_coords - 1))
start_pos = (convert_x((x_coords - 1) * 60), previous_y)
end_pos = (convert_x(x_coords * 60), current_y)
print(start_pos)
print(end_pos)
pygame.draw.aaline(screen, (0, 0, 0), start_pos, end_pos)
pygame.display.flip()
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
Create a list of points from the function:
f = replace_x(function_input)
pt_list = []
for x in range(-20, 20):
pt_list.append((x, f(x)))
Either print the list of points:
print(pt_list)
or print the list in a loop:
for pt in pt_list:
print(pt)
Create a list of screen coordinates from the list of point:
coord_list = []
for pt in pt_list:
x = round(convert_x(pt[0] * 20))
y = round(convert_y(pt[1]))
coord_list.append((x, y))
Draw the curve in the application loop with pygame.draw.aalines():
clock = pygame.time.Clock()
running = True
while running:
clock.tick(60)
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
pygame.draw.aalines(screen, (0, 0, 0), False, coord_list)
pygame.display.flip()
pygame.quit()
Example for input x**3:

How to change the rendered numbers on this code

The program consists in generating 2 random numbers, rendering them on screen (with the '+' symbol, because it's a sum) and expecting the user to put the result of the sum on the box entry. The code already has a function that generates 2 random numbers (x and y), and another one that renders them on screen (besides the score). Here is the code:
import pygame
import random
from InputBox import InputBox
pygame.init()
clock = pygame.time.Clock()
surface = pygame.display.set_mode((600, 400))
pygame.display.set_caption("Projecte MatZanfe")
font = pygame.font.SysFont('comicsans', 50)
base_font = pygame.font.Font(None, 32)
user_text = ''
color_active = pygame.Color('lightskyblue3')
running = True
points = 0
def start_the_game():
x = random.randint(0, 10)
y = random.randint(0, 10)
is_correct = False
return x, y
def display_the_game(x, y):
# Variables
z = x + y
surface.fill((255, 70, 90))
text = font.render(str(x) + "+" + str(y), True, (255, 255, 255))
text_surface = base_font.render(user_text, True, (255, 255, 255))
surface.blit(text, (260, 120))
input_box.draw(surface)
punts = font.render("PuntuaciĆ³: " + str(points),True, (255,255,255))
surface.blit(punts, (350,30))
x, y = start_the_game()
input_box = InputBox(190, 250, 200, 32)
while running:
clock.tick(60)
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
else:
result = input_box.handle_event(event)
if result != None:
if int(result) == int(x) + int(y):
# TODO: when the user is right
points = points + 5
start_the_game()
pygame.display.update()
display_the_game(x, y)
pygame.display.update()
else:
# TODO: when the user is wrong
start_the_game
pygame.display.update()
display_the_game(x, y)
pygame.display.update()
display_the_game(x, y)
pygame.display.update()
pygame.quit()
I need the program to generate two new random numbers if the result is right and render them, apart from adding 5 points to the "PuntuaciĆ³" that appears up to the right (done). If the user is wrong, it just needs to generate 2 new random numbers, and render them (the score doesn't have to change).
Here is the code from the imported InputBox.
import pygame
pygame.init()
surface = pygame.display.set_mode((600, 400))
COLOR_INACTIVE = pygame.Color('lightskyblue3')
COLOR_ACTIVE = pygame.Color('dodgerblue2')
FONT = pygame.font.SysFont('comicsans', 32)
base_font = pygame.font.Font(None, 32)
color_active = pygame.Color('lightskyblue3')
user_text = ''
class InputBox:
def __init__(self, x, y, w, h, text=''):
self.rect = pygame.Rect(x, y, w, h)
self.color = COLOR_INACTIVE
self.text = text
self.txt_surface = FONT.render(text, True, self.color)
self.active = False
def handle_event(self, event):
if event.type == pygame.MOUSEBUTTONDOWN:
# If the user clicked on the input_box rect.
if self.rect.collidepoint(event.pos):
# Toggle the active variable.
self.active = not self.active
else:
self.active = False
# Change the current color of the input box.
self.color = COLOR_ACTIVE if self.active else COLOR_INACTIVE
if event.type == pygame.KEYDOWN:
if self.active:
if event.key == pygame.K_RETURN:
user_input = self.text
self.text = ''
self.txt_surface = FONT.render(self.text, True, self.color)
return user_input
elif event.key == pygame.K_BACKSPACE:
self.text = self.text[:-1]
else:
self.text += event.unicode
# Re-render the text.
self.txt_surface = FONT.render(self.text, True, self.color)
def update(self):
# Resize the box if the text is too long.
width = max(200, self.txt_surface.get_width()+10)
self.rect.w = width
def draw(self, screen):
# Blit the text.
screen.blit(self.txt_surface, (self.rect.x+5, self.rect.y+5))
# Blit the rect.
pygame.draw.rect(screen, self.color, self.rect, 2)
def main():
clock = pygame.time.Clock()
input_box2 = InputBox(190, 250, 200, 32)
input_boxes = [input_box2]
done = False
while not done:
for event in pygame.event.get():
if event.type == pygame.QUIT:
done = True
for box in input_boxes:
box.handle_event(event)
for box in input_boxes:
box.update()
surface.fill((255, 70, 90))
for box in input_boxes:
box.draw(surface)
pygame.display.flip()
clock.tick(30)
if __name__ == '__main__':
main()
pygame.quit()
All you have to do is to create new values for x and y and to reset the input box:
while running:
clock.tick(60)
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
else:
result = input_box.handle_event(event)
if result != None:
if int(result) == int(x) + int(y):
points = points + 5
# create new random numbers
x, y = start_the_game()
# reset input box (just create a new box)
input_box = InputBox(190, 250, 200, 32)
display_the_game(x, y)
pygame.display.update()
pygame.quit()

Why can't I type more than 1 letter into my pygame textboxes? [duplicate]

This question already has answers here:
How can I create a text input box with Pygame?
(5 answers)
How to allow the user to type only under certain conditions in pygame? [duplicate]
(3 answers)
Closed 1 year ago.
I want the user to be able to type a name into each of the 2 textboxes when they click on them. Instead what happens is the next letter will always replace the previous letter instead of writing out a new letter onto the screen. For example, if you try to type "mat" then the a will replace the m and the t will replace the a. How do I fix this?
from pygame import *
screen_width = 1400
screen_height = 800
init()
screen = display.set_mode((screen_width, screen_height))
name_font = font.Font(None, 32)
name_1 = ""
name_2 = ""
class Rectangle:
def __init__(self, x, y):
self.name = ""
self.active = False
self.x = x
self.y = y
self.text_surface = name_font.render(self.name, True, (255, 255, 255))
self.rect_width = max(140, 10 + self.text_surface.get_width())
self.input_rect = Rect(x, y, self.rect_width, 32)
self.input_rect.w = self.text_surface.get_width() + 10
self.click_value = 10
def naming(self, player_name):
for e in events:
if e.type == MOUSEBUTTONDOWN:
if self.input_rect.x + self.click_value >= mx >= self.input_rect.x - 10 and self.input_rect.y + 26 >= my >= self.input_rect.y - 10:
self.active = True
else:
self.active = False
if e.type == KEYDOWN:
if self.active:
if e.key == K_BACKSPACE:
player_name = player_name[:-1]
screen.fill((0, 0, 0))
else:
player_name += e.unicode
self.click_value += 7
self.text_surface = name_font.render(player_name, True, (255, 255, 255))
def draw(self, screen):
draw.rect(screen, (0, 0, 0), self.input_rect, 0)
draw.rect(screen, (255, 255, 255), self.input_rect, 2)
self.input_rect.w = self.text_surface.get_width() + 10
screen.blit(self.text_surface, (self.input_rect.x + 5, self.input_rect.y + 5))
rect_1 = Rectangle(200, 200)
rect_2 = Rectangle(200, 400)
while True:
mx, my = mouse.get_pos()
events = event.get()
for e in events:
if e.type == QUIT:
quit()
screen.fill((0, 0, 0))
rect_1.naming(name_1)
rect_1.draw(screen)
rect_2.naming(name_2)
rect_2.draw(screen)
display.update()
time.delay(1)
I think it has something to do with the placement of the name_1 and name_2 variables but I'm not entirely sure.
Pyhton has not concept of in-out parameters. Use the self.name attribute, instead of an argument:
from pygame import *
screen_width = 1400
screen_height = 800
init()
screen = display.set_mode((screen_width, screen_height))
name_font = font.Font(None, 32)
name_1 = ""
name_2 = ""
class Rectangle:
def __init__(self, x, y):
self.name = ""
self.active = False
self.x = x
self.y = y
self.text_surface = name_font.render(self.name, True, (255, 255, 255))
self.rect_width = max(140, 10 + self.text_surface.get_width())
self.input_rect = Rect(x, y, self.rect_width, 32)
self.input_rect.w = self.text_surface.get_width() + 10
self.click_value = 10
def naming(self):
for e in events:
if e.type == MOUSEBUTTONDOWN:
if self.input_rect.x + self.click_value >= mx >= self.input_rect.x - 10 and self.input_rect.y + 26 >= my >= self.input_rect.y - 10:
self.active = True
else:
self.active = False
if e.type == KEYDOWN:
if self.active:
if e.key == K_BACKSPACE:
self.name = self.name[:-1]
screen.fill((0, 0, 0))
else:
self.name += e.unicode
self.click_value += 7
self.text_surface = name_font.render(self.name, True, (255, 255, 255))
return self.name
def draw(self, screen):
draw.rect(screen, (0, 0, 0), self.input_rect, 0)
draw.rect(screen, (255, 255, 255), self.input_rect, 2)
self.input_rect.w = self.text_surface.get_width() + 10
screen.blit(self.text_surface, (self.input_rect.x + 5, self.input_rect.y + 5))
rect_1 = Rectangle(200, 200)
rect_2 = Rectangle(200, 400)
while True:
mx, my = mouse.get_pos()
events = event.get()
for e in events:
if e.type == QUIT:
quit()
screen.fill((0, 0, 0))
name_1 = rect_1.naming()
rect_1.draw(screen)
name_2 = rect_2.naming()
rect_2.draw(screen)
display.update()
time.delay(1)
You can use this code:-
import pygame
import sys
pygame.init()
clock = pygame.time.Clock()
# it will display on screen
screen = pygame.display.set_mode([600, 500])
# basic font for user typed
base_font = pygame.font.Font(None, 32)
user_text = ''
# create rectangle
input_rect = pygame.Rect(200, 200, 140, 32)
# color_active stores color(lightskyblue3) which
# gets active when input box is clicked by user
color_active = pygame.Color('lightskyblue3')
# color_passive store color(chartreuse4) which is
# color of input box.
color_passive = pygame.Color('chartreuse4')
color = color_passive
active = False
while True:
for event in pygame.event.get():
# if user types QUIT then the screen will close
if event.type == pygame.QUIT:
pygame.quit()
sys.exit()
if event.type == pygame.MOUSEBUTTONDOWN:
if input_rect.collidepoint(event.pos):
active = True
else:
active = False
if event.type == pygame.KEYDOWN:
# Check for backspace
if event.key == pygame.K_BACKSPACE:
# get text input from 0 to -1 i.e. end.
user_text = user_text[:-1]
# Unicode standard is used for string
# formation
else:
user_text += event.unicode
# it will set background color of screen
screen.fill((255, 255, 255))
if active:
color = color_active
else:
color = color_passive
# draw rectangle and argument passed which should
# be on screen
pygame.draw.rect(screen, color, input_rect)
text_surface = base_font.render(user_text, True, (255, 255, 255))
# render at position stated in arguments
screen.blit(text_surface, (input_rect.x+5, input_rect.y+5))
# set width of textfield so that text cannot get
# outside of user's text input
input_rect.w = max(100, text_surface.get_width()+10)
# display.flip() will update only a portion of the
# screen to updated, not full area
pygame.display.flip()
# clock.tick(60) means that for every second at most
# 60 frames should be passed.
clock.tick(60)

How to properly Dirty rectangles for simple application: Logic Issue

I am currently just testing the waters with Pygame display as I am extremely new to the module.
Here is the code:
import pygame
pygame.init()
SCALE = 1
display_width = int(1200 * SCALE)
display_height = int(800 * SCALE)
x = (display_width * 0.45)
y = (display_height * 0.8)
transparent = (0, 0, 0, 0)
black = (0, 0, 0)
white = (255, 255, 255)
green = (44, 215, 223)
red = (255, 67, 34)
blue = (77, 77, 77)
count = 0
running = True
box1_image = True
box3_image = True
background = pygame.image.load('C:/Users/Justi/source/repos/03 Game/Game/assets/background.jpg')
dirty_spot = pygame.image.load('C:/Users/Justi/source/repos/03 Game/Game/assets/dirty.png')
background_resized = pygame.transform.scale(dirty_spot, (display_width, display_height))
background_rect = background_resized.get_rect()
gameDisplay = pygame.display.set_mode(background_rect.size)
pygame.display.set_caption("Game 1")
clock = pygame.time.Clock()
dirty_spot_resized = pygame.transform.scale(dirty_spot, (200, 200))
square_dirty_spot = dirty_spot_resized.convert()
rect_dirty_spot = square_dirty_spot.get_rect()
def dirtyspot1(imagex, imagey):
gameDisplay.blit(dirty_spot_resized, (imagex,imagey))
while running:
rects = []
if rects != []:
pygame.display.update(rects)
for event in pygame.event.get():
if event.type == pygame.quit:
running = False
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_r:
running = False
#if box3_image: #Replacing the Bool passing variable with a simple loop count to trigger the else condition
if count < 50:
print("Test 1")
dirtyspot1(0,0)
pygame.display.update()
else:
print("Test 2")
dirty_rect = background.subsurface(rect_dirty_spot)
gameDisplay.blit(dirty_rect, (0,0))
rects.append(pygame.Rect(0,0, 200, 200))
gameDisplay.fill(white)
clock.tick(30)
count += 1
pygame.quit()
quit()
box1_image & box1_image are bool variables to flag certain condition which is passed from another function.
But I have gotten the passing of said variables working by doing a simple test with print("Test 2"). However, when it tries to blit dirty_rect. Nothing changes on the pygame display.
Assets (if needed):
background.jpg
dirty.png
May I check what is missing to properly "remove/delete" the dirty_spot blit? Thank you in advance.
import pygame
pygame.init()
SCALE = 1
display_width = int(1200 * SCALE)
display_height = int(800 * SCALE)
x = (display_width * 0.45)
y = (display_height * 0.8)
transparent = (0, 0, 0, 0)
black = (0, 0, 0)
white = (255, 255, 255)
green = (44, 215, 223)
red = (255, 67, 34)
blue = (77, 77, 77)
count = 0
running = True
box1_image = True
box3_image = True
background = pygame.image.load('background.jpg')
dirty_spot = pygame.image.load('dirty.png')
background_resized = pygame.transform.scale(background, (display_width, display_height))
background_rect = background_resized.get_rect()
gameDisplay = pygame.display.set_mode((display_width, display_height))
pygame.display.set_caption("Game 1")
clock = pygame.time.Clock()
dirty_spot_resized = pygame.transform.scale(dirty_spot, (200, 200))
square_dirty_spot = dirty_spot_resized.convert()
rect_dirty_spot = square_dirty_spot.get_rect()
show_dirt = False
def dirtyspot1(imagex, imagey):
gameDisplay.blit(dirty_spot_resized, (imagex,imagey))
while running:
rects = []
if rects != []:
pygame.display.update(rects)
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_r:
running = False
if event.key == pygame.K_d:
show_dirt = not show_dirt
if event.key == pygame.K_UP:
rect_dirty_spot.y -= 5
if event.key == pygame.K_DOWN:
rect_dirty_spot.y += 5
if event.key == pygame.K_RIGHT:
rect_dirty_spot.x += 5
if event.key == pygame.K_LEFT:
rect_dirty_spot.x -= 5
gameDisplay.blit(background_resized, (0,0))
if show_dirt:
gameDisplay.blit(dirty_spot_resized, rect_dirty_spot)
pygame.display.update()
clock.tick(5)
count += 1
pygame.quit()
quit()
like this? (I changed the FPS to 5 so it takes a while to change)
import pygame
pygame.init()
SCALE = 1
display_width = int(1200 * SCALE)
display_height = int(800 * SCALE)
x = (display_width * 0.45)
y = (display_height * 0.8)
transparent = (0, 0, 0, 0)
black = (0, 0, 0)
white = (255, 255, 255)
green = (44, 215, 223)
red = (255, 67, 34)
blue = (77, 77, 77)
count = 0
running = True
box1_image = True
box3_image = True
background = pygame.image.load('background.jpg')
dirty_spot = pygame.image.load('dirty.png')
background_resized = pygame.transform.scale(background, (display_width, display_height))
background_rect = background_resized.get_rect()
gameDisplay = pygame.display.set_mode(background_rect.size)
pygame.display.set_caption("Game 1")
clock = pygame.time.Clock()
dirty_spot_resized = pygame.transform.scale(dirty_spot, (200, 200))
square_dirty_spot = dirty_spot_resized.convert()
rect_dirty_spot = square_dirty_spot.get_rect()
def dirtyspot1(imagex, imagey):
gameDisplay.blit(dirty_spot_resized, (imagex,imagey))
while running:
rects = []
if rects != []:
pygame.display.update(rects)
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_r:
running = False
gameDisplay.fill(white)
#if box3_image: #Replacing the Bool passing variable with a simple loop count to trigger the else condition
if count < 50:
print("Test 1")
dirtyspot1(0,0)
else:
print("Test 2")
dirty_rect = background.subsurface(rect_dirty_spot)
gameDisplay.blit(dirty_rect, (0,0))
rects.append(pygame.Rect(0,0, 200, 200))
pygame.display.update()
clock.tick(5)
count += 1
pygame.quit()
quit()
I think you have misunderstood things. You can blit one image or surface on top of another, and you build things up like that, then blit them to the display and finally update the display.
You have this line:
background_resized = pygame.transform.scale(dirty_spot, (display_width, display_height))
which I assume should be background not dirty_spot.
I moved the call to display.update() out of the if loop, because you call display.update() last.

Categories