Tutorial 1 : How to integrate mvMotionAI library into a C++ application

Menu

Back To Index

Step by Step Guide to tutorial 1

This file is included with the mvMotionAI 00-02-15 full workspace and this code is revelant to version 00-02-15 and greater. This tutorial does not any specific information to build or compile this code.

Step 1 : include the main library header file

The programmer only has to reference one header file, mvMotionAI.h (usually located in mv directory). For example in this tutorial (and other future applications), we add this following line to the top of the source code and all objects types in mvMotionAI will be declared:

#include <mv/mvMotionAI.h>

Back To Menu

Step 2: Declare & implement various observer functions for loop based functions using the C mvMotionAI interface

All objects created by the mvMotionAI are accessible via the C interface. All C++ objects related to the mvMotionAI (as in C++ pointers) and their memory allocated are automatically held and freed by the mvMotionAI library. To remove the responsibility of memory deletion of objects from the programmer but allow these same objects to be assessible, the library has iteration (loop) functions that allows only the objects that are still in the application's memory to be affected. Within this interface, there are two approaches to retrieve information or setting variables of multiple items in mvMotionAI. The first approach involves using the mvIndex loop function and the second approach uses the C++ pointer loop functions. One more important thing to remember, mvMotionAI does not use callbacks or stored function pointers, so the loop functions below must be called manually for every time that the user-defined function is needed.

Back To Menu

  1. Approach 1 : via the mvIndex C loop functions interface

    When an mvMotionAI object is created (as shown in Step 5 ), a corresponding mvIndex (any non-zero value if correctly created else MV_NULL if error has occurred) is returned to the programmer. Therefore we can retrieve and edit each item by using its mvIndex value. If the programmer wants to manipulate multiple objects within an world instance using their indexes with the same function, we can use

    1. The mvWorld's mvIndex,
    2. A programmer-defined function, (in the form of):

      void (indexFunction)(mvIndex worldIndex, mvIndex objectIndex, void *extraPtr);

    3. .. with one of the following mvIndex loop functions which represent each of the objects within mvMotionAI library.

      MV_GLOBAL_FUNC_PREFIX mvErrorEnum mvApplyToAllBodiesByIndex(mvIndex worldIndex, void (indexFunction)(mvIndex,mvIndex,void*), void* extraPtr);
      MV_GLOBAL_FUNC_PREFIX mvErrorEnum mvApplyToAllObstaclesByIndex(mvIndex worldIndex, void (indexFunction)(mvIndex,mvIndex,void*), void* extraPtr);
      MV_GLOBAL_FUNC_PREFIX mvErrorEnum mvApplyToAllWaypointsByIndex(mvIndex worldIndex, void (indexFunction)(mvIndex,mvIndex,void*), void* extraPtr);
      MV_GLOBAL_FUNC_PREFIX mvErrorEnum mvApplyToAllPathwaysByIndex(mvIndex worldIndex, void (indexFunction)(mvIndex,mvIndex, void*), void* extraPtr);
      MV_GLOBAL_FUNC_PREFIX mvErrorEnum mvApplyToAllGroupsByIndex(mvIndex worldIndex, void (indexFunction)(mvIndex,mvIndex, void*), void* extraPtr);
      MV_GLOBAL_FUNC_PREFIX mvErrorEnum mvApplyToAllBehavioursByIndex(mvIndex worldIndex, void (indexFunction)(mvIndex,mvIndex, void*), void* extraPtr);
      MV_GLOBAL_FUNC_PREFIX mvErrorEnum mvApplyToAllGroupBehavioursByIndex(mvIndex worldIndex, void (indexFunction)(mvIndex,mvIndex, void*), void* extraPtr);
      MV_GLOBAL_FUNC_PREFIX mvErrorEnum mvApplyToAllForcesByIndex(mvIndex worldIndex, void (indexFunction)(mvIndex,mvIndex, void*), void* extraPtr);

    Also we can link these loop functions together and using the same approach, apply them any linked (as in created via the C mvMotionAI library interface) mvWorld instance via their mvIndex. To apply the combined function (void (combinedFunction)(mvIndex worldIndex, void *extraPtr)) to any linked mvWorld instance in the library, the programmer would use the function below:

    MV_GLOBAL_FUNC_PREFIX mvErrorEnum mvApplyToAllWorldsByIndex(void(someFunction)(mvIndex, void* extraPtr), void* extraPtr);

    Back To Menu

    Tutorial 1

    In this example, we have declared a mvIndex observer function in the following format:

    void displayAllBodyByIndexes(mvIndex worldIndex, mvIndex index, void *extraPtr);

    We can apply the void displayAllBodyByIndexes(mvIndex worldIndex, mvIndex index, void *extraPtr) to each body by passing the function into mvApplyToAllBodiesByIndex. Any object can be passed onto the function by setting the pointer (void*) to a struct or object as the second argument of the loop function.

    const char* bodyHeader = "BODY ";

    // loop over bodies in the ourWorld instance
    mvApplyToAllBodiesByIndex(ourWorld, displayAllBodyByIndexes,
      (void*) bodyHeader);

    The programmer can then retrieve that pointer from inside the function by recasting it back. In our tutorial, we are using a C type char string pointer and within the function, printing out that string plus the global position of each body. Below is the implementation of the void displayAllBodyByIndexes(mvIndex worldIndex, mvIndex index, void *extraPtr)function:

    // this function is for iterating over all bodies using the C function interface
    void displayAllBodyByIndexes(mvIndex worldIndex, mvIndex index, void *extraPtr)
    {
      mvCount noOfParameters;
      //PLEASE USE >= MV_MAX_NO_OF_PARAMETERS as the get parameter array size
      mvFloat positionArray[MV_MAX_NO_OF_PARAMETERS];

      if (mvGetBodyParameterv(worldIndex, index, MV_POSITION, &positionArray[0],
        &noOfParameters) == MV_NO_ERROR)
      {
        std::cout << (const char*) extraPtr << " world index : " << worldIndex
          << " body index : " << index << std::endl;

        std::cout << "Pos ";
        for (int j = 0; j < noOfParameters; j++)
        {
          std::cout << positionArray[j] << ", ";
        }

        std::cout << std::endl;
      }
    }

    Back To Menu

  2. Approach 2 : via the C++ pointer loop interface

    The second approach allows the programmer to use the various methods belonging to mvMotionAI C++ classes themselves. By using the C++ pointer loop functions, we can avoid any C++ pointers that reference NULL objects, such as deleted items & non-existent bodies. If we wanted to apply the same function to all objects, the function's format must be in this form:

    void (myClass_Function)(myClass_Ptr,void*);

    ... along with any of these pointer loop functions in the mvMotionAI library.

    MV_GLOBAL_FUNC_PREFIX mvErrorEnum mvApplyToAllBodies(mvIndex worldIndex,void (mvBodyPtr_Function)(mvBodyPtr,void*),void* extraPtr);
    MV_GLOBAL_FUNC_PREFIX mvErrorEnum mvApplyToAllObstacles(mvIndex worldIndex, void (mvObstaclePtr_Function)(mvObstaclePtr,void*),void* extraPtr);
    MV_GLOBAL_FUNC_PREFIX mvErrorEnum mvApplyToAllWaypoints(mvIndex worldIndex, void (mvWaypointPtr_Function)(mvWaypointPtr,void*),void* extraPtr);
    MV_GLOBAL_FUNC_PREFIX mvErrorEnum mvApplyToAllPathways(mvIndex worldIndex, void (mvPathwayPtr_Function)(mvPathwayPtr,void*),void* extraPtr);
    MV_GLOBAL_FUNC_PREFIX mvErrorEnum mvApplyToAllGroups(mvIndex worldIndex, void (mvGroupPtr_Function)(mvGroupPtr,void*),void* extraPtr);
    MV_GLOBAL_FUNC_PREFIX mvErrorEnum mvApplyToAllBehaviours(mvIndex worldIndex, void (mvBehaviourPtr_Function)(mvBehaviourPtr,void*),void* extraPtr);
    MV_GLOBAL_FUNC_PREFIX mvErrorEnum mvApplyToAllGroupBehaviours(mvIndex worldIndex, void (mvGroupBehaviourPtr_Function)(mvGroupBehaviourPtr,void*), void* extraPtr);
    MV_GLOBAL_FUNC_PREFIX mvErrorEnum mvApplyToAllForces(mvIndex worldIndex, void (mvBaseForcePtr_Function)(mvBaseForcePtr,void*),void* extraPtr);

    As in the previous approach, we can join many of these C++ pointer loop functions together and apply them to any existing linked (as in created via the C mvMotionAI library interface) mvWorld instance. For example, a function that use mvWorld pointer (void (mvWorldPtr_CombinedFunction)(mvWorldPtr, void*)) we would pass that combined function as an argument to the following mvMotionAI function below:

    MV_GLOBAL_FUNC_PREFIX mvErrorEnum mvApplyToAllWorlds(void (someFunction)(mvWorldPtr,void*),void* extraPtr);

    Back To Menu

    Tutorial 1

    In this example, we have declared a mvObstacle pointer function in the following format:

    void displayAllObstaclesByPtr(mvObstaclePtr currentObstacle, void* extraPtr);

    To execute this function over all mvObstacle objects inside a mvWorld instance, the programmer should pass displayAllObstaclesByPtr to the corresponding mvObstacle loop function. The example below shows how to pass our mvObstacle function to a loop function, along with C char string variable obstacleHeader. This function prints out the string plus the position of the obstacle object.

    const char* obstacleHeader = "OBSTACLE : ";

    // loop over all obstacles in the ourWorld instance
    mvApplyToAllObstacles(ourWorld, displayAllObstaclesByPtr, (void*) obstacleHeader);

    The full implementation of displayAllObstaclesByPtr can be found in the Full Source Code section of this tutorial.

Back To Menu

Step 3 : initialise mvMotionAI library

Here we initialise the mvMotionAI interface because the mvMotionAI interface and its functions will not work without previously calling the function mvInitMotionAI.

int main(void)
{
  mvInitMotionAI();

Back To Menu

Step 4 : create world instance

Here we create the engine of mvMotionAI library with the mvCreateWorld command. The value type returned is an mvIndex. Most of the functions in the mvMotionAI C interface need an mvIndex of the mvWorld as a parameter. mvIndexes are just integers (or array indexes) that refer to the C++ objects within the mvMotionAI library. Each mvIndex is only unique among the other indexes of the same type but two mvIndexes can refer to the same object through the use of positive and negetive indexes. Positive mvIndexes (starting from 1, 2, ...) are equal to the exact mvIndex returned at the time of creation of the object within mvMotionAI library, while negetive mvIndex (i.e. -1, -2 ..) refers from the current state of any mvMotionAI object starting from the last item created. So mvIndexes are usually non-zero values unless the mvIndex is out of range of any item or MV_NULL. If an mvIndex of MV_NULL or 0 is used within the library, then nothing should happen. Also an error has occured if MV_NULL is returned from an mvCreate_Object function.

  mvIndex ourWorld = mvCreateWorld();

Back To Menu

Step 5 : create multiple bodies

Here is this section, we create a number of mvObstacle and mvBody objects to test out the functions displayAllObstaclesByPtr and displayAllBodyByIndexes within ourWorld variable.

  for (int i = 0; i < 5; i++)
  {
    mvCreateBody(ourWorld, MV_PARTICLE, MV_AABOX, i, i * 2, i * 3);
    mvCreateObstacle(ourWorld, MV_AABOX, MV_LIQUID_OBSTACLE, i * 5, i, i * -2);
  }

Back To Menu

Step 6 : free mvMotionAI library - automatically at close.

The function will clear up any of the memory associated with any object created via C mvMotionAI interface. Actually it does automatically free when the programs closes but the library has not been tested in multi-threaded applications.

  mvFreeMotionAI();

This is the end of the tutorial 1 of mvMotionAI library and more details, the section below contains the full source code of tutorial1.cpp.

Back To Menu

Full Source Code

// step 1 : include the main library header file
#include <mv/mvMotionAI.h>

// for outputting info
#include <iostream>

// step 2: create various function for loop based functions

// mvIndex - c interface index type
void displayAllBodyByIndexes(mvIndex worldIndex, mvIndex index, void *extraPtr);

// c pointer type
void displayAllObstaclesByPtr(mvObstaclePtr currentObstacle, void* extraPtr);

int main(void)
{
  // step 3 : initialise library
  mvInitMotionAI();

  // step 4 : create world instance
  mvIndex ourWorld = mvCreateWorld();

  // step 5 : create multiple bodies
  for (int i = 0; i < 5; i++)
  {
    mvCreateBody(ourWorld, MV_PARTICLE, MV_AABOX, i, i * 2, i * 3);
    mvCreateObstacle(ourWorld, MV_AABOX, MV_LIQUID_OBSTACLE, i * 5, i, i * -2);
  }

  const char* obstacleHeader = "OBSTACLE : ";
  const char* bodyHeader = "BODY ";

  // loop over bodies in the ourWorld instance
  mvApplyToAllBodiesByIndex(ourWorld, displayAllBodyByIndexes,
    (void*) bodyHeader);

  // loop over all obstacles in the ourWorld instance
  mvApplyToAllObstacles(ourWorld, displayAllObstaclesByPtr,\
    (void*) obstacleHeader);

  // step 6 : free motion library - automatically at close.
  mvFreeMotionAI();

  return 0;
}

// this function is for iterating over all bodies using the C function interface
void displayAllBodyByIndexes(mvIndex worldIndex, mvIndex index, void *extraPtr)
{
  mvCount noOfParameters;
  mvFloat positionArray[MV_MAX_NO_OF_PARAMETERS];

  if (mvGetBodyParameterv(worldIndex, index, MV_POSITION, &positionArray[0],
    &noOfParameters) == MV_NO_ERROR)
  {
    std::cout << (const char*) extraPtr << " world index : " << worldIndex
      << " body index : " << index << std::endl;

    std::cout << "Pos ";
    for (int j = 0; j < noOfParameters; j++)
    {
      std::cout << positionArray[j] << ", ";
    }

    std::cout << std::endl;
  }
}

// this functions is used to interact with
void displayAllObstaclesByPtr(mvObstaclePtr currentObstacle, void* extraPtr)
{
  mvVec3 position = currentObstacle->getPosition();

  std::cout << (const char*) extraPtr
    << " Pos : " << position.getX()
    << ", " << position.getY()
    << ", " << position.getZ() << std::endl;
}

Back To Menu


This file was created with HTML Kit on 8th October 2007, last edited on 10th October 2007. This code is revelant to version 00-02-15 and greater.

SourceForge.net Logo