I'm currently finishing a Flappy Bird game in Python 3.8 that will be played by an AI that will learn by itself how to play the game and improve itself from its previous mistakes until a point where it will be "unbeatable". I'm really close to finish this but there's this error in my code:
NameError: name 'base' is not defined
This error wasn't appearing during the previous tests that I made. I looked into all the code that mentioned the base in the game but still, I couldn't find anything wrong. The game code is this:
import pygame
import neat
import time
import os
import random
pygame.font.init()
WIN_WIDTH = 500
WIN_HEIGHT = 800
BIRD_IMGS = [pygame.transform.scale2x(pygame.image.load(os.path.join('imgs', 'bird1.png'))), pygame.transform.scale2x(pygame.image.load(os.path.join('imgs', 'bird2.png'))), pygame.transform.scale2x(pygame.image.load(os.path.join('imgs', 'bird3.png')))]
PIPE_IMG = pygame.transform.scale2x(pygame.image.load(os.path.join('imgs', 'pipe.png')))
BASE_IMG = pygame.transform.scale2x(pygame.image.load(os.path.join('imgs', 'base.png')))
BG_IMG = pygame.transform.scale2x(pygame.image.load(os.path.join('imgs', 'bg.png')))
STAT_FONT = pygame.font.SysFont('comicsans', 50)
class Bird:
IMGS = BIRD_IMGS
MAX_ROTATION = 25
ROT_VEL = 20
ANIMATION_TIME = 5
def __init__(self, x, y):
self.x = x
self.y = y
self.tilt = 0
self.tick_count = 0
self.vel = 0
self.height = self.y
self.img_count = 0
self.img = self.IMGS[0]
def jump(self):
self.vel = -10.5
self.tick_count = 0
self.height = self.y
def move(self):
self.tick_count += 1
d = self.vel * self.tick_count + 1.5 * self.tick_count ** 2
if d >= 16:
d = 16
if d < 0:
d -= 2
self.y = self.y + d
if d < 0 or self.y < self.height + 50:
if self.tilt < self.MAX_ROTATION:
self.tilt = self.MAX_ROTATION
else:
if self.tilt > -90:
self.tilt -= self.ROT_VEL
def draw(self, win):
self.img_count += 1
if self.img_count < self.ANIMATION_TIME:
self.img = self.IMGS[0]
elif self.img_count < self.ANIMATION_TIME*2:
self.img = self.IMGS[1]
elif self.img_count < self.ANIMATION_TIME*3:
self.img = self.IMGS[2]
elif self.img_count < self.ANIMATION_TIME*4:
self.img = self.IMGS[1]
elif self.img_count == self.ANIMATION_TIME*4 + 1:
self.img = self.IMGS[0]
self.img_count = 0
if self.tilt <= -80:
self.img = self.IMGS[1]
self.img_count = self.ANIMATION_TIME*2
rotated_image = pygame.transform.rotate(self.img, self.tilt)
new_rect = rotated_image.get_rect(center=self.img.get_rect(topleft = (self.x, self.y)).center)
win.blit(rotated_image, new_rect.topleft)
def get_mask(self):
return pygame.mask.from_surface(self.img)
class Pipe:
GAP = 200
VEL = 5
def __init__(self, x):
self.x = x
self.height = 0
self.top = 0
self.bottom = 0
self.PIPE_TOP = pygame.transform.flip(PIPE_IMG, False, True)
self.PIPE_BOTTOM = PIPE_IMG
self.passed = False
self.set_height()
def set_height(self):
self.height = random.randrange(50, 450)
self.top = self.height - self.PIPE_TOP.get_height()
self.bottom = self.height + self.GAP
def move(self):
self.x -= self.VEL
def draw(self, win):
win.blit(self.PIPE_TOP, (self.x, self.top))
win.blit(self.PIPE_BOTTOM, (self.x, self.bottom))
def collide(self, bird):
bird_mask = bird.get_mask()
top_mask = pygame.mask.from_surface(self.PIPE_TOP)
bottom_mask = pygame.mask.from_surface(self.PIPE_BOTTOM)
top_offset = (self.x - bird.x, self.top - round(bird.y))
bottom_offset = (self.x - bird.x, self.bottom - round(bird.y))
b_point = bird_mask.overlap(bottom_mask, bottom_offset)
t_point = bird_mask.overlap(top_mask, top_offset)
if t_point or b_point:
return True
return False
class Base:
VEL = 5
WIDTH = BASE_IMG.get_width()
IMG = BASE_IMG
def __init__(self, y):
self.y = y
self.x1 = 0
self.x2 = self.WIDTH
def move(self):
self.x1 -= self.VEL
self.x2 -= self.VEL
if self.x1 + self.WIDTH < 0:
self.x1 = self.x2 + self.WIDTH
if self.x2 + self.WIDTH < 0:
self.x2 = self.x1 + self.WIDTH
def draw(self, win):
win.blit(self.IMG, (self.x1, self.y))
win.blit(self.IMG, (self.x2, self.y))
def draw_window(win, bird, pipes, base, score):
win.blit(BG_IMG, (0, 0))
for pipe in pipes:
pipe.draw(win)
text = STAT_FONT.render('Score: ' + str(score), 1, (255, 255, 255))
win.blit(text, (WIN_WIDTH - 10 - text.get_width(), 10))
base.draw(win)
for bird in birds:
bird.draw(win)
pygame.display.update()
def main(genomes, config):
nets = []
ge = []
birds = []
for _, g in genomes:
net = neat.nn.FeedForwardNetwork.create(g, config)
nets.append(net)
birds.append(Bird(230, 350))
g.fitness = 0
ge.append(g)
pipes = [Pipe(600)]
win = pygame.display.set_mode((WIN_WIDTH, WIN_HEIGHT))
clock = pygame.time.Clock()
score = 0
run = True
while run:
clock.tick(30)
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
pygame.quit()
quit()
pipe_ind = 0
if len(birds) > 0:
if len(pipes) > 1 and birds[0].x > pipes[0].x + pipes[0].PIPE_TOP.get_width():
pipe_ind = 1
else:
run = False
break
for x, bird in enumerate(birds):
bird.move()
ge[x].fitness += 0.1
output = nets[x].activate((bird.y, abs(bird.y - pipes[pipe_ind].height), abs(bird.y - pipes[pipe_ind].bottom)))
if output[0] > 0.5:
bird.jump()
#bird.move()
add_pipe = False
rem = []
for pipe in pipes:
for x, bird in enumerate(birds):
if pipe.collide(bird):
ge[x].fitness -= 1
birds.pop(x)
nets.pop(x)
ge.pop(x)
if not pipe.passed and pipe.x < bird.x:
pipe.passed = True
add_pipe = True
if pipe.x + pipe.PIPE_TOP.get_width() < 0:
rem.append(pipe)
pipe.move()
if add_pipe:
score += 1
for g in ge:
g.fitness += 5
pipes.append(Pipe(600))
for r in rem:
pipes.remove(r)
for x, bird in enumerate(birds):
if bird.y + bird.img.get_height() >= 730 or bird.y < 0:
birds.pop(x)
nets.pop(x)
ge.pop(x)
base.move()
draw_window(win, birds, pipes, base, score)
def run(config_path):
config = neat.config.Config(neat.DefaultGenome, neat.DefaultReproduction,
neat.DefaultSpeciesSet, neat.DefaultStagnation,
config_path)
p = neat.Population(config)
p.add_reporter(neat.StdOutReporter(True))
stats = neat.StatisticsReporter()
p.add_reporter(stats)
winner = p.run(main, 50)
if __name__ == '__main__':
local_dir = os.path.dirname(__file__)
config_path = os.path.join(local_dir, 'config-feedforward.txt')
run(config_path)
And sorry for the such long code, you might want to press Ctrl+F to find all the locations of the base element in the code, and I thank you for the help in advance.
PS: The Base is the floor of the game.
You missed to create an instance of Base in main(). e.g:
def main(genomes, config):
# [...]
base = Base(0)
Related
Im new to the world of algorithms. I created my first NEAT AI using python. This was originally for a school project, but the school doesn't let us install any software on the computers. Therefore, I wanted to make a .exe file from a .py file. I've done this several times, this time it didn't work though. I'm guessing it's because it has NEAT involved. In case anybody is interested, here's the code I use(flappy bird with AI):
import pygame
import neat
import time
import os
import random
pygame.font.init()
WIN_WIDTH = 500
WIN_HEIGHT = 800
GEN = 0
BIRD_IMGS = [pygame.transform.scale2x(pygame.image.load("bird1.png")),
pygame.transform.scale2x(pygame.image.load("bird2.png")),
pygame.transform.scale2x(pygame.image.load("bird3.png"))]
PIPE_IMG = pygame.transform.scale2x(pygame.image.load("pipe.png"))
BASE_IMG = pygame.transform.scale2x(pygame.image.load("base.png"))
BG_IMG = pygame.transform.scale2x(pygame.image.load("bg.png"))
STAT_FONT = pygame.font.SysFont("comicsans", 50)
class Bird:
IMGS = BIRD_IMGS
MAX_ROTATION = 25
ROT_VEL = 25
ANIMATION_TIME = 5
def __init__(self, x, y):
self.x = x
self.y = y
self.tilt = 0
self.tick_count = 0
self.vel = 0
self.height = self.y
self.img_count = 0
self.img = self.IMGS[0]
def jump(self):
self.vel = -10.5
self.tick_count = 0
self.height = self.y
def move(self):
self.tick_count += 1
d = self.vel*self.tick_count + 1.5*self.tick_count**2
if d >= 16:
d = 16
if d < 0:
d -= 2
self.y = self.y + d
if d < 0 or self.y < self.height + 50:
if self.tilt < self.MAX_ROTATION:
self.tilt = self.MAX_ROTATION
else:
if self.tilt > -90:
self.tilt -= self.ROT_VEL
def draw(self, win):
self.img_count += 1
if self.img_count < self.ANIMATION_TIME:
self.img = self.IMGS[0]
elif self.img_count < self.ANIMATION_TIME*2:
self.img = self.IMGS[1]
elif self.img_count < self.ANIMATION_TIME*3:
self.img = self.IMGS[2]
elif self.img_count < self.ANIMATION_TIME*4:
self.img = self.IMGS[1]
elif self.img_count == self.ANIMATION_TIME*4 + 1:
self.img = self.IMGS[0]
self.img_count = 0
if self.tilt <= -80:
self.img = self.IMGS[1]
self.img_count = self.ANIMATION_TIME*2
rotated_image = pygame.transform.rotate(self.img, self.tilt)
new_rect = rotated_image.get_rect(center=self.img.get_rect(topleft= (self.x, self.y)).center)
win.blit(rotated_image, new_rect.topleft)
def get_mask(self):
return pygame.mask.from_surface(self.img)
class Pipe:
GAP = 200
VEL = 5
def __init__(self, x):
self.x = x
self.height = 0
self.top = 0
self.bottom = 0
self.PIPE_TOP = pygame.transform.flip(PIPE_IMG, False, True)
self.PIPE_BOTTOM = PIPE_IMG
self.passed = False
self.get_height()
def get_height(self):
self.height = random.randrange(50, 450)
self.top = self.height - self.PIPE_TOP.get_height()
self.bottom = self.height + self.GAP
def move(self):
self.x -= self.VEL
def draw(self, win):
win.blit(self.PIPE_TOP, (self.x, self.top))
win.blit(self.PIPE_BOTTOM, (self.x, self.bottom))
def collide(self, bird):
bird_mask = bird.get_mask()
top_mask = pygame.mask.from_surface(self.PIPE_TOP)
bottom_mask = pygame.mask.from_surface(self.PIPE_BOTTOM)
top_offset = (self.x - bird.x, self.top - round(bird.y))
bottom_offset = (self.x - bird.x, self.bottom - round(bird.y))
b_point = bird_mask.overlap(bottom_mask, bottom_offset)
t_point = bird_mask.overlap(top_mask, top_offset)
if t_point or b_point:
return True
return False
class Base:
VEL = 5
WIDTH = BASE_IMG.get_width()
IMG = BASE_IMG
def __init__(self, y):
self.y = y
self.x1 = 0
self.x2 = self.WIDTH
def move(self):
self.x1 -= self.VEL
self.x2 -= self.VEL
if self.x1 + self.WIDTH < 0:
self.x1 = self.x2 + self.WIDTH
if self.x2 + self.WIDTH < 0:
self.x2 = self.x1 + self.WIDTH
def draw(self, win):
win.blit(self.IMG, (self.x1, self.y))
win.blit(self.IMG, (self.x2, self.y))
def draw_window(win, birds, pipes, base, score, gen):
win.blit(BG_IMG, (0,0))
for pipe in pipes:
pipe.draw(win)
text = STAT_FONT.render("Pontok: " + str(score), 1, (255,255,255))
win.blit(text, (WIN_WIDTH - 10 - text.get_width(), 10))
text = STAT_FONT.render("Generáció: " + str(gen), 1, (255,255,255))
win.blit(text, (10, 10))
base.draw(win)
for bird in birds:
bird.draw(win)
pygame.display.update()
def main(genomes, config):
global GEN
GEN += 1
nets = []
ge = []
birds = []
for _, g in genomes:
net = neat.nn.FeedForwardNetwork.create(g, config)
nets.append(net)
birds.append(Bird(230, 350))
g.fitness = 0
ge.append(g)
score = 0
base = Base(730)
pipes = [Pipe(600)]
win = pygame.display.set_mode((WIN_WIDTH, WIN_HEIGHT))
clock = pygame.time.Clock()
run = True
while run:
clock.tick(30)
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
pygame.quit()
quit()
pipe_ind = 0
if len(birds) > 0:
if len(pipes) > 1 and birds[0].x > pipes[0].x + pipes[0].PIPE_TOP.get_width():
pipe_ind = 1
else:
run = False
break
for x, bird in enumerate(birds):
bird.move()
ge[x].fitness += 0.1
output = nets[x].activate((bird.y, abs(bird.y - pipes[pipe_ind].height), abs(bird.y - pipes[pipe_ind].bottom)))
if output[0] > 0.5:
bird.jump()
add_pipe = False
rem = []
base.move()
for pipe in pipes:
for x, bird in enumerate(birds):
if pipe.collide(bird):
ge[x].fitness -= 1
birds.pop(x)
nets.pop(x)
ge.pop(x)
if not pipe.passed and pipe.x < bird.x:
pipe.passed = True
add_pipe = True
if pipe.x + pipe.PIPE_TOP.get_width() < 0:
rem.append(pipe)
pipe.move()
if add_pipe:
score += 1
for g in ge:
g.fitness += 5
pipes.append(Pipe(600))
for r in rem:
pipes.remove(r)
for x, bird in enumerate(birds):
if bird.y + bird.img.get_height() >= 730 or bird.y < 0:
birds.pop(x)
nets.pop(x)
ge.pop(x)
draw_window(win, birds, pipes, base, score, GEN)
def run(config_path):
config = neat.config.Config(neat.DefaultGenome, neat.DefaultReproduction, neat.DefaultSpeciesSet,
neat.DefaultStagnation, config_path)
p = neat.Population(config)
p.add_reporter(neat.StdOutReporter(True))
stats = neat.StatisticsReporter()
p.add_reporter(stats)
winner = p.run(main,20)
if __name__ == "__main__":
local_dir = os.path.dirname(__file__)
config_path = os.path.join(local_dir, "config_feedforward.txt")
run(config_path)
When I run the .exe file, the console appears, and shows:
pygame 1.9.6
Hello from the pygame community. https://www.pygame.org/contribute.html
And then stops.
when I run the .py file, it starts the AIs normally and says something like:
******* Running Generation 1 *******
The pyinstaller command I use:
pyinstaller --onefile game.py
I didnt find any solutions to this yet, and I've been browsing for 2 days.
I get no errors when running it from cmd. I also get some "hidden import not found" warnings in pyinstaller while building but I don't think that should be a problem.
I've tried by referencing the /imgs library and config-feedforward.txt but it didn't work that way either. Any help is appreciated. Sorry for any typos or bad english.
Have a nice day!
This question already has answers here:
How do I detect collision in pygame?
(5 answers)
How to detect collisions between two rectangular objects or images in pygame
(1 answer)
Closed 2 years ago.
I'm making a game environment for NEAT. The first two obstacles seem to collide with the players just fine, but none of the other obstacles do anything. The visuals won't work, but based on the size of the player list, yeah no it's not working. The collide class also wouldn't work before I started implementing NEAT, so there's that.
Anyway here's some (probably) irrelevant code:
import pygame
from pygame.locals import *
import random
import os
import neat
debugfun = 0
W = 300
H = 300
win = pygame.display.set_mode((W, H))
pygame.display.set_caption("bruv moment")
coords = [0, 60, 120, 180, 240]
class Player(object):
def __init__(self, x):
self.x = x
self.y = 600 - 60
self.width = 60
self.height = 60
self.pos = 0
self.left = False
self.right = False
def move(self):
if self.left:
self.pos -= 1
if self.right:
self.pos += 1
if self.pos < 0:
self.pos = 4
if self.pos > 4:
self.pos = 0
self.x = coords[self.pos]
class Block(object):
def __init__(self, pos, vel):
self.pos = pos
self.x = coords[self.pos]
self.y = -60
self.width = 60
self.height = 60
self.vel = vel
def move(self):
self.y += self.vel
def redraw_window():
pygame.draw.rect(win, (0, 0, 0), (0, 0, W, H))
for ob in obs:
pygame.draw.rect(win, (0, 255, 0), (ob.x, ob.y, ob.width, ob.height))
for ind in homies:
pygame.draw.rect(win, (255, 0, 0), (ind.x, ind.y, ind.width, ind.height))
pygame.display.update()
obs = []
homies = []
player_collision = False
ge = []
nets = []
And here's some relevant code:
def collide():
for ob in obs:
for x, ind in enumerate(homies):
if ind.y < ob.y + ob.height and ind.y + ind.height > ob.y and ind.x + ind.width > ob.x and ind.x < ob.x + ob.width:
ge[x].fitness -= 1
homies.pop(x)
nets.pop(x)
ge.pop(x)
def main(genomes, config):
speed = 30
pygame.time.set_timer(USEREVENT + 1, 550)
pygame.time.set_timer(USEREVENT + 2, 1000)
for _, g in genomes:
net = neat.nn.FeedForwardNetwork.create(g, config)
nets.append(net)
homies.append(Player(0))
g.fitness = 0
ge.append(g)
clock = pygame.time.Clock()
ran = True
while ran and len(homies) > 0:
clock.tick(27)
collide()
for x, ind in enumerate(homies):
ind.move()
ge[x].fitness += 0.1
try:
output = nets[x].activate((ind.x, abs(obs[0].x - ind.x)))
except IndexError:
output = 50
try:
if output in range(5, 25):
ind.left = True
else:
ind.left = False
if output > 25:
ind.right = True
else:
ind.right = False
except TypeError:
if output[0] in range(5, 25):
ind.left = True
else:
ind.left = False
if output[1] > 25:
ind.right = True
else:
ind.right = False
for ob in obs:
ob.move()
if ob.x > H:
obs.pop(obs.index(ob))
for event in pygame.event.get():
if event.type == pygame.QUIT:
ran = False
pygame.quit()
if event.type == USEREVENT+1:
if speed <= 200:
speed += 3
if event.type == USEREVENT+2:
for g in ge:
g.fitness += 0.5
if len(obs) == 0:
obs.append(Block(round(random.randint(0, 4)), speed))
print(len(homies))
print(len(obs))
redraw_window()
def run(config_file):
config = neat.config.Config(neat.DefaultGenome, neat.DefaultReproduction, neat.DefaultSpeciesSet,
neat.DefaultStagnation, config_path)
p = neat.Population(config)
p.add_reporter(neat.StdOutReporter(True))
stats = neat.StatisticsReporter()
p.add_reporter(stats)
winner = p.run(main, 50)
if __name__ == "__main__":
local_dir = os.path.dirname(__file__)
config_path = os.path.join(local_dir, "avoidpedofiles.txt")
run(config_path)
Everything seems fine but my computer found that i have invalid syntax and it marks colon(:).
code:
if keys[pygame.K_RIGHT] and man.x < 500 - man.width: # <- here he marks this colon
man.x = man.x + man.vel
man.right = True
man.left = False
man.standing = False
Full code:
import pygame
pygame.init()
cl = pygame.time.Clock()
lefty = [pygame.image.load('Game/L1.png'),pygame.image.load('Game/L2.png'),pygame.image.load('Game/L3.png'),pygame.image.load('Game/L4.png'),pygame.image.load('Game\L5.png'),pygame.image.load('Game/L6.png'),pygame.image.load('Game/L7.png'),pygame.image.load('Game/L8.png'),pygame.image.load('Game/L9.png')]
righty = [pygame.image.load('Game/R1.png'),pygame.image.load('Game/R2.png'),pygame.image.load('Game/R3.png'),pygame.image.load('Game/R4.png'),pygame.image.load('Game/R5.png'),pygame.image.load('Game/R6.png'),pygame.image.load('Game/R7.png'),pygame.image.load('Game/R8.png'),pygame.image.load('Game/R9.png')]
gr = pygame.image.load('Game/bg.jpg')
st = pygame.image.load('Game/standing.png')
win = pygame.display.set_mode((500,480))
name = pygame.display.set_caption("photo game")
class player(object):
def __init__(self, x, y, width, height):
self.jumpCount = 10
self.jump=False
self.x = x
self.y = y
self.width = width
self.height = height
self.vel = 5
self.left = False
self.right = False
self.walkCount= 0
self.standing = True
def draw(self,win):
if self.walkCount+1>=27:
self.walkCount=0
if not(self.standing):
if self.left:
win.blit(lefty[self.walkCount//3],(self.x,self.y))
self.walkCount +=1
elif self.right:
win.blit(righty[self.walkCount//3],(self.x,self.y))
self.walkCount +=1
else:
if self.right:
win.blit(righty[0], (self.x, self.y))
else:
win.blit(lefty[0], (self.x, self.y))
class projectiles(object):
def __init__(self,x,y,radius,color,facing):
self.x = x
self.y = y
self.radius = radius
self.color = color
self.facing = facing
self.vel = 8 * facing
def draw(win, self):
pygame.draw.radius(win, self.color, (self.x, self.y), self.radius, self.facing)
def redrawchar():
win.blit(gr,(0,0))
man.draw(win)
for bullet in bullets:
bullet.draw(win)
pygame.display.update()
man = player(50, 420, 62, 62)
while True:
cl.tick(27)
bullets = []
for events in pygame.event.get():
if events.type == pygame.QUIT:
break
for bullet in bullets:
if bullet.x < 500 and bullet.x > 0:bullet.x += bullet.vel
else: bullets.pop(bullets.index(bullet))
for events in pygame.event.get():
if events.type == pygame.QUIT:
break
keys = pygame.key.get_pressed()
if keys[pygame.K_c]:
if man.right:
facing=1
else:
facing = -1
if len(bullets) < 5:
bullets.append(projectiles((round(man.x + man.weight //2)), (round(man.y + man.height //2)), 6, (0,0,0), facing)
if keys[pygame.K_RIGHT] and man.x < 500 - man.width: #here is that error
man.x = man.x + man.vel
man.right = True
man.left = False
man.standing = False
elif keys[pygame.K_LEFT] and man.x > man.vel-5-5:
man.x-=man.vel
man.left = True
man.right = False
man.standing = False
else:
man.standing = True
man.walkCount=0
if not(man.jump):
if keys[pygame.K_SPACE]:
man.jump = True
man.right = False
man.left = False
man.walkCount=0
else:
if man.jumpCount>=-10:
man.y -= (man.jumpCount*abs(man.jumpCount)) *0.5
man.jumpCount -=1
else:
man.jumpCount = 10
man.jump = False
redrawchar()
pygame.quit()
I tryed to put 500 - man.width in brackets like (500 - man.width): but it's not working.
Can someone please help.
I am working in py 3.7 and everything is ok and seems to be right. However why does my computer not like that colon(:) for some reason?
Does anyone have any ideas why?
The syntax error is not caused by the line:
if keys[pygame.K_RIGHT] and man.x < 500 - man.width:
This line is syntactically correct. It is the line before that line, which causes the error:
if len(bullets) < 5:
bullets.append(projectiles((round(man.x + man.weight //2)), (round(man.y + man.height //2)), 6, (0,0,0), facing)
At the end of the call to bullets.append is missing the closing bracket ). This causes the syntax error in the next line, because the subsequent tokens are unexpected.
This question already has answers here:
How do I detect collision in pygame?
(5 answers)
How to detect collisions between two rectangular objects or images in pygame
(1 answer)
Closed 2 years ago.
It can collide properly on all sides and when i jump from the the ground onto the platform the player will land ontop of it and collide properly. However when i am standing on the platform and i jump and try to land on the platform again i fall straight through. Why does this happen?
Also if i hold down space bar then my sprite does not fall through the box and jumps ontop of it normally.
What it looks like: https://gyazo.com/6e0c9dfd15cdd99e72f14137fb5ef1cb
What it should look like: https://gyazo.com/bec5dc5a07d0d323b4d1cc8597eafb39
main.py
import pygame
from map import *
from char import *
pygame.init()
class game():
def __init__(self):
self.width = 1280
self.height = 720
self.gameRunning = True
self.clock = pygame.time.Clock()
self.FPS = 60
self.screen = pygame.display.set_mode((self.width, self.height))
self.loadMapData()
def update(self):
pygame.display.set_caption("{:.2f}".format(self.clock.get_fps()))
self.screen.fill(white)
self.screen.blit(self.map_img, (0,336))
playerGroup.draw(self.screen)
pygame.display.update()
def gameLoop(self):
self.clock.tick(self.FPS)
self.event()
player1.move()
self.update()
def event(self):
for event in pygame.event.get():
if event.type == pygame.QUIT:
self.gameRunning = False
def loadMapData(self):
self.map = TiledMap()
self.map_img = self.map.make_mapSurface()
for tile_object in self.map.gameMap.objects:
if tile_object.name == "Floor":
Collision(tile_object.x, tile_object.y + 336, tile_object.width, tile_object.height)
if tile_object.name == "Collision Box":
Platform(tile_object.x, tile_object.y + 336, tile_object.width, tile_object.height)
g = game()
player1 = player()
while g.gameRunning == True:
g.gameLoop()
map.py
import pygame
import pytmx
from char import *
pygame.init()
class TiledMap():
def __init__(self):
self.gameMap = pytmx.load_pygame("CollisionMap.tmx")
self.mapwidth = self.gameMap.tilewidth * self.gameMap.width
self.mapheight = self.gameMap.tileheight * self.gameMap.height
def renderMap(self, surface):
for layer in self.gameMap.visible_layers:
if isinstance(layer, pytmx.TiledTileLayer):
for x,y,gid in layer:
tile = self.gameMap.get_tile_image_by_gid(gid)
if tile:
surface.blit(tile, (x * self.gameMap.tilewidth, y * self.gameMap.tileheight))
def make_mapSurface(self):
mapSurface = pygame.Surface((self.mapwidth, self.mapheight), pygame.SRCALPHA)
self.renderMap(mapSurface)
return mapSurface
class Collision(pygame.sprite.Sprite):
def __init__(self, x, y, width, height):
self.groups = SolidGroup
pygame.sprite.Sprite.__init__(self, self.groups)
self.rect = pygame.Rect(x, y, width, height)
class Platform(pygame.sprite.Sprite):
def __init__(self, x, y, width, height):
self.groups = platformGroup
pygame.sprite.Sprite.__init__(self, self.groups)
self.rect = pygame.Rect(x, y, width, height)
char.py
import pygame
pygame.init()
black = (0, 0, 0)
white = (255, 255, 255)
red = (255, 0, 0)
green = (0, 255, 0)
blue = (0, 0, 255)
playerGroup = pygame.sprite.Group()
SolidGroup = pygame.sprite.Group()
platformGroup = pygame.sprite.Group()
class player(pygame.sprite.Sprite):
def __init__(self):
self.groups = playerGroup
pygame.sprite.Sprite.__init__(self, self.groups)
self.image = pygame.Surface((50, 50))
self.image.fill(blue)
self.rect = self.image.get_rect()
self.rect.center = (1280/2, 720/2)
self.position = pygame.math.Vector2(400, 300)
self.acceleration = pygame.math.Vector2(0, 0)
self.velocity = pygame.math.Vector2(0, 0)
self.friction = -0.18
self.falling = False
self.up = False
self.down = False
self.right = False
self.Left = False
def checkFalling(self):
self.rect.y += 1
if not pygame.sprite.spritecollideany(self, SolidGroup, False):
self.falling = True
if self.velocity.y < 0:
self.up = True
self.down = False
if self.velocity.y > 0:
self.up = False
self.down = True
else:
self.falling = False
self.up = False
self.down = False
self.rect.y -= 1
def move(self):
self.checkFalling()
if self.falling:
self.acceleration = pygame.math.Vector2(0, 0.5)
if not self.falling:
self.acceleration = pygame.math.Vector2(0, 0)
key = pygame.key.get_pressed()
if key[pygame.K_RIGHT]:
self.acceleration.x = 1
self.right = True
if key[pygame.K_LEFT]:
self.acceleration.x = -1
self.left = True
if key[pygame.K_SPACE]:
self.jump()
self.acceleration.x += self.velocity.x * self.friction
self.velocity += self.acceleration
if abs(self.velocity.x) < 0.1:
self.velocity.x = 0
self.position += self.velocity + 0.5 * self.acceleration
hitsPlatform = pygame.sprite.spritecollide(self, platformGroup, False)
if hitsPlatform:
if self.up:
self.position.y -= self.velocity.y - 0.5 * self.acceleration.y
self.velocity.y = 0
self.rect.midbottom = self.position
"""
Collision Code, not in function because of screen tearing and bouncy collisions
"""
hits = pygame.sprite.spritecollide(self, SolidGroup, False)
if hits:
self.position.y = hits[0].rect.top
self.velocity.y = 0
hitsPlatform = pygame.sprite.spritecollide(self, platformGroup, False)
if hitsPlatform:
if self.down and self.position.y <= 340:
self.position.y = hitsPlatform[0].rect.top
self.velocity.y = 0
if self.velocity.x > 0 and self.position.x + 64 < 239:
self.position.x -= self.velocity.x - 0.5 * self.acceleration.x
if self.velocity.x < 0 and self.position.x > 256:
self.position.x -= self.velocity.x - 0.5 * self.acceleration.x
self.rect.midbottom = self.position
def jump(self):
self.rect.y += 1
hits = pygame.sprite.spritecollide(self, SolidGroup, False)
hitsPlatform = pygame.sprite.spritecollide(self, platformGroup, False)
self.rect.y -= 1
if hits:
self.velocity.y = -15
if hitsPlatform:
self.velocity.y = -15
I am creating a brick breaker game using tkinter, but cannot figure out how to update the scoreboard. I do not get any error messages. The only problem is that the scoreboard stays at zero throughout the game. It should add 10 points each time a block is hit. Any suggestions would be amazing.
from tkinter import *
import random
import time
tk = Tk()
tk.title("Game")
tk.resizable(0, 0)
tk.wm_attributes("-topmost", 1)
canvas = Canvas(tk, width=500, height=400, bd=0, highlightthickness=0)
canvas.pack()
tk.update()
class Ball:
def __init__(self, canvas, paddle, score, block1, block2, block3, block4, block5, color):
self.canvas = canvas
self.paddle = paddle
self.block1 = block1
self.block2 = block2
self.block3 = block3
self.block4 = block4
self.block5 = block5
self.score = score
self.id = canvas.create_oval(10, 10, 25, 25, fill=color)
self.canvas.move(self.id, 245, 100)
starts = [-3, -2, -1, 1, 2, 3]
random.shuffle(starts)
self.x = starts[0]
self.y = -3
self.canvas_height = self.canvas.winfo_height()
self.canvas_width = self.canvas.winfo_width()
self.hit_bottom = False
def draw(self):
self.canvas.move(self.id, self.x, self.y)
pos = self.canvas.coords(self.id)
if pos[1] <= 0:
self.y = 3
if self.hit_paddle(pos) == True:
self.y = -3
if pos[3] >= self.canvas_height:
self.hit_bottom = True
if pos[0] <= 0:
self.x = 3
if pos[2] >= self.canvas_width:
self.x = -3
if self.hit_block(pos) == True:
self.y = +3
if self.hit_block == True:
self.scoreboard = self.score_board + self.add_score
def hit_paddle(self, pos):
paddle_pos = self.canvas.coords(self.paddle.id)
if pos[2] >= paddle_pos[0] and pos[0] <= paddle_pos[2]:
if pos[3] >= paddle_pos[1] and pos[3] <= paddle_pos[3]:
return True
return False
def hit_block(self,pos):
block1_pos = self.canvas.coords(self.block1.id)
if block1_pos and (pos[2] >= block1_pos[0] and pos[0] <= block1_pos[2]):
if block1_pos and(pos[3] >= block1_pos[1] and pos[3] <= block1_pos[3]):
self.canvas.delete(self.block1.id)
return True
block2_pos = self.canvas.coords(self.block2.id)
if block2_pos and (pos[2] >= block2_pos[0] and pos[0] <= block2_pos[2]):
if block2_pos and(pos[3] >= block2_pos[1] and pos[3] <= block2_pos[3]):
self.canvas.delete(self.block2.id)
return True
block3_pos = self.canvas.coords(self.block3.id)
if block3_pos and (pos[2] >= block3_pos[0] and pos[0] <= block3_pos[2]):
if block3_pos and(pos[3] >= block3_pos[1] and pos[3] <= block3_pos[3]):
self.canvas.delete(self.block3.id)
return True
block4_pos = self.canvas.coords(self.block4.id)
if block4_pos and (pos[2] >= block4_pos[0] and pos[0] <= block4_pos[2]):
if block4_pos and(pos[3] >= block4_pos[1] and pos[3] <= block4_pos[3]):
self.canvas.delete(self.block4.id)
return True
block5_pos = self.canvas.coords(self.block5.id)
if block5_pos and (pos[2] >= block5_pos[0] and pos[0] <= block5_pos[2]):
if block5_pos and(pos[3] >= block5_pos[1] and pos[3] <= block5_pos[3]):
self.canvas.delete(self.block5.id)
return True
return False
class Score:
def __init__(self, canvas):
self.canvas = canvas
self.add_score = 10
self.scoreboard = 0
self.id = canvas.create_text(50,25, text='Your score = %s' %(self.scoreboard))
class Paddle:
def __init__(self, canvas, color):
self.canvas = canvas
self.id = canvas.create_rectangle(0, 0, 100, 10, fill=color)
self.canvas.move(self.id, 200, 300)
self.x = 0
self.canvas_width = self.canvas.winfo_width()
self.canvas.bind_all('<KeyPress-Left>', self.turn_left)
self.canvas.bind_all('<KeyPress-Right>', self.turn_right)
def turn_left(self, evt):
self.x = -2
def turn_right(self, evt):
self.x = 2
def draw(self):
self.canvas.move(self.id, self.x, 0)
pos = self.canvas.coords(self.id)
if pos[0] <= 0:
self.x = 0
elif pos[2] >= self.canvas_width:
self.x = 0
class Block:
def __init__(self, canvas, x, y, color):
self.canvas = canvas
self.x = int(x)
self.y = int(y)
self.id = canvas.create_rectangle(self.x, self.y, self.x + 50, self.y + 10, fill=color)
self.canvas.move(self.id, self.x, self.y)
block1 = Block(canvas, 50, 25, 'orange')
block2 = Block(canvas, 90, 25, 'yellow')
block3 = Block(canvas, 130, 25, 'green')
block4 = Block(canvas, 170, 25, 'blue')
block5 = Block(canvas, 210, 25, 'violet')
score = Score(canvas)
paddle = Paddle(canvas, 'blue')
ball = Ball(canvas, paddle, score, block1, block2, block3, block4, block5, 'red')
while 1:
if ball.hit_bottom == False:
ball.draw()
paddle.draw()
tk.update_idletasks()
tk.update()
time.sleep(0.01)
After you change self.scoreboard you have to replace text manually
canvas.itemconfig(self.id, text='Your score = %s' % (self.scoreboard))
effbot.org: The Tkinter Canvas Widget
BTW: If you use IntVar() to keep score then you could use trace('w', callback) to assign function callback to this IntVar() which could change this text on canvas everytime you change value in this IntVar()
effbot.org: The Variable Classes (BooleanVar, DoubleVar, IntVar, StringVar)