""" Sprite Sample Program """importrandomimportarcade# --- Constants ---SPRITE_SCALING_PLAYER=0.5SPRITE_SCALING_COIN=0.2COIN_COUNT=50SCREEN_WIDTH=800SCREEN_HEIGHT=600classCoin(arcade.Sprite):defupdate(self):self.center_y-=1classMyGame(arcade.Window):""" Our custom Window Class"""def__init__(self):""" Initializer """# Call the parent class initializersuper().__init__(SCREEN_WIDTH,SCREEN_HEIGHT,"Sprite Example")# Variables that will hold sprite listsself.player_list=Noneself.coin_list=None# Set up the player infoself.player_sprite=Noneself.score=0# Don't show the mouse cursorself.set_mouse_visible(False)arcade.set_background_color(arcade.color.AMAZON)defsetup(self):""" Set up the game and initialize the variables. """# Sprite listsself.player_list=arcade.SpriteList()self.coin_list=arcade.SpriteList()# Scoreself.score=0# Set up the player# Character image from kenney.nlself.player_sprite=arcade.Sprite("character.png",SPRITE_SCALING_PLAYER)self.player_sprite.center_x=50self.player_sprite.center_y=50self.player_list.append(self.player_sprite)# Create the coinsforiinrange(COIN_COUNT):# Create the coin instance# Coin image from kenney.nlcoin=Coin("coin_01.png",SPRITE_SCALING_COIN)# Position the coincoin.center_x=random.randrange(SCREEN_WIDTH)coin.center_y=random.randrange(SCREEN_HEIGHT)# Add the coin to the listsself.coin_list.append(coin)defon_draw(self):""" Draw everything """arcade.start_render()self.coin_list.draw()self.player_list.draw()# Put the text on the screen.output=f"Score: {self.score}"arcade.draw_text(output,10,20,arcade.color.WHITE,14)defon_mouse_motion(self,x,y,dx,dy):""" Handle Mouse Motion """# Move the center of the player sprite to match the mouse x, yself.player_sprite.center_x=xself.player_sprite.center_y=ydefupdate(self,delta_time):""" Movement and game logic """# Call update on all sprites (The sprites don't do much in this# example though.)self.coin_list.update()# Generate a list of all sprites that collided with the player.hit_list=arcade.check_for_collision_with_list(self.player_sprite,self.coin_list)# Loop through each colliding sprite, remove it, and add to the score.forcoininhit_list:coin.remove_from_sprite_lists()self.score+=1defmain():""" Main method """window=MyGame()window.setup()arcade.run()if__name__=="__main__":main()

This causes the coins to move down. But once they move off the screen they
keep going into negative-coordinate land. We can’t see them any more. Sad.

We can get around this by resetting the coins up to the top. Here’s how its
done:

classCoin(arcade.Sprite):defupdate(self):self.center_y-=1# See if we went off-screenifself.center_y<0:self.center_y=SCREEN_HEIGHT

But this isn’t perfect. Because if your eyes are fast, you can see the coin
‘pop’ in and out of existence at the edge. It doesn’t smoothly slide off. This is
because we move it when the center of the coin is at the edge. Not the top of
the coin has slid off.

There are a couple ways we can do this. Here’s one. We’ll check at -20 instead
of 0. As long as the coin radius is 20 or less, we are good.

classCoin(arcade.Sprite):defupdate(self):self.center_y-=1# See if we went off-screenifself.center_y<-20:self.center_y=SCREEN_HEIGHT+20

There’s another way. In addition to center_y, sprites have other
members that are useful in these cases. They are top, bottom,
left and right. So we can do this:

classCoin(arcade.Sprite):defupdate(self):self.center_y-=1# See if we went off-screenifself.top<0:self.bottom=SCREEN_HEIGHT

Doing this allows the coins to smoothly slide on and off the screen. But since
they reappear at the top, we get repeating patters. See the image below:

Coins repeating in a pattern

Instead we can randomize it a bit:

defupdate(self):# Move the coinself.center_y-=1# See if the coin has fallen off the bottom of the screen.# If so, reset it.ifself.top<0:# Reset the coin to a random spot above the screenself.center_y=random.randrange(SCREEN_HEIGHT+20,SCREEN_HEIGHT+100)self.center_x=random.randrange(SCREEN_WIDTH)

This works, but when we we collect all the coins we are done. What if it was
a never-ending set of coins? Instead of “killing” the coin, let’s reset it to
the top of the screen.

defupdate(self,delta_time):""" Movement and game logic """self.coin_list.update()hit_list=arcade.check_for_collision_with_list(self.player_sprite,self.coin_list)forcoininhit_list:self.score+=1# Reset the coin to a random spot above the screencoin.center_y=random.randrange(SCREEN_HEIGHT+20,SCREEN_HEIGHT+100)coin.center_x=random.randrange(SCREEN_WIDTH)

We can even take that common code, and move it to a method. Here’s a full example:

""" Sprite Sample Program """importrandomimportarcade# --- Constants ---SPRITE_SCALING_PLAYER=0.5SPRITE_SCALING_COIN=0.2COIN_COUNT=50SCREEN_WIDTH=800SCREEN_HEIGHT=600classCoin(arcade.Sprite):""" This class represents the coins on our screen. It is a child class of the arcade library's "Sprite" class. """defreset_pos(self):# Reset the coin to a random spot above the screenself.center_y=random.randrange(SCREEN_HEIGHT+20,SCREEN_HEIGHT+100)self.center_x=random.randrange(SCREEN_WIDTH)defupdate(self):# Move the coinself.center_y-=1# See if the coin has fallen off the bottom of the screen.# If so, reset it.ifself.top<0:self.reset_pos()classMyGame(arcade.Window):""" Our custom Window Class"""def__init__(self):""" Initializer """# Call the parent class initializersuper().__init__(SCREEN_WIDTH,SCREEN_HEIGHT,"Sprite Example")# Variables that will hold sprite listsself.player_list=Noneself.coin_list=None# Set up the player infoself.player_sprite=Noneself.score=0# Don't show the mouse cursorself.set_mouse_visible(False)arcade.set_background_color(arcade.color.AMAZON)defsetup(self):""" Set up the game and initialize the variables. """# Sprite listsself.player_list=arcade.SpriteList()self.coin_list=arcade.SpriteList()# Scoreself.score=0# Set up the player# Character image from kenney.nlself.player_sprite=arcade.Sprite("character.png",SPRITE_SCALING_PLAYER)self.player_sprite.center_x=50self.player_sprite.center_y=50self.player_list.append(self.player_sprite)# Create the coinsforiinrange(COIN_COUNT):# Create the coin instance# Coin image from kenney.nlcoin=Coin("coin_01.png",SPRITE_SCALING_COIN)# Position the coincoin.center_x=random.randrange(SCREEN_WIDTH)coin.center_y=random.randrange(SCREEN_HEIGHT)# Add the coin to the listsself.coin_list.append(coin)defon_draw(self):""" Draw everything """arcade.start_render()self.coin_list.draw()self.player_list.draw()# Put the text on the screen.output=f"Score: {self.score}"arcade.draw_text(output,10,20,arcade.color.WHITE,14)defon_mouse_motion(self,x,y,dx,dy):""" Handle Mouse Motion """# Move the center of the player sprite to match the mouse x, yself.player_sprite.center_x=xself.player_sprite.center_y=ydefupdate(self,delta_time):""" Movement and game logic """# Call update on all sprites (The sprites don't do much in this# example though.)self.coin_list.update()# Generate a list of all sprites that collided with the player.hit_list=arcade.check_for_collision_with_list(self.player_sprite,self.coin_list)# Loop through each colliding sprite, remove it, and add to the score.forcoininhit_list:coin.remove_from_sprite_lists()self.score+=1defmain():""" Main method """window=MyGame()window.setup()arcade.run()if__name__=="__main__":main()

""" Sprite Sample Program """importrandomimportarcade# --- Constants ---SPRITE_SCALING_PLAYER=0.5SPRITE_SCALING_COIN=0.2COIN_COUNT=50SCREEN_WIDTH=800SCREEN_HEIGHT=600classCoin(arcade.Sprite):def__init__(self,filename,sprite_scaling):super().__init__(filename,sprite_scaling)self.change_x=0self.change_y=0defupdate(self):# Move the coinself.center_x+=self.change_xself.center_y+=self.change_y# If we are out-of-bounds, then 'bounce'ifself.left<0:self.change_x*=-1ifself.right>SCREEN_WIDTH:self.change_x*=-1ifself.bottom<0:self.change_y*=-1ifself.top>SCREEN_HEIGHT:self.change_y*=-1classMyGame(arcade.Window):""" Our custom Window Class"""def__init__(self):""" Initializer """# Call the parent class initializersuper().__init__(SCREEN_WIDTH,SCREEN_HEIGHT,"Sprite Example")# Variables that will hold sprite listsself.player_list=Noneself.coin_list=None# Set up the player infoself.player_sprite=Noneself.score=0# Don't show the mouse cursorself.set_mouse_visible(False)arcade.set_background_color(arcade.color.AMAZON)defsetup(self):""" Set up the game and initialize the variables. """# Sprite listsself.player_list=arcade.SpriteList()self.coin_list=arcade.SpriteList()# Scoreself.score=0# Set up the player# Character image from kenney.nlself.player_sprite=arcade.Sprite("character.png",SPRITE_SCALING_PLAYER)self.player_sprite.center_x=50self.player_sprite.center_y=50self.player_list.append(self.player_sprite)# Create the coinsforiinrange(COIN_COUNT):# Create the coin instance# Coin image from kenney.nlcoin=Coin("coin_01.png",SPRITE_SCALING_COIN)# Position the coincoin.center_x=random.randrange(SCREEN_WIDTH)coin.center_y=random.randrange(SCREEN_HEIGHT)coin.change_x=random.randrange(-3,4)coin.change_y=random.randrange(-3,4)# Add the coin to the listsself.coin_list.append(coin)defon_draw(self):""" Draw everything """arcade.start_render()self.coin_list.draw()self.player_list.draw()# Put the text on the screen.output=f"Score: {self.score}"arcade.draw_text(output,10,20,arcade.color.WHITE,14)defon_mouse_motion(self,x,y,dx,dy):""" Handle Mouse Motion """# Move the center of the player sprite to match the mouse x, yself.player_sprite.center_x=xself.player_sprite.center_y=ydefupdate(self,delta_time):""" Movement and game logic """# Call update on all sprites (The sprites don't do much in this# example though.)self.coin_list.update()# Generate a list of all sprites that collided with the player.hit_list=arcade.check_for_collision_with_list(self.player_sprite,self.coin_list)# Loop through each colliding sprite, remove it, and add to the score.forcoininhit_list:coin.remove_from_sprite_lists()self.score+=1defmain():""" Main method """window=MyGame()window.setup()arcade.run()if__name__=="__main__":main()

TODO: Put in some text about spawning a sprite too close to the edge. Also make a refer to it from the final
project.

Take what you’ve learned from the example above, and see if you can replicate
this:

importrandomimportarcadeimportmathSPRITE_SCALING=0.5SCREEN_WIDTH=800SCREEN_HEIGHT=600classCoin(arcade.Sprite):def__init__(self,filename,sprite_scaling):""" Constructor. """# Call the parent class (Sprite) constructorsuper().__init__(filename,sprite_scaling)# Current angle in radiansself.circle_angle=0# How far away from the center to orbit, in pixelsself.circle_radius=0# How fast to orbit, in radians per frameself.circle_speed=0.008# Set the center of the point we will orbit aroundself.circle_center_x=0self.circle_center_y=0defupdate(self):""" Update the ball's position. """# Calculate a new x, yself.center_x=self.circle_radius*math.sin(self.circle_angle) \
+self.circle_center_xself.center_y=self.circle_radius*math.cos(self.circle_angle) \
+self.circle_center_y# Increase the angle in prep for the next round.self.circle_angle+=self.circle_speedclassMyGame(arcade.Window):""" Main application class. """def__init__(self,width,height):super().__init__(width,height)# Sprite listsself.player_list=Noneself.coin_list=None# Set up the playerself.score=0self.player_sprite=Nonedefstart_new_game(self):""" Set up the game and initialize the variables. """# Sprite listsself.player_list=arcade.SpriteList()self.coin_list=arcade.SpriteList()# Set up the playerself.score=0# Character image from kenney.nlself.player_sprite=arcade.Sprite("character.png",SPRITE_SCALING)self.player_sprite.center_x=50self.player_sprite.center_y=70self.player_list.append(self.player_sprite)foriinrange(50):# Create the coin instance# Coin image from kenney.nlcoin=Coin("coin_01.png",SPRITE_SCALING/3)# Position the center of the circle the coin will orbitcoin.circle_center_x=random.randrange(SCREEN_WIDTH)coin.circle_center_y=random.randrange(SCREEN_HEIGHT)# Random radius from 10 to 200coin.circle_radius=random.randrange(10,200)# Random start angle from 0 to 2picoin.circle_angle=random.random()*2*math.pi# Add the coin to the listsself.coin_list.append(coin)# Don't show the mouse cursorself.set_mouse_visible(False)# Set the background colorarcade.set_background_color(arcade.color.AMAZON)defon_draw(self):# This command has to happen before we start drawingarcade.start_render()# Draw all the sprites.self.coin_list.draw()self.player_list.draw()# Put the text on the screen.output="Score: "+str(self.score)arcade.draw_text(output,10,20,arcade.color.WHITE,14)defon_mouse_motion(self,x,y,dx,dy):self.player_sprite.center_x=xself.player_sprite.center_y=ydefupdate(self,delta_time):""" Movement and game logic """# Call update on all sprites (The sprites don't do much in this# example though.)self.coin_list.update()# Generate a list of all sprites that collided with the player.hit_list=arcade.check_for_collision_with_list(self.player_sprite,self.coin_list)# Loop through each colliding sprite, remove it, and add to the score.forcoininhit_list:self.score+=1coin.remove_from_sprite_lists()defmain():window=MyGame(SCREEN_WIDTH,SCREEN_HEIGHT)window.start_new_game()arcade.run()if__name__=="__main__":main()