Homework 13: Lunar Lander
Due Dec 15 by 11:55pm Points 30 Available after Nov 30 at 12am
Purpose
The purpose of this homework is to allow you to practice the concept of animation and event-driven
programming, while continuing to apply the principles of object-oriented programming.
Instructions
This assignment consists of 4 problems, worth a total of 30 points. You must create a file called
hw13.py, and submit it to Gradescope. If you have questions, ask!
Because your homework file is submitted and tested electronically, the following are very important:
Submit the correct file, hw13.py, through Gradescope by the due date deadline.
Your program should run without errors when we execute it using Python 3.
Submit your work to Gradescope under the Homework 13 assignment. Make sure that your file is called
hw13.py: if you don’t match the file name exactly then the testing script won’t work and you’ll lose points.
Note on Gradescope:
The Gradescope autograder will do very little for this assignment, as it requires asynchronous interaction
with a graphical interface, something that’s very difficult to automate. So you’ll need to test your program
for yourself, even more so than usual: don’t rely on Gradescope’s tests to tell you whether it’s
working: the only thing they’ll tell you is whether your file is named correctly.
Documentation:
You don’t need to write documentation for individual functions/methods in this assignment, but
you DO need to write documentation for each class instead. Put this template just inside of the
class definition for every class you write.
12/16/2020 Homework 13: Lunar Lander
https://canvas.umn.edu/courses/194161/assignments/1469846 2/10
'''
Purpose: (What does an object of this class represent?)
Instance variables: (What are the instance variables for this class,
and what does each represent in a few words?)
Methods: (What methods does this class have, and what does each do in a few words?)
'''
This exercise will involve a game that simulates a landing craft descending to the surface of the moon.
You may have played this game before, we'll implement a simple version of it. In our version, you are in
control of a lander that is descending toward the moon. Gravity steadily accelerates your craft towards
the moon's surface. You have two controls: thrust, which accelerates the craft in the direction it’s
currently facing, and turning, which adjusts the orientation of the craft to the left or right. Your goal is to
get your lander to be moving at a slow enough speed that it doesn’t crash upon impact. However, you
have a limited amount of fuel, and when that runs out, you can no longer apply thrust or turn. You will
also need to avoid falling meteors that threaten to destroy your ship on impact.
Problem A. (10 points) Simulating Gravity
To get you started, we’ll give some pretty detailed instructions for the first few steps of the project:
hopefully you can extrapolate from those steps to figure out how to proceed in parts B and C as well.
Our first task is to set up classes to represent the entities that need to be manipulated for the game.
One reasonable division of functionality is to have one class for the player controlled lander, and another
overarching class for the game as a whole (we’ll talk about how to deal with the meteors later). We’re
going to have the lander class derive from Turtle, since a lot of the functionality we want (a movable
image on a screen) is already provided by Turtle.
First, import turtle, math, and random at the top of the file. Then, create a class called Lander to
represent an object falling towards the moon’s surface, and have it inherit from the turtle.Turtle class.
The __init__ method of Lander should take in five parameters:
self
the starting x position for the lander
the starting y position
the starting x velocity
12/16/2020 Homework 13: Lunar Lander
https://canvas.umn.edu/courses/194161/assignments/1469846 3/10
the starting y velocity
The last four values should all be numerical types: integers or floating point numbers. The first thing
__init__ should do is call the constructor for its base class (turtle.Turtle). You can do this by just using
turtle.Turtle.__init__(self)
since turtle.Turtle’s constructor does not take any arguments other than self.
At this point, you should be able to test your code to make sure that you have properly inherited from
turtle.Turtle. For example, if you run the line
>>> Lander(100, -50, 0.5, -0.3)
then you should get a turtle window to pop up with the lander (i.e. the turtle) in the middle of the screen.
This will happen regardless of what you put in for the arguments to the constructor, since you’re not
doing anything with those values just yet.
Next, we want to set up the modified turtle, including a few instance variables that don’t appear in the
original turtle.Turtle class. Do the following in Lander.__init__:
12/16/2020 Homework 13: Lunar Lander
https://canvas.umn.edu/courses/194161/assignments/1469846 4/10
Turtles don’t normally have a velocity, so create two instance variables (self.vx and self.vy) to
represent the lander’s velocity in the x and y directions, and initialize them to the appropriate
parameters.
We’ll also need an instance variable to represent the fuel remaining for our lander. Create an
instance variable to track the fuel remaining and set it equal to 50.
We want the lander to be initially facing upwards, rather than to the right. Remember, the Lander
class inherits from turtle.Turtle, so that means that Lander has every method that turtle.Turtle has
(https://docs.python.org/3.8/library/turtle.html#turtle-methods) . So we can use the .left
(https://docs.python.org/3.8/library/turtle.html#turtle.left) method on our Lander object (self) to turn it
90 degrees to the left, with the line self.left(90).
Use a similar strategy to apply the .penup
(https://docs.python.org/3.8/library/turtle.html#turtle.penup) , .speed
(https://docs.python.org/3.8/library/turtle.html#turtle.speed) , and .setpos
(https://docs.python.org/3.8/library/turtle.html#turtle.setpos) Turtle methods in order to cause our
Lander object (self) to stop drawing, change its speed to 0 (which is weirdly the fastest possible
speed), and move to the initial x and y coordinates that were passed in as parameters.
At this point, if you re-run the line from earlier, then you should now see that the lander is pointing
upwards, and should be located at (100, -50) rather than the middle of the screen at (0, 0).
>>> Lander(100, -50, 0.5, -0.3)
12/16/2020 Homework 13: Lunar Lander
https://canvas.umn.edu/courses/194161/assignments/1469846 5/10
Next, create a new class Game: this will be responsible for keeping the game running, keeping track of
the meteors, and so on. Game should not inherit from anything. Game.__init__ should only take in self
as a parameter, and should do the following:
turtle.setworldcoordinates(0, 0, 1000, 1000)
(https://docs.python.org/3.8/library/turtle.html#turtle.setworldcoordinates) : this will ensure that
regardless of what platform you’re running the program on, the lower left corner of the screen will be
(0, 0), and the upper right will be (1000, 1000).
turtle.delay(0) (https://docs.python.org/3.8/library/turtle.html#turtle.delay) to keep the animation
moving quickly
Create a Lander object to be controlled by the player and set it as an instance variable called
self.player. You should pass the following values into the Lander constructor:
The initial x coordinate should be a random float between 100 and 900. You can use
random.uniform (https://docs.python.org/3/library/random.html#random.uniform) to get a random
floating point number.
The initial y coordinate should be a random float between 500 and 900.
The initial x velocity should be a random float between -5 and 5.
The initial y velocity should be a random float between -5 and 0.
Note that you are creating a Lander object within the Game object (Game has-a Lander), not
using inheritance (Game is-a Lander), so you should be calling the Lander constructor directly
using Lander(...), not using Lander.__init__(...).
12/16/2020 Homework 13: Lunar Lander
https://canvas.umn.edu/courses/194161/assignments/1469846 6/10
Depending on the size of your screen, you may want to double the size of the lander to make it
easier to see. You can do this with the .turtlesize
(https://docs.python.org/3.8/library/turtle.html#turtle.turtlesize) Turtle method. Remember, you can use
any Turtle method on your Lander object because Lander inherits from turtle.Turtle, so you’d use
self.player.turtlesize(2).
We’ll need to add more to this method later, but for now, put a call to Game() at the bottom of your
hw13.py file and run it. Each time you run the file, you should see the lander appear in a random
location on the top half of the screen.
Next, we need to add animation. This requires three steps.
First, create a method move(self) in Lander that moves the Lander to a new position each step,
based on its current velocity. This should consist of:
Subtract 0.0486 from the y velocity (this represents the downward acceleration due to gravity on
the moon).
Compute the new x position by getting previous x position using the xcor()
(https://docs.python.org/3.8/library/turtle.html#turtle.xcor) Turtle method, and then adding the x
velocity.
Do the same for the new y position using ycor()
(https://docs.python.org/3.8/library/turtle.html#turtle.ycor)
Use setpos (https://docs.python.org/3.8/library/turtle.html#turtle.setpos) to move the lander to
the new (x, y) position.
Second, create a method gameloop(self) in Game that does two things:
Calls the move method for the player controlled Lander (self.player)
Calls itself again 30 milliseconds from now. You can do this using
turtle.Screen().ontimer(self.gameloop, 30).
Finally, add a call to self.gameloop() at the end of Game.__init__, so that the animation cycle is
started immediately.
If you completed these steps correctly, then you should see the your Lander shoot off in a random initial
direction, but then start to slowly accelerate downwards. If you want to be sure the acceleration
component is working correctly, temporarily set your initial x and y velocity to 0 and see if the Lander
accelerates downwards.
Finally, let’s implement the thrust function: we want it so that pressing the ‘Up’ arrow will cause the
Lander to increase velocity in whatever direction its currently pointing. First, create a function called
12/16/2020 Homework 13: Lunar Lander
https://canvas.umn.edu/courses/194161/assignments/1469846 7/10
thrust(self) in the Lander class. For now, just have this method print out “Up button pressed”. Then, in
Game.__init__, add the following three lines to the end of the method:
turtle.onkeypress(self.player.thrust, 'Up')
turtle.listen()
turtle.mainloop()
These lines cause turtle to call the thrust method on your player Lander every time the Up arrow is
pressed. Test your program to ensure that it’s currently printing “Up button pressed” whenever you press
the up key. You may need to click on the turtle graphics window first to get it to register, and this may fail
to work entirely in repl.it under some conditions.
Assuming that worked, alter your thrust function to do the following:
If there is greater than 0 fuel remaining, this should:
Reduce the amount of fuel by 1
Get the angle the ship is pointing at in radians - use math.radians
(https://docs.python.org/3/library/math.html#math.radians) (self.heading()
(https://docs.python.org/3.8/library/turtle.html#turtle.heading) )
Get the cosine of that angle, and add it to the x velocity (use math.cos
(https://docs.python.org/3/library/math.html#math.cos) ). Think about why cosine of the angle tells
us what proportion of the unit of thrust to add to the x velocity.
Get the sine of that angle, and add it to the y velocity (use math.sin
(https://docs.python.org/3/library/math.html#math.sin) )
Print out the number of fuel units remaining.
If there is no fuel remaining, the method should instead just print out "Out of fuel".
Now each time you press the up button, the ship should either slow its fall, or start accelerating upwards
if you hit it enough times (unless you press it 50 times, in which case you’ll run out of fuel and it shouldn’t
cause the ship to change speed). Test this further by changing the initial turn angle to something other
than 90 degrees, and ensure that the acceleration is always in the direction the Lander is pointing, even
when that direction isn’t up.
Problem B. (5 points) Turning
12/16/2020 Homework 13: Lunar Lander
https://canvas.umn.edu/courses/194161/assignments/1469846 8/10
Add additional methods so that the Lander turns left 10 degrees whenever the left arrow key is pressed,
and right 10 degrees whenever the right arrow key is pressed. This requires one fuel, so similar to the
thrust method, nothing should happen if there is no fuel remaining, and if there is fuel left then one fuel
should be removed each time a turn occurs. Be sure to print out the remaining fuel each time a turn
happens.
Problem C. (5 points) Game Over
Change your gameloop method in the Game class so that it stops calling itself in the case that the
Lander reaches the bottom of the screen (say, the y coordinate is less than 10), causing the game to
stop running. When this happens, if the Lander’s speed in either the x or the y direction is greater than
3, then print out “You crashed!”. Otherwise, print out “Successful landing!”. If you wish, you can use
turtle.write (https://docs.python.org/3.8/library/turtle.html#turtle.write) to output the message to the turtle
window rather than print it out.
Problem D. (10 points) Meteors
Add red circular meteors to your game. The implementation details are left up to you, but these should
continually appear at the top of the screen and accelerate downward due to gravity. If the Lander
crashes into any Meteor, then the game should end and result in a “You crashed!” message, just as if
you had landed at too great a speed.
12/16/2020 Homework 13: Lunar Lander
https://canvas.umn.edu/courses/194161/assignments/1469846 9/10
Problem E. (0 points) Fun stuff
This is your final homework for this class! Since the autograder can't really test these properly, we will be
playing each and every one of your lander games. Add your own unique touch!
Background color
Different lander shape
Differently sized meteors
Other obstacles (UFOs)
A proper game implementation would use separate image files for some of these things, but uploading
images as separate files to gradescope is going to be a lot of trouble for us, so don't do that.
Uploading to Gradescope
Once you have completed your code, run the file one last time to ensure that you didn’t accidentally
introduce any syntax errors. You should always run the file one last time before submitting, on
12/16/2020 Homework 13: Lunar Lander
https://canvas.umn.edu/courses/194161/assignments/1469846 10/10
every homework assignment. Losing 30% of your grade on an assignment because you accidentally
forget a single # somewhere and caused a syntax error feels awful, so ensure it doesn’t happen to you.
If you run into difficulties on this step, post your issue on the forums, or come into office hours, and we’ll
help you get it fixed.