Jump to content
MilitaryG

C++ scripts

Recommended Posts

I've learned how to add / create lua scripts to object what about c++?

 

how should I procide for c++ scripts to be run on objects?

Share this post


Link to post

You can't attach C++ code as script since C++ code needs to be compiled. You could make a system that mimics C++ in to scripts, but in the end you will need to compile C++ code.

Share this post


Link to post

C++ isn't the same idea as Lua when it comes to attaching scripts to entities. Leadwerks doesn't setup C++ like this, although you could simulate it with classes and setting up the callbacks for each entity.

 

[edit]

Beat

 

http://www.leadwerks.com/werkspace/page/documentation/_/command-reference/entity/

 

At the bottom are entity hooks that represent the same Lua entity functions. I'll setup some code to mimic the Lua system and post it here.

Share this post


Link to post

You can't attach C++ code as script since C++ code needs to be compiled. You could make a system that mimics C++ in to scripts, but in the end you will need to compile C++ code.

 

yes I do understand c++ needs to be compiled and all, but still how would I do that?

 

a simple functional code

 

function Script:Start()
   self.entity:SetPosition (10,10,10)
end

 

would do to get me started.

 

truthfully the more I learn lua the less I like it.

Share this post


Link to post

So there is no "official" way to do this but here is a method.

 

1) Create an "interface" class that has a virtual function for each entity script

 

2) Create classes that represent Lua scripts and derive them from the script interface

 

3) Load your map and then loop over all the entities and you'll need a way to identify at run-time which entity should get what script class. In my example I just look for a key value to see if it's equal to a value of the same name as the script class. This still means you have to attach a script in Lua to set this value. These are reasons why I ask for an editor way to add key values to avoid setting lua scripts if not needed but if we still want to set key values for an entity.

 

4) Create an instance of that script, set the entities user data to this script class instance (we use this later in the global hooks), add all the hooks, add to a list so we can store each instance.

 

5) Create global hooks and inside cast the user data to our script interface so we can call the class virtual functions to get the code to enter our class instances so we aren't working in a global space because that's bad.

 

Here is some code that does what the description above says.

 

 

 

// derive your "script" classes from this interface to make it an "entity script"
class IScript
{
protected:
Entity* entity;
public:
IScript(Entity* e) { entity = e; }
virtual void Collision(Entity* entity, float* position, float* normal, float speed);
virtual void Draw();
virtual void DrawEach(Camera* camera);
virtual void PostRender(Camera* camera);
virtual void UpdateMatrix();
virtual void UpdatePhysics();
virtual void UpdateWorld();
};

// example "script" that you would have to make
class DoorScript : public IScript
{
public:
virtual void Collision(Entity* entity, float* position, float* normal, float speed)
{
}

virtual void Update()
{
}
};

// define each global hook function here and the same idea applies to all. cast the user data on the entity
// to IScript and if it's not NULL call that instance method
void CollisionHook(Entity* entity0, Entity* entity1, float* position, float* normal, float speed)
{
IScript* script = (IScript*)entity0->GetUserData();

if(script != NULL)
{
script->Collision(entity1, position, normal, speed);
}
}

void UpdateWorldHook(Entity* entity)
{
IScript* script = (IScript*)entity->GetUserData();

if(script != NULL)
{
script->UpdateWorld();
}
}

// keep a list somewhere in App.h/cpp
list<Script*> entities;

// called in App.cpp Start()
Map::Load("maps\start.map");

// after map is loaded
list<Entity*>::iterator iter;
for(iter = world->entities.begin(); iter != world->entities.end(); ++iter)
{
Entity* e = (*iter);

// note that if you implement the factory pattern here, this will become easier. you could have a list of registered "scripts" and here you just pass the script value to this factory to create an instance of that script. this way all you have to do is create the "script" class and then register it to the factory. I'll look into making a helper for this as well
if(e->GetKeyValue("script") == "DoorScript")
{
IScript* script = new DoorScript();

e->SetUserData((void*)script);
e->AddHook(Entity::Collision, (void*)CollisionHook);
// add all hooks here

entities.push_back(e);
}
}

Share this post


Link to post

LUA is based on the idea that you attach your scripts to an object and give control to the program which then calls those scripts when needed.

C++ is based on the idea that you make the program and not the scripts. This means, you have a lot more control what happens when. You usually have your main-function which gets executed once the program starts and once this function terminates your whole program exits. For the most applications you have something which is called the main-loop. This is a chunk of code that gets executed over and over until you tell it to exit. Usually this consists of your gameplay-mechanics, a world-update (physic) and a render call. Within this loop you can access all the entities and do what you want to them by iterating over the list of entities.

 

I hope you can see the point that this is an entirely different approach. With the approach C++ uses, you have a lot more control over the executional flow and surely you can simulate something like scripting in C++, like Aggror and Rick mentioned but that is not the usual way, it is meant to be.

Share this post


Link to post

like Aggror and Rick mentioned but that is not the usual way, it is meant to be.

 

The usual way is a little misleading as it seems a lot of game engines are leaning this way these days. Unity (although it's C# it's the same idea and closer to C++ than Lua), Unreal is similar. The major difference is that their editors allow the user to assign which C++ code runs on which entity, where in Leadwerks we have to decide a way to do this ourselves and LE doesn't have anything built-in. With the power of setting key values in the editor and if one implements the factory pattern in C++, it would become fairly easy to do this with minimal glue code. Josh could have done this same thing to help us but he doesn't see C++ that way, but that's his preference only.

Share this post


Link to post

So there is no "official" way to do this but here is a method.

 

1) Create an "interface" class that has a virtual function for each entity script

 

2) Create classes that represent Lua scripts and derive them from the script interface

 

3) Load your map and then loop over all the entities and you'll need a way to identify at run-time which entity should get what script class. In my example I just look for a key value to see if it's equal to a value of the same name as the script class. This still means you have to attach a script in Lua to set this value. These are reasons why I ask for an editor way to add key values to avoid setting lua scripts if not needed but if we still want to set key values for an entity.

 

4) Create an instance of that script, set the entities user data to this script class instance (we use this later in the global hooks), add all the hooks, add to a list so we can store each instance.

 

5) Create global hooks and inside cast the user data to our script interface so we can call the class virtual functions to get the code to enter our class instances so we aren't working in a global space because that's bad.

 

Here is some code that does what the description above says.

 

 

 

// derive your "script" classes from this interface to make it an "entity script"
class IScript
{
protected:
Entity* entity;
public:
IScript(Entity* e) { entity = e; }
virtual void Collision(Entity* entity, float* position, float* normal, float speed);
virtual void Draw();
virtual void DrawEach(Camera* camera);
virtual void PostRender(Camera* camera);
virtual void UpdateMatrix();
virtual void UpdatePhysics();
virtual void UpdateWorld();
};

// example "script" that you would have to make
class DoorScript : public IScript
{
public:
virtual void Collision(Entity* entity, float* position, float* normal, float speed)
{
}

virtual void Update()
{
}
};

// define each global hook function here and the same idea applies to all. cast the user data on the entity
// to IScript and if it's not NULL call that instance method
void CollisionHook(Entity* entity0, Entity* entity1, float* position, float* normal, float speed)
{
IScript* script = (IScript*)entity0->GetUserData();

if(script != NULL)
{
script->Collision(entity1, position, normal, speed);
}
}

void UpdateWorldHook(Entity* entity)
{
IScript* script = (IScript*)entity->GetUserData();

if(script != NULL)
{
script->UpdateWorld();
}
}

// keep a list somewhere in App.h/cpp
list<Script*> entities;

// called in App.cpp Start()
Map::Load("maps\start.map");

// after map is loaded
list<Entity*>::iterator iter;
for(iter = world->entities.begin(); iter != world->entities.end(); ++iter)
{
Entity* e = (*iter);

if(e->GetKeyValue("script") == "DoorScript")
{
IScript* script = new DoorScript();

e->SetUserData((void*)script);
e->AddHook(Entity::Collision, (void*)CollisionHook);
// add all hooks here

entities.push_back(e);
}
}

 

ok is there anything I should include?

and can we get a little bit slower I don't really care if it global and very little as I'm just starting.

and something little and simple would do.

 

ok let me show the errors only of the 1. class:

 

4. ‘Entity’ does not name a type
6. expected ‘)’ before ‘*’ token
7. ‘Entity’ has not been declared
9. ‘Camera’ has not been declared
10. ‘Camera’ has not been declared

 

or am I doing something wrong?

Share this post


Link to post

and can we get a little bit slower I don't really care if it global and very little as I'm just starting.

 

Trust me you care. smile.png

 

In your IScript you'll want to include leadwerks.h

 

#pragma once

#include "Leadwerks.h"

using namespace Leadwerks;

class IScript
{
protected:
Entity* entity;
public:
IScript(Entity* e) { entity = e; }
virtual ~IScript() {}
virtual void Collision(Entity* entity, float* position, float* normal, float speed);
virtual void Draw();
virtual void DrawEach(Camera* camera);
virtual void PostRender(Camera* camera);
virtual void UpdateMatrix();
virtual void UpdatePhysics();
virtual void UpdateWorld();
};
};

Share this post


Link to post

Trust me you care. smile.png

I do care about it when I'm starting to build not when I start to learn the beginnings

 

______

I'm doing this with monodevelop

and I managed to include Leadwerks.h by copying whole include that's from Leadwerks install dir in to GAC(The Global Assembly cache)

 

and had to do:

 

#include "Include/Leadwerks.h"

 

BUT 1 problem it seems includes does not have all of it's own includes.

 

Include/OpenGL.h line 28

 

GL/glew.h

 

but GL dir does not exist and so does not glew.h now what?

 

I thought I managed to solve it but I guess I didn't, ...

Share this post


Link to post

I don't use Monodevelop so not sure what needs to be done. I don't think that's supported by LE so that would mean you have to setup all the paths required to get it working. I think codeblocks on Linux & VS on Windows are directly supported and they get automatically setup with the correct paths for Leadwerks to be compiled in C++. You'd be best to look at those projects to see what paths are all needed and then do that for your monodev project.

Share this post


Link to post

I'm doing this with monodevelop

and I managed to include Leadwerks.h by copying whole include that's from Leadwerks install dir in to GAC(The Global Assembly cache)

 

Isn't monodevelop for C# ( completely different thing )

 

Include/OpenGL.h line 28

 

GL/glew.h

 

but GL dir does not exist and so does not glew.h now what?

 

 

<includedfile> vs "includefile"

 

Are you sure your writing in C++ ?

Share this post


Link to post

It looks like you can use Monodev for C++ too from a quick google search, so I assume that's what he's doing.

Share this post


Link to post

I setup Eclipse to work with Leadwerks, I assume you may have to do some similar configuration for Monodev. here are screenshots of the include paths and the libs that I had to use. Obviously your root paths would be different. And also note that you probably don't need the RakNet code.

 

As for the libraries, linux/eclipse does some monkey business with library names, so you will have to use the correct names for your operationg system and monodevelop. There are also a set of default library paths known to the system, so I did not have to specify the path for any of the OpenGL related libs, sound (OpenAl), X11 or Pthreads. Thus, the paths shown above are only for Leadwerks and RakNet.

post-7558-0-50809600-1408461577_thumb.png

post-7558-0-96553600-1408461584.png

post-7558-0-88606400-1408461590.png

Share this post


Link to post

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...