Sknarp Posted July 22, 2019 Share Posted July 22, 2019 (edited) On 7/29/2019 at 10:29 PM, Sknarp said: If you want to compile this you'll need the modified includes in the same directory, otherwise there's not enough free space. WIPsourceAA.bas 18.82 kB · 20 downloads multisprite_kernel.asm 15.49 kB · 18 downloads score_graphics.asm 929 B · 18 downloads Final version and source above. Might still have alignment issues that need to be fixed, but this is the most complete version as far as I know. ATAX-ATAX is my newest project. I've been working on it for about 8 days so far, so I figured I should try to keep track of my development. I still have quite a lot to do. This is going to be a 4k game, but I'm confident that that won't be a limiting factor in this project. If you're curious why I think 4k will be plenty of room: Spoiler ---BITS!--- There's several places where I only need 1 bit: The player0 has four directions to move in, we can assign each one to a bit for four bits total. The player0's reflected property can be stored in one bit. Player1 needs a 1 bit flag for his missile's direction of movement and one bit to control it turning around when it reaches the edge of the sceen, we can use one bit per flag for a total of two bits. This adds up to seven bits, I put all seven bits in one variable, and made sure that single unused bit is being masked in all operations, so that unused bit can still be utilized for something else later. ---Shared sprite data--- Four of the five enemies have the same sprite, so I just have one copy of the sprite data and use an indexed loop to set the other three pointers to that one, saving a lot of bytes that would have been used by the three redundant sprites. ---Understanding NUSIZ and CTRLPF--- So I wasted time reverse-engineering the NUSIZ and CTRLPF options when all this information already exists somewhere online. Anyway, once I understood what each bit was being used for I found that using binary made it much easier to work with. Doesn't save much, just makes the work go by faster. ---ASM init's--- I've been rewriting all the variable inits to optimized ASM. Overall a lot of LDA's can be removed or changed to shifts and while each change is small it can add up. ---A world without BCD--- I've stripped every single BCD number out, in effect everywhere that used a BCD previously now uses a binary number which overall means a pretty big savings in bytes. ---Low cost logic--- I use things that have reliable values to drive multiple events, rather than waste by using a seperate variable for each action. On the title screen a single 1-byte counter is being used to fade in the title screen, play/stop playing a sound effect, and restrain the fire button at the same time. This same counter is being used in the main loop for an enemy respawn timer, to adjust the probability of player1 attacking, and to slow down the speed at which player0 takes damage at the same time. ---simple math only plz--- I take the time to make sure the math is simple... most of the numbers are divisable by two. Actual divison is used sparingly and always in powers of two. I use bit shifts. The same logic is applied to the vast majority of my comparisons, I focus on checking for zero or nonzero instead of comparing to numbers whenever possible. ---simplified AI--- I control one of the five enemies with one bit for it's AI. The other four enemies are controlled with one loop, with just a few lines of code outside of the loop to allow one of them to shoot missiles. So anyway, I've got the sprites displaying correctly, I have a good chunk of game logic in place, and at this point I'm up to ten screens and have 558b left. I am sure I can reclaim more bytes, and that i can fit plenty more in. I'll try to keep updating as things happen instead of as a retrospective. Edited December 25, 2020 by Sknarp added download links to top post 2 Quote Link to comment Share on other sites More sharing options...
Sknarp Posted July 23, 2019 Author Share Posted July 23, 2019 Reclaiming bytes via kernel 558b free Spoiler So in the previous post I mentioned that I had 558b free and that I was sure I could reclaim more. First off, that 558b was with the debugscore on, which uses 190 bytes more than no options, or 170 bytes more than the noscore option. So if I was to set it to const noscore=1 then I would have 728 (558+170) bytes free. I don't plan on using the score at all so that's the best I can do right? Well, not if we actually dig into the multisprite kernel and see that a lot of that space is being used for the score routines, which we don't need. After a bit of trial and error and a few extra STA WSYNCs, I was able to make a scoreless MSK. In total this saved 86 bytes! Free space: 814 (728+86) 814b free So that saved some bytes, but here's another idea, which DOES NOT save any bytes, but this shows how I went about testing it. Reclaiming bytes via RAM sprites Spoiler rem EXAMPLE ONE rem drawing an arrow to player0 sprite in ROM player0: %00000000 %00010000 %00111111 %11111111 %00111111 %00010000 %00000000 end rem EXAMPLE TWO rem using RAM s-y s=0 : y=0 : player0pointerhi=0 t=16 : x=16 u=63 : w=63 v=255 player0pointerlo = $E9 player0height=7 rem EXAMPLE THREE rem using ram s-y and in ASM asm lda #0 sta s sta y sta player0pointerhi lda #7 sta player0height lda #16 sta t sta x lda #63 sta u sta w lda #233 sta player0pointerlo lda #255 sta v end So the second and third example both work just as well as example one, and I was willing to remove "LDA #255" since it would have sped up the routine and would only have caused there to have been two dots in the middle of the arrow, I could live with that. The problem was simply that doing this doesn't save any ROM at all... I believe this is because of the images being stored as bytes that need to be page aligned, so this doesn't circumvent that requirement. I scrapped this idea because it's not useful in this application. Quote Link to comment Share on other sites More sharing options...
Sknarp Posted July 23, 2019 Author Share Posted July 23, 2019 Saved another 124 bytes by replacing 10 if-then statements with 1 on-goto and shortening labels in the part of the code that changes the playfields. This was something I had been meaning to do for a while, but got sidetracked with trickier optimizations. I still have to program the second game mode, win conditions, and reset switch support. Right now there are 10 screens (not counting the title), I'd like that number to be 20 or 30 so I have a lot more pixel drawing to do. Currently at 960b free. Title screen, shows how CTRLPF manipulation can be used to get around MSK limitations. Quote Link to comment Share on other sites More sharing options...
Sknarp Posted July 24, 2019 Author Share Posted July 24, 2019 Today's improvements: gave the sprites more character, freed up some RAM for a change. I managed to remove the final bit of the score routine, which was swapping around temps and scorepointers. This means lots of extra RAM: Spoiler $bf $c0 $c1 $c2 (C3 is playfieldpos) $c4 $c5 $c6 $c7 $c8 $c9 (CA to D0 are temps and vars used for player repositioning) $d1 $d2 $d3 13 variables that are unused (4 from not needing a minikernal, 6 from the scorepointers, and 3 from the score). I'm not sure if temp1,temp2 and temp6, temp7 are usable, but if they happen to be then the second chunk would be 8 spaces long instead of 6 and the third would be 5 long instead of 3. Contiguous space is always nice to have. Right now I'm only using variable a-i, that leaves j-z(17) and the freshly freed variables(13) for 30 free variables. I also took some time to make the sprites look a bit better. 1 Quote Link to comment Share on other sites More sharing options...
Sknarp Posted July 25, 2019 Author Share Posted July 25, 2019 Daily Progress Report: Kernel improvements, adding more playfields. Did some more editing of the MSK, moved some subroutines into the empty space previously occupied by the scorepointer routines, this saved an additional 22 bytes. Then I went into the scoregraphics, deleted all of the bytes used for drawing the numbers, and adjusted the ORG offset to save another 80 bytes that was being wasted defining the score digits 0-9 This puts the free space over 1K (960+22+80) 1062 bytes of ROM free. 30 bytes of RAM free. After adding a couple more playfields, I noticed that the last row the playfield was being printed twice. In the kernel there was a few STA PFx commands at the bottom that I had removed. When I put them back in, it fixed the double row issue- but it brought back a pretty common bug- there was a few pixels of extra playfield, 1 scanline high by about 1 pfpixel wide. I went back to the bottom of kernel and moved the PFx opcodes to the top of the list of STAs so they happened a few cycles earlier, and finally the bottom of the screen is totally clean. Adding two more playfields brought me down to 916b free - even though the playfield only uses 19 bytes of data there's an unfortunate amount of padding. I don't think I should devote any more time to trying to shave off bytes though, instead I'm just going to see how many playfields I can realistically fit in while still allowing myself a little bit of room for the game modes I have planned. Quote Link to comment Share on other sites More sharing options...
Sknarp Posted July 26, 2019 Author Share Posted July 26, 2019 It occurred to me that the "extra playfield pixels" I referenced in the last post could be re-purposed to do something useful. I had 40 cycles of free time at the bottom of the display kernel, I wrote a simple hack that uses 28 of those cycles to draw the contents of a variable to PF1, I chose the freed up "score" variable for this, added a little bit of code to the main loop and.... now I have an HP bar. The player's color was the only indicator of health before, going from bright yellow to dark yellow to signify shield, and bright white to dark grey to signify ship damage. I admit it was a little convoluted but it was the most efficient way of doing it I could think of at the time. Now there is an HP bar just below the bottom of the playfield so there is an additional indicator of remaining HP. The only issue with the way I implemented this is that there is a mirror/repeat of the HP bar on the right side. Please try the binary and tell me if this works, or if I should just remove it. Note: This is still a WIP so gameplay is not 100% implemented yet- but there's enough for you to play around with for the purposes of this test. WIP_AA_HPTEST.bin 1 Quote Link to comment Share on other sites More sharing options...
Sknarp Posted July 26, 2019 Author Share Posted July 26, 2019 (edited) Small fixes: I forgot to mention in the last update that I put a cap on the counter which controlled when the player could shoot- this fixed a glitch where sometimes you couldn't fire right away (because the counter had wrapped back to zero) After posting the binary, I also took another look at the title screen and decided that some of the letters looked too blocky, so minor edits to the title screen. The HP bar hack: One byte of RAM is used to be able to draw to 8 pfpixels right below the bottom of the normal playfield area. This was based on a suggestion I received to add a health bar. (This is the binary that I posted) After posting the binary, I then received another suggestion that the health bar should change colors, so I used one more byte of RAM to be able to change the color. Now I have an HP bar that goes from green (full HP) to yellow (when HP is below 45%) to flashing red (when HP is below 11%) This trick takes about 100 bytes to pull off, mostly because of the conditionals used to decrease the size and change colors of the bar, making it the least optimized part of the whole program. 916b of free ROM (with 12 screens) becomes 806b free. The 30 bytes of free RAM becomes 28 bytes. I'll have to really evaluate if this feature is worth the cost, but for now I'll leave it in until space gets crunched more- at which point I may either need to remove it or (hopefully) find a way to optimize the conditionals. Adding playfields Further changes since the last post. I added a couple more playfields, this brings it up to 14 playfields with 660b free. After looking at what I have so far, I shuffled the default order of the playfields around so that there's better continuity from one screen to the next. I still need to add a few more, then I can start programming in the different game modes. EDIT: I figured out how to draw the HP bar on ONLY the left side of the screen, but to do so I have to draw it as 2 scanlines tall instead of the 3 scanlines tall it is in the binary. Edited July 26, 2019 by Sknarp Quote Link to comment Share on other sites More sharing options...
Sknarp Posted July 27, 2019 Author Share Posted July 27, 2019 Player0 sprite: The player0 sprite wasn't completely centered, This was easy enough to fix Spoiler rem old sprite player0: %00000000 %00011111 %00111110 %01111100 %00111110 %00011111 %00000000 end rem new sprite player0: %00000000 %00011110 %00111100 %01111000 %00111100 %00011110 %00000000 end The sprite looks almost exactly the same during gameplay, but now won't be offset if you turn around in a tight area, this helps to ensure you won't get stuck in a wall. Kernel Timing I used something like 15 cycles where I had 12 to work with, there was always a bit of room to go a little over-cycle at this point in the kernel (I belive at least 10-20 over was the wiggle room), but I found that one of the opcodes was unneeded (STA PF0), so I removed it and should be cycle exact now. Two Week Progress Report Currently at 16 screens (not counting the title), and 528b free. I also still have 28 variables free. I am now 14 days into development of this game. I still have some time this evening so I might still get more done tonight. Quote Link to comment Share on other sites More sharing options...
Sknarp Posted July 28, 2019 Author Share Posted July 28, 2019 Switch Support & Game Modes When I was programming in the switch support I saved 4 bytes on every switch check by using bit checks instead of bB keywords Spoiler Instead of: if switchreset then goto title I use: if !SWCHB{0} then goto title Title screen now supports Select Switch as well as Fire. Main game now supports Reset Switch. Win Screen supports both the Select Switch and Reset Switch. Two game modes (LEFT "Difficulty" Switch) and Two difficulty settings (RIGHT "Difficulty" Switch): Quote LEFT Switch in B position: Default screen order, enemies respawn on a timer. (Auto Mode) LEFT Switch in A position: Random screen order, enemies all spawn at once and don't respawn until you change screen. (Random Mode) Both Modes: Kill a specific number of enemies to win RIGHT Switch in B position: Kill 100 Enemies To Win, HP restored every 25 (Easy Game) RIGHT Switch in A position: Kill 250 Enemies To Win, No HP restoration (Hard Game) Less than 150b left. Let me know if there are any game-breaking bugs I need to fix. New binary! Enjoy WIP_ATAX-ATAX_by_SKNARP.bin 3 Quote Link to comment Share on other sites More sharing options...
+Random Terrain Posted July 29, 2019 Share Posted July 29, 2019 Did you mean to have some of the enemies move in a jerky way? Some people use fixed point variables to have enemies move at different speeds while still moving smoothly. Quote Link to comment Share on other sites More sharing options...
Sknarp Posted July 29, 2019 Author Share Posted July 29, 2019 3 hours ago, Random Terrain said: Did you mean to have some of the enemies move in a jerky way? Some people use fixed point variables to have enemies move at different speeds while still moving smoothly. Is it their movement speed, or is the jerkiness happening when you are on the same Y as the enemy? If it's the later, I think it's a kernel-related issue that's over my head. Quote Link to comment Share on other sites More sharing options...
+Random Terrain Posted July 29, 2019 Share Posted July 29, 2019 2 hours ago, Sknarp said: Is it their movement speed, or is the jerkiness happening when you are on the same Y as the enemy? If it's the later, I think it's a kernel-related issue that's over my head. Move your ship to the bottom and stare at the bottom 3 enemies. The top two seem to be smooth, but those bottom 3 move a little, then stop a little, move some more, stop a little, and so on. Very jerky movement, at least on Stella. Quote Link to comment Share on other sites More sharing options...
Sknarp Posted July 29, 2019 Author Share Posted July 29, 2019 (edited) I tried to use FP, hung the compiler BAD - eventually got it to work, but it didn't actually have the desired effect because of decimal points being truncated when applied to an integer like x positions. Hanging the compiler (I assume) caused me to eventually be unable to compile any code- and also caused some sort of leak that was making my entire computer slow down. I was able to fix ability to compile by moving the most vital files to a new directory (The old directory will be deleted just to avoid that happening again) and the effects on my computer was mitigated by excessive swearing and a forced reboot. (I probably needed to do a fresh restart anyway, I'm lazy about those) At the moment I am not intending to use Fixed Point anything for anything I will still try tweaking the for loop to see if I can make it look more fluid Edited July 29, 2019 by Sknarp asdfasdfdsf Quote Link to comment Share on other sites More sharing options...
+Random Terrain Posted July 29, 2019 Share Posted July 29, 2019 You shouldn't be using any for-next loops for enemy movement, so that's probably where the problem with jerkiness is coming from. Does this fixed point variable example program compile for you: https://www.randomterrain.com/atari-2600-memories-batari-basic-commands.html#ex_fixed_point_sprite If it does, you were probably doing something wrong. It uses code like this: ;``````````````````````````````````````````````````````````` ; Player0 fixed point variables for more flexibility in ; gameplay mechanics. ; dim _P0_L_R = player0x.a dim _P0_U_D = player0y.b And this: _P0_L_R = _P0_L_R - 0.52 Quote Link to comment Share on other sites More sharing options...
Sknarp Posted July 30, 2019 Author Share Posted July 30, 2019 It's done to save on space, indexing the memory space of one player and incrementing the index/offset..It's probably better I just show the code rather than fail to explain it. If you want to compile this you'll need the modified includes in the same directory, otherwise there's not enough free space. WIPsourceAA.bas multisprite_kernel.asm score_graphics.asm Quote Link to comment Share on other sites More sharing options...
+Random Terrain Posted July 30, 2019 Share Posted July 30, 2019 While looking over the code, I reformatted the comments so it would help me keep track of where I was. I also changed some of the code here and there to save a few bytes or maybe even a few cycles. For example, I got rid of some redundant collision checks. I eventually saw that the "diceroll/32" skip in the for-next loop you used to slow down the enemies was the cause of the jerkiness, so I got rid of that and changed your enemies to fixed point so they now move smoother. If you keep it in, you can change the numbers to whatever speed you'd like. That for-next jerkiness is gone, but an enemy will still jerk whenever the player moves to the same horizontal position. That's because of the change you made to multisprite_kernel.asm. If you add more banks, you might want to get rid of your version of multisprite_kernel.asm and use the original. That will eliminate the weird jerkiness of the enemies whenever the player moves up and down. sknarp_2019y_07m_30d_0607t.bin sknarp_2019y_07m_30d_0607t.bas 3 Quote Link to comment Share on other sites More sharing options...
Sknarp Posted July 30, 2019 Author Share Posted July 30, 2019 Nice, added FP only using 74 bytes- most of which are if statements unfortunately but it might be well worth the cycles for sure. Could I ask a couple of questions about the opts you did? I noticed in the for loop for movement you used <> instead of typical equivalency (= or !=)- I couldn't find much information on if this has advantages- is it faster? Does it take less bytes? Also in the main loop you combined the collision checks, but on the win screen you separated out the switch checks, Which is better: using a bunch of &&'d ifs in one line or doing them as single checks over seperate lines? I really appreciate your help and input- your website is one of the main things I refer to when I am curious how to use a function of bB. 1 Quote Link to comment Share on other sites More sharing options...
+Random Terrain Posted July 30, 2019 Share Posted July 30, 2019 2 hours ago, Sknarp said: I noticed in the for loop for movement you used <> instead of typical equivalency (= or !=)- I couldn't find much information on if this has advantages- is it faster? Does it take less bytes? If you're talking about where I jump over the added if-thens with the fixed point movement, I had to reverse the condition: https://www.randomterrain.com/atari-2600-memories-batari-basic-commands.html#endif Quote Also in the main loop you combined the collision checks, but on the win screen you separated out the switch checks, Which is better: using a bunch of &&'d ifs in one line or doing them as single checks over separate lines? You had "if !SWCHB{0} || !SWCHB{1}" but the AND/OR/NOT Chart says that we can't use NOT with OR. I think you did that in a couple of places, so I separated them. Quote Link to comment Share on other sites More sharing options...
Sknarp Posted July 31, 2019 Author Share Posted July 31, 2019 Alright, so I went ahead and tested if <> has any advantage over !=, because I would love to know of any way to optimize- unfortunately it makes zero difference. In my tests of four conditonal checks using != vs the same four checks rewritten with <> instead, both sets of four checks take up exactly 32 bytes of ROM (8 bytes per conditional check) and take 64 cycles (16 cycles per) so it's just a matter of programmer's choice of style. I really don't understand why you're saying I can't write a conditional that uses a ! token and an || token... There's no reason as to why you can't in the linked page, and the "more information link" just brings you to another copy of the same warnings with again no explanation and a link back to the first verbatim warning. Also it does seem to work just fine, and even if the chart is accurate it says you can use OR with = and the condition if !varthis || !varthat is the same thing as saying if varthis=0 || varthat=0 so I'm really confused on WHY it would only work when written one way, Is there a source post somewhere that explains where the chart came from? Quote Link to comment Share on other sites More sharing options...
+Random Terrain Posted July 31, 2019 Share Posted July 31, 2019 It came from the creator of batari Basic. Some things that are not allowed will compile, but you can end up with weird problems later on and not know why. I sent a PM to someone to see if any of those things in the chart had been changed over time without telling the rest of us. It may take a few days to get a reply. I don't know if something changed, but we could only use <>. != wasn't an option. About OR and NOT, why can we only use one OR? Why can't we use AND and OR? It is (or was) the limitations of the language. After I get a reply, we might find out that some of those limitations no longer exist. If so, it would have been nice to have been told. 1 Quote Link to comment Share on other sites More sharing options...
Sknarp Posted July 31, 2019 Author Share Posted July 31, 2019 Thank you, that would be an awesome bit of information to have for sure. I've been using the syntax if !var1=var2 then a lot so if I need to change it to if var1<>var2 then it's not going to cost me any efficiency and I'll just adjust my style, but if it's safe to do it either way it's good to have the flexibility. As for using if !myvar then instead of if myvar=0 then I can't find the exact post right now but I'm positive I got the idea from some previous post on AA about space saving techniques, so it's important from an efficiency standpoint to know if you can't use ORs with the trick. I understand that it'll be a while before we get the definitive answer, I might just do a preemptive rewrite to be safe either way. Quote Link to comment Share on other sites More sharing options...
+Random Terrain Posted July 31, 2019 Share Posted July 31, 2019 I got a reply: Quote It looks to me like "if !a || !b then" returns reasonable results. So NOT seems to work with OR. The rest of the stuff seems true. I'll update the bB page. He also said this: Quote != isn't valid bB syntax. About using NOT, bit operations do not use an equal sign in if…then statements: https://www.randomterrain.com/atari-2600-memories-batari-basic-commands.html#bit I think someone once posted that "if !_Fried_Pickle then" is faster than ""if _Fried_Pickle = 0 then". I know for sure that the "= 0" version uses two extra bytes. 1 Quote Link to comment Share on other sites More sharing options...
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.