I have created a simple piano tiles game clone in pygame.
Everything working fine except the way i am generating tiles after every certain interval, but as the game speed increases this leaves a gap between two tiles.
In the original version of the game, there's no lag (0 distance ) between two incoming tiles.
Here's a preview of the game:
Currently I am generating tiles like this:
ADDBLOCK = pygame.USEREVENT + 1
ADDTIME = 650
pygame.time.set_timer(ADDBLOCK, ADDTIME)
if event.type == ADDBLOCK:
x_col = random.randint(0,3)
block = Block(win, (67.5 * x_col, -120))
block_group.add(block)
But with time, these tiles speed increase so there's remain a gap between generation of two tiles as shown by red line in the preview. Is there any way to generate tiles consecutively?
Source Code
Use a variable number to know how many tiles have been generated since the start. This variable will start with 0, then you will add 1 to this variable every time a tile is generated.
Then, you can use a variable like scrolling which increases continuously. You will add this scrolling to every tile y pos to render them.
Now you just have to add a tile which y position is like -tile_height - tile_height * number.
If that doesn't make sense to you, look at this MRE:
import pygame
from pygame.locals import *
from random import randint
pygame.init()
screen = pygame.display.set_mode((240, 480))
clock = pygame.time.Clock()
number_of_tiles = 0
tile_height = 150
tile_surf = pygame.Surface((60, tile_height))
tiles = [] # [column, y pos]
scrolling = 0
score = 0
speed = lambda: 200 + 5*score # increase with the score
time_passed = 0
while True:
click = None # used to click on a tile
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
exit()
if event.type == MOUSEBUTTONDOWN:
click = event.pos
screen.fill((150, 200, 255))
if scrolling > number_of_tiles * tile_height:
# new tile
# use "while" instead of "if" if you want to go at really high speed
tiles.append([randint(0, 3), -tile_height - number_of_tiles * tile_height])
number_of_tiles += 1
for x, y in tiles:
screen.blit(tile_surf, (60 * x, y + scrolling))
if y + scrolling > 480: # delete any tile that is no longer visible
tiles.remove([x, y])
if click is not None and Rect((60 * x, y + scrolling), tile_surf.get_size())
.collidepoint(click):
tiles.remove([x, y]) # delete any tile that has been clicked
score += 1 # used to calculate speed
scrolling += speed() * time_passed
pygame.display.flip()
time_passed = clock.tick() / 1000
Related
I made some code for my game using PyGame to spawn an obstacle and im new to coding. It wouldn't spawn the obstacles and so i put a print statement to see when it spawns and it does print but doesn't show up on screen. This is not all the code but instead a minimalistic version of it that only shows the problematic code. no errors show up when running the code
import pygame as pg
import random
pg.init()
obstacle1 = pg.image.load('download1.jpeg')
obstacley = 600#tells object to spawn at top of screen
spawn = random.randint(1,10)
spawned = 0
if spawn == 1 and spawned == 0:
spawn = 0
Obstaclex = random.randint(600,800)#determines where on the top of the screen it spawns with rng
obstaclesize = random.randint(1,5)# determines obstacletype because there are 5 obstacle types that i havent included in this to be as simple as possbile
obstaclespeed = random.randint(3,8)#determines obstaclespeed using rng
spawned = 1
if obstaclesize == 1:
gameDisplay.blit(obstacle1,(obstacley,Obstaclex))
obstacley -= obstaclespeed #changes y position to lower it down the screen to hit player
print ("i have spawned")
You have to blit all the existing obstacles in the game loop in ever frame, not just when creating a new obstacle.
Create an obstacle list (obstacle_list) and append the coordinates of the new obstacle to the list. Draw all the obstacles in the main application loop:
obstacle_list = []
run = True
while run:
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
# [...]
if len(obstacle_list) < spawn:
x = random.randint(600,800)
y = 600
size = random.randint(1,5)
speed = random.randint(3,8)
obstacle_list.append((x, y, size, speed))
# [...]
# move obstacles
for i in range(len(obstacle_list)):
x, y, size, speed = obstacle_list[i]
new_y = y - speed
obstacle_list[i] = (x, new_y, size, speed)
# [...]
# draw obstacles
for x, y, size, speed in obstacle_list:
gameDisplay.blit(obstacle1, (x, y))
# [...]
I am trying to make a tile-based 2d platformer in Python with Pygame. I've started with just creating the window and tile system. It refers to a text file, and based on each number found in the file, blits an image to the Pygame display window("2" for grass image, "1" for dirt image). When the program is executed, the tiles appear on the screen but rapidly flash and move slowly to one side. There are also gaps in between the tiles too, which I am not sure why they are there, but I want to get rid of them.
import pygame, sys
pygame.init()
dirt_img = pygame.image.load("dirt2.png") #loads dirt image
dirt_img = pygame.transform.scale(dirt_img, (80,80)) #scales dirt image up to 80*80
grass_img = pygame.image.load("grass2.png") #loads grass image
grass_img = pygame.transform.scale(grass_img, (80,80)) #scales grass image up to 80*80
clock = pygame.time.Clock()
window = pygame.display.set_mode((1200, 800))
#load map
def load_map(path):
f = open(path + '.txt','r') #open text file
data = f.read() #reads it
f.close() #closes
data = data.split('\n') #splits the data by the new line character
game_map = [] #creates game map data
for row in data:
game_map.append(list(row)) #ads each line in'map.txt'..
#..data to new game map list
return game_map
game_map = load_map('map')
grass_count = 0 #meant to be used to count each time a grass tile is blitted to..
#..move the position over 80 pixles for the next tile to be blited
dirt_count = 0 # I think this might be where my problem is but I am not sure.
# Main loop
run = True
while run:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
sys.exit()
window.fill((135, 178,255)) #sets light Blue background color
for layer in game_map:
for tile in layer:
if tile == '1': #finds '1' in file,
dirt_count += 1 #updates dirt count,
window.blit(dirt_img, (100 * dirt_count + 80, 500))#blits next dirt tile
if tile == '2': #finds '2' in file,
grass_count += 1 #updates grass count,
window.blit(grass_img, (100 * grass_count + 80, 500))#blits next tile
clock.tick(60)
pygame.display.update()
pygame.quit()
The variable dirt_count and grass_count are incremented, but they are never changed back to 0. Set the variables to 0, right before the loop: grass_count = 0 grass_count = 0. Anyway, I don't think that this will satisfy you, since the coordinate of the tile doesn't seem to depend on it's index.
Most likely the position of the tile depends on the row an column:
for row, layer in enumerate(game_map):
for column, tile in enumerate(layer):
x, y = 80 + column * 100, 80 + row * 100
if tile == '1':
window.blit(dirt_img, (x, y))
if tile == '2':
window.blit(grass_img, (x, y))
I'm using Python 3.7.4. I'm using Pycharm 2020 Community as my IDE. I'm using Pygame 1.9.6 as my game interpreter.
I was wondering on how I could keep track of the players click on the chess board. I was thinking it should should in my main() running operation, but where in it?
So on a chessboard it's an 8x8 board, so 64 squares. Like say they click on the square once to select the square with a piece on it, then click on another square to move said piece to other square if the square is empty. An empty square on my chess board is: "01". Like do I need someway to get to the dimensions of the board say, like a row or a column?
I have the dimensions of the board.
WIDTH = HEIGHT = 512 # 400 is another option
DIMENSION = 8 # dimensions of a chess board are 8x8
SQ_SIZE = HEIGHT // DIMENSION
MAX_FPS = 15 # for animations later on
IMAGES = {}
def main():
p.init()
screen = p.display.set_mode((WIDTH, HEIGHT))
clock = p.time.Clock()
screen.fill(p.Color("white"))
gs = ChessEngine.GameState()
loadImages() # only do this once, before the while loop
running = True
while running:
for e in p.event.get():
if e.type == p.QUIT:
running = False
drawGameState(screen, gs)
clock.tick(MAX_FPS)
p.display.flip()
I've never done mouse clicks before so I was wondering on how I could do that?
The index of the clicked field can be computed by the // (floor division) operator. Get the MOUSEBUTTONDOWN event (see pygame.event) and divide the mouse position coordinates by SQ_SIZE:
def main():
# [...]
while running:
for e in p.event.get():
if e.type == p.QUIT:
running = False
if e.type == p.MOUSEBUTTONDOWN:
mousePos = e.pos
column, row = mousePos[0] // SQ_SIZE, mousePos[1] // SQ_SIZE
columnName, rowName = chr(ord('a') + column), str(row+1)
print("clicked at " + columnName + rowName)
You can get the mouse coordinates and divide it by SQ_SIZE, but use floor-division (mousex//SQ_Size), using the two division signs terminates the decimal point and you will be left with the index of the board. For example if you click at (230, 213), you could have...
if pygame.mouse.get_pressed()[0]: # Is the left mouse button down
mousex, mousey = pygame.mouse.get_pos() # (230, 213)
col = mousex // SQ_SIZE # 230 // 64 = 3
row = mousey // SQ_SIZE # 213 // 64 = 3
pieceSelected = chessBoard[row][col]
This would allow you to get the piece that the user clicked on.
I have an interesting problem. I need to make such that image must appear every random time in a random place and if it collides with my GAMER it must affect GAMER(some function) with GAMER for exactly 3 sec and disappear and appear after a random time again.
. I have an idea but it does not work.(note: this is a part of code i already initialized everythiing)
clock = pygame.time.Clock()
FPS = 30
playtime = 0
newtime=random.randint(3,10)
while mainloop:
milliseconds = clock.tick(FPS)
seconds = milliseconds / 1000.0
playtime += seconds
if playtime>=newtime:
image.draw()
newtime=random.randint(2,6) #because next appear time must change
if collision(GAMER,image):
GAMER.do_something() #how to do it exactly for 3 sec?
image.far_away() #just dissapear for some time
When you talk about an image, then you talk about a pygame.Surface. A pygame.Surface can be blit() to the display (respectively the Surface which is associated to the window). For instance
screen.blit(image, image_rect)
You cannot move a surface far away. You have to draw the entire scene in every frame and you have to draw (blit) the image on the display surface in every frame.
You can change the position of the image. Create a random position when the time span exceeds:
position = random.randint(0, window_height), random.randint(0, window_width)
image_rect = image.get_rect(center = position)
When the player collides with the image, then set compute the time point 3 seconds in the future. Effect the player as long the 3 seconds are not exceeded:
if image_rect.colliderect(GAMER.rect):
affecttime = playtime + 3
if playtime < affecttime:
GAMER.do_something()
General process:
clock = pygame.time.Clock()
FPS = 30
newtime=random.randint(3,10)
playtime = 0
affecttime = 0
position = random.randint(0, window_height), random.randint(0, window_width)
image_rect = image.get_rect(center = position)
while mainloop:
milliseconds = clock.tick(FPS)
seconds = milliseconds / 1000.0
playtime += seconds
# handle events (event loop)
for event in pygame.event.get():
if event.type == pygame.QUIT:
mainloop = False
if playtime >= newtime:
newtime = playtime + random.randint(2,6)
position = random.randint(0, window_height), random.randint(0, window_width)
image_rect = image.get_rect(center = position)
if image_rect.colliderect(GAMER.rect):
affecttime = playtime + 3
position = .... # set position far away
image_rect = image.get_rect(center = position)
if playtime < affecttime:
GAMER.do_something()
# clear dispaly
scree.fill(0)
#draw image at the current position
screen.blit(image, image_rect)
# update disaply
pygame.display.update()
I'm currently working on a school project where I'm making a "hexcells" similar game in pygame and now I'm trying to blit an a new image if the user has clicked a current image. It will blit an image in the top left area, if clicked in the top left area, but not if I click any of the existing images. I told the program to print the coordinates from the images with help of the .get_rect() function, but it remains the same whereever I click and the coordinates aren't even where a image is. Can someone help me understand how this works and help me blit the new images on top of the existing images? Code below is not the entire document, however there is so much garbage/trash/unused code so I'd thought I spare you the time of looking at irrelevant code. Also sorry if the formatting is wrong or the information isn't enough, I tried my best.
import pygame, sys
from pygame.locals import *
#Magic numbers
fps = 30
winW = 640
winH = 480
boxSize = 40
gapSize = 75
boardW = 3
boardH = 3
xMargin = int((winW - (boardW * (boxSize + gapSize))) / 2)
yMargin = int((winW - (boardW * (boxSize + gapSize))) / 2)
#Lil bit o' color R G B
NAVYBLUE = ( 60, 60, 100)
correctCords = [[175,275,375],[375,275,175]]
bgColor = NAVYBLUE
unC = pygame.image.load("unC.png")
cor = pygame.image.load("correct.png")
inc = pygame.image.load("wrong.png")
correct = "Correct"
inCorrect = "Incorrect"
def main():
global FPSCLOCK, DISPLAYSURF
pygame.init()
FPSCLOCK = pygame.time.Clock()
DISPLAYSURF = pygame.display.set_mode((winW, winH))
mousex = 0 #stores x-coordinate of mouse event
mousey = 0 #stores y-coordinate of mouse event
pygame.display.set_caption("Branches")
DISPLAYSURF.fill(bgColor)
gridGame(inCorrect, correct,gapSize,xMargin,yMargin,boxSize)
while True:
mouseClicked = False
for event in pygame.event.get():
if event.type == QUIT or (event.type == KEYUP and event.key == K_ESCAPE):
pygame.quit()
sys.exit()
elif event.type == MOUSEMOTION:
mousex,mousey = event.pos
elif event.type == MOUSEBUTTONUP:
mousex, mousey = event.pos
pos = pygame.mouse.get_pos()
mouseClicked = True
unCa = unC.get_rect()
corA = cor.get_rect()
print unCa
print corA
print pos
if unCa.collidepoint(pos):
DISPLAYSURF.blit(cor,(mousey,mousex))
"""lada = unC.get_rect()
lada =
if mousex and mousey == lada:
for x in correctCords:
for y in x:
for z in x:
if mousey and mousex == z and y:
DISPLAYSURF.blit(cor,(mousey,mousex))
print lada"""
pygame.display.update()
FPSCLOCK.tick(fps)
def gridGame(inCorrect, correct,gapSize,xMargin,yMargin,boxSize):
grid = []
cordX = []
cordY = []
correctRecs = []
#cordinates = []
#cordinates.append([])
#cordinates.append([])
#cordinates.append([])
#this is basically getBoard() all over again
#This part will arrange the actual backend grid
for row in range(3):
grid.append([])
#cordinates[0].append(gapSize+(row+1)*100)
#cordinates[1].append(gapSize+(row+1)*100)
#cordinates[2].append(gapSize+(row+1)*100)
for column in range(3):
grid[row].append(inCorrect)
for row in range(3):
cordX.append([])
for column in range(3):
cordX[row].append(gapSize+(row+1)*100)
for row in range(3):
cordY.append([])
for column in range(3):
cordY[row].append(gapSize+(column+1)*100)
#print cordX[0][0], cordY[0][0]
grid[0][2] = correct
grid[1][1] = correct
grid[2][0] = correct
#Y-AXEL SKRIVS FoRST ([Y][X])
#print cordinates[2][1]
DISPLAYSURF.blit(cor,(100,100))
#Let's draw it as well
for row in range(3):
for column in range(3):
DISPLAYSURF.blit(unC,(gapSize+(row+1)*100,gapSize+(column+1)*100))
main()
Also real sorry about the horrible variable naming and occasional swedish comments.
unCa = unC.get_rect() gives you only image size - so use it only once at start (before while True) - and later use the same unCa all the time to keep image position and change it.
btw: better use more readable names - like unC_rect
ie.
# move 10 pixel to the right
unC_rect.x += 10
# set new position
unC_rect.x = 10
unC_rect.right = 100
unC_rect.topleft = (10, 200)
unC_rect.center = (10, 200)
# center on screen
unC_rect.center = DISPLAYSURF.get_rect().center
etc.
And then use this rect to blit image
blit(unC, unC_rect)
and check collision with other rect
if unC_rect.colliderect(other_rect):
or with point - like mouse position
elif event.type == MOUSEMOTION:
if unC_rect.collidepoint(pygame.mouse.get_pos()):
hover = True
# shorter
elif event.type == MOUSEMOTION:
hover = unC_rect.collidepoint(pygame.mouse.get_pos()):