PDA

View Full Version : [AS3] Is making enemies move by waypoints a good idea?


kidshenlong
04-21-2011, 01:43 PM
Hey guys, I'll keep it short.

Got some enemies in an array which I'd like to move in a predetermined path... I've done a bit of research. And I think it's a good choice as setting up some sort of real AI or A* algorithm might be a bit overkill as I just need space invader like movement really...

So 3 questions really... Waypoints, yes? If so, how would I go about using them and finally if I was to use way points I'd imagine using these coordinates with an array would make all my enemies move as one... How would I avoid this?

Thanks!!

Rhuno
04-21-2011, 04:41 PM
Waypoints are good; especially for simple AI. Even A* essentially just generates waypoints to form a path anyway. The difference is it can do it in real time as opposed to the predetermined route you're looking at.

To use them, just pick the points you want the enemies to move to. When you determine that an enemy has reached a point, set his target as the next one in the sequence. As for the grouping problem, there are several options:

- Start enemies out at varying distances from the first point
- Set them on timers so that they don't all start following the path at the same time
- Have a large array of waypoints and have the enemies select a smaller subset of those points to follow. This way not all enemies will have the same path.

Hope that helps; I'd be interested to see other suggestions also!

rrh
04-21-2011, 04:57 PM
For Space Invader movement, you might give each invader an offsetx and offsety to identify where each should be positioned relative to the group as a whole.

I don't think I'd really use waypoints for Space Invaders. The movement is a fairly simple pattern, but with variations. Like, if you shoot the outer columns of the group, the group will have to move farther to reach the wall. So I don't think you can really assign it a specific point, it's a whole region.

kidshenlong
04-21-2011, 08:42 PM
Tbh space invader movement was just an example. They'll be doing a whole bunch of crazy movement hopefully... I can see why having a set point would be bad especially for your example "rrh"... But that is tbh a lot more intelligent than I'd like to make them right now... Thanks for the suggestions Rhuno I'm gonna get cracking on em right now. Has anyone got a specific details of how I'd do this? Google's a bit unclear?

Keep the suggestions coming!!

tadster
04-22-2011, 06:06 PM
Why not just give them all individual looping functions, in which they follow their own path/instructions/tween. You would also have to set up a way in which they can all loop at different speeds, and a way to fully optimize such a strategy. (because adding many enter frame or timer loops, will drain performance)

kidshenlong
04-22-2011, 06:49 PM
Because tbh I don't need them doing separate things. I'd like them all to fly in one by one whiz around for a bit all following the same path) become stationary for a bit and if they haven't been destroyed after a certain while start whizzing again... They'd all be going at the same speed and have all the same attributes... Need to space them actually...

Any other ideas??

I'm still not too sure how to go about doing waypoints...

tadster
04-22-2011, 09:37 PM
Looks like you want to make a class for your enemies. So they all would be of the same class, then just add them to the game, creating a method that happens when they get added, that would then start them following the way point.

Tweening is an example of using pre-determined points for motion.

kidshenlong
04-22-2011, 10:30 PM
Ohh I've got a class and method set up already. Just need help setting up the actual way points now.... wouldn't tweening be more the animation side rather than coding? Either way could someone explain hoe to set way points or tweening up? Or link to a tutorial? Leaning towards way points tbh

kidshenlong
04-22-2011, 10:48 PM
Double post

tadster
04-23-2011, 02:30 AM
package {

import flash.display.*;
import EnemyClass;


public class Main extends Sprite {

private var commonPath:Array =
[0,0,4,4,8,9,10,10,12,12,14,12,21,24,34,38,34,50,34 ,75,34,100,34,150,34,200,34,150,34,300,34,350,34,5 00];

public function Main() {

addEnemy();

}
public function addEnemy():void {

addChild(new EnemyClass(commonPath));

}
}
}



package {

import flash.display.Sprite;
import flash.events.Event;

public class EnemyClass extends Sprite {
public var path:Array = [];
public function EnemyClass(path:Array = null) {
this.path = path;
with(this.graphics) {
beginFill(0xFF0000);drawCircle(0,0,20);
}
if(!stage) addEventListener(Event.ADDED_TO_STAGE, startMoving) else startMoving(null);
}
private function startMoving(e:Event):void {
removeEventListener(Event.ADDED_TO_STAGE, startMoving);
addEventListener(Event.ENTER_FRAME, move);
}

private function move(e:Event):void {
if(path.length >= 2) {
this.x = path.pop();
this.y = path.pop();
} else {
removeEventListener(Event.ENTER_FRAME, move);
parent.removeChild(this);
(parent as Main).addEnemy();
}
}
}
}


Something like that should get you started.

kidshenlong
04-24-2011, 06:22 PM
Would you mind explaining the code a bit. Tried to get it to work but I don't understand it entirely...

tadster
04-24-2011, 06:40 PM
ok, here we go, are you using the Flash IDE, CS5 or some other?
I've edited the code I did in the other posts (I had forgot to put package declarations) using that we'll go step by step:

Open Flash and make a brand new blank fla, save it somewhere on your computer.

save the first code as Main.as
and the second as EnemyClass.as

then put both files in the same folder as the fla.

then in Flash put "Main" in the Class box

then test movie.

a red circle will travel down the screen going a little bit jagged then straiten out and continue down. When it is done, another one will then start to go, but it will all happen pretty fast.
What is happening is the points in the array are being used to tell the circles/enemies where to travel, the commonPath array contains the waypoints, or set of numbers that represent the x and y positions the enemy will travel.

kidshenlong
04-24-2011, 06:52 PM
I got the setting up part, just the actual code and how it works are still a bit of a mystery...

Anyway I did what you said and the ball just flies up out of the left corner and I get this error message:

TypeError: Error #1009: Cannot access a property or method of a null object reference.
at EnemyClass/move()

A lot of my programs give me this error and I'm still not too sure what's wrong...

rrh
04-24-2011, 07:00 PM
Any time there's a null object reference it means you tried to access something like:
blah.function();
or
blah.property;But blah wasn't defined.
In the move function, trace the values of path and parent, see if they are null.
trace(path);

kidshenlong
04-24-2011, 07:05 PM
Ahhh I know what you mean. So how would I then go about giving "blah" a definition?

And when I traced it gave me this:


0,0,4,4,8,9,10,10,12,12,14,12,21,24,34,38,34,50,34 ,75,34,100,34,150,34,200,34,150,34,300,34,350
0,0,4,4,8,9,10,10,12,12,14,12,21,24,34,38,34,50,34 ,75,34,100,34,150,34,200,34,150,34,300
0,0,4,4,8,9,10,10,12,12,14,12,21,24,34,38,34,50,34 ,75,34,100,34,150,34,200,34,150
0,0,4,4,8,9,10,10,12,12,14,12,21,24,34,38,34,50,34 ,75,34,100,34,150,34,200
0,0,4,4,8,9,10,10,12,12,14,12,21,24,34,38,34,50,34 ,75,34,100,34,150
0,0,4,4,8,9,10,10,12,12,14,12,21,24,34,38,34,50,34 ,75,34,100
0,0,4,4,8,9,10,10,12,12,14,12,21,24,34,38,34,50,34 ,75
0,0,4,4,8,9,10,10,12,12,14,12,21,24,34,38,34,50
0,0,4,4,8,9,10,10,12,12,14,12,21,24,34,38
0,0,4,4,8,9,10,10,12,12,14,12,21,24
0,0,4,4,8,9,10,10,12,12,14,12
0,0,4,4,8,9,10,10,12,12
0,0,4,4,8,9,10,10
0,0,4,4,8,9
0,0,4,4
0,0

TypeError: Error #1009: Cannot access a property or method of a null object reference.
at EnemyClass/move()

tadster
04-24-2011, 07:09 PM
oh, woops, swap these lines:


parent.removeChild(this);
(parent as Main).addEnemy();


to this:

(parent as Main).addEnemy();
parent.removeChild(this);


and, to make it go down, let's use shift instead of pop in the move method.

this.x = path.shift();
this.y = path.shift();

kidshenlong
04-24-2011, 07:15 PM
It works!! Who thought solving that problem could be so simple.... So I basically just have to mess around with this code and I can position the enemies where ever??

One other question seeing as your here! Some of my main code has been throwing an errors at me for ages! Would you mind taking a look at it? I'm sure it's something small...

tadster
04-24-2011, 07:22 PM
Yes! you've got the idea, just messing with the numbers in the array will make the enemy move different, the values are x y pairs.

Ok, I'll look at your code, please only post the relevant parts.

kidshenlong
04-24-2011, 07:33 PM
Yes! you've got the idea, just messing with the numbers in the array will make the enemy move different, the values are x y pairs.

Ok, I'll look at your code, please only post the relevant parts.

Thanks a million dude :)

The relevant parts I guess would be where it says the error is happening...

The actual error code is TypeError: Error #1010: A term is undefined and has no properties.
at alienTester/moveShot()
at alienTester/moveAll()

And it happens when I try to shoot a enemy.

Here's moveAll...

public function moveAll(event:Event) {
moveShip();

//moveEnemy()

var timePassed:uint=getTimer()-lastTime;
lastTime+=timePassed;


moveShot(timePassed);

}


And moveShot

private function moveShot(timeDiff:uint){
for(var n:uint=0;n<shotArray.length;n++) {
//add vel to position
shotArray[n].shot.y -= 10;
//find out if shot has gone off the screen
if(shotArray[n].shot.y < TOP) {
//shot is off screen - get rid of it
removeChild(shotArray[n].shot);
shotArray.splice(n, 1);
}
//for (var i:uint=0; i<enemyArray.length; i++) {
if(shotArray[n].shot.hitTestObject(enemy)){
enemy.parent.removeChild(enemy);

//}
}

}
}


The other error is this:

TypeError: Error #1034: Type Coercion failed: cannot convert Object@2988aaa9 to flash.display.DisplayObject.
at Asteria/moveShot()
at Asteria/moveAll()

but the code for that one is slightly different but same cause. I try to shoot an enemy and that happens the enemy won't be removed. I assume the relevant bits would be

public function moveAll(event:Event) {
moveShip();
//
moveShot();
//
//get timer difference and animate asteroids
var timePassed:uint = getTimer() - lastTime;
lastTime += timePassed;
moveAst(timePassed);
moveEnemy(timePassed);



}//end of move all

and

private function moveShot():void {
for(var n:uint=0;n<shotArray.length;n++) {
//add vel to position
shotArray[n].shot.y -= 10;
//find out if shot has gone off the screen
if(shotArray[n].shot.y < TOP) {
//shot is off screen - get rid of it
removeChild(shotArray[n].shot);
shotArray.splice(n, 1);
}
for (var i:uint=0; i<enemyArray.length; i++) {
if (shotArray[n].shot.hitTestObject(enemyArray[i])) {
// remove movie clip from stage
removeChild(enemyArray[i]);

// remove from array

//enemyArray.splice(i, 1);

// score
//score += 100;
//scoreTxt.text = score.toString();
//alter ball's path, make game more exciting
removeChild(shotArray[n].shot);
shotArray.splice(n, 1);

}
if (enemyArray.length == 0) {
// no more blocks - game over
trace("Congratulations! You win");
}
}
//if asteroid is big enough, break it in half

for (var j:uint=0; j<astArray.length; j++) {
if (shotArray[n].shot.hitTestObject(astArray[j].asteroid)) {
//remove shot and update count

removeChild(shotArray[i].shot);
shotArray.splice(i, 1);
//if (numShots>0) {
//numShots--;
//}
//if asteroid is big enough, break it in half
if (astArray[j].asteroid.scaleX>0.5) {
//make asteroid half the size
astArray[j].asteroid.scaleX /= 2;
astArray[j].asteroid.scaleY /= 2;
//create another asteroid in the same place
//gives the impression that the asteroid has split in two
asteroid = new mcAsteroid();
asteroid.y = astArray[j].asteroid.y;
asteroid.x = astArray[j].asteroid.x;
asteroid.scaleX = astArray[j].asteroid.scaleX;
asteroid.scaleY = astArray[j].asteroid.scaleY;
asteroid.rotation = Math.random()*360;
//var velX:Number = Math.random()*2-1.5;
var velY:Number = Math.random()*2+1.5;
addChild(asteroid);
//push this asteroid into the array
astArray.push({asteroid:asteroid, velY:velY});
} else {
//asteroid is small enough - remove it from the stage
removeChild(astArray[j].asteroid);
//remove it from the array
astArray.splice(j, 1);
}
}
}

}
}//end moveShot()

private function placeEnemies(e:Event) : void
{
if(enemyArray.length < 5){

//run if condition is met.
if (Math.floor(Math.random() * 90) == 5)
{
enemy = new mcEnemy();

enemy.y = 100 // Math.random() * 800;
enemy.x = Math.random() * 500;
addChild(enemy);
trace("enemy created");
var velY:Number = Math.random()*2+1.5;
enemyArray.push({enemy:enemy, velY:velY});
}
}
if (enemyArray.length == 5)
{

trace("enemies at 5");
removeEventListener(Event.ENTER_FRAME, placeEnemies);
enemyArray.length == 0;

}


}//placeEnemies

Sorry there's so much. Tried to keep it down to relevant but kinda hard lol

tadster
04-24-2011, 07:39 PM
I just saw you had posted it in another thread earlier, and i posted in that one too, but I think this line of code is the problem

for (var i:uint=0; i<enemyArray.length; i++) {
if (shotArray[n].shot.hitTestObject(enemyArray[i])) {
// remove movie clip from stage
removeChild(enemyArray[i]);

// remove from array

//enemyArray.splice(i, 1);

// score
//score += 100;
//scoreTxt.text = score.toString();
//alter ball's path, make game more exciting
removeChild(shotArray[n].shot);
shotArray.splice(n, 1);

}

enemyArray[i] in both cases should be enemyArray[i].enemy

and you do need to be splicing the enemyArray

kidshenlong
04-24-2011, 07:46 PM
I'm goign to respond in the other thread to keep things on track!