Related
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.
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
I have a maze organized in a grid. Each cell of the grid stores the information about the walls to its right and bottom neighboring cell. The player is an object of a certain size whose bounding box is known. I want to move the player smoothly through the maze with the walls preventing them from going through.
Minimal and reproducible example:
import pygame, random
class Maze:
def __init__(self, rows = 9, columns = 9):
self.size = (columns, rows)
self.walls = [[[True, True] for _ in range(self.size[1])] for __ in range(self.size[0])]
visited = [[False for _ in range(self.size[1])] for __ in range(self.size[0])]
i, j = (self.size[0]+1) // 2, (self.size[1]+1) // 2
visited[i][j] = True
stack = [(i, j)]
while stack:
current = stack.pop()
i, j = current
nl = [n for n in [(i-1, j), (i+1, j), (i, j-1), (i, j+1)]
if 0 <= n[0] < self.size[0] and 0 <= n[1] < self.size[1] and not visited[n[0]][n[1]]]
if nl:
stack.insert(0, current)
next = random.choice(nl)
self.walls[min(next[0], current[0])][min(next[1], current[1])][abs(next[1]-current[1])] = False
visited[next[0]][next[1]] = True
stack.insert(0, next)
def draw_maze(surf, maze, x, y, l, color, width):
lines = [((x, y), (x + l * len(maze.walls), y)), ((x, y), (x, y + l * len(maze.walls[0])))]
for i, row in enumerate(maze.walls):
for j, cell in enumerate(row):
if cell[0]: lines += [((x + i*l + l, y + j*l), (x + i*l + l, y + j*l + l))]
if cell[1]: lines += [((x + i*l, y + j*l + l), (x + i*l + l, y + j*l + l))]
for line in lines:
pygame.draw.line(surf, color, *line, width)
pygame.init()
window = pygame.display.set_mode((400, 400))
clock = pygame.time.Clock()
maze = Maze()
player_rect = pygame.Rect(190, 190, 20, 20)
run = True
while run:
clock.tick(100)
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
keys = pygame.key.get_pressed()
player_rect.x += (keys[pygame.K_RIGHT] - keys[pygame.K_LEFT]) * 3
player_rect.y += (keys[pygame.K_DOWN] - keys[pygame.K_UP]) * 3
window.fill(0)
draw_maze(window, maze, 20, 20, 40, (196, 196, 196), 3)
pygame.draw.circle(window, (255, 255, 0), player_rect.center, player_rect.width//2)
pygame.display.flip()
pygame.quit()
exit()
Use mask collision. Draw the maze of a transparent pygame.Surface:
cell_size = 40
maze = Maze()
maze_surf = pygame.Surface((maze.size[0]*cell_size, maze.size[1]*cell_size), pygame.SRCALPHA)
draw_maze(maze_surf, maze, 0, 0, cell_size, (196, 196, 196), 3)
Crate a pygame.Mask from the Surface with pygame.mask.from_surface:
maze_mask = pygame.mask.from_surface(maze_surf)
Create a mask form the player:
player_rect = pygame.Rect(190, 190, 20, 20)
player_surf = pygame.Surface(player_rect.size, pygame.SRCALPHA)
pygame.draw.circle(player_surf, (255, 255, 0), (player_rect.width//2, player_rect.height//2), player_rect.width//2)
player_mask = pygame.mask.from_surface(player_surf)
Calculate the new position of the player:
keys = pygame.key.get_pressed()
new_rect = player_rect.move(
(keys[pygame.K_RIGHT] - keys[pygame.K_LEFT]) * 3,
(keys[pygame.K_DOWN] - keys[pygame.K_UP]) * 3)
Use pygame.mask.Mask.overlap to see if the masks are intersects (see Pygame collision with masks is not working). Skip the movement when the mask of the maze intersects the player's mask:
offset = (new_rect.x - maze_pos[0]), (new_rect.y - maze_pos[1])
if not maze_mask.overlap(player_mask, offset):
player_rect = new_rect
See also Maze collision detection
Minimal example: repl.it/#Rabbid76/PyGame-Maze-MaskCollision
import pygame, random
class Maze:
def __init__(self, rows = 9, columns = 9):
self.size = (columns, rows)
self.walls = [[[True, True] for _ in range(self.size[1])] for __ in range(self.size[0])]
visited = [[False for _ in range(self.size[1])] for __ in range(self.size[0])]
i, j = (self.size[0]+1) // 2, (self.size[1]+1) // 2
visited[i][j] = True
stack = [(i, j)]
while stack:
current = stack.pop()
i, j = current
nl = [n for n in [(i-1, j), (i+1, j), (i, j-1), (i, j+1)]
if 0 <= n[0] < self.size[0] and 0 <= n[1] < self.size[1] and not visited[n[0]][n[1]]]
if nl:
stack.insert(0, current)
next = random.choice(nl)
self.walls[min(next[0], current[0])][min(next[1], current[1])][abs(next[1]-current[1])] = False
visited[next[0]][next[1]] = True
stack.insert(0, next)
def draw_maze(surf, maze, x, y, l, color, width):
lines = [((x, y), (x + l * len(maze.walls), y)), ((x, y), (x, y + l * len(maze.walls[0])))]
for i, row in enumerate(maze.walls):
for j, cell in enumerate(row):
if cell[0]: lines += [((x + i*l + l, y + j*l), (x + i*l + l, y + j*l + l))]
if cell[1]: lines += [((x + i*l, y + j*l + l), (x + i*l + l, y + j*l + l))]
for line in lines:
pygame.draw.line(surf, color, *line, width)
pygame.init()
window = pygame.display.set_mode((400, 400))
clock = pygame.time.Clock()
maze_pos = 20, 20
cell_size = 40
maze = Maze()
maze_surf = pygame.Surface((maze.size[0]*cell_size, maze.size[1]*cell_size), pygame.SRCALPHA)
draw_maze(maze_surf, maze, 0, 0, cell_size, (196, 196, 196), 3)
maze_mask = pygame.mask.from_surface(maze_surf)
player_rect = pygame.Rect(190, 190, 20, 20)
player_surf = pygame.Surface(player_rect.size, pygame.SRCALPHA)
pygame.draw.circle(player_surf, (255, 255, 0), (player_rect.width//2, player_rect.height//2), player_rect.width//2)
player_mask = pygame.mask.from_surface(player_surf)
run = True
while run:
clock.tick(100)
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
keys = pygame.key.get_pressed()
new_rect = player_rect.move(
(keys[pygame.K_RIGHT] - keys[pygame.K_LEFT]) * 3,
(keys[pygame.K_DOWN] - keys[pygame.K_UP]) * 3)
offset = (new_rect.x - maze_pos[0]), (new_rect.y - maze_pos[1])
if not maze_mask.overlap(player_mask, offset):
player_rect = new_rect
window.fill(0)
window.blit(maze_surf, maze_pos)
window.blit(player_surf, player_rect)
pygame.display.flip()
pygame.quit()
exit()
Implement simple logic that tests if there is a wall in the player's path when the player moves. Discard the movement when a collision with a wall is detected.
Add methods to the Maze class that check for a wall between a cell and its neighboring cell:
class Maze:
# [...]
def wall_left(self, i, j):
return i < 1 or self.walls[i-1][j][0]
def wall_right(self, i, j):
return i >= self.size[0] or self.walls[i][j][0]
def wall_top(self, i, j):
return j < 1 or self.walls[i][j-1][1]
def wall_bottom(self, i, j):
return j >= self.size[0] or self.walls[i][j][1]
Calculate the rows and columns of the corner points of the player's bounding box.
i0 = (player_rect.left - maze_pos[0]) // cell_size
i1 = (player_rect.right - maze_pos[0]) // cell_size
j0 = (player_rect.top - maze_pos[1]) // cell_size
j1 = (player_rect.bottom - maze_pos[1]) // cell_size
As the player moves, test to see if the player is entering a new cell. Use the new methods in the Maze class to test whether there is a wall in the player's path. Skip the movement if the path is blocked by a wall:
keys = pygame.key.get_pressed()
if keys[pygame.K_LEFT]:
new_rect = player_rect.move(-3, 0)
ni = (new_rect.left - maze_pos[0]) // cell_size
if i0 == ni or not (maze.wall_left(i0, j0) or maze.wall_left(i0, j1) or (j0 != j1 and maze.wall_bottom(ni, j0))):
player_rect = new_rect
if keys[pygame.K_RIGHT]:
new_rect = player_rect.move(3, 0)
ni = (new_rect.right - maze_pos[0]) // cell_size
if i1 == ni or not (maze.wall_right(i1, j0) or maze.wall_right(i1, j1) or (j0 != j1 and maze.wall_bottom(ni, j0))):
player_rect = new_rect
keys = pygame.key.get_pressed()
if keys[pygame.K_UP]:
new_rect = player_rect.move(0, -3)
nj = (new_rect.top - maze_pos[1]) // cell_size
if j0 == nj or not (maze.wall_top(i0, j0) or maze.wall_top(i1, j0) or (i0 != i1 and maze.wall_right(i0, nj))):
player_rect = new_rect
if keys[pygame.K_DOWN]:
new_rect = player_rect.move(0, 3)
nj = (new_rect.bottom - maze_pos[1]) // cell_size
if j1 == nj or not (maze.wall_bottom(i0, j1) or maze.wall_bottom(i1, j1) or (i0 != i1 and maze.wall_right(i0, nj))):
player_rect = new_rect
See also Maze collision detection
Minimal example: repl.it/#Rabbid76/PyGame-Maze-CollisionLogic
import pygame, random
class Maze:
def __init__(self, rows = 9, columns = 9):
self.size = (columns, rows)
self.walls = [[[True, True] for _ in range(self.size[1])] for __ in range(self.size[0])]
visited = [[False for _ in range(self.size[1])] for __ in range(self.size[0])]
i, j = (self.size[0]+1) // 2, (self.size[1]+1) // 2
visited[i][j] = True
stack = [(i, j)]
while stack:
current = stack.pop()
i, j = current
nl = [n for n in [(i-1, j), (i+1, j), (i, j-1), (i, j+1)]
if 0 <= n[0] < self.size[0] and 0 <= n[1] < self.size[1] and not visited[n[0]][n[1]]]
if nl:
stack.insert(0, current)
next = random.choice(nl)
self.walls[min(next[0], current[0])][min(next[1], current[1])][abs(next[1]-current[1])] = False
visited[next[0]][next[1]] = True
stack.insert(0, next)
def wall_left(self, i, j):
return i < 1 or self.walls[i-1][j][0]
def wall_right(self, i, j):
return i >= self.size[0] or self.walls[i][j][0]
def wall_top(self, i, j):
return j < 1 or self.walls[i][j-1][1]
def wall_bottom(self, i, j):
return j >= self.size[0] or self.walls[i][j][1]
def draw_maze(surf, maze, x, y, l, color, width):
lines = [((x, y), (x + l * len(maze.walls), y)), ((x, y), (x, y + l * len(maze.walls[0])))]
for i, row in enumerate(maze.walls):
for j, cell in enumerate(row):
if cell[0]: lines += [((x + i*l + l, y + j*l), (x + i*l + l, y + j*l + l))]
if cell[1]: lines += [((x + i*l, y + j*l + l), (x + i*l + l, y + j*l + l))]
for line in lines:
pygame.draw.line(surf, color, *line, width)
pygame.init()
window = pygame.display.set_mode((400, 400))
clock = pygame.time.Clock()
maze = Maze()
player_rect = pygame.Rect(190, 190, 20, 20)
run = True
while run:
clock.tick(100)
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
maze_pos = 20, 20
cell_size = 40
i0 = (player_rect.left - maze_pos[0]) // cell_size
i1 = (player_rect.right - maze_pos[0]) // cell_size
j0 = (player_rect.top - maze_pos[1]) // cell_size
j1 = (player_rect.bottom - maze_pos[1]) // cell_size
keys = pygame.key.get_pressed()
if keys[pygame.K_LEFT]:
new_rect = player_rect.move(-3, 0)
ni = (new_rect.left - maze_pos[0]) // cell_size
if i0 == ni or not (maze.wall_left(i0, j0) or maze.wall_left(i0, j1) or (j0 != j1 and maze.wall_bottom(ni, j0))):
player_rect = new_rect
if keys[pygame.K_RIGHT]:
new_rect = player_rect.move(3, 0)
ni = (new_rect.right - maze_pos[0]) // cell_size
if i1 == ni or not (maze.wall_right(i1, j0) or maze.wall_right(i1, j1) or (j0 != j1 and maze.wall_bottom(ni, j0))):
player_rect = new_rect
keys = pygame.key.get_pressed()
if keys[pygame.K_UP]:
new_rect = player_rect.move(0, -3)
nj = (new_rect.top - maze_pos[1]) // cell_size
if j0 == nj or not (maze.wall_top(i0, j0) or maze.wall_top(i1, j0) or (i0 != i1 and maze.wall_right(i0, nj))):
player_rect = new_rect
if keys[pygame.K_DOWN]:
new_rect = player_rect.move(0, 3)
nj = (new_rect.bottom - maze_pos[1]) // cell_size
if j1 == nj or not (maze.wall_bottom(i0, j1) or maze.wall_bottom(i1, j1) or (i0 != i1 and maze.wall_right(i0, nj))):
player_rect = new_rect
window.fill(0)
draw_maze(window, maze, 20, 20, cell_size, (196, 196, 196), 3)
pygame.draw.circle(window, (255, 255, 0), player_rect.center, player_rect.width//2)
pygame.display.flip()
pygame.quit()
exit()
Both #Rabbid76 solutions are good, but I would like to provide another approach.
In this approach, you would need two variables x and y to store the previous position, position before the collision. You would then need to store all the maze line's rect in a list.
Now, check if the player's rect has collided with any of the rect in the list either by iterating through the list and using Rect.colliderect or use pygame's Rect.collidelist(note: collidelist will return -1 if there is no collision). If they have collided reset the current position to the previous position.
code:
import pygame, random
class Maze:
def __init__(self, rows = 9, columns = 9):
self.size = (columns, rows)
self.walls = [[[True, True] for _ in range(self.size[1])] for __ in range(self.size[0])]
visited = [[False for _ in range(self.size[1])] for __ in range(self.size[0])]
i, j = (self.size[0]+1) // 2, (self.size[1]+1) // 2
visited[i][j] = True
stack = [(i, j)]
while stack:
current = stack.pop()
i, j = current
nl = [n for n in [(i-1, j), (i+1, j), (i, j-1), (i, j+1)]
if 0 <= n[0] < self.size[0] and 0 <= n[1] < self.size[1] and not visited[n[0]][n[1]]]
if nl:
stack.insert(0, current)
next = random.choice(nl)
self.walls[min(next[0], current[0])][min(next[1], current[1])][abs(next[1]-current[1])] = False
visited[next[0]][next[1]] = True
stack.insert(0, next)
def draw_maze(surf, maze, x, y, l, color, width):
lines = maze_lines(maze, x, y, l)
for line in lines:
pygame.draw.line(surf, color, *line, width)
def maze_lines(maze, x, y, l):
lines = [((x, y), (x + l * len(maze.walls), y)), ((x, y), (x, y + l * len(maze.walls[0])))]
for i, row in enumerate(maze.walls):
for j, cell in enumerate(row):
if cell[0]: lines += [((x + i * l + l, y + j * l), (x + i * l + l, y + j * l + l))]
if cell[1]: lines += [((x + i * l, y + j * l + l), (x + i * l + l, y + j * l + l))]
return lines
pygame.init()
window = pygame.display.set_mode((400, 400))
clock = pygame.time.Clock()
maze = Maze()
player_rect = pygame.Rect(190, 190, 20, 20)
line_rects = [pygame.draw.line(window, (0, 0, 0), *line) for line in maze_lines(maze, 20, 20, 40)] # first store all the line's rect in the list
prev_x, prev_y = 0, 0
run = True
while run:
clock.tick(100)
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
keys = pygame.key.get_pressed()
prev_x, prev_y = player_rect.x, player_rect.y
player_rect.x += (keys[pygame.K_RIGHT] - keys[pygame.K_LEFT]) * 3
player_rect.y += (keys[pygame.K_DOWN] - keys[pygame.K_UP]) * 3
# if any(x.colliderect(player_rect) for x in line_rects):
if player_rect.collidelist(line_rects) != -1:
player_rect.x = prev_x
player_rect.y = prev_y
window.fill(0)
draw_maze(window, maze, 20, 20, 40, (196, 196, 196), 3)
pygame.draw.circle(window, (255, 255, 0), player_rect.center, player_rect.width//2)
pygame.display.flip()
pygame.quit()
exit()
Output:
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)
I am trying to make realistic water in pygame:
This is till now my code:
from random import randint
import pygame
WIDTH = 700
HEIGHT = 500
win = pygame.display.set_mode((WIDTH, HEIGHT))
WHITE = (255, 255, 255)
BLACK = (0, 0, 0)
AQUA = 'aqua'
RADIUS = 1
x, y = 0, HEIGHT//2
K = 1
FORCE = 100
VELOCITY = 0.5
run = True
class Molecule:
def __init__(self, x, y, radius, force, k):
self.x = x
self.y = y
self.radius = radius
self.force = force
self.k = k
self.max_amplitude = y + force/k
self.min_amplitude = y - force/k
self.up = False
self.down = True
self.restore = False
def draw(self, win):
pygame.draw.circle(win, BLACK, (self.x, self.y), self.radius)
def oscillate(self):
if self.y <= self.max_amplitude and self.down == True:
self.y += VELOCITY
if self.y == self.max_amplitude or self.up:
self.up = True
self.down = False
self.y -= VELOCITY
if self.y == self.min_amplitude:
self.up = False
self.down = True
molecules = []
for i in range(100):
FORCE = randint(10, 20)
molecules.append(Molecule(x, y, RADIUS, FORCE, K))
x += 10
while run:
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
win.fill(WHITE)
for molecule in molecules:
molecule.draw(win)
molecule.oscillate()
for i in range(len(molecules)):
try:
pygame.draw.line(win, BLACK, (molecules[i].x, molecules[i].y), (molecules[i+1].x, molecules[i+1].y))
pygame.draw.line(win, AQUA, (molecules[i].x, molecules[i].y), (molecules[i+1].x, HEIGHT))
except:
pass
pygame.display.flip()
pygame.quit()
But as may expected the water curve is not smooth:
Look at it:
Sample Img1
I want to connect the two randomly added wave points using a set of circles not line like in this one so that a smooth curve could occur.
And in this way i could add the water color to it such that it will draw aqua lines or my desired color line from the point to the end of screen and all this will end up with smooth water flowing simulation.
Now the question is how could i make the points connect together smoothly into a smooth curve by drawing point circles at relative points?
I suggest sticking the segments with a Bézier curves. Bézier curves can be drawn with pygame.gfxdraw.bezier
Calculate the slopes of the tangents to the points along the wavy waterline:
ts = []
for i in range(len(molecules)):
pa = molecules[max(0, i-1)]
pb = molecules[min(len(molecules)-1, i+1)]
ts.append((pb.y-pa.y) / (pb.x-pa.x))
Use the the tangents to define 4 control points for each segment and draw the curve with pygame.gfxdraw.bezier:
for i in range(len(molecules)-1):
p0 = molecules[i].x, molecules[i].y
p3 = molecules[i+1].x, molecules[i+1].y
p1 = p0[0] + 10, p0[1] + 10 * ts[i]
p2 = p3[0] - 10, p3[1] - 10 * ts[i+1]
pygame.gfxdraw.bezier(win, [p0, p1, p2, p3], 4, BLACK)
Complete example:
from random import randint
import pygame
import pygame.gfxdraw
WIDTH = 700
HEIGHT = 500
win = pygame.display.set_mode((WIDTH, HEIGHT))
WHITE = (255, 255, 255)
BLACK = (0, 0, 0)
AQUA = 'aqua'
RADIUS = 1
x, y = 0, HEIGHT//2
K = 1
FORCE = 100
VELOCITY = 0.5
class Molecule:
def __init__(self, x, y, radius, force, k):
self.x = x
self.y = y
self.radius = radius
self.force = force
self.k = k
self.max_amplitude = y + force/k
self.min_amplitude = y - force/k
self.up = False
self.down = True
self.restore = False
def draw(self, win):
pygame.draw.circle(win, BLACK, (self.x, self.y), self.radius)
def oscillate(self):
if self.y <= self.max_amplitude and self.down == True:
self.y += VELOCITY
if self.y == self.max_amplitude or self.up:
self.up = True
self.down = False
self.y -= VELOCITY
if self.y == self.min_amplitude:
self.up = False
self.down = True
molecules = []
for i in range(50):
FORCE = randint(10, 20)
molecules.append(Molecule(x, y, RADIUS, FORCE, K))
x += 20
clock = pygame.time.Clock()
run = True
while run:
clock.tick(100)
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
win.fill(WHITE)
for molecule in molecules:
molecule.draw(win)
molecule.oscillate()
ts = []
for i in range(len(molecules)):
pa = molecules[max(0, i-1)]
pb = molecules[min(len(molecules)-1, i+1)]
ts.append((pb.y-pa.y) / (pb.x-pa.x))
for i in range(len(molecules)-1):
p0 = molecules[i].x, molecules[i].y
p3 = molecules[i+1].x, molecules[i+1].y
p1 = p0[0] + 10, p0[1] + 10 * ts[i]
p2 = p3[0] - 10, p3[1] - 10 * ts[i+1]
pygame.gfxdraw.bezier(win, [p0, p1, p2, p3], 4, BLACK)
for i in range(len(molecules)-1):
pygame.draw.line(win, AQUA, (molecules[i].x, molecules[i].y), (molecules[i].x, HEIGHT))
pygame.display.flip()
pygame.quit()
If you want to "fill" the water, you must calculate the points along the Bézier line and draw a filled polygon. How to calculate a Bézier curve is explained in Trying to make a Bezier Curve on PyGame library How Can I Make a Thicker Bezier in Pygame? and "X". You can use the following function:
def ptOnCurve(b, t):
q = b.copy()
for k in range(1, len(b)):
for i in range(len(b) - k):
q[i] = (1-t) * q[i][0] + t * q[i+1][0], (1-t) * q[i][1] + t * q[i+1][1]
return round(q[0][0]), round(q[0][1])
def bezier(b, samples):
return [ptOnCurve(b, i/samples) for i in range(samples+1)]
Use the bezier to stitch the wavy water polygon:
ts = []
for i in range(len(molecules)):
pa = molecules[max(0, i-1)]
pb = molecules[min(len(molecules)-1, i+1)]
ts.append((pb.y-pa.y) / (pb.x-pa.x))
pts = [(WIDTH, HEIGHT), (0, HEIGHT)]
for i in range(len(molecules)-1):
p0 = molecules[i].x, molecules[i].y
p3 = molecules[i+1].x, molecules[i+1].y
p1 = p0[0] + 10, p0[1] + 10 * ts[i]
p2 = p3[0] - 10, p3[1] - 10 * ts[i+1]
pts += bezier([p0, p1, p2, p3], 4)
Draw the polygon with pygame.draw.polygon():
pygame.draw.polygon(win, AQUA, pts)
Complete example:
from random import randint
import pygame
class Node:
def __init__(self, x, y, force, k, v):
self.x = x
self.y = y
self.y0 = y
self.force = force
self.k = k
self.v = v
self.direction = 1
def oscillate(self):
self.y += self.v * self.direction
if self.y0 - self.force / self.k > self.y or self.y0 + self.force / self.k < self.y:
self.direction *= -1
def draw(self, surf):
pygame.draw.circle(surf, "black", (self.x, self.y), 3)
window = pygame.display.set_mode((700, 500))
clock = pygame.time.Clock()
width, height = window.get_size()
no_of_nodes = 25
dx = width / no_of_nodes
nodes = [Node(i*dx, height//2, randint(15, 30), 1, 0.5) for i in range(no_of_nodes+1)]
def ptOnCurve(b, t):
q = b.copy()
for k in range(1, len(b)):
for i in range(len(b) - k):
q[i] = (1-t) * q[i][0] + t * q[i+1][0], (1-t) * q[i][1] + t * q[i+1][1]
return round(q[0][0]), round(q[0][1])
def bezier(b, samples):
return [ptOnCurve(b, i/samples) for i in range(samples+1)]
run = True
while run:
clock.tick(100)
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
for molecule in nodes:
molecule.oscillate()
ts = []
for i in range(len(nodes)):
pa = nodes[max(0, i-1)]
pb = nodes[min(len(nodes)-1, i+1)]
ts.append((pb.y-pa.y) / (pb.x-pa.x))
pts = [(width, height), (0, height)]
for i in range(len(nodes)-1):
p0 = nodes[i].x, nodes[i].y
p3 = nodes[i+1].x, nodes[i+1].y
p1 = p0[0] + 10, p0[1] + 10 * ts[i]
p2 = p3[0] - 10, p3[1] - 10 * ts[i+1]
pts += bezier([p0, p1, p2, p3], 4)
window.fill("white")
pygame.draw.polygon(window, 'aqua', pts)
for molecule in nodes:
molecule.draw(window)
pygame.display.flip()
pygame.quit()
exit()