Space Invaders monster movment? How?
by Thomas Svensson · in Torque Game Builder · 05/17/2007 (9:01 am) · 14 replies
I am learning the ins and outs of TGB (Or rather just learning TGB).
For my first learningproject i decided i wanted to make a Space Invader MONSTER movment arrangement.
No shooting, no nothing but make some monster act in clusters of let say 24. Every monster shall be "aware" of eachother to that point that when that monster or monsters who is nearest the world limit "crashes into" that limit everybody turns. So, every monsters stay in place during a turn.
What i have done is the easiest thing.
I have tried to just let monster be aware of different world limits. Which is a bad solution since the monster get very odd confinement that way. So i scrapped that. ( i am a newbie! :) )
I then got the brilliant idea of making every monster think for them selfs regarding collision, when a monster crashes into another one, its time to turn. (It sure looked funny doing it that way).
I then started to think about what i want to do and realized that this is an array moving about of some sort. Looking at the help i saw that there was some array stuff available and also that the majong demo had arrays in it. ( i didn't do that tutorial at first but i have now (since i couldn't blew up anything, it was of little interest - me, destructor of world? Perhaps)).
If i had an array of looking like this (1,1 to 4,6) (four rows with 6 columns (a small invader fleet, but its not the size thats matter). I could then track every object.
And now i started to see a solution. How one should do it, then i started to think of it in the limited amount of knowledge i have in TGB and wondered. Am i on the right track? Or am i overly complicating stuff?
I do want to be able to let every row act in a special way. Have different attack patterns so to speak. And also be able to divide the group into half.
I know, perhaps i should start with something simpler, but i do know how one entity exist and how you script movement to that, and how you shoot things (and get your fish to swim away to be gone forever). This would teach me a lot on what to expect when the real project starts in a couple of months.
I hope i'll get some pointer on this, if not i will try and solve this problem and come back with an solution later.
For my first learningproject i decided i wanted to make a Space Invader MONSTER movment arrangement.
No shooting, no nothing but make some monster act in clusters of let say 24. Every monster shall be "aware" of eachother to that point that when that monster or monsters who is nearest the world limit "crashes into" that limit everybody turns. So, every monsters stay in place during a turn.
What i have done is the easiest thing.
I have tried to just let monster be aware of different world limits. Which is a bad solution since the monster get very odd confinement that way. So i scrapped that. ( i am a newbie! :) )
I then got the brilliant idea of making every monster think for them selfs regarding collision, when a monster crashes into another one, its time to turn. (It sure looked funny doing it that way).
I then started to think about what i want to do and realized that this is an array moving about of some sort. Looking at the help i saw that there was some array stuff available and also that the majong demo had arrays in it. ( i didn't do that tutorial at first but i have now (since i couldn't blew up anything, it was of little interest - me, destructor of world? Perhaps)).
If i had an array of looking like this (1,1 to 4,6) (four rows with 6 columns (a small invader fleet, but its not the size thats matter). I could then track every object.
And now i started to see a solution. How one should do it, then i started to think of it in the limited amount of knowledge i have in TGB and wondered. Am i on the right track? Or am i overly complicating stuff?
I do want to be able to let every row act in a special way. Have different attack patterns so to speak. And also be able to divide the group into half.
I know, perhaps i should start with something simpler, but i do know how one entity exist and how you script movement to that, and how you shoot things (and get your fish to swim away to be gone forever). This would teach me a lot on what to expect when the real project starts in a couple of months.
I hope i'll get some pointer on this, if not i will try and solve this problem and come back with an solution later.
#2
One thing i was thinking of (and wrongly) was that i was going to use one object (one monster) and then link the other 23 to it. I couldn't make it work when i tried the function.
But what you saying, if i understand you correctly, is basicly: (and now i am thinking visually).
Create a rectacngle and hang up your monster as if they were christmasdecorations. I then take it that you can unlink and link them back unto this "piece" as you see fit by scripts?
Please stop me if i am completly wrong, but if this works, it will solve alot of other problem following this, but problems i didn't want to tackle until i had a moving unit.
Very much thank you for getting me on track on this one.
05/17/2007 (12:20 pm)
I have had many thoughts about this during the day walking my dog. Link points has been one of them. But when your not sure your tend to run home to "mama" and do it the way your should have done it in a language familiar to you.One thing i was thinking of (and wrongly) was that i was going to use one object (one monster) and then link the other 23 to it. I couldn't make it work when i tried the function.
But what you saying, if i understand you correctly, is basicly: (and now i am thinking visually).
Create a rectacngle and hang up your monster as if they were christmasdecorations. I then take it that you can unlink and link them back unto this "piece" as you see fit by scripts?
Please stop me if i am completly wrong, but if this works, it will solve alot of other problem following this, but problems i didn't want to tackle until i had a moving unit.
Very much thank you for getting me on track on this one.
#3
05/17/2007 (12:36 pm)
Yeah i think thats exactly what he's saying. make a big rectangle with mounting points wherever you want to add your monsters. then you can just delete the monsters as they get hit. and you can move them all by just moving the rectangle back and forth. have the world collision callback of the monster sprites cause a change in direction of the rectangle.
#4
05/17/2007 (12:53 pm)
You are correct, and Matt described it exactly.
#5
Doing it this way wasn't any sport! :) It was to easy. Just to make sure i understood it mechanicly i made a white square, added four mount points, mounted four Monsters and let it move around. I then created a black rectacngle and put in a layer between the "ships" (ugly green dots) and the white square. The illusion was there. I didn't have to script anything else then movement of the "plate".
Well i will now try to detach one enemy Monster and reattach him to the mount point. Can you track a mountpoints position? Is that possible? Well, we will see in another hour I guess.
05/18/2007 (3:01 am)
Thanks!Doing it this way wasn't any sport! :) It was to easy. Just to make sure i understood it mechanicly i made a white square, added four mount points, mounted four Monsters and let it move around. I then created a black rectacngle and put in a layer between the "ships" (ugly green dots) and the white square. The illusion was there. I didn't have to script anything else then movement of the "plate".
Well i will now try to detach one enemy Monster and reattach him to the mount point. Can you track a mountpoints position? Is that possible? Well, we will see in another hour I guess.
#6
Atleast, i have now found the references and starting to understand how i should think. I got some gotchas.
I also started to understand the debug function (hard to debug when you don't declare anything! :))
And also, i realized i should declare some variable so i could track the object on screen. Perhaps there is some more effective (and correct?) way than how i solved the problem now. (i have a function onlevelloaded for every object so i can declare the variable since i want to track every object. Right or wrong? Hm?).
Well, i got everything spinning and got stuff to keep position and also got around to dismount. Found some nice tutorial about pathfinding which will be useful to.
My mission now is to succed to get back to the mountpoint after being away from it for a while. I feel there is gonna be alot of try and error here, but i feel some basics are getting into my head atleast.
And i also found out a little thing called visible... hm :)
Well well, not my intention to spam this forums with my little escapeds. Will post complete code when i am finish for comments. And will keep my comments on my success to a minimum. But to say the least, i am not used to stuff being easy. I feel like i must unlearn alot.
05/18/2007 (5:40 am)
Well, it does take time to get the head around some stuff. I am not used to think from this point of view. My head is spinning.Atleast, i have now found the references and starting to understand how i should think. I got some gotchas.
I also started to understand the debug function (hard to debug when you don't declare anything! :))
And also, i realized i should declare some variable so i could track the object on screen. Perhaps there is some more effective (and correct?) way than how i solved the problem now. (i have a function onlevelloaded for every object so i can declare the variable since i want to track every object. Right or wrong? Hm?).
Well, i got everything spinning and got stuff to keep position and also got around to dismount. Found some nice tutorial about pathfinding which will be useful to.
My mission now is to succed to get back to the mountpoint after being away from it for a while. I feel there is gonna be alot of try and error here, but i feel some basics are getting into my head atleast.
And i also found out a little thing called visible... hm :)
Well well, not my intention to spam this forums with my little escapeds. Will post complete code when i am finish for comments. And will keep my comments on my success to a minimum. But to say the least, i am not used to stuff being easy. I feel like i must unlearn alot.
#7
I have this square with four entitys mounted to. I have named them enemy01,enemy02,enemy11,enemy12. The square on which they are mounted is called mother. I have created four linkpoints thru the levelbuilder on mother. One in each corner. Link points are 1,2,3,4.
When i press 'w' i get enemy12 to dismount, and go downwards. When i release he uses the command moveto and go back to the point of where the linkpoint is (in this case Linkpoint number two).
And now, it would be so simple and just mount him back? I thought. But ... nah.
If i try the mount commands inputs, which hold and x,y coordinater Enemy12 disapear. If just use
enemy12.mount($mother) the enemy12 mounts on mother (in the middle) and also it creates a new linkpoint (number 5).
Why i send mother away in the end is only for me an easy way checking if the mounts works...
The code i have been using is:
The obvious question is, why am i so stupid and can't get my head to work? I have cleaned up the code and realized, that for so many hours, i have really done very little. :)
05/18/2007 (8:18 am)
This dismount, mount stuff is makeing me crazy,I have this square with four entitys mounted to. I have named them enemy01,enemy02,enemy11,enemy12. The square on which they are mounted is called mother. I have created four linkpoints thru the levelbuilder on mother. One in each corner. Link points are 1,2,3,4.
When i press 'w' i get enemy12 to dismount, and go downwards. When i release he uses the command moveto and go back to the point of where the linkpoint is (in this case Linkpoint number two).
And now, it would be so simple and just mount him back? I thought. But ... nah.
If i try the mount commands inputs, which hold and x,y coordinater Enemy12 disapear. If just use
enemy12.mount($mother) the enemy12 mounts on mother (in the middle) and also it creates a new linkpoint (number 5).
Why i send mother away in the end is only for me an easy way checking if the mounts works...
The code i have been using is:
function Mother::onLevelLoaded(%this, %scenegraph)
{
$Mother = %this;
echo(%this.getLinkPoint(2));
}
function Enemy12::onLevelLoaded(%this, %scenegraph)
{
$Enemy12 = %this;
moveMap.bindCmd(keyboard, "w", "Enemy12Up();", "Enemy12Stop();");
}
function Enemy12Up()
{
$Enemy12.dismount();
$Enemy12.setLinearVelocityY(20);
}
function Enemy12Stop()
{
$Enemy12.moveto($Mother.getLinkPoint(2),10,true,true,true,0.1);
}
function Enemy12::onPositionTarget()
{
$Enemy12.mount($Mother);
$Mother.setLinearVelocityX(20);
}The obvious question is, why am i so stupid and can't get my head to work? I have cleaned up the code and realized, that for so many hours, i have really done very little. :)
#8
$enemy.mount($mother.getLinkPoint(2));
something like that, since getLinkPoint returns the coords of the link point
05/18/2007 (8:40 am)
Try using getLinkPoint(%id) on mother first, like:$enemy.mount($mother.getLinkPoint(2));
something like that, since getLinkPoint returns the coords of the link point
#9
I might add that i am using the levelbuilder for as much as possible, since it seems to be the preferred way in 1.5beta3. Don't know if there is something to it?
(I will bet on me doing something wrong as the most likely reason however. :) )
I did notice a nice side effect to everything now though that will simplify the next step greatly. (If i just can make this work! Then i have the basics on place).
05/18/2007 (10:43 am)
Thanks for the idea Matt, i had however tried that (and did it again just to be sure). If i just use linkpoint as a reference i will get back x and y coordinate. TGB protest then that i can't find any reference to any object by that name (i.e 3.5787, 25.4311).I might add that i am using the levelbuilder for as much as possible, since it seems to be the preferred way in 1.5beta3. Don't know if there is something to it?
(I will bet on me doing something wrong as the most likely reason however. :) )
I did notice a nice side effect to everything now though that will simplify the next step greatly. (If i just can make this work! Then i have the basics on place).
#10
Here is an example using it - it will add some sprites to the set then move the set left and right, changing direction when it hits the sides:
(You can see a movie of it here (wmv/385KB))
Place this code in a file and exec it from e.g. the end of startGame() in game.cs (remember to change the image map to something that exists in your project) and it should just work.
05/18/2007 (10:51 am)
Perhaps in this case t2dSceneObjectSet would be of help, it allows you to treat a bunch of scene objects like one composite object and apply position, rotation etc to them relatively as a unit.Here is an example using it - it will add some sprites to the set then move the set left and right, changing direction when it hits the sides:
(You can see a movie of it here (wmv/385KB))
function TestApp::addSprite( %this, %x, %y )
{
%s = new t2dStaticSprite()
{
scenegraph = %this.sg;
imageMap = "orcImageMap"; // CHANGE THIS TO YOUR OWN IMAGE MAP!!!
frame = 0;
};
%s.setPosition( %x, %y );
%this.os.add( %s );
}
function TestApp::onAdd( %this )
{
%this.sw = scenewindow2D;
%this.sg = sceneWindow2D.getSceneGraph();
%this.os = new t2dSceneObjectSet()
{
scenegraph = %this.sg;
};
%this.addSprite( 0, 0 );
%this.addSprite( -20, 0 );
%this.addSprite( 20, 0 );
%this.addSprite( 0, -20 );
%this.addSprite( 0, 20 );
%this.step = 0.25; // move unit per tick
%this.camoutline = new t2dShapeVector();
%this.camoutline.setFillMode( false );
%this.camoutline.setLineColor( "1 0 1" );
%this.camoutline.setPolyPrimitive( 4 );
%cs = %this.sw.getCurrentCameraSize();
%this.camoutline.setSize( getWord( %cs, 0 ), getWord( %cs, 1 ) );
%this.camoutline.addToScene( %this.sg );
// create a shape vector to show the outline of the object set
%this.outline = new t2dShapeVector();
%this.outline.setFillMode( false );
%this.outline.setLineColor( "1 0 0" );
%this.outline.setPolyPrimitive( 4 );
%this.outline.setSize( %this.os.getWidth(), %this.os.getHeight() );
%this.outline.addToScene( %this.sg );
%this.setTimerOn( 32 );
}
function TestApp::onTimer( %this )
{
// We just custom check the object set has hit the sides of the screen and switch direction
%cs = %this.sw.getCurrentCameraSize(); // camera size
%cw = getWord( %cs, 0 ); // camera width
%rc = %cw * 0.5; // right screen limit
%lc = -%rc; // left screen limit
%ow = %this.os.getWidth(); // object set width
%hw = %ow * 0.5; // half object set width
%lx = %this.os.getPositionX() - %hw; // left side of set
%rx = %lx + %ow; // right side of set
// Left or right side hit screen edges?
if( ( %rx + %this.step > %rc ) || ( %lx + %this.step < %lc ) )
%this.step = -%this.step; // yes so toggle direction
// Next position
%px = %this.os.getPositionX() + %this.step;
// Set the object set position
%this.os.setPositionX( %px );
// Set the outline position so we can see where the set is
%this.outline.setPositionX( %px );
}
// Create a custom scene graph
sceneWindow2D.setSceneGraph( new t2dSceneGraph() );
// Launch our app
$app = new t2dSceneObject()
{
class = "TestApp";
scenegraph = scenewindow2d.getSceneGraph();
};Place this code in a file and exec it from e.g. the end of startGame() in game.cs (remember to change the image map to something that exists in your project) and it should just work.
#11
Whats the pros and cons with the different approaches?
As i understand in this solution you create a object that will turn no matter what the number of little monsters? If i only have one left, it will turn on the same place and don't go to the limits of the screen?
I have to dynamicly alter the size of the SceneObject when the little monsters get hit?
It really had me thinking and i felt like i understood what it should do before i tried it.
... And then i saw the nice little video! :) Your monsters looks like nicer then mine.
05/18/2007 (11:17 am)
Thanks for that input, i however do the same thing with "my" script above. (altough i mount them to a surface).Whats the pros and cons with the different approaches?
As i understand in this solution you create a object that will turn no matter what the number of little monsters? If i only have one left, it will turn on the same place and don't go to the limits of the screen?
I have to dynamicly alter the size of the SceneObject when the little monsters get hit?
It really had me thinking and i felt like i understood what it should do before i tried it.
... And then i saw the nice little video! :) Your monsters looks like nicer then mine.
#12
If you add this to the code above:
And from the console you can type:
a few times and you will see that it updates the set bounds and still works without changing anything.
05/18/2007 (11:39 am)
With the set if you remove a sprite it will automatically resize to fit all sprites and so keep on working regardless.If you add this to the code above:
function TestApp::killOne( %this )
{
if( %this.os.getCount() > 0 )
{
%obj = %this.os.getObject( 0 );
%this.os.remove( %obj );
%obj.safeDelete();
%this.outline.setSize( %this.os.getWidth(), %this.os.getHeight() );
}
}And from the console you can type:
$app.killOne();
a few times and you will see that it updates the set bounds and still works without changing anything.
#13
I see alot of easyness going with the mounted thing from above where you can script with ease som intresting behaviour to your monsters. But i feel i will have to let go of that and really start looking into you solution instead Neo. But i really hate given up on something when i know its lack of my understanding that makes me give up
---
Well, to the mount/dismount thingie.
I realized something irritating (for me) atleast.
If i try to do the mount thingy with mount.
ie. $Enemy12.mount($Mother ....) the syntax for the coordinate is in this format "X Y",
ie. $Enemy12.mount($Mother,"0.5 0", ....);
Then i can mount it at that position.
The $Mother.getLinkPosition(2) returns me the value absolut to screen... i think?
But i already have one? Why can't i use that? Am i missing something or what. Or is the correct solution going down Morpheu... oh sorry :) Neos path?.
05/19/2007 (1:18 am)
Okey, thanks Neo. I have not given up on the original script Yet. I feel i must solve THAT problem to come around to understand this beast. Altough i see i didn't added my code for getting everything to turn around. Which it does, depending of how many "Monsters" i have.I see alot of easyness going with the mounted thing from above where you can script with ease som intresting behaviour to your monsters. But i feel i will have to let go of that and really start looking into you solution instead Neo. But i really hate given up on something when i know its lack of my understanding that makes me give up
---
Well, to the mount/dismount thingie.
I realized something irritating (for me) atleast.
If i try to do the mount thingy with mount.
ie. $Enemy12.mount($Mother ....) the syntax for the coordinate is in this format "X Y",
ie. $Enemy12.mount($Mother,"0.5 0", ....);
Then i can mount it at that position.
The $Mother.getLinkPosition(2) returns me the value absolut to screen... i think?
But i already have one? Why can't i use that? Am i missing something or what. Or is the correct solution going down Morpheu... oh sorry :) Neos path?.
#14
$Enemy12.mount($Mother, $Mother.getLocalPoint($Mother.getLinkPoint(2)), 0, true );
When i do this it works like a charm, and i don't create another linkpoint!
The trouble i had was that i thought that getLinkPoint was getting the point from the object ON the object.
Instead it was getting me the the coordinate on screen (or scene or... what its called).
So, i saw there was a converter who converted a local point to a world point and then it was a matter of minute to get the world point to a local point. So.
This code now does what i want. I will now add world limit restriction on my monsters and instruct mother to turn when one of them hit the bounderies. I will then start to add som interesting maneuvers to individual monsters and simulate "attacks". Well, the real basic stuff is in place and i can move on.
Obstacles to overcome:
I will start out with four seperate attack pattern, which will require some knowledge of where on screen they are, and make sure they get back to mama safely.
When that are in place i will start to make them attack in pair.
After that i would like to create beavoiurs like attacking in formation, groups, follow the leader and stuff.
After that its time to randomize it. And trying to sync it. My building blocks for the real shootem up game is then forming (a game that really has nothing to do with space invaders at all!).
---
Thanks to you who created the asteroid example script in TDN. It put me into the right direction regarding mounts. And thanks for the idea of using mounts in the first place.
05/19/2007 (1:33 am)
It helps when you talks out loud! :) I got the solution as soon as I posted the above!$Enemy12.mount($Mother, $Mother.getLocalPoint($Mother.getLinkPoint(2)), 0, true );
When i do this it works like a charm, and i don't create another linkpoint!
The trouble i had was that i thought that getLinkPoint was getting the point from the object ON the object.
Instead it was getting me the the coordinate on screen (or scene or... what its called).
So, i saw there was a converter who converted a local point to a world point and then it was a matter of minute to get the world point to a local point. So.
This code now does what i want. I will now add world limit restriction on my monsters and instruct mother to turn when one of them hit the bounderies. I will then start to add som interesting maneuvers to individual monsters and simulate "attacks". Well, the real basic stuff is in place and i can move on.
Obstacles to overcome:
I will start out with four seperate attack pattern, which will require some knowledge of where on screen they are, and make sure they get back to mama safely.
When that are in place i will start to make them attack in pair.
After that i would like to create beavoiurs like attacking in formation, groups, follow the leader and stuff.
After that its time to randomize it. And trying to sync it. My building blocks for the real shootem up game is then forming (a game that really has nothing to do with space invaders at all!).
---
Thanks to you who created the asteroid example script in TDN. It put me into the right direction regarding mounts. And thanks for the idea of using mounts in the first place.
function Mother::onLevelLoaded(%this, %scenegraph)
{
$Mother = %this;
echo(%this.getLinkPoint(2));
}
function Enemy12::onLevelLoaded(%this, %scenegraph)
{
$Enemy12 = %this;
moveMap.bindCmd(keyboard, "w", "Enemy12Up();", "Enemy12Stop();");
}
function Enemy12Up()
{
$Enemy12.dismount();
$Enemy12.setLinearVelocityY(20);
}
function Enemy12Stop()
{
$Enemy12.moveto($Mother.getLinkPoint(2),10,true,true,true,0.1);
}
function Enemy12::onPositionTarget()
{
%i=$Enemy12.mount($Mother, $Mother.getLocalPoint($Mother.getLinkPoint(2)), 0, true );
echo(%i);
$Mother.setLinearVelocityX(20);
}
Torque 3D Owner Stephen Zepp
If I remember SI correctly, what was actually going on is that the "monsters" were actually one primary object that moved back and forth, with a bunch of attackable units that were "mounted" to the main object. In other words (as you mention briefly), it's a "moving array".
So, to duplicate that, create one single object with quite a few link points, and mount your individual monster units to it. When one of the monster units hits a world limit, have it send the "main" object a "switch movement direction" input, and handle it.
This would be the basic case, you could then break them up into your rows (have several 1 high but many wide objects, etc) for whatever type of scenario you want.