Artillery Game

BuildItsProgramming
This is a basic artillery game I wrote in python.  There are still some minor issues I need to fix, but it works and is playable.  It includes wind, movement, and variable-height (but not shape) terrain.





Here is the code:




from tkinter import *

from sys import getfilesystemencoding

import time

import random

import math


height = 600

width = 800

global t, Vo, P1Vo, P2Vo, P1A, P2A, counter,wind,active

Vo=0

t=0

Angle=0

counter=2

P1Vo=0

P1A=0

P2Vo=0

P2A=0

wind=0

active=False


##


def windspeed():

   global wind

   x=0

   for i in range(4):

      x+=random.randint(-20,20) 

   wind=x//4

   return wind


canvas = Canvas(highlightthickness=0, height=height, width=width, )

canvas.master.title("Artillery")

if getfilesystemencoding() == 'utf-8':       # only for mac

   canvas.master.call('console', 'hide')

canvas.pack()


canvas.create_rectangle(0,600,800,590,fill='green', outline='green', tag = 'ground')




class missile():

   "blows junk up"

   def __init__(self,power=Vo,angle=Angle, start=0,y=590, direction='right'):

      global t


      self.power=power

      self.angle=angle

      self.x=start

      self.y=y

      self.d=direction

      self.id = canvas.create_oval(self.x,self.y,self.x+5,self.y-5,fill='red')

   def trajectory(self,start, starty):

      "calculates the position of the missile"

      global t

      #canvas.coords(self.id,self.x,self.y,self.x+5,self.y-5)

      #canvas.create_oval(self.x,self.y,self.x+1,self.y-1)

      if self.d=='right':

         self.x=int((self.power*t*math.cos(self.angle))//1)+start

      else:

         self.x=int(-((self.power*t*math.cos(self.angle))//1))+start

      self.y=int((-(((-9.8*(t**2))//2) + (self.power*math.sin(self.angle)*t)//1))+starty)

      canvas.coords(self.id,self.x,self.y,self.x+5,self.y-5)


      t+=.005

      

class tank():

   "shoots some missiles"

   def __init__(self, pos=50,health=100,movement=100, side=10,):

      self.pos=pos

      self.side=side

      self.health=health

      self.pic=canvas.create_rectangle(self.pos, 590, self.pos+20, 580)

      self.display_health()

      self.movement=movement

      self.display=canvas.create_text(self.side+50, 50, text=(self.movement))

      self.barrel_r()

   def display_health(self):

      "displays the tank's health bar"

      self.x=canvas. create_rectangle(self.side, 20, self.side+self.health, 23, fill='red')

   def move_left(self):

      global Angle

      canvas.coords(self.pic, self.pos-2, 590, self.pos+18, 580)

      canvas.update()

      self.movement-=1

      self.pos-=2

      a_up(Angle/.0174532925)

      self.display_mov()

   def move_right(self):

      canvas.coords(self.pic, self.pos+2, 590, self.pos+22, 580)

      canvas.update()

      self.movement-=1

      self.pos+=2

      a_up(Angle/.0174532925)

      self.display_mov()

   def display_mov(self):

      "displays the amount of movement left"

      canvas.delete(self.display)

      self.display=canvas.create_text(self.side+50, 50, text=(self.movement))

   def barrel_r(self):

      global Angle

      self.b=canvas.create_line(self.pos+10, 580, 15*math.cos(Angle)+self.pos+10, 580- 15*math.sin(Angle))

      self.tip=(15*math.cos(Angle)+self.pos+10)

      self.y=(580- 15*math.sin(Angle))

      canvas.update()

   def barrel_l(self):

      global Angle

      self.b=canvas.create_line(self.pos+10, 580, 15*math.cos(Angle-(math.pi))+self.pos+10, 580- 15*math.sin(Angle))

      self.tip=(15*math.cos(Angle-(math.pi))+self.pos+10)

      self.y=(580- 15*math.sin(Angle))

      canvas.update()


class terrain():

   "a hill that is placed in the middle of the map"

   def __init__(self):

      height=random.randint(50,600)

      self.shape=canvas.create_polygon(100, 600+height, 250, 200+height, 300, 250+height,400, 0+height, 700, 600+height, fill='green')



hill=terrain()



      

wind=windspeed()

z=canvas.create_text(400,20,text=('Wind Speed: %.2d') %(wind))



tank1=tank()

tank2=tank(pos=720, side=690)


def shoot(tank, p, a):

   "animates the missile, along with lots of other stuff"

   global t,counter, P1Vo, P2Vo, P1A, P2A, Angle, Vo, tank1, tank2,wind,z,active,text, hill

   active=True

   if counter %2 ==0:

      tank=tank2

      target=tank1

   else:

      tank=tank1

      target=tank2    

   if tank==tank1:

      d='right'

   else:

      d='left'

   

   x=missile(power=p,angle=a,start=tank.tip+1, y=tank.y-3, direction=d)

   while True:

      x.x+=int((wind*t**2)/5)


      x.trajectory(start=tank.tip, starty=tank.y)


      hit=target.pos

      if (hit<= x.x <= hit+20) and 590>=x.y>=580:

         target.health-=20

         print (target.health)

         t=0

         canvas.delete(x.id)

         counter+=1

         tag=target.x

         canvas.delete(tag)

         target.display_health()

         if target.health==0:

            if target==tank1:

               player='Player 1'

            else:

               player='Player 2'

            text=canvas.create_text(400,300, text=("%s wins") % (player))

            

            canvas.update()

            break 

         break

         

      elif x.y>600 or x.x>800 or x.x<0:

         t=0

         canvas.delete(x.id)

         counter+=1

         break

      elif hill.shape in (canvas.find_overlapping(x.x, x.y, x.x+5, x.y-5)):

         canvas.delete(x.id)

         t=0

         counter+=1

         break


      time.sleep(.001):

      canvas.update()


   if counter % 2 == 0:

      p_adjuster.set(P1Vo)

      a_adjuster.set(P1A/.0174532925)


   else:

      p_adjuster.set(P2Vo)

      a_adjuster.set(P2A/.0174532925)

   wind=windspeed()

   canvas.delete(z)

   z=canvas.create_text(400,20,text=('Wind Speed: %.2d') %(wind))

   active=False





  

def keypress(event):

   global tank1, Vo, Angle, counter, P1A, P2A, P1Vo, P2Vo,active


   if not active:

      if event.keysym=="space":

         if counter % 2 == 0:

            Angle=P1A

            Vo=P1Vo

         else:

            Angle=P2A

            Vo=P2Vo


         shoot(tank1, Vo, Angle)

   if event.keysym=='Right':

      if counter %2 ==0: 

         tank=tank2

      else:

         tank=tank1

      if tank.movement > 0 and tank.pos<778:

         tank.move_right()

      else:

         pass


   elif event.keysym=='Left':

      if counter %2 ==0:

         tank=tank2

      else:

         tank=tank1

      if tank.movement > 0 and 0<tank.pos:

         tank.move_left()

      else: 

         pass


def retry(event):

   global  tank1, tank2,text,counter, P1Vo, P2Vo, P1A, P2A, hill

   counter=2

   canvas.delete(text)

   canvas.delete(tank1.pic)

   canvas.delete(tank2.pic)

   canvas.delete(tank1.b)

   canvas.delete(tank2.b)

   canvas.delete(tank1.x)

   canvas.delete(tank2.x)

   canvas.delete(tank1.display)

   canvas.delete(tank2.display)

   canvas.delete(hill.shape)

   hill=terrain()

   P1Vo, P2Vo, P1A, P2A=0, 0, 0, 0

   tank1.health=100

   tank2.health=100

   tank1=tank()

   tank2=tank(pos=720, side=690)

   p_adjuster.set(0)

   a_adjuster.set(0)




def p_up(x):

   global Vo, Angle,counter, P1Vo, P2Vo

   if counter % 2 == 0:

         P1Vo=int(x)

         Vo=P1Vo

   else:

         P2Vo=int(x)

         Vo=P2Vo

def a_up(x):

   global Vo,Angle,counter, P1A, P2A, tank1, tank2

   if counter % 2 == 0:

         P1A=int(x)*.0174532925

         Angle=P1A

         tank=tank2

         canvas.delete(tank.b)

         tank.barrel_l()

   else:

         P2A=int(x)*.0174532925

         Angle=P2A

         tank=tank1

         canvas.delete(tank.b)

         tank.barrel_r()

   



p_adjuster = Scale(canvas.master, length=400, orient=HORIZONTAL, command=p_up, from_=0, to=200, label="Power")

p_adjuster.pack(side=LEFT)

a_adjuster = Scale(canvas.master, length=400, orient=HORIZONTAL, command=a_up, from_=0, to=90, label = "Angle" )

a_adjuster.pack(side=RIGHT)

x

     

canvas.master.bind("<Key>", keypress)

canvas.master.bind("<Key-Return>", retry)



####




canvas.mainloop()





In order to run the game at a reasonable speed, it may be necessary to adjust the numbers in line 64:

"t+=.005"

or line 183:

"time.sleep(.001):"

To play, you can move your tank with the arrow keys, and press space bar to fire.  Power and angle are adjusted with the sliders.