#!/usr/bin/env python # monstertron basic setup. By Chuck Liang. ########### # The object of the this game is to capture all the diamonds while avoiding # the monsters. You also have can fire up to three energy bombs at a time, # which will momentarily freeze the monsters. # The variables that control the game are: # px, py, pdx, pdy, prad: these variables control the position, movement, # and radius of the "professor" representing the human player. # BX, BY, BDX, BDY, BSTATE, Brad: vectors that control the bombs/bolts. # The BSTATE vector controls whether a bomb is active. ## The above variables are global: they are accessed and modified by both the # the keyhandler and the mydraw function, which contains the main animation # loop. ## The follwing variables, however, are all local within mydraw: # m, MX, MY, MDX, MDY, MF : these vectors control the monsters. m is the # number of monsters. MF is the freeze state. When zero, monster can move # speed: controls speed that the human moves. Monsters move at approximately # the same speed, but there is a randomness to the Monsters' movements. ## Some of these variables are global because they have to be set by the ## keyboard event handler. ########### import pygtk import gtk import gobject import time import threading from random import randint import pango width,height = 900,700 delaytime = 80 # 100ms delay between animation frames window = gtk.Window(gtk.WINDOW_TOPLEVEL) window.set_title("Monstertron by Chuck Liang") window.connect("destroy", lambda w: gtk.main_quit()) area = gtk.DrawingArea() area.set_size_request(width,height) window.resize(width,height) window.add(area) window.show_all() gc0 = area.window.new_gc() cmap = gc0.get_colormap() # common colors green = cmap.alloc_color(red=0,green=65535,blue=0) blue = cmap.alloc_color(red=0,green=0,blue=65535) red = cmap.alloc_color(red=65535,green=0,blue=0) white = cmap.alloc_color("white") black = cmap.alloc_color("black") gray = cmap.alloc_color("gray") yellow = cmap.alloc_color("yellow") purple = cmap.alloc_color("purple") gc0.set_foreground(green) gc0.set_background(blue) gc0.line_width = 1 # double buffering setup dbuf = gtk.gdk.Pixmap(area.window,width,height,-1) gc1 = dbuf.new_gc() gc1.set_colormap(cmap) ### Thread control syn = threading.Event() # throttles mainloop syn2 = threading.Event() # throttles user thread syn.clear() syn2.clear() stopall = False # for cleanup class MyThread ( threading.Thread ): def __init__(self,brush,gc): self.win = brush self.dgc = gc threading.Thread.__init__(self) def run ( self ): global mydraw mydraw(self.win,self.dgc) eehandler = 0 def area_expose_cb(area, event): global mainloop,eehandler my = MyThread(dbuf,gc1) my.start() # start student thread, which calls mydraw area.handler_block(eehandler) # prevent restart when window moved. mainloop(area.window) # start main animation refresh cycle return True # get ready for expose event eehandler = area.connect("expose_event", area_expose_cb) # animation refresh control loop: def mainloop(brush): if not stopall: syn.wait() # wait for permission to refresh screen syn.clear() # reset for next round brush.draw_drawable(gc0,dbuf,0,0,0,0,width,height) # refresh syn2.set() # informs user thread to goto next iteration eid = gobject.timeout_add(delaytime, mainloop, brush) # reschedule return False # end mainloop def updateDisplay(): syn.set() # release mainloop to refresh screen syn2.wait() # synch with mainloop before looping again syn2.clear() # reset for next round # end updateDisplay def cleanup(): global stopall stopall = True syn.set() syn2.set() # end cleanup ####################### Your code goes below: ############################ ########################################################################## def drawcircle(brush,gc,x,y,radius,fill): brush.draw_arc(gc,fill,x-radius,y-radius,2*radius,2*radius,0,360*64) # draws text with given font such as "normal bold 24" (see sample call below) def drawtext(brush,gc,x,y,font,text): layout = area.create_pango_layout(text) layout.set_font_description(pango.FontDescription(font)) brush.draw_layout(gc,x,y,layout) # end drawtext # distance: def dist(x1,y1,x2,y2): dx = x1-x2 dy = y1-y2 return (dx*dx + dy*dy)**0.5 # detect collision between two circles def collide(x1,y1,r1,x2,y2,r2): d = dist(x1,y1,x2,y2) return d<=(r1+r2) # collide # make sure coordinates stay within width, height: def inbounds(x,y): if (x<15): x = width-15 if (x>(width-15)): x = 15 if (y<15): y = height-15 if (y>height-15): y = 15 return (x,y) # return the tuple x,y # end inbounds # movement vector of human figure: pdx,pdy = 0,0 # global values that can be altered with keystrokes px,py = width-200,200 # initial position pheight, pwidth = 0,0 # to be set later speed = 4 # default speed of monsters and professor # variables for bolts must be declared here b = 3 # max number of bolts BX = b*[0] BY = b*[0] BDX = b*[0] BDY = b*[0] BSTATE = b*[False] # false means bolt is not active. Brad = 4 # function to find first active bolt, -1 if none are active def active(BSTATE): ax = -1 i = 0 while i= 0): BSTATE[i] = True BX[i] = px+pwidth/2 BY[i] = py+pheight/2 BDX[i] = pdx + pdx # inherit movement of professor BDY[i] = pdy + pdy # but will be 100% faster if k==65365: # page up: speed up speed += 1 if k==65366: # page down: slow down speed -= 1 # print "key ",k," not recognized" # keyhandler # connects key-press event to calling the above function: keyhandler = window.connect("key_press_event", keyhandler) # main animation procedure MUST be called mydraw def mydraw(brush,gc): global BX, BY, BSTATE global px, py, pdx, pdy, pheight, pwidth # load animated gifs and set frame advance iter devices profan = gtk.gdk.PixbufAnimation("man15.gif") # monsteran = gtk.gdk.PixbufAnimation("head1.gif") monsteran = gtk.gdk.PixbufAnimation("gremlin1.gif") geman = gtk.gdk.PixbufAnimation("gem1.gif") effectan = gtk.gdk.PixbufAnimation("explode.gif") mwidth,mheight = monsteran.get_width(), monsteran.get_height() #gif size pwidth,pheight = profan.get_width(),profan.get_height() Prad = (pwidth+pheight)/4 - 4# approx radius of professor prof = profan.get_iter() monster = monsteran.get_iter() effect = effectan.get_iter() gem = geman.get_iter() # Set intial position of professor: # px,py = width-200,200 # pdx,pdy = 0,0 # These values are set externally # Set initial position and movement vector of monsters m = 4 # number of monsters MX = m*[0] MY = m*[0] MDX = m*[0] MDY = m*[0] MF = m*[0] # freez factor 0 means monster can move # radius value of all monsters is constant Mrad = (mwidth+mheight)/4 - 4 freeztime = 32 # number of frames monster will freez when hit with bolt i = 0 while iwidth-Brad or BY[i]height-Brad: BSTATE[i] = False i +=1 # while i: bolts # brush.draw_pixbuf(gc,gem.get_pixbuf(),0,0,gx,gy) px,py = px+pdx, py+pdy # move professor (px,py) = inbounds(px,py) # wraparounds brush.draw_pixbuf(gc,prof.get_pixbuf(),0,0,px,py) # draw prof prof.advance() # advance animated gifs to next frame: monster.advance() # gem.advance() # (gx,gy) = inbounds(gx,gy) c = c+1 if (caught): gc.set_foreground(yellow) drawtext(brush,gc,200,height/2,"sans bold 24", "Who You Gonna Call Now, Prof???!!!") # display new animation frame: updateDisplay() # end while # show explosion, messages to end game cleanup() # should be called after end of all animation # end mydraw ########################################################################## # The following line must be the last line in the program gtk.main()