MexSource Posted November 24, 2013 Share Posted November 24, 2013 //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 Quote C++ :3 Link to comment Share on other sites More sharing options...
Rick Posted November 24, 2013 Share Posted November 24, 2013 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. Quote Link to comment Share on other sites More sharing options...
Josh Posted November 24, 2013 Share Posted November 24, 2013 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. Quote 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 More sharing options...
MexSource Posted November 25, 2013 Author Share Posted November 25, 2013 (edited) 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 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 November 25, 2013 by MexMaster Quote C++ :3 Link to comment Share on other sites More sharing options...
Rick Posted November 25, 2013 Share Posted November 25, 2013 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. Quote Link to comment Share on other sites More sharing options...
MexSource Posted November 25, 2013 Author Share Posted November 25, 2013 I tried but was a little too much for my brain now can you please post an example and i will look at it? -Mex Quote C++ :3 Link to comment Share on other sites More sharing options...
Rick Posted November 25, 2013 Share Posted November 25, 2013 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 Quote Link to comment Share on other sites More sharing options...
MexSource Posted November 25, 2013 Author Share Posted November 25, 2013 will have a look at it tomorrow 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 -Mex Quote C++ :3 Link to comment Share on other sites More sharing options...
MexSource Posted November 26, 2013 Author Share Posted November 26, 2013 void MapLoader(Entity* entity, Object* extra){ ((App*)extra)->LoadMapEntity(entity); System::Print("load entity?"); } tried this in my maploader function no single 'load entity?' line in my log :/ Quote C++ :3 Link to comment Share on other sites More sharing options...
Rick Posted November 26, 2013 Share Posted November 26, 2013 Show me how you assigned that callback for loading the map. An alternative method would be to just loop over the world.entities container after you load the map. It stores all the entities that got loaded. Quote Link to comment Share on other sites More sharing options...
MexSource Posted November 26, 2013 Author Share Posted November 26, 2013 (there's already a list :/ ) 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 -Mex Quote C++ :3 Link to comment Share on other sites More sharing options...
Rick Posted November 26, 2013 Share Posted November 26, 2013 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. Quote Link to comment Share on other sites More sharing options...
MexSource Posted November 26, 2013 Author Share Posted November 26, 2013 One simple question: Can i get all boxes from the scene and store them? Quote C++ :3 Link to comment Share on other sites More sharing options...
Rick Posted November 26, 2013 Share Posted November 26, 2013 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. Quote Link to comment Share on other sites More sharing options...
MexSource Posted November 26, 2013 Author Share Posted November 26, 2013 Is there a function or are they displayed as entites? btw: Thank you so much everything now works -Mex Oh wait i could look myself too thanks for everything Quote C++ :3 Link to comment Share on other sites More sharing options...
Rick Posted November 26, 2013 Share Posted November 26, 2013 If you attach an empty lua script they should now just be normal entities as far as I know. Make sure they have names in the editor and you should see them in the world->entities list. 1 Quote Link to comment Share on other sites More sharing options...
MexSource Posted November 26, 2013 Author Share Posted November 26, 2013 Oh you're faster than i can edit my post Thank you (again) Quote C++ :3 Link to comment Share on other sites More sharing options...
Rick Posted November 26, 2013 Share Posted November 26, 2013 Anytime! I love this stuff Quote Link to comment Share on other sites More sharing options...
Recommended Posts
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.