
For my programming elective, I thought I’d try to get students programming autonomous agents that we could all compile together into some type of game. Since it was, for most of them a first class in programming, this has proven a little too ambitious, and I’ve had to adjust a bit to build up to it.
Step 1: Build a spaceship/vehicle/agent.

- We’re using VPython so we can build 3d ships. Students get to exercise their creativity a bit and learn how to place things in 3d co-ordinate space.
- The ship must have a front end and all the parts must be put into a single frame so the whole thing can be moved as a unit.
- Although it’s not required, I’ve added in the beginnings of a trail so we can track the motion of the spaceship
from visual import * f = frame() r = ring(frame=f, thickness=.25, axis=(0,1,0)) cabin = sphere(frame=f, radius=0.6, color=color.red) front = pyramid(frame=f, height=1,width=1,length=2, color=color.blue) trail = curve(pos=[f.pos,])
Step 2: Make the spaceship a class.
- Putting the spaceship in a separate class, away from the rest of the code, makes it easier to move from one program to another. That means we can import everyone’s ships into a single program at the end.
from visual import *
class spaceship1:
def __init__(self):
self.f = frame()
self.r = ring(frame=self.f, thickness=.25, axis=(0,1,0))
self.cabin = sphere(frame=self.f, radius=0.6, color=color.red)
self.front = pyramid(frame=self.f, height=1,width=1,length=2, color=color.blue)
self.trail = curve(pos=[self.f.pos,])
ss = spaceship1()
Make the spaceship move
- We’re going to control the movement of the spaceship using the arrow keys. Left and right to turn; up and down to accelerate and decelerate.
- To allow movement, we’ll put the keyboard controls into an infinite loop, but to allow maximum flexibility (and to show how to use create methods in a class) we’re putting the actual movement in as methods in the class: the turning method is named turn_xz and movement is move_xz since all the motion is going to be restricted in the xz plane for now.
from visual import *
class spaceship1:
def __init__(self):
self.f = frame()
self.r = ring(frame=self.f, thickness=.25, axis=(0,1,0))
self.cabin = sphere(frame=self.f, radius=0.6, color=color.red)
self.front = pyramid(frame=self.f, height=1,width=1,length=2, color=color.blue)
self.trail = curve(pos=[self.f.pos,])
def turn_xz(self, turn_rate):
self.f.axis = rotate(self.f.axis, turn_rate, (0,1,0))
def move_xz(self, speed):
self.f.pos = self.f.pos + self.f.axis*speed
self.trail.append(pos=self.f.pos)
ss = spaceship1()
turn = 0.0
speed=0.0
while 1:
rate(20) #slows down execution of the loop
ss.turn_xz(turn)
ss.move_xz(speed)
if scene.kb.keys: # event waiting to be processed?
s = scene.kb.getkey() # get keyboard info
if s == 'left':
turn = turn + 0.01
if s == 'right':
turn = turn - 0.01
if s == 'up':
speed = speed + 0.01
if s == 'down':
speed = speed - 0.01
if s == ' ':
if turn <> 0:
turn = 0
elif speed <> 0:
speed = 0
Fire missiles
- We add in missiles by creating a class very similar to the spaceship. For now our missile is just a ball but I’m putting it into a frame anyway in case later on I want it to be a composite object.
- Since we can fire multiple missiles, in the code I create a list to hold all the missiles.
- Missiles are fired using the “a” key.
from visual import *
class spaceship1:
def __init__(self):
self.f = frame()
self.r = ring(frame=self.f, thickness=.25, axis=(0,1,0))
self.cabin = sphere(frame=self.f, radius=0.6, color=color.red)
self.front = pyramid(frame=self.f, height=1,width=1,length=2, color=color.blue)
self.trail = curve(pos=[self.f.pos,])
def turn_xz(self, turn_rate):
self.f.axis = rotate(self.f.axis, turn_rate, (0,1,0))
def move_xz(self, speed):
self.f.pos = self.f.pos + self.f.axis*speed
self.trail.append(pos=self.f.pos)
class missile:
def __init__(self, axis, pos):
self.f = frame(axis=axis, pos=pos)
self.r = sphere(frame=self.f, radius=0.2, color=color.green)
self.speed = 0.5
def move_xz(self):
self.f.pos = self.f.pos + self.f.axis*self.speed
ss = spaceship1()
turn = 0.0
speed=0.0
missiles = [] #list for missiles
while 1:
rate(20) #slows down execution of the loop
ss.turn_xz(turn)
ss.move_xz(speed)
#move missiles
for i, m in enumerate(missiles):
m.move_xz()
if scene.kb.keys: # event waiting to be processed?
s = scene.kb.getkey() # get keyboard info
if s == 'left':
turn = turn + 0.01
if s == 'right':
turn = turn - 0.01
if s == 'up':
speed = speed + 0.01
if s == 'down':
speed = speed - 0.01
if s == ' ':
if turn <> 0:
turn = 0
elif speed <> 0:
speed = 0
#fire missile
if s == 'a':
missiles.append(missile(ss.f.axis, ss.f.pos))
Final adjustments
- Finally, I’m going to put in a boundary, and set it up to delete the missiles if they go out of bounds.
- I’m also going to set an option so that the scene follows the ship, which makes it easier to keep track of things.
from visual import *
class spaceship1:
def __init__(self):
self.f = frame()
self.r = ring(frame=self.f, thickness=.25, axis=(0,1,0))
self.cabin = sphere(frame=self.f, radius=0.6, color=color.red)
self.front = pyramid(frame=self.f, height=1,width=1,length=2, color=color.blue)
self.trail = curve(pos=[self.f.pos,])
def turn_xz(self, turn_rate):
self.f.axis = rotate(self.f.axis, turn_rate, (0,1,0))
def move_xz(self, speed):
self.f.pos = self.f.pos + self.f.axis*speed
self.trail.append(pos=self.f.pos)
class missile:
def __init__(self, axis, pos):
self.f = frame(axis=axis, pos=pos)
self.r = sphere(frame=self.f, radius=0.2, color=color.green)
self.speed = 0.5
def move_xz(self):
self.f.pos = self.f.pos + self.f.axis*self.speed
class bounds:
def __init__(self, boundary_distance):
self.boundary_distance = boundary_distance
self.border = curve(pos=[(-boundary_distance,0,-boundary_distance),
(boundary_distance,0,-boundary_distance),
(boundary_distance,0,boundary_distance),
(-boundary_distance,0,boundary_distance),
(-boundary_distance,0,-boundary_distance)])
def in_bounds(self, pos):
if ( pos.x < -self.boundary_distance or
pos.x > self.boundary_distance or
pos.z < -self.boundary_distance or
pos.z > self.boundary_distance):
return false
else:
return true
ss = spaceship1()
turn = 0.0
speed=0.0
l_track_ship = 1
scene.range=10
scene.forward = (0,-1,0)
missiles = []
boundary_distance = 100
boundary = bounds(boundary_distance)
while 1:
rate(20)
if l_track_ship > 0:
scene.center = ss.f.pos
ss.turn_xz(turn)
ss.move_xz(speed)
#move missiles
del_list = []
for i, m in enumerate(missiles):
m.move_xz()
#delete missile if out of bounds
if boundary.in_bounds(m.f.pos) == False:
del_list.append(i)
for i in del_list:
missiles[i].f.visible = False
del missiles[i]
#if m <> None:
# m.move_xz()
if scene.kb.keys: # event waiting to be processed?
s = scene.kb.getkey() # get keyboard info
if s == 'left':
turn = turn + 0.01
if s == 'right':
turn = turn - 0.01
if s == 'up':
speed = speed + 0.01
if s == 'down':
speed = speed - 0.01
if s == ' ':
if turn <> 0:
turn = 0
elif speed <> 0:
speed = 0
#fire missile
if s == 'a':
missiles.append(missile(ss.f.axis, ss.f.pos))
Next steps
Now that we’re cooking with charcoal — we have a functioning program — the next steps will be setting up a target to shoot at, and, if the students are ready, letting them program their ships to move autonomously. If they’re not ready then, as an example, I’ll program some opposition.
![Rendered by QuickLaTeX.com \left[ \begin{array}{ccc} 1 & -2 & 1 \\ 0 & 1 & 2 \\ 2 & 3 & -2 \end{array} \right] \left[ \begin{array}{c} x \\ y \\ z \end{array} \right] = \left[ \begin{array}{c} -4 \\ 4 \\ 2 \end{array} \right]](https://MontessoriMuddle.org/wp-content/ql-cache/quicklatex.com-d7c93a4faec058d3b5dda1831bdeaca7_l3.png)
![Rendered by QuickLaTeX.com \left[ \begin{array}{cccc} 1 & -2 & 1 & -4 \\ 0 & 1 & 2 & 4\\ 2 & 3 & -2 & 2\end{array} \right]](https://MontessoriMuddle.org/wp-content/ql-cache/quicklatex.com-d2316bca341c565fbeab22075f4e2d73_l3.png)






















