Roguelike walk around demo with simple field of view

User projects written in or related to FreeBASIC.
dabooda
Posts: 112
Joined: Aug 28, 2006 21:35
Location: Texas
Contact:

Postby dabooda » Jan 10, 2008 22:39

Just my 2c's but I would use toggles. like so:

Code: Select all

Dim as Integer key_toggle = 0 'toggle
If key_toggle = 0 then
     'read key
     if multikey(key_code) then key_toggle = 1: do action
ElseIf key_toggle = 1 then
     'read for key up
     if multikey(key_code) then key_toggle = 0
EndIf


This keeps your key from reading more than once. Just do that for all your directions, of course you will have to implement it slightly different. You could also easily implement a count to maybe set the key_toggle to 0 every so many frames, this limits the repeat rate then. Also I would select only one key for each move, the arrow keys are sufficient enough.

DaBooda out...
Lachie Dazdarian
Posts: 2338
Joined: May 31, 2005 9:59
Location: Croatia
Contact:

Postby Lachie Dazdarian » Jan 10, 2008 22:50

My keyboard works fine. Simply, INKEY sucks and shouldn't be used for GAMES. As well as console mode. Period. And I think the main problem was that annoying hang error.

BTW, I'm with dabooda on this. Shees, you can easily code using MULTIKEY so the user needs to press keys REPEADETLY, or that a key reacts first time you press and then every [insert_number] of loops. What’s the problem?
KristopherWindsor
Posts: 2428
Joined: Jul 19, 2006 19:17
Location: Sunnyvale, CA
Contact:

Postby KristopherWindsor » Jan 10, 2008 22:56

What’s the problem?


If you get low FPS, you might press and release a key so quickly, that it is never pressed when Multikey is called, so the key press will not be read. Also, Multikey allows multiple, simultaneous key presses; for this game, I am not sure that you are supposed to be able to move diagonally. Inkey would handle that better (for this game) IMO because it would move the player horizontally and vertically in two different frames, instead of at the same time.
If you do not want a 30FPS real-time action game, use Inkey. ;-)
Lachie Dazdarian
Posts: 2338
Joined: May 31, 2005 9:59
Location: Croatia
Contact:

Postby Lachie Dazdarian » Jan 10, 2008 23:05

If you get low FPS, you might press and release a key so quickly, that it is never pressed when Multikey is called, so the key press will not be read.


Jesus, how low FPS you would need for this to happen? Just make the code react on FIRST keypress ALWAYS, and then on second every few loops.
elsairon
Posts: 207
Joined: Jul 02, 2005 14:51

Postby elsairon » Jan 11, 2008 1:49

Lachie Dazdarian wrote:My keyboard works fine.


So the numpad works fine using both the first and the second examples?

Lachie Dazdarian wrote:BTW, I'm with dabooda on this. Shees, you can easily code using MULTIKEY so the user needs to press keys REPEADETLY, or that a key reacts first time you press and then every [insert_number] of loops. What’s the problem?


The problem so far is that when the user slightly taps a key, the faster the computer is the more keyboard events get processed for that action. For example the player shoots across the screen moving 19 spaces instead of 1 space he wanted to move.

I have tested two different variations of the multikey input (see above), and both have this problem.

Another option I have considered is this (maybe what you are referring to here?). When a multikey event is detected, process the input. Continue checking this same multikey event and looping until the key is released. The problem with this approach is that the key can't be held down to issue multiple events, it has to be pressed and released for each move. So if the user holds down the key for n time, then issue another of the same key events.

The problem with using multikey for this approach is that the game is designed to process a single player action at a time. Multikey is designed to process more than one. So I have to poll every possible key, and then trap each one individially.

With Inkey I can wait for an event, and then process it without checking every other possible event or trapping any of them.
elsairon
Posts: 207
Joined: Jul 02, 2005 14:51

Postby elsairon » Jan 11, 2008 1:53

dabooda wrote:Just my 2c's but I would use toggles. like so ...
<snip example>
This keeps your key from reading more than once.


Thanks. I think this will solve the issue.
KristopherWindsor
Posts: 2428
Joined: Jul 19, 2006 19:17
Location: Sunnyvale, CA
Contact:

Postby KristopherWindsor » Jan 11, 2008 4:11

You can solve the speed issue by Sleeping for a few milliseconds after each frame, to keep a constant framerate on all computers. Use the Timer to see long it takes for each loop (frame), then Sleep 1000 / framesPerSecond - timeSpentOnFrame. (But add a check so that value is never negative.) ;-)
elsairon
Posts: 207
Joined: Jul 02, 2005 14:51

Postby elsairon » Jan 11, 2008 4:34

Ok. Got the speed issue handled.

Changes
- much tweaked multikey input handler.
- los function passes params byref instead of byval.
- per suggestion only 4 movement keys (up, down, left, and right)

About the keyhandler:
There is a controlled delay between keypress to game function events. Initially the delay starts at about 1/3 of a second if the user presses any key. If the user holds down a key for longer than that, then the delay changes that specific key event starts repeating at a much faster rate.

This supports the single action per event as well as faster (repeating) actions.

Note: To change the wait_trap and wait_repeat variables in the player_command sub to adjust these times.

Edit: Los routine updated; now casts shadows explicitly and more accurately.

Code: Select all

' RogueLike walk-around demo
'
' uses Bresenhams line algorithm for raycasting field of view
'
' adjust 'walls' const to change number of random wall cell generated

' changed to graphic mode for no cursor, multi-key support
#include "fbgfx.bi"

Const yes = 1
Const no  = 0
const shadow = 2
Const maxcol = 20
Const maxrow = 20
Const walls =  20
Const floor = 3
Const wall  = 4

Const floor_symbol =  "."
Const wall_symbol =   "#"
Const player_symbol = "@"

Dim Shared As Integer player_row, player_column, map( 1 To maxrow , 1 To maxcol )
Dim Shared losmap( 1 To maxrow , 1 To maxcol ) As Integer

Declare Function los( byref As Integer, byref As Integer, byref As Integer, byref As Integer ) As Integer
Declare Sub init_display
Declare Sub init_player
Declare Sub init_map
Declare Sub show_map
Declare Sub show_player
Declare Sub show_info
Declare Sub calc_fov
Declare Sub player_command
Declare Sub move_north
Declare Sub move_south
Declare Sub move_east
Declare Sub move_west



Sub init_display
   
    Screen 17
    Width 80, 25
   
End Sub



Function los _
    ( _
            Byref x1 As Integer, _
            Byref y1 As Integer, _
            Byref x2 As Integer, _
            Byref y2 As Integer _
    ) As Integer
   
    ' Starts los at x1, y1 and advances to x2, y2
    ' using Bresenham's integer line algorithm
   
    Dim As Integer deltax, deltay, x, y, den, _
                 curspace, num, numadd, length, _
                 xinc1, yinc1, xinc2, yinc2, dx, dy, _
                 losflag
   
    deltax = Abs( x2 - x1 )
    deltay = Abs( y2 - y1 )
    x = x1
    y = y1
    If x2 >= x1 Then
        xinc1 = 1
        xinc2 = 1
    Else
        xinc1 = -1
        xinc2 = -1
    End If
    If y2 >= y1 Then
        yinc1 = 1
        yinc2 = 1
    Else
        yinc1 = -1
        yinc2 = -1
    End If
    If deltax >= deltay Then
        xinc1 = 0
        yinc2 = 0
        den = 2 * deltax
        num = deltax
        numadd = 2 * deltay
        length = deltax
    Else
        xinc2 = 0
        yinc1 = 0
        den = 2 * deltay
        num = deltay
        numadd = 2 * deltax
        length = deltay
    End If
   
    losflag = yes
    For curspace = 0 To length - 1
        num = num + numadd
        If num >= den Then
                num = num - den
                x = x + xinc1
                y = y + yinc1
        End If
        x = x + xinc2
        y = y + yinc2
       
        if losmap( x, y ) <> shadow then
            losmap( x, y ) = losflag                   
            If losflag = yes and map( x, y ) = wall Then losflag = shadow
        end if
   
    Next curspace
   
    If x = x2 And y = y2 and losflag = yes Then return 1
    Return 0
   
End Function



Sub init_map
   
    Dim As Integer x, y, wc, wr, count_walls
   
    ' cover map with floor
    For x = 1 To maxcol
        For y = 1 To maxrow
            map( x, y ) = floor
        Next y
    Next x
    ' make some random walls
    If walls And walls < maxcol * maxrow Then
        Do
            wc = Int(Rnd*maxcol)+1
            wr = Int(Rnd*maxrow)+1
            If map( wr, wc ) <> wall Then
                map( wr, wc ) = wall
                count_walls += 1
            End If
        Loop Until count_walls = walls
    Else
        ? "const walls invalid value = " & walls & "!"
        Sleep
        End
    End If
   
End Sub



Sub init_player
   
    Dim As Integer good_player_location
   
    ' locate player, ensure player does not start on a wall
    good_player_location = no
    Do
        player_column = Int ( Rnd * maxcol ) + 1
        player_row = Int ( Rnd * maxrow ) + 1
        If map( player_row, player_column ) <> wall Then good_player_location = yes
    Loop Until good_player_location = yes
   
End Sub



Sub calc_fov
   
    Dim As Integer c, r
   
    ' clear the previous fov
    For c = 1 To maxcol
        For r = 1 To maxrow
            losmap( r, c ) = no
        Next r
    Next c   
   
    ' los ray from player location to every column edge on the first and last row
    For c = 1 To maxcol
        los( player_row, player_column,      1, c )
        los( player_row, player_column, maxrow, c )
    Next c
    ' los ray from player location to every row edge on first and last column
    ' (skipping the corners because we already checked those above )
    For r = 2 To maxrow - 1
        los( player_row, player_column, r,      1 )
        los( player_row, player_column, r, maxcol )
    Next r
   
End Sub



Sub show_map
   
    Dim As String mapchar
    Dim As Integer x, y
   
    ' draw map
    For x = 1 To maxrow
        For y = 1 To maxcol
            mapchar = " "
            If losmap( x, y ) = yes Then
               
                Select Case map( x, y )
                Case wall : mapchar = wall_symbol
                Case Else : mapchar = floor_symbol
                End Select
               
            End If
            Locate x,y
            ? mapchar
        Next y
    Next x

End Sub



Sub show_player

    Locate player_row, player_column
    ? player_symbol
   
End Sub



Sub show_info
   
    ' show commands
    Locate 01,25: ? "COMMAND LIST"
    Locate 03,25: ? "Keypress  Function"
    Locate 04,25: ? "--------  ----------"
    Locate 05,25: ? "Esc       Exit Test"
    Locate 06,25: ? "M         New Map"
    Locate 07,25: ? "Left      Move West"
    Locate 08,25: ? "Up        Move North"
    Locate 09,25: ? "Down      Move South"
    Locate 10,25: ? "Right     Move East"
   
    ' show mapkey
    Locate 13,25: ? "MAP KEY"
    Locate 15,25: ? "Symbol  Meaning"
    Locate 16,25: ? "------  -------"
    Locate 17,25: ? "  " & wall_symbol & "     Wall"
    Locate 18,25: ? "  " & floor_symbol & "     Floor"
    Locate 19,25: ? "  " & player_symbol & "     Player"
   
End Sub



Sub move_north
   
    ' don't move north if on north edge of map or if a wall is in the way
    If player_row > 1 Then
        If map( player_row - 1, player_column ) <> wall Then
            player_row -= 1
        End If
    End If

End Sub


   
Sub move_south
   
    ' don't move south if on south edge of map or if a wall is in the way
    If player_row < maxrow Then
        If map( player_row + 1, player_column ) <> wall Then
            player_row += 1
        End If
    End If

End Sub



Sub move_west
   
    ' don't move west if on west edge of map or if a wall is in the way
    If player_column > 1 Then
        If map( player_row, player_column - 1 ) <> wall Then
            player_column -= 1
        End If
    End If

End Sub



Sub move_east
   
    ' don't move east if on east edge of map or if a wall is in the way
    If player_column < maxcol Then
        If map( player_row, player_column + 1 ) <> wall Then
            player_column += 1
        End If
    End If

End Sub

   

Sub player_command
   
    static trap as integer
    static last_command as integer
    static repeat as integer
    static last_event as double
    dim as double delay, trap_wait, repeat_wait, time_start
   
    trap_wait = .3
    repeat_wait = .06
    time_start = timer
   
    if time_start - last_event > repeat_wait + .02 or trap <> last_command then
        repeat = -1
        delay = trap_wait
    elseif trap = repeat then
        delay = repeat_wait
    end if
   
    if trap then
        last_command = trap
        ' wait until the key is released before trying another key
        while multikey( trap )
            ' break out early if the key is held down long enough
            if timer - time_start > delay then
                repeat = trap
                exit while
            end if
        wend
    end if

    trap = 0
    last_event = timer

    Do
        If multikey(FB.SC_ESCAPE) Then Cls: End
        If multikey(FB.SC_M     ) Then init_map: init_player: trap = FB.SC_M: Exit Do
        If multikey(FB.SC_LEFT  ) Then move_west:  trap = FB.SC_LEFT  : Exit Do
        If multikey(FB.SC_RIGHT ) Then move_east:  trap = FB.SC_RIGHT : Exit Do
        If multikey(FB.SC_UP    ) Then move_north: trap = FB.SC_UP    : Exit Do
        If multikey(FB.SC_DOWN  ) Then move_south: trap = FB.SC_DOWN  : Exit Do
        ' ensure some free cpu cycles
        Sleep 1, 1
    Loop

End Sub

' initalization

init_display
init_map
init_player
show_info

' main loop
Do
    calc_fov
    show_map
    show_player
    player_command
Loop


KristopherWindsor wrote:You can solve the speed issue by Sleeping for a few milliseconds after each frame, to keep a constant framerate on all computers.

I'll keep this in mind for controlled display speed for animations and such :)
elsairon
Posts: 207
Joined: Jul 02, 2005 14:51

Postby elsairon » Jan 14, 2008 1:43

First post updated with latest RL 'walk-around' example demonstrating both fixed and scrolling map views.

Return to “Projects”

Who is online

Users browsing this forum: Bing [Bot] and 4 guests