View Full Version : [AS3] Platform game - scrolling
aaron_da_killa
02-14-2009, 04:27 AM
Hey guys
I'm working on a platform game for my multimedia major project in ActionScript 3.0 (I'm learning ActionScript 3.0 as I go). I've done alot of the coding work but there is much more to do. My platform game isn't tile based. I have a jpeg background and use movieclips for the characters and objects aswell as invisible rectangles (movieclips) for triggers and collisons (so my game is object based?)
Its come time where I need to implement some sort of scrolling into the game and I have no idea how I'm going to do it. I've thought of two ways I can do it:
Method 1: The player is in the center of the camera and the world moves around him. I could build the levels in "blocks" and place them in each frame on the movieclip, only the "blocks" that can be seen are rendered for performance reasons.
Method 2: The player is not in the center of the camera and is free to move around in the scene. When he touches one of the edges of the camera, the next "block" is loaded and the player is teleported to the appropriate side (if player touches right of camera, next block is loaded and player teleports to the left of the screen). Each "block" could be built in the timeline somewhere and I use actionscript to render them active or inactive. Only one block will be renderd at one time.
I prefer Method 1 but I think it will be harder to do. I'm just wondering if anybody has insight into any of the above or scrolling for platform games in general.
Any help is greatly apperciated :).
EightySeven
02-14-2009, 01:40 PM
After much stress over this very issue I've come up with a solution for my games you might adapt something like it for yours
private function scrollWithPlayer() {
var stagePosition:Number=gamelevel.x + hero.mc.x;
var stagePositiony:Number=gamelevel.y + hero.mc.y;
var rightEdge:Number=stage.stageWidth - edgeDistance;
var leftEdge:Number=edgeDistance;
var topEdge:Number=edgeDistance;
var bottomEdge:Number=stage.stageHeight - edgeDistance;
if (stagePosition > rightEdge) {
gamelevel.x-= stagePosition - rightEdge;
if (gamelevel.x < -(gamelevel.width - stage.stageWidth)) {
gamelevel.x=-(gamelevel.width - stage.stageWidth);
}
}
if (stagePosition < leftEdge) {
gamelevel.x+= leftEdge - stagePosition;
if (gamelevel.x > 0) {
gamelevel.x=0;
}
}
if (stagePositiony < topEdge) {
gamelevel.y-= stagePositiony - topEdge;
if (gamelevel.y > 0) {
gamelevel.y=0;
}
}
if (stagePositiony > bottomEdge) {
gamelevel.y-= stagePositiony - bottomEdge;
if (gamelevel.y < -(gamelevel.height - stage.stageHeight)) {
gamelevel.y=-(gamelevel.height - stage.stageHeight);
}
}
}
gamelevel is a MC on the stage that houses my level and contents including the heroMC
edgeDistance is a uint that depends on your screen size. its teh distance from the edge at which the level will start scrolling
I had some help creating this
aaron_da_killa
02-14-2009, 11:09 PM
Thanks EightySeven :). Interesting, so does this mean that "gamelevel" is larger than the stage?
EightySeven
02-15-2009, 03:09 AM
yes, larger. why else would u want to scroll of ur level was smaller then your stage?
aaron_da_killa
02-15-2009, 04:15 AM
Right, so is there a way to embedd or group my "gamelevel" (huge jpeg movieclip) with other movieclips?
Because for my platform game using your method (which I like :D),I would have my "gamelevel", than I would have invisible blocks (also movieclips) which are used to define the collisions of objects painted onto the jpeg background, than I will also have invisible blocks (movieclips) for triggering events as the player is moving through the level. Than I would have movieclips for animated or dynamic objects.
So how do I move all these movieclips with my background movieclip? I imagine that writing code for each movieclip to scroll through the world and such would be a very tedious task and inefficient performance wise too.
bluemagica
02-15-2009, 05:27 AM
too put it simply, you would just put everything scrollable inside a single movieclip....that way everything scrolls together!
But for very large levels, this method is really inefficient! I suggest you go for tile-based approach, as it will give you much more flexibility with level design and implementation!
aaron_da_killa
02-15-2009, 06:20 AM
thanks bluemagica
too put it simply, you would just put everything scrollable inside a single movieclip....that way everything scrolls together!
Right, but for some things I need them as separate movieclips so I can refer to them individually in the code. Things like crates for example that the player can stand on top of are embedded inside the jpeg background (which is a movieclip), but what about the invisible box that defines the collision box for that crate?, I need to refer to these invisible boxes in the code so they need their own instance name. What I guess I'm asking is if there is someway to somehow group a bunch of movieclips so I can refer to the group of movieclips but also the individual movieclips. So say if my group name is group1 and in that group I have cratecollison1 and trigger1 I can say like:
if player something than group 1 something (which effects trigger1 and cratecollison1) but I can also say:
if player something than trigger1 something (which effects trigger1 but not cratecollison1)
But for very large levels, this method is really inefficient! I suggest you go for tile-based approach, as it will give you much more flexibility with level design and implementation!
I've considered the tile based approach and having level arrays and such but I don't think that is a good idea for my project.
Edit: I just thought of something. Would it work if I put everything I wanted to scroll on layer 2 than be able to scroll layer 2 just as I would with a moveclip?
bluemagica
02-15-2009, 10:06 AM
-_- is today you first time with flash? I already said to put everything in a single movieclip! That means, make the invisible box or whatever a movieclip, give it instance name, and then put it inside the main scrolling movieclip! If you are still confused, just select all movieclips and press F8 !
To refer to them you would use parent_movieclip.child_movieclip.x or something like that!
EightySeven
02-15-2009, 02:23 PM
I believe its MovieClip(parent).whateveruneed.
bluemagica
02-15-2009, 03:50 PM
true, there is no such thing as parent_movieclip.....i gave it just as a placeholder!
aaron_da_killa
02-16-2009, 06:02 AM
-_- is today you first time with flash? I already said to put everything in a single movieclip! That means, make the invisible box or whatever a movieclip, give it instance name, and then put it inside the main scrolling movieclip! If you are still confused, just select all movieclips and press F8 !
To refer to them you would use parent_movieclip.child_movieclip.x or something like that!
Nope, today is my 14th day using flash. Anyway, what you just told me was what I was asking in my last two posts. I didn't know you could sort of create a hiearchy with movieclips like that. Thanks bluemagica!
Anyways, I've successfuly created horizontal scrolling! I'm currently working on vertical scrolling which is hard. Basically, I'm modifying my player jump function so that instead of moving the player, it will move the whole world, but I'm encountering some issues with this so I gotta keep working.
I have one question though guys, I don't understand : MovieClip(parent).whateveruneed.
I have my level as a movieclip named "level" and inside that I have "platform", so if I 'need' platform is this code correct: MovieClip(level).platform
If I use that code I get errors and I've tried other combinations such as:
"level(parent).platform" and "MovieClip.level.platform" but I keep getting compile errors. So what am I doing wrong? :S
Anyway guys, when this is sorted I can't wait to show you my platform game so far :D. The level is only a prototype used for developing the code, so its not pretty at the moment.
aaron_da_killa
02-16-2009, 08:07 AM
Sorry, ignore my last post I figured it out.
I totally broke my code trying to get vertical scrolling to work. Horizontal scrolling is very easy but I tried to modify my player jump function to instead of move the player, move the whole level and it messed up my collisons for the platforms so I tried to undo it and now I have a big mess of code on my hands where vertical scrolling is removed but player jumping and platform collisions is messed up which I'll attend to tommorow.
I think I need to create a new jump function from scratch. The one I'm using now is based off this one (http://www.mrsunstudios.com/2008/08/tutorial-create-a-platform-game-in-as3/) and it sucks ass. Do you guys know of any examples of jump functions I could look at?, the maths in them is mind boggling.
Edit: By the way guys, thanks for the help so far, wouldn't be this far without you two :).
kkbbcute
02-16-2009, 01:52 PM
Earlier on you mentioned that you think tiling isn't a good idea. Well, actually it is sort of a must when you move on to larger more complex games. Simply put, you can just use tiling not in the traditional sense in let's say 10 by 10 pixel boxes, but rather to divide up the game world into huge areas, and things such as hitTests will only be done on the current and adjacent tiles.
bluemagica
02-16-2009, 01:58 PM
Yep, though later on, the implementation will vary a lot, like in my new project i am using a large bitmap based world and dividing it based on its colors....but i guess, somethings are better learnt when you have a bit more experience and experimented!
I do suggest you read up on tonypa's tile based tutorials....though they may not be what you need eactly for your game, but i am sure, if you learn the concepts, you will be much better off!
As for jumping, there is no fixed algorithm, its just manipulating the y coordinate, and how you do it, depends entirely upon you! You don't have to bother with math( although this is the first time i heard jumping had mind-boggling math), you should think more about the logic, like what are the exact conditions you need for jumping(Hint: place below not free, meaning standing on something), etc!
aaron_da_killa
02-17-2009, 05:43 AM
Earlier on you mentioned that you think tiling isn't a good idea. Well, actually it is sort of a must when you move on to larger more complex games. Simply put, you can just use tiling not in the traditional sense in let's say 10 by 10 pixel boxes, but rather to divide up the game world into huge areas, and things such as hitTests will only be done on the current and adjacent tiles.
Yeah, I intitaly expected to myself to build the level in large tiles so I could only have parts of the world renderd at the one time, but I guess I'll probably figure it out later.
I think what I am in desperate need of is a new jump function. I've noticed that my collison detection code is very unreliable and inaccurate and I need to put in alot of leeway!, sometimes it will work, sometimes it won't work and sometimes the results will vary depending on the platform size. I think the inaccuracy lies somewhere in my jump function (which I stole from a platform game tutorial and adaopted into my code) because only the top/bottom of platform collison detection is unreliable, the left and right edges all ways seem to work.
I think that once I make a better jump function, the collison detection will be much better which will make the vertical scrolling work properly.
As for tonypa's tile based tutorials, there pretty good! I've had a breif look at them and will certainly go through them proerly later (including the jump function :cool: ).
(BTW, if this post is full of spelling errors, thats because I am using IE7 and don't have my much needed firefox spell checker)
aaron_da_killa
02-17-2009, 08:55 AM
Double Post:
Wow, I just made a really simple jump function, thanks to reading this (http://www.tonypa.pri.ee/tbw/tut07.html) page, I used their idea but none of their code, it doesn't get much simpler than this:
//My Jump Function, this is triggerd every frame!
public function mainJump(event:Event):void{
if (playerJumpAllow == 1)
{
jumpSpeed2 += gravity;
player.y += jumpSpeed2;
}
}
//Variables needed for jumping
var gravity:Number = 0.8;
var jumpSpeed2:Number = -18;
var playerJumpAllow:Number = 0;
What I simply do is set playerJumpAllow to one when the up key is pressed and set it to zero as soon as the player collides with one of my platforms stopping the jump otherwise the player would jump than fall into oblivion. Here is my old jump function:
public function mainJump():void{
//if main isn't already jumping
if(!mainJumping){
//then start jumping
mainJumping = true;
jumpSpeed = jumpSpeedLimit*-1;
player.y += jumpSpeed;
jumpSoundEffect.play();
} else {
//then continue jumping if already in the air
if(jumpSpeed < 0){
jumpSpeed *= 1 - jumpSpeedLimit/jumpHeight; // last number controls jump height
if(jumpSpeed > -jumpSpeedLimit/5){
jumpSpeed *= -1;
}
}
if(jumpSpeed > 0 && jumpSpeed <= jumpSpeedLimit){
jumpSpeed *= 1 + jumpSpeedLimit/50;
}
player.y += jumpSpeed;
if(player.y >= stage.stageHeight - player.height -20){
mainJumping = false;
player.y = stage.stageHeight - player.height -20;
}
}
}
Maybe not for you guys because your much better at this than me, but when I look at my old jump function, its easy to see why the I thought the maths was crazy at first glance.
kkbbcute
02-17-2009, 09:15 AM
Actually if you need this sort of code for like gravity, acceleration and stuff, with info on hitTests, ActionScript Animation by Friends of ED is a good book to consider, so you don't have to run back and forth on the web to try and find a tutorial.
bluemagica
02-17-2009, 11:02 AM
Good job, you are learning pretty fast! just a few small things:-
when you need something to oscillate between two values, like your playerJumpAllow, use Boolean instead of Number!
Also when writing a chain equation like a+b*c*d, make use of brackets, (a+b)*c*d! otherwise due to operator preference, your equations may turn up with unexpected values.
and finally
LEARN TO USE CODE BLOCKS WHILE POSTING!!
when you post some code, type it within [code]your code here[/cde] ......the end tag is code not cde( i had to misspell it so that it dosent get interpreted)!
aaron_da_killa
02-19-2009, 03:37 AM
Thanks guys. :cool:
when you need something to oscillate between two values, like your playerJumpAllow, use Boolean instead of Number!
Will do from now on. Is there some sort of performance/memory gain or something?
Also when writing a chain equation like a+b*c*d, make use of brackets, (a+b)*c*d! otherwise due to operator preference, your equations may turn up with unexpected values.
Roger that!
Actually if you need this sort of code for like gravity, acceleration and stuff, with info on hitTests, ActionScript Animation by Friends of ED is a good book to consider, so you don't have to run back and forth on the web to try and find a tutorial.
Alrighty, thanks for the recommendation. I'll look into that!
Now, I have a bizarre problem, really frikken weird and I cannot for the life of me figure out what is going on :eek:. For some reason, when the player is standing on a platform, he can't jump when he is facing or moving right however he can jump if he is facing left or moving left. And if the player walks off the platform (there is no gravity yet), he can jump facing any direction, so its something that has to do with when the player is on the platform.
Here is the swf (http://files.filefront.com/Untitled+1swf/;13319751;/fileinfo.html), and here is the code if anybody is interested in taking a look (code still has numbers instead of booleans bluemagica):
package {
import flash.display.Stage;
import flash.events.Event;
import flash.events.KeyboardEvent;
import flash.ui.Keyboard;
import flash.display.MovieClip
import flash.display.Sprite
import flash.media.Sound;
public class PlayerMovement extends MovieClip {
var leftKeyDown:Boolean = false;
var upKeyDown:Boolean = false;
var rightKeyDown:Boolean = false;
var downKeyDown:Boolean = false;
var mainSpeedRight:int = 4;
var mainSpeedLeft:int = 4;
var playerWalkSpeed:int = 4; // set same as mainSpeedLeft/Right. (used by scroll)
var zombieSpeed:Number = 1;
var carrierSpeed:Number = 2;
var mainJumping:Boolean = false;
var jumpSpeed:Number = 0;
var jumpHeight:Number = 180;
var jumpSpeedLimit:Number = 12;
var jumpSoundEffect:jumpSound = new jumpSound();
var zombieAITest:int = 1;
var carrierAITest:int = 1;
var allowRightScroll:int =0;
var allowLeftScroll:int =0;
var allowRevertToNormWalkSpeed:int =1;
var stopJump:Number = 1;
var jumpSpeed2:Number = -18;
var gravity:Number = 0.7;
public function PlayerMovement() {
player.addEventListener(Event.ENTER_FRAME, moveChar);
stage.addEventListener(KeyboardEvent.KEY_DOWN, checkKeysDown);
stage.addEventListener(KeyboardEvent.KEY_UP, checkKeysUp);
player.y = 480 - player.height - 32;
player.x = 330;
stage.addEventListener (Event.ENTER_FRAME, ifplatformCollide);
stage.addEventListener (Event.ENTER_FRAME, returnNormalWalkingSpeed);
stage.addEventListener (Event.ENTER_FRAME, startScroll);
player.gotoAndStop("idle"); //players default stance
stage.addEventListener (Event.ENTER_FRAME, mainJump);
}
/************************************************** ***************************************
************************************************** ****************************************
************************************************** ****************************************
PLAYER CODE (KEYBOARD CONTROL, JUMPING, PLAYER GRAVITY)
************************************************** ****************************************
************************************************** ****************************************
************************************************** ***************************************/
//Controls left and right player movement
private function moveChar(event:Event):void{
//if certain keys are down then move the character
if(leftKeyDown){
player.x -= mainSpeedLeft;
allowRightScroll = 1;
player.gotoAndStop("left");
}
if(rightKeyDown){
player.x += mainSpeedRight;
allowLeftScroll = 1;
player.gotoAndStop("right");
}
if(upKeyDown){
stopJump = 0;
}
}
//Listens for keys pressed down
private function checkKeysDown(event:KeyboardEvent):void{
if(event.keyCode == 37){
leftKeyDown = true;
}
if(event.keyCode == 38){
upKeyDown = true;
}
if(event.keyCode == 39){
rightKeyDown = true;
}
if(event.keyCode == 40){
downKeyDown = true;
}
}
//Listens for keys being released
private function checkKeysUp(event:KeyboardEvent):void{
if(event.keyCode == 37){
leftKeyDown = false;
allowRightScroll = 0;
}
if(event.keyCode == 38){
upKeyDown = false;
}
if(event.keyCode == 39){
rightKeyDown = false;
allowLeftScroll = 0;
}
if(event.keyCode == 40){
downKeyDown = false;
}
}
public function mainJump(event:Event):void{
if (stopJump == 0){
jumpSpeed2 += gravity;
player.y += jumpSpeed2;
}
}
public function mainJumpStop():void{
stopJump = 1;
jumpSpeed2 = -18;
}
public function returnNormalWalkingSpeed(event:Event):void{
if (player.x > 270 && player.x + player.width < 370 && allowRevertToNormWalkSpeed == 1){
mainSpeedRight = 4;
mainSpeedLeft = 4;
}
}
/************************************************** ***************************************
************************************************** ****************************************
************************************************** ****************************************
ARTIFICAL INTELLIGENCE CODE
************************************************** ****************************************
************************************************** ****************************************
************************************************** ***************************************/
/************************************************** ***************************************
************************************************** ****************************************
************************************************** ****************************************
LEVEL COLLISON DETECTION CODE
************************************************** ****************************************
************************************************** ****************************************
************************************************** ***************************************/
private function ifplatformCollide(event:Event):void{
if (player.hitTestObject(platform)){
platformSit();
allowRevertToNormWalkSpeed = 0;
}
else {
mainSpeedRight = 4;
mainSpeedLeft = 4;
playerWalkSpeed = 4;
allowRevertToNormWalkSpeed = 1;
}
}
// Function to make:
// * Player sit ontop of platform
// * Player to bump head on bottom of platform
private function platformSit():void{
//if player touches above platform (works)
if (player.y + player.height <= platform.y + platform.height/2){
mainJumpStop();
player.y = platform.y - player.height;
mainSpeedRight = 4;
mainSpeedLeft = 4;
}
}
/************************************************** ***************************************
************************************************** ****************************************
************************************************** ****************************************
WORLD CODE (TRIGGERS, SCROLLING, ITEMS)
************************************************** ****************************************
************************************************** ****************************************
************************************************** ***************************************/
public function startScroll(event:Event):void{
if (player.x <= 270 && allowRightScroll == 1){
mainSpeedLeft = 0;
tehBackground.x += playerWalkSpeed;
platform.x += playerWalkSpeed;
}
if (player.x + player.width >= 370 && allowLeftScroll == 1){
mainSpeedRight = 0;
tehBackground.x -= playerWalkSpeed;
platform.x -= playerWalkSpeed;
}
}
}
}
Additional Information:
-Player is a movieclip names "player"
-Platform is a movieclip named "platform"
-background is a movieclip named "tehBackground"
-Player has 3 different frames/states/animations/frames (not sure what there called) named in order: "idle", "left", "right"
Any ideas?
aaron_da_killa
02-19-2009, 06:50 AM
Double Post:
I've figured out what the problem is but not how to fix it and I'm not sure if its an error in my code, something I should be doing differently or a flash bug.
Basically, for some reason, when the player is facing left on a platform, for every second frame or whatever, the game thinks the player is not on the platform and thus the else statement in ifplatformCollide() is triggered. The ifplatformCollide() else statement should only be triggered if the player IS NOT on a platform.
How did I figure this out? Well I built a working jump function which allows the player to jump while on a platform and facing either direction (see previous post). So then I added gravity to the game in the ifplatformCollide(), else statement which basically sets playerJump to 2 and is incrimented by 2 (makes the player fall realistically) when the player is not on a platform and is not jumping. When I faced left on a platform, I noticed the player appeared to be jumping up and down very quickly. That was because even though the player was on the platform, the else statement in ifplatformCollide() was being triggered (gravity) then the next frame, the game realized the player was actually on the platform and sets player.y to platform.y - player.height (sets player to stand above platform), and than the next frame the game thought the player wasn't on the platform so gravity was triggered making the player fall slightly etc etc. This is happening in 60 fps so it makes the player appear as though they are jumping very quickly.
So to summarize, when the player is facing left, in every second frame the game thinks the player is not on the platform. Why on Earth would this be? I'm almost certain that it is not a coding bug, I have went over it a billion times!
aaron_da_killa
02-19-2009, 10:10 PM
Tripple Post:
Alrighty, ignore my last two posts. I figured out the problem (I think), I restructured ifplatformCollide() function and it seems to have fixed my problem, still not sure why it was effecting when the player was left but its fixed now.
The code is in good shape at the moment, I have more accuracte collison detection with working horizontal scrolling. All that is left is to impement vertical scrolling and everything else should be easy enough.
|
vBulletin® v3.8.4, Copyright ©2000-2009, Jelsoft Enterprises Ltd.