It is currently Thu Nov 23, 2017 4:08 am

All times are UTC - 7 hours





Post new topic Reply to topic  [ 1386 posts ]  Go to page Previous  1 ... 16, 17, 18, 19, 20, 21, 22 ... 93  Next
Author Message
 Post subject:
PostPosted: Wed Aug 31, 2011 2:24 pm 
Offline
User avatar

Joined: Thu Apr 23, 2009 11:21 pm
Posts: 803
Location: cypress, texas
here is code from the scrolling tutorial
Code:
NTSwapCheck:
  LDA scroll       ; check if the scroll just wrapped from 255 to 0
  BNE NTSwapCheckDone  ;if not, skip this NameTable Swap
 
NTSwap:
  LDA currNameTable    ; load current nametable number (0 or 1)
  EOR #$01         ; exclusive OR of bit 0 will flip that bit
  STA currNameTable    ; so if nametable was 0, now 1
                   ;    if nametable was 1, now 0
  inc CameraX+1
 
NTSwapCheckDone:

  LDA #$00
  STA $2003       


And I added the inc CameraX+1. After starting our game and then waiting for a while CameraX+1 becomes very incremented. That isn't good. If our character waits at the beginning of "the game" the scroll variable stays at 0. So each time it runs through this code it changes currNameTable... that's not good either, right? I'm unsure of changing the code because there may be a reason that bunnyboy kept it like this. :? Do you have a helpfull idea?

edit: And what if during the game one person stops traveling with scroll at exactly 0 and waits for a bit? It would mess up the same way, I think. :(


Last edited by unregistered on Wed Aug 31, 2011 3:06 pm, edited 1 time in total.

Top
 Profile  
 
 Post subject:
PostPosted: Wed Aug 31, 2011 3:01 pm 
Online
User avatar

Joined: Sat Feb 12, 2005 9:43 pm
Posts: 10118
Location: Rio de Janeiro - Brazil
That code is terrible. The camera can only move 1 pixel at a time (otherwise you might miss the 0 that triggers the nametable switch), and the person who wrote it failed to realize that you don't need any sort of special checks to switch nametables: the lowest bit of CameraX+1 (i.e. the 9th bit of the overall coordinate) tells you which name table to display.

You can do something like this:
Code:
   lda currNameTable
   and #$fe ;clear the lowest bit
   sta currNameTable

   lda CameraX+1 ;get the high byte of the camera
   and #$01 ;keep only the lowest bit
   ora currNameTable ;combine with the other value
   sta currNameTable ;this is what you'll write to $2000 when setting the scroll


And the low byte of CameraX (CameraX+0 or simply CameraX - I like the "+0" because it helps me identify multi-byte variables, even though in practice adding 0 is useless) is what you'll write to $2005 when setting the X scroll. There's no need for a "scroll" variable.

That way you can modify CameraX anyway you want, no need to change it pixel by pixel, which mean your character can move faster if you want.


Top
 Profile  
 
 Post subject:
PostPosted: Wed Aug 31, 2011 9:20 pm 
Offline
User avatar

Joined: Thu Apr 23, 2009 11:21 pm
Posts: 803
Location: cypress, texas
tokumaru wrote:
Code:
   lda currNameTable
   and #$fe ;clear the lowest bit
   sta currNameTable


Does currNameTable ever have a value other than 0 or 1? :)
After this code is run currNameTable is always 0 right?

tokumaru wrote:
Code:
   lda CameraX+1 ;get the high byte of the camera
   and #$01 ;keep only the lowest bit
   ora currNameTable ;combine with the other value
   sta currNameTable ;this is what you'll write to $2000 when setting the scroll


What do you mean ora currNameTable to say? X OR False == X ? :)


Last edited by unregistered on Wed Aug 31, 2011 9:41 pm, edited 1 time in total.

Top
 Profile  
 
 Post subject:
PostPosted: Wed Aug 31, 2011 9:40 pm 
Online
User avatar

Joined: Sat Feb 12, 2005 9:43 pm
Posts: 10118
Location: Rio de Janeiro - Brazil
unregistered wrote:
Does currNameTable ever have a value other than 0 or 1? :)

Heh, I don't know, I haven't seen the rest of the code. Even if the name suggests it only specifies a nametable, I assumed it was the value that's written to $2000 (the lower 2 bits select the nametable, while the upper bits do other things).

Quote:
After this code is run currNameTable is always 0 right?

The purpose is to clear bit 0, but keep all the others.

tokumaru wrote:
Is the ora currNameTable a waste? X OR False == X ? :) (I'm sorry, this is me asking stupid questions.) :?

OR can be used to set bits. First I cleared the bit (AND 0 always results in 0) and then I OR'ed it with the nametable bit. 0 OR 0 = 0, while 0 OR 1 = 1, so I essentially transferred the bit from one variable (CameraX+1) to the other (currNameTable).

You can do this in many different ways, but the code I wrote is more "compatible" with the one you had before, so I thought it would be easier for you to understand. Honestly I'd rather just do this to set the scroll:

Code:
   lda CameraX+1
   and #$01 ;keep only the first bit
   ora Cur2000Settings ;combine with the other PPU settings
   sta $2000
   lda CameraX+0
   sta $2005 ;set the horizontal scroll
   lda #$00
   sta $2005 ;set the vertical scroll

This takes care of everything. You just have to put all your $2000 configuration in "Cur2000Settings" and keep the lowest bit clear.


Top
 Profile  
 
 Post subject:
PostPosted: Wed Aug 31, 2011 10:09 pm 
Offline
User avatar

Joined: Thu Apr 23, 2009 11:21 pm
Posts: 803
Location: cypress, texas
I'm sorry for saying some of the code that you spent valuable time typing out for me was a waste. My sister helped me understand my mistake but I asked her too late. Ok. Thank you for your response tokumaru. Have a good night. :)


Top
 Profile  
 
 Post subject:
PostPosted: Thu Sep 01, 2011 5:55 am 
Online
User avatar

Joined: Sat Feb 12, 2005 9:43 pm
Posts: 10118
Location: Rio de Janeiro - Brazil
Maybe you should have your sister code the game then! XD


Top
 Profile  
 
 Post subject:
PostPosted: Thu Sep 01, 2011 10:16 am 
Offline
User avatar

Joined: Thu Apr 23, 2009 11:21 pm
Posts: 803
Location: cypress, texas
haha! Thanks, your code works excellent! I can increase the speed of the scrolling like you said! :D Time for lunch... (I've been working on learning and using this code for almost 3 hours.)


Top
 Profile  
 
 Post subject:
PostPosted: Thu Sep 01, 2011 10:51 am 
Offline
Formerly 65024U

Joined: Sat Mar 27, 2010 12:57 pm
Posts: 2257
Also, maybe make it so that you have 2 variables for the screen nametabale and other stuff, so that when you do a $2000 and $2001 store, you don't have to worry about your code running out of VBlank. :D


Top
 Profile  
 
 Post subject:
PostPosted: Thu Sep 01, 2011 1:00 pm 
Offline
User avatar

Joined: Thu Apr 23, 2009 11:21 pm
Posts: 803
Location: cypress, texas
3gengames wrote:
Also, maybe make it so that you have 2 variables for the screen nametabale and other stuff, so that when you do a $2000 and $2001 store, you don't have to worry about your code running out of VBlank. :D


I've never planned on doing a $2000 and $2001 store except the first one, but I read bunnyboys code and it says:
Code:
  ;;This is the PPU clean up section, so rendering the next frame starts properly.
  LDA #%10010000   ; enable NMI, sprites from Pattern Table 0, background from Pattern Table 1
  ORA nametable    ; select correct nametable for bit 0
  STA $2000
 
  LDA #%00011110   ; enable sprites, enable background, no clipping on left side
  STA $2001
   

So I added the $2000 store that tokumaru suggested. Maybe future $2000 stores would be good to have.? Thanks 3gengames. :) Writes to register $2000 are ignored for the first 30000 cycles! :shock: Well my first $2000 store didn't matter.....


Top
 Profile  
 
 Post subject:
PostPosted: Thu Sep 01, 2011 1:13 pm 
Offline
Formerly 65024U

Joined: Sat Mar 27, 2010 12:57 pm
Posts: 2257
Yes, in your startup code you should have something like...

Setup stuff;
BIT $2002
-
BIT $2002
NPL -
Clear RAM/Stuff;
-
Bit $2002
BPL -
MainCode after

and then you need 2 variables in RAM, 1 for the $2000 write, and 1 for the $2001 write. After you wait the 2 frames with the BIT loops in the beginning, you can just write the statuses to RAM, and then turn on the NMI with a $2002 write outside of VBlank to start it, but at the end of your VBlank you can then write the writes from the 2 RAM spots to $2000 and $2001, because then other parts of your program that need to edit attributes of the screen like moving the nametable to another one or stuff, can do so without custom and bulky VBlank code to catch those and add them outside of the preprocessing. Make sense?

A bad example would be using the intensity bits to show the game's paused. [Bad idea to do something like that, but makes a good example.] If you don't use the method of storing $2000/$2001 write from RAM, then your program will have to set a flag and catch inside VBlank that a certain program needs to run and eat up precious cycles. But with the other method, you can over run your main game engine by making the pause turn on the intensity bits from the piece of RAM instead of trying to catch that it needs to happen in VBlank. Although the best way for this to seperate your NMI and your game code entirely and just do a INC FRAME/RTI, although there's still benefits from writing to $2000/$2001 inside VBlank from RAM though. :)


Top
 Profile  
 
 Post subject:
PostPosted: Thu Sep 01, 2011 2:28 pm 
Offline
User avatar

Joined: Thu Apr 23, 2009 11:21 pm
Posts: 803
Location: cypress, texas
ok. : )
---
Before continueing scrolling beyond two screens... I think I should introduce our character to the level. Right now it doesn't rely on anything coded in the level. We want this lady to stand on the ground.... how should we do that? I have the tile codes for the ground parts/sprites.


Top
 Profile  
 
 Post subject:
PostPosted: Thu Sep 01, 2011 2:30 pm 
Offline
Formerly 65024U

Joined: Sat Mar 27, 2010 12:57 pm
Posts: 2257
Well, start making parts of the entire system. Stuff like background collision [Possibly worth using 64 bytes as a buffer to do calculations outside of vblank for the buffer] and stuff like that. Hit detection, object creation/deletion, etc. :)


Top
 Profile  
 
 Post subject:
PostPosted: Thu Sep 01, 2011 3:36 pm 
Online
User avatar

Joined: Sat Feb 12, 2005 9:43 pm
Posts: 10118
Location: Rio de Janeiro - Brazil
How are your levels stored? Just like you read them in order to draw to the nametables, you have to read them to check for collisions. Each block in the level must have its own solidity information (you can use a table for that).

You'll have to check key points around the character and make decisions depending on the solidity of the blocks that surround her. For gravity, for example, you should always check the block right below the character's feet, and if it's not solid the character must move down (i.e. fall).

Here are some posts where I talked about background collision, see if you can get something useful from them:

http://nesdev.com/bbs/viewtopi ... =4617#4617
http://nesdev.com/bbs/viewtopi ... 0918#40918
http://nesdev.com/bbs/viewtopi ... 9897#59897
http://nesdev.com/bbs/viewtopi ... 0374#60374

I'm not gonna lie to you, this will be hard to get right. This is the part where your little NES program stops being a playground and starts becoming a game. At this point, everything you program needs to be more robust and integrated, everything must be a "system", rather than just random blocks of code with immediate results on the screen. This is serious business.


Top
 Profile  
 
 Post subject:
PostPosted: Thu Sep 01, 2011 3:49 pm 
Offline
Formerly 65024U

Joined: Sat Mar 27, 2010 12:57 pm
Posts: 2257
How good of practice is it to buffer a map with either 64 bytes [1 pit per tile] or 2 bits per tile and make it 128 bytes and use that to do all calculations out of vblank and such?


Top
 Profile  
 
 Post subject:
PostPosted: Thu Sep 01, 2011 5:18 pm 
Online
User avatar

Joined: Sat Feb 12, 2005 9:43 pm
Posts: 10118
Location: Rio de Janeiro - Brazil
Considering that there are usually several objects that need collision tests against the background, the time taken to do this will easily be more than 20 scanlines, so that fact that this HAS to be done outside of VBlank is not even up for discussion.

Now, if you use only 1 bit per tile, you can only mark the tiles as either solid or empty. Forget about water, lava, blocks that hurt the player, and so on. This might be OK for some simple games, but definitely too limited for the majority of them. With 2 bits it gets a little better, but not much.

The ideal way to do it, in my opinion, is to use metatiles and associate all collision information to them, rather than to individual tiles. Also, instead of buffering whole screens of collision data, just read the metatiles from the level map (which may or may not be buffered) and then look for their collision information. I don't expect newbies to do this on their first try though.


Top
 Profile  
 
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 1386 posts ]  Go to page Previous  1 ... 16, 17, 18, 19, 20, 21, 22 ... 93  Next

All times are UTC - 7 hours


Who is online

Users browsing this forum: TOUKO and 5 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to:  
Powered by phpBB® Forum Software © phpBB Group