• Please review our updated Terms and Rules here
  • Exhibitor application for VCF West 2022 is now open! If you are interested in exhibiting, please fill out the form here.

CGA 160x100x16 bidirectional scrolling

resman

Experienced Member
Joined
Jan 1, 2014
Messages
493
Location
Lake Tahoe


isotest.png

I've always been a fan of the isometric view for games. It is a visually interesting projection that combines the simplicity of a top down view with a pseudo-3D aesthetic that conveys a sophisticated image without the overhead of a real 3D implementation. I figured that the LORES library might be able to pull off a simplified isometric environment, but there are a few issues to work through in order to do so.

One of the constraints of the LORES library scrolling actually works in our favor: scrolling horizontally by two pixels with the ability of scrolling vertically by one pixel matches well with the 2:1 aspect ration of an isometric tile. And that is about the only common ground between the LORES library and isometric tiles.

The LORES library is based around square 16x16 pixel tiles. Isometric tiles (technically, these aren't perfect isometric tiles) look more like flattened diamond shapes with a 2:1 aspect ratio - two pixels wide for each vertical pixel. This gives the impression of looking at a scene from a 45 degree diagonal and an elevated height. I took the approach of mapping 32x16 isometric tiles to 16x16 square tiles using a combination of modern tools and my image converter program, 'slicer', found in the MAPEDIT directory. Note that it isn't as simple as just making tiles that are twice as wide as the 16x16 LORES tiles - the isometric tiles' origin alternates from intersecting the 16x16 tile grid to halfway between the LORES tile grid. Read on to see my conversion workflow...

Creating an Isometric Grid and Map​

Watching some YouTube videos on how all the cool kids create their isometric tile maps for use in Steam, I found a very nifty program called Aseprite: https://www.aseprite.org. I went ahead and bought this tool, affordably priced at $20 for a LOT of functionality. I created my first test map using Aseprite, but realized that I could have done everything just as easily using GIMP: https://www.gimp.org. So I exported the map file over to GIMP and worked from there.

The Isometric Grid​

First, I created an isometric grid to align the 32x16 isometric tile to the 16x16 square tiles and create a guide for drawing the isometric tiles. Image layers are a powerful tool used in many image manipulation programs like Photoshop, Aseprite and GIMP. Taking advantage of this tool is very useful. I created the base layer as the isometric grid. Drawing the actual isometric tile images on transparent layers above this allows for easy edge alignment. Use as many layers as you want for floors, walls, etc. By keeping them on separate layers as you draw them makes arrangement a breeze. I also made a solid black layer just above the grid layer that I normally keep invisible so the grid shows through. By toggling its visibility, it shows me what the map looks like without the underlying grid.

Isometric Tiles​

Using layers for different tiles makes for an easy alignment process. For instance, create a floor tile that will be used many times. I will create the base tile off to the side. Once satisfied, I will select it and copy it. Then the copy can be pasted around the map using the grid as a guide. You will find my 'isotest.xcf' GIMP image file that has all the isometric tiles flattened to one layer.

Exporting Map for Slicing and Conversion​

When it's time to convert the isometric map into something digestible to LORES, set the visibility of the black background layer (or whatever color you want for the background) to 'visible' and export to a '.pnm' Portbale BitMap format using 'Raw' data values. This will be fed into the 'slicer' tool. The slicer tool is very generic C code that should compile under just about any modern platform. It takes a Portable BitMap '.pnm' file (raw RGB values with a simple ASCII header) and converts it into a '.SET' tile set file and a '.MAP' tile map file ready to import using the LORES MAPIO functions or further editing with MAPEDIT. 'slicer' will reduce all identical tiles into one to save memory so it is important to carefully align the isometric tiles and not introduce any spurious pixels that will cause additional tiles to be generated. My command line to for conversion is:

../MAPEDIT/slicer -g 1.8 -n isotest

This uses a gamma of 1.8 and disabled dithering for a closest 4 BPP IRGB color match, creating 'isotest.set' and 'isotest.map' from 'isotest.pnm'.

ISOTEST.EXE​

Finally there is a test harness program to scroll around the map. It simply uses the four arrow keys to scroll along the isometric axes, quitting with the 'ESC' key. It includes two additional routines to convert between world coordinates (s,t) and screen coordinates (x,y).

Limitations​

Of course there are going to be limitations to what can be accomplished with the LORES library and what one might expect from a modern isometric implementation. Most isometric games allow characters to move behind objects and be properly occluded. LORES has no such concept, so care must be taken to keep objects/sprites always in front or hide them completely when occluded. Adding height to the tiles isn't impossible, but will take additional programming effort over what I've done here. Remeber there is a limit to the number of sprites that can be updated per frame, so don't expect to be able to implement melee of fighting sprites without clever programming & scheduling.

Future Effects​

Adding visibility to the map is one thing I would like to explore. Populating the map as the player moves through the map so the entire map isn't exposed all at once should be quite doable.

Asset files and executable can be found here: https://github.com/dschmenk/LORES/tree/main/SRC/ISOTEST
 

resman

Experienced Member
Joined
Jan 1, 2014
Messages
493
Location
Lake Tahoe

2D Platformer Test​


The most obvious use of the CGA LORES library is to create a 2D side view platformer style game. This is a simple Lode Runner looking test to try out the new sprite page slicer:
Code:
            Controls:
                LEFT ARROW  - run left
                RIGHT ARROW - run right
                UP ARROW    - ascend ladder
                DOWN ARROW  - descend ladder

Implementation Details​

I discovered that there is a vibrant community building Game Boy games. The Game Boy has a graphics resolution of 160x144 which maps pretty well to the 160x100 CGA LORES resolution, at least as far as assets go. Even the tile size of 16x16 matches the LORES tile size. So there are potentially lots of available assets from the Game Boy development community. Look at Game Boy Studio for many ideas and great pixel artwork.

The running/climbing/falling man sprite is derived from the Game Boy Kung Fu Man available here: https://chasersgaming.itch.io/rpg-asset-character-kung-fu-man-gameboy. This is also a great site for assets. The PICO-8 is a fantasy console that has a community of asset creators that also matches well to the LORES library.

Once again, the limitations of a 4.77 MHz CPU raises its ugly head. Even though this sprite doesn't look very big, it really pushes the limits of the number of pixels that can be updated during inactive video. It is a 14x23 pixel sprite which is only 294 pixels, but that pushes our poor 8088 to its limits. If scrolling and other sprites are going to be updated, care will have to be taken to ensure timing doesn't cause sparkles or tearing.

However, I think it looks great.

As always, source and binaries are available here: https://github.com/dschmenk/LORES/tree/main/SRC/PLATFORM
 

CP/M User

Veteran Member
Joined
May 2, 2003
Messages
2,981
Location
Back of Burke (Guday!), Australia
It doesn't sound highly optimized if a single sprite 14x23 is pushing a 8088 to it's limited in LOW-RES. My Amstrad runs at 4Mhz, there's no hardware sprites with a Z80A processor (same as Gameboy), LOW-RES at 160x200. Are you drawing the Sprite from Pixel or using Bytes to Mask the Sprite?
 

VileR

Veteran Member
Joined
Jul 21, 2011
Messages
550
Location
Israel
The 8088 only gets a small fraction of the total frame time to push all this data out, if you want to avoid display issues. That's a limitation of CGA architecture in this particular mode. I don't think the Amstrad CPC or Gameboy have similar constraints (could be wrong of course).

The 'safe' limit is probably around twice the size of that sprite, but on top of that it also has to scroll... so it's a tight squeeze.
 

resman

Experienced Member
Joined
Jan 1, 2014
Messages
493
Location
Lake Tahoe
It's sometimes hard to remember just how slow a 4.77 MHz 8088 is. It really is about the same performance as its contemporary 8 bit CPUs. In contrast, my 7.16 MHz Compaq Deskpro with a NEC V30 can run the entire game loop during inactive video with time to spare. But since I'm targeting the original IBM PC (and Compaq Portable)...

In this case, the size of the sprite is only half the story. In order to update the sprite without an erase/redraw cycle, I pre-render the sprite with the background that overlaps the previous sprite position into a memory buffer and use one draw operation to update the screen. So the effective size up to 50% more than the actual sprite (I had to increase the overlap border size for this test) and the draw operation is really nothing more than unrolled memory move instructions. As VileR mentioned, updating the screen memory has to occur during inactive video - there is no double buffering and you can't really race the beam because accessing video memory during active video will case sparkle artifacts (snow).

The consolation is that you have the opportunity to update the screen 60 times a second, so you don't have to do everything at once. The trick is to schedule what gets updated and when, giving the impression of fluid animation. Makes me feel like the Atari 2600 guys had it easy ;-)
 

resman

Experienced Member
Joined
Jan 1, 2014
Messages
493
Location
Lake Tahoe

2D Side Scroller Test​

The above platform test now with scrolling!


If anyone wants to test this out on a 4.77 MHz 8088, I'd appreciate the feedback. Vertical or horizontal scrolling should make timing, but the cases where our hero jumps and it scrolls diagonally may push the envelope. There *may* be snow. It looks fine on my Compaq Portable, but it doesn't suffer from snow. The profiling bars creep in to active video when this happens, so I'm not hopeful.

This version is actually updating the sprite every other frame, leaving time for additional sprites/game logic to run during the opposite frame.
 

Attachments

  • SideScroller.zip
    63 KB · Views: 2

Plasma

Veteran Member
Joined
Nov 7, 2005
Messages
1,228
I don't have real hardware setup to test on but it looks great in dosbox. What are the differences between the EXEs? Also is there a key to jump?

How many enemies can you add at 4.77 MHz?
 

resman

Experienced Member
Joined
Jan 1, 2014
Messages
493
Location
Lake Tahoe
I don't have real hardware setup to test on but it looks great in dosbox. What are the differences between the EXEs? Also is there a key to jump?

How many enemies can you add at 4.77 MHz?
Thanks for trying it out.

The four binaries are the four build options: Microsoft C 5.1 or Borland C++ 3.1 with and without profiling bars (border color). You will only see the profiling bars on a real CGA, so useless for emulation or EGA/VGA. So:

PLATFORM.EXE = MSC no profiling
PLATFRMP.EXE = MSC w/ profiling
PLATBC.EXE = BC31 no profiling
PLATPBC.EXE = BC31 w/ profiling

Now, I didn't add a jump key for a few reasons, but mostly this was just a test to see if developing this test into a real game would be worth it. It wouldn't be hard, but I'd have to add more art for the hero sprite.

Have I covered the bases for the different styles of scrolling games? Is there something else I should provide a demo/test for? Does anyone really care?
 

resman

Experienced Member
Joined
Jan 1, 2014
Messages
493
Location
Lake Tahoe
How many enemies can you add at 4.77 MHz?
Forgot to answer this part of your question. And it's a good one. I should say "That is left as an exercise to the reader" or something along those lines ;-) Of course the correct answer is "It depends".

If you look back at the other demos, you will notice a few "cheats" to have enough enemies on screen to make it interesting. In RepelZ, the enemy tanks and SAM installations are actually tiles, not sprites. Looking at it as a cost analysis: tiles are cheap, sprites are expensive. When enemies are destroyed, an explosion sprite overlays the enemy tile as it gets updated to a tile of a destroyed enemy. The biggest issue of using tiles over sprites is that they are mostly non-moving and static. RepelZ does use sprites for the drone and missiles but they are small and can be updated along with scrolling the map.

With Invaders, there are many sprites on-screen at a time that appear to be moving all at once, but they are actually updated in a round-robin fashion, one per video frame so as to not overload the CPU with inactive-video updates. However, Invaders doesn't scroll during gameplay so the only updates are the sprites.

With PLATFORM, I'm trying to push the boundaries with a large animated hero sprite and simultaneous scrolling. If the enemies and other objects can be implemented with tiles, then there is a minimal impact to rendering overhead. If there are going to be sprites on-screen with the hero during scrolling it then gets more interesting. The LORES library has to keep track of updates to sprites (and tiles that change) every frame. It does intersection checks between sprites, changed tiles, and screen boundary visibility during scrolling. Even if a sprite doesn't explicitly get updated in the game loop, it will be flagged for redraw should it hit any of the intersection tests. The implication is that if our hero sprite moves and the screen scrolls causing another sprite to become visible, our poor 4.77 MHz 8088 may fail to get all the drawing done during inactive video.

That may have been more of an explanation than you wanted. Hope that helps answer some of the challenges, though. Anyone want to try their hand at writing a LORES game/demo?
 
Last edited:
Top