I have a script that I'm working on, in Pyglet.In this application I wanted to insert a console and I took as an example "examples/text_input.py" from Pyglet's guide. I modified it and tried to adapt it to my use. The result is this:
import pyglet, pyperclip
from pyglet.gl import *
from pyglet import clock
from collections import OrderedDict
key = pyglet.window.key
class MainGame(pyglet.window.Window):
#VariableFrame
WDisplay, HDisplay = 1024, 576
Fullscreen = False
FPS = 60
Title = "test"
ConsoleVar = False
#VariableConsole
showFPS = False
showPOSITION = False
showENTITY = False
showINFO = False
showHELP = False
helpPAGE = 0
GAMEMODE = 0
GODMODE = False
def __init__(self, width=WDisplay, height=HDisplay, caption=Title, fullscreen=Fullscreen, *args, **kwargs):
super().__init__(width, height, caption, fullscreen, *args, **kwargs)
platform = pyglet.window.get_platform()
display = platform.get_default_display()
screen = display.get_default_screen()
self.infoScreen = (screen.width, screen.height)
self.xDisplay = int(screen.width / 2 - self.width / 2)
self.yDisplay = int(screen.height / 2 - self.height / 2)
self.set_location(self.xDisplay, self.yDisplay)
self._load()
def _load(self):
self.mapInfo = OrderedDict()
pyglet.resource.add_font('graphics/fonts/pkmndp.ttf')
pyglet.resource.add_font('graphics/fonts/pkmndpb.ttf')
self.consoleClass = Console(self, '')
self.text_cursor = self.get_system_mouse_cursor('text')
self.focus = None
self.set_focus(self.consoleClass)
def update(self, dt):
if self.ConsoleVar:
self.consoleClass.update()
def on_draw(self):
pyglet.gl.glClearColor(1, 1, 1, 1)
self.clear()
if self.ConsoleVar:
for sprite in self.mapInfo :
self.mapInfo[sprite].draw()
def on_mouse_press(self, x, y, button, modifiers):
if self.ConsoleVar:
if self.focus:
self.focus.caret.on_mouse_press(x, y, button, modifiers)
def on_mouse_drag(self, x, y, dx, dy, buttons, modifiers):
if self.ConsoleVar:
if self.focus:
self.focus.caret.on_mouse_drag(x, y, dx, dy, buttons, modifiers)
def on_text(self, text):
if self.ConsoleVar:
if self.focus:
self.focus.caret.on_text(text)
def on_text_motion(self, motion):
if self.ConsoleVar:
if self.focus:
self.focus.caret.on_text_motion(motion)
def on_text_motion_select(self, motion):
if self.ConsoleVar:
if self.focus:
self.focus.caret.on_text_motion_select(motion)
def on_key_press(self, symbol, modifiers):
if symbol == key.F1 and modifiers & key.MOD_CTRL:
if self.ConsoleVar:
self.ConsoleVar = False
self.focus.document.text = ""
else:
self.ConsoleVar = True
self.focus.document.text = "/"
self.focus.caret.position = 1
if symbol == key.F2 and modifiers & key.MOD_CTRL:
if self.ConsoleVar:
self.ConsoleVar = False
self.focus.document.text = ""
else:
self.ConsoleVar = True
self.focus.caret.position = 0
if symbol == key.ENTER:
if self.ConsoleVar:
self.ConsoleVar = False
self.consoleClass.Enter()
if modifiers & key.MOD_CTRL and symbol == key.V:
if self.ConsoleVar:
self.consoleClass.Copy_Paste("paste")
if modifiers & key.MOD_CTRL and symbol == key.C:
if self.ConsoleVar:
self.consoleClass.Copy_Paste("copy")
def set_focus(self, focus):
if self.focus:
self.focus.caret.visible = False
self.focus.caret.mark = self.focus.caret.position = 1
self.focus = focus
if self.focus:
self.focus.caret.visible = True
self.focus.caret.mark = 1
self.focus.caret.position = len(self.focus.document.text)
class Console(object):
ComandConsole = []
def __init__(self, game, text):
self.game = game
self.groups = self.game.mapInfo
self.image = pyglet.resource.image("graphics/other/alpha.png")
self.alpha = self.image.get_region(x=32, y=64, width=32, height=32)
self.alpha.width = self.game.WDisplay
self.sprite = pyglet.sprite.Sprite(self.alpha)
self.sprite.opacity = 128
self.sprite.x, self.sprite.y = 0, 10
self.groups["bg"] = self.sprite
self.document = pyglet.text.document.UnformattedDocument(text)
self.document.set_style(0, len(self.document.text), dict(font_name = "Power Clear", font_size = 15, color=(255,255, 255, 255)))
font = self.document.get_font()
height = font.ascent - font.descent
self.layout = pyglet.text.layout.IncrementalTextLayout(self.document, self.game.WDisplay, height, multiline=False)
self.caret = pyglet.text.caret.Caret(self.layout)
self.groups["text"] = self.layout
self.layout.x = 20
self.layout.y = (self.alpha.height / 2 + self.sprite.y) - (self.layout.height / 2)
pad = 2
def hit_test(self, x, y):
return (0 < x - self.layout.x < self.layout.width and
0 < y - self.layout.y < self.layout.height)
def Copy_Paste(self, function):
if function == "copy":
pyperclip.copy('Hello world!')
if function == "paste":
paste = pyperclip.paste()
self.document.text = self.document.text + paste
self.game.focus.caret.position = self.game.focus.caret.mark = len(self.document.text)
def Enter(self):
if len(self.document.text) == 0:
pass
else:
if self.document.text[0] == "/":
if self.document.text == "/ciao":
print("ciao")
else:
print("errore comando")
else:
print(self.document.text)
self.document.text = ""
def update(self):
pass
if __name__ == "__main__":
window = MainGame()
pyglet.clock.schedule_interval(window.update, 1/window.FPS)
pyglet.app.run()
Now, I would like to be able to highlight some text in the console by pressing shift + left or right and, by pressing crtl + c, copy the selected text via pyperclip. How can I do?
Another question, always inherent. In the Console Class, I would like to create a rectangle above the console. In it, I would like to report some text on several lines (like a chat). The problem, more than anything else, is that I do not know how to write the text as soon as it reaches the limit of the rectangle.
Very last, now the console is called with crtl + F1 (and the symbol "/" is added) or with crtl + F2. However, I would like to activate it with the letters "U" and "T". The problem is that I do it, the console appears with the letters pressed to recall it. So how can I avoid it?
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()
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()
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.
The problem is next, I have falling circles and I need them to be deleted if they will overlap with the player. I have tried to create a bunch of methods to get coordinates of the circles and the rectangle however when i try checking if they overlap i get an error.
TypeError: unorderable types: method() > method()
Here is the code:
# Colour
# Created by Niktia Kotter
#!/usr/bin/env python
import pygame, sys, random, time
from pygame.locals import*
# set up pygame
pygame.init()
FPS=60
fpsclock = pygame.time.Clock()
# colours R G B
WHITE = (255, 255, 255)
BLACK = (0 , 0 , 0 )
RED = (237, 28 , 36 )
# set up screen
SCREEN_W = 800
SCREEN_H = 480
SCREEN = pygame.display.set_mode((SCREEN_W,SCREEN_H),0,32)
snapMultX = SCREEN_W / 5
snapMultY = SCREEN_H / 5
basicFont = pygame.font.SysFont(None, 32)
# set up functions
def isPointInsideRect(Cx, Cy, rectX, rectY, rectW, rectH ):
if ((Cx > rectX) and \
(Cx < rectY) and \
(Cy > rectW) and \
(Cy < rectH)):
return True
else:
return False
"""
def doRectsOverlap(rect1, rect2):
for a,b in [(rect1, rect2), (rect2, rect1)]:
# check if a's corners are inside b
if ((isPointInsideRect(a.left, a.top, b)) or
(isPointInsideRect(a.left, a.bottom, b)) or
(isPointInsideRect(a.right, a.top, b)) or
(isPointInsideRect(a.right, a.bottom, b))):
return True
return False
"""
# set up calsses
class Actor:
def __init__ (self):
self._x = snapMultX*2
self._y = SCREEN_H - snapMultX/5 -(snapMultX/2)
self._w = snapMultX
self._h = snapMultX/2
self._colour = WHITE
self._Rect = pygame.Rect(self._x, self._y, self._w, self._h)
def moveRight(self):
self._x += snapMultX
def moveLeft(self):
self._x -= snapMultX
def draw(self):
pygame.draw.rect(SCREEN, self._colour, (self._x, self._y, self._w, self._h))
return
def rectX(self):
return self._x
def rectY(self):
return self._y
def rectW(self):
return self._w
def rectH(self):
return self._h
class Enemy:
def __init__ (self, location):
self._x = snapMultX*location+snapMultX/2
self._y = 0
self._r = snapMultX/10
self._colour = WHITE
def move(self, dy):
self._y += dy
def draw(self):
pygame.draw.circle(SCREEN, self._colour, (int(self._x),int(self._y)), int(self._r), 0)
return
def GetCircleX(self):
return self._x
def GetCircleY(self):
return self._y
class Capture(object):
def __init__(self):
self.caption = pygame.display.set_caption('Space Invaders')
self.screen = SCREEN
self.startGame = True
self.gameOver = False
self.enemyCount = 0
self.timer = 50
self.score = 0
def main(self):
clock = pygame.time.Clock()
enemy =[]
player = Actor()
while True:
if self.startGame:
SCREEN.fill(BLACK)
pygame.draw.polygon(SCREEN,WHITE, [(snapMultX*1-snapMultX/5*2,0), (snapMultX*0+snapMultX/5*2,0), (snapMultX*0+snapMultX/2,snapMultY/4)])
pygame.draw.polygon(SCREEN,WHITE, [(snapMultX*2-snapMultX/5*2,0), (snapMultX*1+snapMultX/5*2,0), (snapMultX*1+snapMultX/2,snapMultY/4)])
pygame.draw.polygon(SCREEN,WHITE, [(snapMultX*3-snapMultX/5*2,0), (snapMultX*2+snapMultX/5*2,0), (snapMultX*2+snapMultX/2,snapMultY/4)])
pygame.draw.polygon(SCREEN,WHITE, [(snapMultX*4-snapMultX/5*2,0), (snapMultX*3+snapMultX/5*2,0), (snapMultX*3+snapMultX/2,snapMultY/4)])
pygame.draw.polygon(SCREEN,WHITE, [(snapMultX*5-snapMultX/5*2,0), (snapMultX*4+snapMultX/5*2,0), (snapMultX*4+snapMultX/2,snapMultY/4)])
player.draw()
# enemy move/spawn timer
self.timer -= 1
# enemy spawner
if self.timer <= 0:
num = random.randint(0, 5)
if num == 0:
print (0)
enemy.append(Enemy(0))
if num == 1:
print (1)
enemy.append(Enemy(1))
if num == 2:
print (2)
enemy.append(Enemy(2))
if num == 3:
print (3)
enemy.append(Enemy(3))
if num == 4:
print (4)
enemy.append(Enemy(4))
# player mover
for event in pygame.event.get():
if player._x != snapMultX*4 and (event.type == KEYDOWN) and (event.key == K_d):
player.moveRight()
if player._x != 0 and(event.type == KEYDOWN) and (event.key == K_a):
player.moveLeft()
if event.type == QUIT:
pygame.quit()
sys.exit()
# enemy logic
if self.timer <= 0:
for e in enemy:
e.move(snapMultY)
if isPointInsideRect(e.GetCircleX, e.GetCircleY, player.rectX, player.rectY, player.rectW, player.rectH):
self.score += 1
enemy.remove(e)
if e._y > snapMultY*5:
enemy.remove(e)
# reste timer
self.timer = 50
for e in enemy:
e.draw()
# score
self.myScore = "Score = " + str(self.score)
text = basicFont.render(self.myScore, True, RED, WHITE)
textRect = text.get_rect()
textRect.centerx = SCREEN.get_rect().centerx
textRect.centery = SCREEN.get_rect().centery
SCREEN.blit(text, textRect)
pygame.display.update()
fpsclock.tick(FPS)
if __name__ == '__main__':
game = Capture()
game.main()
The cause of your error is actually a typo and the joys of Python Duck Typing. The key to debugging is understanding what the error means.
Your error "TypeError: unorderable types: method() > method()". What does this mean?
Obviously you have a type error, but what does that really mean. It means that Python is trying to complete an operation that has certain requirements. In this case in has do to with unorderable types - we are trying to do a comparison on two things that don't have an orderable property so that they can't be compared in that way. The next portion says "method() > method()". That means we are attempting to compare that one method is greater than another. That probably isn't what is intended.
So now we have to look at those comparisons in our ifs. Lets look at isPointInsideRect.
def isPointInsideRect(Cx, Cy, rectX, rectY, rectW, rectH ):
if ((Cx > rectX) and (Cx < rectY) and (Cy > rectW) and (Cy < rectH)):
return True
else:
return False
Here we are doing a whole bunch of comparisons on six values. Lets look at where this method gets called? This function gets called in one uncommented-out line (Line 175).
if isPointInsideRect(e.GetCircleX, e.GetCircleY, player.rectX, player.rectY, player.rectW, player.rectH):
Do you see the issue here? Each of those values that you are passing into the function aren't values, they are method definitions. Hence, everytime isPointInsideRect is doing those comparisons, they are comparing one method to another. And that isn't a valid comparison.
Trying changing line 175 to:
if isPointInsideRect(e.GetCircleX(), e.GetCircleY(), player.rectX(), player.rectY(), player.rectW(), player.rectH()):