I'm trying to create a function that tells me if two canvas objects(in my code, rec and block) touch each other in Tkinter. I tried to do so with the information of their coordinates but it doesn't seem to work. Can you please help me?
The function will be used in snake which I'm creating in the code below, so don't ask my why the code is so long.
The function is in the line 119, same_poz
This is my code:
from tkinter import *
import time
import random
import threading
root = Tk()
root.title('Snake')
x, y = 484, 484
recX, recY = x // 2, y // 2
recW, recH = recX + 22, recY + 22
randoms = []
for i in range(484):
if i % 11 == 0:
randoms.append(i)
blockX, blockY = random.choice(randoms), random.choice(randoms)
blockW, blockH = blockX + 22, blockY + 22
c = Canvas(root, bg='black', width=x, height=y)
c.pack()
class Snake(threading.Thread):
def __init__(self, c, x, y, recX, recY, recW, recH, blockX, blockY, blockW, blockH):
super(Snake, self).__init__()
self.c = c
self.x = x
self.y = y
self.recX = recX
self.recY = recY
self.recW = recW
self.recH = recH
self.blockW = blockW
self.blockH = blockH
self.rec = c.create_rectangle(recX, recY, recW, recH, fill='red', outline='white')
self.blockX = blockX
self.blockY = blockY
self.block = c.create_rectangle(blockX, blockY, blockW, blockH, fill='green',
outline='white')
self.moving_right = False
self.moving_left = False
self.moving_up = False
self.moving_down = False
self.moving = False
def movingright(self):
self.moving_right = True
self.moving_left = False
self.moving_up = False
self.moving_down = False
self.moving = True
c.move(self.rec, 11, 0)
self.after4 = root.after(150, self.movingright)
def movingleft(self):
self.moving_left = True
self.moving_left = False
self.moving_up = False
self.moving_down = False
self.moving = True
c.move(self.rec, -11, 0)
self.after3 = root.after(150, self.movingleft)
def movingup(self):
self.moving_up = True
self.moving_right = False
self.moving_left = False
self.moving_up = False
self.moving = True
c.move(self.rec, 0, -11)
self.after = root.after(150, self.movingup)
def movingdown(self):
self.moving_down = True
self.moving_right = False
self.moving_left = False
self.moving_down = False
self.moving = True
c.move(self.rec, 0, 11)
self.after2 = root.after(150, self.movingdown)
def stop(self):
self.moving_right = False
self.moving_left = False
self.moving_up = False
self.moving_down = False
self.moving = False
try:
root.after_cancel(self.after)
except AttributeError:
pass
try:
root.after_cancel(self.after2)
except AttributeError:
pass
try:
root.after_cancel(self.after3)
except AttributeError:
pass
try:
root.after_cancel(self.after4)
except AttributeError:
pass
def move(self, n):
if n.keysym == 'Up':
self.stop()
self.movingup()
if n.keysym == 'Down':
self.stop()
self.movingdown()
if n.keysym == 'Right':
self.stop()
self.movingright()
if n.keysym == 'Left':
self.stop()
self.movingleft()
def same_poz(self):
if self.blockY == self.recY:
self.helpY = random.randint(10, self.y - self.blockY)
self.c.move(self.block, 0, self.helpY)
if self.blockX == self.recY:
self.helpX = random.randint(10, self.x - self.blockX)
self.c.move(self.block, 0, self.helpX)
if self.blockW == self.recW:
self.helpW = random.randint(10, self.x - self.blockW)
self.c.move(self.block, 0, self.helpW)
if self.blockH == self.recH:
self.helpH = random.randint(10, self.y - self.blockH)
self.c.move(self.block, 0, helpH)
cube = Snake(c, x, y, recX, recY, recW, recH, blockX, blockY, blockW, blockH)
cube.start()
cube.c.bind_all('<Key>', cube.move, cube.stop)
cube.c.bind_all('<Key>', cube.moving_left, cube.moving_right)
cube.c.bind_all('<Key', cube.moving_up, cube.moving_down)
cube.c.bind(cube.same_poz)
root.mainloop()
There are way too many problems with your code, with what you provided. I do not know why you are programming using Tkinter when you are still lacking the basics of Python. (Don't mean to sound harsh)
I do not know why you decided to inherit from threading.Thread when
you do not have any use for anything Thread provides in that
class.
Way too many instance parameters which you have no use for at all, and too many instance parameters that you have to change every single time.
Not using elif and instead using if constantly.
If you are using a thread to handle Tkinter changes outside of mainloop, there is no need to use .after since it basically does that.
Tkinter has dedicated bindings for every single key, including combinations of keys. There is no need to catch every single key event.
Use if __name__ == '__main__': if you are working with a single script, for testing it.
Some reading material on Tkinter - http://effbot.org/tkinterbook/
Here is a minimal rework of the code, that is working.
import time
import random
import threading
from tkinter import *
MOVINGUP = 'u'
MOVINGDOWN = 'd'
MOVINGLEFT = 'l'
MOVINGRIGHT = 'r'
NOTMOVING = '0'
class Snake:
def __init__(self, root, recX, recY, recW, recH, blockX, blockY, blockW, blockH):
self.root = root
self.c = Canvas(root, bg='black', width=x, height=y)
self.c.pack()
self.rec = self.c.create_rectangle(recX, recY, recW, recH, fill='red', outline='white')
self.block = self.c.create_rectangle(blockX, blockY, blockW, blockH, fill='green', outline='white')
self.direction = NOTMOVING
self.root.bind('<Up>', lambda e: self.moveset(MOVINGUP))
self.root.bind('<Down>', lambda e: self.moveset(MOVINGDOWN))
self.root.bind('<Left>', lambda e: self.moveset(MOVINGLEFT))
self.root.bind('<Right>', lambda e: self.moveset(MOVINGRIGHT))
def moveset(self, direction):
self.direction = direction
def movement(self):
if self.direction == MOVINGUP:
self.c.move(self.rec, 0, -11)
elif self.direction == MOVINGDOWN:
self.c.move(self.rec, 0, 11)
elif self.direction == MOVINGLEFT:
self.c.move(self.rec, -11, 0)
elif self.direction == MOVINGRIGHT:
self.c.move(self.rec, 11, 0)
self.same_poz()
def run(self):
while True:
time.sleep(0.15)
self.movement()
def same_poz(self):
# Snake (x0, y0, x1, y1)
snakepos = self.c.bbox(self.rec)
# Food block (x0, y0, x1, y1)
food = self.c.bbox(self.block)
# If direction matters, if not then possible to only use self.hit in a single condition.
if self.direction == MOVINGRIGHT and self.hit(snakepos, food):
print('Caught the food moving right.')
elif self.direction == MOVINGLEFT and self.hit(snakepos, food):
print('Caught the food moving left.')
elif self.direction == MOVINGUP and self.hit(snakepos, food):
print('Caught the food moving up.')
elif self.direction == MOVINGDOWN and self.hit(snakepos, food):
print('Caught the food moving down.')
def hit(self, snakepos, food):
"""
Recieves coordinates of food block and snake block and returns if they collide.
:param snakepos: Tuple containing (x0, y0, x1, y1) of the snake.
:param food: Tuple containing (x0, y0, x1, y1) of the food block.
:return: Boolean whether they collide
"""
snakex = (snakepos[0], snakepos[2])
snakey = (snakepos[1], snakepos[3])
foodx = (food[0], food[2])
foody = (food[1], food[3])
# Returns True if any of the snake x cooridnates are between the food x coordinates, or both x coordinates match.
if any((foodx[0] < xcoord < foodx[1] for xcoord in snakex)) or foodx == snakex:
# Returns True if any of the snake y cooridnates are between the food y coordinates, or both y coordinates match.
return any((foody[0] < ycoord < foody[1] for ycoord in snakey)) or foody == snakey
return False
if __name__ == '__main__':
root = Tk()
root.title('Snake')
x, y = 484, 484
recX, recY = x // 2, y // 2
recW, recH = recX + 22, recY + 22
randoms = []
for i in range(484):
if i % 11 == 0:
randoms.append(i)
blockX, blockY = random.choice(randoms), random.choice(randoms)
blockW, blockH = blockX + 22, blockY + 22
snake = Snake(root, recX, recY, recW, recH, blockX, blockY, blockW, blockH)
threading.Thread(target=snake.run, daemon=True).start()
root.mainloop()
Related
I am trying to make a platforming game and I keep getting this error when I tried to add particles for when the character jumps, and I can't figure it out. Everytime I try and jump with the character the error pops up. I will need some help in order to fix this.
Code for the Level
import pygame
# Importing the necessary files
from tiles import Tile
from settings import tile_size, screen_width
from player import Player
from particles import ParticleEffect
class Level:
def __init__(self, level_data, surface):
# Level setup
self.display_surface = surface
self.setup_level(level_data)
self.world_shift = 0
self.current_x = 0
# Particles
self.dust_sprite = pygame.sprite.GroupSingle()
def setup_level(self, layout):
self.tiles = pygame.sprite.Group()
self.player = pygame.sprite.GroupSingle()
for row_index, row in enumerate(layout):
for column_index, cell in enumerate(row):
x = column_index * tile_size
y = row_index * tile_size
if cell == "X":
tile = Tile((x, y), tile_size)
self.tiles.add(tile)
if cell == "P":
player_sprite = Player((x, y), self.display_surface, self.jump_particles)
self.player.add(player_sprite)
def jump_particles(self, pos):
jump_particle_sprite = ParticleEffect(pos, 'Jump')
self.dust_sprite.add(jump_particle_sprite)
def scroll_x(self):
player = self.player.sprite
player_x = player.rect.centerx
direction_x = player.direction.x
if player_x < screen_width / 4 and direction_x < 0:
self.world_shift = 8
player.speed = 0
elif player_x > screen_width - (screen_width / 4) and direction_x > 0:
self.world_shift = -8
player.speed = 0
else:
self.world_shift = 0
player.speed = 8
# Checks for horizontal collisions with the tiles
def horizontal_collision(self):
player = self.player.sprite
player.rect.x += player.direction.x * player.speed
for sprite in self.tiles.sprites():
if sprite.rect.colliderect((player.rect)):
if player.direction.x < 0:
player.rect.left = sprite.rect.right
player.on_left = True
self.current_x = player.rect.left
elif player.direction.x > 0:
player.rect.right = sprite.rect.left
player.on_right = True
self.current_x = player.rect.right
if player.on_left == True and (player.rect.left < self.current_x or player.direction.x >= 0):
player.on_left = False
if player.on_right == True and (player.rect.left > self.current_x or player.direction.x <= 0):
player.on_right = False
def vertical_collision(self):
player = self.player.sprite
player.apply_gravity()
for sprite in self.tiles.sprites():
if sprite.rect.colliderect((player.rect)):
if player.direction.y > 0:
player.rect.bottom = sprite.rect.top
player.direction.y = 0
player.on_ground = True
elif player.direction.y < 0:
player.rect.top = sprite.rect.bottom
player.direction.y = 0
player.on_ceiling = True
if player.on_ground == True and player.direction.y < 0 or player.direction.y > 1:
player.on_ground = False
if player.on_ceiling == True and player.direction.y > 0:
player.on_ceiling = False
def run(self):
# Tiles for the level
self.tiles.update(self.world_shift)
self.tiles.draw(self.display_surface)
self.scroll_x()
# Dust Particles
self.dust_sprite.update(self.world_shift)
self.dust_sprite.draw(self.display_surface)
# Player for the level
self.player.update()
self.horizontal_collision()
self.vertical_collision()
self.player.draw(self.display_surface)
Code for the Class ParticleEffect
import pygame
from support import import_folder
class ParticleEffect(pygame.sprite.Sprite):
def _init__(self, pos, type):
super().__init__()
self.frame_index = 0
self.animation_speed = 0.5
if type == 'Jump':
self.frames = import_folder('Hero/Dust Particles/Jump')
if type == 'Land':
self.frames = import_folder('Hero/Dust Particles/Land')
self.image = self.frames[self.frame_index]
self.rect = self.image.get_rect(center = pos)
def animate(self):
self.frame_index += self.animation_speed
if self.frame_index >= len(self.frames):
self.kill()
else:
self.image = self.frames[int(self.frame_index)]
def update(self, x_shift):
self.animate()
self.rect.x += x_shift
import_folder is just a class used for loading images.
The full error is
File "C:\School\KS5\Computer Science\Project\Coding\pythonProject\player.py", line 109, in get_input
self.jump_particles(self.rect.midbottom)
File "C:\School\KS5\Computer Science\Project\Coding\pythonProject\level.py", line 35, in jump_particles
jump_particle_sprite = ParticleEffect(pos, 'Jump')
File "C:\School\KS5\Computer Science\Project\Coding\pythonProject\venv\lib\site-packages\pygame\sprite.py", line 115, in __init__
self.add(*groups)
File "C:\School\KS5\Computer Science\Project\Coding\pythonProject\venv\lib\site-packages\pygame\sprite.py", line 133, in add
self.add(*group)
File "C:\School\KS5\Computer Science\Project\Coding\pythonProject\venv\lib\site-packages\pygame\sprite.py", line 133, in add
self.add(*group)
TypeError: pygame.sprite.Sprite.add() argument after * must be an iterable, not int
You have a typo in the __init__() method in your ParticleEffect class that is causing this issue.
The def _init__(self, pos, type) is missing a underscore _ at the beginning.
I'm working on a basic game with python, but the system gives an error
impostors.x = new_x_pos
AttributeError: 'list' object has no attribute 'x'
Below is my code, can anyone tell me what I'm doing wrong? I've checked very carefully but still can't find the error, Since I'm a newbie, I don't have much experience so I hope you guys can help me
import pgzrun
import random
FONT_COLOR = (255, 255, 255) #màu RGB
WIDTH = 1300
HEIGHT = 700
CENTER_X = WIDTH / 2
CENTER_Y = HEIGHT / 2
CENTER = (CENTER_X, CENTER_Y)
START_SPEED = 10
COLORS = ["orange", "blue"]
current_level = 1
final_level = 5
game_over = False
game_complete = False
impostors = []
animation = []
def draw():
global impostors,current_level,game_over,game_complete
screen.clear()
screen.blit("dark",(0,0))
if game_over:
display_message("Game Over", "Press Space to play again")
elif game_complete:
display_message("You win", "Press Space to play again")
else:
for im in impostors:
im.draw()
def update():
global impostors,current_level,game_over,game_complete
if len(impostors) == 0:
impostors = make_impostors(current_level)
if (game_over or game_complete) and keyboard.space:
impostors = []
current_level = 1
game_complete = False
game_over = False
def make_impostors(number_of_impostors):
colors_to_create = get_colors_to_create(number_of_impostors)
new_impostors = create_impostors(colors_to_create)
layout_impostors(new_impostors)
animate_impostors(new_impostors)
return new_impostors
def get_colors_to_create(number_of_impostors):
colors_to_create = ["red"]
for i in range(0,number_of_impostors):
random_color = random.choice(COLORS)
colors_to_create.append(random_color)
return colors_to_create
def create_impostors(colors_to_create):
new_impostors = []
for color in colors_to_create:
impostor = Actor(color + "-im")
new_impostors.append(impostors)
return new_impostors
def layout_impostors(impostors_to_layout):
number_of_gaps = len(impostors_to_layout) + 1
gap_size = WIDTH/number_of_gaps
random.shuffle(impostors_to_layout)
for index, impostor in enumerate(impostors_to_layout):
new_x_pos = (index + 1)*gap_size
impostor.x = new_x_pos
def animation_impostors(impostors_to_animate):
for impostors in impostors_to_animate:
duration = START_SPEED - current_level
impostors.anchor = ("center", "bottom")
animation = animation(impostors, duration = duration, on_finished = handle_game_over, y = HEIGHT)
animations.append(animation)
def handle_game_over():
global game_over
game_over = True
def on_mouse_down(pos):
global impostors, current_level
for impostors in impostors:
if impostors.collidepoint(pos):
if "red" in impostors.image:
red_impostor_click()
else:
handle_game_over()
def red_impostor_click():
global current_level, impostors, animation, game_complete
stop_animations(animations)
if current_level == final_level:
game_complete = True
else:
current_level = current_level + 1
impostors = []
animations = []
def stop_animations(animations_to_stop):
for animation in animations_to_stop:
if animation.running:
animation.stop()
def display_message(heading_text, sub_heading_text):
screen.draw.text(heading_text, fontsize = 60, center = CENTER, color = FONT_COLOR)
screen.draw.text(sub_heading_text,
fontsize = 30,
center = (CENTER_X, CENTER_Y + 30),
color = FONT_COLOR)
pgzrun.go()
The problem is the loop for impostors in impostors:. Rename the loop variable to impostor:
def on_mouse_down(pos):
global impostors, current_level
for impostor in impostors:
if impostor.collidepoint(pos):
if "red" in impostors.image:
red_impostor_click()
else:
handle_game_over()
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.
After some work I finished my first algorithm for a maze generator and now I am trying to make it visual in Pygame. I first let the algorithm generate a maze and then I make a visual representation of it.
Here I get into multiple problems, but I think they are all linked to the same thing which is that the first cell of the maze gets overwritten in some way. Because of this, what I get is totally not a maze at all but just some lines everywhere.
I tried putting the removal of walls in a seperate method, but that does not seem to work also. I looked if the remove walls method gets called at the first cell and it says it is true, but in some way the values of that cell gets overwritten.
Code:
import pygame
import random
WIDTH = 300
HEIGHT = 300
CellSize = 30
Rows = int(WIDTH/30)
Columns = int(HEIGHT/30)
current = None
grid = []
visited = []
DISPLAY = pygame.display.set_mode((WIDTH, HEIGHT))
class Cell:
def __init__(self, r, c):
self.r = r
self.c = c
self.x = CellSize * c
self.y = CellSize * r
self.sides = [True, True, True, True] # Top, Bottom, Left, Right
self.visited = False
self.neighbours = []
self.NTop = None
self.NBottom = None
self.NRight = None
self.NLeft = None
self.NTopIndex = None
self.NBottomIndex = None
self.NRightIndex = None
self.NLeftIndex = None
self.nr = None
self.nc = None
self.random = None
self.neighbour = None
def index(self, nr, nc):
self.nr = nr
self.nc = nc
if self.nr < 0 or self.nc < 0 or self.nr > Rows-1 or self.nc > Columns-1:
return -1
return self.nr + self.nc * Columns
def neighbour_check(self):
# Get neighbour positions in Grid
self.NTopIndex = self.index(self.r, self.c - 1)
self.NBottomIndex = self.index(self.r, self.c + 1)
self.NRightIndex = self.index(self.r + 1, self.c)
self.NLeftIndex = self.index(self.r - 1, self.c)
# Look if they are truly neighbours and then append to neighbour list
if self.NTopIndex >= 0:
self.NTop = grid[self.NTopIndex]
if not self.NTop.visited:
self.neighbours.append(self.NTop)
if self.NBottomIndex >= 0:
self.NBottom = grid[self.NBottomIndex]
if not self.NBottom.visited:
self.neighbours.append(self.NBottom)
if self.NRightIndex >= 0:
self.NRight = grid[self.NRightIndex]
if not self.NRight.visited:
self.neighbours.append(self.NRight)
if self.NLeftIndex >= 0:
self.NLeft = grid[self.NLeftIndex]
if not self.NLeft.visited:
self.neighbours.append(self.NLeft)
# Choose random neighbour
if len(self.neighbours) > 0:
self.random = random.randint(0, len(self.neighbours) - 1)
self.neighbour = self.neighbours[self.random]
# Remove the wall between self and neighbour
if self.neighbour == self.NTop:
if self == grid[0]:
print('TOP')
self.sides[0] = False
self.NTop.sides[1] = False
elif self.neighbour == self.NBottom:
if self == grid[0]:
print('BOTTOM')
self.sides[1] = False
self.NBottom.sides[0] = False
elif self.neighbour == self.NLeft:
if self == grid[0]:
print('LEFT')
self.sides[2] = False
self.NLeft.sides[3] = False
elif self.neighbour == self.NRight:
if self == grid[0]:
print('RIGHT')
self.sides[3] = False
self.NRight.sides[2] = False
else:
print('SIDES ERROR')
return self.neighbours[self.random]
else:
return -1
def draw(self):
global DISPLAY, CellSize
# Top
if self.sides[0]:
pygame.draw.line(DISPLAY, (0, 0, 0), (self.x, self.y), (self.x + CellSize, self.y))
# Bottom
if self.sides[1]:
pygame.draw.line(DISPLAY, (0, 0, 0), (self.x, self.y + CellSize), (self.x + CellSize, self.y + CellSize))
# Left
if self.sides[2]:
pygame.draw.line(DISPLAY, (0, 0, 0), (self.x, self.y), (self.x, self.y + CellSize))
# Right
if self.sides[3]:
pygame.draw.line(DISPLAY, (0, 0, 0), (self.x + CellSize, self.y), (self.x + CellSize, self.y + CellSize))
class Maze:
def __init__(self):
global current
self.next = None
self.running = True
self.DISPLAY = None
self.display_running = True
def init_cells(self):
# Make grid and make cell 0 the begin of the algorithm
global current
for i in range(0, Columns):
for j in range(0, Rows):
cell = Cell(j, i)
grid.append(cell)
current = grid[0]
def init_maze(self):
global current, visited
print(grid[0].sides)
# Start Algorithm
while self.running:
# Check if the current cell is visited, if not make it visited and choose new neighbour
if not current.visited:
current.visited = True
visited.append(current)
self.next = current.neighbour_check()
if not self.next == -1:
# If it finds a neighbour then make it the new current cell
# self.next.visited = True
current = self.next
elif self.next == -1 and len(visited) > 0:
# If it doesn't then look trough the path and backtrack trough it to find a possible neighbour
if len(visited) > 1:
del visited[-1]
current = visited[-1]
# If the last cell of the visited list is Cell 0 then remove it
elif len(visited) <= 1:
del visited[-1]
elif len(visited) <= 0:
# Stop the Algorithm
self.running = False
print('Done')
def draw(self):
DISPLAY.fill((255, 255, 255))
# Get the maze made by the algorithm and draw it on the screen
for i in range(0, len(grid)):
grid[i].draw()
pygame.display.update()
while self.display_running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
self.display_running = False
maze = Maze()
maze.init_cells()
maze.init_maze()
maze.draw()
I put some print methods in it for debugging purposes.
And am still a beginner in programming, I know it could probably be way cleaner or that some naming of methods could be better.
What I want to happen is that in def init_maze the maze blueprints gets written out and that in def draw the blueprint gets drawn on the screen.