Copying Function - python

I am making a game similar to Adventure Capitialist. The desired outcome is to have multiple "buy buttons". I have a function that creates one, but if I copy and paste, and change coordinates, it still doesn't work. I will put code from before I attempted to copy the function, because I think I was pretty far off from my desired outcome. The Function I want to copy is capitialistOne
import pygame, sys, shelve, pickle
import time as Time
from decimal import Decimal
pygame.init()
WHITE = (255,255,255)
BLACK = (0,0,0)
GREEN = (10, 200, 40)
RED = pygame.Color('red')
DISPLAYSURF = pygame.display.set_mode((460, 720))
clock = pygame.time.Clock()
logo = pygame.image.load('Logo.png')
menu = pygame.image.load('menu.png')
storeBoard = pygame.image.load('storeBoard.png')
loadingBar = pygame.image.load('loadingBar.png')
mainMenu = pygame.image.load('mainMenu.png')
Font1 = pygame.font.SysFont('monaco', 24)
Font2 = pygame.font.SysFont('monaco', 30)
cash = 5
barlength = 102 # the lenght of the growing bar
def buyDraw(amount, minxbuy, minybuy):
buySurface = Font1.render('{0}'.format(amount), True, BLACK)
buyRect = buySurface.get_rect()
buyRect.midtop = (85, minybuy)
DISPLAYSURF.blit(buySurface, buyRect)
def cashDraw(cash):
cashSurface = Font2.render(' ${0}'.format(cash), True, GREEN)
cashRect = cashSurface.get_rect()
cashRect.midtop = (387, 10)
DISPLAYSURF.blit(cashSurface, cashRect)
def capitalistOne(amount, cost, timez, gain, minxbuy, maxxbuy, minybuy, maxybuy, minxgain, maxxgain, minygain, maxygain, cash):
pygame.display.set_caption('capitalist')
buy_button = pygame.Rect(minxbuy, minybuy, maxxbuy, maxybuy)
gain_button = pygame.Rect(minxgain, minygain, maxxgain, maxygain)
menuRect = pygame.Rect(400, 680, 30, 30)
coefficient = maxxgain / timez #
time = 0
dt = 0
upgrade = amount * gain
loop = False
while True:
mouse_pressed = pygame.mouse.get_pressed()
mouse_pos = pygame.mouse.get_pos()
inc = time * coefficient
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
sys.exit()
#Return to menu
if menuRect.collidepoint(mouse_pos) and mouse_pressed[0]:
f = open('store.pckl', 'wb')
pickle.dump(amount, f)
f.close()
opening()
# Max LVL
if buy_button.collidepoint(mouse_pos) and mouse_pressed[0] and amount >= 1000:
maxLvlSurface = Font1.render('Max Lvl Reached', True, RED)
maxLvlRect = maxLvlSurface.get_rect()
maxLvlRect.midtop = (215, 5)
DISPLAYSURF.blit(maxLvlSurface, maxLvlRect)
pygame.display.flip()
Time.sleep(0.5)
# buy button
if buy_button.collidepoint(mouse_pos) and mouse_pressed[0] and cash >= cost and amount < 1000:
amount += 1
cash -= cost
upgrade = amount * gain
#Gain Button
if gain_button.collidepoint(mouse_pos) and mouse_pressed[0] and amount > 0:
loop = True # alows the user to click, then have the bar grow, rather than while they are clicking run it
if loop == True:
if time < timez: # if the bar isnt full, add to it
time += dt
if time >= timez: # if the bar is full, reset time, give cash.
cash += upgrade
time = 0
loop = False
# Draw everything
else:
DISPLAYSURF.blit(storeBoard, (0,0)) # Draw the background, icons, ect.
pygame.draw.rect(DISPLAYSURF, GREEN, (minxgain + 1, minygain, inc, maxygain)) # Draws a portion of the green bar
pygame.draw.rect(DISPLAYSURF, BLACK, gain_button, 2) # draws a border around the gain bar
DISPLAYSURF.blit(mainMenu, (400, 680))# draws a main menu button to return to main menu
buyDraw(amount, minxbuy, minybuy)# draws the buy button
# Should the cash be displayed in Sci Notation or in standar
if int(cash) < 1000000:
cashDraw(cash)
if int(cash) > 1000000:
SciNot = '%.2E' % Decimal(str(cash))
cashDraw(SciNot)
pygame.display.flip()
dt = clock.tick(60) / 1000
def opening():
DISPLAYSURF.fill(WHITE)
DISPLAYSURF.blit(logo, (155, 50))
DISPLAYSURF.blit(menu, (0 , 125))
saveRect = pygame.Rect(400, 680, 30, 30)
pygame.display.set_icon(logo)
pygame.display.flip()
f = open('store.pckl', 'rb')
gShovelAmount = pickle.load(f)
f.close()
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
sys.exit()
if event.type == pygame.MOUSEBUTTONDOWN:
(x, y) = pygame.mouse.get_pos()
if x < 375 and x > 80 and y < 545 and y > 395:
capitalistOne(
amount=gShovelAmount, cost=5, timez=10, gain=5, minxbuy=21,
maxxbuy=41, minybuy=21, maxybuy=41, minxgain=120,
maxxgain=204, minygain=21, maxygain=41, cash=cash)
opening()

Here is a button that should suit your needs:
class Button(object):
global screen_width,screen_height,screen
def __init__(self,x,y,width,height,text_color,background_color,text):
self.rect=pygame.Rect(x,y,width,height)
self.x=x
self.y=y
self.width=width
self.height=height
self.text=text
self.text_color=text_color
self.background_color=background_color
def check(self):
return self.rect.collidepoint(pygame.mouse.get_pos())
def draw(self):
pygame.draw.rect(screen, self.background_color,(self.rect),0)
drawTextcenter(self.text,font,screen,self.x+self.width/2,self.y+self.height/2,self.text_color)
pygame.draw.rect(screen,self.text_color,self.rect,3)
Implemented into the main loop:
button=Button(x,y,width,height,text_color,background_color,text)
while not done:
for event in pygame.event.get():
if event.type==QUIT:
terminate()
elif event.type==pygame.MOUSEBUTTONDOWN:
if dodger_button.check():
#what to do when button is pressed
#fill screen with background
screen.fill(background)
button.draw()
pygame.display.flip()
clock.tick(fps)

Related

How do I make this game properly fullscreen?

import random
from time import sleep
import pygame
class InlineOverdrive:
def __init__(self):
pygame.init()
self.display_width = 600
self.display_height = 600
self.black = (0, 0, 0)
self.white = (255, 255, 255)
self.clock = pygame.time.Clock()
self.gameDisplay = None
self.initialize()
def initialize(self):
self.crash = False
self.carImg = pygame.image.load('.\\img\\Car.png')
self.car_x_coordinate = (self.display_width * 0.45)
self.car_y_coordinate = (self.display_height * 0.8)
self.car_width = 49
# Background
self.bgImg = pygame.image.load(".\\img\\Background.png")
rect = self.bgImg.get_rect ()
self.bg_x2 = 0
self.bg_y2 = -600
self.bg_x1 = 0
self.bg_y1 = 0
self.bg_speed = 3
self.count = 0
def car(self, car_x_coordinate, car_y_coordinate):
self.gameDisplay.blit(self.carImg, (car_x_coordinate, car_y_coordinate))
def racing_window(self):
self.gameDisplay = pygame.display.set_mode((self.display_width, self.display_height))
pygame.display.set_caption('Inline Overdrive')
self.run_car()
def run_car(self):
while not self.crash:
for event in pygame.event.get():
self.backgroundroad()
if event.type == pygame.QUIT:
self.crash = True
# print(event)
if (event.type == pygame.KEYDOWN):
if (event.key == pygame.K_LEFT):
self.car_x_coordinate -= 50
print ("CAR X COORDINATES: %s" % self.car_x_coordinate)
if (event.key == pygame.K_RIGHT):
self.car_x_coordinate += 50
print ("CAR X COORDINATES: %s" % self.car_x_coordinate)
print ("x: {x}, y: {y}".format(x=self.car_x_coordinate, y=self.car_y_coordinate))
self.gameDisplay.fill(self.black)
self.backgroundroad()
self.car(self.car_x_coordinate, self.car_y_coordinate)
self.highscore(self.count)
self.count += 1
if (self.count % 100 == 0):
self.bg_speed += 1
if self.car_x_coordinate < 100 or self.car_x_coordinate > 360:
self.crash = True
self.display_message("You Have Crashed!")
pygame.display.update()
self.clock.tick(60)
def display_message(self, msg):
font = pygame.font.SysFont("NFS_by_JLTV.ttf", 72, True)
text = font.render(msg, True, (255, 255, 255))
self.gameDisplay.blit(text, (400 - text.get_width() // 2, 240 - text.get_height() // 2))
pygame.display.update()
self.clock.tick(60)
sleep(1)
inline_overdrive.initialize()
inline_overdrive.racing_window()
def backgroundroad(self):
self.gameDisplay.blit(self.bgImg, (self.bg_x1, self.bg_y1))
self.gameDisplay.blit(self.bgImg, (self.bg_x2, self.bg_y2))
self.bg_y1 += self.bg_speed
self.bg_y2 += self.bg_speed
if self.bg_y1 >= self.display_height:
self.bg_y1 = 0
elif self.bg_y2 >= self.display_height:
self.bg_y2 = 0
def highscore(self, count):
font = pygame.font.SysFont("NFS_by_JLTV.ttf", 20)
text = font.render("SCORE : " + str(count), True, self.white)
self.gameDisplay.blit(text, (0, 0))
if __name__ == '__main__':
inline_overdrive = InlineOverdrive()
inline_overdrive.racing_window()
I want this code to be able to loop the background infinitely as it moves along with the player. The screen currently does not scroll properly. The crash text is also not centered. How can I center it? If I can get my background to work properly, then my game is mostly complete. My car is also off screen for some reason. What needs to be done to make it be on the screen in the background?Image of My Car and Image of My Background
To center text on screen (or on any other Surface()) you can use Rect().center and
text_rect.center = display_rect.center # center on screen
text_rect.center = button_rect.center # center on button
font.render gives Surface(), and it has .get_rect() to get Rect() with its size and position - at start it may have position (0,0) but self.gameDisplay is also a Surface() and it has .get_rect() which gives Rect() with its size and position. If you copy .center from display to text_rect then you will have centered rect and you can use it in blit() to center text
def display_message(self, msg):
font = pygame.font.SysFont("NFS_by_JLTV.ttf", 72, True)
text_image = font.render(msg, True, (255, 255, 255))
text_rect = text_image.get_rect()
text_rect.center = self.gameDisplay.get_rect().center
self.gameDisplay.blit(text_image, text_rect)
# ... rest ...
As for background mistake is self.bg_y1 = 0 and self.bg_y2 = 0 because you have to set -600 to put background above visible area.
if self.bg_y1 >= self.display_height:
self.bg_y1 = -600
elif self.bg_y2 >= self.display_height:
self.bg_y2 = -600
Maybe it would be simpler if you would use Rect() which has .top and .bottom
and you could set as start
self.display_rect = self.gameDisplay.get_rect()
self.bg2_rect.bottom = self.display_rect.top
self.bg1_rect.bottom = self.display_rect.bottom
and later
if self.bg1_rect.top >= self.display_rect.bottom:
self.bg1_rect.bottom = self.display_rect.top
elif self.bg2_rect.top >= self.display_rect.bottom:
self.bg2_rect.bottom = self.display_rect.top
BTW:
Rect() has also .left, .right, .centerx, .centery, etc. It has also functions to detect collisions with point (ie. mouse position) - ie. rect.collidepoint(mouse_pos) - or with other rectange - ie. car_rect.colliderect( obstacle_rect )

Pygame beginner, player animation not working despite doing it by the tutorial

First time ever working with Pygame for a school assignment and I'm following a tutorial for it with my project members (tutorial link https://youtu.be/AY9MnQ4x3zk).
Problem is that despite following the tutorial to the dot at the "animating the player", my character (named "Marko" in the game and code) doesn't have his animation playing. When I start the game the character is stuck on it's first frame of animation. I've created a 3-frame animation and have the frames as separate png-files. The game so far itself works (it's on very beginner level, just a couple spawning enemies, collision and intro screens done so far), but the animation has had me and my project group scratching our heads for days. So far haven't found a solution by Googling nor searching here.
Also at the "# Marko's animations" -part "marko" is darkened and when hovering mouse on it, it says ""(variable) marko: Surface - "marko" is not accessed Pylance""
Here's the entire code:
import sys
from pygame.locals import *
from random import randint
from pygame import mixer
pygame.init()
width = 1920
height = 1080
screen = pygame.display.set_mode((width,height))
pygame.display.set_caption("Putkimies Marko")
start_time = 0
score = 0
nopeus = [3,3]
clock = pygame.time.Clock()
game_active = False
marko_gravity = 0
# Score
def display_score():
current_time = int(pygame.time.get_ticks() / 1000) - start_time
score_surf = test_font.render(f'Score: {current_time}',False,(black))
score_rect = score_surf.get_rect(center = (900,50))
screen.blit(score_surf,score_rect)
return current_time
def obstacle_movement(obstacle_list):
if obstacle_list:
for obstacle_rect in obstacle_list:
obstacle_rect.x -= 5
if obstacle_rect.bottom == 955:
screen.blit(rat,obstacle_rect)
else:
screen.blit(fly,obstacle_rect)
return obstacle_list
else: return[]
def collisions(marko,obstacles):
if obstacles:
for obstacle_rect in obstacles:
if marko.colliderect(obstacle_rect): return False
return True
# Surfaces
background = pygame.image.load("marko_background.png").convert_alpha()
sewer = pygame.image.load("background_sewer.png").convert_alpha()
ground = pygame.image.load("ground.png").convert_alpha()
rat = pygame.image.load("rat.png").convert_alpha()
game_over = pygame.image.load("game_over.png").convert_alpha()
fly = pygame.image.load("fly.png").convert_alpha()
# Marko Surfaces
marko_run_1 = pygame.image.load("marko_run_1.png").convert_alpha()
marko_run_2 = pygame.image.load("marko_run_2.png").convert_alpha()
marko_run_3 = pygame.image.load("marko_run_3.png").convert_alpha()
marko_run = [marko_run_1,marko_run_2,marko_run_3]
marko_index = 0
marko_jump = pygame.image.load("marko_jump.png").convert_alpha()
marko = marko_run[marko_index]
# Fonts
test_font = pygame.font.Font("supermario.ttf", 50)
# Colors
black = (0,0,0)
red = (255,0,0)
green = (0,255,0)
blue = (0,0,255)
light_blue = (94,129,162)
purple = (36,5,83)
# Rects
game_overSurface = game_over.get_rect(midtop = (970,-200))
platform = pygame.Surface((300,50))
groundSurface = ground.get_rect(midtop = (960,480))
markoSurface = marko.get_rect()
text_surface = test_font.render('Putkimies Marko', False, red)
markoSurface.left = 50
markoSurface.bottom = 714
# Obstacles
obstacle_rect_list = []
# Intro screen
player_stand = pygame.image.load("putkimies_marko_idle.png")
player_stand = pygame.transform.rotozoom(player_stand,0,2)
player_stand_rect = player_stand.get_rect(center = (950,500))
game_name = test_font.render("PUTKIMIES MARKO", False,"Black")
game_name_rect = game_name.get_rect(center = (950,350))
game_message = test_font.render('PRESS SPACE TO PLAY',False,"Black")
game_message_rect = game_message.get_rect(center = (950,650))
game_message_start_again = test_font.render('PRESS SPACE TO PLAY AGAIN',False,"Black")
game_message_start_again_rect = game_message.get_rect(center = (850,720))
# Marko's animations
def marko_animation():
global markoSurface, marko_index
if markoSurface.bottom < 955:
marko = marko_jump
else:
marko_index += 0.1
if marko_index >= len(marko_run):marko_index = 0
marko = marko_run[int(marko_index)]
# Timer
obstacle_timer = pygame.USEREVENT + 1
pygame.time.set_timer(obstacle_timer,1500)
# Background music
mixer.music.load('smb_stage_clear.wav')
mixer.music.play(0)
# -1 Makes the music loop
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
sys.exit()
if event.type == KEYDOWN:
if event.key == K_ESCAPE:
pygame.quit()
sys.exit()
if game_active:
if event.type == KEYDOWN:
if event.key == K_SPACE and markoSurface.bottom >= 955:
marko_gravity = -18
else:
if event.type == pygame.KEYDOWN and event.key == pygame.K_SPACE:
game_active = True
start_time = int(pygame.time.get_ticks() / 1000)
if event.type == obstacle_timer and game_active:
if randint (0,2):
obstacle_rect_list.append(rat.get_rect(midbottom = (randint(2000,2200),955)))
else:
obstacle_rect_list.append(fly.get_rect(midbottom = (randint(2000,2200),855)))
if game_active:
# Draw
screen.blit(sewer, (0,0))
screen.blit(ground, (0,955))
marko_animation()
screen.blit(marko,markoSurface)
score = display_score()
# Key uses
key_use = pygame.key.get_pressed()
if key_use[K_LEFT]:
markoSurface.move_ip((-7,0))
if key_use[K_RIGHT]:
markoSurface.move_ip((7,0))
# Marko
marko_gravity += 1
markoSurface.y += marko_gravity
if markoSurface.bottom >= 955: markoSurface.bottom = 955
if markoSurface.left <= 0: markoSurface.left = 0
if markoSurface.right >= 1920: markoSurface.right = 1920
# Obstacle movement
obstacle_rect_list = obstacle_movement(obstacle_rect_list)
# Collision
game_active = collisions(markoSurface,obstacle_rect_list)
else: # Intro screen
screen.fill ("Light blue")
screen.blit(player_stand,player_stand_rect)
obstacle_rect_list.clear()
markoSurface.left = 80 # returns marko to 80
# Draws score message if score > 0
score_message = test_font.render(f'Your score: {score}',False,(red))
score_message_rect = score_message.get_rect(center = (950,650))
screen.blit(game_name,game_name_rect)
if score == 0: screen.blit(game_message,game_message_rect)
else:
screen.blit(score_message,score_message_rect)
screen.blit(game_over,game_overSurface)
screen.blit(game_message_start_again,game_message_start_again_rect)
pygame.display.update()
clock.tick(60)```
marko is a variable in global namespace. You must use the global statement to change a variable in the global namespace within a function:
def marko_animation():
global marko # <---
global marko_index
if markoSurface.bottom < 955:
marko = marko_jump
else:
marko_index += 0.1
if marko_index >= len(marko_run):
marko_index = 0
marko = marko_run[int(marko_index)]

Pygame: Sprites spawn close to each other [duplicate]

Right now, my game blits all the images in random positions correctly and also gets the rect of the images correctly, but I can´t figure out how to use colliderect to make sure the images don´t overlap. How could it work for my code?
Also I´m trying to make the first text fade out and I don´t know why it doesn´t work for me.
Here is the code:
class GAME1:
def __init__(self, next_scene):
self.background = pygame.Surface(size)
# Create an array of images with their rect
self.images = []
self.rects = []
self.imagenes1_array = ['autobus.png','coche.png','barco.png','autobus2.png','grua.png','bici.png']
for i in self.imagenes1_array:
# We divide in variables so we can then get the rect of the whole Img (i2)
i2 = pygame.image.load(i)
self.images.append(i2)
s = pygame.Surface(i2.get_size())
r = s.get_rect()
# Trying to use colliderect so it doesnt overlap
if pygame.Rect.colliderect(r,r) == True:
x = random.randint(300,1000)
y = random.randint(200,700)
self.rects.append(r)
def start(self, gamestate):
self.gamestate = gamestate
for rect in self.rects:
# Give random coordinates (we limit the dimensions (x,y))
x = random.randint(300,1000)
y = random.randint(200,700)
rect.x = x
rect.y = y
def draw(self,screen):
self.background = pygame.Surface(size)
font = pygame.font.SysFont("comicsansms",70)
# First half (Show image to remember)
text1 = font.render('¡A recordar!',True, PURPLE)
text1_1 = text1.copy()
# This surface is used to adjust the alpha of the txt_surf.
alpha_surf = pygame.Surface(text1_1.get_size(), pygame.SRCALPHA)
alpha = 255 # The current alpha value of the surface.
if alpha > 0:
alpha = max(alpha-4, 0)
text1_1 = text1.copy()
alpha_surf.fill((255, 255, 255, alpha))
text1_1.blit(alpha_surf, (0,0), special_flags = pygame.BLEND_RGBA_MULT)
screen.blit(text1_1, (600,50))
# Second half (Show all similar images)
text2 = font.render('¿Cuál era el dibujo?',True, PURPLE)
#screen.blit(text2, (500,50))
for i in range(len(self.images)):
#colliding = pygame.Rect.collidelistall(self.rects)
screen.blit(self.images[i], (self.rects[i].x, self.rects[i].y))
def update(self, events, dt):
for event in events:
if event.type == pygame.MOUSEBUTTONDOWN:
for rect in self.rects:
if rect.collidepoint(event.pos):
print('works!')
Use collidelist() to test test if one rectangle in a list intersects:
for i in self.imagenes1_array:
s = pygame.image.load(i)
self.images.append(s)
r = s.get_rect()
position_set = False
while not position_set:
r.x = random.randint(300,1000)
r.y = random.randint(200,700)
margin = 10
rl = [rect.inflate(margin*2, margin*2) for rect in self.rects]
if len(self.rects) == 0 or r.collidelist(rl) < 0:
self.rects.append(r)
position_set = True
See the minimal example, that uses the algorithm to generate random not overlapping rectangles:
import pygame
import random
pygame.init()
window = pygame.display.set_mode((400, 400))
clock = pygame.time.Clock()
def new_recs(rects):
rects.clear()
for _ in range(10):
r = pygame.Rect(0, 0, random.randint(30, 40), random.randint(30, 50))
position_set = False
while not position_set:
r.x = random.randint(10, 340)
r.y = random.randint(10, 340)
margin = 10
rl = [rect.inflate(margin*2, margin*2) for rect in rects]
if len(rects) == 0 or r.collidelist(rl) < 0:
rects.append(r)
position_set = True
rects = []
new_recs(rects)
run = True
while run:
clock.tick(60)
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
elif event.type == pygame.KEYDOWN:
new_recs(rects)
window.fill(0)
for r in rects:
pygame.draw.rect(window, (255, 0, 0), r)
pygame.display.flip()
pygame.quit()
exit()

Python_textinput issue while using two instances of it

I'm working on a choice based adventure game with python, and I'm using pygame to create some graphics for the game.
As I was trying to create a screen so the player can input his real name and the main character name I faced an issue: as I try to create both text inputs (using pygame_textinput module) on the same screen, it just clones what I write in one of them.
I thought I could solve this by putting the other input on a new screen but when I hit enter on the first screen it just passes through the rest of the code and the second input stays empty.
How could I solve this issue?
#Imports
import contextlib
with contextlib.redirect_stdout(None):
import pygame
import pickle
import time
import random
import pygame_textinput.pygame_textinput as textinput
#Really messy, I know#
#Save Stuff
Choices = {}
def save(to_save, save_filepath):
pickle.dump(to_save, open(save_filepath, "wb"))
def load(save_filepath):
return pickle.load(open(save_filepath, "rb"))
#Initializations
pygame.init()
#Screen
scrWidth = 640
scrHeight = 480
screen = pygame.display.set_mode((scrWidth, scrHeight))
pygame.display.set_caption('Something')
#Images
startscreenbg = pygame.image.load('assets/Images/startscreen.jpg').convert()
#Text Input
real_nametxtinput = textinput.TextInput(text_color=(255,255,255))
char_nametxtinput = textinput.TextInput(text_color=(255,255,255))
#Clock
clock = pygame.time.Clock()
#Game Constants
next = False
real_name = ''
char_name = ''
real_name_done = False
char_name_done = False
##### Global Functions #####
#Buttons stuff
buttonTextFont = pygame.font.SysFont("comicsansms", 20)
def createButton(msg, msgcolor,x,y,width,height,color1,color2,action=None):
mouse = pygame.mouse.get_pos()
click = pygame.mouse.get_pressed()
if x+width > mouse[0] > x and y+height > mouse[1] > y:
pygame.draw.rect(screen, color2,(x,y,width,height))
if click[0] == 1 and action != None:
action()
else:
pygame.draw.rect(screen, color1,(x,y,width,height))
buttontext = buttonTextFont.render(msg, 1, msgcolor)
screen.blit(buttontext, (x + (width//2) - (buttontext.get_width()//2), (y + (height//2) - (buttontext.get_height()//2))))
##### Screens/Chapters #####
def update_next1():
global next
next = True
def start_screen():
screen.blit(startscreenbg, (0, 0))
new_game = createButton('New Game',(255,255,255), 80, 100, 200, 50, (0,180,0), (0,255,0), update_next1)
load_game = createButton('Load Game', (255,255,255), 360, 100, 200, 50, (0,0,180), (0,0,255))
#Names
def real_name_screen():
global real_name, real_name_done
screen.blit(startscreenbg, (0,0))
pygame.draw.rect(screen, (102, 255, 102), (150, 90, 200, 50))
screen.blit(real_nametxtinput.get_surface(), (150,100))
if real_nametxtinput.update(events):
real_name = real_nametxtinput.get_text()
real_name_done = True
def char_name_screen():
global char_name, char_name_done
screen.blit(startscreenbg, (0, 0))
pygame.draw.rect(screen, (255, 102, 255), (150, 90, 200, 50))
screen.blit(char_nametxtinput.get_surface(), (150, 100))
if char_nametxtinput.update(events):
char_name = char_nametxtinput.get_text()
if char_name != '':
char_name_done = True
run = True
while run:
clock.tick(27)
events = pygame.event.get()
for event in events:
if event.type == pygame.QUIT:
run = False
if not next:
start_screen()
if next:
real_name_screen()
if real_name_done:
char_name_screen()
if char_name_done:
#This is just so I could test it
print(real_name, char_name)
run = False
pygame.display.update()
pygame.quit()
quit()
You need a way to keep track if one of the text input widgets is active, and a way to switch between all widgets.
I hacked together this example, adjust as needed (there's a lot that could be improved):
import os.path
import pygame
import pygame.locals as pl
pygame.font.init()
class WidgetManager:
def __init__(self):
self.widgets = []
def update(self, events, dt):
for e in events:
if e.type == pygame.MOUSEBUTTONDOWN:
for w in self.widgets:
w.active = False
if w.rect.collidepoint(e.pos):
w.active = True
for w in self.widgets:
w.update(events, dt)
def draw(self, surface):
for w in self.widgets:
surface.blit(w.surface, w.rect)
class TextInput:
"""
This class lets the user input a piece of text, e.g. a name or a message.
This class let's the user input a short, one-lines piece of text at a blinking cursor
that can be moved using the arrow-keys. Delete, home and end work as well.
"""
def __init__(
self,
initial_string="",
font_family="",
font_size=35,
antialias=True,
active=False,
text_color=(0, 0, 0),
rect=pygame.Rect(0, 0, 10, 10),
cursor_color=(0, 0, 1),
repeat_keys_initial_ms=400,
repeat_keys_interval_ms=35):
"""
:param initial_string: Initial text to be displayed
:param font_family: name or list of names for font (see pygame.font.match_font for precise format)
:param font_size: Size of font in pixels
:param antialias: Determines if antialias is applied to font (uses more processing power)
:param text_color: Color of text (duh)
:param cursor_color: Color of cursor
:param repeat_keys_initial_ms: Time in ms before keys are repeated when held
:param repeat_keys_interval_ms: Interval between key press repetition when helpd
"""
# Text related vars:
self.antialias = antialias
self.text_color = text_color
self.font_size = font_size
self.input_string = initial_string # Inputted text
self.active = active
self.rect = rect
if not os.path.isfile(font_family):
font_family = pygame.font.match_font(font_family)
self.font_object = pygame.font.Font(font_family, font_size)
# Text-surface will be created during the first update call:
self.surface = pygame.Surface((1, 1))
self.surface.set_alpha(0)
# Vars to make keydowns repeat after user pressed a key for some time:
self.keyrepeat_counters = {} # {event.key: (counter_int, event.unicode)} (look for "***")
self.keyrepeat_intial_interval_ms = repeat_keys_initial_ms
self.keyrepeat_interval_ms = repeat_keys_interval_ms
# Things cursor:
self.cursor_surface = pygame.Surface((int(self.font_size/20+1), self.font_size))
self.cursor_surface.fill(cursor_color)
self.cursor_position = len(initial_string) # Inside text
self.cursor_visible = True # Switches every self.cursor_switch_ms ms
self.cursor_switch_ms = 500 # /|\
self.cursor_ms_counter = 0
def update(self, events, dt):
for event in events:
if event.type == pygame.KEYDOWN and self.active:
self.cursor_visible = True # So the user sees where he writes
# If none exist, create counter for that key:
if event.key not in self.keyrepeat_counters:
self.keyrepeat_counters[event.key] = [0, event.unicode]
if event.key == pl.K_BACKSPACE:
self.input_string = (
self.input_string[:max(self.cursor_position - 1, 0)]
+ self.input_string[self.cursor_position:]
)
# Subtract one from cursor_pos, but do not go below zero:
self.cursor_position = max(self.cursor_position - 1, 0)
elif event.key == pl.K_DELETE:
self.input_string = (
self.input_string[:self.cursor_position]
+ self.input_string[self.cursor_position + 1:]
)
elif event.key == pl.K_RETURN:
return True
elif event.key == pl.K_RIGHT:
# Add one to cursor_pos, but do not exceed len(input_string)
self.cursor_position = min(self.cursor_position + 1, len(self.input_string))
elif event.key == pl.K_LEFT:
# Subtract one from cursor_pos, but do not go below zero:
self.cursor_position = max(self.cursor_position - 1, 0)
elif event.key == pl.K_END:
self.cursor_position = len(self.input_string)
elif event.key == pl.K_HOME:
self.cursor_position = 0
else:
# If no special key is pressed, add unicode of key to input_string
self.input_string = (
self.input_string[:self.cursor_position]
+ event.unicode
+ self.input_string[self.cursor_position:]
)
self.cursor_position += len(event.unicode) # Some are empty, e.g. K_UP
elif event.type == pl.KEYUP:
# *** Because KEYUP doesn't include event.unicode, this dict is stored in such a weird way
if event.key in self.keyrepeat_counters:
del self.keyrepeat_counters[event.key]
# Update key counters:
for key in self.keyrepeat_counters:
self.keyrepeat_counters[key][0] += dt # Update clock
# Generate new key events if enough time has passed:
if self.keyrepeat_counters[key][0] >= self.keyrepeat_intial_interval_ms:
self.keyrepeat_counters[key][0] = (
self.keyrepeat_intial_interval_ms
- self.keyrepeat_interval_ms
)
event_key, event_unicode = key, self.keyrepeat_counters[key][1]
pygame.event.post(pygame.event.Event(pl.KEYDOWN, key=event_key, unicode=event_unicode))
# Re-render text surface:
self.surface = pygame.Surface(self.rect.size)
self.surface.blit(self.font_object.render(self.input_string, self.antialias, self.text_color), (0, 0))
pygame.draw.rect(self.surface, self.text_color, (0, 0, *self.rect.size), 1)
# Update self.cursor_visible
self.cursor_ms_counter += dt
if self.cursor_ms_counter >= self.cursor_switch_ms:
self.cursor_ms_counter %= self.cursor_switch_ms
self.cursor_visible = not self.cursor_visible
if self.cursor_visible and self.active:
cursor_y_pos = self.font_object.size(self.input_string[:self.cursor_position])[0]
# Without this, the cursor is invisible when self.cursor_position > 0:
if self.cursor_position > 0:
cursor_y_pos -= self.cursor_surface.get_width()
self.surface.blit(self.cursor_surface, (cursor_y_pos, 0))
return False
def get_surface(self):
return self.surface
def get_text(self):
return self.input_string
def get_cursor_position(self):
return self.cursor_position
def set_text_color(self, color):
self.text_color = color
def set_cursor_color(self, color):
self.cursor_surface.fill(color)
def clear_text(self):
self.input_string = ""
self.cursor_position = 0
def main():
screen = pygame.display.set_mode((800, 600))
clock = pygame.time.Clock()
manager = WidgetManager()
manager.widgets.append(TextInput(text_color=pygame.Color('grey'), cursor_color=pygame.Color('grey'), rect=pygame.Rect(5, 5, 790, 35)))
manager.widgets.append(TextInput(text_color=pygame.Color('orange'), cursor_color=pygame.Color('orange'), rect=pygame.Rect(5, 55, 790, 35), active=True))
dt = 0
while True:
events = pygame.event.get()
for e in events:
if e.type == pygame.QUIT:
return
screen.fill((30, 30, 30))
manager.draw(screen)
manager.update(events, dt)
dt = clock.tick()
pygame.display.update()
if __name__ == '__main__':
main()
You see TextInput now has an active flag. If it's not set, the key input is ignored. Also, we store the position and size of TextInput in the new attribute rect, so the new class WidgetManager can switch between the widgets by clicking one with the mouse.
I also removed the Clock from the TextInput class, since calling self.clock.tick() is something the main loop should do.

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