-Basti- wrote:
Code:
LatchController:
LDA #$01
STA $4016
LDA #$00
STA $4016 ; tell both the controllers to latch buttons
ReadA:
LDA $4016 ; player 1 - A
AND #%00000001 ; only look at bit 0
BEQ ReadADone ; branch to ReadADone if button is NOT pressed (0)
fire:
LDA sprite_RAM+68 ;$D8
SBC #$01
STA sprite_RAM+68
LDA sprite_RAM+68
CMP $50
BNE fire
ReadADone:
There are a couple of things wrong.
First, you are doing a subtraction with an unknown value in the carry flag, so your subtraction will sometimes subtract 1 (if the carry is set) and sometimes 2 (if the carry is clear). In the 6502, all additions and subtractions make use of the carry flag, so if you are not sure of it's value, you should clear it (CLC) before additions and set it (SEC) before subtractions. Since you could be accidentally subtracting 2 sometimes, that could cause the sprite to go past the point you are checking for (i.e., if you want it to reach position $50 but it goes straight from $51 to $4F without ever actually being $50).
Second, are you sure that line is supposed to be CMP $50? Because that will compare the accumulator with the byte at memory location $0050, not screen position $50. If you have the actual destination of the sprite stored at $0050, that's fine (although I'd suggest you always use variable names when referencing memory locations to avoid this sort of confusion), but if you want the sprite to move until position $50 you have to change that to CMP #$50.
Also, you are moving the sprite all at once. Your loop there will only finish when the sprite has moved all the way, so in the best case you'll see it magically teleport from the source to the destination when you hit the button.
Animation in video games consoles is frame-based. You have to move things little by little each frame, so that the user/player has a chance to see every step of the animation. Also, you can't get stuck in a loop moving a single object, because a game has many active objects at once doing different things and they all must appear to move at the same time.
The idea is that a part of your code, your main game loop, runs once per frame, at 60fps, and there you update all the active objects a little step at a time. So in your case it the main loop would look something like this:
1. check for input and skip to 3 if the button is not pressed;
2. move the sprite by 1 pixel;
3. wait for VBlank;
4. use a sprite DMA to update the positions of the sprites on the screen;
5. go back to 1;
The above will move the sprite whenever you press the button, as long as the button keeps pressed. If you want to press the button only once and move the sprite all the way, the could would look like this:
1. check for input and skip to 3 if the button is not pressed;
2. set a flag indicating that the sprite must move;
3. check the value of the flag and skip to 5 if it's clear;
4. if the sprite is not at the destination, move it;
5. wait for VBlank;
6. use a sprite DMA to update the positions of the sprites on the screen;
7. go back to 1;
In every game, the general structure of the main loop is:
1. check for input;
2. update the main character based on that input;
3. update the other objects (enemies, items, etc);
4. wait for vblank;
5. draw the frame;
6. go back to 1;
Note that all object updates are in very small steps. Each frame you move the objects according to their speed, check for collisions with other objects and things like that. But always
one step at a time, so that during VBlank you have the chance to show the state of the game to the user/player. If you move an object several steps without updating the screen every step, there will be no visible animation.
Don't wait for VBlank by polling $2002 though, that will cause you to miss some frames. Instead, make your NMI routine modify a flag, and have your main loop poll that flag instead. That way you will detect every VBlank.
I suggest you play with variations of the loop structures above to get acquainted with how game logic works. Does that make sense?