Search code examples
actionscript-3flashgame-physicscollisionstage

AS3 How can I constrain an objects movement within the stage?


My object is controlled via mouse movement (for now)... Because of the way it's controlled (object always moves away from cursor), I want to add constraints so that it not only stays within the stage but leaves space between the movement boundaries and the stage edges...

Therefore if the object moves too close to the stage limits, there will be room for the cursor to move it back into the play area.

Currently, I have a rectangle created dynamically within the stage and I was thinking I could constrain movement to within the area of this rectangle, which would leave enough room around the edges... How can I do this?

However, if there's a better/easier way to get the desired results... I'm all ears.

import flash.events.KeyboardEvent;
import flash.display.MovieClip;
import flash.events.Event;
import flash.display.Shape;

var rectangle:Shape = new Shape;
//initialize "rectangle" shape
rectangle.graphics.beginFill(0xCCCCCC); 
//choose colour for fill - black
rectangle.graphics.drawRect(50, 50, 450, 300);
//draw shape
rectangle.graphics.endFill(); 
//end fill
addChild(rectangle);
//add "rectangle" to stage

var hero:MovieClip = new hero_mc();
//initialize "hero" object - "hero_mc"

hero.x = stage.stageWidth / 2;
hero.y = stage.stageHeight / 2;
//set spawn location, centre stage

addChild(hero);
//add "hero" to stage

function cursorHold(evt:Event):void {
    trace("moving");

    var dX:Number = hero.x - stage.mouseX;
    //get adjacent
    var dY:Number = hero.y - stage.mouseY;
    //get opposite

    var r:Number = Math.sqrt(Math.pow(dX, 2) + Math.pow(dY, 2));
    //get hypotenuse

    var angle:Number = Math.acos(dX/r)*180/Math.PI;
    //get angle

    var radians:Number = deg2rad(angle);
    //call conversion function for angle

    var speed:Number = 1.5;
    //set speed

    var xV:Number = Math.cos(radians) * speed;
    //get x velocity
    var yV:Number = Math.sin(radians) * speed;
    //get y velocity

    hero.x += xV;
    //move hero along new x velocity
    if (stage.mouseY > hero.y) {
        hero.y -= yV;
    } else {
        hero.y += yV;
    } 
    //move hero along new y velocity    
}

function deg2rad(deg:Number):Number {
    return deg * (Math.PI / 180);
    //convert degrees to radians
}

stage.addEventListener(Event.ENTER_FRAME, cursorHold, false, 0, true);

Here's an image: https://lh5.googleusercontent.com/lWG8uR9MLK32oHXX26JBiLtBdvmiICFuxOQakQESnBY=w552-h402-no

So, "hero_mc" shouldn't be able to move into the white area but it should still move (scrape against the edges with the mouse movement.

Apologies if the code is a mess... I'm pretty new to ActionScript 3.0. Any tips on cleaning it up a bit would also be more than welcome.


Solution

  • here are some tips for you..

    First, I would add a var for the margin to dynamically draw the active area of the stage and then create the rectangle using that, like this -

    // margin of stage
    var margin:uint = 20; 
    
    rectangle.graphics.drawRect(margin, margin, stage.stageWidth-(2*margin), stage.stageHeight-(2*margin));
    

    Then I would also add a var for getting the center of the hero mc like this -

    var heroCenter:Number = hero.width * .5;
    

    And finally a var for setting the yV to += or -= and using an if to set it like this -

    var posNeg:Number = 0;
    if(stage.mouseY > hero.y){
        posNeg = -1;
    } else {
        posNeg = 1;
    }
    
    hero.y += yV*posNeg;
    

    Here is the full code. I set it to a speed to 10 to test faster.

    import flash.events.KeyboardEvent;
    import flash.display.MovieClip;
    import flash.events.Event;
    import flash.display.Shape;
    
    // margin of stage
    var margin:uint = 20; 
    
    var rectangle:Shape = new Shape;
    //initialize "rectangle" shape
    rectangle.graphics.beginFill(0xCCCCCC); 
    //choose colour for fill - black
    rectangle.graphics.drawRect(margin, margin, stage.stageWidth-(2*margin), stage.stageHeight-(2*margin));
    //draw shape
    rectangle.graphics.endFill(); 
    //end fill
    addChild(rectangle);
    //add "rectangle" to stage
    
    var hero:MovieClip = new hero_mc();
    //initialize "hero" object - "hero_mc"
    
    // half hero to make sure hero goes completely to edge of stage without going over or under
    // best if the hero widht is an even number.
    var heroCenter:Number = hero.width * .5;
    
    hero.x = stage.stageWidth / 2;
    hero.y = stage.stageHeight / 2;
    //set spawn location, centre stage
    
    addChild(hero);
    //add "hero" to stage
    
    var posNeg:Number = 0;
    
    function cursorHold(evt:Event):void {
        //trace("moving");
    
        var dX:Number = hero.x - stage.mouseX;
        //get adjacent
        var dY:Number = hero.y - stage.mouseY;
        //get opposite
    
        var r:Number = Math.sqrt(Math.pow(dX, 2) + Math.pow(dY, 2));
        //get hypotenuse
    
        var angle:Number = Math.acos(dX/r)*180/Math.PI;
        //get angle
    
        var radians:Number = deg2rad(angle);
        //call conversion function for angle
    
        var speed:Number = 10;
        //set speed
    
        var xV:Number = Math.cos(radians) * speed;
        //get x velocity
        var yV:Number = Math.sin(radians) * speed;
        //get y velocity
    
        hero.x += xV;
        if(hero.x < margin + heroCenter){
            hero.x = margin + heroCenter;
        }
    
        if(hero.x > stage.stageWidth - (margin + heroCenter)){
            hero.x = stage.stageWidth - (margin + heroCenter);
        }
    
        if(stage.mouseY > hero.y){
            posNeg = -1;
        } else {
            posNeg = 1;
        }
    
        hero.y += yV*posNeg;
        //move hero along new x velocity
        if (hero.y > stage.stageHeight - (margin + heroCenter)) {
            hero.y = stage.stageHeight - (margin + heroCenter);
        } else if (hero.y < margin + heroCenter) {
            hero.y = margin + heroCenter;
        }
        //move hero along new y velocity    
    }
    
    function deg2rad(deg:Number):Number {
        return deg * (Math.PI / 180);
        //convert degrees to radians
    }
    
    stage.addEventListener(Event.ENTER_FRAME, cursorHold, false, 0, true);