Jump to content
IGNORED

Is 10 FPS a too low framerate for a LYNX tile based game?


Nop90

Recommended Posts

I'm working on the port of Xump for the lynx and at the moment I have a working alpha with one level and without music/sfx.

 

The first working build had about 4 FPS during gameplay. Optimizing the code I reached steady 7 FPS. Now I'm moving things in a cart filesystem to load title screen and menu backgrounds only when needed, so I can have other memory to make more optimizazions. I think I can reach about 10 FPS, but no more, mostly because to maintain the original level fomat I have to use small 8x7 px tiles.

 

Kojote, the Retroguru team leader, thinks this is a too low FPS for an official release, but it seems to me that some commercial games have worst FPS.

 

What do you think about this? Is it worth to continue the project with such a performance limit?

Link to comment
Share on other sites

Assembly is an option, but my ASM skills are very rusty and I should rewrite all the game engine. Probably I'll try to optimize a little more the C code first.

 

The screen is very static, there is only the player sprite moving and some animates tiles. The alpha version I have is not bad IMHO, getting some more speed could be enough.

 

At the moment I'm testing it with mednafen on a Linux VM on my PC, and with the online emulator on atarigamer. I'm in the waiting list for a SD cart, so I can test it on my Lynx, but I don't expect big differences.

  • Like 1
Link to comment
Share on other sites

I'm using 3 sprites. One for the game header (where score and time are placed), one for text chars and one for the tiles (about 20 tiles).

 

Here is a screenshot of the game screen:

post-66453-0-42888000-1547672350.png

 

Please don't judge the gfx quality, they are only a fast rescaling of the original tiles. If this project reach an acceptable level of quality we will hire a gfx artist to make better graphics.

 

At the moment I'm testing the code to find FPS bottlenecks.

 

Commenting out the tiles drawing loop and the animation logic (i.e. drawing only the header, the topscreen numbers and the player tile) I have 50 FPS. I can't go faster than this even if I remove all the drawings. Maybe an emulator limit?

 

Simply using tgi_clear() the framerate drops to 25 FPS. I'm avoiding to use it.

 

Both the tiles drawing loop and the game logic are very CPU intensive, so I', going to work them now.

 

I also tryed using a single buffer, drawing only changes to the screen, but the speed is still to low and I have a lot of flickering, so at the moment this isn't a good solution.

 

 

 

Link to comment
Share on other sites

tgi_clean() probably clears the screen (by drawing a large pixel I assume).

Also you dont need to draw all tiles each 'frame'.

Just draw those that changed (but in a double buffer, that is fine).

That should work in C as well. How tight is your memory currently?

Link to comment
Share on other sites

I'm using 3 sprites. One for the game header (where score and time are placed), one for text chars and one for the tiles (about 20 tiles).

 

 

 

Why this complicated? Why not drawing the tiles and all this directly? Now you are "drawing" into some buffer to use it as sprite data to use Suzy to draw it to the screen?

 

BTW: Atari recommends to use 60Hz screen refresh. 50Hz flickers a lot on the old LCDs.

 

Link to comment
Share on other sites

 

Why this complicated? Why not drawing the tiles and all this directly? Now you are "drawing" into some buffer to use it as sprite data to use Suzy to draw it to the screen?

 

BTW: Atari recommends to use 60Hz screen refresh. 50Hz flickers a lot on the old LCDs.

 

 

In the site structure I'm only changing the pointer do the pixel data, the I let Suzy draw it. I suppose this is faster than writing directy to the video buffer.

 

I set the screen refresh at 75FPS, 50FPS is what i get o the emulator doing almost nothing.

Link to comment
Share on other sites

 

Both the tiles drawing loop and the game logic are very CPU intensive, so I', going to work them now.

 

 

 

 

 

Tiles drawing loop ?

Do you mean you draw each tile individually inside a loop ?

If so, you'd better create a list a chained sprite, it uses a bit more memory but is far more efficient.

If your level is never changing, you only declare it once at the beginning and only have to make a DrawSprite in your game logic loop.

If it change sometimes (tile disapearing for example), you just have to change the pointer to pixel data of the sprite when needed.

Link to comment
Share on other sites

Chained sprite. This is new to me, but now I understand that *next in the sprite struct.

 

So I can declare an array of sprites and initialize them with the game map (position, pixels data pointers and the chain) when loading the map.

 

Thanks, I'll try this way.

Link to comment
Share on other sites

This should improve a lot your FPS.

We made a test with Anata years ago on a Mario like level with scrolling, it was unplayable without sprite chaining and smooth once sprite chaining was used.

 

You can create an array of sprites (just like your array of tiles - but think of setting visible flag to no to the item not to be displayed) or create a list of sprites, and declare only visible tiles. This is more efficient in memory, but is a bit more difficult to make the link between sprite and tile if needed.

The first sprite must a be a "real and complete" sprite declaration, but the next one can bypass zoom end color definition to gain some space if every definition is the same (look at Mathias or Bastian source code for old newcc65 for example).

Link to comment
Share on other sites

For Lacim's Legacy I generate speedcode/sprite chains on the fly :)

It might be faster to plot a single empty sprite rather than disabling it in the chain (since you modify pointers already you dont have to deal with the skip-sprite flag code).
At least that was the the case for me :)
You can also speed up the process alot if for example the top and/or bottom part of the chain isnt updated very often. Just enter the chain at a later point and modify it to return earlier.

Link to comment
Share on other sites

 

 

Are you using linked sprites?

 

Apparently the answer is no :)

 

And yes, that's the problem!!!

 

It's easy to solve luckily :)

1) Define an initial SCB with a size, position, data, palette, scaling,

2) Then link it to a second SCB that only define data and position (as you reuse the scaling and the palette of the first SCB - you need to set the CTL flags correctly - check the docs for that).

3) GOTO 2) for all the tile of your level

4) Just draw your first SCB and - automagically - the whole level will be drawn with this single call :)

 

edit: for instance here are the SCB definition for my level (also tile-based). Note that I'm using the old compiler, so it might look a bit different in the new compiler but you get the idea. Note also that I need to define an array of size X to store X copy of _SCBLevelNext.

 

 

_SCBLevel: dc.b $c0, $10, $20 ; CTL0, CTL1 = zoom X/Y, NO COLLISION

dc.w _g_arrSCBLevel ; NEXT (pointer to the linked list)
dc.w 0 ; DATA (dummy sprite)
dc.w 0, 0 ; X & Y position
dc.w $100, $100 ; Width and height (256 = normal)
dc.b $01, $23, $45, $67, $89, $ab, $cd, $ef ; Palette definition
_SCBLevelNext: dc.b $c0, $08, $20 ; CTL0, CTL1 = reuse existing palette, NO COLLISION
dc.w 0, 0 ; NEXT, DATA
dc.w 0, 0 ; X & Y position
Edited by LordKraken
Link to comment
Share on other sites

Also, you might consider:

- to use Enthusi trick of entering the SCB chain a bit later, and exiting it a bit earlier, updating only the part that has been actually modified,

- OR to increase the size of your sprites a little bit.

 

Right now, even with linked sprites, you still have a fair amount of sprite to draw (260 to cover the screen whil I only need 100 with 12 * 12 pixels tiles)

Edited by LordKraken
Link to comment
Share on other sites

Also, you might consider:

- to use Enthusi trick of entering the SCB chain a bit later, and exiting it a bit earlier, updating only the part that has been actually modified,

- OR to increase the size of your sprites a little bit.

 

Right now, even with linked sprites, you still have a fair amount of sprite to draw (260 to cover the screen whil I only need 100 with 12 * 12 pixels tiles)

 

260 sprites? Why? The backdrop, title, title bar, score (10), player and the field (< 80): ~ 100 sprites

Edited by 42bs
Link to comment
Share on other sites

He wrote that his sprite are 8*8, so 160 / 8 = 20 sprites for a line and 102 / 8 = 12 sprites for a row, so 20 * 12 = 240 sprites to cover the screen (and you have to add a line and a row for scrolling on top of that - if you want scrolling oc).

So even if you remove the upper part with the title and the score, it's still a bunch of sprites.

Edited by LordKraken
Link to comment
Share on other sites

I think the approach is not suitable :)

If I were going for such a layout, I might end up doing draw-loops in code actually but only those that were marked 'dirty' by moving objects.

Ignoring a few you can still easily ,x index a list of tiles and check for dirty (or also other) flags.

Link to comment
Share on other sites

He wrote that his sprite are 8*8, so 160 / 8 = 20 sprites for a line and 102 / 8 = 12 sprites for a row, so 20 * 12 = 240 sprites to cover the screen (and you have to add a line and a row for scrolling on top of that - if you want scrolling oc).

So even if you remove the upper part with the title and the score, it's still a bunch of sprites.

 

So the design needs to be re-considered. As from what I have seen so far, the "playfield" are the stones the player walks on (BTW, anyone remember Oxygen on ST or Enigma, similar game). The rest is "background". No need to split up the background in tiles.

If the background is static, then it would be even easier, as you only need to draw the modified parts.

I wonder what FPS Loopz or Lemmings has ...

Link to comment
Share on other sites

I'm restarting the port from scratch. Drawing tiles is one of the reasons for low FPS, but the other one seems to be the use of an array of struct for the gamemap. I'll code something faster to address.

 

At the moment I created a new cart structure with the intro, the main code (for now only the menu,the pause screen and the gameover screen), the different backgrounds in separate cart files, and the first bg music (also in a cart file).

 

Now I'm adding the 48 levels data in separated cart files. I think I'll load them in the back buffer because I need them only to setup the level map at the beginnig of every level. This way I can save another 1kB of memory.

 

If I don't use animated tiles I can draw the full level only once, than I can draw less than 20 chained sprites every frame. This should give a good result.

 

But to do this I have to understand how to use a single buffer. Using two buffers I need to maintain the two buffers aligned (every frame I have to draw the previous changes than draw the new changes) and this doubles the number of sprites to draw.

 

Can you give me an hint about this? If I can use on lynx a smart trick, a code snippet would be apreciated.

Link to comment
Share on other sites

Before you start to write code for the whistles and bells, I'd study what is possible to draw in one VBL. Maybe you can "animate" by color cycling?

Using two static buffers means, you just have to redraw the parts that change, but in both. If this is quicker than redrawing everything needs to be tested.

 

There is a book about r-type for the Spectrum. IIRC the coder used to redraw only the modified parts but with double buffering.

 

I just checked: In Invaders, I use a single buffer and just remove the aliens at old position and draw at the new one. I had to do this because the alien-shots destroy the bunker.

Link to comment
Share on other sites

In Solitaire I used a static buffer for the table and all the cards and drew only the zoomed up pile while playing. Erase was copying areas from background and drawin was directly to screen, But now I am simplifying the cards and going back to normal dbl buffering. It looks so much nicer.

Link to comment
Share on other sites

Thanks. I know the basic concepts of single and double buffering, have only to make some experience with them on the Lynx.

 

Finished adding the levels to the cart structure, now I'm going to implement the data structure for the level map and the loading code, than the new drawing logic.

Link to comment
Share on other sites

I created the cart structure using the cart template and almost everything went fine, but the game freezes at startup if I use in the code the clock() function or the CLOCKS_PER_SEC value;

 

The same code works loading the whole code in ram (without using the cart structure), but while in a cart structure the code freezes even if the call to clock() is in a part of code not loaded (at startup I load the intro, but the call to clock() is in the game section loaded from the cart after the intro).

 

Could be a problem of the linker? Does somebody else had this problem? Can you find me to find a solution?

Link to comment
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.
Note: Your post will require moderator approval before it will be visible.

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...
  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...