AES Atlas: Earth's Last Hope (AKA weird twin-stick-shooter-ish game)

MistSonata

Moderator
So, I've spent a few days working on this, and I'm actually really super proud of it. This is a new game that I'm working on called AES Atlas: Earth's Last Hope. A while ago I posted an image of a screen I made in NESmaker, and while I wasn't planning anything around it at the time, Joe asked me if I was going to do something with it because he was interested in showcasing it in a video (I think?).

HWtXHOq.png


And I turned that into this:

A53FCNe.png


So, I thought it might be cool to have a little shooter game where you save the earth from some kind of extraterrestrial threat or something (haven't thought it through yet). But the movement scripts that come with the beta require that you move in a direction to face that direction, and I was already learning more about assembly so I was eager to try some things out. I had the idea to separate the direction the ship faces with the actual movement, and it took hours to get right, but I did it. In this game, the directional buttons only affect which direction your facing, and pressing the B button will propel you forward in whatever direction you're facing. You can also press the A button to fire a projectile! I'll post my scripts and settings here soon in case any of you want to try it out.

Here's a video of the game in action so far.

You can also download the rom below and try it out for yourself! There aren't any enemies or win/lose states yet (or even music), but it's still kind of fun to glide around and shoot all over the place.

By the way! If any of you crazy awesome music makers are feeling generous, this game could use some kickass music and sound effects (for when that's available). I'd also love some ideas on what kind of enemies to make (because right now I'm a bit stumped).
 

Attachments

  • AES_Atlas (0_00w).rar
    13.4 KB · Views: 139

MistSonata

Moderator
DumbDirectionChange.asm
Code:
DumbDirectionChange:
    ;; "if it's dumb but it works, it's not dumb"
    ;; now if only it would work...
    
    ;;; Object_movement
    ;; 0 0 0 0 0 0 0 0
    ;;           x x x
    ;            0 0 0 = down
    ;            0 0 1 = down right
    ;            0 1 0 = right
    ;            0 1 1 = up right
    ;            1 0 0 = up
    ;            1 0 1 = up left
    ;            1 1 0 = left
    ;            1 1 1 = down left
    
    


    LDA gamepad
    AND #%11110000
    BNE updateDirection
    
    RTS
    
    updateDirection:
    
    ;LDA gamepad
    
    CMP #%10010000 ;; check if upright is pressed
    BEQ faceDirUpRight
    CMP #%10100000 ;;check if downright is pressed
    BEQ faceDirDownRight
    CMP #%01010000 ;;check if upleft is pressed
    BEQ faceDirUpLeft
    CMP #%01100000 ;;check if downleft is pressed
    BEQ faceDirDownLeft
   
    CMP #%00010000 ;; check if up is pressed
    BEQ faceDirUp
    CMP #%00100000 ;;check if down is pressed
    BEQ faceDirDown
    CMP #%01000000 ;;check if left is pressed
    BEQ faceDirLeft
    CMP #%10000000 ;;check if right is pressed
    BEQ faceDirRight
    
    RTS ;; If there's no dpad press, why are you here anyway? shoo!
    
    faceDirUpRight:
    
    LDX player1_object
    LDA Object_movement,x
    AND #%11111000
    ORA      #%011
    STA Object_movement,x
    
    RTS
    
    faceDirUpLeft:
    
    LDX player1_object
    LDA Object_movement,x
    AND #%11111000
    ORA      #%101
    STA Object_movement,x
    
    RTS
    
    faceDirDownRight:
    
    LDX player1_object
    LDA Object_movement,x
    AND #%11111000
    ORA      #%001
    STA Object_movement,x
    
    RTS
    
    faceDirDownLeft:
    
    LDX player1_object
    LDA Object_movement,x
    AND #%11111000
    ORA      #%111
    STA Object_movement,x
    
    RTS
    
    faceDirUp:
    
    
    LDX player1_object
    LDA Object_movement,x
    AND #%11111000
    ORA      #%100
    STA Object_movement,x
    
    RTS
    
    faceDirDown:
    
    
    LDX player1_object
    LDA Object_movement,x
    AND #%11111000
    STA Object_movement,x
    
    RTS
    
    faceDirLeft:
    
    LDX player1_object
    LDA Object_movement,x
    AND #%11111000
    ORA      #%110
    STA Object_movement,x
    
    RTS
    
    faceDirRight:
    
    LDX player1_object
    LDA Object_movement,x
    AND #%11111000
    ORA      #%010
    STA Object_movement,x
    
    RTS



testingpropulsion.asm
Code:
Propulsion:

    LDA gamepad ;check if b is pressed, otherwise no propulsion
    AND #%00000001 
    BNE updatePropulsion
    RTS
    
    updatePropulsion:

    LDX player1_object
    LDA Object_movement,x
    AND #%01 ;; check if facing diagonal
    BNE moveDiagonal
    
    ;; move4directions
    LDA Object_movement,x
    AND #%00000110
    CMP #%000
    BEQ moveDown
    CMP #%010
    BEQ moveRight
    CMP #%100
    BEQ moveUp
    CMP #%110
    BEQ moveLeft
    
    RTS
    
    moveDiagonal:
    
    LDA Object_movement,x
    AND #%00000111
    CMP #%001
    BEQ moveDownRight
    CMP #%011
    BEQ moveUpRight
    CMP #%101
    BEQ moveUpLeft
    CMP #%111
    BEQ moveDownLeft
    
    RTS
    
    ;; ORA!ORA!ORA!ORA!ORA!ORA!ORA!ORA!ORA!ORA!ORA!ORA!ORA!ORA!ORA!ORA!ORA!ORA!ORA!ORA!ORA!
    ;; ORA!ORA!ORA!ORA!ORA!ORA!ORA!ORA!ORA!ORA!ORA!ORA!ORA!ORA!ORA!ORA!ORA!ORA!ORA!ORA!ORA!
    ;; ORA!ORA!ORA!ORA!ORA!ORA!ORA!ORA!ORA!ORA!ORA!ORA!ORA!ORA!ORA!ORA!ORA!ORA!ORA!ORA!ORA!
    ;; ORA!ORA!ORA!ORA!ORA!ORA!ORA!ORA!ORA!ORA!ORA!ORA!ORA!ORA!ORA!ORA!ORA!ORA!ORA!ORA!ORA!
    ;; ORA!ORA!ORA!ORA!ORA!ORA!ORA!ORA!ORA!ORA!ORA!ORA!ORA!ORA!ORA!ORA!ORA!ORA!ORA!ORA!ORA!
    ;; ORA!ORA!ORA!ORA!ORA!ORA!ORA!ORA!ORA!ORA!ORA!ORA!ORA!ORA!ORA!ORA!ORA!ORA!ORA!ORA!ORA!
    
    moveUp:
    ORA #%00100000
    STA Object_movement,x
    RTS
    
    moveDown:
    ORA #%00110000
    STA Object_movement,x
    RTS
    
    moveLeft:
    ORA #%10000000
    STA Object_movement,x
    RTS
    
    moveRight:
    ORA #%11000000
    STA Object_movement,x
    RTS
    
    moveDownRight:
    ORA #%11110000
    STA Object_movement,x
    RTS
    
    moveUpRight:
    ORA #%11100000
    STA Object_movement,x
    RTS
    
    moveUpLeft:
    ORA #%10100000
    STA Object_movement,x
    RTS
    
    moveDownLeft:
    ORA #%10110000
    STA Object_movement,x
    RTS
    
    
    ;; 「 や れ や れ だ ぜ . . . 」



releaseupdate.asm
Code:
ReleaseUpdate:

    LDX player1_object
    LDA Object_movement,x
    AND #%00000111
    ;ORA #%00011000
    STA Object_movement,x
    RTS

And here's a screenshot of the input manager, and how the buttons are mapped to the scripts

BtQocpr.png


By the way.. For some reason, the game will glitch out if you don't have all the movement scripts from the UserScripts\MovementScripts\ folder in your Code Scripts. Not sure why, but if you get the same problem, just load those scripts into NESmaker.

Feel free to use this stuff or suggest changes to the scripts I have here. I'm basically a beginner to 6502 so I'm sure there's some things I've missed.

And for those of you who are curious this took about 12-ish hours from start to finish. 8 of which were spent tearing my hair out trying to figure out which bytes do what or why the ship wouldn't face diagonally. :p
 

dale_coop

Moderator
Staff member
Oh wow, twin stick shooter! Very nice job :) The graphics are very good.
Sad, I couldn't shoot some alien spaceships in this demo... :p
Hope I will able, next time <3 Can't wait to see more.
 

Mihoshi20

Member
Very impressive use of the limited colors to make such a diverse title screen and seeing diagonal movement is always a work of wonder.

Also seems that the ship won't fire diagonally up left but will in all other diagonal directions.
 

CutterCross

Active member
*Does backflips over rows of chairs and tables* Did someone say something about needing kickass MUSIC?

Lol I'm just joking XD but I do offer commissions for NES music! If you haven't already you can check out my work here: https://www.youtube.com/channel/UCHXqT6BNFn46mvIeCKDz6PA
 

MistSonata

Moderator
You're all very kind. :)

Mihoshi20 said:
Also seems that the ship won't fire diagonally up left but will in all other diagonal directions.

No, you can shoot diagonally up left, it's just that the engine spawns projectiles at the top left corner of the object it's coming from, and if you're too close to a solid object, it'll collide with it before really appearing.
 

Mihoshi20

Member
MistSonata said:
You're all very kind. :)

Mihoshi20 said:
Also seems that the ship won't fire diagonally up left but will in all other diagonal directions.

No, you can shoot diagonally up left, it's just that the engine spawns projectiles at the top left corner of the object it's coming from, and if you're too close to a solid object, it'll collide with it before really appearing.

Interesting. I've been tinkering around in the asm also and partially gotten ChangeObjectState to work so it'll do the idle to movement animation switching but if add to too many directions I start hitting branch out of range walls. Wondering if you also ran into this which i suspect is either an issue with the engine or the bank the code lives in out of space.
 

MistSonata

Moderator
Mihoshi20 said:
Interesting. I've been tinkering around in the asm also and partially gotten ChangeObjectState to work so it'll do the idle to movement animation switching but if add to too many directions I start hitting branch out of range walls. Wondering if you also ran into this which i suspect is either an issue with the engine or the bank the code lives in out of space.

I have no idea. I barely understand how the scripts I made work, and I'm the one who wrote them.

I did run into the same out or range issue in my asm code, but it was close enough to within range that I just needed to do a small amount of rearranging. Maybe try that?
 

Mihoshi20

Member
MistSonata said:
Mihoshi20 said:
Interesting. I've been tinkering around in the asm also and partially gotten ChangeObjectState to work so it'll do the idle to movement animation switching but if add to too many directions I start hitting branch out of range walls. Wondering if you also ran into this which i suspect is either an issue with the engine or the bank the code lives in out of space.

I have no idea. I barely understand how the scripts I made work, and I'm the one who wrote them.

I did run into the same out or range issue in my asm code, but it was close enough to within range that I just needed to do a small amount of rearranging. Maybe try that?

Fair enough. I'll probably do some poking around around and testing and see if I can figure out what's causing the issue and a quick fix for it. Probably also cross reference with Joe's code too as I'm using your DumbDiretionChange and testingpropulsion files but using the default button release code. I also commented out the need to check if a button is pressed before moving as I didn't need that function. It works relatively well. Still a bit of 'moonwalking' sometimes and I think diagonal movement is slightly faster. But all in all it's great to have some form of diagonal movement as that's what my game was designed for.
 

dale_coop

Moderator
Staff member
Yeah, congrats. It’s not easy to code in ASM, and the code can be tricky sometimes (often).
But ORA! ;) you did it.

Yesterday I fought for hours with some code I wanted to write, but at last, I gave up. My code was not working.
My brain doesn’t think ASM, need more practice
 

Mihoshi20

Member
I see what's going on now, which is even more interesting as you've worked around either a limitation in the tool which treats a press of Down Left as a Down or Left press which is a little annoying. But I did manage to get the movement and idle animation toggle to work.

In DumbDirectionChange.asm under DumbDirectionChange: near the very top of the file simply type ChangeObjectState #$01 right before the commented out section talking about Object_movement.

Same goes for releaseupdate.asm place ChangeObjectState #$00 directly under ReleaseUpdate:

This should re-enable the switching between idle animations and movement animations.
 

RadJunk

Administrator
Staff member
This is all amazing! :)

Just also wanted to give you at least one branch out of range fix! (there are multiple ways to fix this)

Ok, so let's say you have a code, and it looks like this:

Code:
      LDA someVariable ;; check the state of some variable
      CMP temp ;;; compare the value to some variable.
      BEQ skipAllTheCode ;;; if it equals the variable, skip all the code
      ;;;;;; if you're here, it means you DIDN'T skip the code.
      ;;;; do a bunch of things.
      LDA #$00
      STA something
      JSR doAlotOfThings
      RTS
skipAllTheCode:
      ;; bypassed all of those a lot of things
      RTS


That will work fine. BUT, the position counter can't branch across a page (256 values beyond its current position in the code) using this method. So, for instance, this might be a problem...

Code:
      LDA someVariable ;; check the state of some variable
      CMP temp ;;; compare the value to some variable.
      BEQ skipAllTheCode ;;; if it equals the variable, skip all the code
      ;;;;;; if you're here, it means you DIDN'T skip the code.
      ;;;; do a bunch of things.
      LDA #$00
      STA something
      JSR doAlotOfThings
      ;;;; a hundred other lines of code
      ;;;; two hundred lines of code...
      ;; now skipAllTheCode is FURTHER than the above BEQ can jump....thus, you get a branch out of range issue....
      RTS
skipAllTheCode:
      ;; bypassed all of those a lot of things
      RTS


If something like this is the culprit and you need to fix it, here's an easy fix! Since the JMP command CAN jump beyond a page, you can INVERT the branch...like this:

Code:
      LDA someVariable ;; check the state of some variable
      CMP temp ;;; compare the value to some variable.
 ;;;;===================================
      ;;;; INVERT THE BRANCH HERE...instead of checking if it's equal, check if it's NOT equal...
      BNE DONTskipAllTheCode ;; if it's NOT equal, you DO want to do the code...so we'll make a label where that code starts....
      JMP skipAllTheCode ;;; so now this means if it IS equal, in which case we want to JUMP to that label, which doesn't have the single code page limit.
 DONTskipAllTheCode: ;; this label now represents what happens if that variable was NOT zero.
 ;;;;==================================
      ;;;;;; if you're here, it means you DIDN'T skip the code.
      ;;;; do a bunch of things.
      LDA #$00
      STA something
      JSR doAlotOfThings
      ;;;; a hundred other lines of code
      ;;;; two hundred lines of code...
      ;; now skipAllTheCode is FURTHER than the above BEQ can jump....thus, you get a branch out of range issue....
      RTS
skipAllTheCode:
      ;; bypassed all of those a lot of things
      RTS


That may fix the problem. As you add code to the middle of existing code, this tends to happen often. Does this make sense?
 

Mihoshi20

Member
TheNew8bitHeroes said:
This is all amazing! :)

Just also wanted to give you at least one branch out of range fix! (there are multiple ways to fix this)

Ok, so let's say you have a code, and it looks like this:

Code:
      LDA someVariable ;; check the state of some variable
      CMP temp ;;; compare the value to some variable.
      BEQ skipAllTheCode ;;; if it equals the variable, skip all the code
      ;;;;;; if you're here, it means you DIDN'T skip the code.
      ;;;; do a bunch of things.
      LDA #$00
      STA something
      JSR doAlotOfThings
      RTS
skipAllTheCode:
      ;; bypassed all of those a lot of things
      RTS


That will work fine. BUT, the position counter can't branch across a page (256 values beyond its current position in the code) using this method. So, for instance, this might be a problem...

Code:
      LDA someVariable ;; check the state of some variable
      CMP temp ;;; compare the value to some variable.
      BEQ skipAllTheCode ;;; if it equals the variable, skip all the code
      ;;;;;; if you're here, it means you DIDN'T skip the code.
      ;;;; do a bunch of things.
      LDA #$00
      STA something
      JSR doAlotOfThings
      ;;;; a hundred other lines of code
      ;;;; two hundred lines of code...
      ;; now skipAllTheCode is FURTHER than the above BEQ can jump....thus, you get a branch out of range issue....
      RTS
skipAllTheCode:
      ;; bypassed all of those a lot of things
      RTS


If something like this is the culprit and you need to fix it, here's an easy fix! Since the JMP command CAN jump beyond a page, you can INVERT the branch...like this:

Code:
      LDA someVariable ;; check the state of some variable
      CMP temp ;;; compare the value to some variable.
 ;;;;===================================
      ;;;; INVERT THE BRANCH HERE...instead of checking if it's equal, check if it's NOT equal...
      BNE DONTskipAllTheCode ;; if it's NOT equal, you DO want to do the code...so we'll make a label where that code starts....
      JMP skipAllTheCode ;;; so now this means if it IS equal, in which case we want to JUMP to that label, which doesn't have the single code page limit.
 DONTskipAllTheCode: ;; this label now represents what happens if that variable was NOT zero.
 ;;;;==================================
      ;;;;;; if you're here, it means you DIDN'T skip the code.
      ;;;; do a bunch of things.
      LDA #$00
      STA something
      JSR doAlotOfThings
      ;;;; a hundred other lines of code
      ;;;; two hundred lines of code...
      ;; now skipAllTheCode is FURTHER than the above BEQ can jump....thus, you get a branch out of range issue....
      RTS
skipAllTheCode:
      ;; bypassed all of those a lot of things
      RTS


That may fix the problem. As you add code to the middle of existing code, this tends to happen often. Does this make sense?

Hmm, interesting and really good to know and to keep in mind when diving into the code. I can't recall the exact terminology for the CPU time it takes to execute a line of asm code but I imagine when you say the countercan't go over 256 you're meaning that. Luckily though an easy implementation could be found that worked as before I was trying to add it to each direction check which I'm glad didn't work as it would have massively bloated the code and CPU cycles. But it's still good to get familiar with the NES' quirks as I'm really not used to at all working this close to the hardware and without an OS middleman. It's been a really fun exercise all around.
 
Top Bottom