It is currently Wed Oct 17, 2018 10:05 pm

All times are UTC - 7 hours





Post new topic Reply to topic  [ 40 posts ]  Go to page 1, 2, 3  Next
Author Message
PostPosted: Wed Nov 25, 2009 6:21 am 
Offline
User avatar

Joined: Wed Nov 25, 2009 5:06 am
Posts: 37
Hi! Obviously I'm new here and I'm completely new to programming for any console. Although I'm currently programming for the SNES I hope I can ask questions here, too, as this was the only newbie subforum I saw.
I have two questions regarding scrolling and sprites on these old systems (NES and SNES) - I guess they are quite similar in this regard.

1. There are many games using sprites which are much bigger than 8x8 pixels, Super Metroid for example. I read I can use sizes up to 64x64, but still the Samus sprite is still bigger (bosses even more). Do I have to "render" multiple sprites to get one big image on the screen? That's what I currently do, but it's somewhat strange.

2. I want to implement scrolling in my game, however from what I saw/read this can't be done like it's done on modern computers (for example) where the whole screen is constantly re-drawn. I should say that I implemented a tile-based engine (something like in Mario games).
What I've read up to now is still a bit unclear to me, however it sounded like I have to substitute rows of tiles on the screen while moving/scrolling the map. I managed to get the background scrolling, but of course it always wrapped at the end of the screen. What is the proper way to do this? I'm aiming for something like in Mario3 on the NES.

I hope I wasn't too unclear, if so please ask anything that isn't clear.
Thanks in advance!


Top
 Profile  
 
 Post subject:
PostPosted: Wed Nov 25, 2009 9:56 am 
Offline
User avatar

Joined: Fri Nov 12, 2004 2:49 pm
Posts: 7548
Location: Chexbres, VD, Switzerland
About sprites you shouldn't confuse sprites with meta-sprites.

Sprites (on the hardware viewpoint) is a piece of graphic the PPU place over BG by hardware.

A meta sprite (commonly called Sprite in Gamer's communauty) is one or more sprites that joined together to form a character, enemy, weapon, etc...

About BG scrolling you can't redraw the whole screen at once, but all you have to know is that you have memory for something larger than the screen which is shown, so basically you redraw tiles in the parts that aren't visiable when scrolling. On the NES it's a bit more complicated if you want to do multi-directionnal scrolling because you don't always have the margin I just talked about, and this leads into glitches on the sides of the screen (you have probably already seen them in NES games).

_________________
Life is complex: it has both real and imaginary components.


Top
 Profile  
 
PostPosted: Wed Nov 25, 2009 10:51 am 
Offline
User avatar

Joined: Sat Feb 12, 2005 9:43 pm
Posts: 10897
Location: Rio de Janeiro - Brazil
AndiNo wrote:
Do I have to "render" multiple sprites to get one big image on the screen? That's what I currently do, but it's somewhat strange.

This is how it happens. It may seem strange if you are doing it in a hardcoded way (manually setting up all the sprites of a particular object), but usually programmers implement a sprite system. For each possible frame of a character there is a list of the necessary sprites to draw it. It's just a series of .db or .dw statements that represent things like "this frame needs 4 sprites; the first one is at coordinates (4, 5) and uses tile $78; the second is at coordinates (12, 8) and uses tile $79 (...)". The coordinates are usually relative to the position of the object/character being drawn. This means that the sprite system can draw any frame of any character if you point it to the correct list.

Quote:
What I've read up to now is still a bit unclear to me, however it sounded like I have to substitute rows of tiles on the screen while moving/scrolling the map. I managed to get the background scrolling, but of course it always wrapped at the end of the screen. What is the proper way to do this?

So you noticed it wraps around, right? All you have to do is redraw that part that wraps, before it wraps. What you have to do is constantly overwrite the parts that are off screen with new data before they are back on screen (due to wrapping). Players won't notice the background is wrapping, because you drew new tiles over the old ones.

When scrolling horizontally you have to draw columns of tiles, and when scrolling vertically you have to draw rows of tiles. The size of the drawing area that is off screen makes a difference. The NES has only 2 built in Name Tables, which you can arrange as a 512x240 (vertical mirroring) or 256x480 (horizontal mirroring) area, so it's hard to scroll vertically and horizontally without some visible glitches (like Bregalad said), because you always lack an off screen area either vertically or horizontally.

There are ways to avoid these glitches, even though many games just make them appear at the top and/or bottom 8 scanlines in hopes that TVs will not display those scanlines (which is not always the case). some very famous games like SMB3 or Kirby have the glitches very visible at the sides. The SNES has a drawing area big enough for this not to be a problem there.


Top
 Profile  
 
 Post subject:
PostPosted: Wed Nov 25, 2009 2:56 pm 
Offline
User avatar

Joined: Wed Nov 25, 2009 5:06 am
Posts: 37
Thanks, that were some really helpful answers!
I will try to implement these metasprites. From there animations shouldn't be too hard to do.
I will have to take a more detailed look at scrolling though when I have the time. Your posts were good hints as to what I have to look at.
If I have any questions I will come back... I didn't expect the "homebrew" scene to be so active :)


Top
 Profile  
 
 Post subject:
PostPosted: Wed Nov 25, 2009 4:22 pm 
Offline
User avatar

Joined: Sat Feb 12, 2005 9:43 pm
Posts: 10897
Location: Rio de Janeiro - Brazil
AndiNo wrote:
I will try to implement these metasprites. From there animations shouldn't be too hard to do.

You can think of animations as collections of metasprites, much like metasprites are collections of sprites. For animations, you have to specify the duration of each frame, and some other details such as if the animation loops or stays in the last frame when it finishes, things like that, but depending on the needs of your game of course.

Quote:
I will have to take a more detailed look at scrolling though when I have the time.

It helps if you create a "camera" object that is not much different from other game objects. It has a position within the level and dimensions, like any regular object. By keeping track of how much it moves, you can tell when you need a new column or row of tiles. Using the direction of that movement and the dimensions of the camera you can tell where to read the tiles from (in the level map) and where to write them to (in VRAM).


Top
 Profile  
 
 Post subject:
PostPosted: Thu Nov 26, 2009 12:22 pm 
Offline
User avatar

Joined: Wed Nov 25, 2009 5:06 am
Posts: 37
Thanks for your reply! However I have to say I already have some experience with "2D side scrollers". I have already implemented such a game engine in C++ with SDL on the computer, so I just have to get used to this stuff again, and of course I have to understand how the SNES works (in those parts).
I will do some research and come back here if there is something I don't understand. Thanks for your help so far!


Top
 Profile  
 
 Post subject:
PostPosted: Fri Nov 27, 2009 5:34 pm 
Offline
User avatar

Joined: Wed Nov 25, 2009 5:06 am
Posts: 37
Back again! I also have some questions at hand and hope you don't mind giving me advice again :)
1. My game is coming along nicely, however I've run into some hardware-specific problems. After expanding my code I now experience quite some lagging and flickering of my sprites. I assume this is due too much code being executed (execution is taking too long). Is there anything I can do about this (except reducing running code of course) ?

2. From what I understood the system runs constantly at 60 FPS, so I have a set amount of time per frame. Is that the time between the vertical blanks? Concerning the code being executed, if it takes longer than the given time I have per frame, does the SNES just draw the current status of the game while the code is still performing in the background?

3. Whenever a gameobject is destroyed, its sprite remains at the last given position on the screen. Thus I reset all SNES-sprites at the beginning of each frame so they are not visible anymore. Is there any other way to do that? And what can I do to make a specific sprite really invisible (not just giving them position 0,0)?

Thanks in advance again! I'm looking forward to getting a small game done! :)


Top
 Profile  
 
 Post subject:
PostPosted: Fri Nov 27, 2009 6:08 pm 
Offline
User avatar

Joined: Sat Feb 12, 2005 9:43 pm
Posts: 10897
Location: Rio de Janeiro - Brazil
I understand that you are familiar with how games work, and your biggest problem is implementing what you already know in an old gaming console. Having made that transition myself I do believe I can help you out a bit.

I'll try to answer what I can, but since I don't know much about the SNES itself (it's not among the consoles I have programmed for), I'll leave anything too specific for other people to answer.

AndiNo wrote:
After expanding my code I now experience quite some lagging and flickering of my sprites. I assume this is due too much code being executed (execution is taking too long).

Hard to know without knowing more about how you coded it.

Quote:
Is that the time between the vertical blanks?

Yeah, usually you use the time between vertical blanks to calculate all the game logic and generate the data you need to update the video, and vertical blank is the time when you do all the video updates, using the data you calculated earlier.

Quote:
Concerning the code being executed, if it takes longer than the given time I have per frame, does the SNES just draw the current status of the game while the code is still performing in the background?

It depends on how you code the game. Your program should be able to tell when a frame wasn't enough time to calculate everything, in which case you don't perform video updates, or else you'd get a corrupt frame (this might be what's causing the problem you described before).

When playing games you can often see that when there are too many objects on screen at once the games lag. Usually, you don't do any video updates when a lag frame is detected, because you don't want to use partially processed data or anything like that, so you just keep calculating the game logic until it's done, and hopefully by the next VBlank everything will be ready. Because of this players get the impression that the things are in "slow motion".

Quote:
Whenever a gameobject is destroyed, its sprite remains at the last given position on the screen. Thus I reset all SNES-sprites at the beginning of each frame so they are not visible anymore. Is there any other way to do that?

Why don't you make the object's destructor place the sprites it was using off screen? In most NES games, the sprites are usually all reset (put off screen) to be reused by the objects as necessary every frame, but this is partially done because of sprite cycling as well, so I'm not sure if this is common on SNES games. Genesis/MD games seem to do it like in the NES though.

Quote:
And what can I do to make a specific sprite really invisible (not just giving them position 0,0)?

What's so bad about placing the sprites off screen? I don't know if the SNES has any means of making individual sprites invisible, but none of the other consoles I know do. The closest thing to actually disabling sprites I've already seen is in the video chip used by the MSX (and a shitload of other machines): if you put one sprite at a certain Y coordinate, all the sprites after that are ignored. This is useful, but doesn't allow you disable individual sprites.


Top
 Profile  
 
 Post subject:
PostPosted: Sat Nov 28, 2009 3:20 am 
Offline
User avatar

Joined: Fri Nov 12, 2004 2:49 pm
Posts: 7548
Location: Chexbres, VD, Switzerland
You should probably separate software sprites from hardware sprites (I don't know if you arlready do).
OAM memory ($200-$2ff) should be cleared at the start of every frame so all sprites are below the screen (Y position $f0).
Then whenever you need to show a metasprite, call a routine that mazes it into memory for you, by adding relative H/V positions to the main sprite position and coping other attributes to OAM. Having a system that allows to switch the palette and flip the sprite at least horizontally is a nice plus. I could share my OAM engine if you want.

For the SNES I'm pretty sure it's almost exactly the same, exept you have 2 OAM buffers, and that X/Y pos have more than 8 bits (so you can scroll them correctly at last). You'd still want to place a sprite below the screen to hide it.

And BTW the C64 has a way to actually disable sprites, and you usually have to play tricks with it to do OAM cycling to be able to show more than 8 sprites on the screen.

_________________
Life is complex: it has both real and imaginary components.


Top
 Profile  
 
 Post subject:
PostPosted: Sat Nov 28, 2009 4:35 am 
Offline
User avatar

Joined: Wed Nov 25, 2009 5:06 am
Posts: 37
I can write down what things I do in every frame, maybe that would make things a bit clearer. Besides that I have to say I'm not programming in assembler but in C (using the SNES SDK). I've read many posts which state that C is subordinate to assembler on the SNES, do you think that could be the (main) reason for my game running slowly?
btw: Is there a way to measure the time left before the vblank happens? And I read you can set the SNES clock from 2.68 to 3.xx MHz. I tried that as I guessed it could possibly make the CPU faster, but the flickering was worse - maybe I did something wrong or am assuming wrong things.

What can I do if ALL frames take more than one vblank to be completed? I changed my program so that it waits for vblank before drawing stuff and the flickering was gone, however it runs slow now (as you said).

tokumaru wrote:
Why don't you make the object's destructor place the sprites it was using off screen?
I don't because I currently only save HOW MANY sprites are in use, not where. I would have to implement some intelligence that assigns sprite numbers to objects, however that seems to be a bit complicated. I will look into that.

tokumaru wrote:
What's so bad about placing the sprites off screen?
Nothing, but I should have asked slightly different, as Bregalad wrote what I wanted to know :) So putting sprites at a given position makes the SNES not render them is what I understand.

@Bregalad
Thanks for your proposal but I think that won't be helpful to me as I'm using C, not assembler. However I implemented metasprites and wanted to test them when the flickering problem got in my way ;)


Top
 Profile  
 
 Post subject:
PostPosted: Sat Nov 28, 2009 10:48 am 
Offline

Joined: Sun Sep 19, 2004 11:12 pm
Posts: 20662
Location: NE Indiana, USA (NTSC)
AndiNo wrote:
I can write down what things I do in every frame, maybe that would make things a bit clearer. Besides that I have to say I'm not programming in assembler but in C (using the SNES SDK). I've read many posts which state that C is subordinate to assembler on the SNES, do you think that could be the (main) reason for my game running slowly?

C isn't necessarily slow. Compilers are slow because there isn't much of a market for compilers targeting 6502 family ISA because microcontrollers are either PIC or ARM nowadays. Also, use of data types too big for the CPU and operations that the CPU doesn't support natively is slow, such as multiplication, division, data-dependent rotation, or array-of-structure memory organization. C just hides that for you by making everything look like a PDP-11 from the programmer's perspective.

Quote:
btw: Is there a way to measure the time left before the vblank happens?

The Super NES has a scanline counter, doesn't it?

Quote:
And I read you can set the SNES clock from 2.68 to 3.xx MHz. I tried that as I guessed it could possibly make the CPU faster, but the flickering was worse

A lot of games OC the Super NES CPU to 3.6 MHz. This became more common as the faster ROMs needed for 3.6 MHz operation dropped in price.

Quote:
What can I do if ALL frames take more than one vblank to be completed?

You could always go the Micronics route of reducing the frame rate to 30 or 20 fps. A lot of Game Boy monochrome games like Pokemon ran at 30 fps to compensate for the original model's slow LCD, and it still doesn't look that bad on a Super Game Boy.

Quote:
I don't because I currently only save HOW MANY sprites are in use, not where.

If the first 16 sprites are in use, and this number drops to 13, kill 13 through 15. It should be simpler on the Super NES than on the NES because you don't have to worry as much about cycling, sprite 0 hit detection, or huge metasprites.

Quote:
tokumaru wrote:
What's so bad about placing the sprites off screen?
Nothing, but I should have asked slightly different, as Bregalad wrote what I wanted to know :) So putting sprites at a given position makes the SNES not render them is what I understand.

As long as they're vertically offscreen. Otherwise, they might contribute to the 100% overdraw limit per scanline.


Last edited by tepples on Sat Nov 28, 2009 10:51 am, edited 1 time in total.

Top
 Profile  
 
 Post subject:
PostPosted: Sat Nov 28, 2009 10:51 am 
Offline
User avatar

Joined: Sat Feb 12, 2005 9:43 pm
Posts: 10897
Location: Rio de Janeiro - Brazil
AndiNo wrote:
I'm not programming in assembler but in C

This makes a big difference I guess. C programs are never as fast as hand-coded assembly on these old processors. I wouldn't be surprised if a complex game with scrolling, many sprites and so on couldn't handle all its logic in a single frame.

Quote:
btw: Is there a way to measure the time left before the vblank happens?

In the NES we usually change something on the display, such as the monochrome bit, at the exact moment the frame calculations are over. I'm sure the SNES has something you can change mid-frame for a visual indication of how much time you have left. Of course that if your logic takes over one full frame, you'll see one frame without the visual indication and the next one will have it, because the first frame doesn't have any free time at all.

Quote:
What can I do if ALL frames take more than one vblank to be completed?

If you don't want to code it in assembly or optimize the hell out of it, embrace your new frame rate of 30 frames per second. It will not look as smooth, but if you move your objects twice as much they will appear to be moving at the same speed as before.

Quote:
I don't because I currently only save HOW MANY sprites are in use, not where.

Well, then I don't know how your sprite system works. You have to know which sprites you used if you want to move them, animate them and so on, don't you?

If the sprite remains after an object is destroyed this means the sprite was somehow hardwired to that particular object, and to me this means there must be some variable responsible for this link. Personally I prefer to not hardcode sprites, like I explain below.

Quote:
I would have to implement some intelligence that assigns sprite numbers to objects, however that seems to be a bit complicated. I will look into that.

Most games I studied (on the NES and Genesis/MD) completely reassign the sprites every frame. AFAIK, this is the most "professional" way to handle sprites.

In my (NES) game, every frame I loop through all the active objects so that each on can do their thing (move, shoot, whatever). When they are done, they draw themselves by calling the sprite rendering routine. This routine gets a pointer to the meta-sprite to use from the object's RAM (which could be anything the object put there, but usually the character animation routine maintains this value so that it points to the current animation frame) and uses the object's position to process the meta-sprite information and generate all the individual sprites necessary.

After all hardware sprites have been written, I put the remaining ones (the ones I didn't use) off screen, so that they are not displayed.

With this technique the objects don't know which hardware sprites were used, but they don't have to, because they are completely redrawn every frame. Also, once they are destroyed, they simply won't call the drawing routine anymore and will be 100% gone.


Top
 Profile  
 
 Post subject:
PostPosted: Sat Nov 28, 2009 11:10 am 
Offline
User avatar

Joined: Wed Dec 06, 2006 8:18 pm
Posts: 2827
About CPU Speed and SNES. The SNES CPU generally runs at 3.58mhz on Internal Operation Cycles like Register access. On cycles that access external memory like ROM, RAM, or SNES registers the speed of the bus changes. There is no way to make RAM access faster but if you use FastROM and enable it with the appropriate register, Banks above $80 will be accessed at FastROM speed giving some speed boost.

But it sounds to me like you need to figure out what all you have going on and see where you are spending too much time. FastROM can give you a small boost but you can't depend on that. Also contrary to what people may think or tell you, the SNES is pretty much never going to run 3.58mhz because your game will have to access memory that takes more cycles so your CPU reguardless of FastROM will be running between 2.68mhz and 3.58mhz and with usage of FastROM the average speed just gets to be a bit higher which is nice.

About sprites, I would agree that you should keep a counter of how many sprites you are using and when the number from the last frame to the new frame goes down you should set the range of previously used but now unused sprites to have a Y position below the screen. It's fast and to the point making the sprites out of the way. Don't set sprites to 0, it's better practice to set them below the screen. NTSC SNES normally runs for 224 lines of active video though to be safe you could always just set all the sprites to Y = 240.

If you want to always run at 30FPS you will need your NMI handler to count how many Vertical Blanks have happened since the previous video frame update. When two have happened it would be time to reset the counter and quickly update the video in the VBLANK time remaining. This would ensure you maintain 30FPS at maximum and reduce the slowdown effect of too much processing.

About flickering, this could happen if you are out of time in VBLANK. If you run out the remaining transfers will be ignored or corrupted. You need to be very efficient with your VBLANK time. Flickering normally will only happen if you have too many sprites on the same scanline and you are cycling the sprite order. If you are not then sprites over 34 (total 8x8 units) simply aren't drawn. SNES has registers that let you change sprite priority without changing the software order you put sprites together with. But if you layer sprites for a reason you will need to do it in software or check things atleast.

As far as what code you are executing you should make sure that VBLANK time is first spent doing any video updates. Nothing should come before this. It's the only time you get to change the video frame. If your processing isn't complete yet you just simply don't update the video at all and resume processing and hopefully you will be ready next time around. Other than that you just need to make choices about how you process each game frame. You only have whatever VBLANK time remains plus all active scanlines' time (minus WRAM refresh and HDMA if using it) to process all your game logic and prepare the video update for the next VBLANK. Perhaps something in your design just eats up way too much time.

tokumaru, I'm not so sure that C is the problem for his speed. It may be partly responsible but even C code can be wasteful of cpu time due to how it is written not just because it is C and not ASM. Going 30FPS certainly is an easy way to gain alot more processing time though.


Top
 Profile  
 
 Post subject:
PostPosted: Sat Nov 28, 2009 12:55 pm 
Offline
User avatar

Joined: Wed Nov 25, 2009 5:06 am
Posts: 37
Big thanks guys, your posts make for a VERY interesting read! I already gained some new insight in the whole SNES-tech. I will revise my code to find the slowdowns, I guess I assumed too much power when writing the code (coding for todays PCs has its impact on me ;) ).
Then only one thing remains: Could you (like tepples partially did) write a short summary of which operations are costly CPU-time-wise? i.e. is comparing two numbers more expensive than adding etc... I think this would prove to be a help when revising the code - of course only if it makes a difference and not only my code is written badly :)


Top
 Profile  
 
 Post subject:
PostPosted: Sat Nov 28, 2009 1:20 pm 
Offline
User avatar

Joined: Sat Feb 12, 2005 9:43 pm
Posts: 10897
Location: Rio de Janeiro - Brazil
AndiNo wrote:
Could you (like tepples partially did) write a short summary of which operations are costly CPU-time-wise?

The only individual thing I can think of that tepples didn't mention is floating-point numbers. Don't use them, stick to integers and use fixed-point if you really need fractional values.

I guess it's obvious that most of the time is spent in loops, so you should try to optimize/avoid those as much as possible. If you are modifying only a few elements of an array, modify each one explicitly instead of using a loop.

Also, don't bother clearing values that will be overwritten (like I mentioned I do in my sprite system, I just place off screen the sprites that weren't used, instead of clearing them all before rendering any sprites).

I'll let you know if I think of anything else.


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

All times are UTC - 7 hours


Who is online

Users browsing this forum: Markos11 and 3 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