Jump to content

  • Log In with Google      Sign In   
  • Create Account

FREE SOFTWARE GIVEAWAY

We have 4 x Pro Licences (valued at $59 each) for 2d modular animation software Spriter to give away in this Thursday's GDNet Direct email newsletter.


Read more in this forum topic or make sure you're signed up (from the right-hand sidebar on the homepage) and read Thursday's newsletter to get in the running!


- - - - -

Passing a value into a bound class.


Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.

  • You cannot reply to this topic
22 replies to this topic

#1 Fayte   Members   -  Reputation: 139

Like
0Likes
Like

Posted 28 September 2012 - 10:21 PM

Ok here's the deal,

I have an Image class with a draw function like this:
void Img::Draw(SDL_Surface* surface) {
SDL_Rect offset;
offset.x = X;
offset.y = Y;
SDL_BlitSurface(imgSurface, NULL, surface, &offset);
}

I would like to be able to do this in the script:
Image img;

img.x = 0;
img.y = 0;

img.Draw();

But I need to pass the screen Surface to the draw function I don't want my scripters to have to do img.Draw(GetSurface()); I would like this to be handled through the C++ backend code is there a way that everytime img.Draw() is called in script I can pass the SDL_Surface into the C++ method?

If you need this explained better ask away its 12 A.M. here Posted Image might not have explained it the best.

Edited by Fayte, 29 September 2012 - 06:17 AM.


Sponsor:

#2 saejox   Members   -  Reputation: 714

Like
0Likes
Like

Posted 29 September 2012 - 04:43 AM

how about you also have this draw function

void Img::Draw() {
Draw(GetSurface());
}


#3 Fayte   Members   -  Reputation: 139

Like
0Likes
Like

Posted 29 September 2012 - 06:06 AM

how about you also have this draw function

void Img::Draw() {
Draw(GetSurface());
}


Well I thought that at first too, but the thing is GetSurface(); is in my engine class which has an instance that would need to be passed but I don't know if I can pass the instance into the Image class every time a new one is created in Angelscript. Sorry rather new to Angelscript Posted Image

#4 saejox   Members   -  Reputation: 714

Like
0Likes
Like

Posted 29 September 2012 - 07:30 AM

first divide your problem to small problems.

can you do this in your script now?

Image img;
img.x = 0;
img.y = 0;

if not please read this section of the manual
http://www.angelcode.com/angelscript/sdk/docs/manual/doc_register_api_topic.html

Edited by saejox, 29 September 2012 - 07:31 AM.


#5 Fayte   Members   -  Reputation: 139

Like
0Likes
Like

Posted 29 September 2012 - 07:33 AM

first divide your problem to small problems.

can you do this in your script now?

Image img;
img.x = 0;
img.y = 0;

if not please read this section of the manual
http://www.angelcode..._api_topic.html

Yesir :) got that far.

#6 saejox   Members   -  Reputation: 714

Like
0Likes
Like

Posted 29 September 2012 - 08:12 AM

then i just dont understand why you cant create a second function in you Img class.

class Img
{
void Img::Draw(SDL_Surface* surface)
{
SDL_Rect offset;
offset.x = X;
offset.y = Y;
SDL_BlitSurface(imgSurface, NULL, surface, &offset);
}

void Img::Draw()
{
Draw(GetSurface());
}
}

register Img::Draw() to script.
like this
r = engine->RegisterObjectMethod("Image", "void Draw()", asMETHODPR(Image, Draw, (void), void), asCALL_THISCALL);

surely you have access to GetSurface() function in C++. ( or engine->GetSurface() )

#7 Fayte   Members   -  Reputation: 139

Like
0Likes
Like

Posted 29 September 2012 - 11:25 AM

then i just dont understand why you cant create a second function in you Img class.

class Img
{
void Img::Draw(SDL_Surface* surface)
{
SDL_Rect offset;
offset.x = X;
offset.y = Y;
SDL_BlitSurface(imgSurface, NULL, surface, &offset);
}

void Img::Draw()
{
Draw(GetSurface());
}
}

register Img::Draw() to script.
like this

r = engine->RegisterObjectMethod("Image", "void Draw()", asMETHODPR(Image, Draw, (void), void), asCALL_THISCALL);

surely you have access to GetSurface() function in C++. ( or engine->GetSurface() )

You are quite right but I cant pass my engine variable into a c++ class that's not instanced yet can I? Sorry for being newbish like I said I'm new to angelscript. But I don't know how to pass in GetSurface() into my Img class. Without first saying Image img = new Image(engine); on my C++ side.

#8 saejox   Members   -  Reputation: 714

Like
0Likes
Like

Posted 29 September 2012 - 01:18 PM

your problem is pretty much a c++ pointer ownership issue.

So what is this mystical "engine" class would you show me?

#9 Jake Albano   Members   -  Reputation: 649

Like
1Likes
Like

Posted 29 September 2012 - 01:39 PM

Here's how I give my classes access to the main engine class:

When I set up the script engine, I pass the address of my engine class instance in as userdata (a void pointer):

engine = asCreateScriptEngine(ANGELSCRIPT_VERSION);
engine->SetUserData(&myGameEngine);

Then, in my class constructors that need a pointer to the engine (to access window drawing, content management, etc.), I do this:

asIScriptContext* context = NULL;
asIScriptEngine* engine = NULL;
context = asGetActiveContext(); // Get the currently executing angelscript context
if ((context = asGetActiveContext()) != NULL && (engine = context->GetEngine()) != NULL)
{
	// owner is a member pointer to the engine
	owner = reinterpret_cast<Engine*>(engine->GetUserData());
}

Hopefully that helps.

Edited by Jake Albano, 29 September 2012 - 01:41 PM.


#10 Fayte   Members   -  Reputation: 139

Like
0Likes
Like

Posted 29 September 2012 - 03:19 PM

Here's how I give my classes access to the main engine class:

When I set up the script engine, I pass the address of my engine class instance in as userdata (a void pointer):

engine = asCreateScriptEngine(ANGELSCRIPT_VERSION);
engine->SetUserData(&myGameEngine);

Then, in my class constructors that need a pointer to the engine (to access window drawing, content management, etc.), I do this:

asIScriptContext* context = NULL;
asIScriptEngine* engine = NULL;
context = asGetActiveContext(); // Get the currently executing angelscript context
if ((context = asGetActiveContext()) != NULL && (engine = context->GetEngine()) != NULL)
{
	// owner is a member pointer to the engine
	owner = reinterpret_cast<Engine*>(engine->GetUserData());
}

Hopefully that helps.


Gonna try that but here is my engine class

#include "Engine.h"
#include <windows.h> // For the WaitMessage() function.
#include "Scripting/ScriptManager.h"
using namespace Ogre;
/** Default constructor. **/
AffinityEngine::AffinityEngine() {
m_lLastTick   = 0;
m_iWidth   = 1024;
m_iHeight   = 768;
m_czTitle   = 0;
m_pScreen   = 0;
m_iFPSTickCounter = 0;
m_iFPSCounter  = 0;
m_iCurrentFPS  = 0;
m_bMinimized  = false;
}
/** Destructor. **/
AffinityEngine::~AffinityEngine() {
SDL_Quit();
}
/** Sets the height and width of the window.
@param iWidth The width of the window
@param iHeight The height of the window
**/
void AffinityEngine::SetSize(const int& iWidth, const int& iHeight) {
m_iWidth  = iWidth;
m_iHeight = iHeight;
if(m_vmVideoMode == VideoMode_3D) {
  m_pScreen = SDL_SetVideoMode( iWidth, iHeight, 0, SDL_OPENGL );
} else if(m_vmVideoMode == VideoMode_2D) {
  m_pScreen = SDL_SetVideoMode( iWidth, iHeight, 0, SDL_SWSURFACE );
}
}
/** Initialize SDL, the window and the additional data. **/
void AffinityEngine::Init(VideoMode videoMode) {
printf("Engine Initialing.\n");
// Register SDL_Quit to be called at exit; makes sure things are cleaned up when we quit.
atexit( SDL_Quit );
// Initialize SDL's subsystems - in this case, only video.
if ( SDL_Init( SDL_INIT_VIDEO ) < 0 )  {
  fprintf( stderr, "Unable to init SDL: %s\n", SDL_GetError() );
  exit( 1 );
}
SetTitle("Affinity Engine");
m_vmVideoMode = videoMode;
// Attempt to create a window with the specified height and width.
SetSize(m_iWidth, m_iHeight);
if(videoMode == VideoMode_3D){
  m_rRoot = new Root("plugins_d.cfg", "ogre.cfg", "AffinityEngine.log");
  m_rRoot->restoreConfig();
  m_rRoot->initialise(false);
  NameValuePairList misc;
  #ifdef _WIN32
	SDL_SysWMinfo wmInfo;
	SDL_VERSION(&wmInfo.version);
	SDL_GetWMInfo(&wmInfo);

	size_t winHandle = reinterpret_cast<size_t>(wmInfo.window);
	size_t winGlContext = reinterpret_cast<size_t>(wmInfo.hglrc);

	misc["externalWindowHandle"] = StringConverter::toString(winHandle);
	misc["externalGLContext"] = StringConverter::toString(winGlContext);
   #else
	misc["currentGLContext"] = String("True");
   #endif
	  m_rwRenderWindow = m_rRoot->createRenderWindow("MainRenderWindow", 1024, 768, false, &misc);
   m_rwRenderWindow->setVisible(true);
   printf("Initialized 3D Rendering.\n");
} else {
  printf("Initialized 2D Rendering.\n");
}
// If we fail, return error.
if ( m_pScreen == NULL ) {
  fprintf( stderr, "Unable to set up video: %s\n", SDL_GetError() );
  exit( 1 );
}
printf("Engine Initialized.\n");
AdditionalInit();
}
/** The main loop. **/
void AffinityEngine::Start() {
printf("Engine Started\n");
m_lLastTick = SDL_GetTicks();
m_bQuit = false;
m_smScriptManager = new ScriptManager("../Data/Scripts", this);
m_smScriptManager->Init();
// Main loop: loop forever.
while ( !m_bQuit ) {
  // Handle mouse and keyboard input
  HandleInput();
  if ( m_bMinimized ) {
   // Release some system resources if the app. is minimized.
   WaitMessage(); // pause the application until focus in regained
  } else {
   // Do some thinking
   DoLogic();
   // Render stuff
   DoRender();
  }
}
End();
}
/** Handles all controller inputs.
@remark This function is called once per frame.
**/
void AffinityEngine::HandleInput() {
// Poll for events, and handle the ones we care about.
SDL_Event event;
while ( SDL_PollEvent(&event) ) {
  switch (event.type) {
  case SDL_KEYDOWN:
   // If escape is pressed set the Quit-flag
   /*if (event.key.keysym.sym == SDLK_ESCAPE){
	m_bQuit = true;
	break;
   }*/
   m_smScriptManager->e_imInputMgr->InjectKeyboard(event.key.keysym.sym, InputState::Down);
   KeyDown(event.key.keysym.sym);
   break;
  case SDL_KEYUP:
   m_smScriptManager->e_imInputMgr->InjectKeyboard(event.key.keysym.sym, InputState::Up);
   KeyUp(event.key.keysym.sym);
   break;
  case SDL_QUIT:
   m_bQuit = true;
   break;
  case SDL_MOUSEMOTION:
   m_smScriptManager->e_imInputMgr->InjectMouse(event.motion.x, event.motion.y, event.button.button);
   MouseMoved(event.button.button, event.motion.x, event.motion.y, event.motion.xrel, event.motion.yrel);
   break;
  case SDL_MOUSEBUTTONUP:
   m_smScriptManager->e_imInputMgr->InjectMouse(event.motion.x, event.motion.y, event.button.button);
   MouseButtonUp(event.button.button, event.motion.x, event.motion.y, event.motion.xrel, event.motion.yrel);
   break;
  case SDL_MOUSEBUTTONDOWN:
   m_smScriptManager->e_imInputMgr->InjectMouse(event.motion.x, event.motion.y, event.button.button);
   MouseButtonDown(event.button.button, event.motion.x, event.motion.y, event.motion.xrel, event.motion.yrel);
   break;
  case SDL_ACTIVEEVENT:
   if ( event.active.state & SDL_APPACTIVE ) {
	if ( event.active.gain ) {
	 m_bMinimized = false;
	 WindowActive();
	} else {
	 m_bMinimized = true;
	 WindowInactive();
	}
   }
   break;
  } // switch
} // while (handling input)
}
/** Handles the updating routine. **/
void AffinityEngine::DoLogic() {
long iElapsedTicks = SDL_GetTicks() - m_lLastTick;
m_lLastTick = SDL_GetTicks();
m_smScriptManager->ParseScripts();
Logic( iElapsedTicks );
m_smScriptManager->Update();
m_iFPSTickCounter += iElapsedTicks;
}
/** Handles the rendering and FPS calculations. **/
void AffinityEngine::DoRender() {
++m_iFPSCounter;
if ( m_iFPSTickCounter >= 1000 ) {
  m_iCurrentFPS = m_iFPSCounter;
  m_iFPSCounter = 0;
  m_iFPSTickCounter = 0;
}
if(m_vmVideoMode == VideoMode_2D) {
  SDL_FillRect( m_pScreen, 0, SDL_MapRGB( m_pScreen->format, 0, 0, 0 ) );
  // Lock surface if needed
  if ( SDL_MUSTLOCK( m_pScreen ) )
   if ( SDL_LockSurface( m_pScreen ) < 0 )
	return;
  Render( GetSurface() );
  m_smScriptManager->Draw();
  // Unlock if needed
  if ( SDL_MUSTLOCK( m_pScreen ) )
   SDL_UnlockSurface( m_pScreen );
  // Tell SDL to update the whole gScreen
  SDL_Flip( m_pScreen );
}else{
  m_rRoot->renderOneFrame();
  SDL_GL_SwapBuffers();
}
}
/** Sets the title of the window
@param czTitle A character array that contains the text that the window title should be set to.
**/
void AffinityEngine::SetTitle(std::string czTitle) {
m_czTitle = czTitle.c_str();
SDL_WM_SetCaption( czTitle.c_str(), 0 );
}
/** Retrieve the title of the application window.
@return The last set windows title as a character array.
@remark Only the last set title is returned. If another application has changed the window title, then that title won't be returned.
**/
const char* AffinityEngine::GetTitle() {
return m_czTitle;
}
/** Retrieve the main screen surface.
@return A pointer to the SDL_Surface surface
@remark The surface is not validated internally.
**/
SDL_Surface* AffinityEngine::GetSurface() {
return m_pScreen;
}
/** Get the current FPS.
@return The number of drawn frames in the last second.
@remark The FPS is only updated once each second.
**/
int AffinityEngine::GetFPS() {
return m_iCurrentFPS;
}
void AffinityEngine::Shutdown() {
m_bQuit = true;
}
ScriptManager* AffinityEngine::GetScriptManager() {
return m_smScriptManager;
}

Ok while making those changes I got this error:

Engine Initialing.
Initialized 2D Rendering.
Engine Initialized.
Engine Started
(0, 0) : ERR  : Failed in call to function 'RegisterObjectBehaviour' with 'Imag
e' and 'ref@ f()' (Code: -10)

from this line

r = e_seScriptEngine->RegisterObjectBehaviour("Image", asBEHAVE_FACTORY, "ref@ f()", asFUNCTION(Img_Factory), asCALL_CDECL); assert(r >= 0);

and here is the function:

static Img* Img_Factory() {
return new Img();
}

Edited by Fayte, 29 September 2012 - 04:27 PM.


#11 Fayte   Members   -  Reputation: 139

Like
0Likes
Like

Posted 29 September 2012 - 04:33 PM


Here's how I give my classes access to the main engine class:

When I set up the script engine, I pass the address of my engine class instance in as userdata (a void pointer):

engine = asCreateScriptEngine(ANGELSCRIPT_VERSION);
engine->SetUserData(&myGameEngine);

Then, in my class constructors that need a pointer to the engine (to access window drawing, content management, etc.), I do this:

asIScriptContext* context = NULL;
asIScriptEngine* engine = NULL;
context = asGetActiveContext(); // Get the currently executing angelscript context
if ((context = asGetActiveContext()) != NULL && (engine = context->GetEngine()) != NULL)
{
	// owner is a member pointer to the engine
	owner = reinterpret_cast<Engine*>(engine->GetUserData());
}

Hopefully that helps.


Gonna try that but here is my engine class

#include "Engine.h"
#include <windows.h> // For the WaitMessage() function.
#include "Scripting/ScriptManager.h"
using namespace Ogre;
/** Default constructor. **/
AffinityEngine::AffinityEngine() {
m_lLastTick   = 0;
m_iWidth   = 1024;
m_iHeight   = 768;
m_czTitle   = 0;
m_pScreen   = 0;
m_iFPSTickCounter = 0;
m_iFPSCounter  = 0;
m_iCurrentFPS  = 0;
m_bMinimized  = false;
}
/** Destructor. **/
AffinityEngine::~AffinityEngine() {
SDL_Quit();
}
/** Sets the height and width of the window.
@param iWidth The width of the window
@param iHeight The height of the window
**/
void AffinityEngine::SetSize(const int& iWidth, const int& iHeight) {
m_iWidth  = iWidth;
m_iHeight = iHeight;
if(m_vmVideoMode == VideoMode_3D) {
  m_pScreen = SDL_SetVideoMode( iWidth, iHeight, 0, SDL_OPENGL );
} else if(m_vmVideoMode == VideoMode_2D) {
  m_pScreen = SDL_SetVideoMode( iWidth, iHeight, 0, SDL_SWSURFACE );
}
}
/** Initialize SDL, the window and the additional data. **/
void AffinityEngine::Init(VideoMode videoMode) {
printf("Engine Initialing.\n");
// Register SDL_Quit to be called at exit; makes sure things are cleaned up when we quit.
atexit( SDL_Quit );
// Initialize SDL's subsystems - in this case, only video.
if ( SDL_Init( SDL_INIT_VIDEO ) < 0 )  {
  fprintf( stderr, "Unable to init SDL: %s\n", SDL_GetError() );
  exit( 1 );
}
SetTitle("Affinity Engine");
m_vmVideoMode = videoMode;
// Attempt to create a window with the specified height and width.
SetSize(m_iWidth, m_iHeight);
if(videoMode == VideoMode_3D){
  m_rRoot = new Root("plugins_d.cfg", "ogre.cfg", "AffinityEngine.log");
  m_rRoot->restoreConfig();
  m_rRoot->initialise(false);
  NameValuePairList misc;
  #ifdef _WIN32
	SDL_SysWMinfo wmInfo;
	SDL_VERSION(&wmInfo.version);
	SDL_GetWMInfo(&wmInfo);

	size_t winHandle = reinterpret_cast<size_t>(wmInfo.window);
	size_t winGlContext = reinterpret_cast<size_t>(wmInfo.hglrc);

	misc["externalWindowHandle"] = StringConverter::toString(winHandle);
	misc["externalGLContext"] = StringConverter::toString(winGlContext);
   #else
	misc["currentGLContext"] = String("True");
   #endif
	  m_rwRenderWindow = m_rRoot->createRenderWindow("MainRenderWindow", 1024, 768, false, &misc);
   m_rwRenderWindow->setVisible(true);
   printf("Initialized 3D Rendering.\n");
} else {
  printf("Initialized 2D Rendering.\n");
}
// If we fail, return error.
if ( m_pScreen == NULL ) {
  fprintf( stderr, "Unable to set up video: %s\n", SDL_GetError() );
  exit( 1 );
}
printf("Engine Initialized.\n");
AdditionalInit();
}
/** The main loop. **/
void AffinityEngine::Start() {
printf("Engine Started\n");
m_lLastTick = SDL_GetTicks();
m_bQuit = false;
m_smScriptManager = new ScriptManager("../Data/Scripts", this);
m_smScriptManager->Init();
// Main loop: loop forever.
while ( !m_bQuit ) {
  // Handle mouse and keyboard input
  HandleInput();
  if ( m_bMinimized ) {
   // Release some system resources if the app. is minimized.
   WaitMessage(); // pause the application until focus in regained
  } else {
   // Do some thinking
   DoLogic();
   // Render stuff
   DoRender();
  }
}
End();
}
/** Handles all controller inputs.
@remark This function is called once per frame.
**/
void AffinityEngine::HandleInput() {
// Poll for events, and handle the ones we care about.
SDL_Event event;
while ( SDL_PollEvent(&event) ) {
  switch (event.type) {
  case SDL_KEYDOWN:
   // If escape is pressed set the Quit-flag
   /*if (event.key.keysym.sym == SDLK_ESCAPE){
	m_bQuit = true;
	break;
   }*/
   m_smScriptManager->e_imInputMgr->InjectKeyboard(event.key.keysym.sym, InputState::Down);
   KeyDown(event.key.keysym.sym);
   break;
  case SDL_KEYUP:
   m_smScriptManager->e_imInputMgr->InjectKeyboard(event.key.keysym.sym, InputState::Up);
   KeyUp(event.key.keysym.sym);
   break;
  case SDL_QUIT:
   m_bQuit = true;
   break;
  case SDL_MOUSEMOTION:
   m_smScriptManager->e_imInputMgr->InjectMouse(event.motion.x, event.motion.y, event.button.button);
   MouseMoved(event.button.button, event.motion.x, event.motion.y, event.motion.xrel, event.motion.yrel);
   break;
  case SDL_MOUSEBUTTONUP:
   m_smScriptManager->e_imInputMgr->InjectMouse(event.motion.x, event.motion.y, event.button.button);
   MouseButtonUp(event.button.button, event.motion.x, event.motion.y, event.motion.xrel, event.motion.yrel);
   break;
  case SDL_MOUSEBUTTONDOWN:
   m_smScriptManager->e_imInputMgr->InjectMouse(event.motion.x, event.motion.y, event.button.button);
   MouseButtonDown(event.button.button, event.motion.x, event.motion.y, event.motion.xrel, event.motion.yrel);
   break;
  case SDL_ACTIVEEVENT:
   if ( event.active.state & SDL_APPACTIVE ) {
	if ( event.active.gain ) {
	 m_bMinimized = false;
	 WindowActive();
	} else {
	 m_bMinimized = true;
	 WindowInactive();
	}
   }
   break;
  } // switch
} // while (handling input)
}
/** Handles the updating routine. **/
void AffinityEngine::DoLogic() {
long iElapsedTicks = SDL_GetTicks() - m_lLastTick;
m_lLastTick = SDL_GetTicks();
m_smScriptManager->ParseScripts();
Logic( iElapsedTicks );
m_smScriptManager->Update();
m_iFPSTickCounter += iElapsedTicks;
}
/** Handles the rendering and FPS calculations. **/
void AffinityEngine::DoRender() {
++m_iFPSCounter;
if ( m_iFPSTickCounter >= 1000 ) {
  m_iCurrentFPS = m_iFPSCounter;
  m_iFPSCounter = 0;
  m_iFPSTickCounter = 0;
}
if(m_vmVideoMode == VideoMode_2D) {
  SDL_FillRect( m_pScreen, 0, SDL_MapRGB( m_pScreen->format, 0, 0, 0 ) );
  // Lock surface if needed
  if ( SDL_MUSTLOCK( m_pScreen ) )
   if ( SDL_LockSurface( m_pScreen ) < 0 )
	return;
  Render( GetSurface() );
  m_smScriptManager->Draw();
  // Unlock if needed
  if ( SDL_MUSTLOCK( m_pScreen ) )
   SDL_UnlockSurface( m_pScreen );
  // Tell SDL to update the whole gScreen
  SDL_Flip( m_pScreen );
}else{
  m_rRoot->renderOneFrame();
  SDL_GL_SwapBuffers();
}
}
/** Sets the title of the window
@param czTitle A character array that contains the text that the window title should be set to.
**/
void AffinityEngine::SetTitle(std::string czTitle) {
m_czTitle = czTitle.c_str();
SDL_WM_SetCaption( czTitle.c_str(), 0 );
}
/** Retrieve the title of the application window.
@return The last set windows title as a character array.
@remark Only the last set title is returned. If another application has changed the window title, then that title won't be returned.
**/
const char* AffinityEngine::GetTitle() {
return m_czTitle;
}
/** Retrieve the main screen surface.
@return A pointer to the SDL_Surface surface
@remark The surface is not validated internally.
**/
SDL_Surface* AffinityEngine::GetSurface() {
return m_pScreen;
}
/** Get the current FPS.
@return The number of drawn frames in the last second.
@remark The FPS is only updated once each second.
**/
int AffinityEngine::GetFPS() {
return m_iCurrentFPS;
}
void AffinityEngine::Shutdown() {
m_bQuit = true;
}
ScriptManager* AffinityEngine::GetScriptManager() {
return m_smScriptManager;
}

Ok while making those changes I got this error:

Engine Initialing.
Initialized 2D Rendering.
Engine Initialized.
Engine Started
(0, 0) : ERR  : Failed in call to function 'RegisterObjectBehaviour' with 'Imag
e' and 'ref@ f()' (Code: -10)

from this line

r = e_seScriptEngine->RegisterObjectBehaviour("Image", asBEHAVE_FACTORY, "ref@ f()", asFUNCTION(Img_Factory), asCALL_CDECL); assert(r >= 0);

and here is the function:

static Img* Img_Factory() {
return new Img();
}


Once I get my game running again I can test to see if the changes worked. (Sorry for the double post meant to edit >.<)

Edited by Fayte, 29 September 2012 - 04:33 PM.


#12 Jake Albano   Members   -  Reputation: 649

Like
1Likes
Like

Posted 29 September 2012 - 04:36 PM

You'll want to do it like this:

r = e_seScriptEngine->RegisterObjectBehaviour("Image", asBEHAVE_FACTORY, "Image@ f()", asFUNCTION(Img_Factory), asCALL_CDECL); assert(r >= 0);

Using "image" instead of "ref".

#13 saejox   Members   -  Reputation: 714

Like
1Likes
Like

Posted 29 September 2012 - 05:20 PM

i might be missing the point here but wouldn't singleton engine class solve this?

class Engine
{
	 private:
	 Engine::Engine();
	 static Engine *instance;
	 public:
	 static Engine *get()
	 {
  	 if (!instance)
   	 instance = new Engine;
	   return instance;
	 }
	 void init()
	 {
	 	 // Do init.
	 }
}
Engine* Engine::instance = 0;

they you will have access to it anywhere anytime.

#14 Jake Albano   Members   -  Reputation: 649

Like
0Likes
Like

Posted 29 September 2012 - 05:23 PM

I avoid singletons since they're essentially global variables, but yes, that would be one way to solve the problem.

#15 saejox   Members   -  Reputation: 714

Like
-2Likes
Like

Posted 29 September 2012 - 05:42 PM

a very wrong misconception.
singletons are definitely not global variables. you cant control access with global variables.

the way you do it is more akin to a global variable.
it makes engine to accessible and volatile to every piece of code in your program.

what if some evil soul decides to call asGetActiveContext()->GetEngine()->SetUserdata(null);
angry employee maybe?

#16 Jake Albano   Members   -  Reputation: 649

Like
0Likes
Like

Posted 29 September 2012 - 06:17 PM

I strongly suggest you read this article: http://gameprogrammi.../singleton.html Singletons have a lot of attractive features at first glance, but they're really a bad idea in the long run.

I do understand the difference between a plain global and the singleton pattern, but functionally they serve the same purpose of providing global access to the same variable anywhere in your program. Additionally, my engine is designed so I could have multiple instances of it running in the same program. Using a singleton for the engine would prevent me from doing this.

As far as malicious use goes (although I'm not sure why that would ever be a concern), your singleton example above is just as susceptible:

delete Engine::get();

To each his own. Let's not go any further off topic. :)

#17 Fayte   Members   -  Reputation: 139

Like
0Likes
Like

Posted 29 September 2012 - 06:34 PM

i might be missing the point here but wouldn't singleton engine class solve this?

class Engine
{
	 private:
	 Engine::Engine();
	 static Engine *instance;
	 public:
	 static Engine *get()
	 {
	   if (!instance)
   	 instance = new Engine;
	   return instance;
	 }
	 void init()
	 {
	 	 // Do init.
	 }
}
Engine* Engine::instance = 0;

they you will have access to it anywhere anytime.


Ok the singleton thing to me is a relatively new concept I can do it in C# but C++ eludes me.

Here is the game class that inherits from the engine class and I added your singleton code to it:

#ifndef GAME_H
#define GAME_H
#include "Engine\Engine.h"
#include <stdlib.h>
#include <stdio.h>
#include <fcntl.h>
#include <io.h>
#include <iostream>
#include <string>
#include <iostream>
/*
#ifdef _MSC_VER
#include <crtdbg.h>  // debugging routines
#endif
*/
using namespace std;

class Game : public AffinityEngine {
private:
static Game *instance;
public:
Game();
~Game();
void AdditionalInit ();
void Logic   (const int& iElapsedTime );
void Render   (SDL_Surface* pDestSurface );

void KeyUp	   (const int& iKeyEnum);
void KeyDown	 (const int& iKeyEnum);

void MouseMoved	 (const int& iButton, const int& iX, const int& iY, const int& iRelX, const int& iRelY);

void MouseButtonUp  (const int& iButton, const int& iX, const int& iY, const int& iRelX, const int& iRelY);

void MouseButtonDown(const int& iButton, const int& iX, const int& iY, const int& iRelX, const int& iRelY);

void WindowInactive ();
void WindowActive ();

void End   ();
void Setup   ();
static Game *get() {
		 if (!instance){
   instance = new Game;
   }
		 return instance;
	}
};
Game::Game() {
instance = this;
}
Game::~Game() {
//delete m_smScriptManager;
}
void Game::Setup() {
}
#endif

when I compile I get this:

1>ScriptManager.obj : error LNK2005: "public: void __thiscall Game::Setup(void)" (?Setup@Game@@QAEXXZ) already defined in Engine.obj
1>ScriptManager.obj : error LNK2005: "public: virtual __thiscall Game::~Game(void)" (??1Game@@UAE@XZ) already defined in Engine.obj
1>ScriptManager.obj : error LNK2005: "public: __thiscall Game::Game(void)" (??0Game@@QAE@XZ) already defined in Engine.obj
1>Img.obj : error LNK2005: "public: void __thiscall Game::Setup(void)" (?Setup@Game@@QAEXXZ) already defined in Engine.obj
1>Img.obj : error LNK2005: "public: virtual __thiscall Game::~Game(void)" (??1Game@@UAE@XZ) already defined in Engine.obj
1>Img.obj : error LNK2005: "public: __thiscall Game::Game(void)" (??0Game@@QAE@XZ) already defined in Engine.obj
1>main.obj : error LNK2005: "public: void __thiscall Game::Setup(void)" (?Setup@Game@@QAEXXZ) already defined in Engine.obj
1>main.obj : error LNK2005: "public: virtual __thiscall Game::~Game(void)" (??1Game@@UAE@XZ) already defined in Engine.obj
1>main.obj : error LNK2005: "public: __thiscall Game::Game(void)" (??0Game@@QAE@XZ) already defined in Engine.obj
1>	 Creating library C:\Users\Xios\Documents\Visual Studio 2010\Projects\AffinityEngine-Oblivion\Debug\AffinityEngine-Oblivion.lib and object C:\Users\Xios\Documents\Visual Studio 2010\Projects\AffinityEngine-Oblivion\Debug\AffinityEngine-Oblivion.exp
1>MSVCRTD.lib(cinitexe.obj) : warning LNK4098: defaultlib 'msvcrt.lib' conflicts with use of other libs; use /NODEFAULTLIB:library
1>Engine.obj : error LNK2001: unresolved external symbol "private: static class Game * Game::instance" (?instance@Game@@0PAV1@A)

turns out it was because I had a couple of my functions implemented in the .h file now I only have:

Game.obj : error LNK2001: unresolved external symbol "private: static class Game * Game::instance" (?instance@Game@@0PAV1@A)

That was fixed by making a Game.cpp and putting this in it.

Game* Game::instance = 0;
Game::Game() {
Game::instance = this;
}

just helping others with the same issue later.

Now I don't get any errors from the program or the script but my image doesn't show up. If I had to wager a guess it's that the image class still is not getting the right engine instance regardless of the singleton. Is my script running on a separate thread? Is that the issue because I have not specifically tried. I would have to assume this is correct because when I try this:

image = new Img();
image->X = 0;
image->Y = 0;
image->fileName = "AyphixPresents.png";

inside of C++ it works great. Which is essentially the same thing my script does when I do this:

class GameManager {
	string GameTitle;
	bool quit;
	Image@ img;
	GameManager(string gameTitle) {
		quit = false;
		GameTitle = GameTitle;
		Application.SetTitle(gameTitle);
		@img = Image();
		img.X = 0;
		img.Y = 0;
		img.Filename = "../Data/Images/AyphixPresents.png";
	}
	void Update() {
		if(Input.GetKeyDown(Keycode::Escape)){
			Application.Exit();
		}
		//img.draw();
	}
}


Problem solved :)

r = e_seScriptEngine->RegisterObjectProperty("Image", "int Y", asOFFSET(Img, Y)); assert(r >= 0);
asOFFSET(Img, Y) was asOFFSET(Img, X) when I changed it, it worked. Thanks to both of you for the help!

Edited by Fayte, 29 September 2012 - 08:06 PM.


#18 Fayte   Members   -  Reputation: 139

Like
0Likes
Like

Posted 29 September 2012 - 09:44 PM

Ok one last question before I call this success :)

I want to be able to pass my x y and filename into my constructor;

But my factory looks like this with no clue what angelscript is passing into the constructor.

static Img* Img_Factory() {
return new Img();
}

Does it really matter what my factory has? Will I will be able to register a constructor with those in it?

#19 Jake Albano   Members   -  Reputation: 649

Like
1Likes
Like

Posted 30 September 2012 - 07:34 AM

Yes, this is possible. You can register multiple constructors for a class:

You'll need separate factory functions:
static Img* Img_Factory() {
return new Img();
}

static Img* Img_Factory(int x, int y) {
return new Img(int x, int y);
}

And register them this way:
r = e_seScriptEngine->RegisterObjectBehaviour("Image", asBEHAVE_FACTORY, "Image@ f()", asFUNCTION(Img_Factory), asCALL_CDECL); assert(r >= 0);
r = e_seScriptEngine->RegisterObjectBehaviour("Image", asBEHAVE_FACTORY, "Image@ f(int, int)", asFUNCTIONPR(Img_Factory, (int, int), Img*), asCALL_CDECL); assert(r >= 0);

asFUNCTIONPR lets you distinguish between overloaded functions.
http://www.angelcode.com/angelscript/sdk/docs/manual/doc_register_func.html

#20 Fayte   Members   -  Reputation: 139

Like
0Likes
Like

Posted 30 September 2012 - 07:57 AM

Yes, this is possible. You can register multiple constructors for a class:

You'll need separate factory functions:

static Img* Img_Factory() {
return new Img();
}

static Img* Img_Factory(int x, int y) {
return new Img(int x, int y);
}

And register them this way:
r = e_seScriptEngine->RegisterObjectBehaviour("Image", asBEHAVE_FACTORY, "Image@ f()", asFUNCTION(Img_Factory), asCALL_CDECL); assert(r >= 0);
r = e_seScriptEngine->RegisterObjectBehaviour("Image", asBEHAVE_FACTORY, "Image@ f(int, int)", asFUNCTIONPR(Img_Factory, (int, int), Img*), asCALL_CDECL); assert(r >= 0);

asFUNCTIONPR lets you distinguish between overloaded functions.
http://www.angelcode...ister_func.html


:) Thanks a ton for all the help.




Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.



PARTNERS