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