Questions from the forum

Top  Previous  Next

Q: I want my enemies to attack only when they can see the player. How can I calculate something like this ?

A: Here's an enemy that moves in a circle and plays an alarm sound if it can see the player.

 

SOUND* alarm_wav = "alarm.wav";

 

action players_code() // attach this action to your player

{        

       var movement_speed = 20; // movement speed

       VECTOR temp, players_sensor;

       set (my, INVISIBLE); // 1st person player

       player = my; // I'm the player

       while (1)

       {

               my.pan -= 7 * mouse_force.x * time_step;

               camera.x = my.x;

               camera.y = my.y;

               camera.z = my.z + 50 + 1.1 * sin(my.skill44); // play with 50 and 1.1

               camera.pan = my.pan;

               camera.tilt += 5 * mouse_force.y * time_step;

               vec_set (temp.x, my.x); // trace 10,000 quants below the player

               temp.z -= 10000;

               temp.z = -c_trace (my.x, temp.x, IGNORE_ME | IGNORE_PASSABLE | USE_BOX) - 2; // play with 2

               temp.x = movement_speed * (key_w - key_s) * time_step;

               temp.y = movement_speed * (key_a - key_d) * 0.6 * time_step;

               c_move (my, temp.x, nullvector, IGNORE_PASSABLE | GLIDE);

               wait (1);

       }

}

 

action my_enemy() // attach this action to your enemies

{

       while (!player) {wait (1);} // wait until the player model is loaded in the level

       var alarm_handle, walk_percentage = 0;

       while (1)

       {

               // scans a sector that's got 120 degrees horizontally, 60 degrees vertically and a length of 1000 quants

               // the player will be detected only if its action includes this line of code: "player = my;" (without the quotes)

               if ((c_scan(my.x, my.pan, vector(120, 60, 1000), IGNORE_ME) > 0) && (you == player))

               {

                       if (!snd_playing(alarm_handle)) // the alarm sound isn't playing already?

                       {

                               alarm_handle = snd_play(alarm_wav, 70, 0); // then let's play it!

                       }

               }

               c_move (my, vector(5 * time_step, 0, 0), nullvector, IGNORE_PASSABLE | GLIDE);

               my.pan += 1 * time_step; // make the enemy rotate in a circle

               ent_animate(my, "walk", walk_percentage, ANM_CYCLE); // play the "walk" animation in a loop

               walk_percentage += 2 * time_step; // 2 controls the walk animation speed

               wait (1);

       }

}

 

 

Q: I have upgraded to A7.82 but now I'm getting an error with your multiplayer Aum workshops (shooting from the wrong player). How can I fix that?

A: Your hard drive doesn't have enough time to read all the resources; replacing the "wait (-0.5);" instruction from my code with a "wait (-3);" should solve the problem. A more elegant solution is presented below:

 

my = ent_create ("redsoldier.mdl", vector (100, 50, 40), move_players);

while (my.client_id != dplay_id) wait (1); // wait until the handle is ready

client_ent = handle(my);

 

 

Q: I have found the cubemap rendering script at the wiki page. Can someone explain what does it do and how does it work?

A: That script creates a sky cube bitmap by taking 6 screenshots (the 6 faces of a cube) from the level and merging them into a single tga bitmap, just like the one below. You can then use a simple "ent_createlayer" instruction to display your sky cube.

 

aum90_faq1

 

void main()

{

       fps_max = 70;

       video_mode = 7; // run in 800x600 pixels

       video_depth = 32; // 32 bit mode

       video_screen = 1; // start in full screen mode

       level_load ("mylevel.wmb");

       wait (3);

       ent_createlayer("skycube+6.tga", SKY | CUBE | VISIBLE , 1);

}

 

 

Q: I have tried to add a sound to my fireplace entity, but I can't hear it. I am using this snippet:

 

var fire_handle;

 

SOUND* fire = "fire.wav";

 

ENTITY* fireplace = "fireplace.mdl";

 

action my_fire()

{

       fire_handle = ent_playsound (fireplace, fire, 80);

}

 

A: Your code has a small problem: it plays the "fire.wav" sound only once and by the time the player moves close to the fireplace, the sound has stopped for good. Use the modified code below:

 

var fire_handle;

 

SOUND* fire = "fire.wav";

 

action my_fire() // attach this action to your fireplace entity

{

       fire_handle = ent_playloop(my, fire, 80);

}

 

 

Q: I'd like to press a key and have an animated sprite show up, go through all its frames and then disappear. The things should repeat when I press the key again.

A: Here's an example.

 

function animated_sprite()

{

       set(my, BRIGHT);

       my.alpha = 100;

       my.frame = 1; // start with the first frame

       while (my.frame < 20) // change this value if your animated sprite doesn't contain 20 frames

       {

               my.frame += 1.2 * time_step; // 1.2 gives the animation speed

               wait (1);

       }

       // let's fade out the last animation frame (remove the "while" loop below if you don't want that to happen

       while (my.alpha > 0)

       {

               my.alpha -= 0.7 * time_step; // 0.7 gives the fade-out animation speed

       }

       ent_remove (my); // remove the sprite

}

 

function create_sprite()

{

       // creates the sprite 300 quants in front of the camera in this example; feel free to use your own values

       // use your own animated sprite here

       VECTOR sprite_offset;

       vec_set (sprite_offset.x, vector(300, 0, 0));

       vec_rotate (sprite_offset.x, camera.pan);

       vec_add (sprite_offset.x, camera.x);

       ent_create("muzzle+20.tga", sprite_offset.x, animated_sprite);

}

 

function init_startup()

{

       on_c = create_sprite; // press the "C" key to create the sprite

}

 

aum90_faq2

 

 

Q: I want to have certain NPCs track the player and other objects using their heads and eyes. Should I use vertex or bone animations?

A: Use bones - it's much easier to do it. Check out "The Bone Collector" workshop (script23_2.c) that's available at http://tutorial.3dgamestudio.net to see a good example.

 

 

Q: I'd like to attach a rotating entity to the player, but it must perform collision detection as it rotates around the player. Can you help?

A: Use the snippet below - it does the job.

 

ENTITY* dummy_ent;

 

// the function below moves the "real" rotating entity towards the position of the dummy entity (if possible)

function rotate_guard()

{

       proc_mode = PROC_LATE;

       while (!dummy_ent) {wait (1);}

       VECTOR offset_speed;

       while (1)

       {

               vec_diff(offset_speed.x, dummy_ent.x, my.x);

               // normalize the speed with which the "real" entity follows the dummy entity, play with 10

               vec_normalize(offset_speed, 10 * time_step);

               c_move(my, nullvector, offset_speed.x, IGNORE_PASSABLE | GLIDE);

               my.pan = dummy_ent.pan;                

               wait (1);

       }

}

 

// the function below creates a dummy entity that rotates around the player at all times, penetrating the walls, etc

function rotate_around_player()

{

//        set (my, INVISIBLE | PASSABLE); // make the dummy entity invisible and passable

       ent_create("guard.mdl", my.x, rotate_guard); // use your own model here

       var rotation_angle;

       VECTOR my_speed, temp;

       while (!player) {wait (1);} // wait until the player model is loaded

       my.emask |= (ENABLE_IMPACT | ENABLE_ENTITY);

       while (1)

       {

               my.x = player.x - 250 * cos(rotation_angle);

               my.y = player.y - 250 * sin(rotation_angle);

               my.z = player.z + 30; // play with 30

               rotation_angle += 0.5 * time_step;

               vec_set(temp.x, player.x);

               vec_sub(temp.x, my.x);

               vec_to_angle(my.pan, temp);

               wait (1);

       }

}

 

action players_code() // attach this action to your player

{        

       var movement_speed = 20;

       VECTOR temp, players_sensor;

       set (my, INVISIBLE);

       player = my;

       dummy_ent = ent_create("dummy.mdl", nullvector, rotate_around_player); // put this line inside your player action

       while (1)

       {

               my.pan -= 7 * mouse_force.x * time_step;

               camera.x = my.x;

               camera.y = my.y;

               camera.z = my.z + 50 + 1.1 * sin(my.skill44);

               camera.pan = my.pan;

               camera.tilt += 5 * mouse_force.y * time_step;

               vec_set (temp.x, my.x);

               temp.z -= 10000;

               temp.z = -c_trace (my.x, temp.x, IGNORE_ME | IGNORE_PASSABLE | USE_BOX) - 2;

               temp.x = movement_speed * (key_w - key_s) * time_step;

               temp.y = movement_speed * (key_a - key_d) * 0.6 * time_step;

               c_move (my, temp.x, nullvector, IGNORE_PASSABLE | GLIDE);

               wait (1);

       }

}

 

 

Q: Rarely, the game window goes to the background without any reason; this happens even if my game is running in full screen mode. Why is this happening?

A: Another application takes control; it's usually your antivirus, which doesn't download its updates silently, but pops up a small window that sends your game to the background. Disable the antivirus temporarily and see if this solves the problem; otherwise, you'll have to do the same thing with all the applications that are running in the background until you find the guilty one and you get rid of it / replace it.

 

 

Q: I would like to include an NPC script in my rpg level. Can anyone give me an example?

A: Here's an example for an NPC that moves around, stops for a while and then moves again. It can avoid walls and gives some advice if the player comes close to it.

 

// use a wave file that contains something like "Stay away from the red rabbit, stranger!"

SOUND* advice_wav = "advice.wav";

 

action my_npc()

{

       VECTOR front_pos;

       var distance_covered = 0;

       var sound_once = 1;

       while (!player) {wait (1);} // wait until the player model is loaded

       while (1)

       {

               vec_set(front_pos.x, vector(50, 0, 0)); // compute a position that's placed 50 quants in front of the player

               // rotate "front_pos" in the direction (angles) given by the entity

               vec_rotate(front_pos.x, my.pan);

               vec_add(front_pos.x, my.x); // add the resulting vector to entity's position

               // front_pos isn't touching any walls and the player didn't move 500 quants without pausing yet?

               if ((c_content(front_pos.x, 0) == 1) && (distance_covered < 500))

               {

                       // 5 gives the movement speed

                       distance_covered += c_move(my, vector(5 * time_step, 0, 0), nullvector, IGNORE_PASSABLE | GLIDE);

                       my.skill22 += 5 * time_step; // 5 gives the "walk" animation speed

                       ent_animate(my, "walk", my.skill22, ANM_CYCLE);

                       // if the player is closer than 150 quants to the npc and advice_wav wasn't played yet

                       if ((vec_dist(player.x, my.x) < 150) && (sound_once == 1))

                       {

                               sound_once = 2; // don't allow the sound to be played more than once per walking cycle

                               ent_playsound(my, advice_wav, 50);

                       }

               }

               else // the player is close to a wall or it has moved more than 500 quants?

               {

                       sound_once = 1; // reset sound_once

                       distance_covered = 0; // reset distance_covered!

                       my.skill99 = 0;

                       while (my.skill99 < 5) // the npc stays in front of the wall for 5 seconds

                       {

                               my.skill99 += time_step / 16;

                               ent_animate(my, "stand", my.skill22, ANM_CYCLE);

                               my.skill22 += 3 * time_step; // 3 gives the "stand" animation speed

                               wait (1);

                       }

                       my.skill99 = my.pan;

                       my.skill99 += random(180); // and then adds a random pan angle to its initial pan, in order to avoid the wall

                       while (my.pan < my.skill99) // rotate the npc towards the direction given by its new pan angle

                       {

                               my.pan += 10 * time_step;

                               wait (1);

                       }

               }

               wait (1);

       }

}

 

 

Q: I would like to know how can I get the coordinates of a point on an entity's surface that was clicked using the left mouse button.

A: There you go.

 

VECTOR hit_coords;

 

BMAP* pointer_tga = "pointer.tga";

 

function mouse_startup()

       mouse_mode = 2;

       mouse_map = pointer_tga;

       while (1)

       

               vec_set(mouse_pos, mouse_cursor);

               wait(1);

       }

}

 

action players_code() // attach this action to your player

{        

       var movement_speed = 20;

       VECTOR temp, players_sensor;

       set (my, INVISIBLE);

       player = my;

       while (1)

       {

               my.pan -= 7 * mouse_force.x * time_step;

               camera.x = my.x;

               camera.y = my.y;

               camera.z = my.z + 50 + 1.1 * sin(my.skill44);

               camera.pan = my.pan;

               camera.tilt += 5 * mouse_force.y * time_step;

               vec_set (temp.x, my.x);

               temp.z -= 10000;

               temp.z = -c_trace (my.x, temp.x, IGNORE_ME | IGNORE_PASSABLE | USE_BOX) - 2;

               temp.x = movement_speed * (key_w - key_s) * time_step;

               temp.y = movement_speed * (key_a - key_d) * 0.6 * time_step;

               c_move (my, temp.x, nullvector, IGNORE_PASSABLE | GLIDE);

               wait (1);

       }

}

 

function getcoords_startup()

{

       VECTOR pos1, pos2;

       while (1)

       {

               while (!mouse_left) {wait (1);}

               while (mouse_left) {wait (1);}

               beep();

     pos1.x = mouse_pos.x;

     pos1.y = mouse_pos.y;

     pos1.z = 0;

     vec_for_screen (pos1, camera);

     pos2.x = mouse_pos.x;

     pos2.y = mouse_pos.y;

     pos2.z = 20000; // use a big value here

     vec_for_screen (pos2, camera);

     c_trace (pos1.x, pos2.x, IGNORE_PASSABLE | SCAN_TEXTURE);

               // now "hitvertex" holds the coordinates of the closest vertex to the hit point

               if (mouse_ent) // the mouse has clicked an entity?

                       vec_for_vertex(hit_coords, mouse_ent, hitvertex); // then get the xyz coordinates of "hitvertex"

               wait (1);

       }

}

 

PANEL* coords_pan = // displays the xyz coordinates of "hitvertex"

{

       layer = 15;

       digits(50, 20, 6 ,* , 1, hit_coords.x);

       digits(50, 40, 6 ,* , 1, hit_coords.y);

       digits(50, 60, 6 ,* , 1, hit_coords.z);

       flags = SHOW;

}