I have a maze game that comprises of 3 different class, which includes 2 maze solving algorithms and a class for players to move around with the up, down, left and right key. So the way to toggle between the classes is to use a tab key. But however, when i reach the class where users can manually control the sprite, there will always be a random black arrow that looks like its going through spasm in the middle of my window. Even though i can manage to control the orange sprite, but that black arrow is still there. Is there anyway that i can remove it? I tried using hideturtle to hide the arrow, but to no avail.
I highly suspect that it was due to this part of my code that resulted in the appearance of the black arrowhead. But i wasn't able to find a replacement for that.
while True:
ManualMovements()
This is how the black sprite looks like right now:
My current code:
from turtle import * # import the turtle library
# define the tile_size and cursor_size for usage later on
TILE_SIZE = 24
CURSOR_SIZE = 20
screen = Screen() # instantiate the Screen class from turtle
screen.setup(700, 700) # determine the size of the turtle pop out window
class Wall(Turtle): # create Wall class to plot out the walls
def __init__(self):
super().__init__() # inherit from Turtle(parent class)
self.hideturtle() # hide the cursor
self.shape('square') # define the shape of the object we wanna draw out
self.shapesize(TILE_SIZE / CURSOR_SIZE) # define the size of the square
self.pencolor('black') # define the color that we are going to plot the grids out
self.penup() # to prevent the pen from leaving a trace
self.speed('fastest') # get the fastest speed
class Path(Turtle): # create Path class to plot out the path
def __init__(self):
super().__init__() # inherit from Turtle(parent class)
self.hideturtle() # hide the cursor
self.shape('square') # define the shape of the object we wanna draw out
self.shapesize(TILE_SIZE / CURSOR_SIZE) # define the size of the square
self.pencolor('white') # define the color that we are going to plot the grids out
self.penup() # to prevent the pen from leaving a trace
self.speed('fastest') # get the fastest speed
class Sprite(Turtle): # create Sprite class to define the turtle and its characteristics
def __init__(self):
super().__init__() # inherit from Turtle(parent class)
self.shape('turtle') # define the shape of the object we wanna draw out
self.shapesize((TILE_SIZE / CURSOR_SIZE)-0.4) # define the size of the square
self.color('orange') # define the color that we are going to plot the turtle
self.penup() # to prevent the pen from leaving a trace
self.speed('slowest') # set speed to slowest to observe the sprite movement
class ManualMovements(Sprite): # create ManualMovement class to let the user manually control the sprite
def __init__(self):
super().__init__()
self.moves = 0
self.hideturtle()
self.screen.onkeypress(self.go_up, "Up")
self.screen.onkeypress(self.go_down, "Down")
self.screen.onkeypress(self.go_left, "Left")
self.screen.onkeypress(self.go_right, "Right")
def go_up(self):
xcor = sprite.xcor()
ycor = sprite.ycor()
if (xcor, ycor + TILE_SIZE) not in walls:
sprite.setheading(90)
sprite.goto(xcor, ycor + TILE_SIZE)
def go_down(self):
xcor = sprite.xcor()
ycor = sprite.ycor()
if (xcor, ycor - TILE_SIZE) not in walls:
sprite.setheading(270)
sprite.goto(xcor, ycor - TILE_SIZE)
def go_left(self):
xcor = sprite.xcor()
ycor = sprite.ycor()
if (xcor - TILE_SIZE, ycor) not in walls:
sprite.setheading(180)
sprite.goto(xcor - TILE_SIZE, ycor)
def go_right(self):
xcor = sprite.xcor()
ycor = sprite.ycor()
if (xcor + TILE_SIZE, ycor) not in walls:
sprite.setheading(0)
sprite.goto(xcor + TILE_SIZE, ycor)
def setup_maze(level): # create a setup_maze function so that we can plot out the map in turtle
# declare maze_height and maze_width first as the limits for the entire maze
maze_height, maze_width = len(level), len(level[0])
# get the center point for each maze
center_horizontal_point = (maze_width + 1) / 2
center_vertical_point = (maze_height + 1) / 2
for y in range(maze_height): # for loop to limit the entire maze
for x in range(maze_width):
character = level[y][x] # get the character at each x,y coordinate
# calculate the screen x, y coordinates
screen_x = ((x - maze_width) * TILE_SIZE) + (center_horizontal_point * TILE_SIZE)
screen_y = ((maze_height - y) * TILE_SIZE) - (center_vertical_point * TILE_SIZE)
if character == "X":
maze.fillcolor('grey')
maze.goto(screen_x, screen_y)
maze.stamp()
walls.append((screen_x, screen_y)) # add coordinates for the wall to the list
else:
maze.fillcolor('white')
maze.goto(screen_x, screen_y)
maze.stamp()
paths.append((screen_x, screen_y)) # add coordinates for the path to the list
if character == "e":
maze.fillcolor(['white', 'red'][character == 'e'])
maze.goto(screen_x, screen_y) # proceed on to the coordinates on turtle
maze.stamp() # stamp out the boxes
finish.append((screen_x, screen_y)) # add coordinates for the endpoint to the list
if character == 's': # if statement to determine if the character is s
maze.fillcolor('green')
maze.goto(screen_x, screen_y)
maze.stamp() # stamp out the boxes
start.append((screen_x, screen_y)) # add coordinates for the startpoint to the list
sprite.goto(screen_x, screen_y) # move the sprite to the location where it is supposed to start
def endProgram(): # exit the entire program upon clicking anywhere in the turtle window
screen.exitonclick()
grid = [] # create a grid list to store the labels while reading from the txt file
walls = [] # create walls coordinate list
start = []
finish = [] # enable the finish array
paths = []
maze = Wall() # enable the Wall class
sprite = Sprite() # enable the Sprite class
path = Path()
with open("map02.txt") as file: # open the txt file and read contents and append it to maze
for line in file:
grid.append(line.strip())
setup_maze(grid) # call the setup maze function
start_x, start_y = (start[0])[0], (start[0])[1]
sprite.seth(0)
sprite.goto(start_x, start_y)
while True:
ManualMovements()
screen.listen() # we need this in order to allow turtle to detect what key we are pressing and respond to it
screen.mainloop()
A sample txt file map:
XXXXXXXXXXXXXXXXXXXX
Xe.................X
XXXXXXX...X..XXXXX.X
XXXXXX....X.....XXXX
XXX.......X...X.XXXX
XXXXXX....X.....XXXX
X.........X...XXXXXX
X.XXXXXX..X...XXXXXX
X.X.......X..XXXXXXX
X.X...XXXX.........X
X.XXXXXsXX..XXXXXXXX
X..............XXXXX
XXXXXXXXXXXXXXXXXXXX
EDIT: Some edits have been made. Please relook again. In order to execute the code, you have to press tab once before pressing the up, down, left, right buttons from my side. I also have removed the 2 classes to prevent confusion and also since i pinpointed that this part of the code is where my error should come from. The current code above does replicate the same error too.
The problem is that your ManualMovements class is wrong-headed. Rather than a bizarre helper class, it should be a subclass of Sprite. (Akin to a fully automated Sprite subclass.) I've reworked your code accordingly below as well as made other fixes and optimizations -- pick and choose as you see fit:
from turtle import Screen, Turtle
# define some global constants for use later
TILE_SIZE = 24
CURSOR_SIZE = 20
class Wall(Turtle):
''' class to plot out walls '''
def __init__(self):
super().__init__(shape='square') # inherit from parent class
self.hideturtle()
self.shapesize(TILE_SIZE / CURSOR_SIZE) # define the size of the square
self.penup() # prevent the pen from leaving a trace
self.speed('fastest')
class Path(Wall):
''' class to plot out the path '''
def __init__(self):
super().__init__() # inherit from parent class
self.pencolor('white') # define the color that we are going to plot the grids out
class Sprite(Turtle):
''' class to define turtle sprite and its characteristics '''
def __init__(self):
super().__init__(shape='turtle') # inherit from parent class
self.shapesize((TILE_SIZE / CURSOR_SIZE) - 0.4) # define the size of the square
self.color('orange') # color that we are going to plot the turtle
self.penup() # prevent the pen from leaving a trace
self.speed('slowest') # set speed to slowest to observe the sprite movement
class ManualSprite(Sprite):
''' class to let the user manually control the sprite '''
def __init__(self):
super().__init__()
screen.onkeypress(self.go_up, 'Up')
screen.onkeypress(self.go_down, 'Down')
screen.onkeypress(self.go_left, 'Left')
screen.onkeypress(self.go_right, 'Right')
def go_up(self):
screen.onkeypress(None, 'Up') # disable handler inside handler
xcor = int(self.xcor())
ycor = int(self.ycor())
if (xcor, ycor + TILE_SIZE) not in walls:
self.setheading(90)
self.sety(ycor + TILE_SIZE)
screen.onkeypress(self.go_up, 'Up') # reenable handler on exit
def go_down(self):
screen.onkeypress(None, 'Down')
xcor = int(self.xcor())
ycor = int(self.ycor())
if (xcor, ycor - TILE_SIZE) not in walls:
self.setheading(270)
self.sety(ycor - TILE_SIZE)
screen.onkeypress(self.go_down, 'Down')
def go_left(self):
screen.onkeypress(None, 'Left')
xcor = int(self.xcor())
ycor = int(self.ycor())
if (xcor - TILE_SIZE, ycor) not in walls:
self.setheading(180)
self.setx(xcor - TILE_SIZE)
screen.onkeypress(self.go_left, 'Left')
def go_right(self):
screen.onkeypress(None, 'Right')
xcor = int(self.xcor())
ycor = int(self.ycor())
if (xcor + TILE_SIZE, ycor) not in walls:
self.setheading(0)
self.setx(xcor + TILE_SIZE)
screen.onkeypress(self.go_right, 'Right')
def setup_maze(level):
''' plot out the map as a maze in turtle '''
# declare the limits for the entire maze
maze_height, maze_width = len(level), len(level[0])
# get the center point for each maze
center_horizontal_point = (maze_width + 1) / 2
center_vertical_point = (maze_height + 1) / 2
start = finish = None
for y in range(maze_height):
for x in range(maze_width):
character = level[y][x] # get the character at each coordinate
# calculate the screen x, y coordinates
screen_x = int((x - maze_width) * TILE_SIZE + center_horizontal_point * TILE_SIZE)
screen_y = int((maze_height - y) * TILE_SIZE - center_vertical_point * TILE_SIZE)
maze.goto(screen_x, screen_y)
if character == 'X':
maze.fillcolor('grey')
walls.append((screen_x, screen_y)) # add coordinates for the wall
else:
paths.append((screen_x, screen_y)) # add coordinates for the path
if character == 'e':
maze.fillcolor('red')
finish = (screen_x, screen_y)
elif character == 's':
maze.fillcolor('green')
start = (screen_x, screen_y)
else:
maze.fillcolor('white')
maze.stamp()
return start, finish
grid = [] # create a grid list to store the labels while reading from the txt file
with open("map02.txt") as file: # open the txt file and read contents and append it to maze
for line in file:
grid.append(line.strip())
screen = Screen() # extract the Screen class from turtle
screen.setup(700, 700) # set the size of the turtle window
sprite = ManualSprite() # instantiate a Sprite instance
walls = [] # walls coordinate list
paths = []
maze = Wall() # instantiate the Wall class
path = Path()
start, finish = setup_maze(grid)
sprite.setheading(0)
sprite.goto(start) # move the sprite to the start location
screen.listen() # allow turtle to detect key press and respond to it
screen.mainloop()
I've tossed comments that simply echo the obvious. Also, your logic didn't take into account the imprecision of floating point coordinates which makes them difficult to compare -- I've converted those comparisons to int.
Related
so currently i'm trying to plot out a block maze by reading from a .txt file and then displaying it in Python's Turtle Library. Currently, my code is only able to draw out the boxes, but not the grid lines surrounding the boxes. Is there anyway to deal with this problem, cuze i tried to see the docs and they only suggested turtle.Turtle.fillcolor, which doesnt really seems right.
Here's my current code:
# import the necessary library
import turtle
# read the .txt file here!
with open("map01.txt") as f:
content = f.readlines()
content = [x.strip() for x in content]
# create the map here!
window = turtle.Screen()
window.bgcolor("white") # set the background as white(check if this is default)
window.title("PIZZA RUNNERS") # create the titlebar
window.setup(700,700)
# create pen
class Pen(turtle.Turtle):
def __init__(self):
turtle.Turtle.__init__(self)
self.shape("square")
self.color('grey')
self.penup()
self.speed(0)
# create maze_list
maze = []
# add the maze to maze
maze.append(content)
# create conversion from the list to the map in turtle
def setup_maze(level):
for y in range(len(level)):
for x in range(len(level[y])):
# get the character at each x,y coordinate
character = level[y][x]
# calculate the screen x, y coordinates
screen_x = -288 + (x * 24)
screen_y = 288 - (y * 24)
# check if it is a wall
if character == "X":
pen.goto(screen_x, screen_y)
pen.stamp()
# create class instances
pen = Pen()
# set up the maze
setup_maze(maze[0])
# main game loop
while True:
pass
And this is how the current text file i am reading from looks like:
XXXXXXXXXXXX
X.........eX
X.XXX.XXX..X
X.XsX.X.XX.X
X.X......X.X
X.XXXXXXXX.X
X..........X
XXXXXXXXXXXX
The 's' and 'e' are supposed to represent the starting point and the ending point, which is not implemented yet, so it can be ignored. The dots represent the path, and the X represents walls. The current map(or txt) dimension is 8 rows by 12 columns.
Right now my output looks like this:
I wanted it to look something like this(referring to the addition of grids, not the same pattern maze):
Assuming what you desire is:
Then we need to resize the square cursor from its default size of 20 to your tile size of 24:
from turtle import Screen, Turtle
TILE_SIZE = 24
CURSOR_SIZE = 20
class Pen(Turtle):
def __init__(self):
super().__init__()
self.shape('square')
self.shapesize(TILE_SIZE / CURSOR_SIZE)
self.color('grey')
self.penup()
self.speed('fastest')
def setup_maze(level):
''' Conversion from the list to the map in turtle. '''
maze_height, maze_width = len(level), len(level[0])
for y in range(maze_height):
for x in range(maze_width):
# get the character at each x,y coordinate
character = level[y][x]
# check if it is a wall
if character == 'X':
# calculate the screen x, y coordinates
screen_x = (x - maze_width) * TILE_SIZE
screen_y = (maze_width - y) * TILE_SIZE
pen.goto(screen_x, screen_y)
pen.stamp()
screen = Screen()
screen.setup(700, 700)
screen.title("PIZZA RUNNERS")
maze = []
with open("map01.txt") as file:
for line in file:
maze.append(line.strip())
pen = Pen()
setup_maze(maze)
screen.mainloop()
If you're looking for something more like:
Then change the line:
self.color('grey')
in the code above to:
self.color('black', 'grey')
Finally, if you desire:
Then we need to make a couple of small changes to the code above:
class Pen(Turtle):
def __init__(self):
super().__init__()
self.shape('square')
self.shapesize(TILE_SIZE / CURSOR_SIZE)
self.pencolor('black')
self.penup()
self.speed('fastest')
def setup_maze(level):
''' Conversion from the list to the map in turtle. '''
maze_height, maze_width = len(level), len(level[0])
for y in range(maze_height):
for x in range(maze_width):
# get the character at each x,y coordinate
character = level[y][x]
# check if it is a wall or a path
pen.fillcolor(['white', 'grey'][character == 'X'])
# calculate the screen x, y coordinates
screen_x = (x - maze_width) * TILE_SIZE
screen_y = (maze_width - y) * TILE_SIZE
pen.goto(screen_x, screen_y)
pen.stamp()
I am new to Pygame, and doing a assigned homework. I tried to make an program called Pong by python3. The ball was moving correctly, but after I write something new in the program, the ball just stopped at the initial point. I already check many times of my code, but I can't find what's wrong with it.
Here is my code below:
# Pong Version 2
# Display the ball and both paddles, with the ball bouncing from the window edges.
# The ball bounce off the paddles. It go through the back of paddles.
# The paddles do not move, but score is updated.
# The game ends when a score is 11 or until the player closes the window.
import pygame, random
def main():
# initialize all pygame modules (some need initialization)
pygame.init()
# create a pygame display window
pygame.display.set_mode((1000, 800))
# set the title of the display window
pygame.display.set_caption('Pong')
# get the display surface
w_surface = pygame.display.get_surface()
# create a game object
game = Game(w_surface)
#init text
pygame.font.init()
# start the main game loop by calling the play method on the game object
game.play()
# quit pygame and clean up the pygame window
pygame.quit()
class Game:
# An object in this class represents a complete game.
def __init__(self, surface):
# Initialize a Game.
# - self is the Game to initialize
# - surface is the display window surface object
# === objects that are part of every game that we will discuss
self.surface = surface
self.bg_color = pygame.Color('black')
self.FPS = 60
self.game_Clock = pygame.time.Clock()
self.close_clicked = False
self.continue_game = True
self.num_board1 = '0'
self.num_board2 = '0'
# === game specific objects
#ball elements
#(ball_color,ball_radius,ball_center,ball_velocity,surface)
self.ball = Ball('white', 10, [500, 400], [10,20], self.surface)
#rectangle elements
#(rect_left_top,rect_width_height,rect_surface,rect_color)
self.paddle1 = Rect((150,350),(10,100),self.surface,'white')
self.paddle2 = Rect((840,350),(10,100),self.surface,'white')
#board elements
#(name,size,content,color,center,screen)
#board size is (57,104)
self.board1 = Board("",150,self.num_board1,(100,100,100),(10,10),self.surface)
self.board2 = Board("",150,self.num_board2,(100,100,100),(933,10),self.surface)
def play(self):
# Play the game until the player presses the close box.
# - self is the Game that should be continued or not.
while not self.close_clicked: # until player clicks close box
# play frame
self.handle_events()
self.draw()
if self.continue_game:
self.update()
self.decide_continue()
self.game_Clock.tick(self.FPS) # run at most with FPS Frames Per Second
def handle_events(self):
# Handle each user event by changing the game state appropriately.
# - self is the Game whose events will be handled
events = pygame.event.get()
for event in events:
if event.type == pygame.QUIT:
self.close_clicked = True
def draw(self):
# Draw all game objects.
# - self is the Game to draw
self.surface.fill(self.bg_color) # clear the display surface first
# Draw game elements ball
self.ball.draw()
# Draw game elements paddles
self.paddle1.draw()
self.paddle2.draw()
# Draw game elements boards
self.board1.draw()
self.board2.draw()
pygame.display.update() # make the updated surface appear on the display
def update(self):
# Update the game objects.
# - self is the Game to update
self.ball.move()
def decide_continue(self):
# Check and remember if the game should continue
# - self is the Game to check
pass
if self.num_board1 or self.num_board2 == '11':
self.continue_game = False
class Ball:
# An object in this class represents a ball that moves
def __init__(self, ball_color, ball_radius, ball_center, ball_velocity, surface):
# Initialize a ball.
# - self is the ball to initialize
# - color is the pygame.Color of the ball
# - center is a list containing the x and y int
# coords of the center of the ball
# - radius is the int pixel radius of the ball
# - velocity is a list containing the x and y components
# - surface is the window's pygame.Surface object
self.color = pygame.Color(ball_color)
self.radius = ball_radius
self.center = ball_center
self.velocity = ball_velocity
self.surface = surface
def move(self):
# Change the location of the ball by adding the corresponding
# speed values to the x and y coordinate of its center
# - self is the ball
size = self.surface.get_size() # size is a tuple (width,height)
for index in range(0,2):
self.center[index] = self.center[index] + self.velocity[index]
if self.center[index] < self.radius: # left or top
self.velocity[index] = -self.velocity[index] # bounce the ball
if self.center[index]+ self.radius > size[index]:# right of bottom
self.velocity[index] = -self.velocity[index] # bounce the ball
def draw(self):
# Draw the ball on the surface
# - self is the ball
pygame.draw.circle(self.surface, self.color, self.center, self.radius)
class Rect:
def __init__(self,rect_left_top,rect_width_height,rect_surface,rect_color):
#set elements
# - rect_left_top is the distance from edge
# - rect_width_height is width and height of the rectangle
# - rect_surface is the surface of rectangle
# - rect_color is color of the rectangle
self.left_top = rect_left_top
self.width_height = rect_width_height
self.surface = rect_surface
self.color = pygame.Color(rect_color)
self.rect = (self.left_top,self.width_height)
def draw(self):
# draw the rectangle
pygame.draw.rect(self.surface,self.color,self.rect)
class Board:
def __init__(self,name,size,content,color,text_left_right,surface):
# - name is the typeface of the text
# - size is the size of the text
# - content is the content fo the text
# - color is the color of text, it looks like (x,x,x), which is combined by three basic color)
# - text_left_right is a the left and right distance from edge
# - surface is a the display.set_mode, used to blit text
self.name = name
self.size = size
self.content = content
self.color = color
self.text_left_right = text_left_right
self.surface = surface
def draw(self):
#to show the text
font = pygame.font.SysFont(self.name,self.size)
text = font.render(self.content,True,self.color)
self.surface.blit(text,self.text_left_right)
main()
The problem with decide_continue method.
When I remove call of decide_continue from play method ball start moving:
def play(self):
# Play the game until the player presses the close box.
# - self is the Game that should be continued or not.
while not self.close_clicked: # until player clicks close box
# play frame
self.handle_events()
self.draw()
if self.continue_game:
self.update()
self.game_Clock.tick(self.FPS) # run at most with FPS Frames Per Second
So the problem with decide_continue method. You should review it.
Going by the test done by Yurii (see other answer), since you didn't mention which change you had made before the program didn't work properly anymore.
decide_continue(self) has the following if-clause:
if self.num_board1 or self.num_board2 == '11':
This means it evaluates whether self.num_board1 is equivalent to True (i.e., not False, 0, empty string and the like), which is probably always the case, or it compares self.num_board2 to the string '11'.
Important note: the string '0', the initial value for the boards, does not evaluate to False: it's not an empty string, nor an integer 0.
Because of the first condition, this if-statement will practically always evaluate in being true.
You probably want:
if self.num_board1 == '11' or self.num_board2 == '11':
or something like that. You should also consider whether you want a '11' string, or that this should be a number (integer) instead, given that you call the variable num_board.
Further, since no manipulations with num_board1/2 appear to be done, it's value will likely never change from the initial value '0', in which case it'll, at this moment, never be equal to '11'.
The Point of the game is to make all the circles disappear when they Collide but for some reason some circles aren't disappearing? - Thank you for your help in advance!
import turtle
import random
import math
import time
# Setting up the Screen
ms = turtle.Screen()
ms.bgcolor("red")
ms.title("Space Rocket Minigame #Rafa94")
# Using class functions/Methods
# subclass
class Border(turtle.Turtle):
def __init__(self): # class constrcutor
turtle.Turtle.__init__(self) # adding our Objects attributes all starting with "self"
self.penup()
self.hideturtle()
self.speed(0)
self.color("silver")
self.pensize(5)
def draw_border(self):
self.penup()# getting our pen to start drawing
self.goto(-300, -300)
self.pendown()
self.goto(-300, 300)
self.goto(300, 300)
self.goto(300, -300)
self.goto(-300, -300)
class Player(turtle.Turtle): # since it got inherited this class becomes a Superclass
def __init__(self): # self is our only argument here but it will have multiple attributes
turtle.Turtle.__init__(self) # since we are using the Turtle module, we are able to use it's built in functions
self.penup()# our attributes
self.speed(0)
self.shape("triangle")
self.color("black")
self.velocity = 0.1
def move(self):
self.forward(self.velocity)
# Border Checking
if self.xcor() > 290 or self.xcor() < -290: # Left side is -290 Right side is 290 we also want the coordinates x and y to be below 300 to not go over our border
self.left(60)
if self.ycor() > 290 or self.ycor() < -290:
self.left(60)
def turnleft(self):
self.left(30)
def turnright(self):
self.right(30)
def increasespeed(self):
self.velocity += 1
class Goal(turtle.Turtle): # Sub Class
def __init__(self):
# since we are using the Turtle module we are able to use it's built in functions
turtle.Turtle.__init__(self)
self.penup() # our attributes
self.speed(0)
self.shape("circle")
self.color("green")
self.velocity = 3 #xcor #ycor
self.goto(random.randint(-250, 250), random.randint(-250, 250)) # we are making our turtle "go to" X & Y coordinates by -250 and 250 only randomly. We also have our random module here aswell
self.setheading(random.randint(0, 360)) # setting the heading to see in which direction i want it to go
def jump(self): # Jump = Collidee
self.goto(random.randint(-250, 250), random.randint(-250, 250)) # "jump" stands for Collidee so if the circle "jumps" with player it will move to random postion by 250 and -25
self.setheading(random.randint(0, 360)) # from where it collidee's it goes 360 moves location 360 Right
def move(self): # we copyed the same method cause it will be doing the same movements as the player we want it to go "forward" with our set "speed" & also check for our borders we set
self.forward(self.velocity)
# Border Checking
if self.xcor() > 290 or self.xcor() < -290: # Left side is -290 Right side is 290 we also want the coordinates x and y to be below 300 to not go over our border
self.left(60)
if self.ycor() > 290 or self.ycor() < -290:
self.left(60)
# Collision checking function/Method
# Uses the Pythgorean Theorem to measure the distance between two objects
def isCollision(t1, t2): # t1 = turtle1 t2 = turtle also when a function starts with "is" isCollision most likely it will be a Boolean of True or False
a = t1.xcor()-t2.xcor() # xcor = Right -xcor = Left/ when they collide the xcor is 0
b = t1.ycor()-t2.ycor() # ycor = Right -ycor = Left/ when they collide the ycor is 0
distance = math.sqrt((a ** 2) + (b ** 2))
if distance < 30:
return True
else:
return False
# Create class instances
player = Player() # after creating a class must make instances to call it in other words make an Object of the class
border = Border() # sub class
#goal = Goal() #sub class
# Draw our border
border.draw_border()
#create multiple goals
goals = [] # Creating a list of goals
for count in range(6): # We are making the code repeat 6 times
goals.append(Goal()) # each time the code runs it puts a goal the end 6 times
# Set keyboard bindings
ms.listen()
ms.onkey(player.turnleft, "Left")
ms.onkey(player.turnright, "Right")
ms.onkey(player.increasespeed, "Up")
# speed game up
ms.tracer(0.1)
# main loop
while True:
ms.update()
player.move() # these two are class methods
#goal.move() # the reason we copyed like we said is cause it's gunna have the exact same movements as our player!
# we want the goal to be True to in our while loop in order for the code to be excuted
for goal in goals:
# Basically saying If there is a collision between the player and goal we the want the goal to "jump" / Function in our while True loop
goal.move()
if isCollision(player, goal):
goal.jump() # baiscally saying if the goal collide's move or "jump" to other location
time.sleep(0.005)
As far as I can tell, your circles (goals) disappear and reappear elsewhere as you designed them to do. One possibiliy is that since you move the circles to a random location, that location can be close to where they disappeared from, making it appear that nothing happened.
Generally, your code is a mess. Below is my rewrite of it to bring some structure and style to it. As well as take more advantage of what turtle offers:
from turtle import Screen, Turtle
from random import randint
WIDTH, HEIGHT = 600, 600
CURSOR_SIZE = 20
class Border(Turtle):
def __init__(self): # class initializer
super().__init__(visible=False)
self.penup()
self.color("silver")
self.pensize(5)
def draw_border(self):
self.goto(-WIDTH/2, -HEIGHT/2)
self.pendown()
for _ in range(2):
self.forward(WIDTH)
self.left(90)
self.forward(HEIGHT)
self.left(90)
class Player(Turtle):
def __init__(self):
super().__init__(shape="triangle")
self.color("black")
self.penup()
self.velocity = 0.1
def move(self):
self.forward(self.velocity)
if not (CURSOR_SIZE - WIDTH/2 < self.xcor() < WIDTH/2 - CURSOR_SIZE and CURSOR_SIZE - HEIGHT/2 < self.ycor() < HEIGHT/2 - CURSOR_SIZE):
self.undo() # undo forward motion
self.left(60)
self.forward(self.velocity) # redo forward motion in new heading
def turn_left(self):
self.left(30)
def turn_right(self):
self.right(30)
def increase_speed(self):
self.velocity += 1
class Goal(Turtle):
def __init__(self):
super().__init__(shape="circle")
self.color("green")
self.penup()
self.velocity = 3
self.jump()
def jump(self):
while self.distance(player) < CURSOR_SIZE * 10: # make sure we move far away from player
self.goto(randint(CURSOR_SIZE - WIDTH/2, WIDTH/2 - CURSOR_SIZE), randint(CURSOR_SIZE - HEIGHT/2, HEIGHT/2 - CURSOR_SIZE))
self.setheading(randint(0, 360))
def move(self):
self.forward(self.velocity)
if not (CURSOR_SIZE - WIDTH/2 < self.xcor() < WIDTH/2 - CURSOR_SIZE and CURSOR_SIZE - HEIGHT/2 < self.ycor() < HEIGHT/2 - CURSOR_SIZE):
self.undo() # undo forward motion
self.left(60)
self.forward(self.velocity) # redo forward motion in new heading
def isCollision(t1, t2):
return t1.distance(t2) < CURSOR_SIZE
def move():
player.move()
for goal in goals:
goal.move()
if isCollision(player, goal):
goal.jump()
screen.update()
screen.ontimer(move, 10)
# Setting up the Screen
screen = Screen()
screen.bgcolor("red")
screen.title("Space Rocket Minigame #cdlane")
screen.tracer(False)
# Create class instances
Border().draw_border()
player = Player()
# Create multiple goals
goals = [Goal() for _ in range(6)]
# Set keyboard bindings
screen.onkey(player.turn_left, "Left")
screen.onkey(player.turn_right, "Right")
screen.onkey(player.increase_speed, "Up")
screen.listen()
move()
screen.mainloop()
For my homework I have to draw a rectangle frame and the turtle should be a dot and moving to a random destination.
When I press the space bar(which starts and stops the simulation), the frame starts changing position bouncing with the dot. The dot is also not moving but only bounce in the center.
'''
import turtle
import random
#used to infect
class Virus:
def __init__(self, colour, duration):
self.colour = colour
self.duration = duration
## This class represents a person
class Person:
def __init__(self, world_size):
self.world_size = world_size
self.radius = 7
self.location = turtle.position()
self.destination = self._get_random_location()
#random locations are used to assign a destination for the person
#the possible locations should not be closer than 1 radius to the edge of the world
def _get_random_location(self):
x = random.randint(-349, 349)
y = random.randint(-249, 249)
return (x, y)
#draw a person using a dot. Use colour if implementing Viruses
def draw(self):
turtle.penup()
turtle.home()
turtle.pendown()
turtle.dot(self.radius*2)
#returns true if within 1 radius
def reached_destination(self):
self.location = turtle.position()
distX = abs(abs(self.destination[0])-abs(self.location[0]))
distY = abs(abs(self.destination[1])- abs(self.location[1]))
if distX and distY < self.radius:
return True
else:
pass
#Updates the person each hour.
#- moves each person by calling the move method
#- if the destination is reached then set a new destination
#- progress any illness
def update(self):
self.move()
if self.reached_destination():
self._get_random_location()
else:
self.move()
#moves person towards the destination
def move(self):
turtle.setheading(turtle.towards(self.destination))
turtle.forward(self.radius/2)
class World:
def __init__(self, width, height, n):
self.size = (width, height)
self.hours = 0
self.people = []
self.add_person()
#add a person to the list
def add_person(self):
person = Person(1)
self.people.append(person)
#simulate one hour in the world.
#- increase hours passed.
#- update all people
#- update all infection transmissions
def simulate(self):
self.hours += 1
for item in self.people:
item.update()
#Draw the world. Perform the following tasks:
# - clear the current screen
# - draw all the people
# - draw the box that frames the world
# - write the number of hours and number of people infected at the top of the frame
def draw(self):
turtle.clear()
turtle.hideturtle()
turtle.penup()
turtle.right(180)
turtle.forward(250)
turtle.right(90)
turtle.forward(350)
turtle.left(180)
turtle.pendown()
turtle.forward(700)
turtle.left(90)
turtle.forward(500)
turtle.left(90)
turtle.forward(700)
turtle.left(90)
turtle.forward(500)
turtle.right(180)
turtle.forward(500)
turtle.write(f'Hours: {self.hours}', False, 'left')
turtle.update()
for item in self.people:
item.draw()
#---------------------------------------------------------
#Should not need to alter any of the code below this line
#---------------------------------------------------------
class GraphicalWorld:
""" Handles the user interface for the simulation
space - starts and stops the simulation
'z' - resets the application to the initial state
'x' - infects a random person
'c' - cures all the people
"""
def __init__(self):
self.WIDTH = 800
self.HEIGHT = 600
self.TITLE = 'COMPSCI 130 Project One'
self.MARGIN = 50 #gap around each side
self.PEOPLE = 200 #number of people in the simulation
self.framework = AnimationFramework(self.WIDTH, self.HEIGHT, self.TITLE)
self.framework.add_key_action(self.setup, 'z')
self.framework.add_key_action(self.infect, 'x')
self.framework.add_key_action(self.cure, 'c')
self.framework.add_key_action(self.toggle_simulation, ' ')
self.framework.add_tick_action(self.next_turn)
self.world = None
def setup(self):
""" Reset the simulation to the initial state """
print('resetting the world')
self.framework.stop_simulation()
self.world = World(self.WIDTH - self.MARGIN * 2, self.HEIGHT - self.MARGIN * 2, self.PEOPLE)
self.world.draw()
def infect(self):
""" Infect a person, and update the drawing """
print('infecting a person')
self.world.infect_person()
self.world.draw()
def cure(self):
""" Remove infections from all the people """
print('cured all people')
self.world.cure_all()
self.world.draw()
def toggle_simulation(self):
""" Starts and stops the simulation """
if self.framework.simulation_is_running():
self.framework.stop_simulation()
else:
self.framework.start_simulation()
def next_turn(self):
""" Perform the tasks needed for the next animation cycle """
self.world.simulate()
self.world.draw()
## This is the animation framework
## Do not edit this framework
class AnimationFramework:
"""This framework is used to provide support for animation of
interactive applications using the turtle library. There is
no need to edit any of the code in this framework.
"""
def __init__(self, width, height, title):
self.width = width
self.height = height
self.title = title
self.simulation_running = False
self.tick = None #function to call for each animation cycle
self.delay = 1 #smallest delay is 1 millisecond
turtle.title(title) #title for the window
turtle.setup(width, height) #set window display
turtle.hideturtle() #prevent turtle appearance
turtle.tracer(0, 0) #prevent turtle animation
turtle.listen() #set window focus to the turtle window
turtle.mode('logo') #set 0 direction as straight up
turtle.penup() #don't draw anything
turtle.setundobuffer(None)
self.__animation_loop()
def start_simulation(self):
self.simulation_running = True
def stop_simulation(self):
self.simulation_running = False
def simulation_is_running(self):
return self.simulation_running
def add_key_action(self, func, key):
turtle.onkeypress(func, key)
def add_tick_action(self, func):
self.tick = func
def __animation_loop(self):
try:
if self.simulation_running:
self.tick()
turtle.ontimer(self.__animation_loop, self.delay)
except turtle.Terminator:
pass
gw = GraphicalWorld()
gw.setup()
turtle.mainloop()
'''
The turtle dot should be bouncing slowly to the random location and the frame should stay still when I press the space bar. And I know the code is long sorry about that.
the frame starts changing position bouncing with the dot. The dot is
also not moving but only bounce in the center.
I've reworked your Person and World classes below to address these two issues. This simulation model you're given uses a single turtle which means we have to play by certain rules:
Each Person must keep track of their own position and heading
Only the draw() method should have the pen down, all other Person methods should have the pen up if using the turtle to do calculations
Whenever a Person uses the turtle, you can't assume anything about it as another Person was just using the turtle so you must set your heading, position and pen state
The changed portion of your posted code:
FONT = ('Arial', 16, 'normal')
# This class represents a person
class Person():
def __init__(self, world_size):
self.world_size = world_size
self.radius = 7
self.location = turtle.position()
self.destination = self._get_random_location()
turtle.penup()
turtle.setposition(self.location)
turtle.setheading(turtle.towards(self.destination))
self.heading = turtle.heading()
# random locations are used to assign a destination for the person
# the possible locations should not be closer than 1 radius to the edge of the world
def _get_random_location(self):
x = random.randint(self.radius - 349, 349 - self.radius)
y = random.randint(self.radius - 249, 249 - self.radius)
return (x, y)
# draw a person using a dot. Use colour if implementing Viruses
def draw(self):
x, y = self.location
# use .circle() not .dot() as the latter causes an extra update (flicker)
turtle.penup()
turtle.setposition(x, y - self.radius)
turtle.pendown()
turtle.begin_fill()
turtle.circle(self.radius)
turtle.end_fill()
# returns true if within 1 radius
def reached_destination(self):
distX = abs(self.destination[0] - self.location[0])
distY = abs(self.destination[1] - self.location[1])
return distX < self.radius and distY < self.radius
# Updates the person each hour.
# - moves each person by calling the move method
# - if the destination is reached then set a new destination
# - progress any illness
def update(self):
self.move()
if self.reached_destination():
self.destination = self._get_random_location()
turtle.penup()
turtle.setposition(self.location)
turtle.setheading(turtle.towards(self.destination))
self.heading = turtle.heading()
# moves person towards the destination
def move(self):
turtle.penup()
turtle.setheading(self.heading)
turtle.setposition(self.location)
turtle.forward(self.radius / 2)
self.location = turtle.position()
class World:
def __init__(self, width, height, n):
self.size = (width, height)
self.hours = 0
self.people = []
for _ in range(n):
self.add_person()
# add a person to the list
def add_person(self):
person = Person(1)
self.people.append(person)
# simulate one hour in the world.
# - increase hours passed.
# - update all people
# - update all infection transmissions
def simulate(self):
self.hours += 1
for item in self.people:
item.update()
# Draw the world. Perform the following tasks:
# - clear the current screen
# - draw all the people
# - draw the box that frames the world
# - write the number of hours and number of people infected at the top of the frame
def draw(self):
turtle.clear() # also undoes hideturtle(), etc.
turtle.hideturtle()
turtle.setheading(0)
turtle.penup()
turtle.setposition(-350, -250)
turtle.pendown()
for _ in range(2):
turtle.forward(500)
turtle.right(90)
turtle.forward(700)
turtle.right(90)
for item in self.people:
item.draw()
turtle.penup()
turtle.setposition(-350, -250)
# leave this to the end as .write() forces an extra update (flicker)
turtle.write(f'Hours: {self.hours}', move=False, align='left', font=FONT)
turtle.update()
I've also included some tweaks to reduce flicker. I'm sure there's lots more work to be done.
If we wanted to run this simulation faster, we'd make each Person a separate turtle (e.g. via inheritance) and use the reshaped turtle itself as it's presence on the screen and not draw the Person. And we'd throw separate turtles at the outline frame and the text to simplify updates.
I'm learning Object Orientated Python and understand the main principals of classes and creating objects from classes however I need something explained Re: the pygame code below. I'm struggling to get my head around what's happening when sprite lists are being created and the two lines of code under the code which creates the ball object (allsprites.add etc). In other words what are sprites and why are lists of them created? Why isn't the ball object just created from the class on its own? Why does it need to be added to a sprite list?? What's going on? Any explanation would be greatly appreciated.
"""
Sample Breakout Game
Sample Python/Pygame Programs
Simpson College Computer Science
http://programarcadegames.com/
http://simpson.edu/computer-science/
"""
# --- Import libraries used for this program
import math
import pygame
# Define some colors
black = (0, 0, 0)
white = (255, 255, 255)
blue = (0, 0, 255)
# Size of break-out blocks
block_width = 23
block_height = 15
class Block(pygame.sprite.Sprite):
"""This class represents each block that will get knocked out by the ball
It derives from the "Sprite" class in Pygame """
def __init__(self, color, x, y):
""" Constructor. Pass in the color of the block,
and its x and y position. """
# Call the parent class (Sprite) constructor
pygame.sprite.Sprite.__init__(self)
# Create the image of the block of appropriate size
# The width and height are sent as a list for the first parameter.
self.image = pygame.Surface([block_width, block_height])
# Fill the image with the appropriate color
self.image.fill(color)
# Fetch the rectangle object that has the dimensions of the image
self.rect = self.image.get_rect()
# Move the top left of the rectangle to x,y.
# This is where our block will appear..
self.rect.x = x
self.rect.y = y
class Ball(pygame.sprite.Sprite):
""" This class represents the ball
It derives from the "Sprite" class in Pygame """
# Speed in pixels per cycle
speed = 10.0
# Floating point representation of where the ball is
x = 0.0
y = 180.0
# Direction of ball (in degrees)
direction = 200
width = 10
height = 10
# Constructor. Pass in the color of the block, and its x and y position
def __init__(self):
# Call the parent class (Sprite) constructor
pygame.sprite.Sprite.__init__(self)
# Create the image of the ball
self.image = pygame.Surface([self.width, self.height])
# Color the ball
self.image.fill(white)
# Get a rectangle object that shows where our image is
self.rect = self.image.get_rect()
# Get attributes for the height/width of the screen
self.screenheight = pygame.display.get_surface().get_height()
self.screenwidth = pygame.display.get_surface().get_width()
def bounce(self, diff):
""" This function will bounce the ball
off a horizontal surface (not a vertical one) """
self.direction = (180 - self.direction) % 360
self.direction -= diff
def update(self):
""" Update the position of the ball. """
# Sine and Cosine work in degrees, so we have to convert them
direction_radians = math.radians(self.direction)
# Change the position (x and y) according to the speed and direction
self.x += self.speed * math.sin(direction_radians)
self.y -= self.speed * math.cos(direction_radians)
# Move the image to where our x and y are
self.rect.x = self.x
self.rect.y = self.y
# Do we bounce off the top of the screen?
if self.y <= 0:
self.bounce(0)
self.y = 1
# Do we bounce off the left of the screen?
if self.x <= 0:
self.direction = (360 - self.direction) % 360
self.x = 1
# Do we bounce of the right side of the screen?
if self.x > self.screenwidth - self.width:
self.direction = (360 - self.direction) % 360
self.x = self.screenwidth - self.width - 1
# Did we fall off the bottom edge of the screen?
if self.y > 600:
return True
else:
return False
class Player(pygame.sprite.Sprite):
""" This class represents the bar at the bottom that the player controls. """
def __init__(self):
""" Constructor for Player. """
# Call the parent's constructor
pygame.sprite.Sprite.__init__(self)
self.width = 75
self.height = 15
self.image = pygame.Surface([self.width, self.height])
self.image.fill((white))
# Make our top-left corner the passed-in location.
self.rect = self.image.get_rect()
self.screenheight = pygame.display.get_surface().get_height()
self.screenwidth = pygame.display.get_surface().get_width()
self.rect.x = 0
self.rect.y = self.screenheight-self.height
def update(self):
""" Update the player position. """
# Get where the mouse is
pos = pygame.mouse.get_pos()
# Set the left side of the player bar to the mouse position
self.rect.x = pos[0]
# Make sure we don't push the player paddle
# off the right side of the screen
if self.rect.x > self.screenwidth - self.width:
self.rect.x = self.screenwidth - self.width
# Call this function so the Pygame library can initialize itself
pygame.init()
# Create an 800x600 sized screen
screen = pygame.display.set_mode([800, 600])
# Set the title of the window
pygame.display.set_caption('Breakout')
# Enable this to make the mouse disappear when over our window
pygame.mouse.set_visible(0)
# This is a font we use to draw text on the screen (size 36)
font = pygame.font.Font(None, 36)
# Create a surface we can draw on
background = pygame.Surface(screen.get_size())
# Create sprite lists
blocks = pygame.sprite.Group()
balls = pygame.sprite.Group()
allsprites = pygame.sprite.Group()
# Create the player paddle object
player = Player()
allsprites.add(player)
# Create the ball
ball = Ball()
allsprites.add(ball)
balls.add(ball)
# The top of the block (y position)
top = 80
# Number of blocks to create
blockcount = 32
# --- Create blocks
# Five rows of blocks
for row in range(5):
# 32 columns of blocks
for column in range(0, blockcount):
# Create a block (color,x,y)
block = Block(blue, column * (block_width + 2) + 1, top)
blocks.add(block)
allsprites.add(block)
# Move the top of the next row down
top += block_height + 2
# Clock to limit speed
clock = pygame.time.Clock()
# Is the game over?
game_over = False
# Exit the program?
exit_program = False
# Main program loop
while exit_program != True:
# Limit to 30 fps
clock.tick(30)
# Clear the screen
screen.fill(black)
# Process the events in the game
for event in pygame.event.get():
if event.type == pygame.QUIT:
exit_program = True
# Update the ball and player position as long
# as the game is not over.
if not game_over:
# Update the player and ball positions
player.update()
game_over = ball.update()
# If we are done, print game over
if game_over:
text = font.render("Game Over", True, white)
textpos = text.get_rect(centerx=background.get_width()/2)
textpos.top = 300
screen.blit(text, textpos)
# See if the ball hits the player paddle
if pygame.sprite.spritecollide(player, balls, False):
# The 'diff' lets you try to bounce the ball left or right
# depending where on the paddle you hit it
diff = (player.rect.x + player.width/2) - (ball.rect.x+ball.width/2)
# Set the ball's y position in case
# we hit the ball on the edge of the paddle
ball.rect.y = screen.get_height() - player.rect.height - ball.rect.height - 1
ball.bounce(diff)
# Check for collisions between the ball and the blocks
deadblocks = pygame.sprite.spritecollide(ball, blocks, True)
# If we actually hit a block, bounce the ball
if len(deadblocks) > 0:
ball.bounce(0)
# Game ends if all the blocks are gone
if len(blocks) == 0:
game_over = True
# Draw Everything
allsprites.draw(screen)
# Flip the screen and show what we've drawn
pygame.display.flip()
pygame.quit()
You don't need to add the balls and blocks to sprite lists - it's just a matter of convenience. You could manually check each ball for a collision, but it's easier to just tell pygame to check them all for you
# See if the ball hits the player paddle
if pygame.sprite.spritecollide(player, balls, False):
# The 'diff' lets you try to bounce the ball left or right
# depending where on the paddle you hit it
diff = (player.rect.x + player.width/2) - (ball.rect.x+ball.width/2)
# Set the ball's y position in case
# we hit the ball on the edge of the paddle
ball.rect.y = screen.get_height() - player.rect.height - ball.rect.height - 1
ball.bounce(diff)
You could draw each thing to the screen separately on each frame, but it's easier just to tell pygame to do it for you:
# Draw Everything
allsprites.draw(screen)
Things can be in more than one list as required, for example a ball is added to the balls list so that you can easily check for collisions, but also added to the allsprites list so that you can easily draw everything on the screen
# Create the ball
ball = Ball()
allsprites.add(ball)
balls.add(ball)
Edit:
An important distinction is that allsprites is actually a sprite.Group. It has a list of sprites inside it, but it also has other methods like draw.
To address your question of "what is a Sprite", it's simply a thing that gets drawn on screen. pygame methods like sprite.Group.draw expect a list of things with certain attributes - such as update. The easiest way to make sure that you provide all of those attributes with the right names is to subclass Sprite, however this is also a (strongly recommended) convenience thing - for instance, this is from the pygame source code:
While it is possible to design sprite and group classes that don't
derive from the Sprite and AbstractGroup classes below, it is strongly
recommended that you extend those when you add a Sprite or Group
class.
So what specifically does subclassing Sprite get you? Let's take a look at the source. Here's how to find the source code for a python module:
>>> import pygame.sprite
>>> pygame.sprite.__file__
'c:\\Python27\\lib\\site-packages\\pygame\\sprite.py'
>>>
Every python module has a __file__ attribute that tells you where the source is located (well not quite every). If you open it up in your editor, and scroll down, you see the class definition for Sprite:
class Sprite(object):
"""simple base class for visible game objects
pygame.sprite.Sprite(*groups): return Sprite
The base class for visible game objects. Derived classes will want to
override the Sprite.update() and assign a Sprite.image and
Sprite.rect attributes. The initializer can accept any number of
Group instances to be added to.
When subclassing the Sprite, be sure to call the base initializer before
adding the Sprite to Groups.
"""
def __init__(self, *groups):
self.__g = {} # The groups the sprite is in
if groups: self.add(groups)
def add(self, *groups):
"""add the sprite to groups
Sprite.add(*groups): return None
Any number of Group instances can be passed as arguments. The
Sprite will be added to the Groups it is not already a member of.
"""
has = self.__g.__contains__
for group in groups:
if hasattr(group, '_spritegroup'):
if not has(group):
group.add_internal(self)
self.add_internal(group)
else: self.add(*group)
def remove(self, *groups):
"""remove the sprite from groups
Sprite.remove(*groups): return None
Any number of Group instances can be passed as arguments. The Sprite will
be removed from the Groups it is currently a member of.
"""
has = self.__g.__contains__
for group in groups:
if hasattr(group, '_spritegroup'):
if has(group):
group.remove_internal(self)
self.remove_internal(group)
else: self.remove(*group)
def add_internal(self, group):
self.__g[group] = 0
def remove_internal(self, group):
del self.__g[group]
def update(self, *args):
"""method to control sprite behavior
Sprite.update(*args):
The default implementation of this method does nothing; it's just a
convenient "hook" that you can override. This method is called by
Group.update() with whatever arguments you give it.
There is no need to use this method if not using the convenience
method by the same name in the Group class.
"""
pass
def kill(self):
"""remove the Sprite from all Groups
Sprite.kill(): return None
The Sprite is removed from all the Groups that contain it. This won't
change anything about the state of the Sprite. It is possible to continue
to use the Sprite after this method has been called, including adding it
to Groups.
"""
for c in self.__g.keys():
c.remove_internal(self)
self.__g.clear()
def groups(self):
"""list of Groups that contain this Sprite
Sprite.groups(): return group_list
Return a list of all the Groups that contain this Sprite.
"""
return self.__g.keys()
def alive(self):
"""does the sprite belong to any groups
Sprite.alive(): return bool
Returns True when the Sprite belongs to one or more Groups.
"""
return (len(self.__g) != 0)
def __repr__(self):
return "<%s sprite(in %d groups)>" % (self.__class__.__name__, len(self.__g))
So in summary, you don't have to subclass Sprite - you could just provide all of these methods on your own - but it's easier if you do ;)