Author |
Message |
- Joined: 05 Sep 2013
- Posts: 4033
- Location: Stockholm, Sweden
|
Posted: Tue Jan 21, 2025 8:23 am
|
willbritton wrote Ah, yeah sorry I was having a senior moment. Of course it works because left scroll will always make the fine pixel value smaller unless a column boundary is crossed, and vice-versa.
oh wait, indeed there's an issue when (old_scroll % 8) is already 0...
so, it should be
- when (old_scroll % 8) is zero (because we're needing a new column for sure if it is)
OR
- when (new_scroll % 8) is not zero and it's < than (old_scroll % 8)
the good thing here is that any unsigned variable % 8 is just an AND 0x07 operation so it doesn't really require any function to perform the division, so the above check is very light.
|
|
|
- Joined: 03 Dec 2021
- Posts: 82
- Location: Italy
|
Posted: Tue Jan 21, 2025 8:56 am
|
sverx wrote willbritton wrote Ah, yeah sorry I was having a senior moment. Of course it works because left scroll will always make the fine pixel value smaller unless a column boundary is crossed, and vice-versa.
oh wait, indeed there's an issue when (old_scroll % 8) is already 0...
so, it should be
- when (old_scroll % 8) is zero (because we're needing a new column for sure if it is)
OR
- when (new_scroll % 8) is not zero and it's < than (old_scroll % 8)
the good thing here is that any unsigned variable % 8 is just an AND 0x07 operation so it doesn't really require any function to perform the division, so the above check is very light.
Thanks @sverx for the suggestions, I have already started to play with it yesterday with some decent (still buggy) results, but I am definitely coming back to this. Indeed, that OR would have probably fixed the bug I was getting yesterday :)
I will let you know about the outcome when I have some time to code.
Cheers!
|
|
|
- Joined: 03 Dec 2021
- Posts: 82
- Location: Italy
|
Posted: Thu Jan 23, 2025 4:18 pm
|
Yes (ops), I did it again! :)
Of course, I wouldn't have done it without your help, so super thanks once again!
I basically implemented @sverx's suggestions for the RIGHT check and tried to reverse the logic for the LEFT, and finally got it working.
As expected, it is working for an increase/decrease of 1 to 7 pixel(s) per frame. For reference, you can find the updated code at the bottom of this message.
As a next step, I think I will implement sprite animation. Right now I just placed the Sonic sprite at the centre of the screen. In this next phase I plan to keep it centered, but animate it as I move the screen towards left or right (I know we cannot flip the sprites in SMS).
Any suggestion on how frequent should I alternate them (e.g. each frame, every N frame)?
Many thanks again!!!
UPDATED CODE
#include "SMSlib.h" // we're including the library with the functions we will use
#include "bank2.h" // we're including the assets we created before
#define BG_TILES 0
#define BG_WIDTH 96
#define BG_HEIGHT 28
#define TILEMAP_WIDTH 32
#define TILEMAP_HEIGHT 28
#define SPRITE_TILES 256
#define SPEED 3
unsigned int old_scroll = 0;
unsigned int new_scroll = 0;
unsigned char playerPosition[2] = {(TILEMAP_WIDTH * 8) / 2, (TILEMAP_HEIGHT * 8) / 2};
void loadAssets(void)
{
SMS_loadPSGaidencompressedTiles(field__tiles__psgcompr, BG_TILES);
for (int i; i < TILEMAP_WIDTH; i++)
SMS_loadTileMapColumn(i, 0, &field__tilemap__cmraw[i * TILEMAP_HEIGHT], TILEMAP_HEIGHT);
SMS_loadBGPalette(field__palette__bin);
SMS_loadPSGaidencompressedTiles(sprites__tiles__psgcompr, SPRITE_TILES);
SMS_loadSpritePalette(sprites__palette__bin);
}
void drawPlayer(void)
{
SMS_addSprite(playerPosition[0], playerPosition[1], SPRITE_TILES);
SMS_addSprite(playerPosition[0] + 8, playerPosition[1], SPRITE_TILES + 2);
SMS_addSprite(playerPosition[0] + 16, playerPosition[1], SPRITE_TILES + 4);
SMS_addSprite(playerPosition[0], playerPosition[1] + 16, SPRITE_TILES + 6);
SMS_addSprite(playerPosition[0] + 8, playerPosition[1] + 16, SPRITE_TILES + 8);
SMS_addSprite(playerPosition[0] + 16, playerPosition[1] + 16, SPRITE_TILES + 10);
}
void main(void)
{
unsigned int ks;
SMS_setSpriteMode(SPRITEMODE_TALL);
loadAssets();
SMS_VDPturnOnFeature(VDPFEATURE_LEFTCOLBLANK); // hide the leftmost column
SMS_displayOn();
for (;;)
{
SMS_initSprites();
drawPlayer();
SMS_waitForVBlank();
SMS_finalizeSprites();
SMS_copySpritestoSAT();
ks = SMS_getKeysStatus();
if ((ks & PORT_A_KEY_RIGHT) && (old_scroll < (BG_WIDTH - TILEMAP_WIDTH) * 8 - SPEED))
{
new_scroll += SPEED;
if (((old_scroll % 8) == 0) || (((new_scroll % 8) != 0) && ((new_scroll % 8) < (old_scroll % 8))))
{
SMS_loadTileMapColumn((TILEMAP_WIDTH + (new_scroll / 8)) % TILEMAP_WIDTH, 0, &field__tilemap__cmraw[(TILEMAP_WIDTH + (new_scroll / 8)) * TILEMAP_HEIGHT], TILEMAP_HEIGHT);
}
old_scroll = new_scroll;
SMS_setBGScrollX(-old_scroll);
}
else if ((ks & PORT_A_KEY_LEFT) && (old_scroll > 0))
{
new_scroll -= SPEED;
if (((new_scroll % 8) == 0) || (((old_scroll % 8) != 0) && ((old_scroll % 8) < (new_scroll % 8))))
{
SMS_loadTileMapColumn((TILEMAP_WIDTH + (old_scroll / 8)) % TILEMAP_WIDTH, 0, &field__tilemap__cmraw[(old_scroll / 8) * TILEMAP_HEIGHT], TILEMAP_HEIGHT);
}
old_scroll = new_scroll;
SMS_setBGScrollX(-old_scroll);
}
}
}
|
|
|
- Joined: 06 Mar 2022
- Posts: 709
- Location: London, UK
|
Posted: Thu Jan 23, 2025 4:51 pm
|
umbe1987 wrote
Any suggestion on how frequent should I alternate them (e.g. each frame, every N frame)?
Well maybe try it out and see how it looks?
But commonly you would animate every frame unless performance constraints force you to alternate different tasks across frames. That's really because it's just most straightforward to do the same procedure every frame tick since it's the logical unit of time in these projects. Of course it does require you to make more frame assets which might be a pain!
Slow movements animated over every other (every 2) frame might not be perceptible, but very fast ones or ones with relatively big displacement can look slightly juddery to keen eyes. Slowing the animation down to every fourth frame will almost certainly start to appear to be discrete movements.
EDIT: of course even if you animate every frame you can choose to repeat or reuse frame assets if you don't need fine movements.
|
|
|
- Joined: 05 Sep 2013
- Posts: 4033
- Location: Stockholm, Sweden
|
Posted: Thu Jan 23, 2025 5:27 pm
|
umbe1987 wrote I think I will implement sprite animation. Right now I just placed the Sonic sprite at the centre of the screen. In this next phase I plan to keep it centered, but animate it as I move the screen towards left or right (I know we cannot flip the sprites in SMS).
Any suggestion on how frequent should I alternate them (e.g. each frame, every N frame)?
Not an easy question at all. A friend working in traditional animation for the movies (24 frames a second) once told me that high quality productions had a 1:1 ratio - which meant one different frame drawn for each screen frame, so a one second animation would need 24 drawings, but often the norm in the industry was 2:1 'half', so the same drawing would be reused for two screen frames, requiring only 12 drawings for a second. Usually it works well 'enough'.
Back to our SMS world, we have the screen updating either 50 or 60 frames per second, depending on the specific hardware, so you probably might want a different image every second frame (25 or 30 fps animation) or every third frame (16.6 or 20 fps animation) or every 4th frame (12.5 or 15 fps animation) or even only every 5th frame (10 or 12 fps animation).
If we're talking about moving sprites around, you probably want to aim for updating their position at each screen frame, as our brain easily perceive if we're not moving them smoothly.
|
|
|
- Site Admin
- Joined: 19 Oct 1999
- Posts: 15022
- Location: London
|
Posted: Thu Jan 23, 2025 6:39 pm
|
Agreed - it would be extremely unusual to animate art at 60fps but not at all unusual to animate sprite positions at 60fps. The former would require tile streaming on every frame, which would take resources from other aspects of the game, but the main reason is that it's a huge amount of artist work and ROM space with diminishing returns.
You can compare the animation in Sonic Mania to that in the Mega Drive Sonic games, for example, and I think that's still not 60fps.
|
|
|
- Joined: 06 Mar 2022
- Posts: 709
- Location: London, UK
|
Posted: Thu Jan 23, 2025 6:59 pm
|
Yes, sorry, reading back I think I clumsily conflated the two, I was really talking about movement resolution, i.e. how often umbe should service the sprite table, and if I implied that having 60 art frames per second was something to remotely consider then I shouldn't have done!
Obviously, classic cinema runs at 24fps and that looks just fine.
|
|
|
- Site Admin
- Joined: 19 Oct 1999
- Posts: 15022
- Location: London
|
Posted: Fri Jan 24, 2025 7:22 am
|
Honestly I wish I had the art skills to make a 60fps art mod of certain games to see how it would look. Outside of “pre-rendered 3D” art style I guess it would be quite hard to do.
|
|
|
- Joined: 05 Sep 2013
- Posts: 4033
- Location: Stockholm, Sweden
|
Posted: Fri Jan 24, 2025 8:34 am
|
Maxim wrote You can compare the animation in Sonic Mania to that in the Mega Drive Sonic games, for example, and I think that's still not 60fps.
Not to derail this topic completely, but what's the animation rate (fps) SMS games typically use? Do we have this information already?
|
|
|
- Joined: 16 May 2002
- Posts: 1386
- Location: italy
|
Posted: Fri Jan 24, 2025 9:29 am
|
I also don't want to derail this topic, but there are a few animations which play at real 50/60 fps in the 16-bit Sonic games, for example when you run at full speed, there's a new frame of running animation for every frame of screen update. Aside from that, and from the centisecond timer in certain game modes, yeah, most animations duplicate frames (or more).
|
|
|
- Joined: 09 Jun 2014
- Posts: 421
|
Posted: Fri Jan 24, 2025 10:30 am
|
If you can watch the animation frame by frame then you count how long one frame of animation takes.
You can use Emulicious and pause the game, then press spacebar to advance one frame.
Or get a 60fps movie of gameplay and play it with a video player or editor that can play frame by frame.
Sonic on the SMS running at full speed changes animation frame every 4 frames.
Slowest walking speed is about 8 frames. I think it will speed up when walking faster but that is hard to figure out. I guess it will speed up to 4 frames.
I've also looked at Sonic on the Megadrive/Genesis and looks like the running animation changes every 3 frames.
So the SMS is a little slower and choppier. I don't know if that was due to constraints or a choice.
The SMS has the same amount of animation as the Megadrive/Genesis though. That is 6 walking frames and 4 running frames.
|
|
|