FishBowl
FishBowl

Reputation: 9

AS3 Psuedo 3D Z-Indexing

I am attempting to make a really basic Pseudo 3D game in AS3. When I press certain keys my character moves up and down but what I want to happen is when the characters y position is above an objects y position then the character should appear behind the object. Here is my code for an objects class at the moment:

package  {

    import flash.display.MovieClip;
    import flash.utils.getTimer
    import flash.events.Event;

    public class bushMC extends MovieClip {

        private var lastFrame:int = new int(0);
        private var dt:Number = new Number();
        private var main:Main;      

        public function bushMC(){
            main = this.parent as Main;
            stage.addEventListener(Event.ENTER_FRAME, update);
            trace(main.getChildIndex(this));
        }
        private function update(e:Event):void{          
            dt = (getTimer() - lastFrame)/30;
            lastFrame = getTimer();

            if(main.char.y + 200 < this.y + 55 && main.getChildIndex(main.char) > main.getChildIndex(this)){
                main.setChildIndex(this, main.getChildIndex(main.char)+1);

            }
            else if(main.getChildIndex(main.char) < main.getChildIndex(this)){
                main.setChildIndex(this, main.getChildIndex(main.char));
            }
        }
    }

}

I have tried editing loads of the values(+1, -1, equal to) for each calculation but I can't seem to find the right ones. One I tried almost works but instead when the char is supposed to be behind the object it simply flickers in-front and then behind continuously.

Thanks in advance, Kyle.

Upvotes: 0

Views: 229

Answers (2)

Vesper
Vesper

Reputation: 18747

You should have a sorted list of bushes somewhere, which is then added via addChild() in the right order - uppermost bush has lowermost Z-position (child index 0 or the least of bushes, there could be other objects). Then, as your player moves, you track its position relative to list of bushes, so you don't run the full list check for z-ordering of player, but only check "nearest" bushes for possible change, then you set child index of player to found value. Note that if you're setting child index of player to bush's index, if you are moving player forwards (greater indexes), set to -1, as the bush will actually be one position lower because of player occupying a position in the display list, and if you are setting child index to lower values, set to equal. There is a more elegant version of this, using the fact that your bushes are continuous within display list, with only interruption being player, although it will run out of steam once more moving objects will appear.

And yes, you run update on the player or any other moving objects, not on the bush.

function updateZPos(e:Event):void {
    // process coordinates change
    var p:DisplayObjectContainer=this.parent; 
    // a bit faster to use function local var to get parent
    var ci:int=p.getChildIndex(this); // changeable, get current index
    var prev:DisplayObject=null;
    if(ci>0) prev=p.getChildAt(ci-1);
    var next:DisplayObject=null;
    if(ci<p.numChildren-1) next=p.getChildAt(ci+1);
    while(prev) {
        if (this.y<prev.y) {
            ci--;
            p.setChildIndex(this,ci);
            if (ci>0) prev=p.getChildAt(ci-1); else prev=null;
        } else break;
    while(next) {
        if (this.y>next.y) {
            ci++;
            p.setChildIndex(this,ci);
            if(ci<p.numChildren-1) next=p.getChildAt(ci+1); else next=null;
        } else break;
    }
}

This function was written with implication of display list of p being pre-sorted, and will maintain sorted state of it after moving of this, and is suitable for any moving object, not just the player. For this to work without messing up your other objects, separate everything moving into one container which will then get referenced as base for sorting display list. Otherwise your player might eventually get above all as the last element to check will be say score textfield with Y of 0. Also you will need to maintain coherent position of register point all over your set of moving objects' classes, so that say the base of a bush will be at Y=0 instead of being at Y=30, as implied in your code. The legs of a player should then also be at Y=0.

Upvotes: 0

Will
Will

Reputation: 378

I just tried a little quick mock script based off your code. I got it working how I assume you are attempting to get it to work:

import flash.events.Event;
import flash.display.MovieClip;
var char:MovieClip = new MovieClip();
var bush:MovieClip = new MovieClip();

char.graphics.beginFill(0xFF0000);
char.graphics.drawCircle(0, 0, 30);

bush.graphics.beginFill(0x00FF00);
bush.graphics.drawEllipse(0, 0, 40, 80);

this.addChild(char);
this.addChild(bush);

bush.x = 100+(Math.random()*350);
bush.y = 100+(Math.random()*200);

this.addEventListener(Event.ENTER_FRAME, updateYPos);

function updateYPos(e:Event):void {
    char.x = mouseX;
    char.y = mouseY;

    if(char.y < bush.y + 30 && this.getChildIndex(char) >= this.getChildIndex(bush)){
        this.setChildIndex(bush, this.getChildIndex(char));
    }
    else if(char.y > bush.y + 30 && this.getChildIndex(char) < this.getChildIndex(bush)){
        this.setChildIndex(bush, this.getChildIndex(char));
    }
}

I hope this sample is enough to help you. All it needed was an extra condition on the else if and it works. :)

Upvotes: 2

Related Questions