Csci 1020 February 13, 2023 Program Assignment 6

Write a GUI which demonstrates some sort of game or situation with figures or images moving within a canvas.

You should first get the sample p6.py program working, and study the code. You must import the correct sound library and the correct code for your machine: mac, windows, or linux. Make sure that you copy the 3 cat files and the boing sound .wav file, and put these with p6.py sample code in a directory.

Three cats are moved around the canvas using a random number generator. When any two images get too close (within 50 pixel units), the sound plays, and the cats go back to their corners and restart.

Here are some things you could do.

  1. Show a ball moving around a hole, a goal, a catcher's mitt, whatever. Play the sound then reset when the ball gets close enough to count as a score.
  2. Show people walking around, and they say "pardon me" when they get too close, then they jump to a position a proper distance apart.
  3. Play freeze tag, or some modification of freeze tag..

That list above is not a limitation, just some thoughts. Your program must do this:

Here are the links to the sample code and needed files:

directory with all source files

p6sample.py

cat1.gif

cat2.gif

cat3.gif

boing_spring.wav

p6sampleb.py

meow2.wav


The sample p6 program introduces several new things. One is a class. We will study classes separately and later, but it is something to talk about now with canvas because you have been using them already.

class HeadClass:
   pass

This above creates a new class HeadClass, and it will hold all the information about each cat object: x, y, dx, dy, and image.

head = []
ncats = 3

This above creates an empty list head which will hold cat objects, and there will be ncats of them in the list (3).

x = [30,Cwidth-30, 30]
y = [30,Cheight-30, Cheight-30]
dx = [1,-1, 1]
dy = [1,-1,-1]

cat1 = PhotoImage(file='cat1.gif')
cat2 = PhotoImage(file='cat2.gif')
cat3 = PhotoImage(file='cat3.gif')

cats = [cat1,cat2,cat3]

Above the information for each cat is put in a list, 3 values for x, y, dx, dy, and cats.

for i in range(ncats):
   h = HeadClass()   # create an object
   h.x = x[i]        # x position
   h.y = y[i]        # y position
   h.dx = dx[i]      # x motion
   h.dy = dy[i]      # y motion
   h.cim = C.create_image(x[i],y[i],image=cats[i]) # place the head on Canvas
   head.append(h)

Above the lists are used to initialize h which is type HeadClass, and after each h is initialized, it is loaded into the list head. After this loop runs, head contains the information about each cat: head[0], head[1], and head[2]. Note that the indices start at 0 and go up to 2 for ncats=3.

The for loop loops 3 times. range(ncats) creates a list which is [0,1,2] in this case because ncats=3, then for each element of the list, i is set to that value and the instructions in the for loop are executed. Thus, this section loops three times with i=0, i=1, and i=2, and i corresponds to the position in x, y, dx, dy, and cats lists.

def runit():
   global running,x,y,dx,dy
   running = True # set True on entry
   while running==True:
      for k in range(ncats):
         for j in range(ncats):
            if(j==k): continue # skip
            if( (head[k].x-head[j].x)**2 + (head[k].y-head[j].y)**2 < 50**2):
               play_sound("boing_spring.wav")
               for i in range(ncats):
                  C.move(head[i].cim,x[i]-head[i].x,y[i]-head[i].y)
                  head[i].x = x[i]
                  head[i].y = y[i]
               W.update()
               continue
         head[k].dx += random.choice([-1,1])
         head[k].dy += random.choice([-1,1])
         if(head[k].dx < -4): head[k].dx = -4
         if(head[k].dx >  4): head[k].dx =  4
         if(head[k].dy < -4): head[k].dy = -4
         if(head[k].dy >  4): head[k].dy =  4
         if head[k].x <= 10 and head[k].dx<0: 
            head[k].dx = -head[k].dx
         elif head[k].x >= Cwidth-10 and head[k].dx>0: 
            head[k].dx = -head[k].dx
         if head[k].y <= 10 and head[k].dy<0: 
            head[k].dy = -head[k].dy
         elif head[k].y >= Cheight-10 and head[k].dy>0: 
            head[k].dy = -head[k].dy
         head[k].x = head[k].x + head[k].dx
         head[k].y = head[k].y + head[k].dy
         C.move(head[k].cim,head[k].dx,head[k].dy)
         W.update()
         sleep(.005)

Above is the loop which runs when the Run button is pressed. The variable "running" is set to be true, and while running==True, the while loop keeps running, over and over endlessly.

There is another for loop whithin the while loop, for k in range(ncats). This checks each cat object. The for j in range(ncats) loop, also checks each other cat, and this is examined below.

         for j in range(ncats):
            if(j==k): continue # skip
            if( (head[k].x-head[j].x)**2 + (head[k].y-head[j].y)**2 < 50**2):
               play_sound("boing_spring.wav")
               for i in range(ncats):
                  C.move(head[i].cim,x[i]-head[i].x,y[i]-head[i].y)
                  head[i].x = x[i]
                  head[i].y = y[i]
               W.update()
               continue

Above, the distance between cats is calculated using the Pythagorean theorem, and if the distance is less than or equal to 50, a sound is played, then each cat position is reset to its original x, y position, then each cat image is moved to its original x, y position. The W.update() comand redraws the Canvas, and this should be done after a move or an object is placed on the Canvas so that it shows immediately. The continue command exits the for loop.

         head[k].dx += random.choice([-1,1])
         head[k].dy += random.choice([-1,1])
         if(head[k].dx < -4): head[k].dx = -4
         if(head[k].dx >  4): head[k].dx =  4
         if(head[k].dy < -4): head[k].dy = -4
         if(head[k].dy >  4): head[k].dy =  4
         if head[k].x <= 10 and head[k].dx<0: 
            head[k].dx = -head[k].dx
         elif head[k].x >= Cwidth-10 and head[k].dx>0: 
            head[k].dx = -head[k].dx
         if head[k].y <= 10 and head[k].dy<0: 
            head[k].dy = -head[k].dy
         elif head[k].y >= Cheight-10 and head[k].dy>0: 
            head[k].dy = -head[k].dy
         head[k].x = head[k].x + head[k].dx
         head[k].y = head[k].y + head[k].dy
         C.move(head[k].cim,head[k].dx,head[k].dy)
         W.update()
         sleep(.005)

Several things happen above. A random number, -1 or 1, is selected and added to the motion dx and dy. The motion speed dx and dy are kept between -4 and 4 by testing. We want cat heads to stay within the Canvas, so motion is reversed if the position is within 10 units of an edge. The C.move command moves the image. We update the Canvas with C.update(). The sleep(.005) function stops the program for .005 seconds. You can adjust this value. If the sleep value is too low, cat heads may move too fast to see.


Some changes are easier to make than others. You need your own images and a sound, and the images must be type .gif and the sound type .wav . (Use .gif and .wav in order to be portable.) You can change the canvas size and background color. You can reduce or increase the number of objects to place and move on the Canvas, and you only need to move one object.

For a simpler start, you can work with the single-cat-and-litter-box program here:

p6simple.py

litter_box.gif

cat1.gif

boing_spring.wav


Content is neither approved nor reviewed by FDLTCC.