Introduction to GameMonkey Script Part 2
Embedding GameMonkey
Operator OverridesIf you have ever overridden a class operator in C++ you will know how powerful this feature is - operator overriding allows you to specify a function to control the behaviour of a type when certain script operators are used. The operators you can override for a type in GM Script are:
In this simple example I will only override the dot operators to provide access to the simulated member access method of the Vector data. Operator overriding follows the same structure for each operator so it is simple to adapt my example to use the index operators. Operator functions all have the same signature: void GM_CDECL operator_func(gmThread * a_thread, gmVariable * a_operands);
GetDot OperatorThe operands passed to the operators vary on the type of operator. For the GetDot operator the operands are as follows:
The following code details the GetDot function we will be using: void GM_CDECL OpGetDot(gmThread * a_thread, gmVariable * a_operands) { GM_ASSERT(a_operands[0].m_type == Type); Vector* thisVec = static_cast<Vector*>(static_cast<gmUserObject*>(GM_OBJECT(a_operands[0].m_value.m_ref))->m_user); GM_ASSERT(a_operands[1].m_type == GM_STRING); gmStringObject* stringObj = static_cast<gmStringObject*>(GM_OBJECT(a_operands[1].m_value.m_ref)); const char* propName = stringObj->GetString(); // Resolve the member name if(::stricmp(propName, "x") == 0) { a_operands[0].SetFloat(thisVec->x); } else if(::stricmp(propName, "y") == 0) { a_operands[0].SetFloat(thisVec->y); } else if(::stricmp(propName, "z") == 0) { a_operands[0].SetFloat(thisVec->z); } else { a_operands[0].Nullify(); } }
The process is simple; first we check that the type of the variable being operated on matches that of the newly bound Vector type. Afterwards, the string name of the member is retrieved and checked against the members we wish to export. Confusingly operand zero is also the return variable, so it must be set with the relevant value from the bound class. This is as simple as copying the value from the 'real' member in our class to the variable represented by operand zero. If there is a problem, you should nullify the return variable, which returns null to GameMonkey Script. With the Get Dot operator function created, it's time to add its registration to the BindLib function we looked as earlier. This is as simple as calling the RegisterTypeOperator on the newly bound type, passing the relevant operator and function handler as parameters: a_machine->RegisterTypeOperator(Type, O_GETDOT, NULL, OpGetDot); |