Help with limiting text input

john2367

New Member
Joined
Feb 19, 2019
I need help. I am trying to stop the program to stop detecting inputs from the keyboard when enter has been pressed or when text reaches a certain length. I also want to incorporate this and use it with text files so that it can be saved when enter is pressed. I am not sure how to do this. I cant seem to understand how writing to text files work either.

here is a code snippet that I tried to do when enter is pressed. I will use all of this for a high score system that I am trying to make.
Cerberus X:
Import mojo

Class MyApp Extends App

    Field text$="Type something:"

    Method OnCreate()
        SetUpdateRate 30
    End
    
    Method OnUpdate()
        
        Local valid:Bool = True

        Repeat
        
            Local char=GetChar()
            If Not char Exit
            If char>=32
                text+=String.FromChar( char )
            Endif
            
        Until KeyHit(KEY_ENTER)

    End
    
    Method OnRender()
        Cls
        DrawText text,0,0
    End
End

Function Main()
    New MyApp
End
 

dawlane

Active Member
CX Code Contributor
Joined
Jun 21, 2017
Welcome to the club.

Depending on your programming knowledge you may understand some of the code that I post.
I would recommend using a fine state machine.
Cerberus X:
Strict
Import mojo

' the high score table etc and associated code should be kept separate from the main code.
Class CHighScores

    Field name:String

    ' Poll the keyboard for characters.
    Method PollInput:Bool()
        Local char:= GetChar()    ' Get a character key press
        If char=13 Return True    ' If Enter is pressed then return true to breakout of the input routine
    
        ' Allow ASCII characters and ignore keycodes for DEL and anything below a space character.
        ' Only allow ten characters to be entered. Strings are character arrays that start at index 0.
        If (char>=32 And char<127) And name.Length()<10 name+=name.FromChar(char)
    
        ' Capture Back space and DEL keycodes to delete a character from the name using string slicing.
        If (char=8 Or char=127) And name.Length()>0 name=name[..name.Length()-1]
        Return False
    End Method

    Method DrawEnterName:Void()
        DrawText("Enter name: "+name, 0, 200)
    End Method

End

' Game states - Google 'Fine state machine' for info
Const GSTATE_TITLE:=1
Const GSTATE_START_GAME:=2
Const GSTATE_PLAYGAME:=3
Const GSTATE_GAMEOVER:=4
Const GSTATE_SHOW_HIGHSCORE:=5
Const GSTATE_ENTERNAME_HIGHSCORE:=6

' Game class
Class CGame Extends App

    Field gameState:=GSTATE_ENTERNAME_HIGHSCORE    ' NOTE: You would normally set this to GSTATE_TITLE, but just for this demo it's set to enter a name
    Field highScores:=New CHighScores()

    Method OnCreate:Int()
        SetUpdateRate(60)
        Return 0
    End Method

    Method OnUpdate:Int()
    
        Select gameState
            Case GSTATE_TITLE
                Print "TITLE ROUTINE"
            Case GSTATE_START_GAME
                Print "DO START GAME ROUTINE"
            Case GSTATE_PLAYGAME
                Print "DO PLAY GAME ROUTINE"
            Case GSTATE_GAMEOVER
                Print "DO GAME OVER ROUTINE"
            Case GSTATE_ENTERNAME_HIGHSCORE
                ' As long as the PollInput returns False the game state remains the same.
                If highScores.PollInput()
                    ' Do update to high score table etc before changing game state.
                    gameState=GSTATE_SHOW_HIGHSCORE
                Endif
            Case GSTATE_SHOW_HIGHSCORE
                Print "HIGH SCORES ROUTINE"
        End Select
    
        Return 0
    End Method

    Method OnRender:Int()
        Cls
        Select gameState
            Case GSTATE_TITLE
                Print "DRAW TITLE ROUTINE"
            Case GSTATE_START_GAME
                Print "DRAW START GAME ROUTINE"
            Case GSTATE_PLAYGAME
                Print "DRAW PLAY GAME ROUTINE"
            Case GSTATE_GAMEOVER
                Print "DRAW GAME OVER ROUTINE"
            Case GSTATE_ENTERNAME_HIGHSCORE
                highScores.DrawEnterName()
            Case GSTATE_SHOW_HIGHSCORE
                Print "DRAW HIGH SCORES ROUTINE"
        End Select
        Return 0
    End Method

End Class


Function Main:Int()
    New CGame()
    Return 0
End Function
Depending on how you want to save data, it can get complicated.
This is one approach using one method for a High score table. NOTE: That this demo was just for show and doesn't use the full mojo framework.
Cerberus X:
Strict

' Import the file stream and the filesystem modules
Import mojo    ' Needed for getdate
Import brl.filestream
Import brl.filesystem

#Rem
    As building refreshes the data directory the path will be set to empty so that the hi score file will be at the same level as the executable
    Edit the DATAPATH constant to use the cerberus://data/ directory.
#End
Const DATAPATH:="" '"cerberus://data/"
Const ENTRIES:=20    ' Total number of high score entries. NOTE that you have to delete the old high score save file if you change this.

' Simple class data structure to hold a high score with the players name
Class CHighScore
    Field name:String
    Field score:Int

    Method New( n:String, s:Int )
        name=n
        score=s
    End Method
End Class

' The High Score Table class will create a new high score table or load a previous high score table
Class CHighScoreTable

    Field highScores:=New Stack<CHighScore>    ' Holds the entries for the high scores

    ' Either load a previously saved high score table or create a new one
    Method New()
        If FileType( DATAPATH+"hiscore.txt" )=FILETYPE_FILE
            Print "Found High Score File"
            ReadTableIn()
        Else
            Print "Creatings New High Score Table"
            For Local i:=1 To ENTRIES
                Self.highScores.Push( New CHighScore( "Player "+i, i*100 ) )
            Next
    
        Endif
    End Method

    ' Displays the high score table in reverse order. The last one pushed needs to be the highest score.
    Method ShowHighScores:Void()
        Local rank:=0
        For Local i:= Eachin Self.highScores.Backwards()
            rank+=1
            Print "RANK "+rank+" "+i.name+" "+i.score
        Next
    End Method

    #Rem
        Use this to check to see if the player has attained a high score.
        If the player has attained a high score; then it will return the rank position index, else it will return -1.
    #End
    Method IsHighScore:Int( s:Int )
        ' The index needs to start at the last item pushed onto the stack
        Local idx:=Self.highScores.Length()-1, hiScorer:CHighScore
        While idx >-1
            hiScorer=Self.highScores.Get( idx )
            If hiScorer.score<=s Exit
            idx-=1
        Wend

        Return idx
    End Method

    ' Update the high score table and write the results back to the high score table file.
    Method UpdateHighTable:Void( n:String, s:Int, idx:Int )

        ' Remove the bottom item from the stack before inserting the new high score.
        Self.highScores.Remove( 0 )
        Self.highScores.Insert( idx, New CHighScore( n, s ) )

        ' The updated high score file should be written here, but for this example it's going to be written else where.
        'Self.WriteTableOut()

    End Method

    ' Write the high score table to a file.
    Method WriteTableOut:Void()
        Local f:FileStream

        #Rem
            WriteShort, WriteString and WriteInt are high level stream operations.
            The stream position is automatically updated and any write errErrorn be caught within
            a Try/Catch block.
        #End
        Try

            f=FileStream.Open( DATAPATH+"hiscore.txt", "w" )    ' Open the high score file in write mode only.
            For Local i:=Eachin Self.highScores
                ' Variable name lengths
                f.WriteShort( i.name.Length() )     ' High score name length
                f.WriteString( i.name )                ' High score name is of variable length
                f.WriteInt( i.score )                 ' High score stored as a integer
            Next
            f.Close()
            Print "High score file successfully written."
    
        ' Report an error giving the position in the stream of where the write failed.
        Catch err:StreamWriteError
            Local p:=f.Position()
            If f<>Null f.Close()
            Error  "High Score Table write error! Position is "+p
        End
    End Method

    ' Read the high score table to a file.
    Method ReadTableIn:Void()
        Local f:FileStream

        #Rem
            ReadShort, ReadString and ReadInt are high level stream operations.
            The stream position is automatically updated and any write error can be caught within
            a Try/Catch block.
        #End
        Try
            f=FileStream.Open( DATAPATH+"hiscore.txt", "r" )
            Local len:=0, n:="", s:=0
    
            ' Read the data in until the End Of File has been reached.
            While Not f.Eof
                len=f.ReadShort()        ' Get the length of the name string to read
                n=f.ReadString( len )    ' Read the name string
                s=f.ReadInt()            ' Read the score
                Self.highScores.Push( New CHighScore( n, s ) )
            Wend
            f.Close()
            Print "High score file successfully read."
    
        ' Report an error giving the position in the stream of where the read failed.
        Catch err:StreamReadError
            Local p:=f.Position()
            If f<>Null f.Close()
            Error  "High Score Table read error! Position is "+p
        End
    End Method
End Class

' The first run will show the default table entries, subsequent runs should add a new player with a new high score to the table.
Function Main:Int()
    Local date := GetDate()
    Seed = date[3] * 3600000 + date[4] * 60000 + date[5] * 1000 + date[6]

    Local highScoreTable:= New CHighScoreTable()    ' Create a high score table

    ' Only add to the high scores if the high score file exists.
    ' Each re-run should give a different player with a different high score if the score is high enough.
    If FileType( DATAPATH+"hiscore.txt" )=FILETYPE_FILE
        Local names:String[]=[ "MikeHart","dawlane","Holzchopf","Martin","muruba","Phil7","Gerry Quinn","Dubbsta","PixelPaladin","Ferret3D" ]
        Local player:=names[ Rnd(names.Length()-1) ], score:=Int( Rnd(6000) ), idx:=highScoreTable.IsHighScore( score )
        Print "Generating new player high...."
        Print "Player: "+player+" with a score of: "+score
        If idx>-1 highScoreTable.UpdateHighTable(  player, score, idx )
    Endif

    ' Write the high score table to file before displaying it.
    highScoreTable.WriteTableOut()
    highScoreTable.ShowHighScores()
    Return 0
End Function
This link show another way to do a highscore table.
 
Last edited:

john2367

New Member
Joined
Feb 19, 2019
Welcome to the club.

Depending on your programming knowledge you may understand some of the code that I post.
I would recommend using a fine state machine.
Cerberus X:
Strict
Import mojo

' the high score table etc and associated code should be kept separate from the main code.
Class CHighScores

    Field name:String

    ' Poll the keyboard for characters.
    Method PollInput:Bool()
        Local char:= GetChar()    ' Get a character key press
        If char=13 Return True    ' If Enter is pressed then return true to breakout of the input routine
   
        ' Allow ASCII characters and ignore keycodes for DEL and anything below a space character.
        ' Only allow ten characters to be entered. Strings are character arrays that start at index 0.
        If (char>=32 And char<127) And name.Length()<10 name+=name.FromChar(char)
   
        ' Capture Back space and DEL keycodes to delete a character from the name using string slicing.
        If (char=8 Or char=127) And name.Length()>0 name=name[..name.Length()-1]
        Return False
    End Method

    Method DrawEnterName:Void()
        DrawText("Enter name: "+name, 0, 200)
    End Method

End

' Game states - Google 'Fine state machine' for info
Const GSTATE_TITLE:=1
Const GSTATE_START_GAME:=2
Const GSTATE_PLAYGAME:=3
Const GSTATE_GAMEOVER:=4
Const GSTATE_SHOW_HIGHSCORE:=5
Const GSTATE_ENTERNAME_HIGHSCORE:=6

' Game class
Class CGame Extends App

    Field gameState:=GSTATE_ENTERNAME_HIGHSCORE    ' NOTE: You would normally set this to GSTATE_TITLE, but just for this demo it's set to enter a name
    Field highScores:=New CHighScores()

    Method OnCreate:Int()
        SetUpdateRate(60)
        Return 0
    End Method

    Method OnUpdate:Int()
   
        Select gameState
            Case GSTATE_TITLE
                Print "TITLE ROUTINE"
            Case GSTATE_START_GAME
                Print "DO START GAME ROUTINE"
            Case GSTATE_PLAYGAME
                Print "DO PLAY GAME ROUTINE"
            Case GSTATE_GAMEOVER
                Print "DO GAME OVER ROUTINE"
            Case GSTATE_ENTERNAME_HIGHSCORE
                ' As long as the PollInput returns False the game state remains the same.
                If highScores.PollInput()
                    ' Do update to high score table etc before changing game state.
                    gameState=GSTATE_SHOW_HIGHSCORE
                Endif
            Case GSTATE_SHOW_HIGHSCORE
                Print "HIGH SCORES ROUTINE"
        End Select
   
        Return 0
    End Method

    Method OnRender:Int()
        Cls
        Select gameState
            Case GSTATE_TITLE
                Print "DRAW TITLE ROUTINE"
            Case GSTATE_START_GAME
                Print "DRAW START GAME ROUTINE"
            Case GSTATE_PLAYGAME
                Print "DRAW PLAY GAME ROUTINE"
            Case GSTATE_GAMEOVER
                Print "DRAW GAME OVER ROUTINE"
            Case GSTATE_ENTERNAME_HIGHSCORE
                highScores.DrawEnterName()
            Case GSTATE_SHOW_HIGHSCORE
                Print "DRAW HIGH SCORES ROUTINE"
        End Select
        Return 0
    End Method

End Class


Function Main:Int()
    New CGame()
    Return 0
End Function
Depending on how you want to save data, it can get complicated.
This is one approach using one method for a High score table. NOTE: That this demo was just for show and doesn't use the full mojo framework.
Cerberus X:
Strict

' Import the file stream and the filesystem modules
Import mojo    ' Needed for getdate
Import brl.filestream
Import brl.filesystem

#Rem
    As building refreshes the data directory the path will be set to empty so that the hi score file will be at the same level as the executable
    Edit the DATAPATH constant to use the cerberus://data/ directory.
#End
Const DATAPATH:="" '"cerberus://data/"
Const ENTRIES:=20    ' Total number of high score entries. NOTE that you have to delete the old high score save file if you change this.

' Simple class data structure to hold a high score with the players name
Class CHighScore
    Field name:String
    Field score:Int

    Method New( n:String, s:Int )
        name=n
        score=s
    End Method
End Class

' The High Score Table class will create a new high score table or load a previous high score table
Class CHighScoreTable

    Field highScores:=New Stack<CHighScore>    ' Holds the entries for the high scores

    ' Either load a previously saved high score table or create a new one
    Method New()
        If FileType( DATAPATH+"hiscore.txt" )=FILETYPE_FILE
            Print "Found High Score File"
            ReadTableIn()
        Else
            Print "Creatings New High Score Table"
            For Local i:=1 To ENTRIES
                Self.highScores.Push( New CHighScore( "Player "+i, i*100 ) )
            Next
   
        Endif
    End Method

    ' Displays the high score table in reverse order. The last one pushed needs to be the highest score.
    Method ShowHighScores:Void()
        Local rank:=0
        For Local i:= Eachin Self.highScores.Backwards()
            rank+=1
            Print "RANK "+rank+" "+i.name+" "+i.score
        Next
    End Method

    #Rem
        Use this to check to see if the player has attained a high score.
        If the player has attained a high score; then it will return the rank position index, else it will return -1.
    #End
    Method IsHighScore:Int( s:Int )
        ' The index needs to start at the last item pushed onto the stack
        Local idx:=Self.highScores.Length()-1, hiScorer:CHighScore
        While idx >-1
            hiScorer=Self.highScores.Get( idx )
            If hiScorer.score<=s Exit
            idx-=1
        Wend

        Return idx
    End Method

    ' Update the high score table and write the results back to the high score table file.
    Method UpdateHighTable:Void( n:String, s:Int, idx:Int )

        ' Remove the bottom item from the stack before inserting the new high score.
        Self.highScores.Remove( 0 )
        Self.highScores.Insert( idx, New CHighScore( n, s ) )

        ' The updated high score file should be written here, but for this example it's going to be written else where.
        'Self.WriteTableOut()

    End Method

    ' Write the high score table to a file.
    Method WriteTableOut:Void()
        Local f:FileStream

        #Rem
            WriteShort, WriteString and WriteInt are high level stream operations.
            The stream position is automatically updated and any write errErrorn be caught within
            a Try/Catch block.
        #End
        Try

            f=FileStream.Open( DATAPATH+"hiscore.txt", "w" )    ' Open the high score file in write mode only.
            For Local i:=Eachin Self.highScores
                ' Variable name lengths
                f.WriteShort( i.name.Length() )     ' High score name length
                f.WriteString( i.name )                ' High score name is of variable length
                f.WriteInt( i.score )                 ' High score stored as a integer
            Next
            f.Close()
            Print "High score file successfully written."
   
        ' Report an error giving the position in the stream of where the write failed.
        Catch err:StreamWriteError
            Local p:=f.Position()
            If f<>Null f.Close()
            Error  "High Score Table write error! Position is "+p
        End
    End Method

    ' Read the high score table to a file.
    Method ReadTableIn:Void()
        Local f:FileStream

        #Rem
            ReadShort, ReadString and ReadInt are high level stream operations.
            The stream position is automatically updated and any write error can be caught within
            a Try/Catch block.
        #End
        Try
            f=FileStream.Open( DATAPATH+"hiscore.txt", "r" )
            Local len:=0, n:="", s:=0
   
            ' Read the data in until the End Of File has been reached.
            While Not f.Eof
                len=f.ReadShort()        ' Get the length of the name string to read
                n=f.ReadString( len )    ' Read the name string
                s=f.ReadInt()            ' Read the score
                Self.highScores.Push( New CHighScore( n, s ) )
            Wend
            f.Close()
            Print "High score file successfully read."
   
        ' Report an error giving the position in the stream of where the read failed.
        Catch err:StreamReadError
            Local p:=f.Position()
            If f<>Null f.Close()
            Error  "High Score Table read error! Position is "+p
        End
    End Method
End Class

' The first run will show the default table entries, subsequent runs should add a new player with a new high score to the table.
Function Main:Int()
    Local date := GetDate()
    Seed = date[3] * 3600000 + date[4] * 60000 + date[5] * 1000 + date[6]

    Local highScoreTable:= New CHighScoreTable()    ' Create a high score table

    ' Only add to the high scores if the high score file exists.
    ' Each re-run should give a different player with a different high score if the score is high enough.
    If FileType( DATAPATH+"hiscore.txt" )=FILETYPE_FILE
        Local names:String[]=[ "MikeHart","dawlane","Holzchopf","Martin","muruba","Phil7","Gerry Quinn","Dubbsta","PixelPaladin","Ferret3D" ]
        Local player:=names[ Rnd(names.Length()-1) ], score:=Int( Rnd(6000) ), idx:=highScoreTable.IsHighScore( score )
        Print "Generating new player high...."
        Print "Player: "+player+" with a score of: "+score
        If idx>-1 highScoreTable.UpdateHighTable(  player, score, idx )
    Endif

    ' Write the high score table to file before displaying it.
    highScoreTable.WriteTableOut()
    highScoreTable.ShowHighScores()
    Return 0
End Function
This link show another way to do a highscore table.
Thank you. I will try this now
 
Top Bottom