Mapping Grid Position To Matrix Position - python
I needed help, I was trying to map the position of a ghost in its current position such as (225, 175) to its position on the matrix (7,9), not sure what the math is to calculate its relative position, the reason why im asking is because it makes it easier to detect if theres a wall in matrix position as opposed to current position. I want to be able to do this so I can decide its next move at an intersection.
import pygame
import time
import random
import pickle
import math
pygame.init()
pygame.mixer.init()
pygame.display.set_caption("Pac-Man")
# Sets the size of the screen via (WIDTH, HEIGHT)
SCREEN_WIDTH = 478
SCREEN_HEIGHT = 608
# Speed of Characters
SPEED = 1
# Frames per second, how fast the game runs
FPS = 50
# Colors (RED,GREEN,BLUE)
BLACK = (0, 0, 0)
WHITE = (255, 255, 255)
YELLOW = (255, 255, 0)
BLUE = (0, 0, 255)
# Sets the WIDTH and HEIGHT of the window
WINDOW = (SCREEN_WIDTH, SCREEN_HEIGHT)
# Displays the screen
SCREEN = pygame.display.set_mode(WINDOW)
CLOCK = pygame.time.Clock()
PacManStartSurface = pygame.transform.scale(pygame.image.load
("PacManStart.png"), (23, 23))
PacManStartSurface.convert()
PacManStartRect = PacManStartSurface.get_rect(topleft =
(((SCREEN_WIDTH - 25) // 2),
(SCREEN_HEIGHT + 144) // 2))
PacManSurface = pygame.transform.scale(pygame.image.load
("PacManRight.png"), (23, 23))
PacManSurface.convert()
PacManRect = PacManStartSurface.get_rect(topleft =
(((SCREEN_WIDTH - 125) // 2),
(SCREEN_HEIGHT + 144) // 2))
CurrentSurface = PacManStartSurface
CurrentRect = PacManStartRect
BackgroundSurface = pygame.image.load("Background.png").convert()
PinkGhostSurface = pygame.transform.scale(pygame.image.load("PinkGhost.png")
.convert(), (23, 23))
PinkGhostRect = PinkGhostSurface.get_rect()
YellowGhostSurface = pygame.transform.scale(pygame.image.load
("YellowGhost.png")
.convert(), (23, 23))
YellowGhostRect = YellowGhostSurface.get_rect()
RedGhostSurface = pygame.transform.scale(pygame.image.load("RedGhost.png")
.convert(), (23, 23))
RedGhostRect = RedGhostSurface.get_rect()
BlueGhostSurface = pygame.transform.scale(pygame.image.load("BlueGhost.png")
.convert(), (23, 23))
BlueGhostRect = BlueGhostSurface.get_rect()
pygame.mixer.music.load('power_pellet.wav')
Font = pygame.font.Font("emulogic.ttf", 15)
class PacMan():
def __init__(self):
self.LIVES = 3
class Maze():
def __init__(self):
self.DOTS = []
self.WALLS = []
self.ENERGIZER = []
self.GHOSTS = []
self.WALLS_XY = []
self.BLOCK_WIDTH = 25
self.BLOCK_HEIGHT = 25
self.MAZE_OFFSET_X = 0
self.MAZE_OFFSET_Y = 50
# 0 - Dots
# 1 - Walls
# 2 - Empty Spaces
# 3 - Energizers
# 4 - Ghosts
self.MATRIX = [1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1], \
[1,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,1], \
[1,3,1,1,0,1,1,1,0,1,0,1,1,1,0,1,1,3,1], \
[1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1], \
[1,0,1,1,0,1,0,1,1,1,1,1,0,1,0,1,1,0,1], \
[1,0,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,0,1], \
[1,1,1,1,0,1,1,1,2,1,2,1,1,1,0,1,1,1,1], \
[2,2,2,1,0,1,2,2,2,4,2,2,2,1,0,1,2,2,2], \
[1,1,1,1,0,1,2,1,1,1,1,1,2,1,0,1,1,1,1], \
[0,0,0,0,0,2,2,1,4,4,4,1,2,2,0,0,0,0,0], \
[1,1,1,1,0,1,2,1,1,1,1,1,2,1,0,1,1,1,1], \
[2,2,2,1,0,1,2,2,2,2,2,2,2,1,0,1,2,2,2], \
[1,1,1,1,0,1,2,1,1,1,1,1,2,1,0,1,1,1,1], \
[1,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,1], \
[1,3,1,1,0,1,1,1,0,1,0,1,1,1,0,1,1,3,1], \
[1,0,0,1,0,0,0,0,0,2,0,0,0,0,0,1,0,0,1], \
[1,1,0,1,0,1,0,1,1,1,1,1,0,1,0,1,0,1,1], \
[1,0,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,0,1], \
[1,0,1,1,1,1,1,1,0,1,0,1,1,1,1,1,1,0,1], \
[1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1], \
[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1]
# BackgroundImage(X, Y, WIDTH, HEIGHT)
self.MAZE_X = self.BLOCK_WIDTH * (len(self.MATRIX[0])
+ self.MAZE_OFFSET_X)
self.MAZE_Y = self.BLOCK_HEIGHT * (len(self.MATRIX)
+ self.MAZE_OFFSET_Y)
self.MAZE_WIDTH = self.BLOCK_WIDTH * len(self.MATRIX[0])
self.MAZE_HEIGHT = self.BLOCK_HEIGHT * len(self.MATRIX)
def DrawMaze(self, MazeSurface):
for ROW in range(len(self.MATRIX)):
for COLUMN in range(len(self.MATRIX[0])):
# Saves the position of each dot
if self.MATRIX[ROW][COLUMN] == 0:
self.DOTS.append([(self.BLOCK_WIDTH * COLUMN),
(self.BLOCK_HEIGHT * ROW), 4, 4])
# Saves the position of each wall
if self.MATRIX[ROW][COLUMN] == 1:
self.WALLS.append(pygame.draw.rect(MazeSurface, WHITE,
[((self.BLOCK_WIDTH) * COLUMN),
((self.BLOCK_HEIGHT) * ROW),
self.BLOCK_WIDTH, self.BLOCK_HEIGHT]))
# Saves the position of each Energizer
if self.MATRIX[ROW][COLUMN] == 3:
self.ENERGIZER.append([(self.BLOCK_WIDTH * COLUMN),
(self.BLOCK_HEIGHT * ROW), 14, 14])
if self.MATRIX[ROW][COLUMN] == 4:
self.GHOSTS.append([(self.BLOCK_WIDTH * COLUMN),
(self.BLOCK_HEIGHT * ROW), 23, 23])
for WALL in self.WALLS:
X, Y, WIDTH, HEIGHT = WALL
self.WALLS_XY.append((X, Y))
class Main(Maze):
def __init__(self):
# Inherits Maze class
Maze.__init__(self)
self.TimeBetweenBites = 0.1
self.LastBiteTime = time.time()
self.MouthOpen = False
self.PacManDirection = ""
self.GhostDirection = ""
self.SCORE = 0
self.HIGH_SCORE = 0
self.GridSizeX = SCREEN_HEIGHT // 19
self.GridSizeY = SCREEN_HEIGHT // 32
def PacManMovement(self):
key = pygame.key.get_pressed()
if key[pygame.K_LEFT] and not key[pygame.K_UP] \
and not key[pygame.K_DOWN]:
self.PacManDirection = "LEFT"
elif key[pygame.K_RIGHT] and not key[pygame.K_UP] \
and not key[pygame.K_DOWN]:
self.PacManDirection = "RIGHT"
elif key[pygame.K_UP] and not key[pygame.K_LEFT] \
and not key[pygame.K_RIGHT]:
self.PacManDirection = "UP"
elif key[pygame.K_DOWN] and not key[pygame.K_LEFT] \
and not key[pygame.K_RIGHT]:
self.PacManDirection = "DOWN"
def ContinuePacManMovement(self):
if self.PacManDirection == "LEFT":
CurrentRect.x -= SPEED
self.PacManWallDetection(-1, 0, CurrentRect)
if self.PacManDirection == "RIGHT":
CurrentRect.x += SPEED
self.PacManWallDetection(1, 0, CurrentRect)
if self.PacManDirection == "UP":
CurrentRect.y -= SPEED
self.PacManWallDetection(0, -1, CurrentRect)
if self.PacManDirection == "DOWN":
CurrentRect.y += SPEED
self.PacManWallDetection(0, 1, CurrentRect)
def ContinueGhostMovement(self):
if self.GhostDirection == "LEFT":
PinkGhostRect.x -= SPEED
self.GhostWallDetection(-1, 0, PinkGhostRect)
if self.GhostDirection == "RIGHT":
PinkGhostRect.x += SPEED
self.GhostWallDetection(1, 0, PinkGhostRect)
if self.GhostDirection == "UP":
PinkGhostRect.y -= SPEED
self.GhostWallDetection(0, -1, PinkGhostRect)
if self.GhostDirection == "DOWN":
PinkGhostRect.y += SPEED
self.GhostWallDetection(-1, 0, PinkGhostRect)
def PacManTeleport(self):
if CurrentRect.right < 0:
CurrentRect.right = SCREEN_WIDTH + 20
if CurrentRect.left > SCREEN_WIDTH:
CurrentRect.right = 0
def GhostTeleport(self, Intersection):
if PinkGhostRect.right < 0:
PinkGhostRect.right = SCREEN_WIDTH + 20
Intersection.append("LEFT")
if PinkGhostRect.left > SCREEN_WIDTH:
PinkGhostRect.right = 0
Intersection.append("RIGHT")
def PacManWallDetection(self, x, y, CurrentRect):
CurrentRect.right += x
for WALL in self.WALLS:
COLLIDE = CurrentRect.colliderect(WALL)
if COLLIDE:
if x < 0:
CurrentRect.left = WALL.right
CurrentSurface = pygame.transform.rotate(PacManSurface, 180)
MazeSurface.blit(CurrentSurface, CurrentRect)
if x > 0:
CurrentRect.right = WALL.left
break
CurrentRect.top += y
for WALL in self.WALLS:
COLLIDE = CurrentRect.colliderect(WALL)
if COLLIDE:
if y < 0:
CurrentRect.top = WALL.bottom
if y > 0:
CurrentRect.bottom = WALL.top
break
def GhostWallDetection(self, x, y, PinkGhostRect):
PinkGhostRect.right += x
for WALL in self.WALLS:
COLLIDE = PinkGhostRect.colliderect(WALL)
if COLLIDE:
if x < 0:
PinkGhostRect.left = WALL.right
if random.randrange(0, 100) <= 40:
self.GhostDirection = "RIGHT"
if x > 0:
PinkGhostRect.right = WALL.left
if random.randrange(0, 100) <= 40:
self.GhostDirection = "LEFT"
break
PinkGhostRect.top += y
for WALL in self.WALLS:
COLLIDE = PinkGhostRect.colliderect(WALL)
if COLLIDE:
if y < 0:
PinkGhostRect.top = WALL.bottom
if random.randrange(0, 100) <= 40:
self.GhostDirection = "DOWN"
if y > 0:
PinkGhostRect.bottom = WALL.top
if random.randrange(0, 100) <= 40:
self.GhostDirection = "UP"
break
def GetAvailableMoves(self):
Intersection = []
self.GhostTeleport(Intersection)
print(PinkGhostRect.topleft)
print(self.WALLS_XY)
if ((PinkGhostRect.x - 1, PinkGhostRect.y)) not in self.WALLS_XY:
Intersection.append("LEFT")
if ((PinkGhostRect.x + 1, PinkGhostRect.y)) not in self.WALLS_XY:
Intersection.append("RIGHT")
if ((PinkGhostRect.x, PinkGhostRect.y - 1)) not in self.WALLS_XY:
Intersection.append("UP")
if ((PinkGhostRect.x, PinkGhostRect.y + 1)) not in self.WALLS_XY:
Intersection.append("DOWN")
print(Intersection)
return Intersection
def EatDots(self):
for ROW in range(len(self.MATRIX)):
for COLUMN in range(len(self.MATRIX[0])):
for DOT in self.DOTS:
CHOMP = CurrentRect.colliderect(DOT)
if CHOMP:
Main.PlaySound(self, 0)
self.DOTS.remove(DOT)
self.MATRIX[ROW][COLUMN] = 3
self.SCORE += 10
if self.SCORE > self.HIGH_SCORE:
self.HIGH_SCORE = self.SCORE
return str(self.SCORE), str(self.HIGH_SCORE)
def EatEnergizer(self):
for ROW in range(len(self.MATRIX)):
for COLUMN in range(len(self.MATRIX[0])):
for POWERUP in self.ENERGIZER:
CHOMP = CurrentRect.colliderect(POWERUP)
if CHOMP:
self.ENERGIZER.remove(POWERUP)
self.MATRIX[ROW][COLUMN] = 3
self.SCORE += 50
Main.PlaySound(self, 1)
if self.SCORE > self.HIGH_SCORE:
self.HIGH_SCORE = self.SCORE
return str(self.SCORE), str(self.HIGH_SCORE)
def EatGhosts(self):
pass
def DrawDots(self):
for POSITION in self.DOTS:
X = POSITION[0] + 13
Y = POSITION[1] + 13
WIDTH = POSITION[2]
HEIGHT = POSITION[3]
pygame.draw.circle(MazeSurface, YELLOW, (X, Y),
WIDTH // 2, HEIGHT // 2)
def DrawEnergizer(self):
for POSITION in self.ENERGIZER:
X = POSITION[0] + 13
Y = POSITION[1] + 13
WIDTH = POSITION[2]
HEIGHT = POSITION[3]
pygame.draw.circle(MazeSurface, YELLOW, (X, Y),
WIDTH // 2, HEIGHT // 2)
def DrawGhosts(self):
MazeSurface.blit(PinkGhostSurface, PinkGhostRect)
MazeSurface.blit(YellowGhostSurface, YellowGhostRect)
MazeSurface.blit(RedGhostSurface, RedGhostRect)
MazeSurface.blit(BlueGhostSurface, BlueGhostRect)
def GhostStartPosition(self):
X, Y, WIDTH, HEIGHT = self.GHOSTS[0]
PinkGhostRect.x = X
PinkGhostRect.y = Y
X, Y, WIDTH, HEIGHT = self.GHOSTS[1]
YellowGhostRect.x = X
YellowGhostRect.y = Y
X, Y, WIDTH, HEIGHT = self.GHOSTS[2]
RedGhostRect.x = X
RedGhostRect.y = Y
X, Y, WIDTH, HEIGHT = self.GHOSTS[3]
BlueGhostRect.x = X
BlueGhostRect.y = Y
def PlaySound(self, Track):
if Track == 0:
Eat = pygame.mixer.Sound("pacman_chomp.wav")
Eat.play()
pygame.mixer.fadeout(400)
if Track == 1:
EatPellet = pygame.mixer.Sound("pacman_eatghost.wav")
EatPellet.play()
pygame.mixer.music.play(7)
pygame.mixer.fadeout(400)
def ShowScore(self):
global Font
OneUpText = Font.render("1UP", True, WHITE)
OneUpTextRect = OneUpText.get_rect(center = (70, 10))
# Displays current score
OneUpScoreText = Font.render(str(self.SCORE), True, WHITE)
OneUpScoreRect = OneUpScoreText.get_rect(center =
((SCREEN_WIDTH - 290)
// 2, 26))
HighScoreText = Font.render("High Score", True, WHITE)
HighScoreTextRect = HighScoreText.get_rect(center =
(SCREEN_WIDTH // 2, 10))
# Displays High Score
HighScoreNumber = Font.render(str(self.HIGH_SCORE), True, WHITE)
HighScoreNumberRect = HighScoreNumber.get_rect(center =
((SCREEN_WIDTH + 90)
// 2, 26))
SCREEN.blit(OneUpText, OneUpTextRect)
SCREEN.blit(OneUpScoreText, OneUpScoreRect)
SCREEN.blit(HighScoreText, HighScoreTextRect)
SCREEN.blit(HighScoreNumber, HighScoreNumberRect)
def PacManBite(self):
global CurrentSurface
CurrentTime = time.time()
if CurrentTime - self.LastBiteTime >= self.TimeBetweenBites:
self.LastBiteTime = CurrentTime
if self.MouthOpen:
CurrentSurface = PacManStartSurface
else:
CurrentSurface = PacManSurface
self.MouthOpen = not self.MouthOpen
if self.PacManDirection == "LEFT":
CurrentSurface = pygame.transform.rotate(CurrentSurface, 180)
if self.PacManDirection == "RIGHT":
CurrentSurface = CurrentSurface
if self.PacManDirection == "UP":
CurrentSurface = pygame.transform.rotate(CurrentSurface, 90)
if self.PacManDirection == "DOWN":
CurrentSurface = pygame.transform.rotate(CurrentSurface, 270)
def PacManLives(self):
pass
def Update(self):
Player.PacManTeleport()
Player.ContinuePacManMovement()
Player.ContinueGhostMovement()
Player.GetAvailableMoves()
MazeSurface.blit(BackgroundSurface, BackgroundRect)
Player.DrawDots()
Player.DrawEnergizer()
Player.DrawGhosts()
Player.EatDots()
Player.EatEnergizer()
MazeSurface.blit(CurrentSurface, CurrentRect)
Player.PacManBite()
SCREEN.blit(MazeSurface, MazeRect)
Player.ShowScore()
Player = Main()
BackgroundSurface = pygame.transform.scale(BackgroundSurface,
(Player.MAZE_WIDTH,
Player.MAZE_HEIGHT))
BackgroundRect = BackgroundSurface.get_rect()
MazeSurface = pygame.Surface((Player.MAZE_WIDTH, Player.MAZE_HEIGHT))
MazeRect = MazeSurface.get_rect(topleft = (Player.MAZE_OFFSET_X,
Player.MAZE_OFFSET_Y))
Player.DrawMaze(MazeSurface)
Player.GhostStartPosition()
'''
Before the game starts ...
pregame = True
while pregame:
if key button pressed:
pregame = False
run = True
'''
run = True
while run:
SCREEN.fill(BLACK)
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
if event.type == pygame.KEYDOWN:
Player.PacManMovement()
Player.Update()
pygame.display.update()
CLOCK.tick(FPS)
pygame.quit()
You just need to divide the position in the grid by the size of a tile with the // (floor-division) operator:
pos_in_maze = (225, 175)
column = pos_in_maze[0] // Player.BLOCK_WIDTH
row = pos_in_maze[1] // Player.BLOCK_HEIGHT
Since the size of a tile is 25 the results are 9 for the column and 7 for the row.
screen_pos = (225, 175)
column = (screen_pos[0] - Player.MAZE_OFFSET_X) // Player.BLOCK_WIDTH
row = (screen_pos[1] - Player.MAZE_OFFSET_Y) // Player.BLOCK_HEIGHT
Since MAZE_OFFSET_X is 0 and MAZE_OFFSET_Y is 50 the results are 9 for the column and 5 for the row.
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)
I need help troubelshotting why my buttons arent being detected properly
My game is a simple slot game that's based around a numpy grid system and is played with left click to spin and r to reset the board. Im trying to implement a point system to make it more exciting but i cant get the code to detect when im clicking the buttons correctly. The part of the code that seems to be malfunctioning is the posCheckRight and posCheckLeft functions (close to the bottom part of the code, row 160 - 184). They work correctly sometimes but more than often not, to replicate my issues try clicking nearby the buttons and check the inputs import pygame as pg import sys import numpy as np import random as rand pg.init() width = 800 height = 800 lineWidth = 15 winLineWidth = 15 boardRows = 4 boardCols = 4 squareSize = 200 space = 55 windowName = "Slots" windowNameInt = 0 cost = 50 costtxt = "Cost: {}".format(cost) fontClr = (255,99,71) player = 1 game_over = False posCheckLvlR = 0 posCheckLvlL = 0 bgColor = (200, 200, 0) lineColor = (0, 0, 180) triangleColor = (255, 0, 0) winLineColor = (220, 220, 220) circleColor = (239, 231, 200) crossColor = (66, 66, 66) screen = pg.display.set_mode((width, height)) pg.display.set_caption(windowName) screen.fill(bgColor) board = np.zeros((boardRows, boardCols)) def drawLines() : #Line 1 vert pg.draw.line(screen, lineColor, (0, squareSize), (width, squareSize), lineWidth) #Line 2 vert pg.draw.line(screen, lineColor, (0, 2 * squareSize), (width, 2 * squareSize), lineWidth) #Line 3 vert pg.draw.line(screen, lineColor, (0, 3 * squareSize), (width, 3 * squareSize), lineWidth) #Line 1 hori pg.draw.line(screen, lineColor, (squareSize, 0), (squareSize, height), lineWidth) #Line 2 hori pg.draw.line(screen, lineColor, (2 * squareSize, 0), (2 * squareSize, height), lineWidth) #Line 3 hori pg.draw.line(screen, lineColor, (3 * squareSize, 0), (3 * squareSize, height - 60), lineWidth) def drawPointSyst() : #(rightest point)(top point)(bottom point) pg.draw.polygon(screen, (triangleColor), ((790, 760), (760, 730), (760, 790))) #(leftest point)(top point)(bottom point) pg.draw.polygon(screen, (triangleColor), ((720, 760), (750, 730), (750, 790))) #temp square pg.draw.rect(screen, (triangleColor), (720, 730, 30, 60)) pg.draw.rect(screen, (triangleColor), (760, 730, 30, 60)) myFont = pg.font.SysFont(None, 50) textSurface = myFont.render(costtxt, True, (fontClr)) #(x,y) screen.blit(textSurface, (560, 750)) snake1 = pg.image.load("snake.png") snake2 = pg.image.load("blackSnake.png") def drawShapes(): for row in range(boardRows): for col in range(boardCols): if board[row][col] == 1: screen.blit(snake2, (int( col * squareSize + squareSize//2 - 32), int( row * squareSize + squareSize//2 - 32))) elif board[row][col] == 2: screen.blit(snake1, (int( col * squareSize + squareSize//2 - 32), int( row * squareSize + squareSize//2 - 32))) def markSquare(row, col): shape = rand.randint(1,2) board[row][col] = shape def freeSquare(row, col): return board[row][col] == 0 def boardCheck(): for row in range(boardRows): for col in range(boardCols): if board[row][col] == 0: return False return True def checkWin(player): global windowNameInt #All vertical for col in range(boardCols): if board[0][col] == player and board[1][col] == player and board[2][col] == player and board[3][col] == player: vertWinLine(col) windowNameInt += 1 #All horizontal for row in range(boardRows): if board[row][0] == player and board[row][1] == player and board[row][2] == player and board[row][3] == player: horiWinLine(row) windowNameInt += 1 #From bottom right to top left if board[3][0] == player and board[2][1] == player and board[1][2] == player and board[0][3] == player: drawAscDiagonal() windowNameInt += 1 #From top left to bottom right if board[0][0] == player and board[1][1] == player and board[2][2] == player and board[3][3] == player: drawDescDiagonal() windowNameInt += 1 def vertWinLine(col): posX = col * squareSize + squareSize//2 color = winLineColor pg.draw.line(screen, color, (posX, 15), (posX, height - 15), lineWidth) # print("verti win") def horiWinLine(row): posY = row * squareSize + squareSize//2 color = winLineColor pg.draw.line(screen, color, (15, posY), (width - 15, posY), winLineWidth) # print("hori win") def drawAscDiagonal(): color = winLineColor pg.draw.line(screen, color, (15, height - 15), (width - 15, 15), winLineWidth) # print("asc win") def drawDescDiagonal(): color = winLineColor pg.draw.line(screen, color, (15, 15), (width - 15, height - 15), winLineWidth) # print("diag win") def restart(): screen.fill(bgColor) drawLines() drawPointSyst() windowName = (str(windowNameInt)) pg.display.set_caption(windowName) for row in range(boardRows): for col in range(boardCols): board[row][col] = 0 drawLines() drawPointSyst() def posCheckLeft(pos) : global posCheckLvlL for x in pos : if posCheckLvlL % 2 == 0 : if x > 720 and x < 750 : posCheckLvlL += 1 pass elif posCheckLvlL % 2 == 1 : if x > 730 and x < 790 : posCheckLvlL += 1 return True return False def posCheckRight(pos) : global posCheckLvlR for x in pos : if posCheckLvlR % 2 == 0 : if x > 760 and x < 790 : posCheckLvlR += 1 pass elif posCheckLvlR % 2 == 1 : if x > 730 and x < 790 : posCheckLvlR += 1 return True return False def game() : for event in pg.event.get(): if event.type == pg.QUIT: sys.exit() if event.type == pg.MOUSEBUTTONDOWN: pos = pg.mouse.get_pos() print(pos) if posCheckLeft(pos) : print("left") if posCheckRight(pos) : print("right") while not boardCheck() : randMouseX = rand.randint(0, width - 1) randMouseY = rand.randint(0, height - 1) clickedRow = int(randMouseY // squareSize) clickedCol = int(randMouseX // squareSize) # print("Click ", pos, "Grid coordinates: ", clickedRow, clickedCol) if freeSquare(clickedRow, clickedCol) : markSquare(clickedRow, clickedCol) drawShapes() checkWin(1) checkWin(2) if event.type == pg.KEYDOWN: if event.key == pg.K_r: restart() pg.display.update() while True: game()
If you need to check the (x,y) position of the clicks, then you just need to check x and y. I believe this does what you want: def posCheckLeft(pos) : x,y = pos return 720 < x < 750 and 730 < y < 790 def posCheckRight(pos) : x,y = pos return 760 < x < 790 and 730 < y < 790
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
Putting the scrolling camera in a mini-window in pygame
I'm trying to create a game where the action is shown in a little box within the main screen object, freeing up the surrounding space for text and menus and what-not. Since the map is larger than the allotted window, I coded a basic "camera" that follows the player around. It mostly works, but I'm having trouble "trimming off" the area outside of this window. Here's the relevant bits of code (EDITED to provide Working Example): import pygame, os, sys from pygame.locals import * pygame.init() RIGHT = 'RIGHT' LEFT = 'LEFT' UP = 'UP' DOWN = 'DOWN' class Camera(): def __init__(self, screen, x_ratio = 1, y_ratio = 1, x_offset = 0, y_offset = 0): self.screen = screen.copy() self.rec = self.screen.get_rect() self.rec.width *= x_ratio self.rec.height *= y_ratio self.x_offset = x_offset self.y_offset = y_offset def get_pos(self): return (self.x_offset - self.rec.x, self.y_offset - self.rec.y) def get_window(self): w = pygame.Rect(self.rec) w.topleft = (0 - self.rec.x, 0 - self.rec.y) return w def move(self, x, y): """Move camera into new position""" self.rec.x = x self.rec.y = y def track(self, obj): while obj.rec.left < self.rec.left: self.rec.x -= 1 while obj.rec.right > self.rec.right: self.rec.x += 1 while obj.rec.top < self.rec.top: self.rec.y -= 1 while obj.rec.bottom > self.rec.bottom: self.rec.y += 1 class Map: def __init__(self, width, height): self.width = width self.height = height self.rec = pygame.Rect(0,0,self.width,self.height) def draw(self, screen): pygame.draw.rect(screen, (200,200,200), self.rec) class Obj: def __init__(self, char, x = 0, y = 0, width = 0, height = 0): self.width = width self.height = height self.rec = pygame.Rect(x, y, width, height) self.cur_map = None self.timers = {} #Dummying in chars for sprites self.char = char self.x_dir = 1 self.y_dir = 1 self.speed = 1 self.moving = False def move(self): if self.x_dir != 0 or self.y_dir != 0: new_x = self.rec.x + (self.x_dir*self.speed) new_y = self.rec.y + (self.y_dir*self.speed) new_rec = pygame.Rect(new_x, new_y, self.width, self.height) #Keep movement within bounds of map while new_rec.left < self.cur_map.rec.left: new_rec.x += 1 while new_rec.right > self.cur_map.rec.right: new_rec.x -= 1 while new_rec.top < self.cur_map.rec.top: new_rec.y += 1 while new_rec.bottom > self.cur_map.rec.bottom: new_rec.y -= 1 self.rec = new_rec def set_dir(self, d): self.x_dir = 0 self.y_dir = 0 if d == LEFT: self.x_dir = -1 elif d == RIGHT: self.x_dir = 1 elif d == UP: self.y_dir = -1 elif d == DOWN: self.y_dir = 1 def set_moving(self, val = True): self.moving = val class Game: def __init__(self): self.screen_size = (800, 600) self.screen = pygame.display.set_mode(self.screen_size) self.map_screen = self.screen.copy() self.title = 'RPG' pygame.display.set_caption(self.title) self.camera = Camera(self.screen, 0.75, 0.75)#, 10, 75) self.fps = 80 self.clock = pygame.time.Clock() self.debug = False self.bg_color = (255,255,255) self.text_size = 18 self.text_font = 'Arial' self.text_style = pygame.font.SysFont(self.text_font, self.text_size) self.key_binds = {LEFT : [K_LEFT, K_a], RIGHT : [K_RIGHT, K_d], UP : [K_UP, K_w], DOWN : [K_DOWN, K_s], 'interact' : [K_RETURN, K_z], 'inventory' : [K_i, K_SPACE], 'quit' : [K_ESCAPE]} self.player = Obj('p', 0, 0, 10, self.text_size) def draw(self, obj): char = obj.char self.draw_text(char, obj.rec.x, obj.rec.y, screen = self.map_screen) def draw_text(self, text, x, y, color = (0,0,0), screen = None): textobj = self.text_style.render(text, 1, color) textrect = textobj.get_rect() textrect.x = x textrect.y = y if screen == None: """Use default screen""" self.screen.blit(textobj, textrect) else: screen.blit(textobj, textrect) def play(self): done = False cur_map = Map(800, 800) self.map_screen = pygame.Surface((cur_map.width, cur_map.height)) self.map_screen.fill(self.bg_color) bg = pygame.Surface((cur_map.width, cur_map.height)) cur_map.draw(bg) self.player.cur_map = cur_map while not done: for event in pygame.event.get(): if event.type == QUIT: pygame.quit() sys.exit() if event.type == KEYDOWN: if event.key in self.key_binds[LEFT]: self.player.set_dir(LEFT) self.player.set_moving() elif event.key in self.key_binds[RIGHT]: self.player.set_dir(RIGHT) self.player.set_moving() elif event.key in self.key_binds[UP]: self.player.set_dir(UP) self.player.set_moving() elif event.key in self.key_binds[DOWN]: self.player.set_dir(DOWN) self.player.set_moving() elif event.type == KEYUP: self.player.set_moving(False) if self.player.moving: self.player.move() self.camera.track(self.player) self.clock.tick() self.screen.fill(self.bg_color) self.map_screen.blit(bg, (0,0)) self.draw(self.player) pygame.draw.rect(self.map_screen, (0,0,0), self.camera.rec, 1) #self.screen.blit(self.map_screen, (0,0), [0 - self.camera.rec.x, 0 - self.camera.rec.y, self.camera.rec.width, self.camera.rec.height]) self.screen.blit(self.map_screen, self.camera.get_pos(), self.camera.get_window()) pygame.display.flip() game = Game() game.play() Moving the player past past the bounds of the camera's window causes the window to roll up completely and disappear. I tried adjusting the blitting coordinates, as advised earlier, but it seems to only change the direction in which the window rolls up.
From your updated code, the blitting coordinates for self.screen.blit(...) are still changing: self.camera.get_window() changes value because rec.x and rec.y are values referring to the player position within the map. Hence you should define a constant minimap coordinate, this should be the same as the camera offset. self.screen.blit(self.map_screen, (self.camera.x_offset,self.camera.y_offset), (*self.camera.get_pos(), self.camera.rec.width, self.camera.rec.height)) Change the Camera().get_pos() to: def get_pos(self): return (self.rec.x, self.rec.y) I believe I only changed the self.screen.blit(...) and stopped using or rewrote your Camera functions as you're confusing yourself with all the rec variables. To illustrate it working amend the Map().draw(screen) to: def draw(self, screen): pygame.draw.rect(screen, (200,200,200), self.rec) pygame.draw.circle(screen, (255, 255, 255), (50, 50), 20, 2) One tip as well don't draw the entire map at each loop, just the part that will be visible.