Hello,
I've been talking to Tokumaru a lot recently about the players movement inside screens/name tables. I'd just like to get some other opinions on how others are handling this situation. I'm currently working on a side scroller with two screens right now (starting small). I'd like to have my character start out at the beginning of NT0 and once the character reaches 128 (middle of the screen) stay there until it reaches 384 (in NT1) where the background will stop scrolling and the character will walk to the end of the screen. I had done some testing with comparing when the hotspot my character was > 128. Once the character reached 128 I just stopped updating the sprites tiles on the screen but kept the animation going and the coordinates of the player on the screen updating. This worked out okay except for when the player goes in the opposite direction. The sprite tiles then update to the coordinates of the last position of the previous location on the screen. So the player just "jumps" to that coordinate (in the wrong direction).
So anyway, what advice can you give me about keeping the character in the middle of the screen during movement except when they reach the ends of the screen?
Thanks!
This is what I do for my games (not for NES, but it should still work for NES):
Keep vars for X scroll, Y scroll, X,Y position of player -- in addition to Sprite data which is to be DMA'd
C-esque psuedo code to give the idea:
Code:
X_scroll = X_player - 128;
if(X_scroll < X_min)
X_scroll = X_min;
if(X_scroll > X_max)
X_scroll = X_max;
Sprite_X = X_Player - X_scroll;
// ditto for Y
All enemies and other sprites will need to be adjusted according to X and Y scroll of course, but that's something you'd have to do anyway.
With your example of only having 2 screens, X_min would probably be 0, and X_max would proably be 256.
The '128' here could probably be better adjusted to center the player better. The actual value you should probably use would be:
(256 - player_width) / 2
Disch wrote:
Code:
X_scroll = X_player - 128;
if(X_scroll < X_min)
X_scroll = X_min;
if(X_scroll > X_max)
X_scroll = X_max;
Sprite_X = X_Player - X_scroll;
// ditto for Y
Hi Disch!
Thanks for your response. This maybe a dumb question but what exactly is your Sprite_X for? The position of the sprite tile on the screen? (X value)
The position of the player's sprite(s). I do not mean to butt in, but that's basically what I told you... =)
I guess Disch can explain it more directly, though...! =)
tokumaru wrote:
The position of the player's sprite(s). I do not mean to butt in, but that's basically what I told you... =)
I guess Disch can explain it more directly, though...! =)
Yep, you're right. I believed you the whole time, just wanted to see what others were doing
I'm kidding... You are more than right to ask more than one opinion... they just happend to coincide this time! =)
I agree with Dish.
Your game engine should be able to totally sparate the position of the player in the level, and the part of the level that is shown on the screen, even if the second varies in function of the first.
I like to have scrolling totally separated from player movement. The physics has priority, meaning the game is technically playable, even if nothing is displayed on the screen.
Then, when the graphics routines are added they have to "watch" the player, to implement scrolling and proper rendering.
Of course I don't actually do it like this, it would be really boring to implement the physics with no display at all, but the concep is still the same in the end: the physics engine is completely independent from rendering, and the camera (scrolling position) acts based on player's movement, wich it constantly watches.
Guys, maybe you can tell me what you think about this.
While talking to lynxsolaris, it was decided that he would use the following method for scrolling the levels:
-the level map is stored in the form of consecutive columns, for easier rendering;
-whenever the "camera" completes 16 pixels of movement (the size of a metatile), a new column of metatiles is to be rendered;
-if the camera was moving left, the index of the column to render is X_scroll/CameraX/whatever divided by 16;
-if the camera was moving right, the index is X_scroll divided by 16 + 16;
-the destination address of the column in the name tables is also defined by these values, where the 5th bit defines the name table and the other 4 define the column;
Now, if he was to use a formula (such as the one Disch suggested) for the location of the camera, that would mean the scroll is not directly manipulated, but is calculated from another value. What would you say is the best method to detect when the 16 pixels have gone by? Keeping a copy of the old X_scroll and comparing it to the new one? The bits after the first 4 would be the interesting ones to compare, as depending on wich (old or new) is greater we know if the camera moved left or right. I they are equal, there is no need to draw a new column.
I'd do something like this. What do you think?
tokumaru wrote:
What would you say is the best method to detect when the 16 pixels have gone by? Keeping a copy of the old X_scroll and comparing it to the new one? The bits after the first 4 would be the interesting ones to compare, as depending on wich (old or new) is greater we know if the camera moved left or right.
Easy enough:
Code:
lda oldXScroll
eor newXScroll
and #%11110000
beq @notChanged
jsr updateMetaTile
@notChanged:
But you also gotta check if the column to update is at the left or at the right. For that you'll have to check wich value (old or new) is bigger. So maybe it'd be better to make a direct comparison?
I guess this could work:
Code:
lda newX
and #$F0
pha
cmp oldX
beq NoUpdate
;set up column index
bcc UpdateLeft ;skip addition if updating the leftmost column
;add 16 to the column index
UpdateLeft:
;render the column to a buffer
NoUpdate:
pla
sta oldX
;go on with logic
That was so so so quickly written... it may have errors...
And what about scrooling like in Sonic games? The camera is not "attached" to the player, it tries to follow the player, but it moves on it's own. I played Sonic for years, but until this day I can not properly describe the behaviour of that camera. Wich means I'd probably have trouble implementing it in case I wished to.
I really like the camera in Sonic. It tries to give you the best view of the surroundings, without beeing one of those annoying cameras that try to predict your actions. Like when you are facing left and right when you turn right the camera moves a lot to the right to show what's in front of you. That's a bit annoying.
I never played paying much attention to that, though. Maybe if I spend some time with the game and keep the camera in mind, I might figure something out.
tokumaru wrote:
Like when you are facing left and right when you turn right the camera moves a lot to the right to show what's in front of you. That's a bit annoying.
It's also annoying in real life. Turn your head by 180 or even 90 degrees and you get a completely different scene.
Quote:
It's also annoying in real life. Turn your head by 180 or even 90 degrees and you get a completely different scene.
But in real life we're given separate controls over camera (head) and movement (legs). Think of the
Torchlight Trouble level in
Donkey Kong Country, where Squawks carries the lamp and switches which side of the screen is illuminated every time you change direction, complete with a bright flash as the lamp shines directly at the player during each switch. Playing that level requires minimization of direction changes, perhaps an intentional challenge from the designers.
tokumaru wrote:
And what about scrooling like in Sonic games? The camera is not "attached" to the player
Sonic scrolling style is what I call "slack" scrolling. It doesn't make the camera rigid to Sonic, rather, it keeps Sonic within a designated rectangle on the screen. When Sonic leaves that rectangle, the screen scrolls in the appropriate direction to keep him in the rectangle. This actually works out to be a little worse than "attached" or "rigid" scrolling (the method I previously described) in some situation, but better in others.
Although the Sonic engine is tricky in that it allows Sonic to actually leave the rectangle if he's going too fast for the drawing to keep up. Rather than doing what's intuitive and just slowing Sonic (and the whole game) down until the drawing can keep up.
Sonic in paticular gives lots of vertical slack (Sonic can get high on the screen, or low on the screen before the screen will actually start scrolling), but doesn't give much horizontal slack (Sonic is stuck pretty close to center at all times). This works well for flat areas, so that when you jump, the ground you're trying to jump to is less likely to scroll off the bottom of the screen. However it ends up being worse for falling long distances or moving upwards long distances since you're very close to the screen edge in both cases.
Some NES games have slack scrolling with lots of Horizontal slack which is just AWFUL. Wai Wai World comes to mind -- you have to get right up to the edge of the screen before it starts scrolling -- making it very difficult to see what you're walking into. I think Goonies 2 has a little more horizontal slack than I'd like, too... but it's not nearly as bad.
Accomplishing slack scrolling is a bit more complex than rigid scrolling. To give the idea (this could probably be improved/optimized a lot, especially with use of constants):
Code:
draw_x = player_x - scroll_x;
if(draw_x < (centerscreen_x - x_slack))
scroll_x = player_x - (centerscreen_x - x_slack);
else if(draw_x > (centerscreen_x + x_slack))
scroll_x = player_x - (centerscreen_x + x_slack);
if(scroll_x < x_min) scroll_x = x_min;
if(scroll_x > x_max) scroll_x = x_max;
//ditto for y
I usually stick to rigid scrolling because it's easier. Though really, I prefer a sort of "preemptive" scrolling. Much like the type of scrolling tokumaru didn't like -- except the way I'd impliment it is that it would only scroll left when you MOVE left (rather than just face left). So that when you're moving left, the screen gradually scrolls so that your player gets closer to the right-hand side, showing more of what's to your left.
Most 2d games also use simple damping on the camera movement. I observed one of the sonic games doing it, stole it and used it on pretty much every 2d camera i worked on.
Code:
; focus pos puts player in exact center
; of the viewport
focus_x = player_x - screen_width / 2;
focus_y = player_y - screen_height / 2;
; [ you can do a slack check here if you
; are making a laggy camera, omitted
; here for brevity]
; calc the difference from current pos,
; and use a fraction of that difference.
; this smooths out the camera movement.
; hopefully, your values have at least 2 bits
; of fixed-point fraction here. ;)
diff_x = (focus_x - scroll_x) / 4;
diff_y = (focus_y - scroll_y) / 4;
; clamp
if (diff_x > 0) diff_x = min(diff_x, min_x);
else diff_x = max(diff_x, -min_x);
if (diff_y > 0) diff_y = min(diff_y, min_y);
else diff_y = max(diff_y, -min_y);
; set
scroll_x += diff_x;
scroll_y += diff_y;
Disch, your code seems to explain well what's going on. The window that Sonic has is indeed pretty narrow. And although it is quite tall, the camera tries to keep Sonic centered while he's on the ground. Maybe that's the trick?
Also, Sonic's position doesn't seem to have a direct influence on the position of the screen. I feel like the screen has it's own speed, wich is what Sonic affects, and is what allows him to move faster than the camera.
I though about the window approach before, but never tried it, thinking it would be bad to have more stuff behind you than in front of you. But if it is done like in Sonic, where the window is so narrow, it looks and feels ok. Also, as most of the Sonic action is left-to-right, I get the feel that the window is not exactly centered, it is placed a bit towards the left, leaving a larger visible area at the right, wich is where you'll usually be heading to.
baisoku, a quick scan through your code hasn't allowed me to understand it yet. I'm kinda sleepy now, I'll try to look at it again tomorrow.
tokumaru wrote:
Sonic's position doesn't seem to have a direct influence on the position of the screen. I feel like the screen has it's own speed, wich is what Sonic affects, and is what allows him to move faster than the camera.
Yes, the screen in
Sonic the Hedgehog 2 has a maximum speed, and that is 2 rows of 8x8 pixel tiles in each dimension.
tepples wrote:
Yes, the screen in Sonic the Hedgehog 2 has a maximum speed, and that is 2 rows of 8x8 pixel tiles in each dimension.
Wich allows us to achieve Sonic-like speeds on the NES. Even if moving on both axes. Of course, the complexity of any current events may slow it down, like the number of enemies on the screen and such, but technically, it is possible to have a smooth Sonic game (unlike the glitchy pirates Somari and Jurassic Boy) on the NES.
I plan to prove that one day, making a decent port of Sonic (still a pirate, though). Of course, a direct port would be boring, so I have to think of something new. Oh well...
Draw a different anthropomorphic woodland creature and make a run cycle. Then you can make your own Sonic clone without having it be a "pirate original".
But then it's just lame...... =)
For some odd reason, a fan-game of an existing series feels much less lame than an obvious copy disguised to look like an original idea.
EDIT: There are thousands of Sonic games made with "Click N' Play" styled tools, and even some that were actually programmed, and they are never referred to as "pirate originals". Does the fact that these games are not made for profit change anything?
tokumaru wrote:
But then it's just lame......
Be lame or be sued. Remember what happened to
The Great Giana Sisters?
Quote:
There are thousands of Sonic games made with "Click N' Play" styled tools, and even some that were actually programmed, and they are never referred to as "pirate originals".
Only because the developer of the original game hasn't referred to the clones as such. (And yes, I'm familiar with Clickteam's tools.)
tepples wrote:
Be lame or be sued. Remember what happened to The Great Giana Sisters?
Actually I don't. I barelly know the game. Was the similarity to SMB enough to give any trouble to the peoplewho made this game?
Quote:
Only because the developer of the original game hasn't referred to the clones as such. (And yes, I'm familiar with Clickteam's tools.)
Oh well... About the tool, I said "styled" 'cause I think there are others around, I'm not familiar with the people who make them.
Anyway, having a game with characters named "Phonic", "Nails" and "Buckles" would not be enough to escape from a law suit, huh? I'd kinda like to use those names... =)
I wrote a simple
SDL based scrolling demo in C. It shows four algorithms. Only the source is included, so you'll have to build it for your machine (post a Windows build if you make one). I wrote the source code such that it serves as a good shell for developing more scrolling algorithms.
scrolling_algos.zip
It includes one I like the most, which keeps the player near the left or right side of the screen based on the direction he's facing, but doesn't scroll unless the player is moving. It also gives the player some "wiggle" room before scrolling, so he can be moving one direction (with scrolling), then reverse direction and move a bit without scrolling the other direction.
edit: updated link
tokumaru wrote:
tepples wrote:
Be lame or be sued. Remember what happened to The Great Giana Sisters?
Actually I don't. I barelly know the game. Was the similarity to SMB enough to give any trouble to the peoplewho made this game?
Yes. Wikipedia tells all.
blargg wrote:
I wrote a simple
SDL based scrolling demo in C. It shows four algorithms. Only the source is included, so you'll have to build it for your machine (post a Windows build if you make one). I wrote the source code such that it serves as a good shell for developing more scrolling algorithms.
Win32 binary (Requires SDL.dll and run-time data from blargg's archive)
Thanks for the binary. I used to think that the algorithm that moves the camera to show more stuff in front of you was annoying, but the one that does the same thing, but only when you're moving felt worse. It gives a certain feel of interruption...
If you are moving to the same side most of the time, the Sonic-type of camera feels good. Although the window in this demo was a bit large in my opinion.
It was nice to get a direct comparison of algorithms. I missed trying the vertical scrolling along with the horizontal, though.