It is currently Sun Oct 22, 2017 10:29 am

All times are UTC - 7 hours





Post new topic Reply to topic  [ 43 posts ]  Go to page Previous  1, 2, 3
Author Message
PostPosted: Tue May 02, 2017 7:28 am 
Offline
User avatar

Joined: Sat Jan 09, 2016 9:21 pm
Posts: 213
Location: Central Illinois, USA
Bregalad wrote:
So basically, this thread is an exact duplicate of that thread, everything that has been discussed here had already been discussed there, and this was a complete waste of time of ours. Why don't people use the search function.


Well, although the underlying problem was the same for both threads, the first question was very different ("how do I divide by 240" vs "pros and cons of different methods of handling vertical position") Both ended up getting into the same answers, but unless you know they're going to get to the same answers, they are both legitimate separate questions.

Quote:
Agreed, this is an extremely relevant issue for any games wanting to do vertical scrolling on the NES, so it shouldn't necessarily be hidden away in a 10 year old archive. In fact this is a subject that could easily warrant an entire wiki article.


It seems like a common enough problem that an article would make sense.

_________________
My games: http://www.bitethechili.com


Top
 Profile  
 
PostPosted: Tue May 02, 2017 8:58 am 
Offline

Joined: Wed May 19, 2010 6:12 pm
Posts: 2295
You can probably use a LUT of where each row of tiles maps into VRAM.


Top
 Profile  
 
PostPosted: Tue May 02, 2017 9:34 am 
Offline
User avatar

Joined: Sat Feb 12, 2005 9:43 pm
Posts: 10066
Location: Rio de Janeiro - Brazil
It's true that a LUT is the simplest and fastest solution possible, since you wouldn't even have to manually wrap around any values, but when you have levels up to 128 "rooms" tall, like my engine supports, you'd need a 4KB LUT. Not terrible if you have 256 or 512KB of total PRG-ROM, but still a significant amount to worry about depending on the type of bankswitching you're using and when you need that table to be mapped in.

EDIT: Actually, now that I think of it, a LUT wouldn't work for me, because my engine can do vertically looping levels, which causes the level map to repeat while the screen coordinates can keep going indefinitely.


Top
 Profile  
 
PostPosted: Wed May 03, 2017 9:33 am 
Offline

Joined: Wed May 19, 2010 6:12 pm
Posts: 2295
I just noticed your divide by 240 code from 2007. That's some beautifully written code.


Top
 Profile  
 
PostPosted: Wed May 03, 2017 10:04 am 
Offline
User avatar

Joined: Sat Feb 12, 2005 9:43 pm
Posts: 10066
Location: Rio de Janeiro - Brazil
My code? Thanks, I have no idea how I came up with it! :lol:

EDIT: I think it's based on the algorithm in slide 5 of this lecture, but with a few optimizations (no restoring because of preliminary CMP, no initial shifting because I'm using half of the divisor).


Top
 Profile  
 
PostPosted: Thu May 04, 2017 2:41 am 
Offline
User avatar

Joined: Fri Nov 12, 2004 2:49 pm
Posts: 7234
Location: Chexbres, VD, Switzerland
Quote:
EDIT: Actually, now that I think of it, a LUT wouldn't work for me, because my engine can do vertically looping levels, which causes the level map to repeat while the screen coordinates can keep going indefinitely.

Division wouldn't work either, as the VScroll value will eventually warp around. This is a further proof that having a separate counter is a nice idea (even though division would work for non-looping levels, if you know the maximum size in advance).


Top
 Profile  
 
PostPosted: Thu May 04, 2017 5:04 am 
Offline
User avatar

Joined: Sat Feb 12, 2005 9:43 pm
Posts: 10066
Location: Rio de Janeiro - Brazil
I guess you're right. At first I thought that I could safely wrap around at 61440, which's a multiple of 240 and 256 and just past what my division routine from back in the day could handle, but now that I think of it, that would screw up the repetition of the level map since this value is not a power of 2.

Bregalad wrote:
This is a further proof that having a separate counter is a nice idea

Well, I just love this approach... The only drawback I can see is that for everything you need to find the NT position of, you need to calculate the distance between that thing and the level anchor, then add that difference to the screen anchor. Not a big deal when rendering rows and columns of tiles for scrolling, since the offsets from the anchor are fixed (i.e. a row of tiles at the bottom of the screen always starts at anchor + 240, the offset is constant), but if you needed to destroy a block or something in the middle of the screen, you'd need to calculate the offset first.

Dvisions would certainly be slower, because you'd need a different division for each thing you needed the position of, in addition to the divisions needed to find the scroll and the target address for new columns/rows of tiles. You could easily end up with 4 or 5 divisions in a single frame.


Top
 Profile  
 
PostPosted: Thu May 04, 2017 5:54 am 
Offline
User avatar

Joined: Thu Sep 15, 2016 6:29 am
Posts: 253
Location: Denmark (PAL)
All the more reason for keeping your background graphic data completely separated from everything else in your game. You shouldn't need to do this synchronization thing for anything other than scrolling your nametables. Of course, that's easier said than done when you don't have a lot of PRG-ROM space to work with, and I know a lot of people keep the collision data as a part of their nametable data, but I'm glad I decided to split up the two quite early in my project. :P

My biggest reason for always syncing the "nametable scroll" to the "logical scroll" value via division by 15 is that I want to be able to "spawn" the stage at any given coordinate, so I need this routine anyway, and since it's still only called once per frame as a worst case scenario, there's no real loss for only using that. Keeps my code nice and tidy.


Top
 Profile  
 
PostPosted: Thu May 04, 2017 6:10 am 
Offline
User avatar

Joined: Sat Feb 12, 2005 9:43 pm
Posts: 10066
Location: Rio de Janeiro - Brazil
Sumez wrote:
You shouldn't need to do this synchronization thing for anything other than scrolling your nametables.

How do you propose we update the middle of a name table after destroying​ a block or collecting an item then? Characters interact with the level map and items in level space, so that's what you have, and when you need to change or erase them from the name tables you need to convert their positions into screen space, don't you?

Quote:
My biggest reason for always syncing the "nametable scroll" to the "logical scroll" value via division by 15 is that I want to be able to "spawn" the stage at any given coordinate

Totally doable with the 2 anchors approach. In fact, since there's no hardcoded relationship between the 2 separate spaces, you can start the primary anchor anywhere you want in the level, and the secondary anchor anywhere in the name tables, only the lower bits have to match, for obvious reasons. I always initialize my secondary anchor (NTCameraY) to CameraY & 15 (since my meta tiles are 16x16 pixels), no division necessary. Just start on the first NT row every time and it works just fine.

Quote:
so I need this routine anyway, and since it's still only called once per frame as a worst case scenario, there's no real loss for only using that. Keeps my code nice and tidy.

If you think you need the division and you somehow find a division tidier than an addition (to keep 2 anchors synchronized), that's your call, but I honestly think you haven't analyzed the alternate approach in depth yet, and are simply more comfortable with what you already have.


Top
 Profile  
 
PostPosted: Thu May 04, 2017 7:01 am 
Offline
User avatar

Joined: Thu Sep 15, 2016 6:29 am
Posts: 253
Location: Denmark (PAL)
Well, it's purely situational. :) I won't say there's ever a correct or incorrect way to do it. I actually started out trying to update two variables side by side like you are describing, but I ended up having to do a lot of weird fixes throughout my code because everything was aligned to the nametable data (as in your example where parts of the map are destructible). That's not saying it's a bad approach at all, much more likely my ASM code was just too clumsy to begin with.

What you said confuses me. How does keeping two separate variables updated every time you change the Y scroll give you an advantage when working with logic that's tied to nametable addesses (destructible map tiles), compared to updating the "NTCameraY" once per frame through division?
As far as I see, the end result is the same (ie. the rest of my logic doesn't have to know how NTCameraY was generated), but I think I'm probably misunderstanding how your solution works, which would also explain why I had trouble implementing it, when you didn't. :)


Top
 Profile  
 
PostPosted: Thu May 04, 2017 7:21 am 
Offline
User avatar

Joined: Sat Feb 12, 2005 9:43 pm
Posts: 10066
Location: Rio de Janeiro - Brazil
Sumez wrote:
Well, it's purely situational. :) I won't say there's ever a correct or incorrect way to do it.

That's true. We usually give a lot of thought to these problems and design everything around the decisions we make, so we can't simply change our methods because someone said something else works better.

Quote:
What you said confuses me. How does keeping two separate variables updated every time you change the Y scroll give you an advantage when working with logic that's tied to nametable addesses (destructible map tiles), compared to updating the "NTCameraY" once per frame through division?

Are you saying that the only difference is the division itself, and from then on everything works the same for both approaches? If so, I agree with you, and the advantage is that you only need and addition to update NTCameraY, instead of a division.

But it's also possible that someone chooses to use multiple divisions, one for each coordinate that needs converting, as opposed to doing things relative to the anchors.


Top
 Profile  
 
PostPosted: Thu May 04, 2017 7:42 am 
Offline

Joined: Sun Sep 19, 2004 11:12 pm
Posts: 19115
Location: NE Indiana, USA (NTSC)
tokumaru wrote:
Sumez wrote:
You shouldn't need to do this synchronization thing for anything other than scrolling your nametables.

How do you propose we update the middle of a name table after destroying​ a block or collecting an item then?

Unless you're routinely doing huge set pieces where you animate huge parts of the background map, destruction should be less common than scrolling, making slightly slower execution of a destruction acceptable in a soft real time[1] system. Large background animations tend to be more for the collapse phase of a falling block puzzle game.


[1] Wikipedia's article defines "soft real time" as "the usefulness of a result degrades after its deadline, thereby degrading the system's quality of service."


Top
 Profile  
 
PostPosted: Thu May 04, 2017 3:43 pm 
Offline

Joined: Wed May 19, 2010 6:12 pm
Posts: 2295
I think you should have a register holding the y-position of the top of the name tables, and find breakable blocks relative to it.


Top
 Profile  
 
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 43 posts ]  Go to page Previous  1, 2, 3

All times are UTC - 7 hours


Who is online

Users browsing this forum: Bing [Bot], Memblers and 9 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