How to add bubble sort to my boxes in the code? - python

So first here is my code:
import pygame, sys, random
from pygame.locals import *
# Create the constants (go ahead and experiment with different values)
BOARDWIDTH = 4 # number of columns in the board
BOARDHEIGHT = 4 # number of rows in the board
TILESIZE = 80
WINDOWWIDTH = 640
WINDOWHEIGHT = 480
FPS = 30
BLANK = None
# R G B
BLACK = ( 0, 0, 0)
WHITE = (255, 255, 255)
BRIGHTBLUE = ( 0, 50, 255)
DARKTURQUOISE = ( 3, 54, 73)
GREEN = ( 0, 204, 0)
BGCOLOR = DARKTURQUOISE
TILECOLOR = GREEN
TEXTCOLOR = WHITE
BORDERCOLOR = BRIGHTBLUE
BASICFONTSIZE = 20
BUTTONCOLOR = WHITE
BUTTONTEXTCOLOR = BLACK
MESSAGECOLOR = WHITE
XMARGIN = int((WINDOWWIDTH - (TILESIZE * BOARDWIDTH + (BOARDWIDTH - 1))) / 2)
YMARGIN = int((WINDOWHEIGHT - (TILESIZE * BOARDHEIGHT + (BOARDHEIGHT - 1))) / 2)
UP = 'up'
DOWN = 'down'
LEFT = 'left'
RIGHT = 'right'
def main():
global FPSCLOCK, DISPLAYSURF, BASICFONT, RESET_SURF, RESET_RECT, NEW_SURF, NEW_RECT, SOLVE_SURF, SOLVE_RECT
pygame.init()
FPSCLOCK = pygame.time.Clock()
DISPLAYSURF = pygame.display.set_mode((WINDOWWIDTH, WINDOWHEIGHT))
pygame.display.set_caption('Slide Puzzle')
BASICFONT = pygame.font.Font('freesansbold.ttf', BASICFONTSIZE)
# Store the option buttons and their rectangles in OPTIONS.
RESET_SURF, RESET_RECT = makeText('Reset', TEXTCOLOR, TILECOLOR, WINDOWWIDTH - 120, WINDOWHEIGHT - 90)
NEW_SURF, NEW_RECT = makeText('New Game', TEXTCOLOR, TILECOLOR, WINDOWWIDTH - 120, WINDOWHEIGHT - 60)
SOLVE_SURF, SOLVE_RECT = makeText('Solve', TEXTCOLOR, TILECOLOR, WINDOWWIDTH - 120, WINDOWHEIGHT - 30)
mainBoard, solutionSeq = generateNewPuzzle(80)
SOLVEDBOARD = getStartingBoard() # a solved board is the same as the board in a start state.
allMoves = [] # list of moves made from the solved configuration
while True: # main game loop
slideTo = None # the direction, if any, a tile should slide
msg = 'Click tile or press arrow keys to slide.' # contains the message to show in the upper left corner.
if mainBoard == SOLVEDBOARD:
msg = 'Solved!'
drawBoard(mainBoard, msg)
checkForQuit()
for event in pygame.event.get(): # event handling loop
if event.type == MOUSEBUTTONUP:
spotx, spoty = getSpotClicked(mainBoard, event.pos[0], event.pos[1])
if (spotx, spoty) == (None, None):
# check if the user clicked on an option button
if RESET_RECT.collidepoint(event.pos):
resetAnimation(mainBoard, allMoves) # clicked on Reset button
allMoves = []
elif NEW_RECT.collidepoint(event.pos):
mainBoard, solutionSeq = generateNewPuzzle(80) # clicked on New Game button
allMoves = []
elif SOLVE_RECT.collidepoint(event.pos):
resetAnimation(mainBoard, solutionSeq + allMoves) # clicked on Solve button
allMoves = []
else:
# check if the clicked tile was next to the blank spot
blankx, blanky = getBlankPosition(mainBoard)
if spotx == blankx + 1 and spoty == blanky:
slideTo = LEFT
elif spotx == blankx - 1 and spoty == blanky:
slideTo = RIGHT
elif spotx == blankx and spoty == blanky + 1:
slideTo = UP
elif spotx == blankx and spoty == blanky - 1:
slideTo = DOWN
elif event.type == KEYUP:
# check if the user pressed a key to slide a tile
if event.key in (K_LEFT, K_a) and isValidMove(mainBoard, LEFT):
slideTo = LEFT
elif event.key in (K_RIGHT, K_d) and isValidMove(mainBoard, RIGHT):
slideTo = RIGHT
elif event.key in (K_UP, K_w) and isValidMove(mainBoard, UP):
slideTo = UP
elif event.key in (K_DOWN, K_s) and isValidMove(mainBoard, DOWN):
slideTo = DOWN
if slideTo:
slideAnimation(mainBoard, slideTo, 'Click tile or press arrow keys to slide.', 8) # show slide on screen
makeMove(mainBoard, slideTo)
allMoves.append(slideTo) # record the slide
pygame.display.update()
FPSCLOCK.tick(FPS)
def terminate():
pygame.quit()
sys.exit()
def checkForQuit():
for event in pygame.event.get(QUIT): # get all the QUIT events
terminate() # terminate if any QUIT events are present
for event in pygame.event.get(KEYUP): # get all the KEYUP events
if event.key == K_ESCAPE:
terminate() # terminate if the KEYUP event was for the Esc key
pygame.event.post(event) # put the other KEYUP event objects back
def getStartingBoard():
# Return a board data structure with tiles in the solved state.
# For example, if BOARDWIDTH and BOARDHEIGHT are both 3, this function
# returns [[1, 4, 7], [2, 5, 8], [3, 6, BLANK]]
counter = 1
board = []
for x in range(BOARDWIDTH):
column = []
for y in range(BOARDHEIGHT):
column.append(counter)
counter += BOARDWIDTH
board.append(column)
counter -= BOARDWIDTH * (BOARDHEIGHT - 1) + BOARDWIDTH - 1
board[BOARDWIDTH-1][BOARDHEIGHT-1] = BLANK
return board
def getBlankPosition(board):
# Return the x and y of board coordinates of the blank space.
for x in range(BOARDWIDTH):
for y in range(BOARDHEIGHT):
if board[x][y] == BLANK:
return (x, y)
def makeMove(board, move):
# This function does not check if the move is valid.
blankx, blanky = getBlankPosition(board)
if move == UP:
board[blankx][blanky], board[blankx][blanky + 1] = board[blankx][blanky + 1], board[blankx][blanky]
elif move == DOWN:
board[blankx][blanky], board[blankx][blanky - 1] = board[blankx][blanky - 1], board[blankx][blanky]
elif move == LEFT:
board[blankx][blanky], board[blankx + 1][blanky] = board[blankx + 1][blanky], board[blankx][blanky]
elif move == RIGHT:
board[blankx][blanky], board[blankx - 1][blanky] = board[blankx - 1][blanky], board[blankx][blanky]
def isValidMove(board, move):
blankx, blanky = getBlankPosition(board)
return (move == UP and blanky != len(board[0]) - 1) or \
(move == DOWN and blanky != 0) or \
(move == LEFT and blankx != len(board) - 1) or \
(move == RIGHT and blankx != 0)
def getRandomMove(board, lastMove=None):
# start with a full list of all four moves
validMoves = [UP, DOWN, LEFT, RIGHT]
# remove moves from the list as they are disqualified
if lastMove == UP or not isValidMove(board, DOWN):
validMoves.remove(DOWN)
if lastMove == DOWN or not isValidMove(board, UP):
validMoves.remove(UP)
if lastMove == LEFT or not isValidMove(board, RIGHT):
validMoves.remove(RIGHT)
if lastMove == RIGHT or not isValidMove(board, LEFT):
validMoves.remove(LEFT)
# return a random move from the list of remaining moves
return random.choice(validMoves)
def getLeftTopOfTile(tileX, tileY):
left = XMARGIN + (tileX * TILESIZE) + (tileX - 1)
top = YMARGIN + (tileY * TILESIZE) + (tileY - 1)
return (left, top)
def getSpotClicked(board, x, y):
# from the x & y pixel coordinates, get the x & y board coordinates
for tileX in range(len(board)):
for tileY in range(len(board[0])):
left, top = getLeftTopOfTile(tileX, tileY)
tileRect = pygame.Rect(left, top, TILESIZE, TILESIZE)
if tileRect.collidepoint(x, y):
return (tileX, tileY)
return (None, None)
def drawTile(tilex, tiley, number, adjx=0, adjy=0):
# draw a tile at board coordinates tilex and tiley, optionally a few
# pixels over (determined by adjx and adjy)
left, top = getLeftTopOfTile(tilex, tiley)
pygame.draw.rect(DISPLAYSURF, TILECOLOR, (left + adjx, top + adjy, TILESIZE, TILESIZE))
textSurf = BASICFONT.render(str(number), True, TEXTCOLOR)
textRect = textSurf.get_rect()
textRect.center = left + int(TILESIZE / 2) + adjx, top + int(TILESIZE / 2) + adjy
DISPLAYSURF.blit(textSurf, textRect)
def makeText(text, color, bgcolor, top, left):
# create the Surface and Rect objects for some text.
textSurf = BASICFONT.render(text, True, color, bgcolor)
textRect = textSurf.get_rect()
textRect.topleft = (top, left)
return (textSurf, textRect)
def drawBoard(board, message):
DISPLAYSURF.fill(BGCOLOR)
if message:
textSurf, textRect = makeText(message, MESSAGECOLOR, BGCOLOR, 5, 5)
DISPLAYSURF.blit(textSurf, textRect)
for tilex in range(len(board)):
for tiley in range(len(board[0])):
if board[tilex][tiley]:
drawTile(tilex, tiley, board[tilex][tiley])
left, top = getLeftTopOfTile(0, 0)
width = BOARDWIDTH * TILESIZE
height = BOARDHEIGHT * TILESIZE
pygame.draw.rect(DISPLAYSURF, BORDERCOLOR, (left - 5, top - 5, width + 11, height + 11), 4)
DISPLAYSURF.blit(RESET_SURF, RESET_RECT)
DISPLAYSURF.blit(NEW_SURF, NEW_RECT)
DISPLAYSURF.blit(SOLVE_SURF, SOLVE_RECT)
def slideAnimation(board, direction, message, animationSpeed):
#This function does not check if the move is valid.
blankx, blanky = getBlankPosition(board)
if direction == UP:
movex = blankx
movey = blanky + 1
elif direction == DOWN:
movex = blankx
movey = blanky - 1
elif direction == LEFT:
movex = blankx + 1
movey = blanky
elif direction == RIGHT:
movex = blankx - 1
movey = blanky
# prepare the base surface
drawBoard(board, message)
baseSurf = DISPLAYSURF.copy()
# draw a blank space over the moving tile on the baseSurf Surface.
moveLeft, moveTop = getLeftTopOfTile(movex, movey)
pygame.draw.rect(baseSurf, BGCOLOR, (moveLeft, moveTop, TILESIZE, TILESIZE))
for i in range(0, TILESIZE, animationSpeed):
# animate the tile sliding over
checkForQuit()
DISPLAYSURF.blit(baseSurf, (0, 0))
if direction == UP:
drawTile(movex, movey, board[movex][movey], 0, -i)
if direction == DOWN:
drawTile(movex, movey, board[movex][movey], 0, i)
if direction == LEFT:
drawTile(movex, movey, board[movex][movey], -i, 0)
if direction == RIGHT:
drawTile(movex, movey, board[movex][movey], i, 0)
pygame.display.update()
FPSCLOCK.tick(FPS)
def generateNewPuzzle(numSlides):
# From a starting configuration, make numSlides number of moves (and
# animate these moves).
sequence = []
board = getStartingBoard()
drawBoard(board, '')
pygame.display.update()
pygame.time.wait(500) # pause 500 milliseconds for effect
lastMove = None
for i in range(numSlides):
move = getRandomMove(board, lastMove)
slideAnimation(board, move, 'Generating new puzzle...', animationSpeed=int(TILESIZE / 3))
makeMove(board, move)
sequence.append(move)
lastMove = move
return (board, sequence)
def resetAnimation(board, allMoves):
# make all of the moves in allMoves in reverse.
revAllMoves = allMoves[:] # gets a copy of the list
revAllMoves.reverse()
for move in revAllMoves:
if move == UP:
oppositeMove = DOWN
elif move == DOWN:
oppositeMove = UP
elif move == RIGHT:
oppositeMove = LEFT
elif move == LEFT:
oppositeMove = RIGHT
slideAnimation(board, oppositeMove, '', animationSpeed=int(TILESIZE / 2))
makeMove(board, oppositeMove)
if __name__ == '__main__':
main()
Here is the bubble sort code:
def shortBubbleSort(alist):
exchanges = True
passnum = len(alist)-1
while passnum > 0 and exchanges:
exchanges = False
for i in range(passnum):
if alist[i]>alist[i+1]:
exchanges = True
temp = alist[i]
alist[i] = alist[i+1]
alist[i+1] = temp
passnum = passnum-1
alist=[20,30,40,90,50,60,70,80,100,110]
shortBubbleSort(alist)
print(alist)
I am not sure how to select the numbers I have and arrange them using bubble sort method.

Oh - I found your code very complex for python and bubble-sort.
Here is the my view:
def bubbleSort(alist):
for passnum in range(len(alist)-1, 0, -1):
for i in range(passnum):
if alist[i] > alist[i+1]:
alist[i] , alist[i+1] = alist[i+1] , alist[i]
alist = [54,26,93,17,77,31,44,55,20]
bubbleSort(alist)
print(alist)
You do not need any flags or temp variables - this is the python, the language of magic! :) :) :) abracadabra!!!

Related

how can i center the numbers in the two grids?

this is the program of the game, it contains everything but i need help to center the numbers inside the grids, i did some attempts i put them in comments, please help me
imports of my program
import numpy as np
import random
import pygame
from pygame.locals import *
constructor of the class
class Py2048:
def __init__(self):
self.N = 4
self.grid1 = np.zeros((self.N, self.N), dtype=int) #initialiasation de la grid avec des 0
self.grid2 = np.zeros((self.N, self.N), dtype=int) #initialiasation
self.cellSize = 70
self.gap = 3
self.windowBgColor = (187, 173, 160)
self.blockSize = self.cellSize + self.gap * 2
self.W = 700
self.H = self.W
pygame.init()
pygame.display.set_caption("2048")
pygame.font.init()
self.myfont = pygame.font.SysFont('Comic Sans MS', 30)
self.screen = pygame.display.set_mode((self.W, self.H))
adding a new number to the grids
def new_number(self, k=1):
free_poss1 = list(zip(*np.where(self.grid1 == 0))) #position de la grid
free_poss2 = list(zip(*np.where(self.grid2 == 0)))
for pos in random.sample(free_poss1, k=k): #random 2 ou 4
if random.random() < .1:
self.grid1[pos] = 4
else:
self.grid1[pos] = 2
for pos in random.sample(free_poss2, k=k): #random 2 ou 4
if random.random() < .1:
self.grid2[pos] = 4
else:
self.grid2[pos] = 2
#staticmethod
def _get_nums(this):
this_n = this[this != 0]
this_n_sum = []
skip = False
for j in range(len(this_n)):
if skip:
skip = False
continue
if j != len(this_n) - 1 and this_n[j] == this_n[j + 1]:
new_n = this_n[j] * 2
skip = True
else:
new_n = this_n[j]
this_n_sum.append(new_n)
return np.array(this_n_sum)
def make_move(self, move): #move
for i in range(self.N):
if move in 'lr':
this1 = self.grid1[i, :]
this2 = self.grid2[i, :]
else:
this1 = self.grid1[:, i]
this2 = self.grid2[:, i]
flipped = False
if move in 'rd':
flipped = True
this1 = this1[::-1]
this2 = this2[::-1]
this_n1 = self._get_nums(this1)
this_n2 = self._get_nums(this2)
new_this1 = np.zeros_like(this1)
new_this1[:len(this_n1)] = this_n1
new_this2 = np.zeros_like(this2)
new_this2[:len(this_n2)] = this_n2
if flipped:
new_this1 = new_this1[::-1]
new_this2 = new_this2[::-1]
if move in 'lr':
self.grid1[i, :] = new_this1
self.grid2[i, :] = new_this2
else:
self.grid1[:, i] = new_this1
self.grid2[:, i] = new_this2
this is where i have the problem, when i draw the two grids i dont know how to center the numbers in them
def draw_game(self):
self.screen.fill(self.windowBgColor)
for i in range(self.N):
rectY = self.blockSize * i + self.gap
for j in range(self.N):
n1 = self.grid1[i][j]
n2 = self.grid2[i][j]
rectX = 200 + self.blockSize * j + self.gap
pygame.draw.rect(
self.screen,
(255, 255, 255),
pygame.Rect(rectX, 40 + rectY, self.cellSize, self.cellSize),
border_radius = 6
)
pygame.draw.rect(
self.screen,
(255, 255, 255),
pygame.Rect(rectX, 360 + rectY, self.cellSize, self.cellSize),
border_radius = 6
)
if n1 == 0 and n2 == 0:
continue
text_surface1 = self.myfont.render(f'{n1}', True, (0, 0, 0))
text_rect1 = text_surface1.get_rect(center=(rectX ,
rectY ))
self.screen.blit(text_surface1, text_rect1)
# text_surface2 = self.myfont.render(f'{n2}', True, (0, 0, 0))
# text_rect2 = text_surface2.get_rect(center=(rectX ,
# 360 + rectY ))
# self.screen.blit(text_surface2, text_rect2)
#staticmethod
def wait_for_key():
while True:
for event in pygame.event.get():
if event.type == QUIT:
return 'q'
if event.type == KEYDOWN:
if event.key == K_UP:
return 'u'
elif event.key == K_RIGHT:
return 'r'
elif event.key == K_LEFT:
return 'l'
elif event.key == K_DOWN:
return 'd'
elif event.key == K_q or event.key == K_ESCAPE:
return 'q'
def play(self):
self.new_number(k=2)
while True:
self.draw_game()
pygame.display.flip()
cmd = self.wait_for_key()
if cmd == 'q':
break
old_grid1 = self.grid1.copy()
old_grid2 = self.grid2.copy()
self.make_move(cmd)
print(game.grid1)
print(game.grid2)
if all((self.grid1 == old_grid1).flatten()) and all((self.grid2 == old_grid2).flatten()):
continue
self.new_number()
if __name__ == '__main__':
game = Py2048()
game.play()
this is the main code for the modified 2048 game that i wanna create
See How to Center Text in Pygame. When calculating the text rectangle, the center of the text rectangle must be set by the center of the grid. Store the tile rectangle in a variable and use it to set the center of the text rectangle:
for i in range(self.N):
rectY = self.blockSize * i + self.gap
for j in range(self.N):
n1 = self.grid1[i][j]
n2 = self.grid2[i][j]
rectX = 200 + self.blockSize * j + self.gap
tile_rect1 = pygame.Rect(rectX, 40 + rectY, self.cellSize, self.cellSize)
pygame.draw.rect(self.screen, (255, 255, 255), tile_rect1, border_radius = 6)
tile_rect2 = pygame.Rect(rectX, 360 + rectY, self.cellSize, self.cellSize),
pygame.draw.rect(self.screen, (255, 255, 255), tile_rect2, border_radius = 6)
if n1 == 0 and n2 == 0:
continue
text_surface1 = self.myfont.render(f'{n1}', True, (0, 0, 0))
text_rect1 = text_surface1.get_rect(center = tile_rect1.center)
self.screen.blit(text_surface1, text_rect1)
text_surface2 = self.myfont.render(f'{n2}', True, (0, 0, 0))
text_rect2 = text_surface2.get_rect(center = tile_rect2.center)
self.screen.blit(text_surface2, text_rect2)

Sliding image puzzle game - image not centered when game window is resized

I am working on a sliding puzzle game, but when I adjust the game window of the game the image with tiles is stock on the left side and it cannot go with center. I borrowed this code from GitHub. I am new with python and starting to explore new things. I want to learn more in python and thank you in advance. These are the codes:
import pygame as pg
import os.path
import random
import sys
class PuzzlerGame():
def init(self):
global BASICFONT
window_width = 1380
# window_width =700
window_height = 770
self.tile_width = 150
# self.tile_width = 75
self.tile_height = 150
# self.tile_height = 75
self.coloumn = 4
self.rows = 4
self.img_list = [0, "image1.jpg", "image2.jpg", "image3.jpg", "image4.jpg",
"image5.jpg", "image6.jpg", "image7.jpg", "image8.jpg",
"image9.jpg", "image10.jpg", ]
self.empty_tile = (3, 3)
global emptyc, emptyr
emptyc, emptyr = 3, 3
self.color = (255, 130, 130)
# white = (215,215,215)
self.yellow = (255, 255, 0)
self.red = (200, 15, 15)
self.black = (0, 0, 0)
self.tiles = {}
pg.init()
self.gameWindow = pg.display.set_mode((window_width, window_height))
# pg.display.set_caption("Puzzler")
pg.display.set_caption("Fun City slide puzzle")
# self.gameWindow.fill(white)
self.gameWindow.fill(self.red)
pg.display.update()
if (os.path.isfile('level.txt')):
lfile = open('level.txt', 'r')
# print(storefile)
self.level = int(lfile.read())
# self.level=str(lfile.read())
# print(self.highscore)
lfile.close()
else:
self.level = 1
# self.intro()
self.start(1)
def message(self, v1, u1, text):
rect_w = 70
rect_h = 70
font = pg.font.SysFont('comicsansms', 25)
TextSurf = font.render(text, True, self.black)
TextRect = TextSurf.get_rect()
TextRect.center = ((v1 * rect_w + ((rect_w - 3) / 2)),
(u1 * rect_h + (rect_h / 2)))
self.gameWindow.blit(TextSurf, TextRect)
pg.display.update()
def buttons(self, text):
# rect_w = 70
rect_w = 180
# rect_h = 70
rect_h = 180
color = self.color
# additional button
mouse_pos = pg.mouse.get_pos()
click = pg.mouse.get_pressed()
if (self.v * rect_w + rect_w - 3 > mouse_pos[0] > self.v * rect_w
and self.u * rect_h + rect_h - 3 > mouse_pos[1] > self.u * rect_h):
if int(text) <= self.level:
# if str(text)<=self.level:
color = (255, 30, 30)
if click[0] == 1:
self.start(int(text))
else:
pass
pg.draw.rect(self.gameWindow, color, [self.v * rect_w, self.u * rect_h,
rect_w - 100, rect_h - 3])
self.message(self.v, self.u, text)
# self.message(text)
pg.display.update()
def intro(self):
# additional for button
# NEW_SURF, NEW_RECT = self.makeText("New game", self.yellow, window_width - 120, window_height - 90)
while True:
self.v = 4
self.u = 5
for event in pg.event.get():
if event.type == pg.QUIT:
pg.quit()
sys.exit()
for rec in range(1, 2): # Level Number showing
# self.labels(300, 430, "Tap to Start", (0, 0, 255))
# self.buttons(str(rec))
# self.labels()
# self.message(self.v,self.u,str(rec))
self.v += 1
if self.v == 8:
self.v = 4
self.u += 1
#############################################################################
def labels(self, v1, u1, text, color, size=20):
font = pg.font.SysFont('comicsansms', size)
TextSurf = font.render(text, True, color)
TextRect = TextSurf.get_rect()
# print(TextRect)
TextRect.center = (v1, u1)
self.gameWindow.blit(TextSurf, TextRect)
pg.display.update()
def check(self):
global game_over
j, k = 0, 0
tag_list = []
for i in range(1, 17):
# print("checking ",i,tiles[(j,k)])
tag = "tag" + str(i)
# print(tag,j,k)
if self.tiles[(j, k)][1] == tag:
tag_list.append(tag)
j += 1
if j > 3:
k += 1
j = 0
else:
break
if i == 16:
print("GAME FINISHED")
game_over = True
def shift(self, c, r):
global emptyc, emptyr
rect_color = (255, 255, 255) # the square for suffling
# rect_color = (0,0,0)
self.gameWindow.blit(
self.tiles[(c, r)][0],
(emptyc * self.tile_width, emptyr * self.tile_height))
'''pg.draw.rect(gameWindow,black,[c*tile_width,r*tile_height,
tile_width-1,tile_height-1])'''
self.gameWindow.blit(
self.tiles[self.empty_tile][0],
(c * self.tile_width, r * self.tile_height))
# state[(emptyc, emptyr)] = state[(c, r)]
# state[(c, r)] = empty_tile
temp = self.tiles[(c, r)]
# print(temp,c,r)
self.tiles[(c, r)] = self.tiles[(emptyc, emptyr)]
self.tiles[(emptyc, emptyr)] = temp
emptyc, emptyr = c, r
# tiles[(emptyc, emptyr)].fill(black)
pg.draw.rect(self.gameWindow, rect_color, [c * self.tile_width, r * self.tile_height,
self.tile_width - 1, self.tile_height - 1])
self.empty_tile = (emptyc, emptyr)
# empty_tile.fill(0,0,0)
pg.display.flip()
def shuffle(self):
global emptyc, emptyr
# keep track of last shuffling direction to avoid "undo" shuffle moves
last_r = 0
for i in range(100):
# slow down shuffling for visual effect
pg.time.delay(50)
while True:
# pick a random direction and make a shuffling move
# if that is possible in that direction
r = random.randint(1, 4)
if (last_r + r == 5):
# don't undo the last shuffling move
continue
if r == 1 and (emptyc > 0):
self.shift(emptyc - 1, emptyr) # shift left
elif r == 4 and (emptyc < self.coloumn - 1):
self.shift(emptyc + 1, emptyr) # shift right
elif r == 2 and (emptyr > 0):
self.shift(emptyc, emptyr - 1) # shift up
elif r == 3 and (emptyr < self.rows - 1):
self.shift(emptyc, emptyr + 1) # shift down
else:
# the random shuffle move didn't fit in that direction
continue
last_r = r
break # a shuffling move was made
def start(self, l):
f = 1
imageX = 350
imageY = 50
global level, game_over
game_over = False
level = l
img = self.img_list[level]
self.image = pg.image.load("./Res/" + img)
button = pg.image.load("./efx/" + "button.jpg")
self.button = pg.image.load("./efx/" + "button.jpg")
self.gameWindow.fill((190, 190, 190)) # color of the window
for r in range(self.coloumn):
for c in range(self.rows):
tag = "tag" + str(f)
tile = self.image.subsurface(c * self.tile_width, r * self.tile_height,
self.tile_width - 1, self.tile_height - 1)
f += 1
self.tiles[(c, r)] = (tile, tag)
if (c, r) == self.empty_tile:
pg.draw.rect(self.gameWindow, (255, 255, 255),
# pg.draw.rect(self.gameWindow,(260,260,260),
[c * self.tile_width, r * self.tile_height,
self.tile_width - 1, self.tile_height - 1])#width and height of the white tile
break
self.gameWindow.blit(tile, (c * self.tile_width, r * self.tile_height)) # uploading the image through the window
#self.gameWindow.blit(tile,(imageX,imageY))
pg.display.update()
# print(tile)
# print(tiles)
# text = "Level "+str(level)
text = "Have fun!"
self.labels(350, 625, text, (0, 0, 255))
# self.labels(300,625,"Click to start Game",(0,0,255))
self.labels(700, 300, "Tap to start Game", (0, 0, 255))
self.gameWindow.blit(button, (640, 180))
pg.display.update()
self.gameloop()
def gameloop(self):
started = False
show_sol = False
global level
# self.gameWindow.fill((190,190,190),(150,610,300,40))
while True:
if game_over:
self.labels(300, 300, "Good job well played", (255, 100, 30), 50)
# self.labels(300,625,"Click to next Level",(0,0,255))
for event in pg.event.get():
# print(event)
if event.type == pg.QUIT:
pg.quit()
sys.exit()
if event.type == pg.MOUSEBUTTONDOWN:
# print(event.type)
# print(event.dict)
# shuffle()
if not started:
self.shuffle()
self.gameWindow.fill((190, 190, 190), (150, 610, 300, 40))
# self.labels(300,625,"Right click to see Solution",(0,0,255))
started = True
if game_over:
level += 1
# self.labels(300,300,"Good job well played",(255,100,30),50)
# self.labels(300,625,"Click to next Level",(0,0,255))
if self.level < level:
self.level += 1
file = open("level.txt", "w")
file.write(str(self.level))
file.close()
self.start(level)
if event.dict['button'] == 1:
mouse_pos = pg.mouse.get_pos()
c = mouse_pos[0] // self.tile_width
r = mouse_pos[1] // self.tile_height
# print("dot posn",emptyc,emptyr)
# print("mouse posn",c,r)
if c == emptyc and r == emptyr:
continue
elif c == emptyc and (r == emptyr - 1 or r == emptyr + 1):
self.shift(c, r)
self.check()
elif r == emptyr and (c == emptyc - 1 or c == emptyc + 1):
self.shift(c, r)
self.check()
# print(c,r)
elif event.dict['button'] == 3:
saved_image = self.gameWindow.copy()
# print(saved_image)
# gameWindow.fill(255,255,255)
self.gameWindow.blit(self.image, (0, 0))
pg.display.flip()
show_sol = True
elif show_sol and (event.type == pg.MOUSEBUTTONUP):
# stop showing the solution
self.gameWindow.blit(saved_image, (0, 0))
pg.display.flip()
show_sol = False
if name == "main":
PuzzlerGame()
The dest argument of pygame.Surface.blit() can also be a rectangle. To center an image on the screen get the bounding rectangle of the image with pygame.Surface.get_rect. Set the center of the rectangle by the center of the screen. Use the rectangle to blit the image:
game_window_rect = self.gameWindow.get_rect()
dest_rect = saved_image.get_rect(center = game_window_rect.center)
self.gameWindow.blit(saved_image, dest_rect)

Efficiency in Infections - Pygame

I am currently making an infection survival game for my A-level coursework, and I am struggling on how I can make this efficient.
When the cells get infected I need to check more and more cells, my computer science teacher recommended I save infections as a boolean value as I can do a lot more with that later, however it makes it more inefficient due to me having to eventually check the amount of cells squared which causes a lot of framerate issues.
My original idea was to store the uninfected and infected in separate lists but my comp sci teacher said I was over complicating it, however this didn't have any framerate issues.
A lot of my code has taken inspiration from this question Random movement pygame, especially when it comes to the cell movement.
TLDR: I want to make my code more efficient but I can't think of how
My code:
import sys, random, pygame
import matplotlib.pyplot as plt
from pygame.locals import *
import time
pygame.init()
#Window details
windowWidth = 400
windowHeight = 400
pixSize = 2
FPS = 60
screen = pygame.display.set_mode((windowWidth, windowHeight))
pygame.display.set_caption("Infection Game")
class Cell:
def __init__(self):
self.xPos = random.randrange(1,windowWidth)
self.yPos = random.randrange(1,windowHeight)
self.speed = 2
self.isInfected = False
self.infectionRange = 5
self.move = [None, None]
self.direction = None
def cellDraw(self):
if self.isInfected == False:
pygame.draw.rect(screen, (255,255,255), (self.xPos,self.yPos,pixSize,pixSize),0)
else:
pygame.draw.rect(screen, (0,255,0), (self.xPos,self.yPos,pixSize,pixSize),0)
def cellMovement(self):
directions = {"S":((-1,2),(1,self.speed)),"SW":((-self.speed,-1),(1,self.speed)),"W":((-self.speed,-1),(-1,2)),"NW":((-self.speed,-1),(-self.speed,-1)),"N":((-1,2),(-self.speed,-1)),"NE":((1,self.speed),(-self.speed,-1)),"E":((1,self.speed),(-1,2)),"SE":((1,self.speed),(1,self.speed))} #((min x, max x)(min y, max y))
directionsName = ("S","SW","W","NW","N","NE","E","SE") #possible directions
if random.randrange(0,5) == 2: #move about once every 5 frames
if self.direction == None: #if no direction is set, set a random one
self.direction = random.choice(directionsName)
else:
a = directionsName.index(self.direction) #get the index of direction in directions list
b = random.randrange(a-1,a+2) #set the direction to be the same, or one next to the current direction
if b > len(directionsName)-1: #if direction index is outside the list, move back to the start
b = 0
self.direction = directionsName[b]
self.move[0] = random.randrange(directions[self.direction][0][0],directions[self.direction][0][1]) + 0.35
self.move[1] = random.randrange(directions[self.direction][1][0],directions[self.direction][1][1]) + 0.35
if self.xPos < 5 or self.xPos > windowWidth - 5 or self.yPos < 5 or self.yPos > windowHeight - 5: #if cell is near the border of the screen, change direction
if self.xPos < 5:
self.direction = "E"
elif self.xPos > windowWidth - 5:
self.direction = "W"
elif self.yPos < 5:
self.direction = "S"
elif self.yPos > windowHeight - 5:
self.direction = "N"
self.move[0] = random.randrange(directions[self.direction][0][0],directions[self.direction][0][1]) + 0.35
self.move[1] = random.randrange(directions[self.direction][1][0],directions[self.direction][1][1]) + 0.35
if self.move[0] != None: #add the relative coordinates to the cells coordinates
self.xPos += self.move[0]
self.yPos += self.move[1]
def Infect(self):
for i in cellList:
if (self.xPos > i.xPos - self.infectionRange and self.xPos < i.xPos + self.infectionRange) and (self.yPos > i.yPos - self.infectionRange and self.yPos < i.yPos + self.infectionRange):
i.isInfected = True
xgraph = []
ygraph = []
cellList = []
startTime = time.time()
for i in range(1000):
cell = Cell()
cellList.append(cell)
cellList[0].isInfected = True
def gameLoop():
while True:
infectList = []
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
sys.exit()
screen.fill((0,0,0))
for i in cellList:
i.cellDraw()
i.cellMovement()
for i in cellList:
if i.isInfected == True:
i.Infect()
infectList.append(i)
xgraph.append(time.time()-startTime)
ygraph.append(len(infectList))
plt.plot(xgraph,ygraph)
plt.xlabel('time (s)')
plt.ylabel('infected')
if len(infectList) == 1000:
plt.show()
pygame.display.update() #update display
pygame.time.Clock().tick(FPS) #limit FPS
gameLoop()
First off, I've changed some of your code:
if self.isInfected == False:
if self.direction == None:
To
if not self.isInfected:
if self.direction is None:
Just so it reads a little a nicer.
Secondly, I've vectorized the Infect function:
uninfected = [i for i in cellList if not i.isInfected]
uninfected_array = np.array([[i.xPos, i.yPos] for i in uninfected])
indices = np.greater(uninfected_array[:, 0], self.xPos - self.infectionRange) * \
np.greater(self.xPos + self.infectionRange, uninfected_array[:, 0]) * \
np.greater(uninfected_array[:, 1], self.yPos - self.infectionRange) * \
np.greater(self.yPos + self.infectionRange, uninfected_array[:, 1])
for i in np.where(indices)[0]:
uninfected[i].isInfected = True
It takes the same time for this number of cells, but should scale better.
It turns out creating the array takes almost all the time. So you can create it once, pull it out of the loop and shave off a bunch of time:
def Infect(self, uninfected, uninfected_array):
indices = np.greater(uninfected_array[:, 0], self.xPos - self.infectionRange) * \
np.greater(self.xPos + self.infectionRange, uninfected_array[:, 0]) * \
np.greater(uninfected_array[:, 1], self.yPos - self.infectionRange) * \
np.greater(self.yPos + self.infectionRange, uninfected_array[:, 1])
for i in np.where(indices)[0]:
uninfected[i].isInfected = True
uninfected = [i for i in cellList if not i.isInfected]
uninfected_array = np.array([[i.xPos, i.yPos] for i in uninfected])
# To prevent errors with empty arrays
if len(uninfected) > 0:
for i in cellList:
if i.isInfected:
i.Infect(uninfected, uninfected_array)
# To prevent errors when everyone is infected
if infected == 0:
infected = len(cellList) - len(uninfected)
Lastly, you don't really seem to be using the infectList, so I replaced it with a counter:
infected = 0
if len(uninfected) > 0:
for i in cellList:
if i.isInfected:
infected += 1
As a side note, I'd change the UI controls a bit so it's easier to graph, instead of quitting using sys.exit it's nicer just to break out of the while loop. You also only plot the results once:
running = True
while running:
infectList = []
for event in pygame.event.get():
if event.type == QUIT:
running = False
...
pygame.quit()
plt.plot(xgraph, ygraph)
plt.xlabel('time (s)')
plt.ylabel('infected')
plt.show()
Implementing all this results in:
import random
import pygame
import matplotlib.pyplot as plt
from pygame.locals import *
import time
import numpy as np
pygame.init()
# Window details
windowWidth = 400
windowHeight = 400
pixSize = 2
FPS = 60
screen = pygame.display.set_mode((windowWidth, windowHeight))
pygame.display.set_caption("Infection Game")
class Cell:
def __init__(self):
self.xPos = random.randrange(1, windowWidth)
self.yPos = random.randrange(1, windowHeight)
self.speed = 2
self.isInfected = False
self.infectionRange = 5
self.move = [None, None]
self.direction = None
def cellDraw(self):
if not self.isInfected:
pygame.draw.rect(screen, (255, 255, 255), (self.xPos, self.yPos, pixSize, pixSize), 0)
else:
pygame.draw.rect(screen, (0, 255, 0), (self.xPos, self.yPos, pixSize, pixSize), 0)
def cellMovement(self):
directions = {"S": ((-1, 2), (1, self.speed)), "SW": ((-self.speed, -1), (1, self.speed)),
"W": ((-self.speed, -1), (-1, 2)), "NW": ((-self.speed, -1), (-self.speed, -1)),
"N": ((-1, 2), (-self.speed, -1)), "NE": ((1, self.speed), (-self.speed, -1)),
"E": ((1, self.speed), (-1, 2)),
"SE": ((1, self.speed), (1, self.speed))} # ((min x, max x)(min y, max y))
directionsName = ("S", "SW", "W", "NW", "N", "NE", "E", "SE") # possible directions
if random.randrange(0, 5) == 2: # move about once every 5 frames
if self.direction is None: # if no direction is set, set a random one
self.direction = random.choice(directionsName)
else:
a = directionsName.index(self.direction) # get the index of direction in directions list
b = random.randrange(a - 1,
a + 2) # set the direction to be the same, or one next to the current direction
if b > len(directionsName) - 1: # if direction index is outside the list, move back to the start
b = 0
self.direction = directionsName[b]
self.move[0] = random.randrange(directions[self.direction][0][0], directions[self.direction][0][1]) + 0.35
self.move[1] = random.randrange(directions[self.direction][1][0], directions[self.direction][1][1]) + 0.35
if self.xPos < 5 or self.xPos > windowWidth - 5 or self.yPos < 5 or self.yPos > windowHeight - 5: # if cell is near the border of the screen, change direction
if self.xPos < 5:
self.direction = "E"
elif self.xPos > windowWidth - 5:
self.direction = "W"
elif self.yPos < 5:
self.direction = "S"
elif self.yPos > windowHeight - 5:
self.direction = "N"
self.move[0] = random.randrange(directions[self.direction][0][0], directions[self.direction][0][1]) + 0.35
self.move[1] = random.randrange(directions[self.direction][1][0], directions[self.direction][1][1]) + 0.35
if self.move[0] is not None: # add the relative coordinates to the cells coordinates
self.xPos += self.move[0]
self.yPos += self.move[1]
def Infect(self, uninfected, uninfected_array):
indices = np.greater(uninfected_array[:, 0], self.xPos - self.infectionRange) * \
np.greater(self.xPos + self.infectionRange, uninfected_array[:, 0]) * \
np.greater(uninfected_array[:, 1], self.yPos - self.infectionRange) * \
np.greater(self.yPos + self.infectionRange, uninfected_array[:, 1])
for i in np.where(indices)[0]:
uninfected[i].isInfected = True
xgraph = []
ygraph = []
cellList = []
startTime = time.time()
for i in range(1000):
cell = Cell()
cellList.append(cell)
cellList[0].isInfected = True
def gameLoop():
running = True
while running:
infectList = []
for event in pygame.event.get():
if event.type == QUIT:
running = False
screen.fill((0, 0, 0))
for i in cellList:
i.cellDraw()
i.cellMovement()
infected = 0
uninfected = [i for i in cellList if not i.isInfected]
uninfected_array = np.array([[i.xPos, i.yPos] for i in uninfected])
if len(uninfected) > 0:
for i in cellList:
if i.isInfected:
i.Infect(uninfected, uninfected_array)
infected += 1
if infected == 0:
infected = len(cellList) - len(uninfected)
xgraph.append(time.time() - startTime)
ygraph.append(infected)
pygame.display.update() # update display
pygame.time.Clock().tick(FPS) # limit FPS
pygame.quit()
# figured this is what you wanted to do ;)
plt.plot(xgraph, ygraph)
plt.xlabel('time (s)')
plt.ylabel('infected')
plt.show()
gameLoop()
And it runs smooth

How do I move player on y axis in python 3?

I'm trying to move my character through a maze using bitmap. I'm not very good with python yet, so I don't know if this is obvious or not.
The code looks like this:
# the code that works
def movePlayerRight(self):
next_tile_x = self.player_tile_x + 1
if next_tile_x > NUM_TILE_ROWS:
return
elif self.bitmap[self.player_tile_y][next_tile_x] == -1:
return
else:
self.player_tile_x = next_tile_x
# the code that doesn't
def movePlayerUp(self):
next_tile_y = self.player_tile_y - 1
if next_tile_y < 0:
return
elif self.bitmap[self.player_tile_x][next_tile_y] == 1:
return
I couldn't think of a way to search this online besides here so...?
EDIT: I put that in, but the character was clipping through walls and, at certain points, saying the index was out of range?
Also one person said they wanted to see the whole code so:
import pygame
WHITE = ((255,255,255))
BLACK = ((0,0,0))
RED = ((255,0,0))
BLUE = ((0,0,255))
DISPLAY_HEIGHT = 600
DISPLAY_WIDTH = 800
map_bitmap = [[ 1, 1 , 1, 1, 1, 1, 1, 1],
[ 1, 1 , 0, 0, 0, 0, 0, 1],
[ 1, 1 , 1, 0, 1, 0, 0, 1],
[ 1, 0 , 0, 0, 0, 0, 0, 1],
[ 1, 0 , 0, 0, 0, 0, 0, 1],
[ 1, 1 , 1, 1, 1, 1, 1, 1]]
# These start at 0. So if there's 11 columns, it's 0 to 10
MAP_START_TILE_X = 3
MAP_START_TILE_Y = 4
MAP_END_TILE_X = 0
MAP_END_TILE_Y = 2
# Number of tiles per row/column we have
NUM_TILE_COLUMNS = len(map_bitmap[0])
NUM_TILE_ROWS = len(map_bitmap)
# Determines in pixels how wide/tall our tiles are
TILE_WIDTH = int(DISPLAY_WIDTH / NUM_TILE_COLUMNS)
TILE_HEIGHT = int(DISPLAY_HEIGHT / NUM_TILE_ROWS)
# This function is going to draw a bitmap to a surface
def draw_map(surface, bitmap):
# Loop through all indexes in our Y coordinate
for y in range(NUM_TILE_ROWS):
# Each list in this list represents a row
row = bitmap[y]
# Loop through all indexes in our X coordinate
for x in range(NUM_TILE_COLUMNS):
draw_tile = bitmap[y][x]
# If the tile value is 1, we have a wall. Draw a rectangle
if draw_tile == 1:
# render a rectangle
# Rect(left, top, width, height) -> Rect
wall_tile = pygame.Rect(TILE_WIDTH * x, TILE_HEIGHT * y, TILE_WIDTH, TILE_HEIGHT)
pygame.draw.rect(surface, BLACK, wall_tile)
# This function takes a surface and an X/Y coord and draws a red rectangle
# This rectangle represents our player.
# TODO: Figure out how to blit an image instead
def draw_player(surface, tile_x, tile_y):
# Translate tiles to pixels to draw our rectangle
player_tile = pygame.Rect(TILE_WIDTH * tile_x, TILE_HEIGHT * tile_y, TILE_WIDTH, TILE_HEIGHT)
# Draw the tile. Right now
pygame.draw.rect(surface, RED, player_tile)
def draw_fog_of_war(surface, tile_x, tile_y, radius):
# Define some new colors
TRANSPARENT = (0,0,255,0)
GREY = (220,220,220,255)
# Build our overlay surface
overlay_surface = pygame.Surface((DISPLAY_WIDTH, DISPLAY_HEIGHT), pygame.SRCALPHA)
overlay_surface.fill(GREY)
# Convert from tile position to pixels
# Note that we need to consider the CENTER of the tile, not the top-left
center_x = (tile_x * TILE_WIDTH) + (int(TILE_WIDTH / 2))
center_y = (tile_y * TILE_HEIGHT) + (int(TILE_HEIGHT / 2))
center = (center_x, center_y)
# Draw transparent circle on overlay surface
pygame.draw.circle(overlay_surface, TRANSPARENT, center, radius)
# Cover original surface with overlay surface
# blit(source, dest, area=None, special_flags=0) -> Rect
surface.blit(overlay_surface, (0,0))
# Notes:
# Don't forget "self" :)
# Methods (class functions) serve as was to change/get information about the object
# All methods have AT LEAST one parameter: self
# __init__ is called implicitly during instantiation. This is where you configure your object's attributes (class variables)
# Don't forget "self" :)
class Maze:
surface = None
bitmap = []
player_tile_x = -1
player_tile_y = -1
end_tile_x = 4
end_tile_y = 0
def __init__(self, surface, bitmap, start_tile_x, start_tile_y, end_tile_x, end_tile_y):
self.surface = surface
self.bitmap = bitmap
self.player_tile_x = start_tile_x
self.player_tile_y = start_tile_y
self.end_tile_x = end_tile_x
self.end_tile_y = end_tile_y
print("Player at: (%d, %d)" % (self.player_tile_x, self.player_tile_y))
def render(self):
# Recreate our world
self.surface.fill(WHITE)
draw_map(self.surface, self.bitmap)
draw_player(self.surface, self.player_tile_x, self.player_tile_y)
# Kinda arbitrarily setting radius, adjust as needed
radius = TILE_WIDTH * 2
# NOTE: Comment out the draw_fog_of_war to disable this
# Useful when you need to look at the whole map
draw_fog_of_war(self.surface, self.player_tile_x, self.player_tile_y, radius)
def movePlayerLeft(self):
# Shifting left means subtracting X coord by 1
next_tile_x = self.player_tile_x - 1
# Check to see if we run off the map
if next_tile_x < 0:
# Do nothing, return
return
# Check to see if we bump into a tile occupied by a wall
elif self.bitmap[self.player_tile_y][next_tile_x] == 1:
# Do nothing, return
return
# Should be an empty, available tile to move into
else:
# Update our player's X coord position
self.player_tile_x = next_tile_x
def movePlayerRight(self):
next_tile_x = self.player_tile_x + 1
if next_tile_x > NUM_TILE_ROWS:
return
elif self.bitmap[self.player_tile_y][next_tile_x] == -1:
return
else:
self.player_tile_x = next_tile_x
def movePlayerUp(self):
next_tile_y = self.player_tile_y - 1
if next_tile_y < 0:
return
elif self.bitmap[self.player_tile_x][next_tile_y] == -1:
return
else:
self.player_tile_y = next_tile_y
def movePlayerDown(self):
next_tile_y = self.player_tile_y + 1
if next_tile_y > NUM_TILE_COLUMNS:
return
elif self.bitmap[self.player_tile_y][next_tile_y] == 1:
return
else:
self.player_tile_y = next_tile_y
# How we can determine if a player has reached the file tile
def isPlayerAtEnd(self):
if (self.player_tile_x == self.end_tile_x) and (self.player_tile_y == self.end_tile_y):
return True
else:
return False
def main():
# Initialize the module
pygame.init()
# Create a display, returns the default surface to draw on which matches
# the defined resolution
surface = pygame.display.set_mode((DISPLAY_WIDTH,DISPLAY_HEIGHT))
# Create our maze
# __init__(self, surface, bitmap, start_tile_x, start_tile_y, end_tile_x, end_tile_y):
maze = Maze(surface, map_bitmap, MAP_START_TILE_X, MAP_START_TILE_Y, MAP_END_TILE_X, MAP_END_TILE_Y)
# Render the objects onto the surface
maze.render()
# Update the display
pygame.display.update()
running = True
while running:
# Wait for an event. This is different then the timer method
# We are not updating anything until an event is triggered
event = pygame.event.wait()
print(event)
if event.type == pygame.QUIT:
running = False
# Check all key press events.
# Only left movement is implemented right now
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_ESCAPE:
running = False
elif event.key == pygame.K_LEFT:
maze.movePlayerLeft()
elif event.key == pygame.K_RIGHT:
maze.movePlayerRight()
elif event.key == pygame.K_UP:
maze.movePlayerUp()
elif event.key == pygame.K_DOWN:
maze.movePlayerDown()
# Re-render our world
maze.render()
# Update the display
pygame.display.update()
# Did we win? For now, we'll just quit
# TODO: do something more elegant here
if maze.isPlayerAtEnd():
# We won! Exit
running = False
if __name__ == "__main__":
main()
pygame.quit()
quit()
You are missing the else statement in your movePlayerUp function.
def movePlayerUp(self):
next_tile_y = self.player_tile_y - 1
if next_tile_y < 0:
return
elif self.bitmap[self.player_tile_x][next_tile_y] == 1:
return
else:
self.player_tile_y = next_tile_y

Show the player's score in game and update it

I'm new to programming and I'm currently working on a game what's like the game squirrel where you eat others who are smaller than you and get damage of larger ones. I now wanted to display the player's size, which will do it perfectly but it displays only the start size. So when I ate a foe I want that the number changes but I can't figure out how.
def main():
global FPSCLOCK, DISPLAYSURF, BASICFONT, L_SQUIR_IMG, R_SQUIR_IMG, GRASSIMAGES, MEL, MER, L_SQUIR_IMG2, R_SQUIR_IMG2
pygame.init()
FPSCLOCK = pygame.time.Clock()
pygame.display.set_icon(pygame.image.load('cat.png'))
DISPLAYSURF = pygame.display.set_mode((WINWIDTH, WINHEIGHT))
pygame.display.set_caption('Space CAT')
BASICFONT = pygame.font.Font('freesansbold.ttf', 32)
# load the image files
MEL = pygame.image.load("cat.png")
MER = pygame.transform.flip(MEL, True, False)
L_SQUIR_IMG = pygame.image.load("foe1.png")
R_SQUIR_IMG = pygame.transform.flip(L_SQUIR_IMG, True, False)
L_SQUIR_IMG2 = pygame.image.load("spacemouse2.png")
R_SQUIR_IMG2 = pygame.transform.flip(L_SQUIR_IMG2, True, False)
GRASSIMAGES = []
for i in range(1, 5):
GRASSIMAGES.append(pygame.image.load("grass%s.png" % i))
while True:
runGame()
def runGame():
# set up variables for the start of a new game
invulnerableMode = False # if the player is invulnerable
invulnerableStartTime = 0 # time the player became invulnerable
gameOverMode = False # if the player has lost
gameOverStartTime = 0 # time the player lost
winMode = False # if the player has won
Level2 = False # if Level 2 is reached
# create the surfaces to hold game text
gameOverSurf = BASICFONT.render('Game Over', True, WHITE)
gameOverRect = gameOverSurf.get_rect()
gameOverRect.center = (HALF_WINWIDTH, HALF_WINHEIGHT)
winSurf = BASICFONT.render('You have achieved ALPHA CAT!', True, WHITE)
winRect = winSurf.get_rect()
winRect.center = (HALF_WINWIDTH, HALF_WINHEIGHT)
winSurf2 = BASICFONT.render('(Press "r" to restart.)', True, WHITE)
winRect2 = winSurf2.get_rect()
winRect2.center = (HALF_WINWIDTH, HALF_WINHEIGHT + 30)
winSurf3 = BASICFONT.render('You have reached Level 2', True, WHITE)
winRect3 = winSurf3.get_rect()
winRect3.center = (HALF_WINWIDTH, HALF_WINHEIGHT)
# camerax and cameray are the top left of where the camera view is
camerax = 0
cameray = 0
grassObjs = [] # stores all the star objects in the game
squirrelObjs = [] # stores all the non-player fish objects
squirrelObjs2 = [] #stores all the non-player mouse objects
# stores the player object:
playerObj = {'surface': pygame.transform.scale(MEL, (STARTSIZE, STARTSIZE)),
'facing': LEFT,
'size': STARTSIZE,
'x': HALF_WINWIDTH,
'y': HALF_WINHEIGHT,
'bounce':0,
'health': MAXHEALTH}
# show the player's score
winSurf4 = BASICFONT.render(str(playerObj['size']), True, RED)
winRect4 = winSurf4.get_rect()
winRect4.center = (HALF_WINWIDTH + 680, HALF_WINHEIGHT - 420)
moveLeft = False
moveRight = False
moveUp = False
moveDown = False
# start off with some random grass images on the screen
for i in range(7):
grassObjs.append(makeNewGrass(camerax, cameray))
grassObjs[i]['x'] = random.randint(0, WINWIDTH)
grassObjs[i]['y'] = random.randint(0, WINHEIGHT)
while True: # main game loop
# Check if we should turn off invulnerability
if invulnerableMode and time.time() - invulnerableStartTime > INVULNTIME:
invulnerableMode = False
#### move all the fish
for sObj in squirrelObjs:
# move the fish, and adjust for their bounce
sObj['x'] += sObj['movex']
sObj['y'] += sObj['movey']
sObj['bounce'] += 0
if sObj['bounce'] > sObj['bouncerate']:
sObj['bounce'] = 0 # reset bounce amount
# random chance they change direction
if random.randint(0, 99) < DIRCHANGEFREQ:
sObj['movex'] = getRandomVelocity()
sObj['movey'] = getRandomVelocity()
if sObj['movex'] > 0: # faces right
sObj['surface'] = pygame.transform.scale(R_SQUIR_IMG, (sObj['width'], sObj['height']))
else: # faces left
sObj['surface'] = pygame.transform.scale(L_SQUIR_IMG, (sObj['width'], sObj['height']))
#### move all the mice
for sObj2 in squirrelObjs2:
# move the mice, and adjust for their bounce
sObj2['x'] += sObj2['movex']
sObj2['y'] += sObj2['movey']
sObj2['bounce'] += 0
if sObj2['bounce'] > sObj2['bouncerate']:
sObj2['bounce'] = 0 # reset bounce amount
# random chance they change direction
if random.randint(0, 99) < DIRCHANGEFREQ:
sObj2['movex'] = getRandomVelocity()
sObj2['movey'] = getRandomVelocity()
if sObj2['movex'] > 0: # faces right
sObj2['surface'] = pygame.transform.scale(R_SQUIR_IMG2, (sObj2['width'], sObj2['height']))
else: # faces left
sObj2['surface'] = pygame.transform.scale(L_SQUIR_IMG2, (sObj2['width'], sObj2['height']))
#### go through all the objects and see if any need to be deleted.(1)
for i in range(len(grassObjs) - 1, -1, -1):
if isOutsideActiveArea(camerax, cameray, grassObjs[i]):
del grassObjs[i]
for i in range(len(squirrelObjs) - 1, -1, -1):
if isOutsideActiveArea(camerax, cameray, squirrelObjs[i]):
del squirrelObjs[i]
#### go through all the objects and see if any need to be deleted.(2)
for i in range(len(squirrelObjs2) - 1, -1, -1):
if isOutsideActiveArea(camerax, cameray, squirrelObjs2[i]):
del squirrelObjs2[i]
#### add more stars & foes if we don't have enough.
while len(grassObjs) < NUMGRASS:
grassObjs.append(makeNewGrass(camerax, cameray))
if Level2 == False:
while len(squirrelObjs) < NUMSQUIRRELS:
squirrelObjs.append(makeNewFish(camerax, cameray))
#### Level 2 spawn mouse
if Level2 == True:
while len(squirrelObjs2) < NUMSQUIRRELS:
squirrelObjs2.append(makeNewMice(camerax, cameray))
# adjust camerax and cameray if beyond the "camera slack"
playerCenterx = playerObj['x'] + int(playerObj['size'] / 2)
playerCentery = playerObj['y'] + int(playerObj['size'] / 2)
if (camerax + HALF_WINWIDTH) - playerCenterx > CAMERASLACK:
camerax = playerCenterx + CAMERASLACK - HALF_WINWIDTH
elif playerCenterx - (camerax + HALF_WINWIDTH) > CAMERASLACK:
camerax = playerCenterx - CAMERASLACK - HALF_WINWIDTH
if (cameray + HALF_WINHEIGHT) - playerCentery > CAMERASLACK:
cameray = playerCentery + CAMERASLACK - HALF_WINHEIGHT
elif playerCentery - (cameray + HALF_WINHEIGHT) > CAMERASLACK:
cameray = playerCentery - CAMERASLACK - HALF_WINHEIGHT
# draw the black background
DISPLAYSURF.fill(GRASSCOLOR)
# draw all the grass objects on the screen
for gObj in grassObjs:
gRect = pygame.Rect( (gObj['x'] - camerax,
gObj['y'] - cameray,
gObj['width'],
gObj['height']) )
DISPLAYSURF.blit(GRASSIMAGES[gObj['grassImage']], gRect)
### draw the fish
for sObj in squirrelObjs:
sObj['rect'] = pygame.Rect( (sObj['x'] - camerax,
sObj['y'] - cameray - getBounceAmount(sObj['bounce'], sObj['bouncerate'], sObj['bounceheight']),
sObj['width'],
sObj['height']) )
DISPLAYSURF.blit(sObj['surface'], sObj['rect'])
### draw the mice
for sObj2 in squirrelObjs2:
sObj2['rect'] = pygame.Rect( (sObj2['x'] - camerax,
sObj2['y'] - cameray - getBounceAmount(sObj2['bounce'], sObj2['bouncerate'], sObj2['bounceheight']),
sObj2['width'],
sObj2['height']) )
DISPLAYSURF.blit(sObj2['surface'], sObj2['rect'])
### draw the player
flashIsOn = round(time.time(), 1) * 10 % 2 == 1
if not gameOverMode and not (invulnerableMode and flashIsOn):
playerObj['rect'] = pygame.Rect( (playerObj['x'] - camerax,
playerObj['y'] - cameray - getBounceAmount(playerObj['bounce'], BOUNCERATE, BOUNCEHEIGHT),
playerObj['size'],
playerObj['size']) )
DISPLAYSURF.blit(playerObj['surface'], playerObj['rect'])
### draw the health meter
drawHealthMeter(playerObj['health'])
for event in pygame.event.get(): # event handling loop
if event.type == QUIT:
terminate()
elif event.type == KEYDOWN:
if event.key in (K_UP, K_w):
moveDown = False
moveUp = True
elif event.key in (K_DOWN, K_s):
moveUp = False
moveDown = True
elif event.key in (K_LEFT, K_a):
moveRight = False
moveLeft = True
if playerObj['facing'] != LEFT: # change player image
playerObj['surface'] = pygame.transform.scale(MEL, (playerObj['size'], playerObj['size']))
playerObj['facing'] = LEFT
elif event.key in (K_RIGHT, K_d):
moveLeft = False
moveRight = True
if playerObj['facing'] != RIGHT: # change player image
playerObj['surface'] = pygame.transform.scale(MER, (playerObj['size'], playerObj['size']))
playerObj['facing'] = RIGHT
elif winMode and event.key == K_r:
return
elif event.type == KEYUP:
# stop moving the player
if event.key in (K_LEFT, K_a):
moveLeft = False
elif event.key in (K_RIGHT, K_d):
moveRight = False
elif event.key in (K_UP, K_w):
moveUp = False
elif event.key in (K_DOWN, K_s):
moveDown = False
elif event.key == K_ESCAPE:
terminate()
if not gameOverMode:
# actually move the player
if moveLeft:
playerObj['x'] -= MOVERATE
if moveRight:
playerObj['x'] += MOVERATE
if moveUp:
playerObj['y'] -= MOVERATE
if moveDown:
playerObj['y'] += MOVERATE
if (moveLeft or moveRight or moveUp or moveDown) or playerObj['bounce'] != 0:
playerObj['bounce'] += 0
if playerObj['bounce'] > BOUNCERATE:
playerObj['bounce'] = 0 # reset bounce amount
#### check if the player has collided with any fish
for i in range(len(squirrelObjs)-1, -1, -1):
sqObj = squirrelObjs[i]
if 'rect' in sqObj and playerObj['rect'].colliderect(sqObj['rect']):
# a player/fish collision has occurred
if sqObj['width'] * sqObj['height'] <= playerObj['size']**2:
# player is larger and eats the fish
playerObj['size'] += int( (sqObj['width'] * sqObj['height'])**0.2 ) + 1
del squirrelObjs[i]
if playerObj['facing'] == LEFT:
playerObj['surface'] = pygame.transform.scale(MEL, (playerObj['size'], playerObj['size']))
if playerObj['facing'] == RIGHT:
playerObj['surface'] = pygame.transform.scale(MER, (playerObj['size'], playerObj['size']))
if playerObj['size'] > WINSIZE/2:
Level2 = True # Turn on Level 2
if playerObj['size'] > WINSIZE:
winMode = True # turn on "win mode"
elif not invulnerableMode:
# player is smaller and takes damage
invulnerableMode = True
invulnerableStartTime = time.time()
playerObj['health'] -= 1
if playerObj['health'] == 0:
gameOverMode = True # turn on "game over mode"
gameOverStartTime = time.time()
### check if the player has collided with any mice
for i in range(len(squirrelObjs2)-1, -1, -1):
sqObj2 = squirrelObjs2[i]
if 'rect' in sqObj2 and playerObj['rect'].colliderect(sqObj2['rect']):
# a player/mouse collision has occurred
if sqObj2['width'] * sqObj2['height'] <= playerObj['size']**2:
# player is larger and eats the mouse
playerObj['size'] += int( (sqObj2['width'] * sqObj2['height'])**0.2 ) + 1
del squirrelObjs2[i]
if playerObj['facing'] == LEFT:
playerObj['surface'] = pygame.transform.scale(MEL, (playerObj['size'], playerObj['size']))
if playerObj['facing'] == RIGHT:
playerObj['surface'] = pygame.transform.scale(MER, (playerObj['size'], playerObj['size']))
if playerObj['size'] > WINSIZE/2:
Level2 = True # Turn on Level 2
if playerObj['size'] > WINSIZE:
winMode = True # turn on "win mode"
elif not invulnerableMode:
# player is smaller and takes damage
invulnerableMode = True
invulnerableStartTime = time.time()
playerObj['health'] -= 1
if playerObj['health'] == 0:
gameOverMode = True # turn on "game over mode"
gameOverStartTime = time.time()
else:
# game is over, show "game over" text
DISPLAYSURF.blit(gameOverSurf, gameOverRect)
if time.time() - gameOverStartTime > GAMEOVERTIME:
return # end the current game
# show the player's size
if not winMode:
DISPLAYSURF.blit(winSurf4, winRect4)
# check if the player has reached level 2.
if Level2 and playerObj['size'] < WINSIZE/2+10:
DISPLAYSURF.blit(winSurf3, winRect3)
# check if the player has won.
if winMode:
DISPLAYSURF.blit(winSurf, winRect)
DISPLAYSURF.blit(winSurf2, winRect2)
pygame.display.update()
FPSCLOCK.tick(FPS)
Your code rendering the size is:
winSurf4 = BASICFONT.render(str(playerObj['size']), True, RED)
winRect4 = winSurf4.get_rect()
winRect4.center = (HALF_WINWIDTH + 680, HALF_WINHEIGHT - 420)
You call it only at the beginning of the program, so the score is displayed only once.
Just move this code to your main loop:
while True:
(...)
winSurf4 = BASICFONT.render(str(playerObj['size']), True, RED)
winRect4 = winSurf4.get_rect()
winRect4.center = (HALF_WINWIDTH + 680, HALF_WINHEIGHT - 420)
(...)
The score will be refreshed at every iteration. This will do the job, but it is probably unnecessary. It would be best to execute this routine only when the score changes internally, so as to reduce the unnecessary execution of code.

Categories