|
From: John K. <joh...@ho...> - 2003-02-11 19:37:24
|
Here's the actual code for "Shoot the Monkey," in case you have problems
getting it off the web.
JK
# The classic Shoot-the-Monkey Demo
# John W. Keck, February 2003
# American University
#
# camera direction still jerky:
# should monkey be the center?
from visual import *
# define exx marker
newframe = frame
class exx(object):
def __init__(self, frame=None, pos=(0,0,0), axis=(1,0,0),
color=(1.0,0.5,0)):
self.frame = newframe(pos=pos, axis=axis, frame=frame)
self.__pos = vector(pos)
self.__axis = vector(axis)
self.__color = color
# self.parts =
box(frame=self.frame,axis=(1,1,0),size=(2,0.2,1),color=self.__color)
box(frame=self.frame,axis=(1,-1,0),size=(2,0.2,1),color=self.__color)
def getpos(self):
return self.__pos
def setpos(self, pos):
self.frame.pos = self.__pos = vector(pos)
pos = property(getpos, setpos)
def getaxis(self):
return self.__axis
def setaxis(self, axis): # scale all points in front face
self.frame.axis = self.__axis = vector(axis)
length = mag(self.__axis)
axis = property(getaxis, setaxis)
def getcolor(self):
return self.__color
def setcolor(self, color):
self.__color = color
self.faces.color = color
color = property(getcolor, setcolor)
#-----------------------------------------------------------------------
# set defaults and initial parameters
color.orange = (1,0.5,0)
color.brown = (0.46,0.28,0.10)
v0 = 30.0 # default ball speed
mkht = 135 # default monkey height
ballpos = vector(-45,10,0) # default ball position
dt = 0.01 # time increment for action calculation
#-------------------------------
mkpos = (47,mkht,0)
scene = display(title="Shoot the Monkey", center=mkpos, ambient = 0.4, x=0,
y=0, width=500,height=500)
rt = int(1/dt) # limiting rate of action loop
first = 1 # first run flag
while 1:
#----------------------------------------------------------------------
#SET THE STAGE
mkpos = vector(47,mkht,0)
scene.center = mkpos
#set up the environment
floor = box (pos=(10,0,0), size=(110,0.5,6), color=color.green,
opacity=0.5) #length=110, height=0.5, width=6, color=color.green)
tree = cylinder(pos=(60,0,0), axis=(0,mkht,0), radius=3,
color=(0.7,0.7,0.3))
branch = cylinder(pos=(60,mkht-17,0), axis=(-12,30,0), radius=2,
color=(0.7,0.7,0.3))
# power bar for selecting velocity
# pinstr = frame()
i = 0
while i < 5:
pwr0 = box(pos=(-55,i*20+5,-10), size=(4.9,10,4.9),
color=(0.8,0.8,0.5))
## label(frame=pinstr,text=str(i*20), pos=(i*20,0,10), height=8)
pwr1 = box(pos=(-55,i*20+15,-10), size=(4.9,10,4.9),
color=color.yellow)
i += 1
## label(frame=pinstr,text=str(i*20), pos=(i*20,0,10), height=8)
## pinstr.pos = (-62,0,0)
## pinstr.axis = (0,1,0)
## pinstr.visible = 0
power1 = box(pos=(-55,v0/2,-10), size=(5,v0,5), color=color.red)
pwr = label(pos=(-62,v0,0), height=12, visible=1)
pwr.text = '%0.1f' % (v0)
#the monkey
# mkcolor = (1,0.7,0.2)
mkcolor = color.brown
monkey = frame()
sphere(frame=monkey, pos=(1,0,0),radius=2,color=mkcolor) #head
sphere(frame=monkey, pos=(0.6,0,-1.9),radius=1.2,color=(1,0.8,0.5))
#snout
sphere(frame=monkey, pos=(1.5,0.12,-2.3),radius=0.2,color=color.black)
#nostrils
sphere(frame=monkey, pos=(1.5,-0.12,-2.3),radius=0.2,color=color.black)
ring(frame=monkey,
pos=(0.7,0,-2.2),axis=(2,0,-1),radius=0.9,thickness=0.2,color=color.black) #
mouth
eang0 = 65*pi/180
eang1 = 20*pi/180
sphere(frame=monkey,
pos=(1+1.5*cos(eang0),1.5*sin(eang0)*sin(eang1),-1.5*sin(eang0)*cos(eang1)),radius=0.6,color=(0.9,0.9,0.9))
#eyes
sphere(frame=monkey,
pos=(1+1.5*cos(eang0),-1.5*sin(eang0)*sin(eang1),-1.5*sin(eang0)*cos(eang1)),radius=0.6,color=(0.9,0.9,0.9))
#eyes
eang0 = 67*pi/180
eang1 = 19*pi/180
sphere(frame=monkey,
pos=(1+2.02*cos(eang0),2.02*sin(eang0)*sin(eang1),-2.02*sin(eang0)*cos(eang1)),radius=0.2,color=color.black)
#eyes
sphere(frame=monkey,
pos=(1+2.02*cos(eang0),-2.02*sin(eang0)*sin(eang1),-2.02*sin(eang0)*cos(eang1)),radius=0.2,color=color.black)
#eyes
## eang0 = 70*pi/180
## eang1 = 90*pi/180
## cone(frame=monkey,
pos=(1+2.3*cos(eang0),2.3*sin(eang0)*sin(eang1),-2.3*sin(eang0)*cos(eang1)),axis=(-0.5*cos(eang0),-0.5*sin(eang0)*sin(eang1),0.5*sin(eang0)*cos(eang1)),radius=0.3,color=mkcolor)
## cone(frame=monkey,
pos=(1+2.3*cos(eang0),-2.3*sin(eang0)*sin(eang1),-2.3*sin(eang0)*cos(eang1)),axis=(-0.5*cos(eang0),0.5*sin(eang0)*sin(eang1),0.5*sin(eang0)*cos(eang1)),radius=0.3,color=mkcolor)
cylinder(frame=monkey, pos=(-6,0,0), axis=(5,0,0), radius=2,
color=mkcolor) #body
monkey.pos = mkpos
monkey.axis = (0,1,0)
monkey.velocity = vector(0,0,0)
monkey.trail = curve(color=mkcolor)
monkey.mass = 5
#the ball
ball = sphere (pos=ballpos, radius=1, color=(0.4,0.9,1))
ball.mass = 1
ball.trail = curve(color=ball.color)
bpos = label(pos=ballpos, visible=0)
bpos.text = '%0.1f, %0.1f' %(ball.pos.x, ball.pos.y)
# take aim
aim = curve(pos=[ball.pos,monkey.pos+monkey.axis], color=(0.9,0.7,0.7))
dist = mag(ball.pos-monkey.pos)
cx = (monkey.x - ball.x)/dist
cy = (monkey.y - ball.y)/dist
ball.velocity = vector(v0*cx,v0*cy,0)
vel = arrow(pos=ball.pos, axis=ball.velocity/4, shaftwidth=1,
fixedwidth=1, color=color.yellow)
masstot = ball.mass + monkey.mass
# TEXT INSTRUCTIONS
print
print "======================================"
print "Shoot-the-Monkey Physics Demonstration"
print "Written by John W. Keck 2003"
if first:
instr = label(text='Answer question in text\nwindow to continue.',
pos=scene.center+vector(0,scene.range.y,0), height=12)
print
print "Consider the situation depicted here. A gun is accurately
aimed at a monkey"
print "hanging from a tree. The target is well within the gun's
range, but the"
print "instant the gun is fired and the bullet moves with a speed
v0, the monkey"
print "lets go and drops to the ground. What happens? The bullet"
print
print "1. hits the monkey regardless of the value of v0, as long as
he doesn't"
print " hit the ground first."
print "2. hits the monkey only if v0 is large enough for the bullet
to reach"
print " him before he falls much more than the length of his
body."
print "3. misses the monkey entirely."
print
# comment out the following line if it gets annoying
answer = input("Which (1-3)?")
print
print "Try shooting the ball at difference speeds from various
places"
print "to discover the answer."
print
print "At 1-second intervals, the computer will plot measures
showing"
print "how far each body has fallen."
first = 0
instr.visible = 0
while scene.mouse.events: xx = scene.mouse.getevent() # clear mouse
buffer
print
print "=== INSTRUCTIONS ==="
print "Drag Ball to position Ball"
print "Drag power bar at left to change initial velocity"
print "Drag tree to position Monkey"
print "Click background to FIRE"
print
#----------------------------------------------------------------------
# AIMING STAGE
pick = None
go = 1
while go:
if scene.mouse.events:
m1 = scene.mouse.getevent() # obtain drag or drop event
if m1.drag and m1.pick == ball:
drag_pos = m1.pickpos
pick = m1.pick
scene.cursor.visible = 0 # make cursor invisible
elif m1.drop:
pick = None # end dragging
scene.cursor.visible = 1 # cursor visible
if m1.drag and m1.pick == power1:
drag_pos = m1.pickpos
pick = m1.pick
scene.cursor.visible = 0 # make cursor invisible
elif m1.drop:
pick = None # end dragging
scene.cursor.visible = 1 # cursor visible
if m1.drag and m1.pick == tree:
drag_pos = m1.pickpos
pick = m1.pick
scene.cursor.visible = 0 # make cursor invisible
elif m1.drop:
scene.center = monkey.pos # jerky, but workable
pick = None # end dragging
scene.cursor.visible = 1 # cursor visible
if scene.mouse.clicked:
m = scene.mouse.getclick()
print "FIRE!"
go = 0
if pick==ball:
new_pos = scene.mouse.project(normal=(0,0,1))
if new_pos != drag_pos:
pick.pos += new_pos - drag_pos
drag_pos = new_pos
dist = mag(ball.pos-monkey.pos)
cx = (monkey.x - ball.x)/dist
cy = (monkey.y - ball.y)/dist
ball.velocity = vector(v0*cx,v0*cy,0)
vel.axis = ball.velocity/4
vel.pos = ball.pos
aim.pos = [ball.pos,monkey.pos+monkey.axis]
if pick==power1:
new_pos = scene.mouse.project(normal=(0,0,1))
if new_pos != drag_pos:
pick.height += new_pos.y - drag_pos.y
v0 = pick.height
if v0 > 100:
v0 = 100
if v0 < 0:
v0 = 0
pick.height = v0
ball.velocity = vector(v0*cx,v0*cy,0)
vel.axis = ball.velocity/4
vel.pos = ball.pos
power1.y = v0/2
pwr.pos=(-62,v0,0)
pwr.text = '%0.1f' % (v0)
drag_pos = new_pos
if pick==tree:
new_pos = scene.mouse.project(normal=(0,0,1))
if new_pos != drag_pos:
pick.axis.y += new_pos.y - drag_pos.y
h = pick.axis.y
if h > 300:
h = 300
if h < 17:
h = 17
pick.axis.y = h
# pick.y = 0
monkey.pos.y = h
# scene.center = monkey.pos # makes it hard to control
branch.pos.y = h - 17
dist = mag(ball.pos-monkey.pos)
cx = (monkey.x - ball.x)/dist
cy = (monkey.y - ball.y)/dist
ball.velocity = vector(v0*cx,v0*cy,0)
vel.axis = ball.velocity/4
vel.pos = ball.pos
aim.pos = [ball.pos,monkey.pos+monkey.axis]
drag_pos = new_pos
print "Initial velocity = %0.2f m/s at %0.2f degrees"
%(v0,atan(cy/cx)*180/pi)
print "Initial position = (%0.2f, %0.2f)" % (ball.x,ball.y)
ballpos.x = ball.pos.x #save for next time round
ballpos.y = ball.pos.y
mkpos.y = monkey.pos.y
# mkpos0.y = mkpos.y
# find params of line that ball would have travelled without gravity
slope = (ball.pos.y-monkey.pos.y)/(ball.pos.x-monkey.pos.x)
yint = ball.pos.y - slope*ball.pos.x
sphere(pos=monkey.pos,color=color.orange,radius=1.0)
# pwr.visible = 0
# clear mouse event buffer
while scene.mouse.events:
xx = scene.mouse.getevent()
#----------------------------------------------------------------------
# ACTION STAGE
#aim.visible = 0
g = 9.8
t = 0
relvel0 = vector(0,0,0)
bpos0 = ball.pos
go = 1
nohit = 1
b1 = 0
d0 = 0.5*g # standard distance (same for both Monkey and Ball)
while go or nohit:
rate (rt)
# change ball and monkey positions and velocities for free fall
ball.velocity.y -= g*dt
ball.pos += ball.velocity*dt
monkey.velocity.y -= g*dt
monkey.pos += monkey.velocity*dt
scene.center = monkey.pos
if monkey.x > tree.x-tree.radius-1:
ball.velocity.x = -0.8*ball.velocity.x
if ball.x > monkey.x + 10:
go = 0
nohit = 0
if monkey.y <= 6 :
go = 0
# leave trails and show ball's velocity vector
vel.pos = ball.pos
vel.axis = ball.velocity/4
ball.trail.append(pos=ball.pos)
if not nohit: monkey.trail.append(pos=monkey.pos+monkey.axis/2)
# print t,fmod(t,1)
# plot measurement bars to show how fall objects have fallen
# (The distances don't exactly fall on perfect squares because
# of the limited precision of the calculation;
# as dt -> 0, results improve.)
t += dt
if t>(1.0-dt) and nohit:
projy = slope*ball.x + yint
projpos = vector(ball.x, projy, 0)
sphere(pos=mkpos,color=color.orange,radius=1.0)
sphere(pos=projpos,color=color.orange,radius=1.0)
exx(pos=ball.pos)
d = (projy - ball.pos.y)
xx = d/d0/2
i = 0
while i<xx:
b = projpos-vector(0,2*i*d0,0)
b2 = mkpos-vector(0,2*i*d0,0)
curve(pos=[b,b-vector(0,d0,0)],color=color.orange)
curve(pos=[b2,b2-vector(0,d0,0)],color=color.orange)
if (2*i+1)*d0<d:
curve(pos=[b-vector(0,d0,0),b-vector(0,2*d0,0)],color=(0.5,0,0.5))
curve(pos=[b2-vector(0,d0,0),b2-vector(0,2*d0,0)],color=(0.5,0,0.5))
i += 1
# curve(pos=[projpos,ballpos],color=color.orange)
## sphere(pos=monkey.pos,color=color.orange,radius=1.0)
exx(pos=monkey.pos)
t = 0
b1 += 1
# monkey-ball collision
if nohit and (ball.x > monkey.x-2 and ball.x < monkey.x+2) and
(ball.y > monkey.y-5 and ball.y < monkey.y+2):
relvel = mag(monkey.velocity - ball.velocity)
print "BLAM! Ball hits Monkey at %0.2f m/s" % (relvel)
print
print "Notice how the Monkey and the Ball"
print "fell equal distances in equal time intervals."
# perfectly inelastic collision
ball.velocity.x = (ball.mass*ball.velocity.x +
monkey.mass*monkey.velocity.x)/masstot
ball.velocity.y = (ball.mass*ball.velocity.y +
monkey.mass*monkey.velocity.y)/masstot
monkey.velocity = ball.velocity
nohit = 0
# pause option
if scene.mouse.clicked:
m = scene.mouse.getclick()
instr = label(text=' --PAUSED--\nClick to continue',
pos=scene.center, height=12)
m = scene.mouse.getclick()
instr.visible = 0
# wait for user before going back to beginning
while scene.mouse.events: xx = scene.mouse.getevent() # clear mouse
buffer
instr = label(text=' ---DONE---\nClick to re-run', pos=scene.center,
height=12)
m = scene.mouse.getclick()
for obj in scene.objects:
obj.visible = 0
_________________________________________________________________
Help STOP SPAM with the new MSN 8 and get 2 months FREE*
http://join.msn.com/?page=features/junkmail
|