Upcoming Events
Unite 2010
11/10 - 11/12 @ Montréal, Canada

GDC China
12/5 - 12/7 @ Shanghai, China

Asia Game Show 2010
12/24 - 12/27  

GDC 2011
2/28 - 3/4 @ San Francisco, CA

More events...
Quick Stats
115 people currently visiting GDNet.
2406 articles in the reference section.

Help us fight cancer!
Join SETI Team GDNet!
Link to us Events 4 Gamers
Intel sponsors gamedev.net search:

Introduction to GameMonkey Script Part 2
Embedding GameMonkey


Constructor with Parameters

At present, this type is pretty useless as there is no way of accessing the data the Vector contains. The decision about how to access the data is an important one; shall we allow the user to access it via named properties (e.g.: x, y, z members) or via an array of floats. I shall answer this question shortly, but first we need a way of initialising the data on construction of the type. As in the C++ class, we want to allow the user to specify a constructor with several parameters to initialise the data in the vector as well as providing a default constructor.

namespace gmVector
{

int GM_CDECL default_constructor( gmThread *a_thread )
{
    // Create a native object with default params
    Vector *p = new Vector();
    a_thread->PushNewUser( p, Type );
    return GM_OK;	
}

/// This is the constructor for passed data items
int GM_CDECL data_constructor( gmThread *a_thread )
{    
    // Check for a valid number of parameters
    if (a_thread->GetNumParams() != 3 )
        return GM_EXCEPTION;
	
    // Loop through and grab the params, checking their types
    float v[3];
    for (int i = 0; i < 3; ++i)
    {
    	switch (a_thread->Param(i).m_type)
    	{
        case GM_INT:
    		v[i] = a_thread->Param(i).m_value.m_int;
    		break;
    	case GM_FLOAT:
    		v[i] = a_thread->Param(i).m_value.m_float;
    		break;
        default:
            a_thread->GetMachine()->GetLog().LogEntry( "Vector: Param %d error - expected int or float", i );
            return GM_EXCEPTION;
    	}
    }

    // Create a native object with default params
    Vector *p = new Vector( v[0], v[1], v[2] );
    // Return to GM
    a_thread->PushNewUser( p, Type );
    return GM_OK;	
}
			
/// Entry point for the library; this is effectively the constructor 
int GM_CDECL libentry( gmThread *a_thread )
{
    // Delegate the appropriate call based on the arg count
    switch (a_thread->GetNumParams())
    {
    case 0:
        return default_constructor( a_thread );
    case 3:
        return data_constructor( a_thread );
    };
    
    // Not handled, log an error and return an exception
    a_thread->GetMachine()->GetLog().LogEntry( "Vector: Bad number of parameters passed" );
    return GM_EXCEPTION;
}

};	// end namespace gmVector

Example: vector_2.cpp

I have adjusted the libentry function to delegate the actual constructor operation based on the number of parameters passed. The default_constructor function is the same as the previous libentry function, but in data_constructor you can see that I engage in an operation to retrieve the parameters from the thread. This is exactly the same as if you were binding a regular function, so I won't dwell on how it works. The new constructor validates that the parameters are either integers or floats and stores them for passing to the native Vector class' constructor.

The data constructor could be extended to allow for copy construction of objects, allowing you to pass a variable of your Vector type and use it to create a copy of itself. This is important to remember as GameMonkey Script user-bound variables are reference types; if you assign a variable with another they will reference each other and any changes made to one will be visible in the other. As a learning exercise, I will leave the addition of the copy constructor as an extension for you to pursue on your own - you should be able to code it yourself with the information I've given you so far. If you get stuck you may refer to example vector_2a.cpp for my implementation.

Now that there's some actual data in the vector object you need to allow scripts to retrieve it for use in other operations. It is at this point that we must decide the data access method; I have chosen to provide the members x, y z as this is familiar to many people and I feel best represents how I will use the vector in script. As I said previously, the decision is entirely yours and the methods I will describe can be adapted to use the indexed access method if you choose.





Operator Overrides


Contents
  Basic Embedding Concepts
  Executing a String as a Script
  Executing a Script from File
  More on Script Execution
  gmVariable Object
  Calling a Scripted Function
  Creating a host-bound function
  Creating a simple type
  Constructor with Parameters
  Operator Overrides
  SetDot Operator
  Garbage Collection

  Source code
  Printable version
  Discuss this article

The Series
  Language Introduction
  Embedding GameMonkey