Author Topic: Making a SHMUP (shoot-em-up) in Axe  (Read 10732 times)

0 Members and 1 Guest are viewing this topic.

Offline Deep Toaster

  • So much to do, so much time, so little motivation
  • Administrator
  • LV13 Extreme Addict (Next: 9001)
  • *************
  • Posts: 8217
  • Rating: +758/-15
    • View Profile
    • ClrHome
Making a SHMUP (shoot-em-up) in Axe
« on: February 28, 2011, 08:14:35 pm »
This is a more specific tutorial on how to make SHMUP games. Some of the info overlaps with my Arrays in Axe tutorial, though, so I might just delete that someday.

After I finish this tutorial I'll probably work on one to make platformers :D

How to make a shoot-em-up

Space Invaders, Phoenix, Phantom Star—you've seen shoot-em-up games before. They can come in a variety of styles, but in general they're games where you play as a single ship with unlimited firepower firing recklessly and indiscriminately on groups of "enemies" that are only trying to defend their home planet. Cruelty is fun.

This tutorial will guide you step by step in making a simple shoot-em-up. First, as with any game, we need to decide what our game should look like. Let's just stick with one level for the purposes of this tutorial, but we can have a lot of fun with how enemies and bullets move. Let's get creative; maybe something like this?

[epic screenshot goes here]

Looks good? Like with all my programs, the code's split into sections, because it makes debugging that much easier. We start my making the main program ASHMUP that sets everything up:





prgmASHMUPD will hold our data, prgmASHMUPI will set up (initiate) the variables, and prgmASHMUPR will hold all our subroutines. The actual game goes in the loop, so the user can quit at any time by pressing CLEAR. prgmASHMUPK handles user keypresses (and moves the ship accordingly), while prgmASHMUPM moves and tests the enemies and bullets.

The home ship

First let's make our ship move. Create program ASHMUPD and put this in:



That's going to be our character.

Now let's code the actual movement. Since our ship's just one ship, we won't put it in an array. We need to keep track of its X- and Y-positions; for simplicity, how about just X and Y? Here's prgmASHMUPK:





We move two pixels each time.

We haven't given it an initial position yet, so put that in prgmASHMUPI. The ship should start in the center of the screen, maybe a closer to the bottom edge. (44, 40) should work.



But how will we display the ship and all the other stuff in the actual game? For such a simple game, let's just clear the screen and redraw everything every time. It's actually faster than the alternatives in this case because everything on the screen is dynamic. So change the main program to this:





I've also commented the lines "prgmASHMUPM" and "prgmASHMUPR" since we haven't actually made them yet.

Well, how does it look? Compile it and see for yourself.



It's a bit fast, but it works well enough for now. It'll slow down after we add the enemies and bullets anyway. That's what we'll do next.

Chargin' laz0rz

All right, now for the fun stuff: bullets! Since there can be more than one bullet at a time, we need to store it in an array. Arrays are basically lists of elements with a similar structure; see our guide to arrays for more information.

Before we make the subroutines, though, we need to decide what the array's going to look like. An array is just a list of elements, so we need to figure out the most efficient format to store a bullet in. What information do you need about a bullet?

  • Bullet type - Not really important now, but by adding this you're allowing yourself the opportunity to add cannons, laz0rz, and all that fun stuff (later on).
  • Bullet speed - again, this would allow you to have different kinds of bullets.
  • X-value of the bullet
  • Y-value of the bullet

So that's it. Four bytes per element. We can store the bullets in L4, which gives us 323 bytes (80 elements) of memory to work with. First, like with all arrays, we need to set a variable up to store the number of elements. It should be initialized in the init code.



Now you can add the bullet-adding subroutine to put in prgmASHMUPR:





Again, see http://ourl.ca/9288/176368 for a full-length explanation on how this works.

Of course, bullets should only be added when the user presses a button to fire. One option could be 2ND. But we don't want the ship to fire too rapidly, so first set up a counter in the main program. We'll be using this counter for lots of things, here to make sure the fire button doesn't repeat too quickly.





The only new line of code is a "C+1?C" right after the main loop starts. We don't really have to initiate C because since we're not using the whole number anyway, it won't make much of a difference.

What does matter though is how C affects firing. Add this code to the end of prgmASHMUPK:







Just in case you don't understand this code completely, it first checks if 2ND is held down (if didn't memorize the keycode table, it's 54). Then it tests to see if the counter is a multiple of 8. This adds a little pause between consecutive bullets; otherwise, a bullet is added each pass of the loop, and you'd quickly get a continuous stream of bullets!

And if the conditions are right, the program adds a "type 1" bullet with a speed of 3 pixels per pass (a bit faster than the ship at 2) placed at a position three pixels to the right of the ship and four pixels up, which positions a 2- by 4-pixel bullet nicely. Don't bother compiling yet, since we haven't added any of the actual bullet-drawing code. That's in the next section.

Bullets can move

Let's take a break from coding. Put this in ASHMUPD.



That's the sprite for the bullet, of course (2 by 4).

All right, break's over. Back to the code!





That goes in a new program called ASHMUPM (you can check in the main program to see where the code'll be run).

It might look confusing at first, but that's because of how optimized it is. [Insert self-congratulating remarks here.] First of all, the For( loop goes from 1 to L, not 0 to L-1, unlike most indexes, which start at zero. This is because since I is checked against the maximum value (either L or L-1) every pass of the loop, there's a speed optimization in using L. We'll be taking care of that extra 1 in the actual code.

The next line is a gigantic if statement that already moves the bullet. It looks complicated, but just look at the inside first: "{I*4+L4-1?J}." It takes I (the current index being parsed), multiplies it by four (the number of bytes per element), and adds L4-1. Why L4-1? If you just add L4, you get the next element's first byte (since we're starting the loop at 1), so if you subtract one from that, it would be the current element's Y-value. The pointer to that is stored to J for later reference.

Then the {J-2} is subtracted. Since J points to the current Y-value, two bytes before it would be the speed of the bullet. And since our bullets go upwards, we subtract. All of this gets stored back to {J}.

Now here's the (über1337) optimization: Since the store statement is storing to a non-constant pointer (thanks to the J), it returns the pointer stored to, which you can use for further operations. In this case we wrap the whole thing with braces to get the value again and test if it's greater than 127 (because if its signed value is less than zero, its unsigned value is greater than 127; we actually save a few bytes by not having to use sign{). If it did, we call Lbl RSB, which we'll set up next.

Finally, a working gun

Lbl RSB is a subroutine, so that means we go back to prgmASHMUPR. Here's the code:





All this does is remove the element from the list. For a full explanation, see the guide to arrays.

Now there's one last thing we need to do before the program works. Back when we finished the first little demo we commented out all the lines importing programs that didn't exist (yet). Now that we've made them, take all the periods out. You probably don't need a screenshot for this.

Finally, it's time to actually display the bullets. Since they're in an array, the program would have to loop through the array and display each one, but conveniently, we already have one such loop set up in prgmASHMUPM. Let's just edit that to save ourselves another loop:





The code is pretty similar to the stuff in prgmASHMUPM (in fact, we could have saved a few more bytes by combining the two), so I won't explain it here. If you want a review, it's here.

And it works!



Next: Enemieshomer/The+Game+is+near.+Prepare+++Done.png[/img]
« Last Edit: April 19, 2012, 06:46:02 pm by Deep Thought »




Offline willrandship

  • Omnimagus of the Multi-Base.
  • LV11 Super Veteran (Next: 3000)
  • ***********
  • Posts: 2953
  • Rating: +98/-13
  • Insert sugar to begin programming subroutine.
    • View Profile
Re: Making a shoot-em-up in Axe
« Reply #1 on: February 28, 2011, 08:22:12 pm »
Cool! I'd love to try this out.

Offline FinaleTI

  • Believe in the pony that believes in you!
  • CoT Emeritus
  • LV10 31337 u53r (Next: 2000)
  • *
  • Posts: 1830
  • Rating: +121/-2
  • Believe in the pony that believes in you!
    • View Profile
    • dmuckerman.tumblr.com
Re: Making a SHMUP (shoot-em-up) in Axe
« Reply #2 on: February 28, 2011, 08:41:20 pm »
Cool! One suggestion I have is to use DispGraphClrDraw. It would make the program faster, but I'm not sure about smaller.


Spoiler For Projects:

My projects haven't been worked on in a while, so they're all on hiatus for the time being. I do hope to eventually return to them in some form or another...

Spoiler For Pokemon TI:
Axe port of Pokemon Red/Blue to the 83+/84+ family. On hold.

Spoiler For Nostalgia:
My big personal project, an original RPG about dimensional travel and a few heroes tasked with saving the world.
Coding-wise, on hold, but I am re-working the story.

Spoiler For Finale's Super Insane Tunnel Pack of Doom:
I will be combining Blur and Collision Course into a single gamepack. On hold.

Spoiler For Nostalgia Origins: Sky's Story:
Prequel to Nostalgia. On hold, especially while the story is re-worked.

Offline Deep Toaster

  • So much to do, so much time, so little motivation
  • Administrator
  • LV13 Extreme Addict (Next: 9001)
  • *************
  • Posts: 8217
  • Rating: +758/-15
    • View Profile
    • ClrHome
Re: Making a SHMUP (shoot-em-up) in Axe
« Reply #3 on: February 28, 2011, 08:44:08 pm »
Cool! One suggestion I have is to use DispGraphClrDraw. It would make the program faster, but I'm not sure about smaller.

Smaller, too. But yeah, there are a couple of opts I left out, such as combining the display routine as part of ASHMUPM. I might fix that eventually.




Offline FinaleTI

  • Believe in the pony that believes in you!
  • CoT Emeritus
  • LV10 31337 u53r (Next: 2000)
  • *
  • Posts: 1830
  • Rating: +121/-2
  • Believe in the pony that believes in you!
    • View Profile
    • dmuckerman.tumblr.com
Re: Making a SHMUP (shoot-em-up) in Axe
« Reply #4 on: February 28, 2011, 08:48:20 pm »
True. Plus, since it's a tutorial, optimizing the hell out of it might not be the best idea, if only for readability's sake.


Spoiler For Projects:

My projects haven't been worked on in a while, so they're all on hiatus for the time being. I do hope to eventually return to them in some form or another...

Spoiler For Pokemon TI:
Axe port of Pokemon Red/Blue to the 83+/84+ family. On hold.

Spoiler For Nostalgia:
My big personal project, an original RPG about dimensional travel and a few heroes tasked with saving the world.
Coding-wise, on hold, but I am re-working the story.

Spoiler For Finale's Super Insane Tunnel Pack of Doom:
I will be combining Blur and Collision Course into a single gamepack. On hold.

Spoiler For Nostalgia Origins: Sky's Story:
Prequel to Nostalgia. On hold, especially while the story is re-worked.

Offline Deep Toaster

  • So much to do, so much time, so little motivation
  • Administrator
  • LV13 Extreme Addict (Next: 9001)
  • *************
  • Posts: 8217
  • Rating: +758/-15
    • View Profile
    • ClrHome
Re: Making a SHMUP (shoot-em-up) in Axe
« Reply #5 on: February 28, 2011, 08:49:09 pm »
True. Plus, since it's a tutorial, optimizing the hell out of it might not be the best idea, if only for readability's sake.

<_< Whoops.
« Last Edit: February 28, 2011, 08:49:16 pm by Deep Thought »




Offline FinaleTI

  • Believe in the pony that believes in you!
  • CoT Emeritus
  • LV10 31337 u53r (Next: 2000)
  • *
  • Posts: 1830
  • Rating: +121/-2
  • Believe in the pony that believes in you!
    • View Profile
    • dmuckerman.tumblr.com
Re: Making a SHMUP (shoot-em-up) in Axe
« Reply #6 on: February 28, 2011, 08:51:02 pm »
Of course, if you explain it well enough, like with that 4 byte shifting thing, then it probably wouldn't be too much of a problem.


Spoiler For Projects:

My projects haven't been worked on in a while, so they're all on hiatus for the time being. I do hope to eventually return to them in some form or another...

Spoiler For Pokemon TI:
Axe port of Pokemon Red/Blue to the 83+/84+ family. On hold.

Spoiler For Nostalgia:
My big personal project, an original RPG about dimensional travel and a few heroes tasked with saving the world.
Coding-wise, on hold, but I am re-working the story.

Spoiler For Finale's Super Insane Tunnel Pack of Doom:
I will be combining Blur and Collision Course into a single gamepack. On hold.

Spoiler For Nostalgia Origins: Sky's Story:
Prequel to Nostalgia. On hold, especially while the story is re-worked.

Offline Deep Toaster

  • So much to do, so much time, so little motivation
  • Administrator
  • LV13 Extreme Addict (Next: 9001)
  • *************
  • Posts: 8217
  • Rating: +758/-15
    • View Profile
    • ClrHome
Re: Making a SHMUP (shoot-em-up) in Axe
« Reply #7 on: February 28, 2011, 08:54:28 pm »
Which 4-byte shifting code, and for that do you mean it's explained well enough, or should I explain more?




Offline FinaleTI

  • Believe in the pony that believes in you!
  • CoT Emeritus
  • LV10 31337 u53r (Next: 2000)
  • *
  • Posts: 1830
  • Rating: +121/-2
  • Believe in the pony that believes in you!
    • View Profile
    • dmuckerman.tumblr.com
Re: Making a SHMUP (shoot-em-up) in Axe
« Reply #8 on: February 28, 2011, 08:57:24 pm »
The bullet adding subroutine. It made sense to me. I sometimes have trouble grasping weird Axe optimizations and quirks, so I thought it was well explained.

EDIT: I'm talking about the explanation in the other tutorial, the array one. I think it was used for adding enemies to the array.
« Last Edit: February 28, 2011, 08:58:18 pm by FinaleTI »


Spoiler For Projects:

My projects haven't been worked on in a while, so they're all on hiatus for the time being. I do hope to eventually return to them in some form or another...

Spoiler For Pokemon TI:
Axe port of Pokemon Red/Blue to the 83+/84+ family. On hold.

Spoiler For Nostalgia:
My big personal project, an original RPG about dimensional travel and a few heroes tasked with saving the world.
Coding-wise, on hold, but I am re-working the story.

Spoiler For Finale's Super Insane Tunnel Pack of Doom:
I will be combining Blur and Collision Course into a single gamepack. On hold.

Spoiler For Nostalgia Origins: Sky's Story:
Prequel to Nostalgia. On hold, especially while the story is re-worked.

Offline ztrumpet

  • The Rarely Active One
  • CoT Emeritus
  • LV13 Extreme Addict (Next: 9001)
  • *
  • Posts: 5712
  • Rating: +364/-4
  • If you see this, send me a PM. Just for fun.
    • View Profile
Re: Making a SHMUP (shoot-em-up) in Axe
« Reply #9 on: February 28, 2011, 09:50:07 pm »
Looks great!  Are you going to keep the ship on the screen?

Cool! One suggestion I have is to use DispGraphClrDraw. It would make the program faster, but I'm not sure about smaller.
Smaller, too.
I think it would make it bigger, as long as you already have the ClrDraw and DispGraph commands elsewhere.

Offline Deep Toaster

  • So much to do, so much time, so little motivation
  • Administrator
  • LV13 Extreme Addict (Next: 9001)
  • *************
  • Posts: 8217
  • Rating: +758/-15
    • View Profile
    • ClrHome
Re: Making a SHMUP (shoot-em-up) in Axe
« Reply #10 on: February 28, 2011, 10:55:41 pm »
Looks great!  Are you going to keep the ship on the screen?

What do you mean?

Cool! One suggestion I have is to use DispGraphClrDraw. It would make the program faster, but I'm not sure about smaller.
Smaller, too.
I think it would make it bigger, as long as you already have the ClrDraw and DispGraph commands elsewhere.

Nope, it's just a tutorial, so that's all the code :)
« Last Edit: February 28, 2011, 10:56:11 pm by Deep Thought »




Offline ralphdspam

  • LV8 Addict (Next: 1000)
  • ********
  • Posts: 841
  • Rating: +38/-1
  • My name is actually Matt.
    • View Profile
Re: Making a SHMUP (shoot-em-up) in Axe
« Reply #11 on: March 01, 2011, 12:00:36 am »
Thanks! This is really helpful.  :)
Can you attach the source to make it easier to read?
ld a, 0
ld a, a

Offline Deep Toaster

  • So much to do, so much time, so little motivation
  • Administrator
  • LV13 Extreme Addict (Next: 9001)
  • *************
  • Posts: 8217
  • Rating: +758/-15
    • View Profile
    • ClrHome
Re: Making a SHMUP (shoot-em-up) in Axe
« Reply #12 on: March 01, 2011, 12:04:19 am »
Ah, I'll do that when I actually finish the example program ;D

And kalan_vod on RevSoft suggested putting the code in [code] blocks. Would that be helpful?
« Last Edit: March 01, 2011, 12:04:46 am by Deep Thought »




Offline Runer112

  • Project Author
  • LV11 Super Veteran (Next: 3000)
  • ***********
  • Posts: 2289
  • Rating: +639/-31
    • View Profile
Re: Making a SHMUP (shoot-em-up) in Axe
« Reply #13 on: March 01, 2011, 01:52:03 am »
Awesome tutorial! ;D But because I'm OCD about optimization, I feel like optimizing this. Since this is a tutorial, feel free to not include these optimizations, as they'll probably just make the code more confusing. But I want to try to optimize it anyway. :hyper:



Code: (ASHMUP) [Select]
:.SHMUP An awesome game.
:prgmASHMUPD
:prgmASHMUPI
:Repeat getKey(15)
:C+1→C
:prgmASHMUPK
:prgmASHMUPM
:ClrDraw
:If B
:For(I,1,B)
:Pt-On({I*4+L₄-2→J},{J+1},Pic0)
:End
:End
:Pt-Change(X,Y,GDB0)
:DispGraph
:End
:prgmASHMUPR
       
Code: (ASHMUP Optimized) [Select]
:.SHMUP An awesome game.
:prgmASHMUPD
:prgmASHMUPI
:Repeat 0
:C+1→C
:prgmASHMUPK
:ClrDraw
:B
:While
:-1→I
:!If {*4+L₄+2→J+1}+{J-1}→K*4-256<996
:Pt-On({J},K,→{J+1}Pic0)
:Else
:Isub(RSB)
:End
:I
:End
:Pt-On(X,Y,GDB0)
:DispGraph
:EndIf getKey(15)
:Return
:prgmASHMUPR

Optimization notes (savings listed in brackets):
  • [3 bytes, 10 cycles per iteration] – Main getKey(15) loop changed to post-check format
  • [31 bytes, ~104 cycles per bullet] – prgmASHMUPM merged into the already existing bullet drawing loop, removing the need for 2 separate loop structures
  • [8 bytes] – Removed check that B≠0 before the bullet loop; it is unnecessary because the loop already handles this properly
  • [8 bytes, ~38 cycles per bullet] – Bullet loop structure optimized
  • [3 bytes, 16 cycles] – Due to the bullet loop no longer being a For() loop, the value of the loop variable can now be carried into the first function inside the loop
  • [3 bytes, 12 cycles] – Bullet velocity added to y value instead of subtracted from y value
  • [⁻3 bytes, ⁻26 cycles] – Bullet offscreen check changed from <127 to *4-256<996; this is a more compact emulation of (VALUE<64) or (VALUE>248) which would appear to me to be an improved logic statement for this scenario
  • [9 bytes, 57 cycles] – J value when checking bullet y value reused to get x value for Pt-On() simply with {J}
  • [6 bytes, 43 cycles] – Reused the value stored in J from the offscreen check to get the x coordinate for Pt-On()
  • [4 bytes, ~18 cycles] – Stored the bullet y value into a variable when checking the y value to avoid needing to retrieve again later in the Pt-On() command; also moved the code to store the new y value to the bullet's data in the middle of the Pt-On() command so the fact that it returns a pointer doesn't disrupt calculations
  • [3 bytes, 16 cycles] – sub(RSB) called without saving the argument into r1 first
  • [126 bytes] – Player sprite drawn with Pt-On() instead of Pt-Change(), removing the need for a second bulky sprite routine
  • [-1 bytes, ? cycles] – A Return added after the main loop, before prgmASHMUPR; without it, after the user presses clear, program execution would just continue into the first subroutine in prgmASHMUPR, potentially causing big problems



Code: (ASHMUPK) [Select]
:..KEYS
:If getKey(1)
:Y+2→Y
:End
:If getKey(2)
:X-2→X
:End
:If getKey(3)
:X+2→X
:End
:If getKey(4)
:Y-2→Y
:End
:If getKey(54)
:!If C^8
:sub(ASB,1,3,X+3,Y-4)
:End
:End
       
Code: (ASHMUPK Optimized) [Select]
:..KEYS
:!If ^8
:If getKey(54)
:sub(ASB,,⁻3,X+3,Y-4)
:End
:End
:!If getKey(3)-getKey(2)+1*2+X
:+2
:End
:min(-2,88)→X
:!If getKey(1)-getKey(4)+1*2+Y
:+2
:End
:min(-2,56)→Y

Optimization notes:
  • [3 bytes, 16 cycles] – Weapon fire checking moved to the top and the counter check moved before the key check, allowing for the counter value to be carried from the previous statement in prgmASHMUP
  • [3 bytes, 10 cycles] – Omitted the bullet type from sub(ASB), as a 1 can be carried from the getKey(54) check
  • Bullet velocity changed from 3 to ⁻3, as the velocity is now added to the y value instead of subtracted from it
  • [⁻22 bytes, too lazy to calculate cycles] – New approach to movement key checking; also makes sure the ship doesn't leave the screen



Code: (ASHMUPR) [Select]
:..ROUTINES
:Lbl ASB
:If B<80
:r₄→{r₃→{r₂→{r₁→{B+1→B*4+L₄-4}+1}+1}+1}
:End
:Return
:Lbl RSB
:Copy(r₁*4+L₄+4,-4,B-1→B-r₁*4+1)
:Return
       
Code: (ASHMUPR Optimized) [Select]
:..ROUTINES
:Lbl ASB
:Return!If B-80
:r₄→{r₃→{r₂→{r₁→{B+1→B*4+L₄-4}+1}+1}+1}
:Return
:Lbl RSB
:Copy(→r₁*4+L₄+4,-4,B-1→B-r₁*4+1)

Optimization notes:
  • [2 bytes, ~5 cycles] – Changed the check that the number of bullets is not too high from an if statement into a conditional return statement
  • [5 bytes, 20 cycles] – Changed If B<80 to !If B-80; the second is an optimized version of If B=80, which should work equally well because B can be 80 but should never be greater than 80
  • [1 byte] – Removed the last Return, as Axe automatically adds a Return at the end of the program



Confusing enough? ;) Ask me if you have questions about any of this and I might be able to remember what the hell I was thinking.
« Last Edit: March 01, 2011, 05:01:54 pm by Runer112 »

Offline Deep Toaster

  • So much to do, so much time, so little motivation
  • Administrator
  • LV13 Extreme Addict (Next: 9001)
  • *************
  • Posts: 8217
  • Rating: +758/-15
    • View Profile
    • ClrHome
Re: Making a SHMUP (shoot-em-up) in Axe
« Reply #14 on: March 01, 2011, 09:26:00 am »
Dammit, Runer :crazy:

Code: (ASHMUP) [Select]
:.SHMUP An awesome game.
:prgmASHMUPD
:prgmASHMUPI
:Repeat getKey(15)
:C+1→C
:prgmASHMUPK
:prgmASHMUPM
:ClrDraw
:If B
:For(I,1,B)
:Pt-On({I*4+L₄-2→J},{J+1},Pic0)
:End
:End
:Pt-Change(X,Y,GDB0)
:DispGraph
:End
:prgmASHMUPR
       
Code: (ASHMUP Optimized) [Select]
:.SHMUP An awesome game.
:prgmASHMUPD
:prgmASHMUPI
:Repeat 0
:C+1→C
:prgmASHMUPK
:ClrDraw
:B
:While
:-1→I
:If {*4+L₄+2→J+1}+{J-1}→K*4-256<996
:Pt-On({J},K,→{J+1}Pic0)
:Else
:Isub(RSB)
:End
:I
:End
:Pt-On(X,Y,GDB0)
:DispGraph
:EndIf getKey(15)
:Return
:prgmASHMUPR

Optimization notes (savings listed in brackets):
  • [3 bytes, 10 cycles per iteration] – Main getKey(15) loop changed to post-check format
  • [31 bytes, ~104 cycles per bullet] – prgmASHMUPM merged into the already existing bullet drawing loop, removing the need for 2 separate loop structures
  • [8 bytes] – Removed check that B≠0 before the bullet loop; it is unnecessary because the loop already handles this properly
  • [8 bytes, ~38 cycles per bullet] – Bullet loop structure optimized
  • [3 bytes, 16 cycles] – Due to the bullet loop no longer being a For() loop, the value of the loop variable can now be carried into the first function inside the loop
  • [3 bytes, 12 cycles] – Bullet velocity added to y value instead of subtracted from y value
  • [⁻3 bytes, ⁻26 cycles] – Bullet offscreen check changed from <127 to *4-256<996; this is a more compact emulation of (VALUE<64) or (VALUE>248) which would appear to me to be an improved logic statement for this scenario
  • [9 bytes, 57 cycles] – J value when checking bullet y value reused to get x value for Pt-On() simply with {J}
  • [6 bytes, 43 cycles] – Reused the value stored in J from the offscreen check to get the x coordinate for Pt-On()
  • [4 bytes, ~18 cycles] – Stored the bullet y value into a variable when checking the y value to avoid needing to retrieve again later in the Pt-On() command; also moved the code to store the new y value to the bullet's data in the middle of the Pt-On() command so the fact that it returns a pointer doesn't disrupt calculations
  • [3 bytes, 16 cycles] – sub(RSB) called without saving the argument into r1 first
  • [126 bytes] – Player sprite drawn with Pt-On() instead of Pt-Change(), removing the need for a second bulky sprite routine
  • [-1 bytes, ? cycles] – A Return added after the main loop, before prgmASHMUPR; without it, after the user presses clear, program execution would just continue into the first subroutine in prgmASHMUPR, potentially causing big problems

Yeah, I was thinking of combining the loops. If I do I might use some but not all of those optimizations (I don't think most Axe coders would understand five lines of that lol).

Why is post-check more optimized than a Repeat loop, though?

And thanks for catching that missing Return. Didn't see that.

Code: (ASHMUPK) [Select]
:..KEYS
:If getKey(1)
:Y+2→Y
:End
:If getKey(2)
:X-2→X
:End
:If getKey(3)
:X+2→X
:End
:If getKey(4)
:Y-2→Y
:End
:If getKey(54)
:!If C^8
:sub(ASB,1,3,X+3,Y-4)
:End
:End
       
Code: (ASHMUPK Optimized) [Select]
:..KEYS
:!If ^8
:If getKey(54)
:sub(ASB,,⁻3,X+3,Y-4)
:End
:End
:!If getKey(3)-getKey(2)+1*2+X
:+2
:End
:min(-2,88)→X
:!If getKey(1)-getKey(4)+1*2+Y
:+2
:End
:min(-2,56)→Y

Optimization notes:
  • [3 bytes, 16 cycles] – Weapon fire checking moved to the top and the counter check moved before the key check, allowing for the counter value to be carried from the previous statement in prgmASHMUP
  • [3 bytes, 10 cycles] – Omitted the bullet type from sub(ASB), as a 1 can be carried from the getKey(54) check
  • Bullet velocity changed from 3 to ⁻3, as the velocity is now added to the y value instead of subtracted from it
  • [⁻22 bytes, too lazy to calculate cycles] – New approach to movement key checking; also makes sure the ship doesn't leave the screen

Thanks! Doesn't seem too hard to understand/explain, so I'll include that.

Code: (ASHMUPR) [Select]
:..ROUTINES
:Lbl ASB
:If B<80
:r₄→{r₃→{r₂→{r₁→{B+1→B*4+L₄-4}+1}+1}+1}
:End
:Return
:Lbl RSB
:Copy(r₁*4+L₄+4,-4,B-1→B-r₁*4+1)
:Return
       
Code: (ASHMUPR Optimized) [Select]
:..ROUTINES
:Lbl ASB
:Return!If B-80
:r₄→{r₃→{r₂→{r₁→{B+1→B*4+L₄-4}+1}+1}+1}
:Return
:Lbl RSB
:Copy(→r₁*4+L₄+4,-4,B-1→B-r₁*4+1)

Optimization notes:
  • [2 bytes, ~5 cycles] – Changed the check that the number of bullets is not too high from an if statement into a conditional return statement
  • [5 bytes, 20 cycles] – Changed If B<80 to !If B-80; the second is an optimized version of If B=80, which should work equally well because B can be 80 but should never be greater than 80
  • [1 byte] – Removed the last Return, as Axe automatically adds a Return at the end of the program

I like leaving the last Return in because it helps code readability, and it makes it easier to add new subroutines after it. It doesn't actually affect the compiled code, right?
« Last Edit: March 01, 2011, 09:26:49 am by Deep Thought »