scroll to the right or left if needed - actionscript-3

I'm making a platform game.
My game level is very large and I'd like to make the gameLevel scroll when the player is walking.
So far it's scrolling, but the scrolling speed is not fast enough and when the player is walking to the right, he goes out of the screen.
Do you know how I can speed up the scrolling in order to prevent the character to exceed the middle of the screen ?
Here's my code for the scrolling screen :
// scroll to the right or left if needed
public function scrollWithHero() {
var stagePosition:Number = gamelevel.x+hero.mc.x;
var rightEdge:Number = 400-edgeDistance;
var leftEdge:Number = 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;
}
}

There are two ways you can scroll a screen.
The first would be to scroll at the exact same speed as the player's movement. which would mean that you do not really move the player, but rather scroll the world (the player would remain in the exact same place on-screen). This is not a very "elegant" way to go, but many games use it and it works.
The second (and better, IMHO) way would be to define some area around the center of the screen and allow the player to move around within this area. Only once the player reaches the end (to left/right) of this area do you start scrolling. This provides a much smoother effect.
So to implement the area, you need a size for it (lets say 100 as an example) and 300 is the center of the screen. So in this case your "area" would be from 250 to 350. Now you will need to detect when the player moves beyond this area and then scroll (instead of moving the player). This can be implemented as follows:
const CENTER:Number = 300; // center position on screen
const SIZE:Number = 100; // size of the movement area
const LEFT:Number = CENTER - (SIZE/2); // left of movement area
const RIGHT:Number = CENTER + (SIZE/2); // right of movement area
public function scrollWithHero() {
var scrollAmount:Number = 0; // holds amount to scroll by (init to none)
if ( hero.mc.x < LEFT ) { // if left of movement area reached
scrollAmount = LEFT - hero.mc.x; // calculate scroll amount
hero.mc.x = LEFT; // keep player at left of movement area
}
else if ( hero.mc.x > right ) { // else if right of movement area reached
scrollAmount = hero.mc.x - right; // calculate scroll amount
hero.mc.x = RIGHT; // keep player at right of movement area
}
// here you can use scrollAmount to scroll the level, and the player's
// position to calculate their offset into your level
}
This is a basic example just to calculate the relevant values, you will still need to use them, but this should illustrate the idea of how the scrolling works.
You should experiment with the size to find an area that feels good for your implementation. Also, if you set SIZE=0 then the player will remain in the center of the screen (i.e. it will work as described in the first implementation).

Related

Sprites that are partially off screen

I have a sprite 300x200px and when it is partially off the screen, it starts appearing on the left side (like a cycled sides). Hidden area becomes visible on the left side.
How to avoid that?
var ss = queue.getResult(spriteName);
ss.images = [queue.getResult(spriteName + "_png")];
var ssheet = new createjs.SpriteSheet(ss);
var sprite = new createjs.Sprite(ssheet);
sprite.gotoAndPlay("ssh");
sprite.x = 550;
stage.addChild(sprite);
Update (to be more clear):
Stage is 640x480 in size; Sprite is on the right side of the stage and 30% of the sprite is hidden because its off screen. For some reason this 30% of hidden sprite are being shown and played on the left side of the stage. It looks like a cycled tube. Hidden part are immediately shown on the other side of the stage.

SHOW_ALL gets too big instead of scaling

I want to run a two screen application with AIR on my Macbook Pro with Retina display.
On my left screen (the retina) there is kind of a console, with which you select a movie, on the right screen, there is the selected movie playing.
As usually, I use the StageScaleMode.SHOW_ALL to bring it nicely to fullscreen. But this time, it gets scaled way too big. Maybe 100 times too big. I see only a small top left corner of the movie. It only shows the correct size if I choose StageScaleMode.NO_SCALE;
Has anyone a guess why its like this?
here is the portion of the code, where I bring up the two windows and try to show it fullscreen.
public function setToFullscreen(e:Event):void {
startTimer.stop();
startTimer.removeEventListener("timer", setToFullscreen);
windowBig = new NativeWindow(new NativeWindowInitOptions());
windowBig.width = 1870;
windowBig.height = 468;
windowBig.stage.displayState = StageDisplayState.FULL_SCREEN;
windowBig.stage.scaleMode = StageScaleMode.SHOW_ALL;
windowBig.stage.align = StageAlign.TOP_LEFT;
windowBig.title = "Second Screen Window";
windowSmall = stage.nativeWindow;
windowSmall.width = 1280;
windowSmall.height = 1024;
windowSmall.stage.scaleMode = StageScaleMode.NO_SCALE;
windowSmall.stage.align = StageAlign.TOP_LEFT;
windowSmall.title = "First Screen Window";
ScreenManager.openWindowFullScreenOn(windowBig,2);
loader.load();
}
Thank you for your help!
Like OP said it is not possible automatically with SHOW_ALL, but you can do it manually (here it's not exactly as SHOW_ALL: I'm only fitting content to window height, so it works for a window aspect ratio equal or wider than the content ratio, else content will be cropped):
newWindow.addEventListener(Event.RESIZE, onResize);
function onResize(e:Event):void
{
content.height = newWindow.stage.stageHeight; // fit to height
content.scaleX = content.scaleY; // keep width ratio
// Extra: equivalent of StageAlign.TOP => centers horizontally
// (assuming a content registration point at top-left)
var contentRatio = 4/3; // in case content is wider than necessary, e.g. wide background
content.x = newWindow.stage.stageWidth/2 - (content.height * contentRatio )/2;
}

AS3 - Shooting arrows / targeting

I am creating a game where fairies cross the screen (bottom to top). There is a laser at the bottom of the screen that goes from right to left. I want to shoot the laser, and have the laser bullets to go from bottom to top. The code that I have has it going from top to bottom. I have tried to reverse the direction by changing out the + = 10 to - = 10... This did get the bullets in the right direction, however, it started it towards the top of my screen.
stage.addEventListener(MouseEvent.MOUSE_DOWN, targeting)
function targeting(e:MouseEvent):void{
var newArrow:blackArrow = new blackArrow();
addChild(newArrow);
newArrow.y = 50;
newArrow.x = shooterMC.x;
newArrow.addEventListener(Event.ENTER_FRAME, shoot);
}
function shoot(e:Event):void {
var arrowMC:MovieClip = MovieClip(e.target);
arrowMC.y += 10;
}
Thank you in advance for any help that you can give me.
You have to change this line to your desired position you want to start the laser animation from:
newArrow.y = 50;
The coordinate system starts in the upper left corner. So the lower right corner is window width | window height.

Loop an image in Flash

I want to have a scene where an image which is 5000 pixels high is moving up 5 pixels each frame-refresh. When the image is all up, I'd like to see the top of the image connected to the bottom of the image. This should be done untill the level is 'done'. How can I 'loop' such an Image?
You can create a copy of that image which you keep hidden/above and the trick is to update the position and loop accordingly so when one image goes bellow the screen it goes back on top and repeats.
Here's a basic snippet to illustrate the idea using the DisplayObject class and the scrollRect property:
//ignore this, you have your content already
var dummyContent:BitmapData = new BitmapData(100,100,false);
dummyContent.perlinNoise(10,10,8,12,true,true);
//important stuff starts here
var container:Sprite = addChild(new Sprite()) as Sprite;//make a container
container.scrollRect = new Rectangle(0,0,dummyContent.width,dummyContent.height);//set a scrollRect/'mask'
var part1:DisplayObject = container.addChild(new Bitmap(dummyContent));//add two copies
var part2:DisplayObject = container.addChild(new Bitmap(dummyContent));//of the same content
part2.y -= part2.height;//set the 2nd at the top of the 1st
addEventListener(Event.ENTER_FRAME,update);
function update(e:Event):void{
//move both
part1.y += 5;
part2.y += 5;
//check if any reach the bottom so they can be moved back up
if(part1.y >= part1.height) part1.y = -part1.height;
if(part2.y >= part2.height) part2.y = -part2.height;
//the above can also be nicely placed in a loop if you plan on using more seamless looping clips/images
}
Obviously you will have different content, but the principle is the same.
If you're working with images, you can simply use BitmapData's copyPixels method:
var s:int = 5;//scroll speed
//make some content
var w:int = 100;
var h:int = 100;
var dummyContent:BitmapData = new BitmapData(w,h,false);
dummyContent.perlinNoise(10,10,8,12,true,true);
//prepare for stiching
var renderPos:Point = new Point();//position to render the current image to
var prenderPos:Point = new Point();//position to render the previous image (the 'hidden' copy above)
var render:BitmapData = new BitmapData(w,h,false);//create a bitmap data instance to render updated pixels int
addChild(new Bitmap(render));//and add it to the stage
addEventListener(Event.ENTER_FRAME,update);
function update(e:Event):void{
renderPos.y = (renderPos.y+s)%h;//update the scroll position for the 1st part, % is used to loop back to 0 when the position gets to the content height
prenderPos.y = renderPos.y - h;//update the scroll position for the 2nd part (above)
render.lock();//freeze pixel updates
render.copyPixels(dummyContent,dummyContent.rect,renderPos);//copy pixels from the scroll position to the bottom
render.copyPixels(dummyContent,dummyContent.rect,prenderPos);//copy pixels from the top to the scroll position
render.unlock();//unfreeze/update ALL THE PIXELS
}
You can try to use a Rectangle object which changes height (height-scrollPosition) so you potentially access less pixels each time or you can manually work out single for loops using BitmapData's getVector method, but that's something to look into if performance is actually an issue for such a simple task and it's worth checking what's faster ( copy full bitmap rect vs copy partial bitmap rect vs manually copy values using vector )
Be warned, Flash cannot load an image greater than 16,769,025 pixels (or 4095x4095). The height of 5000 pixels will work as long as the width is not greater than 3353.
That said, I'd loop the image by keeping two copies of the image onstage, move both at the same time with a parent object, and reset to origin once your loop point is met.
Consider the following stage setup:
Stage ¬
0: MainTimeline:MovieClip ¬
0: Container:MovieClip ¬
0: img1:Bitmap
1: img2:Bitmap
Now moving container up, you'd just need to check that the looping second image reaches the origin point of the first image.
function onEnterFrame(e:Event):void {
Container.y = Container.y - 5;
if (Container.y < -5000) {
Container.y = -5;
}
}

as3 finding the offset of a block

I am trying to make a pong like game but i need to find the offset from the center of the paddle so that i can make it bounce differently depending on where it hits the paddle. How can i achieve this?
Try:
// get the center of the paddle
var centerXpaddle = paddle.x - paddle.width/2;
var centerYpaddle = paddle.y -paddle.height/2;
if (objectThatHits.hitTestObject(paddle)) {
// get the current point of object
var offsetX = objectThatHits.x - centerXpaddle;
var offsetY = objectThatHits.y - centerYpaddle;
}
The first two lines get the center of the the paddle (it's current position minus half the width and half the height) and the second part is a "test" for when the "object that hits" hits the "paddle".