2

I got feeling retro and decided to write my favorite 8-bit computer game (Williams' Defender) on my first computer (Commodore PET 4032). All the code is being done in 6502 Assembly language. For those not familiar with the PET, all the graphics are character-based and to build games you move different characters around a 40 column x 25-row screen. This is very old tech - there are no sprites, no graphics layers, no ability to AND at the screen level, etc that we would be used to today.

I want the game to have multiple "laser beams" to be fired at the same time, and those laser beams might go on top of one another as they traverse the screen. Right now, as the beams move along the screen they store in memory what was underneath themselves and then replace what was underneath themselves as they move along to restore the background to its original state. The problem comes when a second laser goes on top of the first .. the first moves along and replaces the original background rather than leaving the second laser on top, then that second laser moves along and leaves artifacts of the first behind.

Is there a classic "light" algorithm or rule-set that allows multiple objects to move across one another such that the original proper things underneath are retained? I've tried different approaches (swapping backgrounds as things traverse, etc) but nothing seems to give me the correct result that I want.

4

3 回答 3

2

It's certain an option to have each sprite keep a copy of whatever it overwrote, and have them erase themselves in the opposite order to that in which you drew them. That can't fail, but it assumes you have time for a full sprite draw and erase each frame.

You can also use a screen-sized buffer of 'is background' and 'is sprite' flags. Each time a sprite is drawn, mark its character locations as 'is sprite'. To erase all sprites iterate through the screen-sized buffer repainting the background anywhere that isn't marked 'is background'. You can keep upper and lower bounds of updated positions if iterating the whole 2000 potential slots is too great a cost.

You can also compare the differences between two such buffers to reduce flicker substantially supposing you have only one video buffer: paint the new sprites first, wherever they should go, noting them in the new buffer. Once all sprites are drawn, fill in background anywhere that the new buffer isn't marked 'is sprite' but the old is.

于 2020-01-02T03:46:55.147 回答
2

I would suggest:

  • Maintain a model of the game state that would allow you to redraw the entire screen at any time. This would include the positions and other state of all movable elements
  • As you update the game state between frames, accumulate a mask of all the cells that will need to be redrawn, because something in them changed or moved.
  • Iterate through the game elements in depth order from top to bottom, redrawing the parts of each element that are in the changed-cell mask
  • Remove any cell you draw from the changed-cell mask so it won't be rewritten by deeper elements.
  • The background will be last, and will redraw all remaining cells, leaving you with an empty mask ready for the next frame.

This procedure avoids any flicker that would be caused by undrawing anything you draw in a single frame.

Various indexing structures can be added to the changed cell mask to avoid unnecessary drawing work. What kinds of optimizations are appropriate here depend on your game. If the background is mostly static, for example, then it would be useful to add the coordinates of each changed cell to a list during the update, and then only check those cells during the background redraw. Or you could do this based on the previous positions of all movable elements... up 2 you.

If the majority of the scene changes in every frame, then you can skip the mask accumulation and just start with a full screen mask... although I think a PET might not be fast enough for such games.

于 2020-01-05T17:01:55.580 回答
0

Having never programmed for the Pet, I can't offer any specific advice about what you might try, but I can recommend keeping a copy of the current on-screen background in about 1k of RAM. That way, you can use that data to restore your background when removing the last "sprite" written to that tile. Unfortunately, that also requires you to keep your code and object data combined under 31k, unless you are programming this as a cartridge. Just a few thoughts, for what they're worth.

于 2020-01-18T04:31:13.503 回答