Hi the following code works when scrolling to either the left or right edges of the screen in my game; however when scrolling to the right or bottom edge of the screen when the edge of the "map" has been reached I am able to see beyond the edge of the map i.e. i am seeing white space i.e. the colour of the stage. Whereas, when scrolling to the edge of the map's left or top edge I am not able to see beyond the edge of the map.
public function scroll_screen():void { //scrolling left, right, up, down
var stagePositionX:Number = container.x+player.x;
var rightEdge:Number = stage.stageWidth-edgeDistance;
var leftEdge:Number = edgeDistance;
var stagePositionY:Number = container.y+player.y;
var bottomEdge:Number = stage.stageHeight-edgeDistance;
var topEdge:Number = edgeDistance;
//horizontal scrolling
if (stagePositionX > rightEdge) {
container.x -= (stagePositionX-rightEdge);
if (container.x < -(container.width-stage.stageWidth)) container.x = -(container.width-stage.stageWidth);
}
if (stagePositionX < leftEdge) {
container.x += (leftEdge-stagePositionX);
if (container.x > 0 )container.x = 0;
}
//vertical scrolling
if (stagePositionY > bottomEdge) {
container.y -= (stagePositionY-bottomEdge);
if (container.y < -(container.height-stage.stageHeight)) container.y = -(container.height-stage.stageHeight);
}
if (stagePositionY < topEdge) {
container.y += (topEdge-stagePositionY);
if (container.y > 0) container.y = 0;
}
}
hope that makes sense, thanks
**updated**
Your problem is that container.width is changed when your shapes fly away from initial rectangle.
If you create a var initialContainerWidth and save your container width there until you add any shapes to it and then use this saved variable instead of container.width, it will work fine. Or you can add your flying shapes directly to the stage so that they will not extend container's sizes.
You can just hardcode 1386 instead of container.width to check it.
Related
I have this symbol for a scrollbar in adobe flash:
The instance name of the dark part is handle, and that of the lighter bar is bar. The symbol is an instance of the Scroll class:
package ui {
import flash.display.MovieClip;
import flash.events.MouseEvent;
public class Scroll extends MovieClip{
public static const VERTICAL = 0;
public static const HORIZONTAL = 1;
protected var _handleRatio = 1;
protected var _orientation = VERTICAL;
protected var _mousePrevPos:int;
protected var _handleMargin:int;
protected var _container:MovieClip;
protected var _containerInitialPosition:int; //added after update #2
public function Scroll(container:MovieClip, visibleLength:int, orientation:int = VERTICAL) {
_orientation = orientation;
_container = container;
var containerLength:int;
switch(_orientation){
case VERTICAL:
rotation = 0;
containerLength = container.height;
_containerInitialPosition = container.y; //added after update #2
break
case HORIZONTAL:
rotation = - 90;
containerLength = container.width;
_containerInitialPosition = container.x; //added after update #2
break;
default:
throw new Error('Unknown orientation');
break;
}
if((_handleRatio = visibleLength/containerLength) > 1)
_handleRatio = 1;
handle.height = _handleRatio*height;
_handleMargin = handle.y;
handle.addEventListener(MouseEvent.MOUSE_DOWN, _startDrag, false, 0, true);
}
protected function _startDrag(e:MouseEvent){
stage.addEventListener(MouseEvent.MOUSE_UP, _stopDrag, false, 0, true);
stage.addEventListener(MouseEvent.MOUSE_MOVE, _dragHandle, false, 0, true);
_mousePrevPos = mouseY;
}
protected function _stopDrag(e:MouseEvent = null){
stage.removeEventListener(MouseEvent.MOUSE_UP, _stopDrag);
stage.removeEventListener(MouseEvent.MOUSE_MOVE, _dragHandle);
_mousePrevPos = NaN;
}
protected function _dragHandle(e:MouseEvent){
_moveHandle(mouseY - _mousePrevPos);
_mousePrevPos = mouseY;
}
protected function _moveHandle(moveDifference:int){
if(moveDifference > 0 && !(handle.y + handle.height + _handleMargin > bar.height)){
if(!(handle.y + handle.height + moveDifference + _handleMargin > bar.height))
handle.y = handle.y + moveDifference;
else
handle.y = bar.height - handle.height - _handleMargin;
}
if(moveDifference < 0 && !(handle.y < _handleMargin)){
if(!(handle.y + moveDifference < _handleMargin))
handle.y += moveDifference;
else
handle.y = _handleMargin;
}
switch(_orientation){
case VERTICAL:
_container.y = _containerInitialPosition -((handle.y-_handleMargin)/(bar.height-_handleMargin*2)*_container.height);
// since update #2, the calculated y position is subtracted from the initial y position
break
case HORIZONTAL:
_container.x = _containerInitialPosition -((handle.y-_handleMargin)/(bar.height-_handleMargin*2)*_container.width);
// since update #2, the calculated x position is subtracted from the initial x position
break;
default:
throw new Error('Unknown orientation');
break;
}
}
public function resize(newWidth, newHeight){
switch(_orientation){
case VERTICAL:
width = newWidth;
height = newHeight;
break
case HORIZONTAL:
rotation = 0;
width = newHeight;
height = newWidth;
rotation = -90;
break;
default:
throw new Error('Unknown orientation');
break;
}
}
public function scrollHandle(e:MouseEvent){
_moveHandle(-e.delta);
}
}
}
As you can see, you can create both horizontal and vertical scrollbars. Now, there are two problems with the scrollbar:
For some reason, when dragging the handle up/left with the mouse, the handle moves far slower than the cursor
Also, when you scroll a horizontal scrollbar a little to the right, the left part of the container is cut off, and you can't scroll back to it anymore solved now, see update #2
I really don't know what causes these problems, so can anyone please help me or at least point out where the errors in my code are?
Update
Some extra information to help explain the code:
This is a sketch of a situation where a vertical scrollbar would be needed. The scrollbar would be initiated like so:
var scrollBar:Scroll = new Scroll(container, mask.height, Scroll.VERTICAL);
When the handle of the scrollbar is dragged/scrolled down, the container is moved upwards, so that you get to see a lower part of the contaienr - and vice versa: if you scroll up, the container is moved down.
If you'd want to create a horizontal scrollbar, apart from changing Scroll.VERTICAL into Scroll.HORIZONTAL, you'd pass mask.width as visibleLength instead of mask.height.
I suppose container doesn't neccessarily have to be a MovieClip but can be any DisplayObject.
Also, I'm not using startDrag() so that I can drag the handle and scroll the handle up and down with just one method (_moveHandle()).
Update #2
I solved problem #2: the left part of the container was cut off because when the container hadn't been scrolled yet, the container's x position was somewhere in the middle of the stage. When it was scrolled a little bit to the right, I forgot to set the container's x position to the calculated x position + the initital x position. I updated the code above, with comments behind the new parts so you can see what I changed.
Update #3
You can see a flash file making use of the scrollbar here: http://host.undeadzone.net/scrollBarTest.swf
To reproduce issue #1, do the following:
grab the handle with the mouse and slowly drag the slider down, one notices that the mouse position relative to the slider stays constant. (if you clicked at the top most edge of the handle to start dragging, the mouse will still be at the top most edge when the handle reaches the bottom of the screen. this is the expected behaviour, all good.
Now do the opposite (it doesn't matter if you release the mouse
after doing step 1) and drag the handle upwards slowly. This time,
the position of the mouse relative to the handle changes. If one initiated the drag at the top most edge of the handle and starts
dragging up, the handle does not keep up with the mouse and the
mouse position (relative to the handle) will be above the handle
after dragging, even though it started the dragging within the
handle.
The source code:
http://host.undeadzone.net/scrollBarTest.zip
To fix 1-st issue add e.updateAfterEvent:
protected function _dragHandle(e:MouseEvent){
_moveHandle(mouseY - _mousePrevPos);
_mousePrevPos = mouseY;
e.updateAfterEvent();
}
UPDATE
mouseY returns Number not int.
Replace this line:
protected var _mousePrevPos:int;
with this:
protected var _mousePrevPos:Number;
in Scroll class.
UPDATE #2
Replace
protected function _moveHandle(moveDifference:int){
with
protected function _moveHandle(moveDifference:Number){
Im trying to get an image slider to work properly. But i don't get the next/prev functionality to work.
I have a container mc that holds all images, and a mask that acts as a mask for that container.
Here is how i add the images.
for(var i:int = 0; i<this.container.numChildren; i++) {
var mc:DisplayObject = this.container.getChildAt(i);
if(mc is MovieClip) {
mc.x = xPos;
xPos += mc.width + margin;
mc.y = 0;
}
}
So all images are now positioned in nice row with some margin.
the mask and container has same x/y-position. So, lets say now that i set the witdth of the mask to display 5 of the images that the container holds.
How would i program the next/prev buttons so it displays or hide only one image on click?
eg. tween the container position so it looks correct.
Here is my next and pre function. with is not working. Basically i want the container to always show same amount of items.
private function slideLeft(event:MouseEvent):void {
if(!TweenMax.isTweening(container)) {
var tx:Number = Math.min(container.x + itemWidth, _mask.x);
TweenMax.to(container, 0.3, {x:Math.floor(tx)});
}
}
private function slideRight(event:MouseEvent):void {
if(!TweenMax.isTweening(container)) {
var tx:Number = Math.max(container.x - itemWidth, _mask.x-_mask.width);
TweenMax.to(container, 0.3, {x:Math.floor(tx)});
}
}
Whats wrong? Anyone?
You need to account for the width of the container when showing items to the right. So the minimum x value for the container should be _mask.x - (container.width - _mask.width)
You should also account for the margins or you will see the offset you described in your comment.
private function slideLeft(event:MouseEvent):void {
if(!TweenMax.isTweening(container)) {
var tx:Number = Math.min(container.x + (itemWidth + margin), _mask.x);
TweenMax.to(container, 0.3, {x:Math.floor(tx)});
}
}
private function slideRight(event:MouseEvent):void {
if(!TweenMax.isTweening(container)) {
var tx:Number = Math.max(container.x - (itemWidth + margin), _mask.x - (container.width - _mask.width);
TweenMax.to(container, 0.3, {x:Math.floor(tx)});
}
}
Good luck!
I apologize in advanced if this is a little confusing to understand, but I'll do the best I can to explain it.
Basically I've created a scrolling page that allows you have content that extends beyond the stage and swipe up or down to view it.
In this case, a movieclip the size of the stage masks an object under it (taller than the stage) and swiping up/down affects the objects y position, revealing more of it.
The part I'm stuck on is getting the "scroll bar" object on the side to match the position of the top and bottom of the overflow object;
Since the scroll bar has to stay on the stage, when the bottom of the object is reached the scroll bar ends up being off stage because they move at the same speed, so in this case, the scroll bar would need to move slower in order to be at the bottom when the other object is.
The way it's coded right now I can only seem to match either the top with
scrollbar.y = (e.target.y - barY);
the opposite is achieved by
scrollbar.y = (e.target.y + barY);
but I can't seem to achieve both simultaneously.
I'm coding this in AS3 (flash CC) with mobile being my desired platform to publish, and I'll attach my code as well as some screenshots below.
var ease:int = 6;
var targY:int = dragMe.y;
var barY:int = scrollbar.y;
var drag:Boolean = false;
var pos:Number = 0;
var minY:Number = 0 + dragMe.height / 2; // how low the top can go
var maxY:Number = stage.stageHeight - dragMe.height / 2; // how high the bottom can go
var barMax:Number = 0 + scrollbar.height; // how high the bar can go
var barMin:Number = stage.stageHeight - scrollbar.height; // how low the bar can go
dragMe.mask = mcMask;
mcMask.visible = false;
dragMe.addEventListener(Event.ENTER_FRAME, dragging);
dragMe.addEventListener(MouseEvent.MOUSE_DOWN, mouseDown);
stage.addEventListener(MouseEvent.MOUSE_UP, mouseUp);
function dragging(e:Event):void {
if (drag) {
targY = mouseY + pos;
}
// restrict scrolling to stage
targY = Math.min(targY, minY); // how low the top can go
targY = Math.max(targY, maxY); // how high the bottom can go
barY = Math.min(barY, barMin); // how low the bar can go
barY = Math.max(barY, barMax); // how high the bar can go
// Movement of the text
e.target.y += (targY - e.currentTarget.y) / ease;
// Movement of the bar
scrollbar.y = (e.target.y - barY);
}
function mouseUp(e:MouseEvent):void {
drag = false;
}
function mouseDown(e:MouseEvent):void {
pos = e.currentTarget.y - mouseY;
drag = true;
}
Any help would be greatly appreciated!
Grey = stage
Black = outside stage
Good:
http://i.stack.imgur.com/qvAoz.png
Bad:
http://i.stack.imgur.com/FvHIm.png
The part I'm stuck on is getting the "scroll bar" object on the side to match the position of the top and bottom of the overflow object;
Well, there's no need to get the scrollbar object to match the position of the overflow object, you should bind it to the coordinates of the masker object. Btw I usually gather all UI elements right in the IDE, and then parse them. For example, if I need to add a scroll bar, I need only three elements:
container - all content will be added right in it;
masker
Scrollbar movieclip, which consists of two MCs: bg and a bar.
In this case I don't need to place this elements in code, but just call in a function to handle this elements. The code itself is simple enough. You know the height of the masker, the height and the position of the container, and also the height of the scrollbar background and current position of the bar. All you need is to handle the events and react accordingly.
E.g. in case you are scrolling using your scrollbar, just translate current coordinates of the bar and update container's position. If you are dragging your content, update your bar's position accordingly.
Also, there's a better way to drag the bar:
private static function drag(e:MouseEvent):void
{
var myBounds:Rectangle = new Rectangle(bar.x, 0, 0, barBg.height-bar.height+8);
bar.startDrag(false, myBounds);
bar.addEventListener(Event.ENTER_FRAME, update);
}
static private function stopdrag(e:*):void
{
bar.stopDrag();
update(null);
bar.removeEventListener(Event.ENTER_FRAME, update);
}
static private function update(e:Event):void
{
var scroll_run_length:Number = barBg.height - bar.height + 8;
var modificator:Number = (content.height-masker.height) / scroll_run_length;
content.y = startContY -(bar.y * modificator);
}
I have an Image for drawing my background that I add to the stage. For some reason, there is a small space on the bottom - it's not laid out correctly
See attached image. I draw the background yellow to make it more visible. Why doesn't expand the background all the way to the bottom?
#Override
public void show() {
cam = new OrthographicCamera(Helper.RESOLUTION_WIDTH, Helper.RESOLUTION_HEIGHT);
cam.position.set(Helper.RESOLUTION_WIDTH / 2, Helper.RESOLUTION_HEIGHT / 2, 0);
stage = new Stage(Helper.RESOLUTION_WIDTH, Helper.RESOLUTION_HEIGHT, true);
stage.setCamera(cam); // !IMPORTANT
Image img = new Image(Assets.background);
img.setFillParent(true);
img.setSize(Helper.RESOLUTION_WIDTH, Helper.RESOLUTION_HEIGHT);
stage.addActor(img);
Table table = new Table(skin);
table.debug();
table.setBounds(0, 0, Helper.RESOLUTION_WIDTH, Helper.RESOLUTION_HEIGHT);
table.setFillParent(true);
/* add all the menu items to table */
stage.addActor(table);
}
RESOLUTION_WIDTH = 800
RESOLUTION_HEIGHT = 1280;
I figured out why it would draw that border:
I completely overlooked, that I implemented the resize method and did something weird with the zoom.
cam.viewportHeight = height; //set the viewport
cam.viewportWidth = width;
if (Helper.RESOLUTION_WIDTH / cam.viewportWidth < Helper.RESOLUTION_HEIGHT / cam.viewportHeight)
{
//set the right zoom direct
cam.zoom = Helper.RESOLUTION_HEIGHT / cam.viewportHeight;
} else {
//set the right zoom direct
cam.zoom = Helper.RESOLUTION_WIDTH / cam.viewportWidth;
}
cam.update();
Leaving the resize function to its default implementation fixed the problem.
Thanks, Pranav008 for all the help though!
So Im having trouble figuring this out.
Im trying to make the stage.y and stage.y at the bottom right corner of the stage, so whenever I add a like this
box.x = 100
box.y = 100
this.addChild(box);
it would be 100px from the bottom left corner of the stage.
i tried with
stage.scaleMode = StageScaleMode.NO_SCALE;
stage.align = StageAlign.BOTTOM_LEFT;
but it did`nt work.
Am I missing something?
Your comment of "making a moviecclip and making its Registration point at bottom left ? and adding the things in this movie clip" is certainly one way to do it. Probably the easiest an first method that comes to mind and lets you move it around easily on demand and have any contained objects update.
Another method would be to create a point object and reference that to position everything. Something like:
var origin:Point = new Point(0, this.stage.stageHeight);
and then for your box:
box.x = origin.x + 100;
box.y = origin.y - 100;
However, if you want to change this, you'll have to add some code that goes and updates all the positions of your existing objects.
If you're really insisting on that +y goes upwards and -y going downwards on the stage, you could use a trick, but there may be a hefty overhead mental cost:
Use the first method, but give the movieclip a negative 100 y scaling before positioning at the lower left corner Note that everything will now be upside down though so you'll have to handle/factor that side effect in. Not recommended, but just throwing that out there.
You could also create a static method and call it always when you need, example:
public class DisplayObjectUtils
{
public static function setRegPoint(obj:DisplayObjectContainer, newX:Number, newY:Number):void
{
var bounds:Rectangle = obj.getBounds(obj.parent);
var currentRegX:Number = obj.x - bounds.left;
var currentRegY:Number = obj.y - bounds.top;
var xOffset:Number = newX - currentRegX;
var yOffset:Number = newY - currentRegY;
obj.x += xOffset;
obj.y += yOffset;
var totalChildren:uint = obj.numChildren;
for (var i:int = 0; i < totalChildren; i++)
{
obj.getChildAt(i).x -= xOffset;
obj.getChildAt(i).y -= yOffset;
}
bounds = null;
}
}
And to use, try something like:
//register point in the center of the object //box.width >> 1, box.height >> 1
DisplayObjectUtils.setRegPoint(box, box.width >> 1, box.height >> 1);