Jump to content
  • entries
    657
  • comments
    2,702
  • views
    904,416

release candidate 3


SpiceWare

2,565 views

  • fixed the synchronized rotation issue with large asteroids

When I first started coding Space Rocks, I set it up to support an arbitrary number of styles for each size of asteroid as I didn't know how many would end up in the game. So I wrote the original InitWave routine like this to select a random asteroid style, rotation and speed:

 gSpriteAnimSeqID[i] = LARGE_ASTEROID_SEQ_ID + ((LARGE_VARIATIONS * (Random32() & 0xff)) >> ;
gSpriteAnimControl[i] = RandomRotation();

 

LARGE_VARIATIONS is defined as the number of styles, say 2, 3 or 4. The multiplication with Random32(), combined with the masking (&) and shifting (>>) results in 0-1 for 2 styles, 0-2 for 3 and 0-3 for 4.

 

I thought we'd end up with 3, maybe 4, but the graphics took more space than I was expecting so we ended up with just 21 styles (and we even had to reduce the number of rotation positions from 32 to 24.) As ROM grew ever tighter, I started optimizing the code and rewrote that section like this:

 gSpriteAnimSeqID[i] = LARGE_ASTEROID_SEQ_ID + (Random32() & 1);
gSpriteAnimControl[i] = RandomRotation();

 

Because the style of asteroid and the rotation were in sync with each other (so that style A rotates one direction and B the other), something had to be going on in RandomRotation(). At first glance it's not obvious what it could be:

unsigned char RandomRotation()
{
// bit 7 controls rotation direction, 0-6 speed
// rotation speeds 8-23
return ((Random32() >> 24) & 0x8F) + 8;
}

 

 

In computers, there's no such thing as random. We simulate random using various techniques, and the one I'm using in Space Rocks is known as a Linear Feedback Shift Register (LFSR). The specific implementation I'm using is the Galios LFSR.

unsigned int Random32()
{
static unsigned int random = 0x02468ace;

return random = (random >> 1) ^ (unsigned int)(-(random & 1u) & 0xd0000001u);
}

 

In looking at the init wave routines, bit 0 of the random number is being used to determine which asteroid style is drawn.

 

In looking at the rotation/speed routines, bit 31 of the random number is being used to determine the direction of rotation.

 

In looking at the random number routine, the prior random number is manipulated in such a way that the inversion of whatever was in bit 0 is now in bit 31 (if bit 0 had 0, then bit 31 will get 1. If bit 0 had 1, 31 will get 0). This link between bit 0 of the prior and bit 31 of the current random number is what caused the rotation and style to be in sync.

 

To fix the problem of synchronized rotations, I modified RandomRotation to use a different 8 bit segment of the LFSR as such:

unsigned char RandomRotation()
{
// bit 7 controls rotation direction, 0-6 speed
// rotation speeds 8-23
return ((Random32() >> 16) & 0x8F) + 8;
}

 

 

1there's really 4 styles as each style is available in solid or vector format.

 

 

ROMs

spacerocks20121004_NTSC.bin

spacerocks20121004_PAL.bin

 

Note: if you have a Harmony, please run the Stress Test ROM on your real Atari so we can make sure the screen jitter and rolling problem has been resolved.

 

spacerocks20121004_STRESS_TEST.bin

 

Source

spacerocks20121004.zip

29 Comments


Recommended Comments



Very nice work - I think it is now done!

 

Using the ARM in this way is very interesting - it makes some things easier, but you still have to worry about every byte and cycle just as with normal Atari 2600 programming. I always find the game logic to be a pain to program in 6502, so it is cool to be able to do that in C, while still doing the tricky kernel programming in 6502.

Link to comment

Thanks! There's a couple of cosmetic things left like the new menu title graphic, which is going to be redone to match the label.

 

Yeah, programming in C made a number of things much easier while still maintaining the challenge of the kernel.

Link to comment

Thanks! There's a couple of cosmetic things left like the new menu title graphic, which is going to be redone to match the label.

 

So there is a label already?!

 

Chris

Link to comment

Are you aiming for a release at the Houston Arcade Expo? That doesn't leave much time to get things ready :)

 

Chris

Link to comment

I had a nice run for awhile, but I've lost more often than not and am 0-5 the last five years. So it's anybody's game. There are a lot of really talented artists around AtariAge, and I'm looking forward to seeing what everyone else comes up with.

Link to comment

Can you do something with the shield? Currently it seems that you just have to disable it for a split second to regain full time again. IMO is should take time to recharge.

Link to comment

Probably not, I made a couple fixes to the Magna Mines last night and there's only 11 bytes free for ARM code. I need to do some additional play testing before posting the next RC though, so I'll take a look at it on the off chance I can squeeze something in.

Link to comment

Yep, the game logic is all ARM code, the 6507 handles the kernel, DPC+ register prep and passing of values back and forth for the chips that the ARM doesn't have access to (reading the joystick, updating audio, etc).

 

It's possible enough freed up bytes in the 6507 code would help though, as I could then move a graphic image from the ARM banks into the 6507 banks. The only images in the ARM banks are for the 32 scanline large asteroids though. What's currently free is this:

 

11 - bank 0-4 (ARM)

10, 18, 12, 20 - scattered in bank 5 due to kernel alignment requirements

3 - Display Data

7 - Frequency Data

Link to comment

If possible, I'd like to see the hyperspace re-charge timer decreased a little bit. I know it was put in to stop cheating, but the delay seems too long now.

Link to comment

Couldn't that timer be reused for shield too?

 

There isn't much code to optimize, just heaps of graphic and other data. It already seems pretty good optimized for overlapping.

Link to comment

Just checked and the hyperspace delay is set for 5 seconds. The timer starts as soon as the ship starts to wrap in, which takes about .4 seconds, so the net result is a 4.6 second delay.

 

The same timer is used for shields and hyperspace, ship_special_countdown[player], it's just used differently for each option. For hyperspace it counts down to 0 for when to respawn, and it counts up to 0 for the cool down. For shields it just counts down from 180 (3 seconds) and if it hits 0 the ship explodes.

Link to comment

If I'm not mistaken, based on the thumb flags I see in the make file, that's room for 5 instructions. Of course that depends on how well the C compiler does its job.

 

One thing that can buy back a little space is if I use FRAME for some things instead of Random32() - changing this:

turn = 1 - (Random32() & 2);

 

to this:

turn = 1 - (FRAME & 2);

 

saved 4 bytes so there's now 15 bytes free. That's not a viable solution for all uses of Random32(), but for that one it should be random enough. That's from one of the pending Magna-Mine fixes, before if you hit the double-section Magna-Mine when it was headed straight for you, the back half would always turn clockwise.

j = (direction - gSpriteMotion[i]) & 31;
if (j > 16)
turn = -1;
else if (j > 0)
turn = 1;
else
turn = 0;

 

With this change it now randomly turns:

j = (direction - gSpriteMotion[i]) & 31;
if (j == 16)
turn = 1 - (FRAME & 2); //(Random32() & 2);
else if (j > 16)
turn = -1;
else if (j > 0)
turn = 1;
else
turn = 0;

Link to comment

You can save a few bytes here:

 

P1EarlyHM38: ; 5 20

lda #<DS_HMP0 ; 2 22

sta HMP0 ; 3 25

PHA ; \ 7 cycles, 2 bytes

PLA ; /

jmp P1_RESP1a ; 3 35

 

Instead of sta HMP0, PHA/PLA and later jsr WasteTimeXY you can do SLEEP 2 and a jmp to the previous delay (always SLEEP 2 too)

 

This should save 4 times 3-4 bytes.

 

And the same trick again starting from P1EarlyHM58.

Link to comment

Here is the first part:


P1EarlyHM28: ; 5 20
 lda #<DS_HMP0 ; 2 22
 sta HMP0 ; 3 25
 sta RESP1 ; 3 28
 jmp KL_R2 ; 3 31

P1EarlyHM33: ; 5 20
 SLEEP 2 ; 2 22
 jmp P1EarlyHM28 ; 3 25

P1EarlyHM38: ; 5 20
 SLEEP 2 ; 2 22
 jmp P1EarlyHM33 ; 3 25

P1EarlyHM43: ; 5 20
 SLEEP 2 ; 2 22
 jmp P1EarlyHM38 ; 3 25

P1EarlyHM48: ; 5 20
 SLEEP 2 ; 2 22
 jmp P1EarlyHM43 ; 3 25

P1EarlyHM53: ; 5 20
 SLEEP 2 ; 2 22
 jmp P1EarlyHM48 ; 3 25

Link to comment

Just checked and the hyperspace delay is set for 5 seconds. The timer starts as soon as the ship starts to wrap in, which takes about .4 seconds, so the net result is a 4.6 second delay.

I think that could comfortably be cut in half. After all, hyperspace isn't a guaranteed escape since you can always re-materialize inside a rock.

Link to comment

Guest
Add a comment...

×   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.

Loading...
  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...