Beginner's corner

Top  Previous  Next

Rollem

 

This month I have decided to create a small game example for the A6 commercial users, who can use one physics object. It's a "Marbles" clone, without its bells and whistles, but most of that stuff comes with the level design; however, the code for the ball is finished and can be plugged in any game.

 

aum47_shot_1

 

The goal of the game is simple: you must collect as many gems as possible by running into them. The score is displayed in the upper left corner of the screen using a simple panel definition:

 

panel score_pan

{

   pos_x = 5;

   pos_y = 5;

   layer = 10;

   digits = 10, 10, 5, _a4font, 1, total_score;

   flags = overlay, refresh, visible;

}

 

Let's examine function main:

 

function main()

{

   time_smooth = 0;

   fps_max = 140;

   fps_lock = on;

   level_load (rollem_wmb);

   wait (3);

   ph_setgravity (vector(0, 0, -386));

   while (1)

   {

      camera.x = ball.x;

      camera.y = ball.y;

      camera.z = 1500;

      camera.tilt = -90;

      wait (1);

   }

}

 

This function doesn't smooth the "time" variable, in order to prevent the jerks. We limit the frame rate to 140 (the physics engine is locked to 70 fps by default), and then we lock "time" to the value that was set by fps_max. We load the level, we wait until it is loaded, and then we set a gravity force that's similar to Earth's gravity. The "while" loop makes sure that the camera follows the ball, being placed 1500 quants above the origin and looking down at the ball.

 

var mouse_sensitivity = 400; // experimental value

var key_sensitivity = 250; // experimental value

 

action physics_ball

{

   ball = my;

   my.scale_x = 1.5;

   my.scale_y = my.scale_x;

   my.scale_z = my.scale_x;

   phent_settype (my, ph_rigid, ph_sphere);

   phent_setmass (my, 5, ph_sphere);

   phent_setfriction (my, 40);

   phent_setdamping (my, 20, 20);

   phent_setelasticity (my, 80, 5);

   while(1)

   {

      vec_set (temp, nullvector);

      temp.x = (key_cur - key_cul) * key_sensitivity + mouse_force.x * mouse_sensitivity;

      temp.y = (key_cuu - key_cud) * key_sensitivity + mouse_force.y * mouse_sensitivity;

      temp.z = 0;

      vec_rotate (temp, vector(camera.pan, 0, 0));

      vec_normalize (temp, 200 * time);

      phent_addtorqueglobal (my, temp);

      wait (1);

   }

}

 

You can see that the action attached to the ball is pretty simple: it sets the "ball" pointer, it sets the scale of the ball model, and then it makes it behave like a sphere that weighs 5 kilograms (~11 pounds). We set a friction coefficient of 40, as well as proper damping and bounciness values; make sure to tweak them to your liking.

 

The "while" loop moves the ball when the player presses the arrow keys and / or moves the mouse. Don't forget to play with "mouse_sensitivity" and "key_sensitivity". We use vec_rotate to rotate the movement force along the direction that is pointed by the camera, and then we limit the force that will be applied to the ball to 200 * time. The following line of code adds an angular force to the ball (makes it rotate).

 

What else do we have here? Ah, the gems!

 

action gem_bonus

{

   my.scale_x = 1;

   my.scale_y = my.scale_x;

   my.scale_z = my.scale_x;

   my.passable = on;

   while (ball == null) {wait (1);}

   while (vec_dist(ball.x, my.x) > 70)

   {

      my.pan += 3 * time;

      wait (1);

   }

   snd_play (gem_wav, 100, 0);

   total_score += 10;

   my.invisible = on;

}

 

First of all we set the scale for the gems; I chose to set it to 1, but you might want to use another value here. The gems are passable and need to wait until the "ball" entity is created. Each gem will wait until the ball comes closer than 70 quants to it, and it will rotate by changing its pan angle until that happens. If the ball is moved closer to the gem, we hear a sound, the score is increased by 10 and the gem is made invisible. That's it!

 

 

Handles

 

What do you do when you need to control 20 different entities? Well, you can define 20 different pointers named (let's say) tree1... tree20 and maybe change their z positions this way: tree4.z = 200; or tree15.z = 150; and so on. But what do you do if you need to control 100 or 1000 entities? Who wants to define 1000 pointers?

 

This small article will show you how to use handles, which are nothing more than unique numbers that can be associated to any of your entities, actions, strings, bitmaps, panels... (almost) whatever you might need.

 

var index = 0;

var my_entities[100]; // control up to 100 different entities

 

entity* temp_ptr; // temporary pointer to the entity

 

I have defined a variable named index and an array that can store up to 100 handles; I chose 100 as an example, but you can control over 10,000 entities without any problem. I have also defined a temporary pointer named temp_ptr.

 

action control_entities

{

   my_entities[index] = handle (my);

   index += 1;

   // put the rest of your entity code here

}

 

The action above is attached to our entities; it stores the handle to the entity (a number) inside the array, at the position given by the index variable, and then it increments index, allowing the other entities to store their handles inside the array.

 

function move_entity(number, height)

{

   temp_ptr = ptr_for_handle(my_entities[number]);

   temp_ptr.z += height; // increase the z of the entity by "height" quants

}

 

This is a simple example of a function that moves an entity along its z axis; you could use it to move the crowd sprites in your sports game, and so on. Call the function this way:

 

move_entity(5, 40);

 

and it will move the 5th entity 40 quants upwards; or call it this way:

 

move_entity(23, -30);

 

and it will move the 23rd entity downwards by 30 quants. If you use a while loop to generate random numbers and heights, and then you call function move_entity using those values, you will have a realistic looking, furiously animated crowd in no time!