AS3 panning very slow in only one direction and only with Adobe AIR - actionscript-3

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?

Related

How to add Movie Clips of different sizes next to each other? AS3

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.

AS3 Change position of object in TileList

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.

As3: Not move through objects? How is the logic behind this?

I have a function where I can control my character.
I also have a movieclip on the stage called assassin_table.
I want to make it so that the character can't move in the table, a.k.a make the table work like a wall.
I have this code:
if(!this.hitTestObject(_root.assassin_table))
{
if(upKeyDown)
{
gotoAndStop(4);
y-=Math.cos(rotation/-180*Math.PI)*(mainSpeed +7);
x-=Math.sin(rotation/-180*Math.PI)*(mainSpeed +7);
}
if(!upKeyDown)
{
gotoAndStop(3);
}
}
However, if I touch the table, then I can't move at all.
I know it's because if(!this.hitTestObject(_root.assassin_table)), but I don't understand the logic behind NOT moving through objects. I'd much rather have a near pixel-perfect collision detection system, but since it's so hard to find any good info online which isn't confusing, I'll stick with hitTestObject for now :)
EDIT: Tried something, didn't really work that well.
if(!_root.assassinDead && !teleporting && this.currentFrame != 5)
{
if(this.hitbox.hitTestObject(_root.assassin_table))
{
_root.assassin_table.gotoAndStop(2);
if(this.x > _root.assassin_table.x)
{
trace("Can't move right");
canMoveRight = false;
}
if(this.x <_root.assassin_table.x)
{
trace("Can't move left");
canMoveLeft = false;
}
if(this.y > _root.assassin_table.y)
{
trace("Can't move up");
canMoveUp = false;
}
if(this.y < _root.assassin_table.y)
{
trace("Can't move down");
canMoveDown = false;
}
}
else
{
canMoveRight = true;
canMoveLeft = true;
canMoveUp = true;
canMoveDown = true;
}
}
This causes me to sometimes be able to walk through the table. I figure it's because my character can move in essentially every possible angle (since he's always facing the mouse and there are no tiles/grids).
How would I make it so that it would work with the advanced movement I have?
Moving up runs this:
y-=Math.cos(rotation/-180*Math.PI)*(mainSpeed +7);
x-=Math.sin(rotation/-180*Math.PI)*(mainSpeed +7);
And the rotation is decided by this:
this.rotation = Math.atan2((stage.mouseY - this.y), (stage.mouseX - this.x)) * 180/ Math.PI + 90;
You should seperate your hittest functions for four different moving directions.
I mean, you shouldn't use this "hitTestObject" stuff, that only returns a boolean value "true" or "false", and that's not going to work for you.
You need a function like "testPoint(player.x, player.y);" and returns the object at the given position, so you can implement it for your game like that
if (upKeyDown && testPoint(player.x, player.y - mainSpeed +7) == null) y-=Math.cos(rotation/-180*Math.PI)*(mainSpeed +7);
player.y - mainSpeed +7 // that checks for plus mainSpeed+7 because of trying to stop your player before it get stack inside object
Basically your logic flow should be like this:
Sample input (key press)
Move character
Check for collisions
If collision then move character to it's "outside" the object that it's touching
In your particular case, if your character is on the left of the table, and you're moving right, then first things first, you move your character. At your new position, check for any collisions. If you have a collection, then because you were moving from the left, we want to be on the left of the object that we colliding with, in this case the table, so we position our character to the left of the table.
The first part of that (checking if the character has hit the table) is called collision detection. Moving the character so that it's outside the bounds of the table is called collision response. Collision detection is a pretty big field and really depends on the type of game you're making; you can do grid-based, hit-test based (if you don't have a ton of objects), physics-based, math-based etc. Collision response can be anything and everything, depending on how you want to react to a collision - you can destroy the object (balloon on a spike), change its speed (character running through mud), bounce off it (ball off wall), or stop any further movement (character against wall).
To make things a bit easier:
Separate your systems - your input shouldn't be dependant on your collision for example. If the up key is down, just register that fact - what you do with it later (make your character move) is up to you
Separate your objects position in memory from its position on screen - this will let you move it around, react to collisions etc, and only when everything is good, update the graphics (stops things like graphics entering a wall only to jump out the next frame)
Solve for one axis at a time - e.g. collide on the x axis first, then the y
Pixel perfect collision is rarely needed :) Non-rotated boxes and circles will work a lot more than you'd think
Somewhat related - the shape of your object doesn't have to be the shape that you're colliding with - e.g. your table collision shape could just be a box; your character collision shape could just be a circle
Update
This causes me to sometimes be able to walk through the table
Assuming that we're going to collide our character and table as boxes, you need to take into account their sizes - i.e. we don't just compare the x values, but the right side of our character box against the left side of the table box etc. Something like:
// assumes objects have their anchor point in the top left - if its
// not the case, adjust as you see fit
if( char.x + char.width > table.x ) // right side of the char is overlapping the left side of the table
canMoveRight = false;
else if( char.x < table.x + table.width ) // left side of char vs right side of table
canMoveLeft = false;
// etc
When working with collisions, it's always nice to see the actual boxes, for debugging. Something like this:
var debug:Shape = new Shape;
debug.addEventListener( Event.ENTER_FRAME, function():void
{
debug.graphics.clear();
debug.graphics.lineStyle( 2.0, 0xff0000 );
// char (again assuming anchor point is top left)
debug.graphics.drawRect( char.x, char.y, char.width, char.height );
// table
debug.graphics.drawRect( table.x, table.y, table.width, table.height );
});
// add our debug. NOTE: make sure it's above everything
stage.addChild( debug );

removing old tiles in a running game made with as3 and flash

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 !

Ideas for jumping in 2D with Actionscript 3 [included attempt]

So, I'm working on the basics of Actionscript 3; making games and such.
I designed a little space where everything is based on location of boundaries, using pixel-by-pixel movement, etc.
So far, my guy can push a box around, and stops when running into the border, or when try to the push the box when it's against the border.
So, next, I wanted to make it so when I bumped into the other box, it shot forward; a small jump sideways.
I attempted to use this (foolishly) at first:
// When right and left borders collide.
if( (box1.x + box1.width/2) == (box2.x - box2.width/2) ) {
// Nine times through
for (var a:int = 1; a < 10; a++) {
// Adds 1, 2, 3, 4, 5, 4, 3, 2, 1.
if (a <= 5) {
box2.x += a; }
else {
box2.x += a - (a - 5)*2 } } }
Though, using this in the function I had for the movement (constantly checking for keys up, etc) does this all at once.
Where should I start going about a frame-by-frame movement like that? Further more, it's not actually frames in the scene, just in the movement.
This is a massive pile of garbage, I apologize, but any help would be appreciated.
try doing something like: (note ev.target is the box that you assigned the listener to)
var boxJumpDistance:Number = 0;
function jumpBox(ev:Event){
if (boxJumpDistance<= 5) {
ev.target.x += boxJumpDistance; }
else if(boxJumpDistance<=10){
ev.target.x += boxJumpDistance - (boxJumpDistance - 5)*2
}
else{
boxJumpDistance = 0;
ev.target.removeEventListener(Event.ENTER_FRAME, jumpBox);
}
}
then instead of running the loop, just add a listener:
box2.addEventListener(Event.ENTER_FRAME, jumpBox);
although this at the moment only works for a single box at a time (as it is only using one tracking variable for the speed), what you would really want to do is have that function internally to the box class, but im unsure how your structure goes. the other option would be to make an array for the boxes movement perhaps? loop through the array every frame. boxesMoveArray[1] >=5 for box 1, etc.