AS3 Stop character from moving through walls

10,565

Solution 1

if (leftArrow && ! hitting)

char will move if hitting is false. When char.hitTestObject(bounds) is true you are setting hitting to true. You are not setting hitting again to false anywhere. That's why once left wall is hit it stops left movement permanently. You need to figure out suitable condition to set hitting to false again.

Adding an else branch in detectHit should solve the problem.

function detectHit(e:Event):void {
   if(char.hitTestObject(bounds))
   {
       hitting = true;
   } else { 
       hitting = false;    // add this
   }
}

Solution 2

Allthough Taskinoor's method should work, I would suggest another way to do your hittests.

Since you probably are creating a game (character and bounds), you will have more than one bound. In that case, I would strongly suggest bitmap-hittesting. This way, you can create all your bounds in one movieclip and test for a hit.

I will explain this by using the example of a maze. The maze would then be some lines in a movieclip, randomly put together. If you use HitTestObject and you aren't hitting one of the lines, but your character is over the movieclip, hitTestObject will return true, even though you are not hitting a wall. By using bitmapHitTesting, you can overcome this problem (BitmapHitTest takes transparant pixels into account, whereas hitTestObject does not).

Below you can find an example of how to do bitmapHitTesting. Creating the bitmaps in this function is not necesarry if they do not change shape. In that case, I would suggest placing the code for the bitmapdata in a added_to_stage-method.

private var _previousX:int;
private var _previousY:int;
private var _bmpd:BitmapData ;
private var _physicalBitmapData:BitmapData;

private function walkAround(e:Event):void
{
    var _xTo:int = //Calculate x-to-position;
    var _yTo:int = //Calculate y-to-position;

    //If your character doesn't change shape, you don't have to recalculate this bitmapData over and over. 
    //I suggest placing it in a ADDED_TO_STAGE-Event in that case.
    _bmpd = new BitmapData(char.width, char.height, true, 0);
    _bmpd.draw(char);   

    //If your bounds are static, you don't have to recalculate this bitmapData over and over. 
    //I suggest placing it in a ADDED_TO_STAGE-Event in that case.
    _physicalBitmapData = new BitmapData(bounds.width, bounds.height, true, 0);
    _bmpd.draw(bounds);

    //The below line is the actual hittest
    if(_physicalBitmapData.hitTest(new Point(0, 0), 255, _bmpd, new Point(char.x, char.y), 255))
    {
        char.x = _previousX;
        char.y = _previousY;
    }
    else
    {           
        char.x = _xTo;
        char.y = _yTo;
    }

    _previousX = char.x;
    _previousY = char.y;
}

Solution 3

Look at my hint,

function loop(Event)
{    
    if(isHit==false)
    {
       if(isRight==true){head_mc.x+=1}
       if(isLeft==true){head_mc.x-=1}
       if(isUp==true){head_mc.y-=1}
       if(isDown==true){head_mc.y+=1}
    }

    if(head_mc.hitTestObject(build_mc))
    {
        isHit=true;

        if(isRight==true){head_mc.x-=1}
        if(isLeft==true){head_mc.x+=1}
        if(isUp==true){head_mc.y+=1}
        if(isDown==true){head_mc.y-=1}
    }
    else
    {
        isHit=false;
    }                                        
 }

I use step back to opposite direction instead.

Share:
10,565
Opoe
Author by

Opoe

Updated on June 04, 2022

Comments

  • Opoe
    Opoe almost 2 years

    I want to stop the movieclips movement when it hits a wall (another movieclip). The example below works, but after the collision the movieclip 'blocks' all movement to the left... My question to you is, is this a good way and why isn't it working well?

    There will be something wrong in this code, but i'm learning. For now the example with the leftArrow key;

    variables to check the key, if it's hitting the walls and if it's moving or not:

    var leftArrow:Boolean;
    var speed:int = 10;
    var hitting:Boolean;
    var ismoving:Boolean;
    

    event listeners for the keys/movement and detecting collision:

    stage.addEventListener(KeyboardEvent.KEY_DOWN, keyPressed);
    stage.addEventListener(KeyboardEvent.KEY_UP, keyReleased);
    stage.addEventListener(Event.ENTER_FRAME, walking);
    stage.addEventListener(Event.ENTER_FRAME, detectHit);
    

    detecting collision function:

    function detectHit(e:Event) :void
    {
       if(char.hitTestObject(bounds))
       {
           hitting = true;
       }
    }
    

    function to the left arrow key:

    function keyPressed(event:KeyboardEvent):void
    {
    
        if (event.keyCode == Keyboard.LEFT)
        {
           leftArrow = true;
        }
    
    }
    
    function keyReleased(event:KeyboardEvent):void 
    {
    
        if (event.keyCode == Keyboard.LEFT) 
        {
            leftArrow = false;
        }
    
    }
    

    And the reason it's not working is probably here, but I don't understand why not:

    function walking(event:Event):void {
        if (rightArrow) {
            char.x += speed;    
        }
    
        if (leftArrow && ! hitting) {
            char.x -= speed;
        }
        else
        {
            ismoving = false
        }
    
  • LiraNuna
    LiraNuna over 12 years
    Or just hitting = char.hitTestObject(bounds)
  • Opoe
    Opoe over 12 years
    @taskinoor thank you for the explanation and taking the time to answer
  • Opoe
    Opoe over 12 years
    Thank you for this answer I'm giving this a go when I get more advanced appreciate your time!