Armchair coding Stunt Car Racer

Page 2/4
1 | | 3 | 4

By sd_snatcher

Prophet (2734)

sd_snatcher's picture

10-12-2017, 12:38

But... Why MSX1 and not MSX2? Smile

By santiontanon

Hero (578)

santiontanon's picture

11-12-2017, 02:50

Thanks!!! ok, that was the way! got it! I managed to run it now!

It runs decently fast!!! Specially since I do not see any precalculated tables! I am assuming if we want to get any real speed with complex models, those "divisions by Z" need to be precalculated on a table. But this is a really good starting point!

By TomH

Master (196)

TomH's picture

11-12-2017, 15:54

sd_snatcher wrote:

But... Why MSX1 and not MSX2? Smile

My feeling is that the MSX 2's output abilities are too good. If you're on an MSX 1 then you can justify monochrome, if you're in monochrome then you can get away with the sky being one colour, and the floor and track being a single other colour, with edges painted as lines for emphasis. But once you're on an MSX 2, you've got so much flexibility in visuals that it suddenly looks odd if the side of the tracks are the same colour as the floor, and if they're not then it's a lot more expensive to draw them.

That said, asynchronous rectangle fill and line drawing would do 90% of the output work while the CPU was doing 3d calculations...

santiontanon wrote:

Thanks!!! ok, that was the way! got it! I managed to run it now!

It runs decently fast!!! Specially since I do not see any precalculated tables! I am assuming if we want to get any real speed with complex models, those "divisions by Z" need to be precalculated on a table. But this is a really good starting point!

Is there a video anywhere?

I'm not sure precomputing divide by Z is as big of a win as it feels: it's from the SAM Coupe, a "6Mhz" Z80 (but nowhere near because of the way RAM is shared with the display: the Z80 is permitted RAM access for only one cycle in eight while pixels are being displayed, and one cycle in four at other times, for a hefty wait state bill), but compare computed divides with lookup table divides (links to the same video, at different offsets) and there's not a big difference. That machine has the simplest possible frame buffer but the drawing cost still dominates.

EDIT: it appears the inline player strips the starting time argument for Youtube vides. Skip to the 1m05s mark to see computed divides, to 1m32s to see the exact same thing but with precomputed divides. The long blank screen before the 1m32s is it computing those divides, for the record.

By santiontanon

Hero (578)

santiontanon's picture

11-12-2017, 16:23

hmm, indeed very little difference between pre-calculated and not... I thought there would be more of a difference. But in any case, every clock tick counts Smile

By TomH

Master (196)

TomH's picture

11-12-2017, 20:41

santiontanon wrote:

hmm, indeed very little difference between pre-calculated and not... I thought there would be more of a difference. But in any case, every clock tick counts Smile

Yeah, in that particular case I think the line drawing wasn't good enough. Vanilla Bresenham with a slight machine-specific optimisation related to 4bpp pixel drawing. I think the 64kb table approach mentioned in the 3d rasterisation thread that gets you to run slice without a divide would be the proper thing to do, especially if we're talking about dynamically populating the tile name map because it allows you to pull the fixed -> drawable substitutions outside of the pixel loop.

For MSX1 purposes, I guess I'm now imagining a 128kb MegaROM, which works with as little as 16kb of RAM — enough to compose the next frame before sending it over plus relatively light game state bookkeeping and a slender intermediate 3d calculation scratch pad.

All in all, I think I'd be more worried about gameplay. The cars can't actually roll all that much, so maybe it's as simple as modelling the four wheels fixed around the outside of a 2d quad with springy constraints up to the notional camera platform (i.e. ordinarily force is proportional to distance, but clamp to range), with probably Verlet integration for numeric stability?

I make that something like (taking y to be the direction of gravity):

  1. from current car location and orientation, pick x and z afresh for wheels as though car is entirely level;
  2. apply Verlet integration step using two historic y values per wheel — so momentum and air resistance apply here at the cost of two subtractions, some shifting and an addition per wheel;
  3. apply additional gravity — one addition per wheel;
  4. look up which track segment the player is on, through top-down 2d projection determine track height at each wheel (which might require you to look one segment forwards or backwards) — probably four multiplies and two adds to determine which segment each wheel is on of the three possibilities, then two multiplies to figure out the track height there?;
  5. apply heights as a hard constraint — one comparison and a potential store;
  6. do the Verlet step for the camera platform — also two subtractions, plus some shifts, times four;
  7. apply a spring constraint and a hard bottom for each camera platform vertex — two subtractions, some shifts, a compare and potential store;
  8. figure out the new camera matrix, which is where you hand wave via the lack of roll to throw some classic it's-just-a-game logic at the problem: you want to use only three corners of the platform out of four, so I guess it's whichever three cause the fourth to be below them? Likely to be coherent frame to frame (if you allow a dead zone, so that numerical error doesn't just throw you all over the place while more or less level) so it's a check and fault thing, and probably painful. I'm imagining you have to go all the way to making the hypothetical basis vectors for each potential trio and checking the fourth. There's a relatively compact table-based approach to square roots of numbers that are already close to unit that escapes me now but would be easy to look up, bisecting might actually be more expensive here because at each step of bisecting (x, y) you're testing for x^2 + y^2 = 1. So maybe a multiplication lookup table would be easier, given that if x > 1 or y > 1 independently then obviously the line is too long, which puts you into a small range before you need to do the real work.

Car centre is an independently integrated thing and you come out of the above with number of wheels in contact with the floor, from which you can come up with acceleration.

So, yeah, that would definitely need prototyping before committing to assembly. And is much more where I'd expect the code to be hard to get right than graphical display.

By ARTRAG

Enlighted (5962)

ARTRAG's picture

11-12-2017, 22:14

Why not use msx2 and vdp line commands?

By TomH

Master (196)

TomH's picture

11-12-2017, 22:31

ARTRAG wrote:

Why not use msx2 and vdp line commands?

I'd think rectangles plus lines was the way: fill the silhouette by drawing a single rectangle from the bottom of the screen to the lowest of all the top edge ends, then possibly do a bunch more, say, four-column-width rectangles, or adopt a recursive subdivision strategy, possibly with address alignment in mind. Probably finish off the silhouettes with ordinary vertical lines, then draw the other lines as nature intended.

I just still worry that once you've got the output fidelity of an MSX 2, it starts to feel like the game should look a lot like the 16-bit versions in terms of not taking the short cuts of having floor and track be the same solid colour, and assuming that there is no roll when rendering. So suspension of disbelief is harder. Or else it'll still look like an MSX 1 game, and people will assume you're not using the hardware.

In short: my instinct is that you either take advantage of the better display capabilities and end up a lot slower, or you don't and people wonder why it's not MSX 1 compatible.

There might be an insight I'm failing to spot in rendering, of course. If you alternated track segment colours then corners would suddenly look very peculiar. Like in this image:

Imagine that the sides on the left instead of being a single solid colour have a bunch of screen-aligned rows of different colours. Though the top of the track now looks like filled polygons so maybe it's an acceptable trade?

By santiontanon

Hero (578)

santiontanon's picture

12-12-2017, 03:36

Ok, someone needs to start working on this! Big smileBig smileBig smile

Really want to see a Stunt-car-racer-like on MSX now! I'm in the middle of another game project right now that I'd like to finish first. Otherwise, I'd get on coding tonight! Big smileBig smileBig smile

By santiontanon

Hero (578)

santiontanon's picture

13-12-2017, 04:24

I was just playing a game to the Spectrum version, and I noticed that the opponent car suffers significant distortions when the camera angle rotates, so, definitively there are lots of approximations going on there to make it go fast! But I still think we can do better. So, seriously, someone has to take on this project! Smile

By TomH

Master (196)

TomH's picture

13-12-2017, 18:02

I'm a terrible person at follow-through, hence the title. But it has occurred to me that if you draw from front to back instead of back to front then you might save more work: do the voxel-esque thing of keeping a 1d array of current output heights for the width of the display and at each segment, don't permit yourself to go below that per-column height, then remember to update the table.

It gives you zero overdraw for the track, but line drawing turns into more of a hassle and efficient column filling is mildly more complicated. But also I think it eliminates the potential step of replacing a dynamic tile with one of the fixed ones, so there's less bookkeeping there and — as a very helpful result — you therefore never end up uploading tiles that you're not actually using. So you probably claw back from the IO stuff, and I'm not sure the line drawing is so terrible if you're run slicing. Vertical slices are trivial to clip. Horizontals add a per-pixel decision though. Though if you also maintain a global minimum and always draw lines from top to bottom, there's also a potential win there.

Additional observation: if you're going from front-to-back and filling a populated height table then, supposing there were no other drivers, you could just fill in the horizon at the end. So really no overdraw with no opponent visible.

For the opponent(s?), I guess you need to spirit away a copy of the relevant section of the height table when drawing the track segment he's currently over, then add him at the very end. I can't think of a sufficiently fast way of deciding whether his 2d projection is sufficiently contiguous with that of the track to work within the bounds of a 1d height buffer.

It might be interesting to see exactly how disconcerting it would be for a presentation to use different-coloured segment tops and no definition lines — that's exactly correct until the camera rolls but then makes the edges down to the floor go peculiar. If it were fine then, opponent aside, because you're spitting out a linear list of vertical segments to draw, you could go an entirely different way with the output and cheaply just work out the difference between each frame and the previous so as just to draw the differences. I definitely think that's more of a frame buffer approach than a tile approach though. So MSX 2 territory.

Page 2/4
1 | | 3 | 4
My MSX profile