issue with addChild's X and Y value - actionscript-3

I have an Enemy class that deals with my monster moving and attacking. Within that class, I have another class called enemyMagic, which is a blank movieclip that serves as a masterclass to different movieclips that I will make.
So in the enemyMagic class, I add a movieclip called attack1
public var attack1:Attack1 = new Attack1;
public function EnemyMagic() {
////////////CREATE THE TIMER//////////
masterEnemyAttackTimer.addEventListener(TimerEvent.TIMER, mastertimer);
////////////ATTACKS/////////
//TIER 1//
addChild(attack1);
}
And in the enemy class, I add the enemyMagic when the enemy is attacking a certain position.
for (var k:int = 0; k < Main.tileset.length; k++)
{
if (! Main.tileset[k].tileMiddle.hitTestObject(this.enemyVisionPoint))
{
if (Main.tileset[k].tileHP !== 0)
{
attackoptions.push(Main.tileset[k]);
}
if (Main.tileset[k].tileMiddle.hitTestObject(Main.player.visionPoint))
{
addChild(enemymagic);
Main.tileset[k].outline.gotoAndStop("attack");
this.enemymagic.x = (Main.tileset[k].x);
this.enemymagic.y = (Main.tileset[k].y);
trace(enemymagic.x, enemymagic.y, Main.tileset[k].x, Main.tileset[k].y);
For some reason, the enemymagic is tracing the exact same number as the tile's x and y, but it isn't adding it on the tile. It adds it way off the screen. I think it might be because it starts on the enemy's x and y and then calculates?
So my question is how can I get the enemymagic movie clip to get exactly on the position of the tile?

You can do two things. First, when you do a plain addChild() the base coordinate system of the child is the one of its parent, which is your Enemy instance, which is of course at somewhere nonzero. And then you assign it the coordinates of Main.tileset[k] which has a different parent (most likely instance of Main). This creates the distance you speak of. So, in order to locate your magic over the exact tile, either use this.globalToLocal(Main.tileset[k].localToGlobal(PZERO)) where PZERO is a new Point() constant (or write new Point() instead of PZERO, but this will create another empty Point object and will quickly escalate), or do an addChild() directly to the tile you are attacking with unaltered coordinates.

Related

as3 - How to sort display objects that constantly switch depths?

I have a 2.5D game (2D game that acts like a 3D game) where you constantly switch depths, where the player displays on top of an object when it walks in front of it and when it walks behind it, the object displays on top of the player. Like when the player's y is less than the object's y, the player would be going behind the object and vice versa.
I tried to use a code like this:
if (player.y < block.y)
{
setChildIndex(block, numChildren - 5);
}
else if (player.y > block.y)
{
setChildIndex(block, numChildren - 10);
}
However, I see if I do it this way with multiple times, I would need tons of codes and the display list would get mixed up and sort the wrong depths in the wrong orders. Would anyone please show an organized depth changer with minimal code?
Use a z-index stack sorting, (also refered as z-buffer in the 3D graphics literature) the same used to create the 3D depth effect using just 2D techniques.
In other words assign to each object a zIndex and at regular intervals (e.g onEnterFrame event) run a zsort routine which sorts (the order of) display objects based on their zIndex value. Or, alternatively, you can run zsort routine manualy each time a change of zIndex happens on objects.
Then in your code you simply assign zIndex values to display objects to simulate an object passing in-front or behind another object and zsort takes care of the rest.
A trick here is to have appropriate gaps (i.e not necessarily next zIndex+1) in the values of zIndex assigned on objects, so that objects can be placed between these gaps to simulate passing in front or behind other objects, without having to adjust more than one zIndex value each time, i.e you adjust only one zIndex value of the object passing in-front or behind another object, and not the zIndex of that other object.
The amount of gap between successive zIndexes can be estimated from the maximum number of (other) objects which at any given time might be between these objects (so for example, if, at maximum, 3 objects might at some time move between, in-front or behind any given object, then a gap value for successive zIndexes would be 3 so that all the objects can be accomodated)
here is a very simple zsorter routine which runs periodicaly onEnterFrame event and does the necessary depth sorting for you (from reference 1. below)
package {
import flash.display.*;
import flash.events.*;
public class DepthSortSpace extends MovieClip {
public function DepthSortSpace() {
super();
this.addEventListener( Event.ADDED_TO_STAGE, this.addedToStage, false, 0, true );
}
private function addedToStage( e:Event ) {
this.stage.addEventListener( Event.ENTER_FRAME, this.enterFrame, false, 0, true );
}
private function sortDisplayList():void {
var len:uint = numChildren;
var i,j;
for( i=0; i < len-1; i++ )
for (j=i+1; j < len; j++)
if ( getChildAt(i).y > getChildAt(j).y ) this.swapChildrenAt( i, j );
}
private function enterFrame(e:Event) {
this.sortDisplayList();
}
}
}
The zsorter above is in-fact a movieClip which acts as a scene container, in that you add your display objects to the zsorter movieClip and this takes care to sort them accordingly, but one can just take the zsort routine and apply it to any DisplayObjectContainer or Scene object instance.
Note, the zsorter above uses a bubbleSort sorting algorithm, which has a O(n^2) complexity, but one can use another sorting algorithm (e.g mergeSort with O(n lgn) complexity)
examples and references
http://nephilim.blogspot.gr/2010/06/easy-depth-sorting-in-actionscript-3.html
http://www.actionscript.org/forums/actionscript-3-0-a/169035-sorting-technique.html
http://www.simppa.fi/blog/the-fastest-way-to-z-sort-and-handle-objects-in-as3/

LibGDX - given an arraylist of moving circles, how can i check for collision between them?

So I have 3 classes, MyGdxGame, Ball and DetectCollision. MyGdxGame initialises 4 instances of Ball (different colours and speed/direction, all bounce off the sides of the screen) and stores them as an arraylist.
This arraylist is passed through the constructor of DetectCollision:
public class DetectCollisions {
ArrayList<Ball> ball;
public DetectCollisions(ArrayList<Ball> ball) {
this.ball = ball;
start();
}
public void start() {
for(int i=0; i<ball.size();i++) {
...
}
}
Can anyone give me a hint as to where I should go with this? I just want to detect every time a ball collides with another (and eventually I'll have it print the number of collisions).
Any help highly appreciated :)
If you are going to add a lot of objects to the arraylist, use a 2D physics engine to do all the work for you. If you want to continue implementing your own functions, the very basic method to do is to implement a nested loop over the list to check every possible pair in the arraylist. The complexity is O(n^2)
for(int i=0; i<ball.size();i++) {
for(int j=i+1; j<ball.size();j++) {
check(ball.get(i), ball.get(j));
}
}
The method named check checks if given two circles collide or not. Checking two circles' collision is very easy. If the distance between the central points of the circles is smaller than the sum of the radiuses of the circles, then they collide. Check this page for further info about this.
This is very easy to accomplish if you let each Ball have bounds of type Circle.
You can make a circle as follows: Circle ballBounds = new Circle(float x, float y, float radius) This circle can act as the bounds of each ball ultimately allowing you to check if they collide using the Intersector class.
Having each Ball's boundary we can easily loop through the ArrayList<Ball> and check how many collide. For example:
ArrayList<Ball> ball = new ArrayList<Ball>(); // You need to add Balls to this ArrayList
Intersector intersector = new Intersector();
int counter = 0;
for(int i = 0; i < ball.size()-2; i++){
if(intersecor.overlaps(ball.get(i), ball.get(i+1)){
counter++;
}
i++;
}

AS3 Child Index in relation to Stage

I m currently moving my CPU image post processing frame from AS2 to AS3. I used an array to handle all the objects that need to be rendered each frame.
I sort the array by the object's depth on _root, and then render them all onto one bitmapdata in order to draw them in the correct order.
In my AS3 game project I used displayobjectcontainers to handle "depths". for example I have multiple movieclips acting as containers on MovieClip(root), and then add the child to those movieclips to sort them. I also have other child containers inside those containers, forming an hierarchy.
But now I find it hard to sort the render list array because I cannot simply input an absolute "depth" value for the object. I use parent.getChildIndex, but this just gives me the index of the child in one of those containers.
Ofcourse you can make a big function and finally sort the array, but is there anyway to give the object's absolute index in relation to the root/stage?
Thanks a lot.
You could try something like this, which will start at a given DisplayObjectContainer and generate a list of all descendants in order of depth:
function collateChildren(container:DisplayObjectContainer):Vector.<DisplayObject>
{
var list:Vector.<DisplayObject> = new <DisplayObject>[];
for(var i:int = 0; i < container.numChildren; i++)
{
var child:DisplayObject = container.getChildAt(i);
if(child is DisplayObjectContainer && (child as DisplayObjectContainer).numChildren > 0)
{
// Target contains additional children.
list = list.concat(collateChildren(child as DisplayObjectContainer));
}
else
{
// Target is a child.
list.push(child);
}
}
return list;
}
This will not include children who contain other children, and can be used like:
var children:Vector.<DisplayObject> = collateChildren(stage);
trace(children);
A game world would consist of some layers,like role layer, map layer, and each layer has it's depth in the game world. When you try to add some displayobjects to the world, add the displayobjects to the targe layer.
At most time, the layer count won't be large, like 5 or 6. So you can draw the objects on each layer by layer depth.

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.
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. :)
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.

AS3: How to refer an object by his properties

Well, I'm doing a checkers game and I need to refer a piece by its position (x and y, both) and remove it from the screen (no problem with this).
I've been traying combinations with "this." but nothing.
How would you do that?
this.x and this.y are functional from the scope of your checkers pieces object; however, if you're accessing a piece outside of their scope, you must use a piece's instance name. Although not optimal, you could loop through children DisplayObjects.
// create a collection of your checker pieces
var checkers:Array = [];
// create a checker piece, whatever your DisplayObject class is.
var checker:Checker;
checkers.push(checker);
// add it to the stage, probably your game board
addChild(checker);
checker.x = 100;
checker.y = 100;
// loop through the children (from your game board)
for (var i:uint = 0; i < numChildren; i++)
{
var checker:DisplayObject = getChildAt(i);
trace(checker.x);
trace(checker.y);
}
Using coordinates to reference a piece may not be optimal for game play. You might want to consider a row / column or approach it from how your game board works.
If this is not clear, you should specify some code or expand your question with more detail.