Questions from the forum

Top  Previous  Next

Q: I started to make a little space game and I'd like to use a sprite for the engine exhaust, not particles. Can you help?

A: Here's an example.

 

VECTOR engine_offset;

 

function engine_sprite()

{

       set(my, BRIGHT);

       my.scale_x = 0.6; // set a proper scale for the engine sprite

       my.scale_y = my.scale_x;

       while (1)

       {

               my.pan = you.pan;

               vec_set (my.x, engine_offset.x);

               // choose a random frame for the engine - comment the following line if your sprite isn't animated

               my.frame = 1 + random(4);

               wait (1);

       }        

}

 

action my_ship() // attach this action to your space ship

{

       ent_create("explo+5.tga", engine_offset.x, engine_sprite); // create the animated engine sprite

       while (1)

       {

               // put your own flight code here

               // the example below simply makes the plane fly in a circle

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

               my.pan += 2 * time_step; // 2 sets the radius of the rotation circle

               // end of the simply flying example code

             

               // the engine sprite code starts below

               // place the engine sprite at the proper position, play with the numerical values below

               vec_set(engine_offset.x, vector(-85, 0, -10));

               vec_rotate(engine_offset.x, my.pan);

               vec_add(engine_offset.x, my.x);

               wait (1);

       }

}

 

aum91_faq1

 

 

Q: How can I make c_scan to detect only a specific group of entities (for example only entities with skill14==1) and ignores all others ? SCAN_FLAG2 is perfect for that purpose, but I needed that tag for other group of entities and there are no SCAN_FLAG3, SCAN_FLAG4... unfortunately.

A: Here's an example that does exactly what you want.

 

var entities_detected = 0; // will store the number of entities that have their skill14 set to 1

 

action entity_detector()

{

       random_seed(0); // generate a series of random numbers, used by the scanned entities

       set (my, PASSABLE);

       // set (my, INVISIBLE); // remove this comment after you have set the proper scanning value

       while (1)

       {

               // play with 500, it gives the scanning range

               c_scan(my.x, my.pan, vector(360, 90, 500), IGNORE_ME | SCAN_ENTS);

               wait (1);

       }

}

 

function entity_was_scanned()

{

       if (my.skill14 == 1) // the scanning will work only if this entity has its skill14 set to 1

       {

               entities_detected += 1;

               my.event = NULL; // no need to scan this entity anymore, it was detected already

       }

}

 

action scanned_entities() // place several entities in the level and attach them this action

{

       wait (-3); // wait until the level is loaded

       my.emask |= ENABLE_SCAN; // this entity is sensitive to scanning

       my.event = entity_was_scanned;

       if (random(1) > 0.5)

               my.skill14 = 1; // this entity can be scanned if random(1) is greater than 0.5

}

 

PANEL* output_pan =

{

       layer = 15;

       digits (500, 40, "Entities detected: %.0f", *, 1, entities_detected);

       flags = SHOW;

}

 

aum91_faq2

 

 

Q: What is the license of the models and code included in the AUM? I'd like to use them to create a commercial game and sell it.

A: You can use the code from the Aum without having to pay me or give me credit for it; nevertheless, you can't use the rest of the resources (sounds, models, textures, etc) that aren't free commercially. I always make sure that I have the right to  include these resources in Aum, but I am not allowed to give them away to other people.

 

 

Q: I can't create a passable entity (water) in A7; the “passable” water / terrain is handled as an “impassable” / normal floor.

A: Here's a simple example of a working player / passable water entity combination that uses my article from Aum 34 as a base.

 

#define amplitude skill1

#define water_speed skill2

#define number_of_vertices 1089 // the terrain entity used for the water has 33 x 33 vertices = 1089

 

var vertex_array[number_of_vertices];

var counter;

var index;

 

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);

       }

}

 

action passable_water()

{

       VECTOR temp;

       set (my, TRANSLUCENT | PASSABLE);

       my.alpha = 75;

       my.ambient = -100;

       if (my.amplitude == 0)

       {

               my.amplitude = 2; // default wave amplitude value

       }

       if (my.water_speed == 0)

       {

               my.water_speed = 10; // default wave speed value

       }

       counter = 0;

       while (counter < number_of_vertices)

       {

               vertex_array[counter] = random(360); // set random values in vertex_array

               counter += 1;

       }

       while (1)

       {

               index = 0;

               while (index < number_of_vertices)

               {

                       vec_for_mesh(temp, my, index); // store the vertex coordinates in temp

                       temp.z = sin(counter + vertex_array[index]) * my.amplitude; // change the z component

                       vec_to_mesh(temp, my, index); // deform the terrain entity

                       index += 1;

               }

               counter += my.water_speed * time_step;

               wait(1);

       }

}

 

 

Q: Can I mix *.wdl and *.c scripts in a project? I normally use the template6 *wdl scripts, but I can't find a “shader.wdl” like mtlFX.c in those templates. If I include mtlFX.c, I get lots of errors!

A: Don't mix *.wdl and .c code; you are going to have a lot of trouble, like unexplained / unfixable bugs, and so on. Better make the switch to lite-C - it's getting better and better with each release and you'll also get access to lots of new powerful features.

 

 

Q: I'd need an enemy that follows a path and if the player comes close, it starts chasing the player. When he is close enough to the player, he must shoot the player.

A: Here's a fully functional example.

 

var entity_speed = 3;

var movement_enabled = 0;

var dist_to_node;

var current_node = 1;

var angle_difference = 0;

 

VECTOR temp_angle;

VECTOR pos_node; // stores the position of the node

 

SOUND* hit_wav = "hit.wav";

 

function remove_bullets()

{

       my.event = NULL;

       ent_playsound (my, hit_wav, 1000);

       wait (-0.1);

       ent_remove (me);

}

 

function move_bullets()

{

       my.pan = you.pan; // the bullet and the enemy have the same pan angle

       my.emask |= (ENABLE_ENTITY | ENABLE_IMPACT | ENABLE_BLOCK); // the bullet is sensitive to other entities and level blocks

       my.event = remove_bullets;

       while (my)

       {

               my.skill1 = 15 * time_step; // bullet speed

               my.skill2 = 0;

               my.skill3 = 0;

               move_mode = IGNORE_YOU + IGNORE_PASSABLE + IGNORE_PUSH; // ignores the enemy (its creator = you)

               ent_move(my.skill1, nullvector);

               wait (1);

       }

}

 

function move_target()

{

       while(1)

       {

               if(movement_enabled)

               {

                       entity_speed = minv(5, entity_speed + 0.5 * time_step);

                       ent_animate(my, "walk", my.skill46, ANM_CYCLE); // play its "walk" frames animation

                       my.skill46 += 5 * time_step;

                       my.skill46 %= 100; // loop the animation

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

                       vec_to_angle (my.pan, vec_diff (temp_angle, pos_node, my.x));

               }

               wait(1);

       }

}

 

action my_enemy() // attach this action to your enemy model

       VECTOR temp, bullet_coords;

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

       move_target();

       result = path_scan(me, my.x, my.pan, vector(90, 80, 400)); // scan the area looking for the player

       if (result) {movement_enabled = 1;}

       path_getnode (my, 1, pos_node, NULL);

       vec_to_angle (my.pan, vec_diff (temp_angle, pos_node, my.x)); // rotate towards the node

       while(1)

       {

               if ((c_scan(my.x, my.pan, vector(120, 90, 1000), IGNORE_ME) > 0) && (you == player)) // detected the player?

                       break; // then get out of this loop!

               dist_to_node = vec_dist(my.x, pos_node);

               if(dist_to_node < 50) // close to the node?

               {

                       current_node = path_nextnode(my, current_node, 1);

                       if (!current_node) {current_node = 1;} // reached the end of the path? Then start over!

                       path_getnode (my, current_node, pos_node, NULL);

               }

               wait(1);

       }

       // the enemy has spotted the player here

       while (1) // so it rotates towards it and starts chasing it

       {

               vec_set(temp, player.x);

               vec_sub(temp, my.x);

               vec_to_angle(my.pan, temp);

               my.tilt = 0;

               if (vec_dist (player.x, my.x) < 400) // the enemy has come close enough to the player?

               {

                       movement_enabled = 0; // then it should stop walking

                       my.skill46 = 0;

                       if (random(1) > 0.92) // play with 0.92

                       {

                               vec_set(bullet_coords.x, vector(25, -7, 14)); // play with these values

                               vec_rotate(bullet_coords.x, my.pan);

                               vec_add(bullet_coords.x, my.x);

                               ent_create ("bullet.mdl", bullet_coords.x, move_bullets); // create a bullet

                               while (my.skill46 < 100)

                               {

                                       ent_animate(my, "standshoot", my.skill46, ANM_CYCLE); // play its "walk" frames animation

                                       my.skill46 += 15 * time_step; // "shoot" animation speed

                                       wait (1);

                               }

                       }

               }

               else // the player has moved away again?

               {

                       movement_enabled = 1; // then start chasing him again

               }

               wait (1);

       }

}

 

 

Q: I  want to create a sprite that fades softly in when I come near it and fades out gently when I move away from it.

A: Use the snippet below.

 

var fading_distance = 1000;

 

action fading_entity()

{

       set (my, TRANSLUCENT);

       my.alpha = 100;

       // make sure that the player code includes the "player = my;" line

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

       while (1)

       {

               while(vec_dist (player.x, my.x) < fading_distance) {wait (1);}

               while (my.alpha > 0)

               {

                       my.alpha -= 5 * time_step;

                       wait (1);

               }

               // the entity is invisible here

               while(vec_dist (player.x, my.x) > fading_distance) {wait (1);}

               while (my.alpha < 100)

               {

                       my.alpha += 5 * time_step;

                       wait (1);

               }

       }

}

 

 

Q: I'd need an enemy that shoots the player and creates a health box (that can be picked up by the player) when it dies.

A: Here's an update of my enemy code from Aum32 that does what you need.

 

STRING* bullet_mdl = "bullet.mdl";

 

SOUND* gothealth_wav = "gothealth.wav";

 

function fire_bullets(); // creates the bullets

function remove_bullets(); // removes the bullets after they've hit something

function got_shot();

function move_enemy_bullets();

 

#define idle 1

#define attacking 2

#define dead 3

#define status skill1

#define health skill10

 

function remove_bullets() // this function runs when the bullet collides with something

{

       wait (1); // wait a frame to be sure (don't trigger engine warnings)

       ent_remove (my); // and then remove the bullet

}

 

function health_box()

{

       set (my, PASSABLE);

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

       // wait until the player comes close to the health box

       while (vec_dist (player.x, my.x) > 60)

       {

               my.pan += 5 * time_step;

               wait (1);

       }

       player.skill99 += 50; // player's health would be stored by its skill99 in this example

       snd_play (gothealth_wav, 50, 0);

       wait (-1);

       ent_remove(my);

}

 

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

{

       wait (-7);

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

       var idle_percentage = 0;

       var run_percentage = 0;

       var death_percentage = 0;

       VECTOR content_right; // tracks the content in front of the player

       VECTOR content_left; // tracks the content in front of the player

       VECTOR temp;

       set (my, POLYGON); // use accurate collision detection

       my.health = 100;

       my.emask |= (ENABLE_IMPACT | ENABLE_ENTITY); // the enemy is sensitive to impact with player's bullets

       my.event = got_shot; // and runs this function when it is hit

       my.status = idle; // that's the same thing with my.skill1 = 1; (really!)

       while (my.status != dead) // this loop will run for as long as my.skill1 isn't equal to 3

       {

               if (my.status == idle) // hanging around?

               {

                       ent_animate(my, "stand", idle_percentage, ANM_CYCLE); // play the "stand" aka idle animation

                       idle_percentage += 3 * time_step; // "3" controls the animation speed

                       if (vec_dist (player.x, my.x) < 1000) // the player has come too close?

                       {

                               // scanned in the direction of the pan angle and detected the player?

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

                               {

                                       my.status = attacking; // then attack the player even if it hasn't fired at the enemy yet

                               }

                       }

               }

               if (my.status == attacking) // shooting at the player?

               {

                       // the road is clear? then rotate the enemy towards the player

                       if (c_content (content_right.x, 0) + c_content (content_left.x, 0) == 2)

                       {

                               vec_set(temp, player.x);

                               vec_sub(temp,my.x);

                               vec_to_angle(my.pan, temp); // turn the enemy towards the player

                       }

                       if (vec_dist (player.x, my.x) > 500)

                       {

                               vec_set(content_right, vector(50, -20, -15));

                               vec_rotate(content_right, my.pan);

                               vec_add(content_right.x, my.x);

                               if (c_content (content_right.x, 0) != 1) // this area isn't clear?

                               {

                                       my.pan += 5 * time_step; // then rotate the enemy, allowing it to avoid the obstacle

                               }        

                               vec_set(content_left, vector(50, 20, -15));

                               vec_rotate(content_left, my.pan);

                               vec_add(content_left.x, my.x);

                               if (c_content (content_left.x, 0) != 1) // this area isn't clear?

                               {

                                       my.pan -= 5 * time_step; // then rotate the enemy, allowing it to avoid the obstacle

                               }

                               c_move (my, vector(10 * time_step, 0, 0), nullvector, GLIDE);

                               ent_animate(my, "run", run_percentage, ANM_CYCLE); // play the "run" animation

                               run_percentage += 6 * time_step; // "6" controls the animation speed

                       }

                       else

                       {

                               ent_animate(my, "alert", 100, NULL); // use the last frame from the "alert" animation here

                       }

                       if ((total_frames % 80) == 1) // fire a bullet each second

                       {

                               vec_for_vertex (temp, my, 8);

                               // create the bullet at enemy's position and attach it the "move_enemy_bullets" function

                               ent_create (bullet_mdl, temp, move_enemy_bullets);

                       }

                       if (vec_dist (player.x, my.x) > 1500) // the player has moved far away from the enemy?

                       {

                               my.status = idle; // then switch to "idle"

                       }

               }

               wait (1);

       }

       while (death_percentage < 100) // the loop runs until the "death" animation percentage reaches 100%

       {

               ent_animate(my, "deatha", death_percentage, NULL); // play the "die" animation only once

               death_percentage += 3 * time_step; // "3" controls the animation speed

               wait (1);

       }

       set (my, PASSABLE); // allow the player to pass through the corpse now

       ent_create ("healthbox.mdl", my.x, health_box);

       wait (3);

       ent_remove (my);

}

 

function got_shot()

{

       if (you.skill30 != 1) {return;} // didn't collide with a bullet? Then nothing should happen

       my.health -= 35;

       if (my.health <= 0) // dead?

       {

               my.status = dead; // stop the loop from "action my_enemy"

               my.event = NULL; // the enemy is dead, so it should stop reacting to other bullets from now on

               return; // end this function here

       }

       else // got shot but not (yet) dead?

       {

               my.status = attacking; // same thing with my.skill1 = 2

       }

}

 

function move_enemy_bullets()

{

       VECTOR bullet_speed; // this var will store the speed of the bullet

       my.skill30 = 1; // I'm a bullet

       // the bullet is sensitive to impact with other entities and to impact with level blocks

       my.emask |= (ENABLE_IMPACT | ENABLE_ENTITY | ENABLE_BLOCK);

       my.event = remove_bullets; // when it collides with something, its event function (remove_bullets) will run

       my.pan = you.pan; // the bullet has the same pan

       my.tilt = you.tilt; // and tilt with the enemy

       bullet_speed.x = 50 * time_step; // adjust the speed of the bullet here

       bullet_speed.y = 0; // the bullet doesn't move sideways

       bullet_speed.z = 0; // or up / down on the z axis

       // the loop will run for as long as the bullet exists (it isn't "null")

       while (my)

       {

               // move the bullet ignoring its creator (the enemy)

               c_move (my, bullet_speed, nullvector, IGNORE_YOU);

               wait (1);

       }

}

 

 

Q: I'm working on a high score table; how do I let the player input his name and then attach it to his score so that the score is next to his name?

A: Here's an example that counts how many times you can click the left mouse in 5 seconds; click the right mouse button (once) to start.

 

var high_score = 0;

var current_score = 0;

 

STRING* name_str = "#50";

STRING* input_str = "#50";

STRING* temp_str = "#10"; // just a temporary string

 

TEXT* name_txt =

{

       pos_x = 30;

       pos_y = 30;

       string(name_str);

       flags = SHOW;

}

 

TEXT* input_txt =

{

       pos_x = 10;

       pos_y = 450;

       string(input_str);

       flags = SHOW;

}

 

PANEL* score_txt =

{

       pos_x = 0;

       pos_y = 0;

       digits (450, 30, "Current score: %.0f", *, 1, current_score);

       flags = SHOW;

}

 

function init_startup()

{

       var i;

       while (1)

       {

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

               while (mouse_right) {wait (1);}

               str_cpy(input_str, "#50"); // reset the input string

               current_score = 0;

               i = 0;

               while (i < 5)

               {

                       if (mouse_left) {current_score += 1;}

                       while (mouse_left) {wait (1);}

                       i += time_step / 16;

                       wait (1);

               }

               if (current_score > high_score) // a new high score was achieved?

               {

                       high_score = current_score;

                       str_cpy(input_str, "New high score! Please type in your name!");

                       wait (-3); // display the message for 3 seconds

                       str_cpy(input_str, "#50"); // reset the string

                       inkey(input_str); // now let's input player's name                

                       str_cpy(name_str, input_str); // let's update the high score name on the screen as well

                       str_cat(name_str, " ---- "); // these characters separate the name and the actual high score

                       str_for_num(temp_str, high_score); // convert the numerical value to a string

                       str_cat(name_str, temp_str); // now add the high score to the string that contains the name of the player

               }

               str_cpy(input_str, "The test is over! Press the right mouse button to try again.");

               wait (1);

       }

}

 

aum91_faq3

 

 

Q: How do you create a mouse sensitivity snippet that allows you to see the change in real-time?

A: Use this snippet as a base for your code.

 

var mouse_sensitivity = 2;

var mouse_type = 0;

 

BMAP* slider_pcx = "slider.pcx";

BMAP* background_pcx = "background.pcx";

BMAP* pointer_tga = "pointer.tga";

 

function mouse_startup()

       mouse_map = pointer_tga;

       while (1)

       {

               vec_set(mouse_pos, mouse_cursor);

               wait(1);

       }

}

 

function toggle_mouse()

{

       mouse_type += 1;

       mouse_type %= 2;

       mouse_mode = mouse_type * 2;

}

 

function init_startup()

{

       on_mouse_right = toggle_mouse;

}

 

PANEL* gameover_pan =

{

       bmap = background_pcx;

       layer = 15;

       pos_x = 20;

       pos_y = 30;

       // create a slider that changes mouse_sensitivity between 1 and 10 over 256 pixels

       hslider(22, 0, 256, slider_pcx, 1, 10, mouse_sensitivity);

       flags = SHOW;

}

 

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 -= 3 * mouse_force.x * mouse_sensitivity * 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 += 2.5 * mouse_force.y * mouse_sensitivity * 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);

       }

}

 

aum91_questions4