New Project

A place where you can keep others updated about your NES-related projects through screenshots, videos or information in general.

Moderator: Moderators

dsv101
Posts: 36
Joined: Fri Jun 17, 2011 5:16 am
Location: United States
Contact:

Post by dsv101 » Sat Jun 18, 2011 6:24 am

Lets wait until i have some gameplay before a creative name (that doenst have to do with anything sexual you freaks)!
~Yeah, I Said That

dsv101
Posts: 36
Joined: Fri Jun 17, 2011 5:16 am
Location: United States
Contact:

Post by dsv101 » Sat Jun 18, 2011 7:46 pm

Okay, so what i am looking to do is add shooting in to my game.

Checklist:
Store Bullet off screen (When A is not pressed) - Check :)
When A is pressed a variable is set to 1 and the bullets x = the players x - :(
If that var = 1, bullets y SBC #02 - :(
if bullet off screen, stop moving and set shooting var to 0 - :(

I guess my question here is how i can use the variable system here efficiently.

So far i can just figure out how to set a var

Code: Select all

.rsset $0000
shooting .rs 1 ;this reserves one bit to this var, correct?

User avatar
koitsu
Posts: 4218
Joined: Sun Sep 19, 2004 9:28 pm
Location: A world gone mad

Post by koitsu » Sun Jun 19, 2011 1:39 am

NESASM3 uses some very weird terminology for things. It really would help if you were using an assembler that the rest of the community commonly used (asm6, ca65, or qasm); it would make helping you a lot easier, and we wouldn't be fighting over assembler idiocy like this. :-)

I STRONGLY suggest avoiding using .RSSET and .RS. These pseudo-ops are confusing as hell; I've read the documentation (and its examples) 4 or 5 times now, and although I think I get it, they really don't make any sense. Awful awful awful.

Please use something like this instead:

Code: Select all

Snakes   = $0500   ; Number of snakes (8-bit)
Rocks    = $0501   ; Number of rocks  (16-bit)
Kites    = $0503   ; Number of kites  (8-bit)

.org $c000         ; Our program starts at $C000 in ROM (PRG)

; Variable initialisation

   lda #0          ; We don't want any kites
   sta Kites
   lda #8          ; We want 8 rocks (low byte of 16-bit value)
   sta Rocks
   lda #0          ; Upper byte of 16-bit value
   sta Rocks+1
   lda #$2a        ; We want 42 snakes
   sta Snakes

; Let's do something with Kites, which is easy since it's an
; 8-bit value

   lda Kites       ; Load number of kites (from $0503) into accumulator
   clc
   adc #4          ; Add 4 to it (so we should now have 4 kites)
   sta Kites       ; ...and store it back in $0503
Let's talk about the Kites stuff first. Sure, adding 4 to Kites works fine, because we're adding 4 to 0, which makes 4. But what if Kites had been initialised with value 254 and we wanted to add 4 to that (258 kites)? We'd have a big problem.

254 + 4 = 258. But an 8-bit value can only hold from 0 to 255... so guess what gets written to Kites in that case? 258-256 = 2. You expected 258 kites, but you suddenly have 2.

Welcome to 6502 and 8-bit architectures! :-)

If you actually want to see or validate this in real-time, you can do so by using the virtual 6502 simulator over at 6502asm.com. Put this code into the text box, compile it, then run it. You'll see a dark red dot in the middle of the screen (dark red = $02). Try messing around with the initialisation value for Kites to see what happens.

Code: Select all

; Initialisation

init:
lda #254
sta Kites

lda Kites
clc
adc #4
sta Kites

; Show results in middle of screen as a pixel
; colour ANDed with $0F (see Help)
sta $3EF

; Infinitely loop
jmp init

Kites: dcb 0
Next, note that I explicitly did not mess with Rocks here, meaning I did not show how to, say, add 455 rocks to the existing value. The reason is that working with 16-bit values is a little tricky on the 6502 since all registers are 8-bit. You have to "split up" a 16-bit value into two 8-bit portions and handle them/treat them separately.

In the case of the initialisation routine, for example, if we wanted to have 378 rocks instead of just 8, we'd have done this instead:

Code: Select all

   lda #122         ; We want 378 rocks, so store 122 (378-256) in the low byte
   sta Rocks
   lda #1          ; ...and store 1 (e.g. 256) in the upper byte
   sta Rocks+1
This might be an easier way of looking at it:

Decimal value 378 is written $17A in hexadecimal -- or, to pad things out, written as $017A in hexadecimal. The "lower byte" (e.g. Rocks) would therefore be $7A, and the "upper byte" (e.g. Rocks+1) would therefore be $01.

Doing real-time (e.g. not static/pre-calculated numbers) 16-bit arithmetic gets a little tricky at times, but you'll have to learn that as you go.

My advice right now: try to keep everything within 8 bits (range 0 to 255) if you can. It'll make learning a lot easier. When I say "everything", I mean your counters/variables (number of lives, ships, X/Y offsets, etc.). You're still learning, so keep it simple. :-)

dsv101
Posts: 36
Joined: Fri Jun 17, 2011 5:16 am
Location: United States
Contact:

Post by dsv101 » Sun Jun 19, 2011 10:11 am

thanks man, for this game i am probably keeping everything 4 bit or 1 bit because that is all i will probably need.

now i just have to figure out how to compare values which wont be to hard :)
~Yeah, I Said That

User avatar
tokumaru
Posts: 11869
Joined: Sat Feb 12, 2005 9:43 pm
Location: Rio de Janeiro - Brazil

Post by tokumaru » Sun Jun 19, 2011 10:25 am

koitsu wrote:

Code: Select all

Snakes   = $0500   ; Number of snakes (8-bit)
Rocks    = $0501   ; Number of rocks  (16-bit)
Kites    = $0503   ; Number of kites  (8-bit)
Sorry, but I have to disagree. Declaring variables like this is fine in small programs, but once your games get complex and you have hundreds of variables this is hell to manage. Every time you need to move variables around (and you will need to do this a few times during development, I assure you) you'll have to manually change hundreds of addresses. Not cool. Not to mention that it's really easy to make mistakes and end up with overlapping variables.

Really, what dsv101 used in his example is much better. He can just reserve bytes starting from a base address, guaranteeing that no variables will overlap, and if he wants to rearrange some variables he can just copy/paste them and be done with it.

User avatar
thefox
Posts: 3141
Joined: Mon Jan 03, 2005 10:36 am
Location: Tampere, Finland
Contact:

Post by thefox » Sun Jun 19, 2011 10:35 am

koitsu wrote:I STRONGLY suggest avoiding using .RSSET and .RS. These pseudo-ops are confusing as hell; I've read the documentation (and its examples) 4 or 5 times now, and although I think I get it, they really don't make any sense. Awful awful awful.
Not really true (if I'm not misunderstanding how to use .rsset and .rs -- it has been ~5 years ago since the last time I used NESASM...)

Your example would be something like this when using .rs:

Code: Select all

  .rsset $500
Snakes .rs 1
Rocks  .rs 2
Kites  .rs 1
This is better because now it's much easier to move stuff around or change variable sizes.

User avatar
Dwedit
Posts: 4356
Joined: Fri Nov 19, 2004 7:35 pm
Contact:

Post by Dwedit » Sun Jun 19, 2011 10:43 am

Seems like .reset is equivalent to ASM6's .enum feature, but I think the .enum feature is more clever in how it works.
Here come the fortune cookies! Here come the fortune cookies! They're wearing paper hats!

dsv101
Posts: 36
Joined: Fri Jun 17, 2011 5:16 am
Location: United States
Contact:

Post by dsv101 » Sun Jun 19, 2011 10:43 am

that was my only concern with what he mentioned, if i reserve bytes to a variable, i will have no problems later. But what is the instruction to compare vars?

i pretty much have to do an IF then statement in 6502 ASM

Like:

Code: Select all

ReadA:
  LDA $4016
  AND #%00000001
  BEQ ReadADone

   if shooting = $00   ;how would i do this typoe of line in 6502 ASM?   

   LDA #$01
   STA shooting

ReadADone:

Code: Select all

If shooting = $01 then 

LDA $0207
CLC
ADC #$01
STA $0207
and also

Code: Select all

if $0207 < $00

LDA #$00
STA shooting
[/code]

User avatar
Dwedit
Posts: 4356
Joined: Fri Nov 19, 2004 7:35 pm
Contact:

Post by Dwedit » Sun Jun 19, 2011 10:48 am

You use CMP to compare. CMP is a subtract operation that does not change A. There's also CPX and CPY instructions available, which compare X or Y against a constant value, or a value in memory.

When A == byte, the result of the subtraction is Zero. So that sets the Zero flag, and BEQ (branch if equal) is the instruction you use to branch when Zero is set.

When A >= Byte, carry flag is set, use BCS (branch carry set)
When A < Byte, carry flag is clear, use BCC (branch carry clear)
When A != Byte, zero flag is clear, use BNE (branch not equal)
Here come the fortune cookies! Here come the fortune cookies! They're wearing paper hats!

dsv101
Posts: 36
Joined: Fri Jun 17, 2011 5:16 am
Location: United States
Contact:

Post by dsv101 » Sun Jun 19, 2011 10:55 am

that should do the trick, ill make a post if i have any more problems related to variables in the near future
~Yeah, I Said That

dsv101
Posts: 36
Joined: Fri Jun 17, 2011 5:16 am
Location: United States
Contact:

Post by dsv101 » Sun Jun 19, 2011 11:08 am

lol, its the near future. can you show me some example code please

something under A's push action like

If A then

LDA #$01
STA shooting

else

LDA #$00
STA shooting
~Yeah, I Said That

User avatar
tokumaru
Posts: 11869
Joined: Sat Feb 12, 2005 9:43 pm
Location: Rio de Janeiro - Brazil

Post by tokumaru » Sun Jun 19, 2011 12:34 pm

Do you know how to read the controller? When you read the controller, you typically end up with a variable that contains the state of all the buttons (each bit is a button). What you need to do is look at a specific bit in this variable (the bit that corresponds to the button you want to check) and make a decision based on it. Something like this:

Code: Select all

	lda ControllerState
	and #%00000001 ;<- change this depending on the button you want to check
	beq ButtonNotPressed
	
	;BUTTON IS PRESSED

	jmp Done ;<- this is needed to skip over the "not pressed" code

ButtonNotPressed:

	;BUTTON IS NOT PRESSED

Done:
This is the basic structure of an "IF" in assembly, but the beuty of assembly is that you are not restricted to these basic structures, and you can take shortcuts. In this particular case, you could do something like this:

Code: Select all

	ldx #$00 ;assume "Shooting" will be 0
	lda ControllerState
	and #BUTTON_A ;I'm using a constant here
	beq StoreShooting ;branch if it really is supposed to be 0
	inx ;A is pressed, so "Shooting" needs to be 1
StoreShooting:
	stx Shooting
Last edited by tokumaru on Sun Jun 19, 2011 12:41 pm, edited 1 time in total.

dsv101
Posts: 36
Joined: Fri Jun 17, 2011 5:16 am
Location: United States
Contact:

Post by dsv101 » Sun Jun 19, 2011 12:35 pm

lol, i got reading the controller down already, i was just typing If a to type less :)
~Yeah, I Said That

dsv101
Posts: 36
Joined: Fri Jun 17, 2011 5:16 am
Location: United States
Contact:

Post by dsv101 » Sun Jun 19, 2011 12:38 pm

do you know how to do what i asked though?
~Yeah, I Said That

User avatar
tokumaru
Posts: 11869
Joined: Sat Feb 12, 2005 9:43 pm
Location: Rio de Janeiro - Brazil

Post by tokumaru » Sun Jun 19, 2011 12:41 pm

I edited my post with more useful info.

Post Reply