Schoppy0384 Posted February 2, 2014 Share Posted February 2, 2014 Hi, the Tank in the Photo has a - SetPhysicsMode(Leadwerks::Entity::CharacterPhysics)-. With -tankPivot->GoToPoint(moveTarget,speed,acceleration)- I give the tank new coordinates and the tank drive to this new position. The problem is that the tank is not rotating on the y coordinates. The physics does not apply heir anyway. Is there a way to correct them? Thanks Quote Link to comment Share on other sites More sharing options...
Rick Posted February 2, 2014 Share Posted February 2, 2014 I think you mean the x axis. If you expect it to rotate upward/downward that's not the y axis but the x axis. Character controllers only rotate on the y axis (turns left/right). You'll either have to manually rotate the model yourself up/down based on some factor or use a different physics method to move your tank around. Quote Link to comment Share on other sites More sharing options...
YouGroove Posted February 2, 2014 Share Posted February 2, 2014 Better use oriented bouding box for collision indeed (actually LE3 don't have car physics) ,and call functions like PhysicsSetPosition, PhysicsSetRotation, or AddForce, AddTorque. Character controller as it's name says it , it's for standard character based games, not vehicles. Quote Stop toying and make games Link to comment Share on other sites More sharing options...
Schoppy0384 Posted February 3, 2014 Author Share Posted February 3, 2014 Thanks for the answers. Ok, my Idea is to parent 2 boxes, one on the Frontside and one on the backside from the tank. Then I can check the height difference between the two boxes and calculate the Rotation Angel. What I need is a Pick Y Command on the box to check the Y Coordinate. Which command is the best for this? And second the Rotation Angel, i think ATAN2 is right? Quote Link to comment Share on other sites More sharing options...
DudeAwesome Posted February 3, 2014 Share Posted February 3, 2014 you dont need 2 boxes. 1 box should be enough. the groundcollision and newton do the calculation for you Quote It doesn´t work... why? mhmmm It works... why? Link to comment Share on other sites More sharing options...
Schoppy0384 Posted February 3, 2014 Author Share Posted February 3, 2014 The problem is that I used a Character Controller. See Ricks answer. "Character controllers only rotate on the y axis (turns left/right)." With a Character Controller the Physics are not working. Quote Link to comment Share on other sites More sharing options...
Rick Posted February 3, 2014 Share Posted February 3, 2014 I think what dude is saying is to just make 1 physics box/shape that is your tanks body. When you apply force to it, it'll then move the way you want. It'll go up hills and rotate along the x to pitch up or down. Just play with the friction, mass, and where you apply the force and you should be able to move the physics box (tank) around and get the effect you want. Quote Link to comment Share on other sites More sharing options...
Schoppy0384 Posted February 3, 2014 Author Share Posted February 3, 2014 Ok, but with this way i cannot use the GotoPoint Command. Quote Link to comment Share on other sites More sharing options...
YouGroove Posted February 3, 2014 Share Posted February 3, 2014 Why do you need GotoPoint ? Yes GotoPoint is character controller only. As you can now control physic Box with keys and PhysicsAddForce for example. Quote Stop toying and make games Link to comment Share on other sites More sharing options...
Schoppy0384 Posted February 3, 2014 Author Share Posted February 3, 2014 Oh sorry, I am working on an little Tank RTS Game. I use the Navmesh to navigate the Tanks on the map. With a Character Controller it works very good. But the problem are hills. The Tanks rotate only on the y axis (Character Controller). What i need is a rotation upward/downward for the tanks, see first picture. Quote Link to comment Share on other sites More sharing options...
YouGroove Posted February 3, 2014 Share Posted February 3, 2014 So you really need Navmesh, so character controller. Some solution perhaps : 1) Use some invisible model with character controller : "virtual tank" using navmesh 2) Use Real tank model with simple box physics and uses Physics command to each loop follow the position of your "virtual tank" Quote Stop toying and make games Link to comment Share on other sites More sharing options...
Rick Posted February 3, 2014 Share Posted February 3, 2014 It's a bummer that the path that is found isn't exposed to Lua. I know in 3.0 C++ you get actually get the path points and just use those without having to do anything with the character controller. That would be really handy and maybe make a suggestion that Josh expose this to Lua? 1 Quote Link to comment Share on other sites More sharing options...
beo6 Posted February 4, 2014 Share Posted February 4, 2014 I agree to rick. It would be nice if the path would be accessible. But another idea: Can't we use PickInfo.triangle and entity:AlignToVector or something like that to align it to the ground? In my testing it looked like it might work but i would have to play with it a bit more. Quote Link to comment Share on other sites More sharing options...
YouGroove Posted February 4, 2014 Share Posted February 4, 2014 @Rick: I agree a lot. Could be used by Cars, Tanks, Balls, or whatever custom physic model , not only char controller. Should be in suggestion. Quote Stop toying and make games Link to comment Share on other sites More sharing options...
Schoppy0384 Posted February 4, 2014 Author Share Posted February 4, 2014 Ok, I thing it is Time for some Code (C++). Here I have write a little example with 3 Methods to Navigate a Character to a specific Position. All three Methods has his own problems. You can switch the Method with this lines: // Set Method int method = 1; #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 Model* pickSphere; Entity* characterController; Entity* characterMesh; PickInfo pickinfo; NavMesh* navMesh; NavPath* path; Model* box; list<Model*> models; list<Model*>::iterator modelsIt; int pointCounter = 1; // ####################### Character Move Methods ######################## // Set Method int method = 1; //method 1 = Standard Character Move Method ( only on xy Axis while SetPhysicsMode(Entity::CharacterPhysics)) //method 2 = Character Contoller is only a Pivot. The Charcter Model Follow this Pivot by SetPhysicPosition and Rotation (Problem the Model Collides with the Pivot and looks ver bad!) //method 3 = Calculate the Path Manuel and move and rotate the Model. (The Rotation is Bad and sometimes the Model collides with a wall) bool App::Start() { //Create a window window = Window::Create("RTS_Movement"); //Create a context context = Context::Create(window); //Create a world world = World::Create(); //Create a camera camera = Camera::Create(); camera->SetFOV(40.0f); camera->SetRotation(45,0,0); camera->Move(0,0,-35); //Create a light Light* light = DirectionalLight::Create(); light->SetRotation(35,35,0); //Build a Map //Create the ground Model* ground1 = Model::Box(44.75,0.25,62.5); ground1->SetPosition(8.875,-0.125,-0.25); ground1->SetColor(0.0,0.25,0.0); //Ground Shape Shape* groundShape1 = Shape::Box(0,0,0, 0,0,0, 44.75,0.25,62.5); ground1->SetShape(groundShape1); groundShape1->Release(); Model* ground2 = Model::Box(44.75,0.25,28.5); ground2->SetPosition(-35.875,-0.125,16.75); ground2->SetColor(0.0,0.25,0.0); //Ground Shape Shape* groundShape2 = Shape::Box(0,0,0, 0,0,0, 44.75,0.25,28.5); ground2->SetShape(groundShape2); groundShape2->Release(); Model* ground3 = Model::Box(44.75,0.25,25.0); ground3->SetPosition(-35.875,-0.125,-19.0); ground3->SetColor(0.0,0.25,0.0); //Ground Shape Shape* groundShape3 = Shape::Box(0,0,0, 0,0,0, 44.75,0.25,25.0); ground3->SetShape(groundShape3); groundShape3->Release(); Model* ground4 = Model::Box(16.48,0.25,9.0); ground4->SetPosition(-21.51001,-0.875,-2.0); ground4->SetRotation(0,0,5.0); ground4->SetColor(0.0,0.25,0.0); //Ground Shape Shape* groundShape4 = Shape::Box(0,0,0, 0,0,0, 16.48,0.25,9.0); ground4->SetShape(groundShape4); groundShape4->Release(); Model* ground5 = Model::Box(28.75,0.25,9.0); ground5->SetPosition(-43.875,-1.625,-2.0); ground5->SetColor(0.0,0.25,0.0); //Ground Shape Shape* groundShape5 = Shape::Box(0,0,0, 0,0,0, 28.75,0.25,9.0); ground5->SetShape(groundShape5); groundShape5->Release(); Model* ground6 = Model::Box(0.75,2.75,8.5); ground6->SetPosition(5.625,1.125,11.5); ground6->SetColor(0.0,0.80,0.0); //Ground Shape Shape* groundShape6 = Shape::Box(0,0,0, 0,0,0, 0.75,2.75,8.5); ground6->SetShape(groundShape6); groundShape6->Release(); Model* ground7 = Model::Box(0.75,2.75,8.5); ground7->SetPosition(-5.125,1.125,11.5); ground7->SetColor(0.0,0.80,0.0); //Ground Shape Shape* groundShape7 = Shape::Box(0,0,0, 0,0,0, 0.75,2.75,8.5); ground7->SetShape(groundShape7); groundShape7->Release(); //Enable navigation obstacles ground1->SetNavigationMode(true); ground2->SetNavigationMode(true); ground3->SetNavigationMode(true); ground4->SetNavigationMode(true); ground5->SetNavigationMode(true); ground6->SetNavigationMode(true); ground7->SetNavigationMode(true); //Build the navigation mesh world->BuildNavMesh(); //picksphere pickSphere = Model::Sphere(12); pickSphere->SetScale(0.5); pickSphere->Hide(); if(method == 1) { //#############-- Create a Character --################## //Create a character controller characterController = Pivot::Create(); characterController->SetPosition(0,0,0); characterMesh = Model::Box(1.0,0.2,1.5,characterController); characterMesh->SetScale(1,2,1); characterMesh->SetPosition(0,0,0); characterController->SetMass(1); characterController->SetPhysicsMode(Entity::CharacterPhysics); //####################################################### } if(method == 2) { //#############-- Create a Character --################## //Create a character controller characterController = Pivot::Create(); characterController->SetPosition(0,0,0); characterController->SetMass(1); characterController->SetPhysicsMode(Entity::CharacterPhysics); //Create the Mesh characterMesh = Model::Box(1.0,0.2,1.5); characterMesh->SetScale(1,2,1); characterMesh->SetPosition(0,0,0); characterMesh->SetMass(1); //Set Shape Shape* characterShape = Shape::Box(0,0,0, 0,0,0, 1.0,0.2,1.5); characterMesh->SetShape(characterShape); characterShape->Release(); //####################################################### } if(method == 3) { navMesh = world->navmesh; path = new NavPath(); // Create a new Instance path->navmesh = navMesh; //init list models = list<Model*>(); //#############-- Create a Character --################## //Create the Mesh characterMesh = Model::Box(1.0,0.2,1.5); characterMesh->SetScale(1,2,1); characterMesh->SetPosition(0,0,0); characterMesh->SetMass(1); //Set Shape Shape* characterShape = Shape::Box(0,0,0, 0,0,0, 1.0,0.2,1.5); characterMesh->SetShape(characterShape); characterShape->Release(); //####################################################### } //Move the mouse to the center of the screen window->SetMousePosition(context->GetWidth()/2,context->GetHeight()/2); return true; } bool App::Loop() { //Close the window to end the program if (window->Closed() || window->KeyDown(Key::Escape)) return false; // Show Physics if(window->KeyHit(Key:)) camera->drawphysicsmode = !camera->drawphysicsmode; //Enable/Disable navmesh debugging if(window->KeyHit(Key::N)) { if (camera->GetDebugNavigationMode() == false) {camera->SetDebugNavigationMode(true);} else {camera->SetDebugNavigationMode(false);} } //RTS Camera Movement if(!window->MouseDown(2)) { float strafe = (window->KeyDown(Key:) - window->KeyDown(Key::A))*Time::GetSpeed() * 0.1; float move = (window->KeyDown(Key::W) - window->KeyDown(Key::S))*Time::GetSpeed() * 0.1; camera->Move(strafe,move,move); } //Temp Camera Movement if(window->MouseDown(2)) { float strafe = (window->KeyDown(Key:) - window->KeyDown(Key::A))*Time::GetSpeed() * 0.1; float move = (window->KeyDown(Key::W) - window->KeyDown(Key::S))*Time::GetSpeed() * 0.1; camera->Move(strafe,0,move); //Get the mouse movement float sx = context->GetWidth()/2; float sy = context->GetHeight()/2; Vec3 mouseposition = window->GetMousePosition(); float dx = mouseposition.x - sx; float dy = mouseposition.y - sy; //Adjust and set the camera rotation camerarotation.x += dy / 10.0; camerarotation.y += dx / 10.0; camera->SetRotation(camerarotation); //Move the mouse to the center of the screen window->SetMousePosition(sx,sy); } if(method == 1) { //#############-- Character Movment --################## //Place a new target position for our npcewa if (window->MouseHit(1)) { Vec3 p = window->GetMousePosition(); if (camera->Pick(p.x,p.y,pickinfo,0.5,true)) { pickSphere->Show(); pickSphere->SetPosition(pickinfo.position); } } //Move Character to Pick Position characterController->GoToPoint(pickinfo.position,3.0f,6.0f); //###################################################### } if(method == 2) { //#############-- Character Movment --################## //Place a new target position for our npcewa if (window->MouseHit(1)) { Vec3 p = window->GetMousePosition(); if (camera->Pick(p.x,p.y,pickinfo,0.5,true)) { pickSphere->Show(); pickSphere->SetPosition(pickinfo.position); } } //Move Character to Pick Position characterController->GoToPoint(pickinfo.position,3.0f,6.0f); // Use the Physics to Position and Rotate The Mesh characterMesh->PhysicsSetRotation(characterController->GetRotation().x,characterController->GetRotation().y,characterController->GetRotation().z,0.005); characterMesh->PhysicsSetPosition(characterController->GetPosition().x,characterController->GetPosition().y,characterController->GetPosition().z,0.005); //###################################################### } if(method == 3) { //#############-- Character Movment --################## //Place a new target position for our npcewa if (window->MouseHit(1)) { Vec3 p = window->GetMousePosition(); if (camera->Pick(p.x,p.y,pickinfo,0.5,true)) { pickSphere->Show(); pickSphere->SetPosition(pickinfo.position); } // Create a new Path pointCounter = 1; path->points.clear(); // Clear the old Points path = path->navmesh->FindPath(characterMesh->GetPosition(true), pickinfo.position); // Place Boxes to see the Path Points //Cleat the old Models for(modelsIt = models.begin() ; modelsIt != models.end() ; modelsIt++ ) { delete (*modelsIt); } models.clear(); // Set new Path Models for (int i = 0; i < path->points.size(); i++) { box = Model::Box(0.1,0.1,0.1); box->SetColor(1.0,0.0,0.0); box->SetPosition(path->points.at(i).x,path->points.at(i).y,path->points.at(i).z); models.push_back(box); cout << i << ": " << path->points.at(i).x << ", " << path->points.at(i).y << ", " << path->points.at(i).z << endl; } } //end MouseHit if(path->points.size() > 0 ) { for (int i = 0; i < path->points.size(); i++) { if(i == pointCounter) { // Rotate the Character to the Points float targetX = path->points.at(i).x; float targetY = path->points.at(i).y; float meshPosX = characterMesh->GetPosition(true).x; float meshPosY = characterMesh->GetPosition(true).y; float angle = Math::ATan2(targetY - meshPosY,targetX - meshPosY); characterMesh->SetRotation(0,angle,0); } } if(characterMesh->GetPosition(true).x < path->points.at(pointCounter).x && characterMesh->GetPosition(true).y < path->points.at(pointCounter).y) { characterMesh->Move(0.005,0,0); } if(characterMesh->GetPosition(true).x >= path->points.at(pointCounter).x && characterMesh->GetPosition(true).y >= path->points.at(pointCounter).y) { pointCounter++;; } } //Now lets Move the Character //###################################################### } Time::Update(); world->Update(); world->Render(); // 2d Stuff ########################################### // Camera Projection if(characterController) { Vec3 p = camera->Project(characterController->GetPosition()); std::string text = "Here are the Pivot"; Leadwerks::Font* font = Leadwerks::Context::GetCurrent()->GetFont(); p.x -= font->GetTextWidth(text)/2; p.y -= font->GetHeight()/2; p.y += -50; Leadwerks::Context::GetCurrent()->SetBlendMode(Leadwerks::Blend::Alpha); Leadwerks::Context::GetCurrent()->SetColor(0.0,1.0,0.0); Leadwerks::Context::GetCurrent()->DrawText(text,p.x,p.y); Leadwerks::Context::GetCurrent()->SetColor(1.0,1.0,1.0); } context->Sync(false); return true; } Maybe we'll find a solution together. I think that this is also interesting for others, too. Quote Link to comment Share on other sites More sharing options...
beo6 Posted February 4, 2014 Share Posted February 4, 2014 i don't use C++ at the moment. i think something like this should work: local world = World:GetCurrent() local pickinfo = PickInfo() local rayStart = self.entity:GetPosition() local rayEnd = Vec3(rayStart.x, rayStart.y-50, rayStart.z) if (world:Pick(rayStart,rayEnd,pickinfo,0,true,Collision.Scene)) then self.entity:AlignToVector(pickinfo.normal,1) end however i just get a flickering rotation. Maybe the GoToPoint method overwrites the rotation? Quote Link to comment Share on other sites More sharing options...
Schoppy0384 Posted February 4, 2014 Author Share Posted February 4, 2014 Yes, I have played with AlignToVector, too. It works and rotate the Model in the right Position. But for the Movment I have use SetVelocity and I have a flickering problem too. I think the problem is that AlignToVector breaks the Physic System. Quote Link to comment Share on other sites More sharing options...
beo6 Posted February 5, 2014 Share Posted February 5, 2014 Hello, i got it half working now. here is the script: function Script:Start() -- create pivot that is the real controller self.pivot = Pivot:Create() self.pivot:SetPosition(self.entity:GetPosition(true), true) self.pivot:SetMass(1) self.pivot:SetPhysicsMode(Entity.CharacterPhysics) self.pivot:SetCollisionType(Collision.Character) end function Script:UpdateWorld() -- set model position to pivot position self.entity:SetPosition(self.pivot:GetPosition(true), true) -- disable model picking self.entity:SetPickMode(0) local world = World:GetCurrent() local pickinfo = PickInfo() local rayStart = self.pivot:GetPosition() local rayEnd = Vec3(rayStart.x, rayStart.y-50, rayStart.z) -- pick the ground normal for rotation if (world:Pick(rayStart,rayEnd,pickinfo,0,true,Collision.Scene)) then local v = Vec3(pickinfo.normal.x,pickinfo.normal.y,pickinfo.normal.z) -- align to ground normal if (pickinfo.normal) then self.entity:AlignToVector(v,1,0.3) end System:Print("entityPick normal.x:"..pickinfo.normal.x) System:Print("entityPick normal.y:"..pickinfo.normal.y) System:Print("entityPick normal.z:"..pickinfo.normal.z) end local pivotRotation = self.pivot:GetRotation(true) local modelRotation = self.entity:GetRotation(true) -- overwrite driving direction rotation with pivot rotation self.entity:SetRotation(modelRotation.x, pivotRotation.y, pivotRotation.z, true) -- reenable model picking self.entity:SetPickMode(Entity.SpherePick) end However it only works on one side of a hill. the other side of a hill still rotates the model but in the wrong direction. I need to somehow invert the rotation when on the other side. Anyone an idea? Quote Link to comment Share on other sites More sharing options...
Schoppy0384 Posted February 6, 2014 Author Share Posted February 6, 2014 Hi beo6, I have played around with your sample. The Problem is that the pickinfo.normal.y is allways a possitive value. Its right, it works on one side of a hill. But on the other side the value must be negative. But it is positive. I do not know why this is so. Quote Link to comment Share on other sites More sharing options...
beo6 Posted February 6, 2014 Share Posted February 6, 2014 I think that makes sense since it seems the faces of the terrain are rotated on the other side of the hill. Do we have something like Quaternion.FromToRotation() in the Unity Engine? http://answers.unity3d.com/questions/8867/how-to-get-quaternionfromtorotation-and-hitnormal.html Quote Link to comment Share on other sites More sharing options...
beo6 Posted February 7, 2014 Share Posted February 7, 2014 Hello, i just saw some code from Ogre3D that looked to me like almost the same commands as Leadwerks has, so i ported it over: local terrainNormal = pickinfo.normal local localY = self.entity:GetRotation(true) local weight = 0.10 local newNormal = localY * ( 1 - weight ) + terrainNormal * weight local inclinationAngle = Math:ACos(localY:Dot(newNormal)) if (inclinationAngle ~= 0.0) then local inclinationAxis = Vec3( localY:Cross( newNormal) ).Normalize() --local inclination = Vec3( inclinationAngle, inclinationAxis ) --not exactly sure how to create a Quaternion local inclination = Quat( inclinationAngle, inclinationAxis ) self.entity:SetRotation(inclination) end but beside that i am not sure how a quaternion is now exactly represented in LE and that it seems it crashes on the :Cross() function from a Vector i had no luck. Quote Link to comment Share on other sites More sharing options...
Schoppy0384 Posted February 7, 2014 Author Share Posted February 7, 2014 Hi, i have played with your code. The problem is: self.entity:SetRotation(inclination) inclination is a Quad and a Quad has 4 values. x, y, z, w. And SetRotation accept 3 Values EDIT: Oh Sorry, i see SetRotation accept a Quad. Quote Link to comment Share on other sites More sharing options...
beo6 Posted February 8, 2014 Share Posted February 8, 2014 (edited) Hello, Yes SetRotation accepts a Quad. I think i got it working: --Private values Script.minTargetDistance = 1.0 function Script:Start() self.targetPos = self.entity:GetPosition() -- create pivot that is the real controller self.pivot = Pivot:Create() self.pivot:SetPosition(self.entity:GetPosition(true), true) self.pivot:SetMass(1) self.pivot:SetPhysicsMode(Entity.CharacterPhysics) self.pivot:SetCollisionType(Collision.Character) self.pivot:SetPickMode(0) self.entity:SetPickMode(0) self.entity:SetNavigationMode(true, true) self.originalInclinationQuat = Quat() end function Script:GoToPosition( pos ) self.targetPos = Vec3(pos.x, pos.y, pos.z) if self.pivot:GoToPoint(pos, self.speed, self.acceleration) then --System:Print("unit "..self.entity:GetKeyValue("name", "").." responded. ") else self.pivot:Stop() --System:Print("unit "..self.entity:GetKeyValue("name", "").." cannot go there. ") end end function Script:UpdateWorld() -- set model position to pivot position self.entity:SetPosition(self.pivot:GetPosition(true), true) -- disable model picking self.entity:SetPickMode(0) local world = World:GetCurrent() local pickinfo = PickInfo() local pivotPos = self.pivot:GetPosition() local rayStart = Vec3(pivotPos.x, pivotPos.y+1, pivotPos.z) local rayEnd = Vec3(rayStart.x, rayStart.y-50, rayStart.z) -- pick the ground normal for rotation if (world:Pick(rayStart,rayEnd,pickinfo,0.1,true,Collision.Scene)) then local interpolateSpeed = 0.07 local terrainNormal = pickinfo.normal local localYRel = terrainNormal.y local localY = Vec3( 0, localYRel, 0 ) local weight = 0.1 local newNormal = localY * ( 1 - weight ) + terrainNormal * weight local inclinationAngle = Math:ACos(localY:Dot(newNormal)) local newNormalCross = localY:Cross( newNormal ) local inclinationAxis = newNormalCross:Normalize() inclinationAxis = inclinationAxis:Inverse() --not exactly sure why local inclination = Quat( inclinationAngle, inclinationAxis ) local inclinationSlerp = self.originalInclinationQuat:Slerp( inclination, interpolateSpeed / Time:GetSpeed() ) self.entity:SetRotation(inclinationSlerp) self.originalInclinationQuat = inclinationSlerp -- save interpolated quaternion --turn model to rotation of controller local pivotRotation = self.pivot:GetRotation(true) self.entity:Turn(0,pivotRotation.y,0) end -- reenable model picking self.entity:SetPickMode(Entity.SpherePick) local selfPosition = self.entity:GetPosition(true) -- is entity near destination stop pathfinding if selfPosition:DistanceToPoint(self.targetPos) < self.minTargetDistance then self.pivot:Stop() --System:Print("unit "..self.entity:GetKeyValue("name", "").." reached destination. ") end end It is by no means perfect but it gets the job done for me until a better way is found by someone who is better than me which should not be hard. //Edit: added interpolation to terrain alignment Edited February 10, 2014 by beo6 2 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.