Posted: 27th Sep 2011 20:31
Hello All,

Having trouble understanding how to control the steering of a vehicle using the physics commands. In this case, a Tank.

I know that Kevin Summers did exactly what I need to with his Ludum Dare entry, but I can't seem to be able to wrap my head around how he did it. I can move the Tank without a problem, but when it comes to turning it, that is where I am stuck. Kevin said that he used some Math for the turns, but I don't see any code showing this.

So with all that said, can anyone shed some light on how to control a vehicle, especially during turning?

I've tried several different methods, but the sprite either spins too much or not enough and then continues on the trajectory it was already on, without changing direction. I realize that I need to change the direction of the Force/Impulse/Whatever to match the new angle, but my head hurts trying to figure it out.

I was able to move the vehicles and turn them easily without using physics, but collision detection is much better with physics, so I would prefer going this route.

Any help would be appreciated.

Thanks,
JHA
Posted: 28th Sep 2011 16:38
Ok, I guess I'm asking too much.

Is there a straight forward web site where I can learn about 2D Physics, related to programming?

I'll Google it, but I just didn't know if anyone knew of a good one.

Thank you,
JHA
Posted: 28th Sep 2011 17:09
Well App Game Kit uses Box2D so in essence checking out the manual http://www.box2d.org/manual.html is going to be a good start. Also, posting some code is going to get you a lot more help.
Posted: 28th Sep 2011 17:30
Thanks ElijahNomad!

I didn't know about the Box2D manual. That should help alot.

My code is in a bit of disarray while trying to figure out what each command does, so I'm not sure it would help, but here it is:

+ Code Snippet
SetVirtualResolution(1024, 768)
speed = 5000
Dim m$[768]

LoadImage(1, "bTank.png")
CreateSprite(1, 1): SetSpritePosition(1, 40, 50): SetSpriteShape(1, 3)
LoadImage(2, "wall.png")

SetPhysicsDebugOn()
SetSpritePhysicsOn( 1, 2 )
SetPhysicsGravity( 0, 0 )
`SetSpritePhysicsCanRotate(1, 0)
SetSpritePhysicsRestitution(1, 0)
SetSpritePhysicsFriction(1, 100)
SetSpritePhysicsDamping(1, 1)


Gosub level1
Gosub create_level

do

    Gosub moveTank
    SetSpritePhysicsAngularDamping(1, 15)

    if getrawkeypressed(27) then end
    sync()
loop

moveTank:

    if getrawkeypressed(38) ` Up
        SetSpritePhysicsImpulse(1, GetSpriteX(1), GetSpriteY(1), 0, -speed)
    endif
    if getrawkeypressed(40) ` Down
        SetSpritePhysicsImpulse(1, GetSpriteX(1), GetSpriteY(1), 0, speed)
    endif
    if getrawkeypressed(37) ` Left

        SetSpritePhysicsAngularVelocity(1, .01)
        SetSpritePhysicsAngularImpulse(1, -speed)
        `SetSpritePhysicsImpulse(1, GetSpriteX(1), GetSpriteY(1), -speed, 0)
    endif
    if getrawkeypressed(39) ` Right
        SetSpritePhysicsImpulse(1, GetSpriteX(1), GetSpriteY(1), speed, 0)
    endif

Return

create_level:

    ` Reads Map data from m$[] and builds the level
    wx = 0: wy = 0: loc = 0: wSpr = 999
    for row = 1 to 24
        for col = 1 to 32
            if mid(m$[loc], col, 1) = "1"
                inc wSpr
                CreateSprite(wSpr, 2)
                SetSpritePosition(wSpr, wx, wy)
                SetSpriteDepth(wSpr, 10)
                SetSpritePhysicsOn( wSpr, 1 )
            endif
            inc wx, 32
        next col
        inc loc
        inc wy, 32
        wx = 0
    next row

Return

level1:
    m$[0] =  "11111111111111111111111111111111"
    m$[1] =  "10000000000000010000000000000001"
    m$[2] =  "10000000000000010000000000000001"
    m$[3] =  "10000000000000000000000000000001"
    m$[4] =  "10000000000000000000000000000001"
    m$[5] =  "10000000000000000000000000000001"
    m$[6] =  "10000000000000000000000000000001"
    m$[7] =  "10000000000000000000000000000001"
    m$[8] =  "10000000000000000000000000000001"
    m$[9] =  "10000000000000000000000000000001"
    m$[10] = "10001100000000010000000000110001"
    m$[11] = "10000110000000101000000001100001"
    m$[12] = "10000110000000010000000001100001"
    m$[13] = "10001100000000000000000000110001"
    m$[14] = "10000000000000000000000000000001"
    m$[15] = "10000000000000000000000000000001"
    m$[16] = "10000000000000000000000000000001"
    m$[17] = "10000000000000000000000000000001"
    m$[18] = "10000000000000000000000000000001"
    m$[19] = "10000000000000000000000000000001"
    m$[20] = "10000000000000000000000000000001"
    m$[21] = "10000000000000010000000000000001"
    m$[22] = "10000000000000010000000000000001"
    m$[23] = "11111111111111111111111111111111"
Return


I have attached the 2 images I'm using for my test program, which is just a portion of my main program, so I can get a hold of the physics before implementing it.

Here is what I am trying to do, at the moment:

Up Arrow: Move Tank Forward according to the angle it is heading.
Down Arrow: Stop
Left Arrow: Turn Left and if in motion, keep moving in the new direction.
Right Arrow: Turn Right and if in motion, keep moving in the new direction.

If the tank is not current moving, then I need it to just rotate in place.

I guess I just need to know how to calculate the new direction of the tank and change the Impulse / Force to the new direction. I want the change in Velocity to be immediate and not have any acceleration. Maybe I don't need Impulse or Force at all and should just use the Velocity commands ....

Thanks for the help!

JHA
Posted: 28th Sep 2011 19:11
I got it sorted out using just the Velocity commands!!

Here is the full working version as well as an updated Tank image, due to the need for animation for the different directions.

+ Code Snippet
SetVirtualResolution(1024, 768)

Global btank, bframe, bx, by, speed
btank = 100: bframe = 6: bx = 0: by = 0: speed = 64
Dim m$[768]

` Load Sprites
LoadImage(2, "wall.png")
LoadImage(btank, "bTank.png")
CreateSprite(btank, btank): SetSpritePosition(btank, 64, 364)
SetSpriteAnimation (btank, 32, 32, 8): SetSpriteFrame(btank, 6): SetSpriteShape(btank, 3)

` Set Physics Properties
`SetPhysicsDebugOn()
SetSpritePhysicsOn(btank, 2)
SetPhysicsGravity(0, 0)
SetSpritePhysicsCanRotate(btank, 0)
SetSpritePhysicsRestitution(btank, 0)

` Setup The Level
Gosub level1
Gosub create_level

do
    Gosub tankMoves
    Gosub updatePlayers

    if GetRawKeyPressed(27) then end
    sync()
loop

` Routines & Functions
tankMoves:

    key = GetRawKeyPressed(38) ` Blue Up
    if key = 1
        moveTank(btank, bframe)
    endif

    key = GetRawKeyPressed(40) ` Blue Down
    if key = 1
        stopTank(btank)
    endif

    key = GetRawKeyPressed(37) ` Blue Left
    if key = 1
        inc bframe: if bframe > 8 then bframe = 1
        SetSpriteFrame (btank, bframe)
        SetSpriteShape(btank, 3)
        if bx <> 0 or by <> 0
            moveTank(btank, bframe)
        endif
    endif

    key = GetRawKeyPressed(39) ` Blue Right
    if key = 1
        dec bframe: if bframe < 1 then bframe = 8
        SetSpriteFrame (btank, bframe)
        SetSpriteShape(btank, 3)
        if bx <> 0 or by <> 0
            moveTank(btank, bframe)
        endif
    endif

Return

updatePlayers:

    SetSpritePhysicsVelocity (btank, bx, by)

Return

Function moveTank(player, frame)

    Select frame
        case 1 ` North West
            if player = btank
                bx = -speed
                by = -speed
            endif
        endcase
        case 2 ` West
            if player = btank
                bx = -speed
                by = 0
            endif
        endcase
        case 3 ` South West
            if player = btank
                bx = -speed
                by = speed
            endif
        endcase
        case 4 ` South
            if player = btank
                bx = 0
                by = speed
            endif
        endcase
        case 5 ` South East
            if player = btank
                bx = speed
                by = speed
            endif
        endcase
        case 6 ` East
            if player = btank
                bx = speed
                by = 0
            endif
        endcase
        case 7 ` North East
            if player = btank
                bx = speed
                by = -speed
            endif
        endcase
        case 8 ` North
            if player = btank
                bx = 0
                by = -speed
            endif
        endcase
    EndSelect

EndFunction

Function stopTank(player)

    if player = btank
        bx = 0: by = 0
    endif

EndFunction

create_level:

    ` Reads Map data from m$[] and builds the level
    wx = 0: wy = 0: loc = 0: wSpr = 999
    for row = 1 to 24
        for col = 1 to 32
            if mid(m$[loc], col, 1) = "1"
                inc wSpr
                CreateSprite(wSpr, 2)
                SetSpritePosition(wSpr, wx, wy)
                SetSpriteDepth(wSpr, 10)
                SetSpritePhysicsOn( wSpr, 1 )
            endif
            inc wx, 32
        next col
        inc loc
        inc wy, 32
        wx = 0
    next row

Return

level1:
    m$[0] =  "11111111111111111111111111111111"
    m$[1] =  "10000000000000010000000000000001"
    m$[2] =  "10000000000000010000000000000001"
    m$[3] =  "10000000000000000000000000000001"
    m$[4] =  "10000000000000000000000000000001"
    m$[5] =  "10000000000000000000000000000001"
    m$[6] =  "10000000000000000000000000000001"
    m$[7] =  "10000000000000000000000000000001"
    m$[8] =  "10000000000000000000000000000001"
    m$[9] =  "10000000000000000000000000000001"
    m$[10] = "10001100000000010000000000110001"
    m$[11] = "10000110000000101000000001100001"
    m$[12] = "10000110000000010000000001100001"
    m$[13] = "10001100000000000000000000110001"
    m$[14] = "10000000000000000000000000000001"
    m$[15] = "10000000000000000000000000000001"
    m$[16] = "10000000000000000000000000000001"
    m$[17] = "10000000000000000000000000000001"
    m$[18] = "10000000000000000000000000000001"
    m$[19] = "10000000000000000000000000000001"
    m$[20] = "10000000000000000000000000000001"
    m$[21] = "10000000000000010000000000000001"
    m$[22] = "10000000000000010000000000000001"
    m$[23] = "11111111111111111111111111111111"
Return


I hope someone will find it useful!!

Thanks,
JHA
Posted: 28th Sep 2011 19:12
IRL, when you stopped power to the tracks, your tank would stop moving because of the friction between the ground and the tank. If you are doing a "top down" sprite version, then you can use damping to simulate this. When you press a key you can add the force, when the key is released, damping will stop the movement.

As far as direction, you'll probably need to calculate this, I'm not the best at that, but I can probably find the formulas.

EDIT: Glad you fixed it!
Posted: 28th Sep 2011 19:26
Thanks Rich. That was the approach I was trying to get working with spotty success. The above version does not use any of that, which is really what I was trying to do anyway. All I wanted from the Physics engine was the Collision ability, for this project.

I'll have a go at those functions in a future project though. I definitely want to nail them down.