How is a 3D game like Ant Attack implemented?

The place for codemasters or beginners to talk about programming any language for the Spectrum.
Tommo
Dizzy
Posts: 92
Joined: Sat Mar 20, 2021 3:23 pm

Re: How is a 3D game like Ant Attack implemented?

Post by Tommo »

Tommo wrote: Mon May 17, 2021 12:48 pm because Ant Attack uses a regular grid of fixed-size blocks, there’s no need to draw back-to-front.
...
It’s only if you introduce map elements that are not exactly grid aligned that you need to start coming up with solutions that involve overdraw.
Joefish wrote: Mon May 17, 2021 1:14 pm If that's what you think, go ahead and try it! But that's not how Ant Attack or any of these other isometric games work.
I'd love to hear your list of "any of those other isometric games" that use a regular grid of fixed-size blocks. Have you got a single example beyond Zombie Zombie?
Joefish wrote: Mon May 17, 2021 1:14 pm That's how voxel-based games on PCs work,
It's not even close to how voxel-based games on PCs work.
Joefish wrote: Mon May 17, 2021 1:14 pmbut the Spectrum doesn't have the processing power to work like that. Any one block might only be partly obscuring another block. So do you divide all your blocks up into 8 triangles and check against all 8 x 1/8s of the blocks that may be behind it? Or is it quicker just to draw them all over the top of each other?
Once again: traverse the map to figure out which surfaces are visible. Because it's regular, and all cubes exactly fill a block.

So, no, at no point are you going to work forwards from cubes.

It looks like I last implemented it 16 years ago, here's the entire casting function:

Code: Select all

#define GetByte(x, y)	( ((x) < -64) || ((y) < -64) || ((x) > 63) || ((y) > 63) ) ? 0 : map[((x+64) << 7) | (y+64)]

void LaunchRay(int mapx, int mapy, int x, int y)
{
	int mask = 0x20;
	int byte1, byte2, byte3, byte4;
	int leftempty = 1, rightempty = 1;

	byte4 = GetByte(mapx, mapy);

	while(mask && (leftempty || rightempty))
	{
		byte1 = byte4;
		byte2 = GetByte(mapx + LeftX, mapy + LeftY); //left one
		byte3 = GetByte(mapx + DownX, mapy + DownY); //up one

		mapx += LeftX + DownX;
		mapy += LeftY + DownY;
		byte4 = GetByte(mapx, mapy); //left & up one

		if(leftempty)
		{
			if(byte1&mask)
			{
				draw_sprite(back, ul, x, y);
				leftempty = 0;
			}
			else
			{
				if(byte2&mask)
				{
					draw_sprite(back, mr, x, y);
					leftempty = 0;
				}
				else
					if(byte4&mask)
					{
						draw_sprite(back, bl, x, y);
						leftempty = 0;
					}
			}
		}

		if(rightempty)
		{
			if(byte1&mask)
			{
				draw_sprite(back, ur, x+left->w, y);
				rightempty = 0;
			}
			else
			{
				if(byte3&mask)
				{
					draw_sprite(back, ml, x+left->w, y);
					rightempty = 0;
				}
				else
					if(byte4&mask)
					{
						draw_sprite(back, br, x+left->w, y);
						rightempty = 0;
					}
			}
		}

		mask >>= 1;
	}

	if(leftempty && byte4)
		draw_sprite(back, shadowl, x, y);
	if(rightempty && byte4)
		draw_sprite(back, shadowr, x+left->w, y);
}
Which part of that is too expensive for a Spectrum, exactly? You'd probably unroll it differently, but that's about it.

That's casting into exactly the Ant Attack data format, by the way. Here's some sample output:

Image

`draw_sprite` is an Allegro 4.x call, because as I said this code is 16 years old. It doesn't actually need a 'sprite' routine, they're always character-square aligned and never overlap; even with my inclusion of shadows there's a grand total of five of them. Get rid of the shadows and it'd be three.

EDIT: oh, and this is also exactly how Snake, Rattle & Roll on the NES works per its tile set, except that Rare have gone one step further and allowed for split blocks that have a different graphic for their left and right parts.

So, no, despite your claim that the algorithm above is intractable for some unspecified reason, Rare didn't somehow manage to draw from back to front, to a constructed bitmap, fast enough to scroll, on a NES.
User avatar
rastersoft
Microbot
Posts: 151
Joined: Mon Feb 22, 2021 3:55 pm

Re: How is a 3D game like Ant Attack implemented?

Post by rastersoft »

Tommo wrote: Mon May 17, 2021 12:48 pm Apologies, I’m unable to view a video where I am so I don’t know whether this is already addressed but because Ant Attack uses a regular grid of fixed-size blocks, there’s no need to draw back-to-front. You can very cheaply populate the screen — sprites aside — with no overdraw whatsoever by walking the level data from front to back and stopping as soon as you hit something to populate a triangular grid; since the triangles are a fixed shape they’re just bitmaps in the end.

Since the sprites can move only in integer grid positions it’s also easy to paint them on top without much complexity.

It’s only if you introduce map elements that are not exactly grid aligned that you need to start coming up with solutions that involve overdraw.
That doesn't work when you can do pixel-by-pixel drawing, or when elements can occupy more than one block, or when you have transparency... like in an isometric game, where the screen grid doesn't coincide with the map grid.
Tommo
Dizzy
Posts: 92
Joined: Sat Mar 20, 2021 3:23 pm

Re: How is a 3D game like Ant Attack implemented?

Post by Tommo »

rastersoft wrote: Mon May 17, 2021 2:56 pm
Tommo wrote: Mon May 17, 2021 12:48 pm It’s only if you introduce map elements that are not exactly grid aligned that you need to start coming up with solutions that involve overdraw.
That doesn't work when you can do pixel-by-pixel drawing, or when elements can occupy more than one block, or when you have transparency... like in an isometric game, where the screen grid doesn't coincide with the map grid.
I don't know how to state this any more clearly: the different with Ant Attack, and only Ant Attack, and not all those other isometric titles, and only Ant Attack, and Zombie Zombie is:
  • no in-game elements ever occupy more than one block;
  • I distinguished the level from the sprites because then: the level has no transparency; and
  • the screen grid exactly coincides with the map grid if the screen grid is isosceles triangles.
Seriously, the code is just up there. It's not complicated. The Ant Attack data format is one byte per map column, blocks either filled or empty.

Per isosceles triangle, starting from the roof:

Code: Select all

If the top block you started on is occupied, fill with the horizontal-surface colour and stop.

Otherwise:
while(not at floor) {
    move one block diagonally back.
    
    If it is occupied, fill with wall colour and stop. 
    If the the block below is occupied, fill with horizontal-surface colour and stop.
}
Use two wall colours, one for left-facing triangles, one for right. That gives you the different north/south and east/west faces.

So:
  • that's the algorithm in pseudo code;
  • a concrete C implementation with sample output is above; and
  • I've given you an obvious example of that algorithm in production, regardless of whether Sandy White ever figured it out.
EDIT:
These are 16-year old builds so there's little I can do about them now, but you can see a Windows build of the above code here. To hit that 16-year-old point again, you can also download a Mac version... if you happen to be rocking a PowerPC.

EDIT2:
Oh, and those isosceles triangles are 8 pixels wide and 8 pixels along the vertical edge to match Ant Attack, I think. So the total number to pass through the loop above for scene construction is two times the number of character squares.
User avatar
Joefish
Rick Dangerous
Posts: 2062
Joined: Tue Nov 14, 2017 10:26 am

Re: How is a 3D game like Ant Attack implemented?

Post by Joefish »

Since this is a Spectrum forum, how about a version that runs on a Spectrum then? Otherwise, you've proved nothing. :roll:
I don't care if your algorithm works, or was used on a console with a block-mapped screen. Show it running on a Spectrum at a higher frame rate than Ant Attack.
Tommo
Dizzy
Posts: 92
Joined: Sat Mar 20, 2021 3:23 pm

Re: How is a 3D game like Ant Attack implemented?

Post by Tommo »

Joefish wrote: Mon May 17, 2021 4:31 pm Since this is a Spectrum forum, how about a version that runs on a Spectrum? :roll:
Out of curiosity, how many constructive conversations have you taken part in lately that involve rolling eyes at people?

I'm being attacked on two fronts here, so I just want to clarify: Rastersoft contends that the algorithm wouldn't work, you merely think it'd be the somewhat nebulous too slow? So can you provide a quantification? Size of display, frame rate, etc?

EDIT: you edited as I was asking. Have we any idea what the frame rate of Ant Attack is?

My Z80 skills are meagre, so I hope you'll accept something that is sufficiently fast to prove that a more competent programmer could do a more competent job. I mean, you could argue against me all day that there's no way a Spectrum could scroll at 25Hz since your only retort seems to be "I'm not telling you why, but that's too slow :roll: :roll: :roll:", and it's very improbable that I could get a Spectrum to scroll at 25Hz, but obviously Joffa could.

EDIT2: minor correction to the above; having sketched it out on a piece of paper each maximum-six-step walk through the map gives the final no-overdraw output for a full 64 pixels. So it's the equivalent of one walk per character square.

Each step through the map is three byte fetches and three ANDs.
User avatar
rastersoft
Microbot
Posts: 151
Joined: Mon Feb 22, 2021 3:55 pm

Re: How is a 3D game like Ant Attack implemented?

Post by rastersoft »

Tommo wrote: Mon May 17, 2021 3:01 pm
I don't know how to state this any more clearly: the different with Ant Attack, and only Ant Attack, and not all those other isometric titles, and only Ant Attack, and Zombie Zombie is:
  • no in-game elements ever occupy more than one block;
  • I distinguished the level from the sprites because then: the level has no transparency; and
  • the screen grid exactly coincides with the map grid if the screen grid is isosceles triangles.
OK, now I understand it... The point is to divide each character in an isosceles triangle. That makes sense.
Tommo
Dizzy
Posts: 92
Joined: Sat Mar 20, 2021 3:23 pm

Re: How is a 3D game like Ant Attack implemented?

Post by Tommo »

rastersoft wrote: Mon May 17, 2021 5:30 pm
Tommo wrote: Mon May 17, 2021 3:01 pm
I don't know how to state this any more clearly: the different with Ant Attack, and only Ant Attack, and not all those other isometric titles, and only Ant Attack, and Zombie Zombie is:
  • no in-game elements ever occupy more than one block;
  • I distinguished the level from the sprites because then: the level has no transparency; and
  • the screen grid exactly coincides with the map grid if the screen grid is isosceles triangles.
OK, now I understand it... The point is to divide each character in an isosceles triangle. That makes sense.
If you're good at hieroglyphics, here's the version I just sketched out on paper to persuade myself that I still know what I'm talking about. Plus hopefully to persuade myself that even at my long-decayed remedial level, doing it in Z80 would be achievable.

So, yeah, the bands on the left are the individual triangles you'll try to fill, on the right I calculate that you could use 16 UDGs total (if you'll permit the appropriation of the BASIC term) if you wanted to keep all drawing strictly in terms of complete character squares, and then underneath I restate the algorithm.

Based on my handwriting, you'll have to trust me on that latter part.

Image

EDIT: no, wait, I’m still not quite reporting correctly. At most six times [three fetches and three ANDs] to decide the output colour for 128 pixels, no overdraw. Because it’s two such isosceles triangles at a time. Which can then easily be mapped to 8x8 tiles of which only 16 predrawn combinations are required.

So I keep talking about triangles but there’s no edge scanning or complicated span compositing, it’s just an unmasked blit — exactly one source graphics byte fetched for each screen byte — no shifting or any other manipulation. Just fetch and store.

(and add sprites post hoc; they’re also grid aligned in Ant Attack so that’s really easy compared to a Knight Lore, Bobby Bearing, etc)
User avatar
Joefish
Rick Dangerous
Posts: 2062
Joined: Tue Nov 14, 2017 10:26 am

Re: How is a 3D game like Ant Attack implemented?

Post by Joefish »

Tommo wrote: Mon May 17, 2021 4:52 pmMy Z80 skills are meagre, so I hope you'll accept something that is sufficiently fast to prove that a more competent programmer could do a more competent job.
So what you're saying is, your knowledge of the Spectrum is meagre, but you still think you know better than everyone on a dedicated Spectrum forum?
Tommo wrote: Mon May 17, 2021 4:52 pmI mean, you could argue against me all day that there's no way a Spectrum could scroll at 25Hz since your only retort seems to be "I'm not telling you why, but that's too slow :roll: :roll: :roll:", and it's very improbable that I could get a Spectrum to scroll at 25Hz, but obviously Joffa could
I don't need you to tell me what Joffa could or couldn't do, when Joffa himself has already told me at length what he could or couldn't do.
And I think it's hilarious that you still think 25Hz is a fast scroll.
https://spectrumcomputing.co.uk/entry/3 ... um/50Hurts
Tommo wrote: Mon May 17, 2021 4:52 pmEach step through the map is three byte fetches and three ANDs.
No, each of your steps through the map goes through a seemingly endless set of nested if/else conditions when it would be far, far faster to simply draw the block over whatever's there and move on. That is why your method will be slower. Because of all those conditional jumps you'll be making before you even think about drawing a single pixel.
Tommo
Dizzy
Posts: 92
Joined: Sat Mar 20, 2021 3:23 pm

Re: How is a 3D game like Ant Attack implemented?

Post by Tommo »

Joefish wrote: Mon May 17, 2021 8:00 pm
Tommo wrote: Mon May 17, 2021 4:52 pmMy Z80 skills are meagre, so I hope you'll accept something that is sufficiently fast to prove that a more competent programmer could do a more competent job.
So what you're saying is, your knowledge of the Spectrum is meagre, but you still think you know better than everyone on a dedicated Spectrum forum?
No, that's not even close to what I'm saying. You've one hell of an ego though, especially for somebody plucking claims out of thin air. The only person I'm still in disagreement here is you, so by implication you're asserting that if somebody knows something better than you do then they know better than everybody on a dedicated Spectrum forum? I was unaware that you were at the pinnacle.

If you must insist on being so incredibly tedious, a partial personal retro softography, limited to what I've ever chucked onto Youtube: It'd be interesting to know which statement you disagree with, though:
  1. the Ant Attack level geometry can be drawn directly, no overdraw, using the isosceles triangles as depicted above;
  2. that it's trivial to do so by combining adjacent triangles into a 'UDG'-esque lookup table, reducing drawing to load and store;
  3. that the colour for two such triangles can be picked in, in the worst case, six times (three byte fetches and three ANDs)*.
If anybody else can see what Joefish's problem is, other than that *gasp* somebody dared to disagree with him, I'd be grateful of the assist.

* the Ant Attack level is six blocks high.

At each level the test is: (1) is this block solid?; if not then: (2) is the back wall on the left solid; and/or (3) is the back right solid?

Continue until you hit the floor or have filled both blocks.

Those three tests are three byte fetches and three ANDs per level, six levels total.

On a real Z80 implementation you'd have three versions of the inner loop, one that's still checking both triangles, one that's checking only the left, one that's checking only the right. The C implementation above doesn't do that because on its target processing is cheaper than the cost of trifurcated code.
Joefish wrote: Mon May 17, 2021 8:00 pm
Tommo wrote: Mon May 17, 2021 4:52 pmEach step through the map is three byte fetches and three ANDs.
No, each of your steps through the map goes through a seemingly endless set of nested if/else conditions when it would be far, far faster to simply draw the block over whatever's there and move on. That is why your method will be slower. Because of all those conditional jumps you'll be making before you even think about drawing a single pixel.
Oh, so your problem is that you can't read code. Or pseudocode. Or my handwriting.

Actually, the last one is also my problem.
User avatar
Bedazzle
Manic Miner
Posts: 305
Joined: Sun Mar 24, 2019 9:03 am

Re: How is a 3D game like Ant Attack implemented?

Post by Bedazzle »

druellan wrote: Tue Jan 21, 2020 12:58 pm Image
How you produced this image?
Tommo
Dizzy
Posts: 92
Joined: Sat Mar 20, 2021 3:23 pm

Re: How is a 3D game like Ant Attack implemented?

Post by Tommo »

Joefish wrote: Tue May 18, 2021 1:48 am You posted your C function, not 'pseudo-code'.
Read this post. Is it true or is it false to say that I've posted pseudocode?

See also the step-by-step instructions in this post.
Joefish wrote: Tue May 18, 2021 1:48 amI count up to five levels of nested conditions inside your main loop for each 'cell' of your renderer. Which part of that am I incapable of reading?
Then you have a very atypical concept of nested conditional, and apparently conveniently overlooked my comment:

"On a real Z80 implementation you'd have three versions of the inner loop, one that's still checking both triangles, one that's checking only the left, one that's checking only the right. The C implementation above doesn't do that because on its target processing is cheaper than the cost of trifurcated code."

In the C version there's an outer loop, which has a fixed maximum length of 6 so is trivial to unroll. There's the two `if([left/right]empty)` tests which I've commented on in the quote above. Then inside each there is an identical `if/else if/else if` progression. It's the same three conditionals in each place, being the three ANDs that I keep talking about.

So: as written above it's three levels of nested conditional since normal usage would count `if/else if/else if` as a single level of conditional, regardless of where the brackets fall.

As per the discussion, on a Z80 implementation it'd be three tests and one level of conditionality.

Here's the more meta thing: I already know that your claim that "the Spectrum doesn't have the processing power to work like that" because: (i) it's obvious from first principles — at most six tests per triangle pair. Each test is three fetches, three ANDs; (ii) because I can point to implementations on devices with similar processing power; and (iii) because I've implemented it on systems with a similar level of performance.

Conversely:
  1. it isn't valid to say that whether I'm right or wrong about the algorithmic efficiency is a function of how well I can still code in Z80;
  2. but assuming you've actually understood the algorithm now — which, besides anything else, is a function of my ability to explain it so let's definitely keep a question mark there — but still disagree as to its potential efficiency then a good faith attempt to implement it feels unavoidable.
I'll try, I'll possibly fail, I'll report. I wanted a quantifiable standard but I guess I'll just cross my fingers that the goalposts don't move.
User avatar
druellan
Dynamite Dan
Posts: 1475
Joined: Tue Apr 03, 2018 7:19 pm

Re: How is a 3D game like Ant Attack implemented?

Post by druellan »

Bedazzle wrote: Mon May 17, 2021 9:25 pm How you produced this image?
It was captured from Spud Emulator's memory map feature, it has one of the best visual representations of the internal memory.
User avatar
Bedazzle
Manic Miner
Posts: 305
Joined: Sun Mar 24, 2019 9:03 am

Re: How is a 3D game like Ant Attack implemented?

Post by Bedazzle »

druellan wrote: Wed May 19, 2021 3:20 am It was captured from Spud Emulator's memory map feature, it has one of the best visual representations of the internal memory.
Thanks!
Tommo
Dizzy
Posts: 92
Joined: Sat Mar 20, 2021 3:23 pm

Re: How is a 3D game like Ant Attack implemented?

Post by Tommo »

Tommo wrote: Tue May 18, 2021 2:22 am I'll try, I'll possibly fail, I'll report. I wanted a quantifiable standard but I guess I'll just cross my fingers that the goalposts don't move.
Being a suboptimal person, I've implemented a really suboptimal version of the algorithm discussed above. Specifically, it:
  • fully recalculates the triangles every frame; and
  • then draws any 8x8 character blocks that have changed.
I haven't found either a debugger or a profiler that I really get along with, but based on paper arithmetic I think the first part is safely the greater cost so I'm optimistic for a speed bump if I do the obvious thing: a 2d scroll on that and recalculate only the triangles at the edges. Just the map indexing is really killing me, needing to manipulate 7-bit fields, and I'm also manipulating that four times as often as I would strictly need to if I were willing to throw more memory at the problem. Though I can probably do better without extra storage, there are other programmer conveniences burning cycles.

I've actually improved things slightly from the algorithm given above, making a minor tweak to the Ant Attack data format.

In Ant Attack the square at (x, y, z) is represented by bit z stored in the map at (x, y). In my code that square is instead represented by bit z at (x+z, y+z). So the full 3d map is present and easy to lookup, and rendering proceeds from that, but I've basically got the rows established in front-to-back order relative to the viewer. That means that the per-diamond work is [at most] six compares. Not six times six. But there's an extra table lookup for doing log2.

As an aside before I get to it, it's not accurate to call it a back-to-front or front-to-back renderer; it's a left-to-right, top-to-bottom renderer.

I haven't added sprites. So any comparison with Ant Attack isn't fair, in my code's favour. I'm sure somebody will make a lot of hay with that, I'll just clarify that I think the cost of sprites will not outweigh what I'd save with the optimisation mentioned above; approach for drawing would be to look up columns that the sprite touches from the map data and mask for display, each sprite probably having been cut into six portions in advance.

So that makes the cost of drawing a sprite much the same as of drawing four diamonds, i.e. relative to the full-screen version each sprite would add about 3% rendering cost.

If you've bothered reading this far then here are the numbers:

With a rendering viewport just 6.66% larger than Ant Attack's, I get essentially the same frame rate. Frame counting on videos I made of each put both around the 10fps mark.

When rendering full screen, producing a display around 82% larger than Ant Attack's, my code drops to about 6fps.

There is close to 20kb of RAM unused with the current build. But I've been lazy in some places, unrolling just because it was easier than writing a runtime loop.

Supposing that:
  • unoptimised code;
  • from somebody who hasn't written Z80 in about a decade;
  • without access to a debugger or profiler;
  • with a clearly-stated explanation as to why this hacked-together version is far from optimal;
  • that nevertheless is exceedingly close to the real Ant Attack in frame rate;
isn't sufficient to overcome the false claim that "the Spectrum doesn't have the processing power to work like that" and the various other bits of nonsense above, then the game plan is: (i) clean up code, quite a lot; (ii) look for any further peephole optimisations that drop out; (iii) take a shot at the big structural optimisation mentioned above; (iv) see what I can do about sprites.

Either way, check it out. QAOP to scroll.

I think I'm vindicated. Draw your own conclusions.
Tommo
Dizzy
Posts: 92
Joined: Sat Mar 20, 2021 3:23 pm

Re: How is a 3D game like Ant Attack implemented?

Post by Tommo »

Oops; too late for an edit, but here's what I should have included yesterday evening:

Image Image
User avatar
evilpaul
Manic Miner
Posts: 244
Joined: Tue Jul 28, 2020 8:04 am
Location: Espoo, Finland
Contact:

Re: How is a 3D game like Ant Attack implemented?

Post by evilpaul »

Tommo wrote: Tue May 25, 2021 12:56 pm Oops; too late for an edit, but here's what I should have included yesterday evening:

Image Image
Heh... looks weird (in a good way) having a bigger window :)


[quote=Tommo
In Ant Attack the square at (x, y, z) is represented by bit z stored in the map at (x, y). In my code that square is instead represented by bit z at (x+z, y+z). So the full 3d map is present and easy to lookup, and rendering proceeds from that, but I've basically got the rows established in front-to-back order relative to the viewer. That means that the per-diamond work is [at most] six compares. Not six times six. But there's an extra table lookup for doing log2.
[/quote]
You've processed the map so that the data for a single column, which was previously 6 bits of data stored in a single byte, is now spread across 6 bytes. Am I reading this right?
Tommo
Dizzy
Posts: 92
Joined: Sat Mar 20, 2021 3:23 pm

Re: How is a 3D game like Ant Attack implemented?

Post by Tommo »

evilpaul wrote: Tue May 25, 2021 1:59 pm [quote=Tommo
In Ant Attack the square at (x, y, z) is represented by bit z stored in the map at (x, y). In my code that square is instead represented by bit z at (x+z, y+z). So the full 3d map is present and easy to lookup, and rendering proceeds from that, but I've basically got the rows established in front-to-back order relative to the viewer. That means that the per-diamond work is [at most] six compares. Not six times six. But there's an extra table lookup for doing log2.
You've processed the map so that the data for a single column, which was previously 6 bits of data stored in a single byte, is now spread across 6 bytes. Am I reading this right?
[/quote]

Yes, but to avoid anybody else drawing an improper conclusion: I've reprocessed the map from its original 16kb to a different 16kb; it takes up exactly the same footprint as it did before, and has exactly the same quantity of information — it's still a single bit per cube, and all cubes are stored.

So each column does indeed get spread over six bytes. But each of those six bytes contains data from six columns. And the per-cube lookup cost is not strongly affected.

Addendum: besides the 16kb map, I've got 1kb of tiles, a 32x49 (i.e. 1,568 byte) buffer for triangle colours, a 32x24 buffer for tiles, and sundry other tables probably adding up to less than 300 bytes. So I actually think my buffering might end up being more compact than keeping a back buffer would be.

Additional observation: if you stretched the projection so that all diagonal lines were at 45 degrees, you could draw in full colour, by writing only to the display attributes. I just don't think 45 degrees looks very good.
User avatar
bluespikey
Manic Miner
Posts: 958
Joined: Tue Jun 30, 2020 3:54 pm

Re: How is a 3D game like Ant Attack implemented?

Post by bluespikey »

Tommo wrote: Tue May 25, 2021 2:28 pm
evilpaul wrote: Tue May 25, 2021 1:59 pm [quote=Tommo
In Ant Attack the square at (x, y, z) is represented by bit z stored in the map at (x, y). In my code that square is instead represented by bit z at (x+z, y+z). So the full 3d map is present and easy to lookup, and rendering proceeds from that, but I've basically got the rows established in front-to-back order relative to the viewer. That means that the per-diamond work is [at most] six compares. Not six times six. But there's an extra table lookup for doing log2.
You've processed the map so that the data for a single column, which was previously 6 bits of data stored in a single byte, is now spread across 6 bytes. Am I reading this right?
Yes, but to avoid anybody else drawing an improper conclusion: I've reprocessed the map from its original 16kb to a different 16kb; it takes up exactly the same footprint as it did before, and has exactly the same quantity of information — it's still a single bit per cube, and all cubes are stored.
[/quote]

I've quickly read your interesting thoughts and they all seem very neat and clever. I took Ant Attack apart back in the day just to see what was inside the arena and central pyramid, and the answer is sadly nothing. Can you also rotate the view?
Tommo
Dizzy
Posts: 92
Joined: Sat Mar 20, 2021 3:23 pm

Re: How is a 3D game like Ant Attack implemented?

Post by Tommo »

bluespikey wrote: Tue May 25, 2021 2:56 pm
Tommo wrote: Tue May 25, 2021 2:28 pm Yes, but to avoid anybody else drawing an improper conclusion: I've reprocessed the map from its original 16kb to a different 16kb; it takes up exactly the same footprint as it did before, and has exactly the same quantity of information — it's still a single bit per cube, and all cubes are stored.
I've quickly read your interesting thoughts and they all seem very neat and clever. I took Ant Attack apart back in the day just to see what was inside the arena and central pyramid, and the answer is sadly nothing. Can you also rotate the view?
I'd have to do the bit shuffling at runtime; it'd take some substantial-enough portion of a second that you couldn't do it as part of flowing gameplay, but it wouldn't be overly disruptive if it were user-initiated.

When I get a chance to clean up my code I'll be less coy about that. Upon the realisation that I was close to the finishing line, I got a bit too free with copy and paste. It's presently a mess.
User avatar
evilpaul
Manic Miner
Posts: 244
Joined: Tue Jul 28, 2020 8:04 am
Location: Espoo, Finland
Contact:

Re: How is a 3D game like Ant Attack implemented?

Post by evilpaul »

Yup... view rotation was partly what I was wondering about. Also object manipulation ("Am I in the air or on top of a block?") gets a little bit more complicated. None of that'll affect the framerate though.. and there's nothing wrong with trading a bit of complication for a bit of speed. This is certainly interesting :)

So do you think there's more room for speed improvements?

Just for balance... the original Ant Attack also has room for improvement. I managed to get a little bit of extra speed out of it by fixing/changing some of the rendering code. That code is wrapped up as a trainer here -> https://www.pouet.net/prod.php?which=71448
Tommo
Dizzy
Posts: 92
Joined: Sat Mar 20, 2021 3:23 pm

Re: How is a 3D game like Ant Attack implemented?

Post by Tommo »

evilpaul wrote: Tue May 25, 2021 5:54 pm So do you think there's more room for speed improvements?
Unambiguously large room for improvement; I'm probably spending at least 300 cycles or so on determining the two triangles that go into any individual diamond, and I'm currently doing that 808 times per frame in the fullscreen version if my arithmetic holds up. So that's something like 3.5 frames worth of computation.

If I switch to partial updates of the triangle map then the maximum cost of a scroll is, I think 87 diamond calculations. It'd be less without diagonals.

The cost I'd acquire is manipulating a 32*49 byte buffer to move all values to neighbouring spots and sometimes shift them all two bits one way or the other. But as long as I can beat the really-large number of around 216,000 cycles (i.e. roughly 3 frames) in doing so then I can pocket that saving.

I mean, that's got to add up to at least a two-frame improvement, right? I guess I'll find out if I try to do it. That could give a ~25% improvement, as a ballpark.

And then there are probably a million ways to improve the code in general, without touching the algorithm. I am a mediocre Z80 programmer at best. Let's definitely not lose track of the conversation here — all I'm seeking to prove is that the fairly basic algorithm I suggested doesn't warrant eye rolling and allegations that I don't understand the Spectrum. The objective isn't to prove that it's better than anything else, merely that Ant Attack offers an interesting special-case option which is completely practical.

Curiosity question: I've been judging the frame rate of Ant Attack by frame stepping videos, and I noticed that the helicopter segment in Zombie Zombie, in which the map moves by quite a bit more than one tile per frame, appears to be more like 6 fps than Ant Attack's 10-or-so. Have you any idea whether it has a similar system for scrolling of a cheap 2d manipulation and then do the hard work only to populate the newly-revealed edges?
Tommo
Dizzy
Posts: 92
Joined: Sat Mar 20, 2021 3:23 pm

Re: How is a 3D game like Ant Attack implemented?

Post by Tommo »

Too late again for an edit; I think I've managed to tidy up the code to the point where it, umm, 'accurately represents my abilities'. So: this is the corresponding Github.
Tommo
Dizzy
Posts: 92
Joined: Sat Mar 20, 2021 3:23 pm

Re: How is a 3D game like Ant Attack implemented?

Post by Tommo »

One quick, quite-possibly final update on this: I've implemented the update-the-edges logic described above for a substantial frame rate. We're now talking about 13fps or so full-screen. To me this now feels quite zippy, but I have been staring at the slower versions for a couple of weeks on the way here so others may not be similarly conditioned.

Image

Still no sprites, so this is still an unfair comparison, but that means I'm rendering about 83% more pixels than Ant Attack, around 30% faster.

So, to conclude: this is definitely one way in which a 3d game like Ant Attack can be implemented.

Direct .tap link; repository.
User avatar
Joefish
Rick Dangerous
Posts: 2062
Joined: Tue Nov 14, 2017 10:26 am

Re: How is a 3D game like Ant Attack implemented?

Post by Joefish »

Have to admit, I'm impressed it runs at the speed it does. I assumed it'd be buried in too many decisions to have even the frame rate it has achieved.
That's certainly an acceptable refresh rate for a game, though it doesn't necessarily demonstrate it's any quicker than brute-force over-drawing.
Tommo
Dizzy
Posts: 92
Joined: Sat Mar 20, 2021 3:23 pm

Re: How is a 3D game like Ant Attack implemented?

Post by Tommo »

Joefish wrote: Wed Jun 02, 2021 11:52 am Have to admit, I'm impressed it runs at the speed it does. I assumed it'd be buried in too many decisions to have even the frame rate it has achieved.
That's certainly an acceptable refresh rate for a game, though it doesn't necessarily demonstrate it's any quicker than brute-force over-drawing.
Agreed; and even if this were demonstrated to be faster than Ant Attack — we can all form our own expectations as to how it might run with sprites but that's different than demonstrating — you'd still have to factor in that Ant Attack is a pioneering development, inventing a genre from nothing, and a real commercial product. So fast enough is good enough; it's not meant to be a demo-scene production. Ant Attack itself doesn't prove how fast brute-force over-drawing could be.

That's partly why I also looked at the helicopter sequence in Zombie Zombie, at least to find out to what extent the current frame rate is just the correct gameplay choice. Zombie Zombie is actually seemingly running slower so I don't think Ant Attack is artificially capped.

(relevant stats: mine is now around 25fps at roughly Ant Attack window size, versus the 10–11 of the original. But, again, without sprites.)

Waffling aside: relative speed would depend on level complexity. In extermis, a level with zero cubes in it would obviously be faster to draw brute-force. So either there's a point where ray casting is faster or there isn't, but either way brute-force is definitely faster in some subset of potential scenes.

If it helps with prima facie evaluation of that, shuffling the byte contents reduced the picking-a-colour cost to three compares per triangle, following four fetches and four table lookups per pair of triangles. That's a fixed cost, completely irrespective of level geometry.

So scrolling is a win this way around because it's cheap just to fill in the edges, getting only exactly the new content. With brute-force I think you'd need to inspect more of the map, and use marginally more complicated graphical clipping — e.g. to brute-force but affect only the top or bottom four lines of the display.
Post Reply