Questions from the forum

Top  Previous  Next

Q: I'd like my camera to tilt when the player is going through a slope on a mountain. Can you help?

A: Use the snippet below:

 

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

{

       var movement_speed = 10; // movement speed

       VECTOR temp;

       ANGLE temp_angles;

       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 = player.tilt;

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

               temp_angles.tilt = 0;

               temp_angles.roll = 0;

               temp_angles.pan = -my.pan;

               vec_rotate(normal, temp_angles);

               temp_angles.tilt = -asin(normal.x);

               temp_angles.roll = -asin(normal.y);

               my.tilt += 0.1 * ang(temp_angles.tilt - my.tilt); // play with 0.1

               my.roll += 0.1 * ang(temp_angles.roll - my.roll); // play with 0.1

               wait (1);

       }

}

 

aum85_faq1

 

 

Q: How can I trap the mouse pointer in a rectangular area located in the center of the screen?

A: Use this example:

 

// trap the mouse in an area that has 200x100 pixels and is located in the center of the screen

var area_x = 200;

var area_y = 100;

 

BMAP* pointer_tga = "pointer.tga";

 

function mouse_startup()

       VECTOR temp1_pos, temp2_pos;

       mouse_mode = 2;

       mouse_map = pointer_tga;

       while (1)

       

               vec_set(mouse_pos, mouse_cursor);

               temp1_pos.x = (screen_size.x - area_x) / 2;

               temp2_pos.x = (screen_size.x + area_x) / 2;

               mouse_pos.x = clamp(mouse_pos.x, temp1_pos.x, temp2_pos.x);

               temp1_pos.y = (screen_size.y - area_y) / 2;

               temp2_pos.y = (screen_size.y + area_y) / 2;

               mouse_pos.y = clamp(mouse_pos.y, temp1_pos.y, temp2_pos.y);

               wait(1);

       }

}

 

 

Q: How can I make it so that an entity moves for a specified number of seconds when I press a button?

A: There you go:

 

action moving_puppet()

{

       var movement_time = 5; // move for 5 seconds when the "M" key is pressed

       var movement_speed = 2; // movement speed

       VECTOR temp;

       while (1)

       {

               while (!key_m) {wait (1);} // wait until the player presses the "M" key on the keyboard

               while (key_m) {wait (1);} // wait until the player releases the "M" key

               while (movement_time > 0)

               {

                       movement_time -= time_step / 16; // decrease 1 from movement_time each second

                       my.skill1 += 4 * time_step; // 4 gives the animation speed

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

                       temp.z -= 10000;

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

                       // move the entity with the speed given by movement_speed along the direction pointed by its pan angle

                       c_move (my, vector(movement_speed, 0, temp.z), nullvector, IGNORE_PASSABLE | GLIDE);

                       // animate the model using its "walk" animation in a loop

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

                       wait (1);

               }

               // the walking is over here, so let's switch to the "stand" animation

               ent_animate(my, "stand", 0, 0);

               movement_time = 5; // prepare for a new movement session

       }

}

 

 

Q: How can I make a sound play once as soon as a comparison instruction is successful?

A: Here's an example:

 

STRING* password_str = "iliketoeatalot";

STRING* input_str = "#20"; // this empty string can store up to 20 characters

STRING* messages_str = "30";

 

SOUND* passok_wav = "passok.wav";

 

TEXT* input_txt =

{

       pos_x = 300;

       pos_y = 400;

       string(input_str);

}

 

TEXT* messages_txt =

{

       pos_x = 300;

       pos_y = 300;

       string(messages_str);

}

 

function password_startup()

{

       wait (-3); // wait until the game starts, etc

       // the following loop will run until the correct password is typed in

       while (1)

       {

               str_cpy(messages_str, "Type in the correct password");

               messages_txt.flags |= SHOW; // show the intro message

               wait (-3); // for 3 seconds

               messages_txt.flags &= ~SHOW; // now hide the intro message

               input_txt.flags |= SHOW; // show the input

               str_cpy(input_str, "#20"); // reset the string (if needed)

               inkey(input_str);

            if (str_cmpi(input_str, password_str) == 1) // the correct password was typed in?

             {

                       snd_play(passok_wav, 90, 0);

                       break; // get out of the loop

               }

       }

       // the correct password was typed in here

       str_cpy(messages_str, "Logged into the system");

       messages_txt.flags |= SHOW; // show the outro message

       wait (-5); // for 5 seconds

       messages_txt.flags &= ~SHOW; // now hide the outro message        

       sys_exit(NULL); // shut down the engine

}

 

 

Q: I want to attach the camera of my game to an object (sphere, etc) so that the camera has a physical behaviour and doesn't go through walls anymore.

A: Use this piece of code:

 

VECTOR movement_force;

 

action solid_camera() // attach this action to a sphere model

{

       set (my, INVISIBLE); // no need to see the sphere model

       while (1)

       {

               // use the W and S keys to move forward / backward, 5 gives the movement speed

               movement_force.x = 5 * (key_w - key_s);

               // use the A and D keys to move sideways, 3 gives the movement speed

               movement_force.y = 3 * (key_a - key_d);

               // don't allow the z value of movement_force to change

               movement_force.z = 0;

               my.pan -= 3 * mouse_force.x * time_step; // 3 = horizontal rotation speed

               my.tilt -= 3 * mouse_force.y * time_step; // 3 = vertical rotation speed

               // now move the sphere in the direction given by its pan and tilt angles

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

               // the camera will inherit the same position and angles with the sphere

               vec_set (camera.x, my.x);

               camera.pan = my.pan;

               camera.tilt = my.tilt;

               wait(1);

       }

}

 

 

Q: For my tests I'd need a snippet which, with the press of a button, writes camera's coordinates to an ini file. Then, with the press of another button, the camera would load those coordinates from the ini file.

A: There you go:

 

var file_handle;

 

VECTOR vSpeed, vAngularSpeed, vForce, vMove;

 

function camera_startup() // this camera can pass through walls

{

       while (1)

       {

               vForce.x = - 5 * (key_force.x + mouse_force.x);        // pan angle

               vForce.y = 5 * (key_force.y + mouse_force.y); // tilt angle

               vForce.z = 0; // no changes for the roll angle

               vec_accelerate (vMove, vAngularSpeed, vForce, 0.8);

               vec_add (camera.pan, vMove);

               vForce.x = 6 * (key_w - key_s); // use W and S to move forward

               vForce.y = 6 * (key_a - key_d); // use A and D to move sideways

               vForce.z = 6 * (key_home - key_end); // use Home and End to move upwards / downwards

               vec_accelerate (vMove, vSpeed, vForce, 0.5);

               vec_rotate (vMove, camera.pan);

               vec_add (camera.x, vMove);

               wait(1);

       }

}

 

function save_position()

{

       file_handle = file_open_write ("camera.ini"); // save the data to the camera.ini file

       file_var_write (file_handle, camera.x); // save x, y, z, pan, tilt, roll

       file_var_write (file_handle, camera.y);

       file_var_write (file_handle, camera.z);

       file_var_write (file_handle, camera.pan);

       file_var_write (file_handle, camera.tilt);

       file_var_write (file_handle, camera.roll);

       file_close (file_handle); // close the file, we won't be needing it from now on

}

 

function load_position()

{

       file_handle = file_open_read("camera.ini"); // try to open ini file

       if (file_handle) // the file exists? (the player could press "2" without pressing "1" first)

       {

               camera.x = file_var_read (file_handle); // then restore the x, y, z, pan, tilt, roll

               camera.y = file_var_read (file_handle);

               camera.z = file_var_read (file_handle);

               camera.pan = file_var_read (file_handle);

               camera.tilt = file_var_read (file_handle);

               camera.roll = file_var_read (file_handle);

       }

}

 

function init_startup()

{

       on_1 = save_position; // press "1" to save the camera coordinates

       on_2 = load_position; // press "2" to load the camera coordinates

}

 

 

Q: I'd like to be able to pick, move and drop an object using the mouse cursor.

A: Here's an improved version of my code from Aum52's faq that runs fine with A7 / lite-C:

 

BMAP* pointer_tga = "pointer.tga";

 

VECTOR temp;

 

function mouse_startup()

       mouse_mode = 2;

       mouse_map = pointer_tga;

       while (1)

       

               vec_set(mouse_pos, mouse_cursor);

               wait(1);

       }

}

 

function pick_or_drop()

{

       wait (1);

       my.skill1 += 1;

       if ((my.skill1 % 2) == 1) // clicked the object?

       {

               while (mouse_left) {wait (1);} // wait until the player releases the left mouse button

               while (!mouse_left) // move the object until the player presses the mouse button again

               {

                       temp.x = mouse_cursor.x;

                       temp.y = mouse_cursor.y;

                       temp.z = 200; // move the object 200 quants below the camera, play with this value

                       vec_for_screen(temp.x, camera);

                       vec_set (my.x, temp.x);

                       set (my, PASSABLE);

                       wait (1);

               }

       }

       else // drop the object here

       {

               vec_set (temp.x, my.x);

               temp.z -= 3000; // trace up to 5,000 quants below the player

               // make sure to drop the object on the ground

               my.z -= c_trace (my.x, temp.x, IGNORE_ME + IGNORE_SPRITES + IGNORE_MODELS + USE_BOX);

               reset (my, PASSABLE);

       }

}

 

action click_and_move()

{

       my.skill1 = 0;

       my.emask |= ENABLE_CLICK;

       my.event = pick_or_drop;

}

 

aum85_faq3

 

 

Q: I have developed a small project where the player has to guess a number from 1 to 9. I can enter the code using the keyboard numbers from 1 to 9 but nothing happens when pressing the numerical keypad numbers. I have the num_lock on. Why does this not work?

A: The numerical keypad numbers have other scan codes; use the snippet below to detect the names and the scan codes for the keys on the keyboard. I suggest that you should always use scan codes for your projects.

 

STRING* temp_str = "#10";

 

TEXT* header_txt =

{

       pos_x = 180;

       pos_y = 5;

       string("Key name ------- Scan code");

       flags = SHOW;

}

 

TEXT* keypressed_txt =

{

       pos_x = 200;

       pos_y = 20;

       string(temp_str);

       flags = SHOW;

}

 

PANEL* keypressed_pan =

{

       layer = 15;

       digits(300, 20, 3, * , 1, key_lastpressed);

       flags = SHOW;

}

 

function keys_startup()

{

       while (1)

       {

               if (key_any)

               {

                       beep();

                       str_for_key(temp_str, key_lastpressed); // convert the scan code to the key name

               }

               while (key_any) {wait (1);} // wait until all the keys are released

               wait (1);

       }

}

 

 

Q: I'd like to have a dynamic light that can be picked up by pressing space near it and follows the player. The light should always be on, even after a level changing instruction. How can I do that?

A: The actions attached to entities stop running after a level_load instruction; nevertheless, the variables keep their values and can be used to recreate what's needed, just like this:

 

var got_flashlight = 0;

 

SOUND* gotflashlight_wav = "gotflashlight.wav";

 

ENTITY* flashlight;

 

function move_flashlight()

{

       set (my, PASSABLE | INVISIBLE | CAST);

       my.lightrange = 350;

       my.red = 200;

       my.green = 200;

       my.blue = 160;

       while (player) // this loop will run for as long as the player pointer exists

       {

               vec_set(my.x, player.x);

               wait (1);

       }

}

 

action my_flashlight()

{

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

       while (1)

       {

               if (vec_dist(player.x, my.x) < 70)

               {

                       if (key_space)

                       {

                               snd_play(gotflashlight_wav, 50, 0);

                               flashlight = ent_create("flashlight.mdl", player.x, move_flashlight);

                               got_flashlight = 1;

                               wait (2);

                               break; // get out of this loop

                       }

      }

               wait (1);

       }

       set(my, PASSABLE | INVISIBLE); // hide the flashlight model on the floor

       while (vec_dist(player.x, my.x) < 300) {wait (1);} // wait until the player moves away

       // and then remove the flashlight model from the floor (give the sound effect enough time to play)

       ent_remove (my);

}

 

action players_code() // attach this action to your player model in all the levels

{

       var movement_speed = 10; // movement speed

       VECTOR temp;

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

       player = my; // I'm the player

 

       // this section recreates the flashlight (if needed)

       if (got_flashlight == 1) // the flashlight was picked up in a previous level?

       {

               flashlight = ent_create("flashlight.mdl", player.x, move_flashlight); // the recreate it!

       }

       // end of the section that recreates the flashlight (if needed)

 

       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 = player.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 lever_changer() // attach this action to your level changing entity

{

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

       // wait until the player comes closer than 100 quants to the level changing entity

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

       // now load the new level; the flashlight will be recreated if it was picked up in a previous level

       level_load("level2.wmb");

}

 

 

Q: I'd like to create a mini math quiz with a text like 5 x 2 that appears on the screen. The users enter an answer and press Enter in order to move on to the following question. If they are wrong their score is decreased.

A: Use this example as a base for your code:

 

var score = 0, number1, number2, my_result;

 

STRING* question_str = "#20";

STRING* answer_str = "#5";

STRING* temp_str = "#5";

 

SOUND* goodjob_wav = "goodjob.wav";

SOUND* missed_wav = "missed.wav";

 

TEXT* question_txt =

{

       pos_x = 200;

       pos_y = 200;

       string(question_str);

       flags = SHOW;

}

 

TEXT* answer_txt =

{

       pos_x = 300;

       pos_y = 200;

       string(answer_str);

       flags = SHOW;

}

 

PANEL* score_pan =

{

       layer = 15;

       digits(700, 20, 4, * , 1, score);

       flags = SHOW;

}

 

function init_startup()

{

       random_seed(0); // generate a random sequence of numbers

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

       while (1)

       {

               str_cpy(question_str, "What is ");

               number1 = integer(random(10) + 1); // number 1 ranges from 1 to 10

               str_for_num(temp_str, number1); // convert number1 to a string

               str_cat(question_str, temp_str); // add number1 to question_str

               str_cat(question_str, " x ");

               number2 = integer(random(10) + 1); // number 2 ranges from 1 to 10

               str_for_num(temp_str, number2); // convert number1 to a string

               str_cat(question_str, temp_str); // add number2 to question_str

               wait (1);                        

               str_cat(question_str, " = ");

               str_cpy(answer_str, "#5");

               inkey(answer_str);

               my_result = str_to_num(answer_str);

               if (my_result == (number1 * number2)) // the player has got the correct answer?

               {

                       score += 1; // then increase the score

                       snd_play(goodjob_wav, 60, 0);

               }

               else

               {

                       snd_play(missed_wav, 60, 0);

                       score -= 1; // then decrease the score

                       score = maxv(0, score); // don't allow negative score values

               }

               wait (-3); // wait for 5 seconds before generating a new exercise

       }

}