I started to build a run game app for Android. I chose to make it in flash using tiles and Adobe Air. The game is that a player should run automatically to the right and avoid some obstacles by jumping or sliding along the ground.
I have made a function which always takes the first level in the array and uses as the starting level.
private function createLevel()
{
map_level.levell();
level = map_level.level1;
for(var t = 0; t < level.length; t++)
{
for(var u = 0; u < level[t].length; u++)
{
if(level[t][u] != 0)
{
var new_tile:platform_tile = new platform_tile;
addChild(new_tile);
new_tile.gotoAndStop(level[t][u]);
new_tile.x = u * 32;
new_tile.y = t * 32;
tiles.push(new_tile);
}
}
}
total_tile_width += u;
}
Then I create a function that takes a random level in the array of paths.
private function random_level ()
This level is then added at the end of the first track when the player has reached a certain length along the track, then the track seems endless and then made such that the camera follows the player.
private function update_level ()
{
random_level();
for(var t = 0; t < mid_lvl.length; t++)
{
for(u = 0; u < mid_lvl[t].length; u++)
{
if(mid_lvl[t][u] != 0)
{
var new_tile:platform_tile = new platform_tile;
level[t][u + total_tile_width] = mid_lvl[t][u];
addChild(new_tile);
new_tile.gotoAndStop(mid_lvl[t][u]);
new_tile.x = (u + total_tile_width) * 32;
new_tile.y = t * 32;
tiles.push(new_tile);
}
}
}
// Indstiller hvis spilleren skal have en stigende fart
if( movementspeed < 40)
{
movementspeed = movementspeed + 2;
}
else
movementspeed = movementspeed;
total_tile_width += u;
trace ("speed: " + movementspeed);
}
All this works as it should and game function also perfect as a PC, but the phone seems quick to overload it, since I can not figure out how to remove the old levels that have already been played and therefore there's going to be a lot levels in the phone memory.
I need to something like removeChild("old tiles the left the stage again) but got no idear how to only find the tiles that old and not just all tiles.
Anyone able to help me? btw hope you understand my question as im not the best at writing english.
Morten
You must use 2 BitmapData objects.
2 are the size of the screen. We call them screenBuffer1 and screenBuffer2
the other is larger than the screen by at least the width of a tile. We call it terrainBuffer
Then :
Init the terrainBuffer by drawing all visible tiles of the start screen
Copy the currently visible area on screenBuffer1
Draw sprites on screenBuffer1
Attach screenBuffer1 to stage
Now we start scrolling
Copy the currently visible area on screenBuffer2, offset by scroll amount
Draw sprites on screenBuffer2
Attach screenBuffer2 to stage
Continue increasing offset and alternate screenBuffer1 and screenBuffer2 so one is visible while you draw on the other
When offset reach the witdh of a tile :
if(offset>tileWidth){
offset-=tileWidth;
// Move content of terrainBuffer to the left by tileWidth pixels
// Draw a new column of tile on the right
}
Then keep on looping !
Related
Hello everyone so I am having some trouble with this I have Platforms that I add to the stage which are different sizes in Width. What I am trying to do in my for Loop is add more platforms on the right side of the current platforms x position on stage. I am having trouble because they are different sizes so they end up over lapping each other on this side-scroller game. I align the Platform MC's to the right of the registration like so:
here is the smaller size Movie clip:
I am doing this because I want to add different obstacles to each frame inside the Platform Movie Clip.
add Initial platform:
private function addInitPlatform():void
{
platforms = new mcPlatforms();
platforms.x = (stage.stageWidth / 2) - 380;
platforms.y = (stage.stageHeight / 2) + 175;
addChildAt(platforms, 1);
aPlatformArray.push(platforms);
}
Then add new platforms:
private function addPlatForms():void
{
//Loop trhough Platform Array
for (var i:int = 0; i < aPlatformArray.length; i++)
{
var currentPlat:mcPlatforms = aPlatformArray[i];
nOffSetX += currentPlat.width + 50;
//Add platforms
platforms = new mcPlatforms();
platforms.x = nOffSetX;
platforms.y = (stage.stageHeight / 2) + 175;
addChildAt(platforms, 1);
aPlatformArray.push(platforms);
break;
}
trace(aPlatformArray.length + " NPLATFORMS");
}
I am trying to get the current platform which is the last platform I added to the stage and get its width so i can add it at the end but it still is doing something weird and overlapping over time,
So I was wondering if anyone knows how I should go about solving this so whenever I add on a new platform Movie Clip to the stage it aligns on the right side of the last platform Movie clip added to the stage with some space in between like so:
Thank you in advance!
I'm guessing that you have bunch of different platforms in your library with Linkage names set. Not sure if you want them to be in random order or not, but anyways you probably want to pick them up from an array, so:
var aPlatformsArray:Array = [p1,p2,p3]; //Platform Mc's from library
var addedPlatforms:Array = new Array(); //Array where we store added platforms
The first method was to simply raise offset after adding each platform:
var offsetX:Number = 0; //Starting x for the first platform
for(var i:int=0; i<10; i++){
//Just picking random ones from the Linkage array:
var platform:MovieClip = new aPlatformsArray[Math.floor(Math.random() * aPlatformsArray.length)]();
platform.y = 200;
platform.x = offsetX;
offsetX = platform.x + platform.width + 50;
addChild(platform);
addedPlatforms.push(platform);
}
And actually you don't need to worry about the second method as it's technically slower.
But the main difference is that now we have an array where we pick platforms to the stage, and another array where we push added platforms. The second array is not needed at this point, but you'll probably need it later.
And for offset calculations we use x and width of the "previous" element +fixed gap.
And if you just needed fixed order for the platforms, you'd use similar condition for the loop as you already did, and pick platforms in correct order:
for(var i:int=0; i<aPlatformsArray.length; i++){
var platform:MovieClip = aPlatformsArray[i];
Let me know if this does the job or if I got something wrong.
I have a couple dozen collision detections going on each frame as well as a couple dozen objects panning as the character moves left or right (but only if near the edge of the screen). It actually works perfectly when publish in FlashPlayer21 but if I use Adobe AIR, it goes super slow. This only happens when the character is going right and the background is moving left (so the "camera is panning right"). When the character goes left, it is super smooth. I'm using nearly identical code for both with the exception of a different sign (+/-) here or there. Maybe I shouldn't worry about this, or maybe I need to test on my iphone or a tablet but since I don't know how to do that yet... isn't that the whole point of Adobe having these AIR for desktop and internal iOS mobile device simulators?
Here's the relevant code:
private function panScreen2(c:Runner,speedFac:Number,...depthSets):void{
if (c == char){ // if the c:Runner object is the character in play
// I use drivers to cause objects that can only be displayed on every 8th pixel to still recieve floating point number values for animation
var cDepth: int = c._drives.parent.parent.getChildIndex(c._drives.parent);
// "camera" pans to left as character goes left
if (c.x <= 500 && c._drives._facingRight == false && c._speed !=0)
{
for (var i:int = depthSets.length-1; i >= 0; i--){
for (var j:int = depthSets[i].arr.length-1; j >= 0; j--){
var depthDif:int = -cDepth+depthSets[i].arr[j].parent.parent.getChildIndex(depthSets[i].arr[j].parent)
depthSets[i].arr[j].x -= (c._speed)*depthDif*depthSets[i].ratio-speedFac;
}
}
// "camera" pans to right as character goes right sending objects to left
} else if (c.x >= 1000 && c._drives._facingRight == true && c._speed !=0)
{
for (var i:int = depthSets.length-1; i >= 0; i--){
for (var j:int = depthSets[i].arr.length-1; j >= 0; j--){
var depthDif:int = -cDepth+depthSets[i].arr[j].parent.parent.getChildIndex(depthSets[i].arr[j].parent)
depthSets[i].arr[j].x -= (c._speed)*depthDif*depthSets[i].ratio+speedFac;
}
}
} else
{
c.x += c._speed;
}
}
}
and then I call the function like so:
panScreen(c,{arr:allBlocks,ratio:1},{arr:allDepth,ratio:1},{arr:allBears,ratio:1});
depthSets are the extra parameters I pass when calling the function. It is an object which consists of an array and a ratio. This function iterates through the array (actually Vector, if that matters) and moves everything to the right or left by an amount determined by the ratio and the speed of the character. Pretty straight forward, and again, it works like a charm in Flash Player 21 and works smooth as butter when the character goes leftward which sends all the objects to the right as a "camera" pan. So what's going on with trying to go to the right?
I am using a tileList in ActionScript 3 to display movieclips. However I have the problem that not all reference points of the movieclips are in the correct place. This leads to that these movieclips are shown partly outside of their cell in the tileList.
I have tried to adjust the x and y position of the movieClip before adding it to the tileList, but this did not change anything. Now I have tried to find if it is possible to change the x and y position of an object already in the tileList, but without finding any answers.
I hope that I have made my problem clear.
Thanks in advance!
EDIT:
This is the code I tried:
private function initTileList():void {
for(var i:int = 0; i < _movieClips.length; i++) {
changePos(_movieClips[i]);
tileList.addItem({label: _movieClips[i].name, source: _movieClips[i]});
}
}
private function changePos(mc:MovieClip):void {
if(MovieClip(mc).getRect(mc).x != 0) {
mc.x -= MovieClip(mc).getRect(stateMachineRef).x;
}
if(MovieClip(mc).getRect(mc).y != 0) {
mc.y -= MovieClip(mc).getRect(stateMachineRef).y;
}
}
I do not have any errors, it just doesn't affect the position of the object in the tileList.
Example of how the problem looks.
Hard to say where's the problem without knowing these things:
1. What tileList.AddItem() does exactly;
2. What is stateMachineRef
3. How MovieClips are loaded. If they are loaded from a network, that'll be a whole different story.
By the way, you don't have to cast MovieClip(mc) as mc is already a MovieClip. Also, there is no difference as to when you will correct the coordinates: before or after adding to the tileList. Should work either way.
So, given that information on your problem is not complete, I would just suggest you insure the following steps:
-We assume all tiles are displayed inside a tile container. It can be Stage or a MovieClip or any suitable DisplayObjectContainer, so let's call it just tileContainer from now on.
-We assume all tiles are of the same width and height. If you are not sure, you should check it again.
-We assume that each tile in the tileContainer is displayed at some regular grid coordinates. I.e. it conforms the following code:
for (var pos_y:int = 0; pos_y < GRID_SIZE_Y; pos_y++) {
for (var pos_x:int = 0; pos_x < GRID_SIZE_X; pos_x++) {
var tile:Tile = getNextTile(); // just get a tile from somewhere
tile.source.x = pos_x * TILE_WIDTH; // using your tile structure
tile.source.y = pos_y * TILE_HEIGHT;
tileContainer.addChild(tile.source);
}
}
Now I see your problem that some tiles are created in a way that they have their source movieclip coordinates shifted from (0,0). So they will not align with the grid.
What are you doing seems to be a proper way of aligning them but I don't know exactly what happens in your code so I'll just rewrite it:
function changePos(mc:MovieClip) {
var r:Rectangle = mc.getRect(mc);
mc.x -= r.x; // note you don't need any if's
mc.y -= r.y;
}
And in the above loop just add the changePos() AFTER setting the grid coordinates:
tile.source.x = pos_x * TILE_WIDTH;
tile.source.y = pos_y * TILE_HEIGHT;
changePos(tile.source);
tileContainer.addChild(tile.source);
If you're following all these steps, that's basically all you need and it will work for sure.
Hey everyone so having a little trouble trying to accomplish this. I understand how to add lives and display them through a Dynamic Text Field on the stage. My game is set up right now to where this happens and whenever the player dies a live decrements so it works fine.
But I want to display and Image of all 3 lives a custom Movie Clip that I drew in Flash CS6 to represent the lives. So All 3 lives will be displayed in the game and once the player dies one of the lives images is removed.
I have some idea on what to do. For instance I created a "for loop" to display all 3 images on the screen and created variables to place them horizontally next to each other with a space of 30 pixels.
But I'm not sure if this is the correct way to approach this. Also kind of confused on how I would remove one of the images when the player dies?
Her is my code so far:
public var playerLives:mcPlayerLives;
private var nLives:Number = 3;
private var startPoint:Point;
private var aPlayerLivesArray:Array;
In my main class Engine:
aPlayerLivesArray = new Array;
addPlayerLivesToStage();
Then the addplayerlivestostage function:
public function addPlayerLivesToStage():void
{
var startPoint:Point = new Point((stage.stageWidth / 2) - 300, (stage.stageHeight / 2) - 200);
var xSpacing:Number = 30;
for (var i = 0; i < nLives; i++)
{
trace(aPlayerLivesArray.length);
playerLives = new mcPlayerLives();
stage.addChild(playerLives);
playerLives.x = startPoint.x + (xSpacing * i);
playerLives.y = startPoint.y;
aPlayerLivesArray.push(playerLives);
}
}
So like i stated above everything works fine and it does display the 3 images that represent the lives, but would this be the correct approach or is there an easier method?
i think you're using right way to add lives.
and for removing them, you don't need to remove all and add new lives, you can remove the last element of lives array, so, it's done, i think thats already an easy method
so, you can implement this
for (var i = 0; i < nLives; i++)
to make a better usage for "adding lives in-game (earning lives)"
something like
for (var i = aPlayerLivesArray.length; i < nLives; i++)
but don't forget to decrease array length by 1 after removing last element of livesArray when player dies
Looks pretty close to a reasonable approach. I would have a blank container movieclip on stage where you want the lives icons to display. Create one life icon in your library and link it for export with actionscript. When you generate your game view, you can populate this container with the starting value of three lives. Place the first one, then place the subsequent ones based on the first location.
Some untested code:
NOTE: The following presumes your container clip for the lives is named lives_container and your link instance name for the life icon in the library is Life_icon.
var numberOfLives:Number = 3;
var iconSpacing:Number = 5;
var nextX:Number = 0;
for(var i:int = 0; i < numberOfLives; i++ )
{
var icon:MovieClip = new Life_icon();
icon.x = nextX;
lives_container.addChild( icon );
nextX += icon.width + iconSpacing;
}
This way you could add extra lives easily if the player gained any by adding new icons at the last nextX value, like so:
function addLife():void
{
var icon:MovieClip = new Life_icon();
icon.x = nextX;
lives_container.addChild( icon );
nextX += icon.width + iconSpacing;
}
or remove them as the player loses them:
function removeLife():void
{
var numberOfLivesDisplayed:Number = lives_container.numChildren();
lives_container.removeChildAt( numberOfLivesDisplayed - 1 );
nextX -= icon.width + iconSpacing;
}
Using a container clip for the lives icons makes adjusting the location of the life icons easier if it becomes necessary later.
I have loaded some images through XML and attached into dynamically created MovieClips named mc0,mc1,mc2...etc.
_loader.removeEventListener(ProgressEvent.PROGRESS, onLoadingAction);
count++;
var img:Bitmap = Bitmap(e.target.content);
img.cacheAsBitmap = true;
img.smoothing = true;
img.alpha = 0;
TweenLite.to(MovieClip(my_mc.getChildByName("mc"+count)).addChild(img),1, {alpha:1,ease:Quint.easeIn});
and within ENTER_FRAME handler
for (i=0; i < mc.numChildren; i++)
{
my_mc.getChildAt(i).x -= Math.round((mouseX-stage.stageWidth/2)*.006);
}
Everthing works fine. But it is shaking so that it was not looking good.
How do I achieve smooth movement?
One solution I've used is to round the (x,y) position to the closest integer. No matter that you've added smoothing to your bitmap and cached it, rounding could make it feel less choppy and way smoother.
Another thing you need to be careful is the dimensions of the images. Images that have an odd dimension won't be smoothed the same way as images with even dimensions. Check how to workaround this in my blog post Flash Smoothing Issue.
Since Flash has a variable frame rate (in the sense that it will drop frames), one shouldn't depend on the entering of a frame as a unit of action. Rather, it would be wiser to calculate the elapsed time explicitly.
For instance, in the enter frame handler:
var currentTime:Number = (new Date()).time;
for (i=0; i < mc.numChildren; i++)
{
my_mc.getChildAt(i).x -= speed * (currentTime - lastTime); // speed is in px/ms
}
lastTime = currentTime;
where you have the variable lastTime declared somewhere in a persistent scope:
var lastTime:Number = (new Date()).time;
I don't know if this addresses what you are calling "shaking", but it's at least something to consider.