Sign in to follow this  
brasslips2

2D viewport scrolling in window mode

Recommended Posts

I'm trying to figure out how to scroll my viewport similar to that in warcraft 3 where once the mouse reaches or goes past the client viewport it will scroll the screen in that direction. Currently, I am getting the cursor postion like this... case WM_MOUSEMOVE: { //.. MousePosition = MAKEPOINTS( lParam ); //.. } However, the problem with this is that if the cursor goes past the client viewport then the position stops updating at the maximum or minimum of the client window. For instance if the client window is 1024 wide and if my cursor should technically be at 2000 then MousePosition will only think the cursor is at maybe 1024 or a little less. But once the cursor moves back into the client rectangle it updates fine. So my question is how do i know when to scroll the screen if i can never get coordinates that are negative or greater than that of the window dimensions? [Edited by - brasslips2 on November 12, 2009 2:21:16 PM]

Share this post


Link to post
Share on other sites
MAKEPOINTS is a macro defined in WinGDI.h I guess a more specific question would be how do you get the global mouse position in respect to the (0,0) coordinate of the client rect?

Share this post


Link to post
Share on other sites
Simply:

if( mouse.x == 0 )
scroll.x -= value;
else if( mouse.x == SCREEN_WIDTH-1 )
scroll.x += value;

if( mouse.y == 0 )
scroll.y -= value;
else( mouse.y == SCREEN_HEIGHT-1 )
scroll.y += value;


The scene scrolls with a constant speed no matter how "fast" you try to move the mouse.
You don't have to handle the outer positions at all. If you scroll like this in an RTS, you can see that the mouse never leaves the client area, it "sticks" on it's borders.
If you are in windowed mode, it doesn't matter if the positions aren't updated, because you have to scroll with constant speed, even if you don't move the mouse at all, after you reached the edges (like in any RTS scrolling.)

Or if you have some kind of controls, menus at the edges, than you have to define areas, where you want the scrolling to happen. If you have menu on the top, and other controls on the bottom for example:

if( mouse.y > bottom_scroll_control_area.bottom 
&& mouse.y < bottom_scroll_control_area.top )
scroll.y -= value;
else if( mouse.y > top_scroll_control_area.bottom
&& mouse.y < top_scroll_control_area.top )
scroll.y += value;


These areas are say 10 pixels "tall".

This all stuff requires, that you handle the scrolling in your game loop, not in the window message thing, the scrolling will be continuous, even if you don't move the mouse.

It works like this in Warcraft for example. It even has a "bug":
If you open the menu with hotkey while scrolling with the mouse, and save the game, after it saved it, the screen will scroll, regardless where the mouse is, it only stops, when you move the mouse (so it's position updates in the game loop, while it didn't update in menu mode).

I hope that made sense.

Share this post


Link to post
Share on other sites
Sorry, I was wrong, RTS games only scroll when the mouse is at the edge, so the first code in my previous post is to be used. Or if you have windowed mode, you could use long buttons too at the edges. If you push, you scroll, maybe it's a better solution, because it wont begin scrolling, if you move the mouse to the edge accidentally.

Share this post


Link to post
Share on other sites
Well my concern was with window mode. Because if your mouse pos is at (100,100) and you move your mouse really fast in a positive horizontal direction outside of the client rectangle then you'd think your mouse pos would be at 2000,100 but in reality the macro on returns 100,100 because it is outside of the rectangle and the message was too big of a jump. Is there any way to deal with this issue? Making the mouse never be able to go outside of the client rec would probably fix this. But the question would be how do you even limit the mouse to do that in window mode? Maybe that's why games don't allow you to scroll the viewport when in window mode... fullscreen sounds like the only option...

Share this post


Link to post
Share on other sites
Or the other thing I mentioned, about the button thing:
image

So it scrolls, when you push the button (and keep it pushed) (red and green areas).

Of course, these buttons don't have to be windows GUI buttons, just draw something there to notify the user, that these are buttons to scroll.

Restricting to the window is meaningless, the user would want to click outside, because it's windowed. If full screen, no problem.

But there are tons of gurus in this forum, maybe there's a way to get mouse events even if it leaves the client area, because the window itself stays in focus. You could try to use GetCursorPos instead of message handling. It must return some value.

Share this post


Link to post
Share on other sites
Don't wait until the mouse has left the viewport - at that point you're reacting too late. Instead, check if the cursor is in a region close to the sides, and move the camera accordingly. Keep in mind that if you keep those regions too small, you're going to frustrate players who aren't running your game full-screen.

The border-scrolling doesn't work too well for games that aren't full-screen, from a design perspective. Even in full-screen games, I often find that it gives me too little control over the camera. It's not precise enough imho.


Alternatives would be to use the arrow keys (good for keyboard + mouse control!) or to scroll the map while a mouse-button is held down and the mouse is moving (allows for fast and precise camera control). Whatever works best for your game. You'll probably want to provide multiple methods for different kind of players.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this