Lesson3: Events and Physics

In Lesson 3 you'll write a physics engine application. For this you need to link not only the acknex.lib, but also the ackphysx.lib to your project, and copy the four DLLs required for physics (see publishing) into the folder of your executable. The example .vcproj in the engine_sdk folder does this already automatically in a post-link event.

///////////////////////////////////////////////////////////////
// Lesson3: Physics engine and event functions 
///////////////////////////////////////////////////////////////
#define WIN32_LEAN_AND_MEAN    
#include <windows.h>
#include <stdlib.h>
#include <malloc.h>
#include <memory.h>
#include <tchar.h>
#include "adll.h"

// Include the PhysX library.
// ackphysx.dll and the other PhysX DLLs must be in the EXE folder.
#pragma comment(lib, "ackphysx.lib")
#include "aphysx.h"

// some global definitions - we'll use them later
ENGINE_VARS *ev;
ENTITY *eBlob;
void Kick(void);
void Plop(void);

///////////////////////////////////////////////////////////////
int APIENTRY WinMain(HINSTANCE hInstance,  
                     HINSTANCE hPrevInstance,
                     LPSTR     lpCmdLine,  
                     int       nCmdShow)  
{
  ev = engine_open(NULL);
  add_folder(PATH_TO_SAMPLES);
  
// Activate stencil shadows - they are a 'redefine' variable 
// that has to be set before the first engine frame -
// and set the sound at full volume.
  v(video_mode) = 7;
  v(shadow_stencil) = 3;
  v(d3d_antialias) = 4;
  v(sound_vol) = 100;

// Create a splash screen panel at layer 1.
// The panel definition only contains a single bmap here.
  PANEL* pSplash = pan_create("bmap = logo_800.jpg;",1);

// Scale the panel by the screen to bmap size ratio
// in order to fit the screen, and make it visible.
  pSplash->scale_x = v(screen_size).x / bmap_width(pSplash->bmap);
  pSplash->scale_y = v(screen_size).y / bmap_height(pSplash->bmap);
  pSplash->flags |= SHOW;

// After a panel is set to SHOW, we have to wait 3 frames
// until we can really see it on the screen.
// The first frame paints it into the background buffer,
// two more frames are needed until the background buffer
// is flipped to the front in a triple buffer system.
  for (int i=0; i<3; i++) engine_frame();

// Before we can create level entities, a level must be loaded.
// We'll use the small terrain from the techdemo for a level.
  level_load("small.hmp");

// We use physics, so we register the level as a physics obstacle.
// This also automatically opens the PhysX engine.
  pXent_settype(NULL,PH_STATIC,PH_POLY);

// Now we can create a layer entity for a sky cube at layer 0.
// The SKY flag tells the engine that it's a sky entity, 
// and the CUBE flag tells that the image is a six-sided cube.
  ent_createlayer("skycube+6.dds",SKY|CUBE|SHOW,0);

// Let's now create a ball at position (0,0,100).
// The vector() function converts 3 vars to a temporary var vector
// for passing positions to engine functions.
  eBlob = ent_create("blob.mdl",vector(0,0,100),NULL);

// Now let's set the blob's physical properties. 
// We add a small speed to give it a little sidewards kick. 
  pXent_settype(eBlob,PH_RIGID,PH_CAPSULE);
  pXent_setelasticity(eBlob,80);
  pXent_setdamping(eBlob,20,5);
  pXent_addvelcentral(eBlob,vector(10,20,0));

// Activate an event: if the blob hits something, a sound shall be played. 
// We set the event function and the collision flag for triggering 
// a friction event at collisions with the level. 
  pXent_setcollisionflag(eBlob,NULL,NX_NOTIFY_ON_START_TOUCH);
  eBlob->event = (EVENT)Plop;

// We are setting two entity flags in order to cast, but not receive 
// dynamic shadows for the ball
  eBlob->flags |= SHADOW|CAST;

// Use one of the default materials for giving it a shiny look
  eBlob->material = &v(mat_metal);

// We want to kick the ball by pressing the space key. For this we could scan
// the key state in the main loop; however a more elegant way is a key event.
// We can assign functions to certain events like hitting a key, or a
// collision in the game.
  v(on_space) = (EVENT)Kick;

// Now that everything is set up, remove the splash screen.
  pan_remove(pSplash);

// During the main loop we're just moving the camera, as before.
  while (engine_frame()) 
  {

// For the camera movement we now use a more sophisticated method
// with the vec_accelerate() function. It accelerates a speed and
// is not dependent on the frame rate - so we don't need to
// use time_step in this example. This code is equivalent
// to the built-in camera movement, but uses different keys.
    static VECTOR vSpeed = { 0,0,0 }, vAngularSpeed = { 0,0,0 };
    VECTOR vForce, vMove;

// We need static vectors for the speeds here because they must be 
// preserved between loops.
    vForce.x = -5*(v(key_force).x + v(mouse_force).x);  // pan angle
    vForce.y = 5*(v(key_force).y + v(mouse_force).y);  // tilt angle
    vForce.z = 0;  // roll angle
    vec_accelerate(&vMove,&vAngularSpeed,&vForce,0.8);
    vec_add((VECTOR*)&v(camera).pan,&vMove);    

    vForce.x = 6 * (v(key_w) - v(key_s));    // forward
    vForce.y = 6 * (v(key_a) - v(key_d));    // sideward
    vForce.z = 6 * (v(key_home) - v(key_end));  // upward
    vec_accelerate(&vMove,&vSpeed,&vForce,0.5);
    vec_rotate(&vMove,(ANGLE*)&v(camera).pan);
    vec_add((VECTOR*)&v(camera).x,&vMove);

// Move all physics-controlled entities by the proper distance.
    physX_run(v(time_step)/16);

// Abort the main loop when [Esc] is pressed.
    if (v(key_esc)) break;
  }

// We don't need to free our created entities, bitmaps and sounds. 
// The engine does this automatically when closing.

  engine_close();
  return 0;
}

// This is our event function for the ball impact.
void Plop(void)
{
// Create a ball impact sound.
// Use a static pointer for creating it only once.
  static SOUND* sPong = snd_create("tap.wav");

// Play the sound at the event entities' position and speed.
  ent_playsound(eBlob,sPong,100);
}

// This is our event function for hitting the [Space] key.
void Kick(void)
{
// Create a speed vector and rotate it in camera direction.
  VECTOR vSpeed = { 150,0,0 };
  vec_rotate(&vSpeed,(ANGLE*)&v(camera).pan);

// Add a vertical speed to give the ball an upwards kick.
  vSpeed.z = 75;

// Now apply the speed to the ball, and play a hit sound.
  pXent_addvelcentral(eBlob,&vSpeed);
  Plop();
}

► latest version online