So we were looking at reducing the gameplay from fighting games referenced on the last post.
I thought the arcade Pong (1972) connects well, let’s see, as a kind of combat game, pong sports 2 players each controlling its own pad up and down and they have to bounce back a ball. The ball starts at the middle and takes a random diagonal direction to boot, it bounces on top and lower parts of the screen, the players are also limited by those boundaries.
Your score adds if the opponent can´t deflect the ball, say, whoever scores 10 wins.
The ball resets after score. Each player has a 1 axis control, or say, in a d-pad world, two buttons, up and down.
So how would that mutate into a crude fight game?
We rotate the middle line to make it the ground, each paddle on each side can move sideways instead, and are restricted by the screen border or the other paddle. Whoever presses the attack button, will have the ball blink in front of him and if it touches the other player, he will lose a score point. Score starts at 10 and whoever reaches 0 looses.
Within the differences between both, the later has contact in a sense that the players are on the same space and their distance to each other is a strong game element, one is constantly considering that, it is active, while the prime is more passive and has its main attention on the distance between player and ball should it be heading your way. The later also adds an extra control, an action button.
That, to me, seems to be the very essence of what a fight game is. The very core gameplay.
One can see how extra stuff got this into the 85´s arcade games I mentioned before, adding rounds, jump, crouch, other attacks, other pad types, more pads onscreen, etc.
For this project, let’s target that essence to boot, if that is no fun, whatever we add above it won´t be either.
But let’s get back to the color computer BASIC, Extended Color Basic, to be precise, these could be the major problems I kind of foresee:
- Total memory for the game is about 25kb. Both the code list and variables used will eat through it, the memory use will dictate what I will be able to have in, therefore, the scope and gameplay of the final game.
- Graphics can only be plotted fast enough, I have to check its performance.
- Code structure is troublesome, depending on how it is done, the performance hit is strong.
- Reading controls, be it keys or joysticks, is performance expensive.
- Game logic and AI will also hit it for it demands more code and variables.
- As well as the size of the game, the bigger it is, the slower it might get.
With these in mind, It feels a tripod consisting of graphic performance, memory use and the game idea, will lead the core of the project. The last one is easier to manage and adapt, so at this point, it is necessary to research the prior two.
On the graphic side, I know of 3 ways to draw semigraphic blocks in BASIC:
- Using SET / RESET commands.
- Using PRINT command.
- Using POKE command.
We also need to keep in mind that there is no such concept as sprites, where you go about plotting graphics and the computer will keep its background in memory to automatically fill it under should the sprite move. On modern computers I will usually go about redrawing the whole screen every cycle, there is more than enough power for that, but not here. So, whatever you plot on screen, stays there until erased, there is no transparency, erasing is a matter of plotting the background color over.
Let’s test a full block moving from left to right on screen. I will draw a block, delete it , move it a block further, start over. Here is the code for it:
10 TIMER=0:TM=TIMER
20 X=0:Y=16
30 CLS(0)
50 SET(X,Y,3):SET(X+1,Y,3):SET(X,Y+1,3):SET(X+1,Y+1,3)
60 RESET(X,Y):RESET(X+1,Y):RESET(X,Y+1):RESET(X+1,Y+1)
70 X=X+1
80 IF X=63 THEN ?TIMER-TM;:END
100 GOTO 50
And here is the result.
As one can see, I need 4 SET calls to make a block and 4 RESETs to erase it so this command is actually drawing the pixels inside a block. The time it takes to perform this move is 186. Let’s check how PRINT fares.
10 TIMER=0:TM=TIMER
20 X=224
30 CLS(0)
50 PRINT @X,CHR$(&HAF);
60 PRINT @X,CHR$(&HA0);
70 X=X+1
80 IF X=256 THEN ?TIMER-TM;:END
100 GOTO 50
As we can see, it takes less code and one less variable for position. The speed is so fast that the GIF capture program could not handle recording it properly or in sync at 60fps. The time it took to cover the screen is 34.
Let’s try plotting a 3×3 set of blocks.
10 TIMER=0:TM=TIMER
20 X=224
30 CLS(0)
50 PRINT @X,CHR$(&HAF)CHR$(&HAF)CHR$(&HAF);
51 PRINT @X+32,CHR$(&HAF)CHR$(&HAF)CHR$(&HAF);
52 PRINT @X+64,CHR$(&HAF)CHR$(&HAF)CHR$(&HAF);
60 PRINT @X,CHR$(&HA0)CHR$(&HA0)CHR$(&HA0);
61 PRINT @X+32,CHR$(&HA0)CHR$(&HA0)CHR$(&HA0);
62 PRINT @X+64,CHR$(&HA0)CHR$(&HA0)CHR$(&HA0);
70 X=X+1
80 IF X=253 THEN ?TIMER-TM;:END
100 GOTO 50
One also notices it flicks a lot, so even at this neat speed, a single draw call is actually very time consuming, one can almost see the block plotting order. Let me try that with POKE just for the sake of illustrating it.
10 TIMER=0:TM=TIMER
20 X=224
30 CLS(0)
50 POKE X,175:POKE X+1,175:POKEX+2,175
51 POKE X+32,175:POKE X+33,175:POKEX+34,175
52 POKE X+64,175:POKE X+65,175:POKEX+66,175
60 POKE X,128:POKE X+1,128:POKEX+2,175
61 POKE X+32,128:POKE X+33,128:POKEX+34,128
62 POKE X+64,128:POKE X+65,128:POKEX+66,128
70 X=X+1
80 IF X=253 THEN ?TIMER-TM;:END
100 GOTO 50
Performance is at 239, almost twice slower than the 131 from PRINT. Like I said, each block has a POKE equivalent, while adjacent blocks with PRINT can be stacked, so I´m making 6 PRINT calls against 18 POKE calls, and I´m also calling CHR$ functions inside those PRINT commands!
But… that is a lot of blinking, one may think, how the heck is that disco boogie going to look like a game?
So I made this other test tool, quite a big one at ~8kb in size, with interface and what not, so that also goes for a warming up in coding BASIC.
What you get in this test is individual block drawings (no PRINT stacking) where you can set from 4 to 32 blocks being plotted (pens) and also 2 modes of drawing. The other options are not quite important, so let´s leave them off (0).
On mode 0, all blocks will be drawn and erased just like we were doing so far, attempting to mimic sprites.
Mode 1 is different, blocks are added sideways with a delay in space so to make a snake type animation.
Conclusion: PRINT has the edge over both other commands. While SET could be used for other types of games, for its ability to plot a pixel instead of a block, I can’t really see any benefits on using POKEs. So PRINT is the winner for performance and memory use. Also, attempting to mimic sprites is not practical, the best way to go is to plot over what is already on screen and erasing just the necessary blocks, like that snake mode.
About the last test, things are actually moving faster than I thought possible! At this point, I recalled the articles about BASIC optimization on the COCO by Allen Huffman. Those are superb stuff and feels essential to a project like this, here is the link:
https://subethasoftware.com/2015/01/03/optimizing-color-basic/
As an example, the last test was coded very sloppy with mountains of wastes. It took about 8kb.
After reading Allen´s articles and applying just a few of those techniques, the test now takes 6kb and runs about 2/3 faster!
Would you like to try that test? Download both ASC files from here:
https://drive.google.com/file/d/1w6NfLEXCaThanPLmMMV9SLSeEUBCAf3H/view?usp=sharing
Catch you guys later!