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.
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 }
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; }
|