General newbie questions

Are you new to 6502, NES, or even programming in general? Post any of your questions here. Remember - the only dumb question is the question that remains unasked.

Moderator: Moderators

Post Reply
User avatar
za909
Posts: 211
Joined: Fri Jan 24, 2014 9:05 am
Location: Hungary

General newbie questions

Post by za909 » Sun Feb 16, 2014 1:25 pm

Hey!

Now that I had a little go at 6502 asm with the DPCM hack for Megaman 3, I've been thinking of going out there and starting up some sort of a project from scratch! NROM-256, vertical mirroring, nothing fancy for now.
Overall, I understand everything I need, to make a game, at least I say that now. Reading up on the init process, I've come to a few interesting thoughts and questions. So here I go!

1. How do I load the 8k of data from CHR-ROM through $2007, if $8000-$FFF9 is all PRG-ROM, and there's no mapping capabilities of any kind? Is there something I'm not aware of, or is it automatically loading whatever's not in PRG-ROM?

2. Meta-sprite system. In my head, this sounds too easy to actually be the right answer, so I'd rather ask you people about it. Is it really as simple, as subtracting or adding 8 to the x or y coordinates in relation to the top right/left 8x8 sprite when calculating the overall sprite position, creating a "relative" sprite system? Maybe using a variable instead of 8 for more flexibility.

3. Is the 256-byte OAM data mapped to the CPU, or do games simply store the entire thing in a single RAM page, and copy it to $2004 during a PPU update?

4. Can I possibly use sprite 0 hit, to create a status bar, THEN move it somewhere else during rendering, so that it triggers again and I can set the scroll position once more to create parallax effects as well?

5. Various timing quirks: Whenever I do a little reading to study the hardware, I keep bumping into really intimidating facts about various cycle-based timing properties of each hardware component. Do I really have to keep in mind how the internal cycles of the PPU work for example if I want a standard game running?

6. Collision detection: I really have no clue how to get this done. I suppose for sprites, comparing their overall position is the way to go, but I have absolutely no idea how to make sprites interact with the background, to create "solid" and "non-solid" 16x16 blocks.

JRoatch
Formerly 43110
Posts: 390
Joined: Wed Feb 05, 2014 7:01 am
Location: us-east
Contact:

Re: General newbie questions

Post by JRoatch » Sun Feb 16, 2014 1:54 pm

I can answer what I can, and leave the rest to others.

1. In the ROM image, CHR-ROM is placed after PRG-ROM. When executing, CHR-ROM is permanently mapped to PPU $0000-$1FFF as much as PRG-ROM is mapped to CPU $8000-$FFFF.

3. Most games reserve a page (256 bytes) of CPU RAM and write the high byte of that page to $4014.

5. Not unless you are doing PPU operations mid rendering (like a status bar split with a sprite 0 hit). For simple PPU operations in vblank you have about 2250 cycles from a NMI to do whatever.

User avatar
rainwarrior
Posts: 7836
Joined: Sun Jan 22, 2012 12:03 pm
Location: Canada
Contact:

Re: General newbie questions

Post by rainwarrior » Sun Feb 16, 2014 1:58 pm

1. The CHR-ROM is an entirely separate chip on a separate bus than PRG-ROM. The CHR-ROM block goes in a different place than PRG-ROM, read the iNES file format for information on this.

2. Meta sprite just means making a single "sprite" out of multiple sprite tiles. You can implement this a lot of ways, but what I do is I have a list of 4-byte tiles (X/Y/tile/attribute data) and I simply add the meta-sprite's base X and Y into these (or subtract them from it if flipped).

3. The standard practice is to reserve 256 bytes of RAM for OAM use, and write to $4014 to use the DMA to copy it to the PPU's internal OAM.

4. No, you can only use sprite 0 hit once per frame. However, once you make the first sprite 0 hit, you could write carefully timed code to change the scrolling at other places if you're willing to spend the CPU cycles on it. Look at Rad Racer for an example.

5. Not really. You don't need a fine-grained grasp of the timing unless you want to do more complicated techniques, like parallax scrolling, for example. Even when you do need it, timing may not be as difficult as you think. A good debugging emulator (e.g. FCEUX) can do the cycle counting for you, timing stuff correctly is usually just a matter of inserting NOPs to place your instructions on the right cycles.

6. Generally you will want to store a collision map in RAM somwhere to tell you which tiles are solid and which are empty (if RAM is tight you can even pack up to 8 tiles to a byte as single bits). Collision is a matter of comparing object boundaries, and resolving what happens when they overlap.

lidnariq
Posts: 9658
Joined: Sun Apr 13, 2008 11:12 am
Location: Seattle

Re: General newbie questions

Post by lidnariq » Sun Feb 16, 2014 2:08 pm

za909 wrote:1. How do I load the 8k of data from CHR-ROM through $2007, if $8000-$FFF9 is all PRG-ROM, and there's no mapping capabilities of any kind? Is there something I'm not aware of, or is it automatically loading whatever's not in PRG-ROM?
Because it's CHR ROM, it's already loaded. That's why the iNES format specifies both some number times 16KiB of PRG and some number times 8 KiB of CHR.
3. Is the 256-byte OAM data mapped to the CPU, or do games simply store the entire thing in a single RAM page, and copy it to $2004 during a PPU update?
It's not directly mapped to the CPU, although there is an interface not unlike the 2006/2007 one for CHR data. In practice, almost all games use a 256b RAM page and use the register at $4014 to transfer all 256 bytes during a PPU update.
4. Can I possibly use sprite 0 hit, to create a status bar, THEN move it somewhere else during rendering, so that it triggers again and I can set the scroll position once more to create parallax effects as well?
No, the sprite 0 hit cannot be cleared by software, only by vblank ending.
5. Various timing quirks: Whenever I do a little reading to study the hardware, I keep bumping into really intimidating facts about various cycle-based timing properties of each hardware component. Do I really have to keep in mind how the internal cycles of the PPU work for example if I want a standard game running?
Probably not, especially if you're not doing anything visually complex.

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

Re: General newbie questions

Post by thefox » Sun Feb 16, 2014 2:09 pm

(Bleh, looks like I was ninjaed, twice. Not that surprising, really. :))
za909 wrote:1. How do I load the 8k of data from CHR-ROM through $2007, if $8000-$FFF9 is all PRG-ROM, and there's no mapping capabilities of any kind? Is there something I'm not aware of, or is it automatically loading whatever's not in PRG-ROM?
There's no need to manually load the CHR data with $2007 if you use CHR-ROM, that's only required if you use CHR-RAM. Of course you can read back the data with $2007. By the way, $FFFA-$FFFF is as much PRG-ROM as anything else.
2. Meta-sprite system. In my head, this sounds too easy to actually be the right answer, so I'd rather ask you people about it. Is it really as simple, as subtracting or adding 8 to the x or y coordinates in relation to the top right/left 8x8 sprite when calculating the overall sprite position, creating a "relative" sprite system? Maybe using a variable instead of 8 for more flexibility.
Yes, it is that simple. Basically, you want to create a function that takes these parameters: 1) metasprite data 2) destination coordinates 3) possibly some other attributes, like flip flags, etc. You can select a metasprite data format that suits your needs, but the most flexible and simple one is to store the relative X and Y coordinates, tile number and attributes in there, at 4 bytes per hardware sprite. You will probably want to use signed coordinates, so that it's possible to adjust the origin of your sprites.
3. Is the 256-byte OAM data mapped to the CPU, or do games simply store the entire thing in a single RAM page, and copy it to $2004 during a PPU update?
It's not mapped to CPU memory, it has to be copied with OAM DMA, which takes approximately 512 cycles.
4. Can I possibly use sprite 0 hit, to create a status bar, THEN move it somewhere else during rendering, so that it triggers again and I can set the scroll position once more to create parallax effects as well?
No you can't, because the sprite 0 hit flag isn't cleared until at the beginning of the next frame.
5. Various timing quirks: Whenever I do a little reading to study the hardware, I keep bumping into really intimidating facts about various cycle-based timing properties of each hardware component. Do I really have to keep in mind how the internal cycles of the PPU work for example if I want a standard game running?
No, you don't need to know most of the internal details.
6. Collision detection: I really have no clue how to get this done. I suppose for sprites, comparing their overall position is the way to go, but I have absolutely no idea how to make sprites interact with the background, to create "solid" and "non-solid" 16x16 blocks.
Search the forums. :)
Download STREEMERZ for NES from fauxgame.com! — Some other stuff I've done: fo.aspekt.fi

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

Re: General newbie questions

Post by tokumaru » Sun Feb 16, 2014 5:01 pm

za909 wrote:2. Meta-sprite system. In my head, this sounds too easy to actually be the right answer, so I'd rather ask you people about it. Is it really as simple, as subtracting or adding 8 to the x or y coordinates in relation to the top right/left 8x8 sprite when calculating the overall sprite position, creating a "relative" sprite system? Maybe using a variable instead of 8 for more flexibility.
You should design a meta-sprite system that suits your needs. I prefer to use 4 bytes per sprite: tile index, attributes, relative X and relative Y. The coordinates are signed and relative to the coordinates of the object the meta-sprite represents. This doesn't limit me to grid-like meta-sprites, but wastes more space. Other things to consider in your meta-sprite system is the conversion between world coordinates into screen coordinates (object coordinates are relative to the level, while sprite coordinates are relative to the screen), clipping and flipping. Depending on how simple/complex your game is, you might not have to deal with some of those issues: if your game doesn't scroll, there's no need for coordinate conversion; if the objects never cross screen boundaries, you don't have to worry about clipping; horizontal flipping is a certainty in most games more complex than pong, but vertical flipping might not be necessary.
4. Can I possibly use sprite 0 hit, to create a status bar, THEN move it somewhere else during rendering, so that it triggers again and I can set the scroll position once more to create parallax effects as well?
As others have said, the sprite 0 hit flag only goes up once per frame, and isn't cleared until the next frame, so no. But you do have a few options:

1- Like has already been suggested, you can use timed code between the sprite hit and the next split. This might not be an option if the split is way down the screen, because there will be no time left to handle the game logic before the frame ends and VBlank starts.

2- You can use timed code for the status bar instead. The sprite hit flag is always cleared at the same time every frame, by the end of VBlank, so you can use this to sync to the start of the frame. You can then run some timed code while the status bar is rendered and do your first split. Then you can use the sprite 0 hit for the second split. But you still have to be careful about how much time you dedicate to the game logic, so the position of the split shouldn't vary much from frame to frame.

3- Use the sprite overflow flag for the status bar, and the sprite 0 hit for the other split. The sprite overflow flag is a bit weird, but you can be sure that it will be set if 9 sprites are on the same scanline. So if you put that many sprites by the end of the status bar you'll be able to detect the end of it, and the sprite 0 hit is free for the parallax split. You shouldn't do it the other way around (sprite 0 for the status bar and sprite overflow for the parallax) because the game objects may accidentally line up and cause a premature sprite overflow. Since there are no objects in the status bar area (or if there are, they are controlled), that won't happen there. The main drawback is, obviously, having to waste 9 sprites.
5. Various timing quirks: Whenever I do a little reading to study the hardware, I keep bumping into really intimidating facts about various cycle-based timing properties of each hardware component. Do I really have to keep in mind how the internal cycles of the PPU work for example if I want a standard game running?
If you want to create parallax effects, you do have to know a little about scanline timing. Everything that affects PPU parameters mid-frame (scroll changes, VRAM updates, CHR bankswitching) requires some understanding of the PPU timing in order to be reliable and glitch-free. Guessing + trial-and-error may work some times, but that's not recommended, specially if you're testing on emulators and not the real thing. If you're not doing any PPU tricks mid-frame, you can totally ignore what the PPU does during rendering.
6. Collision detection: I really have no clue how to get this done. I suppose for sprites, comparing their overall position is the way to go, but I have absolutely no idea how to make sprites interact with the background, to create "solid" and "non-solid" 16x16 blocks.
Ideally, collisions happen between objects, not sprites. Always keep in mind that sprites are just a visual representation of in-game objects, which are the actual entities that should be worked on. Sprites are only there so that the player can see what's happening in the game world, and no logic should be based on them. There's plenty of collision discussion in the forums, I'm sure you'll find interesting topics if you search a bit.

For object x object collisions you'll want to read about bounding box collision. Look for it on Google, this is not NES specific and has been used in games for all kinds of platforms since forever.

As for objects vs. background, the basic idea is that you let all objects move like they want to (even if that means going inside a wall, for example), and afterwards you check for any "violations" and push the objects back to the last allowed position. To detect "violations" you just have to check some key point of the objects against the background to see it those points are allowed to be where they are. For example, if the player moved left, you should check all the background blocks from its top left corner down to the bottom left corner, to make sure that all blocks are "non-solid". If you find any solid blocks, you should push the player object right enough to eject it off the wall.

Converting object coordinates to level map coordinates is easy, just divide the pixel coordinates by the size of the basic building blocks of your map. For example, if the top left corner of an object is at coordinates (678, 137), and your meta-tiles are 16x16 pixels large, just divide the pixel coordinates by 16 to find the meta-tile coordinates (42, 8), which you can use to read from your level map. Once you find the meta-tile at that location, just check its attributes to know whether it's solid or not.

Celius
Posts: 2157
Joined: Sun Jun 05, 2005 2:04 pm
Location: Minneapolis, Minnesota, United States
Contact:

Re: General newbie questions

Post by Celius » Mon Feb 17, 2014 12:00 pm

za909 wrote: 6. Collision detection: I really have no clue how to get this done. I suppose for sprites, comparing their overall position is the way to go, but I have absolutely no idea how to make sprites interact with the background, to create "solid" and "non-solid" 16x16 blocks.
Many games start out by having a limited set of 16x16 pixel metatiles defined somewhere in ROM. Separate tables usually define the individual 8x8 pixel tiles that make up those metatiles, and the properties for those metatiles, such as the color attribute and its behavior in the level (solid, non-solid, liquid, acid, etc.). A level map is usually stored in ROM that defines what metatiles make up the level. As the player moves and the level scrolls, your code will need to find the set of metatiles that is being revealed (by scrolling), and then using those values, find the actual 8x8 pixel tiles to write to the name table. You can essentially use that same logic for collision detection. Essentially the two processes both find metatiles at specific object coordinates within the level (the camera is the object in the case of scrolling). Once you find what metatile exists within the level at specific object coordinates, you can look up what metatile "type" it is (solid, non-solid, liquid, acid, etc.). A good example is checking what metatile type exists at the player's feet. If it's solid, reject the player outward. If it's liquid, slow their velocity. If it's acid, damage the player.

Of course, it depends on the style of gameplay. If we're talking about a platformer where the player is constantly being pulled down by gravity, the behaviors of collision will be quite different than something like Final Fantasy, where it's top-down and the player moves 16 pixels at a time in a given direction.

Post Reply