Jump to content
Sign in to follow this  

Recommended Posts

This is a thread, dedicated to the RXB game called "TI Game Engine X".
I wrote this game as entry for the programming contest that did occur until 31th July 2019.

Since the time was running out a bit, I wasn't able to completely showcase its possibilities.

 

First I will post the main program, its instructions again and then I will post a nice level for you.

  • Like 1

Share this post


Link to post
Share on other sites
Posted (edited)

Requirements:

Memory: 32K Memory Expansion
Input: Joystick No 1

Cartridge: RXB 2015 E

Preferred Emulator: Classic99 (developed and tested so far) 

 

Instructions:
You need to reach the end of the Level. You can move to the left and to the right. You can Jump and you will fall down, whenever there is no platform below you. The end of the level is always on the far right, and the game is scrolling automatically to the left. So be quick.

 

You can combine a Jump with a move to the right or left to reach a higher platform next to you.

 

You will loose a life if you fall into the ground or if you get stuck because of the automatic scrolling.

 

You have got 3 lives and have to do the whole level in one attempt.

 

Player Movement:
Joystick Left: Moving Left
Joystick Right: Moving Right
Joystick Fire: Jump

 

This game is inspired by a Game & Watch LCD Handheld called Super Mario Bros, released by Nintendo.

 

The game was created specifically in mind to participate in a Extended Basic Programming Contest, taking place in 2019.
The contest was about creating a game with a maximum of 10 lines of code.

 

This game as such is under Copyright of Klaus Lukaschek.

 

Thanks to Vorticon for hosting the contest, Tursi for the Classic99 Emulator, Mike Wight for making The Cyc, Matthew Hagerty and Marc Hull and Tursi for sharing their Sound Programming Knowledge, Rich Gilbertson for creating his RXB, Ciro Barile for inspiration and motivation and testing, my wife Sandra for her support, my brother Reinhard for learning how to program together.

 

I would love to have had some more time as the released version is running a very small level.

 

Some Tech Talk:

  • Multiple Statements per Line
  • Usage of Variables instead of direct Numbers Constants to win Line Length in critical areas
  • Scrolling part of the screen to the left by using CALL MOVES to copy bytes from VDP Ram to VDP Ram
  • Usage of Logical AND and OR in several places
  • Logical AND is used for bitwise operations
  • Sharing of Program Lines 8-10 for being called via GOSUB with a conditional RETURN or called as normal flow after processing Line 7.
  • Storing a repeating sound list in VDP Ram to be called by the Interrupt Service Routine.
  • CALL IO to talk to the Soundchip.
  • Soundlist is not stored in hexadecimal form to have 1 Byte consuming only 1 Byte, for this a transformation of the string is necessary.
  • Level Data consumes 1 Byte per Column
  • Definition and update of Player Sprite Location via CALL POKEV instead of CALL SPRITE and CALL LOCATE
  • Check for Level collision via CALL PEEKV instead of CALL GCHAR
  • Trimmed any '0' in the end of a CALL CHAR definition.
  • All numeric variables (constants) only have one character as their name.
  • Usage of _ and [ and ] and @ as variable names.
  • Usage of the system timer in >8379 to sync actions.
  • The game is actually an engine, limited to only containing one level for contest reason, therefore many levels can be created.
  • The name X refers to 10 meaning creating a Game Engine with only 10 lines of code.

 

Requires RXB!

OLD DSK1.GAMENGINEX

GAMEENGX.dsk

There was a more completed level released by me after the deadline of the contest.

OLD DSK1.LEVEL1

 

Classic99 Files:

GAMEGINEX

LEVEL1

 

Please ensure that your system&emulator pasting feature respects the seven Ascii Code 127 characters within the S$ string in Line 2.
For the Js99er Emulator check for the FPS rate to ensure the correct speed. It runs considerable slower in the attached RXB version in Js99er.
I used Classic99 for development and testing.

 

And as stated before. It is actually an Engine which includes a short level. And I realized reaching the end of the level is not done nicely in the released version.

I will document how different levels can be created.

 

Edited by kl99
  • Like 5

Share this post


Link to post
Share on other sites
Posted (edited)

First things first, an actual Level!

 

If you want to have a decent Level, try out this one that I made up just before.

In Line 1 you define the Level by setting the string variable L$:

L$="-(([email protected](""@MB,""TMJB<PH\BGH\""^BJHE(""(@8&TMG9RJJJRLKIFJJDKH2<P8""66N6NTHBB""(@9R*B*A(2828PCBH(@@([email protected]&""""""""_"

Line 1 should look like this:

1 _=0 :: K=1 :: H=4 :: I=8 :: M=H*I :: B=M-I :: D=52 :: L$="-(([email protected](""@MB,""TMJB<PH\BGH\""^BJHE(""(@8&TMG9RJJJRLKIFJJDKH2<P8""66N6NTHBB""(@9R*B*A(2828PCBH(@@([email protected]&""""""""_"

It now uses the maximum of 112 Level Steps to still fit with the Game Engine in 10 Lines. This was a rule for the contest.

 

The complete game then looks like this. Please be aware that only the Level Data was changed.

 

I figured out that atariage.com cannot handled Ascii Code 127 at all, which is part of the String Definition for the Autosound.

I therefore removed the Full Text version for copying via clipboard. Sorry for that confusion.

 

Instead go for the Disk Image containing the original Contest Entry loaded via OLD DSK1.GAMENGINEX
or with the Level Data included via OLD DSK1.LEVEL1

 

Go to this post for the files:

https://atariage.com/forums/topic/294259-ti-game-engine-x/?do=findComment&comment=4321477

 

Edited by kl99
  • Like 4

Share this post


Link to post
Share on other sites

How is a Level defined?

 

A level is defined in L$. Each byte in there provides the information for 1 Level Step.
A Level Step is what the game scrolls in one go: Each of the 3 vertical and each of the 3 horizontal lines either show or not show.

1 Level Step therefore contains 6 bit of used data, that are read out to figure out which horizontal and vertical bars to render in a given Level Step.

There is a Level complete character "_" to end the Level and therefore the game. This should be placed as last character to inform the Game Engine to stop.

A Level Step is defined by setting one single Ascii Char, using Range 32-95.

I reserved 113 Bytes for the Level Content.
 

It basically looks like this:

 

Binary    Bit Asc    Asc    Dec            Pattern
                    
000001    0    !    33    1            top |
000010    1    "    34    2            top _
000100    2    $    36    4            mid |
001000    3    (    40    8            mid _
010000    4    0    48    16            low |
100000    5    @    64    32            low _

 

Since we can only store Ascii codes from 32-159 in a CALL CHAR statement, I added an offset of 32 to the actual value representing that bit.

 

Starting from Ascii Code 32 you add the number on the right for the given bar you wanna show.

See pictures to get clearness.


The Game Engine performs the check based on the Information on the screen. If there is a wall that blocks the player he can not pass it. If there is a hole the player will fall into it. So you can be as creative with Level creation as you want. Of course there should be a way to reach the end of the level.

 

 

gex_level-step1.png

gex_level-step2.png

gex_level-step3.png

  • Like 4

Share this post


Link to post
Share on other sites

I have to say that you superbly took advantage of RXB's capabilities. Well done!

  • Like 4

Share this post


Link to post
Share on other sites

WOW well done. 

We need a video of this game.

  • Thanks 1

Share this post


Link to post
Share on other sites
11 hours ago, kl99 said:

Js99er Emulator seems to be missing the Required RXB 2015 E version. It runs considerable slower in the attached RXB version in Js99er.

It runs at the same speed in both emulators on my machine. Perhaps your host is too slow for JS99er? How many FPS do you get according to the JS99er log?

  • Like 1

Share this post


Link to post
Share on other sites
2 hours ago, Asmusr said:

It runs at the same speed in both emulators on my machine. Perhaps your host is too slow for JS99er? How many FPS do you get according to the JS99er log?

 

Hi Asmusr!

Thanks for the analysis tip. In fact I was below 40fps in my default Browser Firefox, too many Tabs. Chrome gave it full speed, cool! Did a full windows restart to get it at least to 53fps in Firefox. I have changed the warning on Js99er and removed the recommendation to only use Classic99.

  • Like 3

Share this post


Link to post
Share on other sites
Posted (edited)

This is a "decoded" view with variables named different to give some hint on their purpose.

Also I tried syntax highlighting to improve readability.

And each statement in the same program line starts in a dedicated row, with :: being removed.

For readability I removed the Constant Definitions and set the Numbers directly.

 

1   Level$="-(([email protected](""@MB,""TMJB<PH\BGH\""^B
            JHE(""(@8&TMG9RJJJRLKIFJJDKH2<
            P8""66N6NTHBB""(@9R*B*A(2828PC
            BH(@@([email protected]&""""""""_"

2   GOSUB 8
    CALL CHAR(33,RPT$("38",7),
              94,"0000000000FEFEFE0",
              96,Sprite$)
    SndEncoded$="CjEpECjEJCgDpECgDJCgDpJCg
                 DTCjEpECjEJCgDpECgDJClCp
                 EClC^[email protected]\"

3   FOR SndPos=1 TO 73
      SndPiece=ASC(SEG$(SndEncoded$,SndPos,1))
      SndDecoded$=SndDecoded$&CHR$(SndPiece-(SndPiece>63)*(SndPiece<96)*64-(SndPiece>96)*32)
    NEXT SndPos
    CALL MOVES("$V",73,SndDecoded$,1760)
    FOR Column=1 TO 31
      CALL VCHAR(7,Column,32,12,19,Column,120,48)
    NEXT Column

4   IF
      SpriteXChr=0
    THEN
      CALL MAGNIFY(3)
      SpriteXChr=25
      SpriteYPix=59
      CALL IO(1,1760)
    ELSE
      IF
        (Steps+1=LEN(Level$))
      THEN
        END
      ELSE
        IF
          (SpriteXChr<5)+(SpriteYPix>107)
        THEN
          CALL POKEV(771,SharedVar AND 1)
          CALL SOUND(-96,-1,0)
          Steps=0
          SharedVar=SharedVar+1
          IF
            SharedVar<16
          THEN
            4
          ELSE
            SpriteXChr=0
            Lives=Lives-1
            IF
              Lives<1
            THEN
              END
            ELSE
              GOTO 4

5   BitFilter=1
    Steps=Steps+1
    LevelData=ASC(SEG$(Level$,Steps,1))-32
    FOR Row=8 TO 14 STEP 3
      CALL VCHAR(Row,25,32-((LevelData AND BitFilter)>0),3)
      CALL HCHAR(Row+2,26,95+((LevelData AND 2*BitFilter)>0),4)
      BitFilter=BitFilter*4
    NEXT Row
    SharedVar=0
    CALL LOAD(-31879,0)
    IF
      Steps=1
    THEN
      9

6   CALL KEY(1,Ignored,FireInput)
    CALL JOYST(1,JoyInput,Ignored)
    IF
      FireInput+JoyInput=0
    THEN
      8
    IF
      FireInput=0
    THEN
      7
    PositCheck=SpriteYPix*4+SpriteXChr+52
    CALL PEEKV(PositCheck,ScreenVal)
    CALL PEEKV(PositCheck-96,ScreenVal2)
    IF
      (ScreenVal=191)+(ScreenVal2<>191)
    THEN
      7
    SpriteYPix=SpriteYPix-24
    CALL POKEV(768,SpriteYPix)
    SharedVar=1

7   IF
      JoyInput=0
    THEN
      8
    PositCheck=SpriteYPix*4+SpriteXChr+52
    CALL PEEKV(PositCheck,ScreenVal)
    CALL PEEKV(PositCheck-1-(JoyInput=4)*5,ScreenVal2)
    IF
      (ScreenVal2<>128)OR((ScreenVal=191)*(SharedVar=0))
    THEN
      8
    SharedVar=0
    SpriteXChr=MIN(MAX(5,SpriteXChr+SGN(JoyInput)*5),25)
    CALL POKEV(769,SpriteXChr*8+3)

8   IF
      Initialized=1
    THEN
      CALL PEEK(-31879,Timer)
      IF
        Timer<40
      THEN
        6
      ELSE
        SpriteXChr=SpriteXChr-5
        IF
          SpriteXChr>0
        THEN
          9
        ELSE
          PositCheck=SpriteYPix*4+61
          CALL PEEKV(PositCheck,ScreenVal)
          SpriteXChr=2-3*(ScreenVal=128)
    ELSE
      Sprite$="070F1F3F2D2510187F988D4D3F4F4438
               E0F8FCFE5C5008C8F0ACB2BAF4E4887"

9   CALL MOVES( "VV",24,230,225,
                "VV",24,262,257,
                "VV",24,294,289,
                "VV",24,326,321,
                "VV",24,358,353,
                "VV",24,390,385,
                "VV",24,422,417,
                "VV",24,454,449,
                "VV",24,486,481)

10  IF
      Initialized=1
    THEN
      CALL POKEV(768,SpriteYPix,SpriteXChr*8+3,192,1)
      PositCheck=SpriteYPix*4+SpriteXChr+52
      CALL PEEKV(PositCheck,ScreenVal)
      IF
        (SpriteYPix>108)+(ScreenVal=190)
      THEN
        4
      ELSE
        SpriteYPix=SpriteYPix+24
        CALL POKEV(768,SpriteYPix)
        GOTO 10
    ELSE
      Initialized=1
      Lives=3
      RETURN

 

String Constants:

Level$

String containing the Level Data. One Byte represents the information for one single Level Scroll Step.

Uses Ascii code values from 32-95 to represent 6bit of data.

Sprite$

Sprite Definition Hexadecimal Code, Sprite uses 4 characters.

SndEncoded$

Soundlist in encoded form to not have to use hexadecimal format which would require 2 bytes for one byte of data. With this it one byte of data only requires one byte of data.

 

String Variable:

SndDecoded$

Soundlist in the necessary form to store in VDP Ram. The soundlist will be called from the Interrupt Service Routine. It consists of the Intromusic plus the repeating sound. The live lost sound is done with a CALL SOUND.

 

Numeric Variables:

BitFilter

Column

Helping Variable referring the current Column that gets cleared/drawn. It starts with Column 1 and ends with column 31.

FireInput

JoyInput

Ignored

Necessary Variable for CALL KEY and CALL JOYST which is assigned by those subprograms but not used by the program.

Initialized

This is used as a Flag to direct the program execution within Program Lines 8 and 10. In case this Flag is set, meaning containing Intialized=1, then the Program Lines 8 & 10 run another way than if the same Program Line 8 is called before the Initialize has happened.

LevelData
Lives

The Variable that represents the number of Lives (Tries) you have. It is initialized with 3. The program checks if there is a life left in case you loose a live. If not, the program ends.
PositCheck
RowSharedVar
ScreenVal

ScreenVal2
SndPiece
SndPos
SpriteXChr

Refers to the current X location of the Player Sprite. It is not representing the Pixel Column but actually the Character (1-32) Column where the Player is rendered. Values are 5,10,15,20 or 25. If the Player gets stuck in the left, the Value can shortly be 0 or 2.

SpriteYPix

Refers to the current Y location of the Player Sprite. It is representing the Pixel Column. Values are 59,83,107. If the player falls down the Value can shortly be 131.

Steps

Refers to the number of the current Level Step that is being rendered at the most right screen. The screen shows 5 full rendered Steps, and at the very left in addition one 3/5 Step.
Timer

The game is using the system timer in the CPU Ram at location >8379. This is part of the GPL Status Block. I reset this Timer to 0 after drawing the next Level Step on the right side and directly before returing the program control to the Joystick Input. The GPL interpreter/TI operating system increments this Timer automatically. Like this i can read the value again after a while to figure out whether the Player should still have time to move the Sprite or whether it is time to perform the Scrolling. Checking this Variable against another Value than 40 will change the speed of the game. The check against 40 in Program Line 8 means the Player has time between 0-39 to move around with the game scrolling. If you check it against a lower Number than 40, the Player will have less time, but the Scrolling will be more smooth. Defining this Number to a good value needs to match the Level Data to still be able to reach the end of the Level.

 

Program Flow = WIP

 

RUN from RXB prompt...

 

Line 1 Define Level$

Line 2 GOSUB 8

...

Line 8 IF Initialized=1 THEN ...  ELSE Define Sprite$

Line 9 harmless line that we can execute with no benefit this time

Line 10 IF Initialized=1 THEN ... ELSE Define Initialized & Lives :: RETURN

 

The Initialized Flag was a speed compromise to use the free space within Program Lines 8 and 10.
Like this Program Line 8 sets the 63 byte long character definition for Sprite$.

Like this Program Line 10 defines 5 numeric constants, the numeric variable Lives and 1 string constant.

Remember that Line 8, 9 and 10 are called as a Subprogram and require a RETURN at the End of Line 10.

When called later 8, 9 and 10 are no longer a Subprogram.

 

The Program Flow continues after the RETURN from the GOSUB call like this:

Line 2 [GOSUB 8] :: Load Characters for Platforms, Screen and Sprite$
       Define SndEncoded$

Line 3 Create SndDecoded$ from SndEncoded$ and write it to VDP Ram.

       Draw the background and empty the foreground screen.

Line 4 IF SpriteXChr=0 THEN
         CALL MAGNIFY(3)
         Define SpriteXChr & SpriteYPix
         Activate Soundchip for autoplaying the Soundlist
        ELSE ...

Line 5 Render one Level Step at the right
       Reset Timer
       IF Steps=1 THEN 9

...

Line 9 Scrolling Screen Lines to the left

Line 10 IF Initialized=1 THEN
      Render/Rerender Sprite
      IF
        (SpriteYPix did completely fall down)

        or

        (Sprite is on a Platform)
      THEN
        4
      ELSE
        Player falls down one step (24 pixels)
        GOTO 10
    ELSE ...

 

The Program is finally fully initialized and will never come back to Lines 1, 2 or 3:

 

Line 4 IF Player reached the end of the Level THEN END
       IF Player got stuck at the left or Player did completely fall down
        THEN
          IF Last Life Lost THEN END

          Handle Life Lost
          Reset SpriteXChr
          GOTO 4

Line 5 Render one Level Step at the right
       Reset Timer

Line 6 Input, Handling Jump Input including Sprite update

Line 7 Handling Left/Right Input including Sprite update

Line 8 Check for Timer and jump to Line 6 if End of Timer is not reached.

       Prepare Sprite Update, Handle Sprite at very left situation.

Line 9 Scrolling Screen Lines to the left

Line 10 IF Initialized=1 THEN
          Render/Rerender Sprite
          IF
            (SpriteYPix did completely fall down)

           or

          (Sprite is on a Platform)
          THEN
            4
          ELSE
            Player falls down one step (24 pixels)
          GOTO 10
        ELSE ...

Edited by kl99
  • Like 2

Share this post


Link to post
Share on other sites

Any plans to expand this, allowing for possible improvements beyond the limits of the 10-line contest constraints?

  • Like 1

Share this post


Link to post
Share on other sites
13 hours ago, jrhodes said:

Any plans to expand this, allowing for possible improvements beyond the limits of the 10-line contest constraints?

Yes, it has too much potential to keep it as such. I wrote already that I run out of time with completing the code, therefore I am still working on it.

Also the 10-line limit makes it slower than necessary. And the levels could be loaded from dedicated files on the disk to make it more flexible.

  • Like 4
  • Thanks 1

Share this post


Link to post
Share on other sites

All the games in 10 line game should now convert the game to a "full" game. All the games deserve a "full" game!

  • Like 1
  • Thanks 1

Share this post


Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...
Sign in to follow this  

  • Recently Browsing   0 members

    No registered users viewing this page.

×
×
  • Create New...