Member Avatar for masterofpuppets

hi
currently I am developing a game in python called TankWar, it is basically 1vs1 game style and each player has its own turn. Both players control their respective tanks using the control keys and WASD and they can specify the missile's angle, velocity, tank position. I am using an equation to find the range of the missile and that works fine. The problem I am having is to design the projectile motion in parabola.
I know what the equation is but the missile is launched about 100 px above of the tank and I can't figure out why. Here's my code( sorry if you can't understand some parts ) i'll clarify if needed :)

# Designed by Georgi Christov ( a.k.a 8masterofpuppets8 )
# Last modified: 16.10.2009

from Tkinter import *
import time
import math

root = Tk(); root.geometry( "800x550+230+100" ); root.title( "TankCombat ( TM )" )
c = Canvas( root, width = 800, height = 400, bg = "white" ); c.pack()

# Variables and objects...
yGround = 350
border = c.create_rectangle( 3, 3, 797, 400, width = 2 )
ground = c.create_line( 0, yGround, 800, yGround )
x1, y1 = 150, yGround - 15
tank_1 = c.create_rectangle( 0, 0, 0, 0 )
tank1Cannon = c.create_line( 0, 0, 0, 0 ); angle1 = 30; missile1 = c.create_oval( 0, 0, 0, 0 )

initialSpeed = 70

############################################################################################################################################################
# Find the coordinates of a point given the angle, the length of the line and the starting coordinates
def end_x( x, d, a ):
    return x + math.sin( math.radians( a ) ) * d
def end_y( y, d, a ):
    return y - math.cos( math.radians( a ) ) * d
# Find the y position of the projectile given the x position, the angle, and the speed
def find_y( x, a, s ):
    first = x * math.tan( math.radians( a ) )
    second = ( 10 * ( x**2 ) / ( 2 * ( s**2 ) ) ) * ( 1 + ( math.tan( math.radians( a ) )**2 ) ) 
    return first - second

############################################################################################################################################################

def launchMissile( xpos, ypos, angle, speed ):
    global missile1
    rangeOfMotion = ( ( speed ** 2 ) / 10 ) * math.sin( math.radians( 2 * angle ) ) # This is the range of motion
    height = ( 1.0 / 20 ) * ( speed**2 ) * math.sin( math.radians( angle ) )**2 # Not sure if I need this

    xInc = xpos
    while xInc < xpos + rangeOfMotion:
        time.sleep( 0.04 )
        c.delete( missile1 )
        missile1 = c.create_oval( xInc, ypos - find_y( xInc, angle, speed ), xInc + 5, ypos - find_y( xInc, angle, speed ) + 5, fill = "black" )
        xInc += 5
        c.update()

def keyboard( event ):
    global x1, y1, angle1, initialSpeed
    
    if event.keysym == "Left":
        x1 -= 1
    elif event.keysym == "Right":
        x1 += 1
    elif event.keysym == "Up":
        if angle1 > 15:
            angle1 -= 1
    elif event.keysym == "Down":
        if angle1 < 85:
            angle1 += 1
    elif event.keysym == "space":
        launchMissile( x1, y1, 85 - angle1, initialSpeed ) 
        root.unbind( "<Any-KeyPress>" )  
    tankCombat()


def tankCombat():
    global yGround, tank_1, x1, y1, tank1Cannon, angle1, langle1

    langle1.place_forget(); langle1 = Label( root, text = "Current angle >> " + str( angle1 ) ); langle1.place( relx = 1, x = -780, y = 440 )
    
    c.delete( tank_1, tank1Cannon )
    tank_1 = c.create_rectangle( x1, y1, x1 + 30, y1 + 15, fill = "green" )
    tank1Cannon = c.create_line( x1 + 15, y1 + 7, end_x( x1 + 15, 15, angle1 ), end_y( y1 + 7, 15, angle1 ), width = 2 )


l1 = Label( root, text = "<< Player One Details >>", font = "Arial" ); l1.place( relx = 1, x = -750, y = 405 )
langle1 = Label( root, text = "Current angle >> " + str( angle1 ) ); langle1.place( relx = 1, x = -780, y = 440 )

tankCombat()
root.bind( "<Any-KeyPress>", keyboard )

mainloop()

This is until I figure out the proper algorithm after that I will add the second player and the other stuff :) all I need is a hint of what I am doing wrong... thx in advance!

I have no idea why your launching above your tank but you really should be using pygame to handle the graphics...

If you can't find any answers then build a projectile log that will log every position the shell has. With this you have a very good diagnostic tool plus you'll be able to tweak your physics...

Member Avatar for masterofpuppets

thanks a lot bro :)
i know it'll be easier with pygame though but i find it easier using tkinter. Anyway I think i fixed part of it, i.e now the position is correct but the parabola is reverse, i.e. negative for some reason. The code I fixed is this:

# Find the y position of the projectile given the x position, the angle, and the speed
def find_y( xp, yp, a, s, time ):
    y = ( -0.5 * 9.80 * ( time**2 ) ) + ( s * math.sin( math.radians( a ) ) * time ) + yp
    return y


def launchMissile( xpos, ypos, angle, speed ):
    global missile1
    rangeOfMotion = ( ( speed ** 2 ) / 10 ) * math.sin( math.radians( 2 * angle ) ) # This is the range of motion

    xInc, t = 0, 0
    while xInc < xpos + rangeOfMotion:
        time.sleep( 0.04 )
        xInc = speed * math.cos( math.radians( angle ) ) * t + xpos + 15
        c.delete( missile1 )
        missile1 = c.create_oval( xInc, find_y( xInc, ypos, angle, speed, t ), xInc + 5, find_y( xInc, ypos, angle, speed, t ) + 5, fill = "black" )
        t += 1
        c.update()

still working on it :) any suggestions welcome...

Member Avatar for masterofpuppets

I fixed it, finally. The problem was that I needed to find the height for each x and y position and subtract h * 2 from the y coordinate to get the actual parabola. Here's the working version:

# Designed by Georgi Christov ( a.k.a 8masterofpuppets8 )
# Last modified: 16.10.2009

from Tkinter import *
import time
import math

root = Tk(); root.geometry( "800x550+230+100" ); root.title( "TankCombat ( TM )" )
c = Canvas( root, width = 800, height = 400, bg = "white" ); c.pack()

# Variables and objects...
yGround = 350
border = c.create_rectangle( 3, 3, 797, 400, width = 2 )
ground = c.create_line( 0, yGround, 800, yGround )
x1, y1 = 150, yGround - 15
tank_1 = c.create_rectangle( 0, 0, 0, 0 )
tank1Cannon = c.create_line( 0, 0, 0, 0 ); angle1 = 30; missile1 = c.create_oval( 0, 0, 0, 0 )

initialSpeed = 70

############################################################################################################################################################
# Find the coordinates of a point given the angle, the length of the line and the starting coordinates
def end_x( x, d, a ):
    return x + math.sin( math.radians( a ) ) * d
def end_y( y, d, a ):
    return y - math.cos( math.radians( a ) ) * d

# Find the y position of the projectile given the x position, the angle, and the speed
def find_y( xp, yp, a, s, time ):
    y = ( -0.5 * 9.80 * ( time**2 ) ) + ( s * math.sin( math.radians( a ) ) * time ) + yp
    return y

############################################################################################################################################################

def launchMissile( xpos, ypos, angle, speed ):
    global missile1
    rangeOfMotion = ( ( speed ** 2 ) / 10 ) * math.sin( math.radians( 2 * angle ) ) # This is the range of motion

    xInc, t = 0, 0
    while xInc < xpos + rangeOfMotion:
        time.sleep( 0.08 )
        xInc = ( speed * math.cos( math.radians( angle ) ) ) * t + xpos + 15
        h = ( find_y( xInc, ypos, angle, speed, t ) - ypos )
        c.delete( missile1 )
        missile1 = c.create_oval( xInc, find_y( xInc, ypos, angle, speed, t ) - h * 2, xInc + 5, find_y( xInc, ypos, angle, speed, t ) - h * 2 + 5, fill = "black" )
        t += 1
        c.update()

def keyboard( event ):
    global x1, y1, angle1, initialSpeed
    
    if event.keysym == "Left":
        x1 -= 1
    elif event.keysym == "Right":
        x1 += 1
    elif event.keysym == "Up":
        if angle1 > 15:
            angle1 -= 1
    elif event.keysym == "Down":
        if angle1 < 85:
            angle1 += 1
    elif event.keysym == "space":
        launchMissile( x1, y1, 90 - angle1, initialSpeed ) 
        root.unbind( "<Any-KeyPress>" )  
    tankCombat()


def tankCombat():
    global yGround, tank_1, x1, y1, tank1Cannon, angle1, langle1

    langle1.place_forget(); langle1 = Label( root, text = "Current angle >> " + str( angle1 ) ); langle1.place( relx = 1, x = -780, y = 440 )
    
    c.delete( tank_1, tank1Cannon )
    tank_1 = c.create_rectangle( x1, y1, x1 + 30, y1 + 15, fill = "green" )
    tank1Cannon = c.create_line( x1 + 15, y1 + 7, end_x( x1 + 15, 15, angle1 ), end_y( y1 + 7, 15, angle1 ), width = 2 )


l1 = Label( root, text = "<< Player One Details >>", font = "Arial" ); l1.place( relx = 1, x = -750, y = 405 )
langle1 = Label( root, text = "Current angle >> " + str( angle1 ) ); langle1.place( relx = 1, x = -780, y = 440 )

tankCombat()
root.bind( "<Any-KeyPress>", keyboard )

mainloop()
Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.