Tuesday, October 25, 2005

And progress continues

Under the watchful eyes of David, my young apprentice, I got my troops moving. I got the real models in, at least for the prototype RTS being built. Now coming out of the command center, in a code which is a bit shakey, are foot soldiers with AK47s. They can't shoot, but they can move! David got me to go as far as animating them! Something I wouldn't do until much later in the script! So these guys walk to where I tell them to go and then stop when they get there. They walk on top of the ground, they don't go off all over the place, they don't bend towards the ground anymore. In fact, the majority of the old problems are gone in terms of movement. Now I have to figure out how to get whole groups of troops to move together in formation.

But I have a good start. My command center builds the troops around the building every five seconds, some basic panels for building the units, units that move, selections that work a lot better so far. Single-unit select, ctrl+click select, deselect is all working fine now. I've started some other units in gameSpace now as well.

My next plan of attack is to create the rally points for building units, creating multiple unit movement, and perhaps creating and implementing some citizens. Yes, it is now time for citizens.

Well, I've got plenty of work to do tomorrow, if I can fit it between my driving test, my recruiting with Mr. Gleason, CAP and reading all of Faulkner's Absalom Absalom.

while(thisCodeDoesntWork)
{
smashComputer(); //take out some pent out anger
throwDartsAtBoss(); //take out more anger
sleep(6*60*60); //sleep six hours
}

Saturday, October 22, 2005

Single Unit Selection.

Well, it seems that the my.enable_detect in that code in my last post was indeed pointless. I commented it out, and it seemed to continue the same. I'll leave it there for now though just in case.

My selection code problem turned out easier than I thought. I had a small mistake in the code.


you = ent_next(null);
while(you != null)
{
you.selected = off;
you = ent_next(null);
wait(1);
}


The problem is this: You is assigned to the first entity. Then while you exists, its .selected flag is set to off. Then you is set to the first entity. The while loop never terminates because you is never null. Pointers are the bane of programming indeed!

So at the forum, someone notice this problem and fixed it for me. That second ent_next command is suppose to be you = ent_next(you); So now single unit selection, ctrl+click multiple unit selection and single unit deselection is finished. Same type unit selection via double click, lassoing units and global deselect is still in the works.

The code is as follows:

function selectMe()
{
if((event_type == event_click) && (my.selected == off) && (key_ctrl != 1))
{
you = ent_next(null);
while(you != null)
{
you.selected = off;
you = ent_next(you);
wait(1);
}
wait(1);
my.selected = on;
return;
}
if((event_type == event_click) && (my.selected == off) && (key_ctrl))
{
my.selected = on;
return;
}
if((event_type == event_click) && (my.selected == on))
{
my.selected = off;
return;
}
}

action selectSprite
{
my.passable = on;
my.overlay = on;
my.tilt = 90;
my.scale_x /= 3;
my.scale_y /= 3;
while((you != null) && (you.selected == on))
{
my.x = you.x;
my.y = you.y;
my.z = you.z;
wait(1);
}
you.selecter = 0;
ent_remove(me);
}

action guard
{
tester = my;
my.enable_click = on;
my.event = selectMe;
while(1)
{
if((my.selected == on) && (unselect == off))
{
if(my.selecter != 1)
{
ent_create(selectBMP,my.x,selectSprite);
my.selecter = 1;
}

Logically, we don't start at the top. In action guard the second and third lines are the beginning of this code. The guard is sensitive to being clicked and his event when clicked is the selectMe() function. Then, when he is clicked, selectMe() is called.

The first line in selectMe() says that if the entity was clicked on, if its .selected flag is off and if the ctrl key is not being pressed then it goes to the next set of commands. The next line searches for the first entity. It enters that while loop, sets .selected to off and then gets the next entity until it runs out of entities. Then the .selected of the entity that entity is turned on. Then the return leaves the function so it can't evaluate the other ifs and hypothetically deselect the unit.

The next if-statement says that if the entity was clicked on, if its .selected flag is off and the ctrl key is on, the entity's .selected is set to on and the return closes the function. This was the easiest of the selection methods.

The last if-statement says that if the entity was clicked on and its .selected flag is on, turn the flag off and leave the function.

Back in the action, we go into the loop. Then there is the if-statement that checks to see if the .selected flag is on. If so, it creates the select sprite, if one hasn't already been created. The sprite follows the entity as it moves and removes itself if the entity's .selected flag is off or if the entity is removed (killed.)

I'm going to leave the wonderful world of selection and movement for a while and get a few basic buildings working. Start working on entity creation around a building. The theory is simple: I have a building, I select it and a panel opens up. I press a button on that panel that creates a unit. That unit is created in a vector by the building. If there is a unit in that vector, create a unit in the next vector and so on and so forth. If all vectors are taken up, wait until there is space. This means arrays of vectors and trace commands.

This is the beginning of my RTS prototype.

while(thisCodeDoesntWork)
{
smashComputer(); //take out some pent out anger
throwDartsAtBoss(); //take out more anger
sleep(6*60*60); //sleep six hours
}

Friday, October 21, 2005

And an RTS was born!

I think I should introduce myself. I am J Kuhl. I make games, flash animations, and fool around with fun and fancy programs. Unfortunately, I have never finished a game. I came close once. Stronghold. A very simple game, a very serious bug. I couldn't fix it. So I have abandoned it. I will go back some day though. Anyways, I am anonymous_alcoholic at 3d Gamestudio's forums and at the forums at 3dgsuv.com and if you need any help, I'll be floating around the forums.

One of my goals with 3d Gamestudio was to make a RTS (Real Time Stratagy) game. It would take what I liked best about Galactic Battlegrounds and Empire Earth and combine them into an uber RTS game. So I started some work. I have unit selection half created. Selection will have multiple parts: click to select one unit, double click to select all visible units of the same type, ctrl+click to select multiple units, drag+click to lasoo units. Once a unit is selected, the player can move it or send it to attack by rightclicking. ctrl+rightclick allows player to attack allies because sometimes the computer needs retribution!

Currently, I have ctrl+click selection working. It is the easiest of them all. My plan of attack on single unit selection has failed so far. Fortunately, Grimber, on the Forums, may have come to my aid. Arrays. He has an idea with arrays.

My movement is also comming along. The code is erratic, but its a start. I need to tinker with it more. The unit doesn't stop at its defined stopping point yet, but he moves towards it. Multiple unit movement is not working yet but I haven't put my heart and soul into that part of the operation, I haven't worked real hard on it yet.

An RTS game is not as simple as it appears to be. Selection should be one of the simpler codes. Right now, I am in fright of the time when I get to do AI . . .

Ah, but that is the fun of it!

This RTS is my primary project right now. But I'll be popping into Stronghold now and then to try to fix/finish it. Before leaving, I wanted to show off my favorite part of Stronghold's code, the MG42 gunners and the sniper towers, well, the MG42 gunners specifically, but the towers work the same way.


action mg42Gunner
{
var gunnerHandle;
var mgScan;
my.mg42 = on;
my.pan = 180;
my.metal = on;
my.enable_detect = on;
my.lightrange = 100;
while(1)
{
mgScan.pan = 360;
mgScan.tilt = 360;
mgScan.z = 2000;
scan_entity(my.x,mgScan);
if(mgTargSw != null)
{
if(mgTargSw.health > 0)
{
gunnerHandle = ent_playsound(my,mg42SND,1000);
while(snd_playing(gunnerHandle) == 1)
{
if(mgTargSw == NULL) { break; }
vec_set(temp,mgTargSw.x);
vec_diff(temp,temp,my.x);
vec_to_angle(my.pan,temp); //turn to target
trace_mode = ignore_me + ignore_passable + ignore_maps + activate_shoot;
trace(my.x,mgTargSw.x);
wait(1);
}
sleep(random(1) + 2);
}
}
wait(1);
}
}

The great thing about this code was that it was a stroke of genius on my part! I was having trouble making these work and then this solution came to me, and to my surprise, it worked the way I wanted it to.

First it sets up two variables, gunnerHandle, which deals with sound, and mgScan, which is a vector that deals with the scan cone. The next line is a way around dealing with pointers. Pointers are very tricky to work with and I find that it is best to avoid them. This method won't work in all situations, but it was awesome in this one. Then the next two lines set the object's properties; it faces to the left of the screen and it's set to look metallic. It can sense scans. Now that I think about it, I'm not sure if I need enable_detect . . . I'll play with it tommorrow. Then it sends out light. Light made it look better. The mg42 is in the window of a building. It was dark and ugly. Now it isn't.

Then there is the main while loop. This loop keeps running until the game ends. The mg42 cannot be removed once created. mgScan is set in the next three lines and the forth line after performs the scan. It scans for enemy entities in a full sphere with a radius of 2000 quants. Another function ensures that only enemies are sensitive to this scan. That other function sets the pointer mgTargSw to the target that detected the scan. (Odd point here: mgTargSw stands for Machine Gunner Target Sword, so as a note of history, I obviously planned to set new pointers for each type of target and realized that I was overcomplicating things. I became lazy, and didn't change the pointer name.)

Then, there is that if statement, if(mgTargSw != null). Once a target has been set, it goes to the next if statement which simply makes sure that the mg42 doesn't fire on a dead guy. If the guy isn't dead yet, a sound is fired, one from Saving Private Ryan, I believe. I don't have an mg42 at home that I can record, unfortunately.

Then a new while. As long as the sound is playing, the gun is firing. The next bunch of lines are simple; Break out of the loop if mgTargSw has died (it'll remove itself when dead and therefore become null), turn to the target, trace the target. That same function that assigned the target the pointer, also kills him. The trace hits the target, his event_shoot event is triggered and his health is diminished until at last, he dies and disappears. Once the mg42 stops playing the gun sound, it stops shooting for about a second. In that time the player is suppose to pretend that it is reloading.

This is the fun in programming. Breaking things apart in reality and rebuilding them little by little in virtual reality. I can easily say: find target, turn, shoot and killl in english. Hell, I can do it in french! cherchez votrez cible, tourez, tirez, et tuez-la! But to speak in C-Script is much more complicated. C++ can be worse!

while(thisCodeWontWork)
{
smashComputer(); //take out some pent out anger
throwDartsAtBoss(); //take out more anger
sleep(6*60*60); //sleep six hours
}