i'm making a game but i want to make the game harder by adding walls. I found out it's called a tilemap. But it's for multiple colours, i just want one color, grey. I want it to be something like 1,1,1,1,
1,0,0,1,
1,0,0,1,
1,1,1,1
0 = nothing. 1 = grey rectangle. I also need it to be like WIDTH = 16
HEIGHT = 9
TILESIZE = dw/WIDTH
but i can't find a way to implement it.
i tried using a def code but it lagged out my game. And i tried using this site: http://usingpython.com/pygame-tilemaps/
import pygame
import os
import sys
pygame.mixer.pre_init()
pygame.mixer.init(44100, 16, 2, 262144)
pygame.init()
from pygame.locals import*
import cv2
import time
import random
import pickle
import shutil
grey = (128,128,128)
def pause():
paused = True
while paused:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
sys.exit()
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_ESCAPE:
paused = False
elif event.key == pygame.K_SPACE:
menu(1)
screen.fill(white)
mts("Paused", black, -100, 100)
mts("Press esc to go back to the game or press space to go back to the menu", black, 25, 45)
pygame.display.update()
clock.tick(60)
def score(score):
text = pygame.font.Font('Fonts/Kuiper_Belt.otf', 25).render("Score: "+str(score), True, black)
screen.blit(text, [0,0])
def highscore(highscore):
text = pygame.font.Font('Fonts/Kuiper_Belt.otf', 25).render("Highscore: "+str(highscore), True, black)
screen.blit(text, [1100,0])
#define the apple to spawn in a random place
def randAppleGen():
randAppleX = random.randrange(0, dw-at, bs)
randAppleY = random.randrange(0, dh-at, bs)
return randAppleX,randAppleY
def snake(bs, sl):
for XnY in sl:
pygame.draw.rect(screen, Dgreen, [XnY[0],XnY[1],bs,bs])
def text_objects(text,color,fontS):
font = pygame.font.Font('Fonts/Kuiper_Belt.otf', fontS)
textSurface = font.render(text, True, color)
return textSurface, textSurface.get_rect()
def mts(msg,color, y_displace=0, fs=35):
textSurf, textRect = text_objects(msg,color,fs)
textRect.center = (dw / 2), (dh / 2)+y_displace
screen.blit(textSurf, textRect)
def gameLoop():
global at
global bs
hs = pickle.load( open( os.getenv('APPDATA')+str('/Snake Universe/h.SNUN'), "rb" ) )
gameExit = False
gameOver = False
gameHack = False
tilemap = [
[1,1,1,1],
[1,0,0,1],
[1,0,0,1],
[1,1,1,1]
]
WIDTH = 4
HEIGHT = 4
TILESIZE = dw/WIDTH
Speed = 20
lead_x = dw/2
lead_y = dh/2
lead_x_change = 0
lead_y_change = 0
pygame.mixer.music.load(os.path.join(os.getcwd(), 'Sounds', 'music1.ogg'))
pygame.mixer.music.play(-1)
slist = []
sl = 0
if sl > 2304:
gameHack = True
randAppleX,randAppleY = randAppleGen()
while not gameExit:
for row in range(HEIGHT):
for column in range(WIDTH):
if tilemap[row][column] == 1:
pygame.draw.rect(screen, grey, (column*TILESIZE, row*TILESIZE, TILESIZE, TILESIZE))
while gameOver == True:
screen.fill(white)
mts("Game over", red, -50,100)
mts("Press enter to play again or press space to go back to the menu", black, 50,50)
pygame.display.update()
for event in pygame.event.get():
if event.type == pygame.QUIT:
gameOver = False
gameExit = True
pygame.quit()
sys.exit()
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_KP_ENTER or event.key==pygame.K_RETURN:
gameLoop()
if event.key == pygame.K_SPACE:
gameExit = False
gameOver = False
menu(1)
while gameHack == True:
pygame.mixer.music.stop()
screen.fill(white)
mts("Hacked", red, -50,100)
mts("You hacked or exploit the game, press enter to quit the game", black, 50,50)
pygame.display.update()
for event in pygame.event.get():
if event.type == pygame.QUIT:
gameOver = False
gameExit = True
pygame.quit()
sys.exit()
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_KP_ENTER or event.key==pygame.K_RETURN:
pygame.quit()
sys.exit()
lead_x += lead_x_change
lead_y += lead_y_change
prev_x, prev_y = lead_x_change, lead_y_change
for event in pygame.event.get():
if event.type == pygame.QUIT:
gameExit = True
pygame.quit()
sys.exit()
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_LEFT and prev_x != bs:
lead_x_change, lead_y_change = -bs, 0
elif event.key == pygame.K_RIGHT and prev_x != -bs:
lead_x_change, lead_y_change = bs, 0
elif event.key == pygame.K_UP and prev_y != bs:
lead_x_change, lead_y_change = 0, -bs
elif event.key == pygame.K_DOWN and prev_y != -bs:
lead_x_change, lead_y_change = 0, bs
elif event.key == pygame.K_ESCAPE:
pause()
elif event.key == pygame.K_s and Speed >= 10 and Speed < 60:
Speed += 10
clock.tick(Speed)
elif event.key == pygame.K_d and Speed <= 60 and Speed > 10:
Speed -= 10
clock.tick(Speed)
elif event.key == pygame.K_a:
sl += 1
if not pygame.Rect(0, 0, dw, dh).contains(lead_x, lead_y, bs, bs):
gameOver = True
screen.fill(white)
#draw the apple
apple = pygame.draw.rect(screen, red, [randAppleX,randAppleY,at,at])
sh = []
sh.append(lead_x)
sh.append(lead_y)
slist.append(sh)
snake(bs, slist)
if len(slist) > sl:
del slist[0]
for eachSegment in slist[:-1]:
if eachSegment == sh:
gameOver = True
score(sl)
highscore(hs)
if sl > hs:
hs += 1
os.remove( os.getenv('APPDATA')+str('/Snake Universe/h.SNUN') )
pickle.dump( sl, open( os.getenv('APPDATA')+str('/Snake Universe/h.SNUN'), "wb" ) )
hs = pickle.load( open( os.getenv('APPDATA')+str('/Snake Universe/h.SNUN'), "rb" ) )
pygame.display.update()
#make the apple spawn
appleRect = pygame.Rect(randAppleX, randAppleY, at, at)
if appleRect.collidepoint(lead_x, lead_y):
while True:
randAppleX, randAppleY = randAppleGen()
appleRect = pygame.Rect(randAppleX, randAppleY, at, at)
if not appleRect.collidepoint(lead_x, lead_y) and \
not any(appleRect.collidepoint(*p) for p in slist):
break
sl += 1
clock.tick(Speed)
pygame.quit()
sys.quit()
I expect it to display a single color tile map, but i keep on getting crashes.
I don't understand why you have problem if you already have it in code and you have example in your link.
tilemap = [
[1,1,1,1],
[1,0,0,1],
[1,0,0,1],
[1,1,1,1]
]
MAPHEIGHT = 4
MAPWIDTH = 4
TILESIZE = dw/MAPWIDTH
GREY = (128,128,128)
for row in range(MAPHEIGHT):
for column in range(MAPWIDTH):
if tilemap[row][column] == 1:
pygame.draw.rect(screen, GREY, column*TILESIZE, row*TILESIZE, TILESIZE, TILESIZE))
EDIT:
You have problem because you use it in wrong place. You have to draw between screen.fill (which clears buffer) and pygame.update (which sends buffer to video card and it displays it on screen)
screen.fill(white)
for row in range(HEIGHT):
for column in range(WIDTH):
if tilemap[row][column] == 1:
pygame.draw.rect(screen, grey, (column*TILESIZE, row*TILESIZE, TILESIZE, TILESIZE))
# ... draw other things ...
pygame.display.update()
You have mess in code. You should have
place where you update values, move object, crate/respaw object, load/save pickle, etc. but don't draw there.
place where you use screen.fill, draw all elements, use pygame.display.update but don't update object and don't load/save pickle
EDIT:
My version (with better names of variables and functions)
import pygame
import os
import sys
import random
import pickle
# --- constants --- (UPPERCASE names)
WHITE = ( 0, 0, 0)
RED = (255, 0, 0)
BLACK = (255, 255, 255)
GREEN = (255, 0, 0)
GREY = (128, 128, 128)
DISPLAY_WIDTH = 1200
DISPLAY_HEIGHT = 800
APPDATA = os.getenv('APPDATA', '')
PICKLE_PATH = os.path.join(APPDATA, 'Snake Universe', 'h.SNUN')
WIDTH = 4
HEIGHT = 4
TILE_SIZE = DISPLAY_WIDTH/WIDTH
BLOCK_SIZE = 20
# --- functions ---
def pause():
paused = True
while paused:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
sys.exit()
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_ESCAPE:
paused = False
elif event.key == pygame.K_SPACE:
menu(1)
screen.fill(WHITE)
mts("Paused", BLACK, -100, 100)
mts("Press esc to go back to the game or press space to go back to the menu", BLACK, 25, 45)
pygame.display.update()
clock.tick(60)
def text_object(text, color=BLACK, font_size=25):
font = pygame.font.SysFont(None, font_size)
surface = font.render(text, True, color)
rect = surface.get_rect()
return surface, rect
def draw_score(screen, score):
surface, rect = text_object("Score: " + str(score))
screen.blit(surface, (0, 0))
def draw_highscore(screen, highscore):
surface, rect = text_object("Highscore: " + str(highscore))
screen.blit(surface, (1100, 0))
def rand_apple_pos():
x = random.randrange(0, DISPLAY_WIDTH - BLOCK_SIZE, BLOCK_SIZE)
y = random.randrange(0, DISPLAY_HEIGHT - BLOCK_SIZE, BLOCK_SIZE)
return x, y
def draw_snake(screen, snake):
for x, y in snake:
pygame.draw.rect(screen, GREEN, (x, y, BLOCK_SIZE, BLOCK_SIZE))
def mts(msg, color, y_displace=0, fs=35):
surface, rect = text_object(msg, color, fs)
rect.center = (DISPLAY_WIDTH / 2), (DISPLAY_HEIGHT / 2) + y_displace
screen.blit(surface, rect)
def game_loop(screen):
highscore = 0
#highscore = pickle.load(open(PICKLE_PATH, "rb" ))
game_exit = False
game_over = False
game_hack = False
speed = 10
lead_x = DISPLAY_WIDTH/2
lead_y = DISPLAY_HEIGHT/2
lead_x_change = 0
lead_y_change = 0
#pygame.mixer.music.load(os.pBLOCK_SIZEh.join(os.getcwd(), 'Sounds', 'music1.ogg'))
#pygame.mixer.music.play(-1)
snake = [(100, 100)]
score = 0
apple_x, apple_y = rand_apple_pos()
apple_rect = pygame.Rect(apple_x, apple_y, BLOCK_SIZE, BLOCK_SIZE)
clock = pygame.time.Clock()
while not game_exit:
while game_over == True:
screen.fill(WHITE)
mts("Game over", RED, -50,100)
mts("Press enter to play again or press space to go back to the menu", BLACK, 50,50)
pygame.display.update()
for event in pygame.event.get():
if event.type == pygame.QUIT:
game_over = False
game_exit = True
pygame.quit()
sys.exit()
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_KP_ENTER or event.key==pygame.K_RETURN:
#gameLoop()
game_over = False
if event.key == pygame.K_SPACE:
game_exit = False
game_over = False
menu(1)
while game_hack == True:
pygame.mixer.music.stop()
screen.fill(WHITE)
mts("Hacked", RED, -50, 100)
mts("You hacked or exploit the game, press enter to quit the game", BLACK, 50,50)
pygame.display.update()
for event in pygame.event.get():
if event.type == pygame.QUIT:
game_over = False
game_exit = True
pygame.quit()
sys.exit()
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_KP_ENTER or event.key==pygame.K_RETURN:
pygame.quit()
sys.exit()
lead_x += lead_x_change
lead_y += lead_y_change
prev_x, prev_y = lead_x_change, lead_y_change
# --- events ---
for event in pygame.event.get():
if event.type == pygame.QUIT:
game_exit = True
pygame.quit()
sys.exit()
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_LEFT and prev_x != BLOCK_SIZE:
lead_x_change, lead_y_change = -BLOCK_SIZE, 0
elif event.key == pygame.K_RIGHT and prev_x != -BLOCK_SIZE:
lead_x_change, lead_y_change = BLOCK_SIZE, 0
elif event.key == pygame.K_UP and prev_y != BLOCK_SIZE:
lead_x_change, lead_y_change = 0, -BLOCK_SIZE
elif event.key == pygame.K_DOWN and prev_y != -BLOCK_SIZE:
lead_x_change, lead_y_change = 0, BLOCK_SIZE
elif event.key == pygame.K_ESCAPE:
pause()
elif event.key == pygame.K_s and speed >= 10 and speed < 60:
speed += 10
clock.tick(speed)
elif event.key == pygame.K_d and speed <= 60 and speed > 10:
speed -= 10
clock.tick(speed)
elif event.key == pygame.K_a:
score += 1
# --- moves ---
if not pygame.Rect(0, 0, DISPLAY_WIDTH, DISPLAY_HEIGHT).contains(lead_x, lead_y, BLOCK_SIZE, BLOCK_SIZE):
game_over = True
if apple_rect.collidepoint(lead_x, lead_y):
while True:
apple_x, apple_y = rand_apple_pos()
# update existing Rect without creating new Rect
apple_rect.x = apple_x
apple_rect.y = apple_x
if not apple_rect.collidepoint(lead_x, lead_y) and \
not any(apple_rect.collidepoint(*pos) for pos in snake):
break
score += 1
# update snake
snake.append( (lead_x, lead_y) )
if len(snake) > score:
del snake[0]
for segment in snake[:-1]:
if segment == snake[-1]:
game_over = True
if score > highscore:
#pickle.dump(score, open(PICKLE_PATH, "wb"))
highscore = score
if score > 2304:
game_hack = True
# --- draw ---
screen.fill(WHITE)
#draw_wall(screen)
for row in range(HEIGHT):
for column in range(WIDTH):
if tilemap[row][column] == 1:
pygame.draw.rect(screen, GREY, (column*TILE_SIZE, row*TILE_SIZE, TILE_SIZE, TILE_SIZE))
draw_snake(screen, snake)
#draw the apple
#draw_apple(screen, apple)
pygame.draw.rect(screen, RED, apple_rect)
draw_score(screen, score)
draw_highscore(screen, highscore)
pygame.display.update()
clock.tick(speed)
# --- end ---
pygame.quit()
sys.quit()
# --- variables ---
tilemap = [
[1,1,1,1,1,1,1,1,1,1,1,1],
[1,0,0,1,1,0,0,1,1,0,0,1],
[1,0,0,1,1,0,0,1,1,0,0,1],
[1,0,0,1,1,0,0,1,1,0,0,1],
[1,0,0,1,1,0,0,1,1,0,0,1],
[1,0,0,1,1,0,0,1,1,0,0,1],
[1,0,0,1,1,0,0,1,1,0,0,1],
[1,1,1,1,1,1,1,1,1,1,1,1],
]
HEIGHT = len(tilemap)
WIDTH = len(tilemap[0])
# --- main ---
pygame.mixer.pre_init()
pygame.mixer.init(44100, 16, 2, 262144)
pygame.init()
screen = pygame.display.set_mode((DISPLAY_WIDTH, DISPLAY_WIDTH))
game_loop(screen)
This is what happens when i don't have a background:
https://www.youtube.com/watch?v=S-bv-j8le24
this is the code:
import pygame
pygame.init()
#####Variables#####
white = (255,255,255)
black = (0,0,0)
red = (255,0,0)
green = (0,255,0)
blue = (0,0,255)
gameWindowWidth = 1280
gameWindowHeight = 720
gameRunning = True
clock = pygame.time.Clock()
###################
#####Loading#####
ninja01 = pygame.image.load("C:\\Users\Tom\Desktop\gameImages\charSprite\s_Idle__000.png")
background = pygame.image.load("C:\\Users\Tom\Desktop\gameImages\Background\DistantCity\PNG\m_image.png")
#################
#####Classes#####
class player():
def __init__(self):
self.playerX = gameWindowWidth * 0.2
self.playerY = gameWindowHeight * 0.8
self.changeOnX = 0
def changingX(self):
if event.type == pygame.KEYDOWN and event.key == pygame.K_RIGHT:
self.changeOnX = 5
if event.type == pygame.KEYDOWN and event.key == pygame.K_LEFT:
self.changeOnX = -5
if event.type == pygame.KEYUP and event.key == pygame.K_RIGHT:
self.changeOnX = 0
if event.type == pygame.KEYUP and event.key == pygame.K_LEFT:
self.changeOnX = 0
def move(self):
self.playerX = self.playerX + self.changeOnX
gameWindow.blit(ninja01, (self.playerX, self.playerY))
################
ninja = player()
gameWindow = pygame.display.set_mode((gameWindowWidth, gameWindowHeight))
pygame.display.set_caption("Platformer Game")
while gameRunning == True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
gameRunning = False
#gameWindow.blit(background, (0, 0))
ninja.changingX()
ninja.move()
pygame.display.update()
clock.tick(144)
this is what happens when i do have a background:
https://www.youtube.com/watch?v=l89zZQ_8kzg
this is the code:
import pygame
pygame.init()
#####Variables#####
white = (255,255,255)
black = (0,0,0)
red = (255,0,0)
green = (0,255,0)
blue = (0,0,255)
gameWindowWidth = 1280
gameWindowHeight = 720
gameRunning = True
clock = pygame.time.Clock()
###################
#####Loading#####
ninja01 = pygame.image.load("C:\\Users\Tom\Desktop\gameImages\charSprite\s_Idle__000.png")
background = pygame.image.load("C:\\Users\Tom\Desktop\gameImages\Background\DistantCity\PNG\m_image.png")
#################
#####Classes#####
class player():
def __init__(self):
self.playerX = gameWindowWidth * 0.2
self.playerY = gameWindowHeight * 0.8
self.changeOnX = 0
def changingX(self):
if event.type == pygame.KEYDOWN and event.key == pygame.K_RIGHT:
self.changeOnX = 5
if event.type == pygame.KEYDOWN and event.key == pygame.K_LEFT:
self.changeOnX = -5
if event.type == pygame.KEYUP and event.key == pygame.K_RIGHT:
self.changeOnX = 0
if event.type == pygame.KEYUP and event.key == pygame.K_LEFT:
self.changeOnX = 0
def move(self):
self.playerX = self.playerX + self.changeOnX
gameWindow.blit(ninja01, (self.playerX, self.playerY))
################
ninja = player()
gameWindow = pygame.display.set_mode((gameWindowWidth, gameWindowHeight))
pygame.display.set_caption("Platformer Game")
while gameRunning == True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
gameRunning = False
gameWindow.blit(background, (0, 0))
ninja.changingX()
ninja.move()
pygame.display.update()
clock.tick(144)
The code is exactly the same appart from the fact that "gameWindow.blit(background, (0, 0))" is commented out in the first one.
My question is why is my character going so much slower when i add the background?
Also in the second one his movement speed doesn't change until i lower the clock.tick to around 30 & below.
The timing of all of your entire game loop is being controlled by the Clock.tick method. So you are only running your input and position update code once each frame. The more sprites you have, the more it will slow down this cycle which is what you are observing when you include the background. You can separate the timing of your input and update logic from the rendering cycle and this would solve your problem. Consider the refactor I have performed below:
import pygame
pygame.init()
#####Variables#####
white = (255,255,255)
black = (0,0,0)
red = (255,0,0)
green = (0,255,0)
blue = (0,0,255)
gameWindowWidth = 1280
gameWindowHeight = 720
gameRunning = True
clock = pygame.time.Clock()
###################
#####Loading#####
ninja01 = pygame.image.load("/path/to/your/ninja/sprite")
background = pygame.image.load("/path/to/your/background/sprite")
#################
#####Classes#####
class player():
def __init__(self):
self.playerX = gameWindowWidth * 0.2
self.playerY = gameWindowHeight * 0.8
self.velocity = 0.0
def setVelocity(self, velocity):
self.velocity = velocity
def update(self, dt):
self.playerX += self.velocity * dt
def draw(self):
gameWindow.blit(ninja01, (self.playerX, self.playerY))
################
ninja = player()
gameWindow = pygame.display.set_mode((gameWindowWidth, gameWindowHeight))
pygame.display.set_caption("Platformer Game")
fps = 60
target_frame_time = 1.0 / fps
current_frame_time = 0.0
while gameRunning == True:
dt = clock.tick()
for event in pygame.event.get():
if event.type == pygame.QUIT:
gameRunning = False
if event.type == pygame.KEYDOWN and event.key == pygame.K_RIGHT:
ninja.setVelocity(1)
if event.type == pygame.KEYDOWN and event.key == pygame.K_LEFT:
ninja.setVelocity(-1)
if event.type == pygame.KEYUP and event.key == pygame.K_RIGHT:
ninja.setVelocity(0)
if event.type == pygame.KEYUP and event.key == pygame.K_LEFT:
ninja.setVelocity(0)
ninja.update(dt)
current_frame_time += dt
if current_frame_time >= target_frame_time:
gameWindow.blit(background, (0, 0))
ninja.draw()
pygame.display.flip()
current_frame_time -= target_frame_time
When update is called on the ninja, the position is calculated using the equation:
distance = velocity * time
With these code changes, you can now achieve a consistent frame rate while your input and game update logic run continuously.
clock.tick(144) means maybe pause if the rendering speed is happening faster than 144 fps. And since that's a high enough framerate, and rendering is still taking long enough, perhaps clock.tick is returning immediately and no delay is necessary.
So when you draw in a background, the rendering certainly wont be done any faster so it would still be slow enough that clock.tick returns immediately. Except now the rendering is a little slower, so you notice the delay from the render.