Jump to content

new game: Asteroid Commander


Recommended Posts

Posted (edited)

I've been noodling this game idea in my head for several years, and finally decided to do it on the Commander X-16.  This isn't in a playable format yet; I spent several months just generating the lookup tables for it, and this is the first time I've had anything at all to show.  I'm gong to use this thread to post updates and releases as progress happens.

Asteroid Commander will be a game sort of like SimCity, in space, with a storyline.  There's no sound in this video.

The asteroid is procedurally generated, and the image is raytraced - for certain very limited definitions of raytracing.  The shadows are very rough right now and I can see I have a bit of work to do on the ray maps, but the toughest part of the game engine is basically done.

Edited by Ed Minchau
  • Like 13
Link to comment
Share on other sites

4 hours ago, rje said:

I love the look!  And of course I like the idea of a new sim game.

Thanks, but it's about to look much better, as I'm reworking the ray maps. This is just the medium view, there will also be a closeup view and a far-out view. And at the rate I'm going it'll take me a year to finish this.

Link to comment
Share on other sites

6 minutes ago, Ed Minchau said:

Thanks, but it's about to look much better, as I'm reworking the ray maps. This is just the medium view, there will also be a closeup view and a far-out view. And at the rate I'm going it'll take me a year to finish this.

All of my hobby projects take awhile, and most of them don't get finished.  

So how do you want the sim to work?  

Oooh, I just had a thought that it could be combined with a space-station-building game. 

Since it's an asteroid colony, you'd have

  • support buildings (power and life support)
  • science buildings (for contracts),
  • revenue buildings (mines, refineries, fabs?),
  • and habitats...

hmmm this could be really fun.  I don't want to kitchen sink it, but I imagine personnel would have to transfer in and out via a shuttle service (perhaps behind the scenes).  That would enforce a population "phase" into the game that could be interesting (or not).

 

 

Edited by rje
Link to comment
Share on other sites

Yeah, the far-out view is for stuff orbiting the asteroid.  I don't think I'll get quite so  detailed as to have the player micromanaging shuttles or other vehicles.  The player will mostly be deciding what buildings to place or upgrade and trading with other locations in the solar system.  As far as the asteroid population, they're part of the storyline (which will be optional; the player can ignore the story and just be Asteroid Mogul).

Link to comment
Share on other sites

39 minutes ago, Ed Minchau said:

I don't think I'll get quite so  detailed as to have the player micromanaging shuttles or other vehicles.

Agreed - I wasn't suggesting a kitchen sink, and while I like "build-it" simulations, I don't like "micromanage it" simulations so much.

Quote

The player will mostly be deciding what buildings to place or upgrade and trading with other locations in the solar system.  As far as the asteroid population, they're part of the storyline (which will be optional; the player can ignore the story and just be Asteroid Mogul).

YES.  This sounds like it hits the sweet spot for me.

 

Edited by rje
Link to comment
Share on other sites

Posted (edited)

So I finally found the bug that was glitching the display on the outside edge of the asteroid, missing a single INC command.  I also slightly increased the speed of the display. The asteroid won't be spinning this fast in the game, I just needed to do this for the test.  I've also tweaked the terrain primitives a bit, and now I'm starting to see craters on the surface. This is particularly noticeable on the low areas on the other side of this particular asteroid, and with a little more tweaking I should have it showing craters on the high areas too.  After I'm satisfied with the look of the asteroid, I'll start on the other display elements and bring in the mouse.  You'll be able to click on the direction arrows in the middle to navigate around the asteroid and rotate your view.  The next step after that is to start displaying text, and then I'll work on the buildings and the background stars and sun.

Edited by Ed Minchau
Link to comment
Share on other sites

Posted (edited)

Making progress.  Now there's craters.  Some of them are a result of the revamped terrain primitives, and just occur as a result of putting the terrain pieces together.  The rest of them are "buildings", up to 16 of them placed around the asteroid.  The terrain is based on a bunch of bits extracted from the commander name and the asteroid name.  There's about a million possible asteroids, which is actually kind of low; there's an estimated quadrillion asteroids of this size (~1km) in our solar system.  If you name yourself Invader Zim and call the asteroid X16 Of Doom, this is the asteroid you'll get.

craters.jpg

 

craters2.jpg

 

craters3.jpg

Edited by Ed Minchau
Link to comment
Share on other sites

Posted (edited)

The asteroid is based on an icosahedron.  This was tessellated once to give a figure with 80 triangular sides, 20 equilateral and 60 isosceles but close to equilateral, with a total of 42 vertices.  Each of those 80 triangles was further subdivided into 81 triangular "cells", which are grouped in three groups of 27 cells in a wedge shape.  So there's 6480 cells on the map,   grouped into 240 "wedges" each with 27 cells.  There are also 16 terrain primitives, each with 27 cells.  The  80 big triangles are all assigned a height, either High or Low, and the  42 vertices are also assigned High or Low depending on the surrounding triangles; if at least 3 neighboring triangles are High, the vertex is High, else Low.

Those Highs and Lows correspond to the corners of the 240 wedges; one is the triangle the wedge is on, one for each of two neighboring triangles, and one for the vertex.  So each of the 240 wedges can be described by 4 bits, corresponding to the 16 terrain primitives.  From the original 80 bits of the triangle heights, the four corners of each wedge can be derived and hence the terrain data for that wedge copied over. 

Most of the map is just 16 small chunks of terrain in different orientations.  Terrain primitive 0000 has a 120 degree curve on it slightly higher than the surrounding terrain, and three such wedges put together forms some of the craters in the low areas in the bottom picture.  Terrain primitive 1111 also has a 120 degree curve on it, much higher than the other terrain, with a deep pit at one corner of the wedge.  Three such primitives put together form a crater like the two close together on the high terrain in the middle picture. All the other terrain primitives have a transition from high terrain to low terrain, and in cases where a low area is completely surrounded by a high area all those primitives put together also look like craters, as you can see in the top two images.

The crater on the left in the first image and on the right in the second image are the same crater.  This is one of the craters that is placed as a "building" in a pseudo-random (again based on the asteroid and commander names) scattering.  There could be as many as 16 of these but probably not, as there's only 122 locations to put buildings (the 80 triangles and 42 vertices) and I'm pretty sure only about 6 will actually show up, as there's usually multiples of the same building area chosen for these types of craters. There are two types of these craters, and both are visible in the first image, but one of them is right at the center and the terminator line is on it so it's harder to see from this angle.

Every cell on the map has a sunrise and sunset value based on its longitude, and comparing the sun position to those values determines whether to show the daytime color or nighttime color for the cell.  The cell also has a height value from 0 to F; actually 00 to F0.  The low four bits are the color value, and 0 indicates terrain, whose color value is dependent on the height.  For other building types the color will be chosen from 15 pairs of day/night colors associated with the building type, along with 0 for terrain color.

Because of various symmetries, I'm able to view this asteroid from directly above each of the 122 building areas using only 4 raytracing maps.  There are 88 8x8 8bpp tiles that make up the asteroid, a 10x10 grid with three missing at each corner.  These are arranged on the screen from top to bottom going left to right.  For each pixel there is a corresponding radius from the center of the image and an angle measured from a line pointing down, going clockwise.  The radius is FF if it is more than 40 pixels from the center, and the very last pixel is given a radius of FE.  All others are values in [0..39].  The angle is measured in bigrees, 256 bigrees = 360 degrees.  So each of the 88x64 pixels that make up the asteroid has a radius byte and an angle byte.  These are stored in VRAM in an 11kb block.

When the image is being calculated, the radius and angle byte are read from VRAM, and if FE we're done, and if FE or FF we just have that as the result.  For a radius of 0 to 39, we calculate a ray.  First the angle byte of the pixel is added to the view rotation (you'll be able to rotate the image by 30 or 18 degrees, depending on whether you're on a hexagonal or pentagonal building area).  Then for each of the four map types there is a 40x256x2 lookup table, and the radius and resultant angle are the lookup indices; the two bytes stored there are pointers, a low byte and a combination ram bank/high byte; when these two bytes are converted to three, they point to the start of a ray.  So that's 10 banks of RAM just for lookup pointers to the rays.

For each of the building areas, the wedges are assigned a "relative wedge" number; the ones that make up the building area itself have the lowest numbers, the ones at the horizon are all clustered around the number 120, and the ones on the opposite side of the asteroid approach a relative wedge number of 239.  No matter how low the ones directly on the horizon are, and how high the ones around the limb are, only 160 out of the 240 could ever possibly be visible.  So for each building area there is a page of RAM set aside in banked RAM, four banks for the building area data.  The first 160 bytes of the page of data for a work area lists the first 160 relative wedges.

The rays themselves start with a relative wedge number, then one byte to list a minimum height for the wedge (if no cell in the wedge is above that minimum height, we can skip the whole wedge) and the number of cells to be tested in the wedge; no ray will ever cross more than 11 cells on a single wedge.  For each wedge once the asteroid is created the maximum height of all the cells in that wedge is found and stored, so the comparison to the minimum height is pretty fast; from the relative wedge number and the building area I can find the actual wedge number and then look up its maximum height and compare to the minimum height for the ray.  If at least one cell in the ray is higher than the minimum height, we can go on and test the cells on this wedge.  The minimum height test is skipped if there is only one cell to test in this wedge.  And for radius  0 to 35, the minimum height is 0 anyhow.

After those first two bytes, there are pairs of bytes listing a cell number and a height.  If the cell in that wedge has a height value greater than the ray's target height value, then that wedge and cell are the result; if not we go on to the next cell and the next until all the cells in that wedge have been checked.  After that the next byte is another relative wedge and minheight/numcells until the target height is 0or the relative wedge number returned is FF.

The two bytes for wedge and cell (actually the high byte of the address of the cell data) are then pushed back into another 11 kb section of VRAM; the automatic increment really came in handy for both reading the radius/angle table and creating the wedge/cell table.  All I had to do was keep going until encountering FE. 

Then to actually draw the asteroid, it reads that wedge/cell data out of VRAM and pushes a color byte back into the tile data section of VRAM.  One of two spots in the tile data actually, as I'll have one set of tiles displayed while another is being drawn.  If the wedge is FF it pushes 00 to the tile data, and if the wedge is FE it pushes 00 to the tile data and stops.  For any other wedge number it puts the wedge and cell high byte into two consecutive locations in zero page.  At this point an earlier version of the program went through several steps to figure out the color, but since then I've had the program calculate the day and night color for every wedge and cell and stored both in lookup tables, so now the program just looks at the sunrise, sunset, and current sun position to determine day or night color.  Then if it is a day color it's one lookup table and if it is night it is the other; that's two more banks of RAM for that.  Whatever it chooses is the color pushed to VRAM.  When you see the terminator line moving across the asteroid in that second video, all that is changing is the sun position, and the asteroid is redrawn with the appropriate day or night colors.

There's about 165 kilobytes of these pre-calculated rays spread out over 22 banks of RAM, so the 80 kb of ray pointers and the rays themselves are less than 256 kb. It would have taken a supercomputer to generate these ray maps back in the 80s, and parts of the process bogged down my 8GHz laptop with GPU for half an hour or more.

The space in these banks that isn't used for rays or pointers is filled up with other tables and even garbage code for now, because the code that creates the asteroid uses the names to generate an address in one of these 32 banks of RAM along with a bit offset from 0 to 7, and then extracts the next 80 bits to generate the heights of all the big triangles.  The 11 bytes that are the source for those 80 bits are also further manipulated to locate the extra craters on the map.

So the next step is to start working with the mouse subroutines and get the navigation buttons (except for zoom in and out) working.

Edited by Ed Minchau
  • Like 5
Link to comment
Share on other sites

I've got my mouse subroutines working now.  There's going to be a lot of things going on that are triggered by the VSYNC interrupt.  It will do a few things like update the time count from 0 to 59, and at certain points in that sequence events will be triggered. but they won't be triggered within the interrupt itself.  Instead I've set aside a zero page variable called FLAG, and the interrupt routine will be setting or resetting bits in that byte.  The main program will include a case/switch type of statement that reads the bits of that byte and executes code if that bit is set.  That way I can also set some tasks a higher priority than other tasks, making the main program just sort of act like an orchestra conductor reading off the sheet music in that one byte. I may need to set another byte or two aside for these flag purposes, but it seems like a good way to keep everything operating in concert.  Part of the interrupt is also one of my mouse subroutines, which checks to see if a mouse button has been pressed and if so converts the 2byte values for MX and MY into single bytes for the 256x192 screen of this game, then sets bit 6 of FLAG.  There's another subroutine which gets called if bit 6 of FLAG is set, Get_Location.  This converts the x and y values into a single byte representing a "hot spot"; right now the subroutine recognizes the ten hot spots for the nav ball and zoom buttons.

Link to comment
Share on other sites

Posted (edited)

This is the main program (for now), initialization, and the custom IRQ handler.  This is all being written in the META/L editor, so it's easy for me to make changes and test quickly.  The only other tool I've used so far has been Libre Office spreadsheets and a ton of notebooks.

.

mainprogram.jpg.4b445fca140a95b9ba4092ec4e1278ea.jpginitializaton.jpg.a6e4c432f226ee300c876e63e3018465.jpgcustomIRQ.jpg.bf0e53d2b3f1e4f876b39f58497eec57.jpg

Edited by Ed Minchau
Link to comment
Share on other sites

  • 2 weeks later...
  • 2 weeks later...
Posted (edited)

So, the map of the asteroid is based on an icosahedron, the 20 sided Platonic solid:

icosahedron

This has been tessellated once; a new vertex created at the midpoint of every edge, with the new vertices extruded out to an equal radius and connected to all their nearest neighbors.  This gives a solid with 80 triangular surfaces:

80triangles.png.1c12fa2371606ef5391a99df350f13a0.png

There are still only 20 equilateral triangles on this object; the other 60 triangles are isosceles but close to equilateral.  Inside each of these triangles we can draw a circle that touches all three sides.  Doing so leaves gaps at the vertices upon which we can center some more circles:

mapareas.jpg.eab2f235ff6c3debc6115b042f9cac90.jpg

I did that markup in Paint so it's not perfect but you get the idea.  There are 42 vertices and 80 faces, so 122 circles can cover about 78% of the surface. the other 22% is the little gaps between the circles.

The orange circles are on equilateral triangles, the red circles are on isosceles triangles, the blue circles are on vertices with 6 edges and the green circles are on vertices with 5 edges.  When a circle is in the center of the screen, the image looks exactly the same (with rotations) as it would if you were looking at any other circle of that color.  So, as long as each circle has a list of where everything else is relative to itself and some base rotation, the asteroid image centered on any circle can be generated using one of only 4 generic maps.

Each triangle is divided into 81 smaller triangles or "cells". There are 18 of those 81 triangles that are outside the circles, which will always remain terrain.  For the orange, red, and blue circles that leaves 42 cells, and for the 12 green circles there's 35 cells.  This next image shows the 42-cell version in two rotations and the 35 cell version in four rotations:

buildingareas.jpg.76fa5b43267d0b66a7aa9b6674039cb6.jpg

(I used this image to help generate the closeup orthogonal view, by squashing it to a 192:13 aspect ratio, putting gray grid lines on the result, then putting numbers in a spreadsheet according to colors inside grid lines. The spreadsheet took over from there.)

The buildings that are going into this game have to fit into 42 cells and still look recognizable without the last 7 cells in the pentagonal map.   Here's how I'm indexing these cells for buildings:

cellindices.jpg.4c191b197da6aef57ad220b510ad66aa.jpg

There are 128 bytes set aside for each building type.  The first 42 bytes describe the cells' height from 0 to 7 (bits 4,5, and 6; bit 7 is 0) and a color index from 0 to 15 (bits 0-3). 

The next 22 bytes aren't allocated yet.

The 65th byte is a building type byte.

That color nybble in the first 42 bytes does not refer directly to a color on the palette.  Instead, it points to a list of 15 day colors and 15 night colors (color index 0 is considered a terrain color, and for that, color is indexed separately by height). So the 15 bytes following the building type byte are the daytime colors, and refer to the palette index.  These are followed by a building level byte, and then the 15 night colors. 

The next 20 bytes aren't allocated yet.  The last 12 bytes are used for the building name.

For every cell on the map there's a sunset value (0 to 255), and the asteroid has a rotation value (also 0-255), so if sunset minus asteroid rotation is positive the daytime color is shown otherwise the night color is shown.  At startup the program goes through each cell on the map and finds the palette index of the day color and night color for each cell and stores those in lookup tables in banked RAM, so the drawing subroutine only needs to switch bank numbers to find sunset, day color, or night color.

Why am I showing all of this?  I think I'm going to need some help designing buildings.  

For visualization purposes, each cell is a triangular tower, and each step increase in height is roughly 1/4 of the length of an edge. A max height 7 tower would be almost twice as tall as it is wide.  Height 0 is fine; it just means the cell height is the default height of the building area but colored differently than the terrain.

The 15 day colors and 15 night colors can be any of the 4096 available colors.  Each cell can use only one of those pairs of colors; if it's using #13 for day then it's also using #13 for night.

As a fun complication, I'm not going to have just one palette.  There will probably be 16 of them, cycling in once every 1/3 of a second.  Most of the colors will stay the same from palette to palette, but I'm going to set aside 32 or 64 of them to change from palette to palette.  This could lead to some interesting and computationally cheap animation effects.

For instance, suppose 4 palette entries are a daytime color, say an amber color most of the time.  And another 4 palette entries are a night colors, say a darker brownish color.  Suppose that color 1 (both day and night) is gray instead in palettes 0-3, and then amber/brown in palettes 4-F; and that color 2 is amber/brown in palettes 0-3 and 8-F but gray in palettes 4-7; color 3 is gray in palettes 8-B, and color 4 is gray in palettes C-F.  Then using those four pairs of cycling colors on cells that are close together could make the illusion of something gray being moved across an amber/brown surface. 

Or more simply, imagine that a color is gray in most of the palettes but red in palettes 7 and F.  Then it would be a blinking red light every couple of seconds.

That sort of quick animation would take place simultaneously all over the image, and in the closeup image, all just by loading 512 bytes into VERA every 20 VSYNCH interrupts.  It'll make it look like there's a lot more going on than there actually is.

So, if anyone wants to take a crack at designing a building, just come up with 42 bytes to describe the height & color index, and a listing of the RGB values for each of the 15 day/night colors, and if any of them are color cycling list the RGB values for that color index for each of 16 palettes.  That and 12 Petscii characters for the name.  If anyone submits a building I'll probably use it for something in the game.

I'm working on a Headquarters building first, as that will always be the first building placed on the map.  After that buildings will have to be placed next to existing buildings.  The other buildings I have in mind are:

- power plant

- habitat (probably several examples of this: level 1, level 2 etc)

- greenhouse (ditto)

- mines of various types

- smelter

- refinery

- foundry

- 3D printer (enormous)

- storage tanks (various)

- warehouses

- factory (various types)

- maintenance shop

- hospital

- armory

- wretched hive of scum and villainy, with live band

- shipyard

- launchpad

I might write a tool to make it easier to design buildings.  If I do, I'll probably share it here.

Edited by Ed Minchau
  • Like 3
Link to comment
Share on other sites

Wow, that is a lot of thoughts gone into the graphics! Good job!

 

So, did I understand correctly, that in case a building is rendered on a "pentagonal" site, 1/6th of the hexagonal "cake" is automatically left away?

 

Also I am not sure if I got the thing with colors already. Each element contains 4 BPP, and I get that you are going to swap out the palette for day and night. For each building type, those 32 colors are stored in the building info. But how do you plan to do this animation thing? Clearly, the 32 (or rather 30) slots in the building info are not enough memory for that. So would those 8-bit numbers, that would normally refer to one of 256 colors from the palette now instead refer to an entire color-cycling palette?

If I understood this correctly, I would encourage to make several of the color cycling palettes identical except for phase offsets. This way, you can have wave-like animations (e.g. waving flags or water or glowing stuff going through transparent pipes)

Edit: Oh wait, there's actually not enough graphical resolution to have waving flags ore pipes 😅

Edited by kliepatsch
Link to comment
Share on other sites

Posted (edited)

Yes, for a pentagonal one cells 35-41 are left out.

The 15 day and 15 night colors will be the only colors on the building,  but for the simple animation the palette itself will be changing. Not all the colors, but a few of them can change depending on which of the 16 palettes is loaded. There isn't enough resolution for small stuff at this scale, although I might have vehicles roaming about in the closeup view.

I'll probably have to place a few buildings on the map to show how the animation will work. 

edited to add: the building cells will be pointing to the same colors on the palette, but those colors themselves may change from palette to palette.  Nothing actually changes in the data for the display itself, except a few colors will look different as they change when the palette switches.

Edited by Ed Minchau
Link to comment
Share on other sites

Posted (edited)

I mentioned that there's going to be 16 palettes.  Well, I've got started on some of the colors that will be cycling, and got the program to recognize my buttons when I click on them.  This video shows some of the code that does the color cycling, how I'm using some zero page locations as flags, and how the custom IRQ routine sets the flags to keep everything synchronized.

I also came up with some slightly more efficient code for PAL+, the palette cycling subroutine.  I saved six bytes and a bunch of jiffies.  It might not seem like much, but every tiny bit of efficiency helps.

betterpaletteswitch.jpg.b246582ecfde0651a83eab2ee9a0da6b.jpg

Edited by Ed Minchau
Link to comment
Share on other sites

Gotta say, I really dig that META/L editor...     

As someone who did all my (limited) ML programming on my Plus/4 back in the day just using the built in TEDMON monitor, there's just something so cool about poking around so close to the bare metal (oh! ... I think I'm getting the naming inspiration).    And you've addressed what was always my bane:  'oh crap, I need to insert something here...' which was not a fun prospect when you worked in a monitor and had to go manually update everything to deal with the fallout of moving, adding, deleting or enlarging something.   

Also, kudos on really taking advantage of the 65c02 instructions... that bit flag system in the latest vid is clever.  

Awesome to watch a coder with skills I'll never have go through the creative process.   Cheers! 

Edited by Snickers11001001
  • Like 1
Link to comment
Share on other sites

54 minutes ago, Snickers11001001 said:

Gotta say, I really dig that META/L editor...     

As someone who did all my (limited) ML programming on my Plus/4 back in the day just using the built in TEDMON monitor, there's just something so cool about poking around so close to the bare metal (oh! ... I think I'm getting the naming inspiration).    And you've addressed what was always my bane:  'oh crap, I need to insert something here...' which was not a fun prospect when you worked in a monitor and had to go manually update everything to deal with the fallout of moving, adding, deleting or enlarging something.   

Also, kudos on really taking advantage of the 65c02 instructions... that bit flag system in the latest vid is clever.  

Awesome to watch a coder with skills I'll never have go through the creative process.   Cheers! 

Yep, the name is because it's as close to the bare metal as you can get, and also it relies very heavily on metadata, in particular labels.  It is the metadata that allows me to easily insert or delete bytes in the middle of the code.

Any of the code I'm showing here is free for other people to use.  I borrow clever code from other people all the time.  Some of the IRQ stuff, for instance, I borrowed that from @SlithyMatt's video on interrupts.  I think I got the idea of using VRAM to store lookups that get called sequentially from @Jeffrey, who was working on Wolfenstein.  Keep looking at other people's code and borrowing stuff, and adapt it to your own needs; after a while you'll have lots of little tricks like that in your arsenal.

Link to comment
Share on other sites

I still haven't figured out exactly how I'm going to populate the windows on the right and bottom left, but I moved some things around on the screen and made a bunch of other cosmetic changes.  I also added a Fast Forward button, which to my astonishment worked perfectly right off the bat.  The game is already at one second of real time = one minute of game time, but when you click on the FFWD button that changes to 1 real second = ten game minutes.  Here's what the screen looks like now:

august11.jpg.270d67ff33e57b49b0fa0a68837181aa.jpg

 

  • Like 2
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.

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.

 Share

×
×
  • Create New...

Important Information

Please review our Terms of Use