Jump to content

good solution for a trigger?


MexSource
 Share

Recommended Posts

//I'm writing here because i have 'no permission' for the Programming section :?

 

Hello,

 

I'm new to Leadwerks and i'm now trying to create triggers with C++

 

I found many examples but either it's for C and in C++ not working or it's old or anything nothing has really worked for me :/

 

So i'm asking is anyone able to give me a good example of a trigger (trigger enter and leave is important) or good ideas?

 

Thanks,

Mex :)

C++ :3

Link to comment
Share on other sites

As far as I'm aware there is no enter/leave functionality built into LE. I've been asking for it on and off for some time now as I agree it's important. You can make this functionality yourself but it's sort of a pain. In C++ LE uses a non class method (normal C method) for calling collisions (which I don't agree with). Look into: http://www.leadwerks.com/werkspace/page/documentation/_/command-reference/entity/entitycollisionhook-r64

 

You have to store lists of entities that have collided already and that collided each frame clearing it out at the start of each frame and only raise some kind of enter/leave yourself. It's a pain and I agree LE should have this functionality already.

Link to comment
Share on other sites

You can set a script with a collision function or use a collision callback. There presently is not a "leave" callback or function though. If the trigger collision type is used, the callback will continually be called each frame as long as the objects are intersecting.

My job is to make tools you love, with the features you want, and performance you can't live without.

Link to comment
Share on other sites

I tried now:

 

virtual void Collision(Entity* collidedEntity, const Vec3& position, const Vec3& normal, float speed);

static void CollisionHook(Entity* entity0, Entity* entity1, float* position, float* normal, float speed);

 

- in App.h

 

and:

 

void Collision(Entity* collidedEntity, const Vec3& position, const Vec3& normal, float speed){

}
void CollisionHook(Entity* entity0, Entity* entity1, float* position, float* normal, float speed){

System::Print("Entity: " + entity0->GetKeyValue("name") + " collided with: " + entity1->GetKeyValue("name"));

}

 

- in App.cpp

 

The error is:

 

1>App.obj : error LNK2001: Nicht aufgelöstes externes Symbol ""public: virtual void __thiscall App::Collision(class Leadwerks::Entity *,class Leadwerks::Vec3 const &,class Leadwerks::Vec3 const &,float)" (?Collision@App@@UAEXPAVEntity@Leadwerks@@ABVVec3@3@1M@Z)".

 

 

1>App.obj : error LNK2001: Nicht aufgelöstes externes Symbol ""public: static void __cdecl App::CollisionHook(class Leadwerks::Entity *,class Leadwerks::Entity *,float *,float *,float)" (?CollisionHook@App@@SAXPAVEntity@Leadwerks@@0PAM1M@Z)".

 

(it's german wink.png hope you can read it. it means 'external unresolved symbol...')

 

i thougt i forgot to link any library but everything is set ok (or is some code wrong?)

 

//Complete files:

 

App.cpp:

 

#include "App.h"
using namespace Leadwerks;
App::App() : window(NULL), context(NULL), world(NULL), camera(NULL) {}
App::~App() { delete world; delete window; }
Vec3 camerarotation;
#if defined (PLATFORM_WINDOWS) || defined (PLATFORM_MACOS)
bool freelookmode=true;
#else
bool freelookmode=false;
#endif
Pivot* player;
float moveSpeed;
float strafeSpeed;
bool sprinting = false;
float jumpAcc;
bool setCrouch = false;
bool isCrouching = false;
float playerHeight;
Vec3 playerMovement;
float sprintSpeed = 1.4;
float crouchSpeed = 0.6;
int pause = 1;
Vec3 mouseposition;
float pausex;
float pausey;
void MapLoader(Entity* entity, Object* extra){
((App*)extra)->LoadMapEntity(entity);
}
Entity* trigger1;
bool App::Start()
{
//Create a window
window = Window::Create("White");

//Create a context
context = Context::Create(window);

//Create a world
world = World::Create();

//Create a camera
camera = Camera::Create();
camera->Move(0,2,0);

//Hide the mouse cursor
window->HideMouse();

std::string mapname = System::GetProperty("map","Maps/start.map");
Map::Load(mapname, MapLoader, (Object*)this);

//Move the mouse to the center of the screen
window->SetMousePosition(context->GetWidth()/2,context->GetHeight()/2);
player = Pivot::Create();
player->SetPhysicsMode(Entity::CharacterPhysics);
player->SetPosition(0,2,0);
player->SetMass(1);

playerHeight = 1.7;
strafeSpeed = 35;
moveSpeed = 35;
jumpAcc = 100;
pausex = 0;
pausey = 0;
mouseposition = window->GetMousePosition();
trigger1->AddHook(Entity::CollisionHook, (void*)CollisionHook);
return true;
}
void App::LoadMapEntity(Entity* e){
if(e->GetKeyValue("name") == "trigger1"){

trigger1 = e;

}
}
void Collision(Entity* collidedEntity, const Vec3& position, const Vec3& normal, float speed){

}
void CollisionHook(Entity* entity0, Entity* entity1, float* position, float* normal, float speed){

System::Print("Entity: " + entity0->GetKeyValue("name") + " collided with: " + entity1->GetKeyValue("name"));
}
bool App::Loop()
{
//Close the window to end the program
if (window->Closed()) return false;

//Press escape to end freelook mode
if (window->KeyHit(Key::Escape))
{

exit(0);

}
.... Everything else has to do with character controllers, movement etc. so it's not really needed

 

App.h:

 

#pragma once
#include "Leadwerks.h"
using namespace Leadwerks;
class App
{
public:
Window* window;
Context* context;
World* world;
Camera* camera;
App();
virtual ~App();
void LoadMapEntity(Entity* e);
virtual bool Start();
virtual bool Loop();
virtual void Collision(Entity* collidedEntity, const Vec3& position, const Vec3& normal, float speed);
static void CollisionHook(Entity* entity0, Entity* entity1, float* position, float* normal, float speed);
};

 

- Mex

 

//Edit:

 

if I add 'App::' in front of both function in App.cpp then i got the error: (translated by google translator:) Access violation when reading at position. I think something with my rguments is wrong but what?

 

:/

Edited by MexMaster

C++ :3

Link to comment
Share on other sites

This is what's a pain about the current process in C++ and it can get complicated.

 

You can just make the CollisionHook() a normal standalone C function and not part of the class. This with it brings issues right? Because now you have scoping issues of what CollisionHook() can see because we all know global variables are evil and to avoid them. Luckily I believe there is a ->SetUserData() and GetUserData() function. This allows us to attach anything to our entities. In our case we would want to attach an object (like App (use 'this' when calling from within App class).

 

Set this up after you've already assigned trigger to e though.

 

trigger->SetUserData((void*)this);

 

Then make sure your virtual collision function is actually part of the App class. So in your source you use App::Collision(etc)

 

Now inside your CollisionHook() you use entity->GetUserData() and cast to App* and check if it's null. If it's not null then you can now call your App's collision virtual function passing in all the parameters. Now you are inside your App class and can access all of it's members.

 

A better way would be to make a base class that has a virtual Collision() and holds an Entity*. Create one of these objects and assign it your 'e' variable. In your collisionhook cast to this base class and call it's virtual Collision(), which if you actually made a child class will call that collision function.

 

Give that a try and if you need I can make an example to show how to do this.

Link to comment
Share on other sites

This is from memory and not tested but it shows you the general idea. You might have to make a couple tweaks to make it work.

 

 

// this is our base class "interface"
// we'll derive any other classes we want to be collidable from this class
class Collidable
{
public:
virtual void Collision(Entity* collidedEntity, const Vec3& position, const Vec3& normal, float speed)=0; // pure virtual so if you derive a class from this you have to implement this in that class
};

// Trigger.h (feel free to break the actual definition of Collision() into it's our source I just put it here to reduce typing
// this is basically a wrapper class for the LE's Entity class to provide us with class level collision callback functionabilty
class Trigger: public Collidable
{
private:
Entity* entity;
public:
Trigger(Entity* e)
{
 entity = e;
}
virtual void Collision(Entity* collidedEntity, const Vec3& position, const Vec3& normal, float speed)
{
 // our game logic on what to do in a collision here
}
Entity* GetEntity() { return entity; }
};

// App.h
#pragma once
#include "Leadwerks.h"
#include "MyGameObject.h"
#include list;
using namespace std;

using namespace Leadwerks;
// declare the normal C collision hook. We'll only ever have this 1 in our entire application because
// the purpose of this function is to just route the collision to the derived Collidable object
void CollisionHook(Entity* entity0, Entity* entity1, float* position, float* normal, float speed);
class App
{
private:
  list<Trigger*> triggers
public:
Window* window;
Context* context;
World* world;
Camera* camera;
App();
virtual ~App();
void LoadMapEntity(Entity* e);
virtual bool Start();
virtual bool Loop();
};

// App.cpp
// have all your other normal stuff but I'm only going to show the new stuff
void CollisionHook(Entity* entity0, Entity* entity1, float* position, float* normal, float speed)
{
  // for each LE entity we attached our MyGameObject which derives from Collidable to we'll get that object back from the entity
  Collidable* c = ((Collidable*)entity0->GetEntityUserData());
  // route the collision to this objects virtual function to be dealt with
  if(c != NULL)
  c->Collide(entity1, position, normal, speed);
}
void App::LoadMapEntity(Entity* e)
{
// I would do something more generic here like maybe say if indexof("trigger") so that it does this for everything you have trigger in the name for
if(e->GetKeyValue("name") == "trigger1")
{
 // make a trigger object passing in the entity to store
 Trigger* trig = new Trigger(e);
 // hook this entity up to the global collision callback
 e->AddHook(Entity::CollisionHook, (void*)CollisionHook);
 // assign the trig object pointer to this entities user data, which is just a generic storage place
 e->SetEntityUserData((void*)trig);
 // add to our trigger list
 triggers.push_back(trig);
 }
}

// please make sure in the editor that you have setup your collisions correctly so it will actually fire the collision callback

Link to comment
Share on other sites

will have a look at it tomorrow wink.png

 

thanks

 

-Mex

 

//edit:

 

added 'System::Print("Entity: " + entity0->GetKeyValue("name") + " collided with: " + entity1->GetKeyValue("name"));' in CollisionHook function

 

but nothing in console and 2 more questions:

 

1:

what do you mean with: // please make sure in the editor that you have setup your collisions correctly so it will actually fire the collision callback

 

2:

what means collision type? ((in level editor)scene -> object ->physics -> collision type)

 

btw: thanks for the good and fast answers smile.png

 

-Mex

C++ :3

Link to comment
Share on other sites

(there's already a list :o :/ )

 

added this:

 

int i = 0;
list<Entity*> entList = world->entities;
while(i < entList.size()){

 System::Print("Entity loaded: " + entList.front()->GetKeyValue("name"));
 entList.pop_front();
 i++;

}

 

I only get ''Entity loaded: " 3 times in console without an name :/

 

i hope its my last question :D

 

-Mex

C++ :3

Link to comment
Share on other sites

I don't think that's how you want to iterate over the list. Try:

 

list<Entity*>::iterator iter;

for(iter = world->entities.begin(); iter != world->entities.end(); ++iter)
{
string name = (*iter)->GetKeyValue("name");
}

 

 

If you want to make it look easier you can use a macro:

 

// top of a header

#define foreach(iter, container) for(iter = container.begin(); iter != container.end(); ++iter)

 

typedef list<Entity*>::iterator EntityIter;

 

and use like:

 

EntityIter iter;

foreach(iter, world->entities)
{
string name = (*iter)->GetKeyValue("name");
}

 

 

If all else fails just attach your project files here and I can take a look to see if anything obvious pops out.

Link to comment
Share on other sites

What are your boxes? If it's csg boxes then you'll need to attach a lua script to them. Even an empty script will work. By doing this you are telling the engine to NOT collapse the csg into the rest of the csg which would make it impossible to get. If they are imported models then you shouldn't have to attach a script.

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

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.

 Share

×
×
  • Create New...