
-----------------------------------
lordroba
Fri Aug 12, 2005 9:26 am

Hasch question, cheking to see if key pressed
-----------------------------------
I'm making a racing game and I want the car speed up while the UP key is being pressed(i know how to do this), and I want the speed to slowly go down while no key is pressed.

How do I check if no key is being pressed and put this into an 'IF' condition so that it lowers the value of the speed variable when this is true?

-----------------------------------
MihaiG
Fri Aug 12, 2005 10:59 am


-----------------------------------
heres a small example


if not hasch then
speed := speed - 1 %speed -= 1
end if


-----------------------------------
lordroba
Fri Aug 12, 2005 11:07 am


-----------------------------------
thank you very much

-----------------------------------
Cervantes
Fri Aug 12, 2005 11:32 am


-----------------------------------
Use Input.KeyDown, not hasch and getch.  It will allow you to get multiple keystrokes at once.

You probably don't want to slow your car down when no key is pressed.  Think about it: the user could press "h" and he would go at a constant speed and not use any fuel or anything.  Instead, you want the car to slow down when the up arrow is not pressed.


if keys (KEY_UP_ARROW) then
    car.speed += car.acceleration
else
    car.speed *= car.deceleration
end if

car.deceleration should be slightly less than 1.  0.99 is a good value to test.

Of course, you could use some physics to determine accelerations with regard to mass, applied force, and frictional forces.


View.Set ("offscreenonly")
var car :
    record
        x, y : real
        mass : real
        internal_friction, net_force : real
        current_vert_angle : real
        speed, applied_engine_force : real
        current_surface_material, tire_material : string
    end record := init (100, 100, 800, 200, 0, 0, 0, 10000, "dry asphault", "rubber")

type Friction_Coefficient :
    record
        surface1, surface2 : string
        value : real
    end record

fcn friction_coeffecient_init (surface1, surface2 : string, value : real) : Friction_Coefficient
    var temp_coeff : Friction_Coefficient
    temp_coeff.surface1 := surface1
    temp_coeff.surface2 := surface2
    temp_coeff.value := value
    result temp_coeff
end friction_coeffecient_init

var coefficients : array 1 .. 2 of Friction_Coefficient
coefficients (1) := friction_coeffecient_init ("rubber", "dry asphault", 0.6)
coefficients (2) := friction_coeffecient_init ("rubber", "wet asphault", 1.2)

fcn friction_force (surface1, surface2 : string, N : real) : real
    for i : lower (coefficients) .. upper (coefficients)
        if Str.Lower (coefficients (i).surface1) = Str.Lower (surface1) and
                Str.Lower (coefficients (i).surface2) = Str.Lower (surface2) then
            %Force of friction = mew (coefficient of friction) * Normal force
            result coefficients (i).value * N
        end if
    end for
end friction_force



var keys : array char of boolean

loop

    car.net_force := -car.internal_friction - friction_force (car.tire_material, car.current_surface_material, cosd (car.current_vert_angle) * car.mass * 9.8) %- car.speed
    % the last bit, - car.speed is an approximation for wind resistance.  I'm not sure how wind resistance works.  Anyone know the formula?

    Input.KeyDown (keys)
    if keys (KEY_UP_ARROW) then
        car.net_force += car.applied_engine_force
    end if
    car.speed += car.net_force / car.mass
    car.speed := max (0, car.speed)
    car.x += car.speed
    car.x mod= maxx
    cls
    Draw.FillOval (round (car.x), round (car.y), 10, 10, black)
    locate (1, 1)
    put car.speed
    View.Update
    delay (10)

end loop

I think this is all correct, except for the fact that the coefficient of friction changes depending upon your speed.  This also does not take into account air resistance, which is greater than the friction between the tires and the road.

-----------------------------------
lordroba
Sat Aug 13, 2005 9:00 am


-----------------------------------
Alright now i'm really pissed, I spent all day yesterday trying to figure this out but I'm having no success.  :x  As you can see in the attached program, the car moves fine, and it turns and everything, but I can't figure out how to make it keep going for a while when you let go of the acceleration(UP) button!  It just stops right where you let go of the key.

can someone plz help me.

I not only want the car to move a fair bit  and eventually stop after you let go of the gas, but I also want it so that the user still has ability to steer the car thru the corner when its moving.

Any help greatly appreciated!

-----------------------------------
Cervantes
Sat Aug 13, 2005 12:11 pm


-----------------------------------
There are two tutorials you should look at:
First, check out zylum's 
        player.x += cosd (player.dir) * player.forward_speed
        player.y += sind (player.dir) * player.forward_speed

You want that to happen all the time.  He won't move if his speed is 0, remember.

Here's the modified code.


var winID := Window.Open ("graphics:1200;800,nobuttonbar,offscreenonly")
colourback (2)

var player :
    record
        x, y : real
        angle : real
        speed : real
        rotation_speed : real
        forward_accel : real
        backward_accel : real
        max_forward_speed : real
        max_backward_speed : real
    end record

player.x := 100
player.y := 100
player.angle := 90
player.speed := 0
player.rotation_speed := 5
player.forward_accel := 1
player.backward_accel := 0.5
player.max_forward_speed := 10
player.max_backward_speed := -5

var picCar := Pic.FileNew ("Trueno.bmp")
var picCarRotated := Pic.Rotate (picCar, round (player.angle), Pic.Width (picCar) div 2, Pic.Height (picCar) div 2)
var picRoad := Pic.FileNew ("Road1.jpg")




procedure playerControls
    var keys : array char of boolean
    Input.KeyDown (keys)

    if keys (KEY_RIGHT_ARROW) & player.speed ~= 0 then
        player.angle := (player.angle - player.rotation_speed) mod 360
    end if

    if keys (KEY_LEFT_ARROW) & player.speed ~= 0 then
        player.angle := (player.angle + player.rotation_speed) mod 360
    end if

    if not keys (KEY_UP_ARROW) & not keys (KEY_DOWN_ARROW) then
        if player.speed = -0.5 then
            player.speed := 0
        end if
        player.speed *= 0.97
    else
        if keys (KEY_UP_ARROW) then
            player.speed := min (player.max_forward_speed, player.speed + player.forward_accel)
        end if

        if keys (KEY_DOWN_ARROW) then
            player.speed := max (player.max_backward_speed, player.speed - player.backward_accel)
        end if
    end if

end playerControls

procedure updatePlayer

    playerControls
    player.x += cosd (player.angle) * player.speed
    player.y += sind (player.angle) * player.speed

    picCarRotated := Pic.Rotate (picCar, round (player.angle), Pic.Width (picCar) div 2, Pic.Height (picCar) div 2)
    Pic.Draw (picCarRotated, 600, 400, picMerge)
    Pic.Free (picCarRotated)
    put player.x, " ", player.y, " ", player.speed


end updatePlayer

loop

    cls
    Pic.Draw (picRoad, -round (player.x), -round (player.y), picCopy)
    updatePlayer
    View.Update

end loop

Window.Close (winID)

I also rotated the picture by 90Â°, so you don't have to bother with the Pic.Rotate in the initialization stages.

-----------------------------------
[Gandalf]
Sat Aug 13, 2005 3:52 pm


-----------------------------------
I was wondering how would you check if the user hit any key at all, not everything (including having no key pressed at all) except some certain keys.  Can't think of anything right now :?...  Thanks.

-----------------------------------
Cervantes
Sat Aug 13, 2005 4:17 pm


-----------------------------------
Could you restate that?

-----------------------------------
[Gandalf]
Sat Aug 13, 2005 9:07 pm


-----------------------------------
Yeah, I knew it was a bit unclear...

When you have an Input.Keydown statment, like if keys ('a') then ... and then you add an else, that else will include when no keys are pressed at all.  I only want to do something when an actual key is pressed (when a key is pressed that is not 'b' for example).

Basically, I want to do an 'else' like statement but without a null key - I can't think of how to detect that.  Probably a pretty simple solution, but I've been wondering for a while and decided to ask.

-----------------------------------
Cervantes
Sun Aug 14, 2005 7:11 am


-----------------------------------

if hasch and not keys ('b') then


"]When you have an Input.Keydown statment, like if keys ('a') then ... and then you add an else, that else will include when no keys are pressed at all.
The else would be entered only if 'a' is not pressed.  Other conditions, such as if 'b' is pressed, are irrelevent.

-----------------------------------
[Gandalf]
Sun Aug 14, 2005 5:56 pm


-----------------------------------
Ok, thanks.  I wasn't thinking about hasch/getch, trying to avoid it.  Is there a way of doing it without them?  Still, it's a pretty good use of hasch (as opposed to using it as a replacement of Input.Keydown).

I know about the else statment, I was just trying to explain the problem that I can't detect if keys(nothingatall).

-----------------------------------
Cervantes
Sun Aug 14, 2005 7:04 pm


-----------------------------------
I agree: I try to avoid using hasch & getch with Input.KeyDown, because of problems with one catching keystrokes that I want the other to catch.  

Here's another way to do it.  There's some need tricks in here, particularly the range of the for loop.

var keys : array char of boolean

fcn key_pressed_other_than (key : char, keyboard : array char of boolean) : boolean
    if keyboard (key) then
        result false
    end if
    for i : char
        if keyboard (i) then
            result true
        end if
    end for
    result false
end key_pressed_other_than

loop
    Input.KeyDown (keys)

    locate (1, 1)
    if key_pressed_other_than ('b', keys) then
        put "A key has been pressed other than 'b'"
    else
        put "'b' has been pressed, or no key has been pressed"
    end if
    exit when keys (KEY_ESC)

end loop


-----------------------------------
[Gandalf]
Sun Aug 14, 2005 11:18 pm


-----------------------------------
Nice.  I'll try it out later on, thanks again :).
Interesting way of doing it, I was wondering about different for loops, now I have something to think about.
