2D Game Scrolling in AS3 (my very early implementation)
A few weeks ago I started work on a new game as a hobby project… unfortunately I also started playing A LOT of Company of Heroes on the PC, so progress on the programming has been slow, very, very slow.
But I did write at least one useful piece of code that I think some people might find useful: Level Scrolling.
When I was working on my first Flash 2D platform engine Sprocket (game was never finished). I found one of the biggest problems was having the level scroll properly. So this time when I started writing the game engine, scrolling was the first thing I nailed down.
In Sprocket I found that scrolling with the Character locked in the center of the screen was unsatisfactory as enemies could easily sneak up behind you. So I developed a system where the mouse controls the user’s view. I was inspired by the scrolling in PC games such as Abuse, and Soldat.
In my new game I’ve created a LevelDisplay class which handles all scrolling work automatically. Just tell the LevelDisplay what game sprite to focus on and it will handle the rest.
Keep in mind all of this code is very early, so please don’t just plonk this in your game. Once I’ve built an actual game I’ll have a better idea of how successful my implementation actually is. But for now I’ll share what I have and maybe you can get some use out of it.
Use the right and left arrow keys to move the game character. Use your mouse to control the view. The pink dot represents the scrolling target. There is NO hit detection in this demo.
Initiatize LevelDisplay like so:
theLevel = new LevelDisplay(screenBounds, levelBackground); theLevel.registerBounds(new Rectangle(0, 0, levelBackground.width, levelBackground.height)); gameCharacter = new Character(); theLevel.addToDisplay(gameCharacter); theLevel.setCameraFocus(gameCharacter, true); addChild(theLevel); this.addEventListener(Event.ENTER_FRAME, onTick);
There are two constructor arguments:
1) A Rectangle which defines the size of the swf display (this contains the scrolling to the confines of the screen) and
2) An image to display in the background.
I define the level boundaries with registerBounds()
I create a new game character and add it to the Level display with addToDisplay().
Then, I tell Level to focus on the character with setCameraFocus(). Setting the second argument to true enabled mouse scrolling.
In an ENTER_FRAME event method I update the display with:
gameCharacter.characterTick(); theLevel.positionStage();
This just tells the character to update his position if there are keyboard inputs and tells LevelDisplay to change the display based on the character and mouse position.
Here is all of the actual scrolling code.
public function positionStage():void { var mousePoint:Point = MouseKeyboardCapture.mousePoint; var relativeMouseX:Number = mousePoint.x - levelGraphics.x; var relativeMouseY:Number = mousePoint.y - levelGraphics.y; var mDX:Number = relativeMouseX - _focusOn.x; var mDY:Number = relativeMouseY - _focusOn.y; var mDist:Number = Math.sqrt(mDX * mDX + mDY * mDY); var mVX:Number = mDX / mDist; var mVY:Number = mDY / mDist; // if (mDist > mouseOutMax) { mDist = mouseOutMax; } var scrollDist:Number = scrollOverLimit * (mDist / mouseOutMax); if (mouseFollowDebug) { followMouseTest.x = _focusOn.x + (mVX * scrollDist); followMouseTest.y = _focusOn.y + (mVY * scrollDist); } if (_focusOn != null) { var scrollTargetX:Number; var scrollTargetY:Number; if (followMouse) { scrollTargetX = -_focusOn.x + (_screenBounds.width / 2) - (mVX * scrollDist); scrollTargetY = -_focusOn.y + (_screenBounds.height / 2) - (mVY * scrollDist); } else { scrollTargetX = -_focusOn.x + (_screenBounds.width / 2); scrollTargetY = -_focusOn.y + (_screenBounds.height / 2); } if (scrollTargetX > _scrollBounds.x) { scrollTargetX = _scrollBounds.x; }else if (-scrollTargetX > _scrollBounds.width - _screenBounds.width) { scrollTargetX = -(_scrollBounds.width - _screenBounds.width); } if (scrollTargetY > _scrollBounds.y) { scrollTargetY = _scrollBounds.y; } else if ( -scrollTargetY > _scrollBounds.height - _screenBounds.height) { scrollTargetY = -(_scrollBounds.height - _screenBounds.height); } levelGraphics.x += (scrollTargetX - levelGraphics.x) * SCROLL_EASE_SPEED; levelGraphics.y += (scrollTargetY - levelGraphics.y) * SCROLL_EASE_SPEED; } }
Lines 2-9:
Here I find the deltas and vectors to the mouse cursor.
Lines 11-14:
I set a cap for the scrolling distance. This makes sure the screen doesn’t scroll too far out. Then I decide how far out from the character the screen will scroll.
Lines 15-18:
I update the position of the little pink dot, this is just for testing/visualization purposes.
Lines 22-28:
I set the position of the screen. If followMouse is set to true I center on the character position PLUS the mouse scroll value found earlier. If the variable is false I just focus on the character and don’t take into account mouse scrolling.
Lines 29-38:
Make sure that target is within the confines of the screen. If I’m scrolling out side of the screen I reset the target here.
Lines 39-40:
Here is where I actually move the screen Sprite. I ease the screen to it’s target. I find that eased movement is much less jarring than eased movement.
I suppose that’s it. As I’ve stated earlier, this is very early code and I’m sure there are a bunch of problems I haven’t discovered yet. Still, I hope you’ve found it helpful.
You may also find the MouseKeyboardCapture class helpful. It’s what I’m using to catch keyboard inputs and keep track of the Mouse Position.
Download the SOURCE CODE HERE.
August 24th, 2009 at 4:17 am
Smooth!