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 |