-
Posts
2,600 -
Joined
-
Last visited
Content Type
Blogs
Forums
Store
Gallery
Videos
Downloads
Everything posted by reepblue
-
The Leadwerks API has standard Boolean functions that detect when the end user has pressed a key. While this is very simple and easy to understand, the issue comes when you wish to support binding of actions. Instead calling functions when a certain key was pressed or held, a better way to detect key events is to assign a key to an action. (e.g: Is the Jump key pressed). In Luawerks, I've written an action script in which returns the window call if the key defined in the user's settings is hit. The downsides is that you had to do this for every action in your game and that this was a system written for Luawerks so it wasn't very portable for non-lua/Leadwerks projects. function Action:MoveForward() if self.suspend==true then return false end local key_forward = GetKeyInt(System:GetProperty("key_forward","w")) return window:KeyDown(key_forward) end For those who don't know, SDL is an Open Source library that comes in handy for things like Window management, input, and such. So over the weekend, I've decided to sit down and create my own Input System in which would be allow for action bindings, portable for any type of project while supporting Game Pads outside of Steam. The first step was to manually poll all inputs and treat them all the same. For the mouse and keyboard, this was just seeing if a key was hit, and registering that event to a map. namespace RInput_KM { void SimulateButton(const Sint32& pKey, bool bDown); const float ButtonDown(const Sint32& pKey); void ShowMouse(); void HideMouse(); void SetMousePosition(const int x, const int y, bool bGlobal = false); void ModMousePosition(const int x, const int y, bool bGlobal = false); void UpdateMousePosition(); void SimulateMouse(const int x, const int y); const int GetMouseX(); const int GetMouseY(); void SetMouseWheelPosition(const int y); const bool OnMouseWheelUp(); const bool OnMouseWheelDown(); // Returns the long to a character. const char* GetButtonName(const Sint32& pButton); // Returns the character to a long const Sint32 GetButtonIndex(const char* pButton); void Enable(); void Disable(); void FlushKeyboard(); void FlushMouse(); void Flush(); } When it comes to buttons, it doesn't matter if the mouse button was pressed or a key stroke. What matters is that a button on the keyboard and mouse combo was pressed. I treat the keyboard and mouse as one controller. You can also "Turn off" the mouse and keyboard if you want. namespace RInput_GamePad { typedef enum { ENUM_GAMEPAD_NULL = -1, ENUM_GAMEPAD_ONE, ENUM_GAMEPAD_TWO, ENUM_GAMEPAD_THREE, ENUM_GAMEPAD_FOUR, ENUM_GAMEPAD_MAX = ENUM_GAMEPAD_FOUR } GamePadIndex; typedef struct { SDL_GameController* controller; const char* pszDeviceName; bool bEnabled; std::map<Uint8, bool> mControllerButtons; } gamepad_t; void Connect(const Sint32& pWhich); void Disconnect(const Sint32& pWhich); gamepad_t GetDeviceFromPort(const GamePadIndex& pPort); // Digital input: void SimulateButton(const Sint32& pWhich, const Uint8& pButton, bool bDown); const float ButtonDown(const Uint8& pButton, const GamePadIndex& iIndex = ENUM_GAMEPAD_ONE); const char* GetButtonName(const Uint8& pButton); const Uint8 GetButtonIndex(const char* pButton); // Analog input: void UpdateAxisMotions(const Sint32& pWhich, const Uint32& pAxis); const Sint16 GetAxisValue(const Sint32& pWhich, const Uint32& pAxis, bool bFlip = false); const float GetAxisFloat(const Sint32& pWhich, const Uint32& pAxis, bool bFlip = false); void Flush(const Sint32& pWhich); void FlushAll(); } Next was the game pads. which were a bit more challenging as you need to consider multiple game pads and the valves of analog inputs. If you were paying attention, You would notice that the ButtonDown functions for both the keyboard+mouse and the game pad are returning floats. While it may be limiting for certain applications, I've created "fake buttons" for events for when the trigger is pressed, or if the left stick is to the left. All input returns a float ranging from 0.0 to 1.0. For digital inputs like buttons, this will be a 1 or 0, but for analog the value depending the range from the resting point to the max will called. So if the left stick is all the way to the left, you'd get 1; half way 0.5. This is much better then dealing with direct Uint32 values. Last was to merge both controllers into one entry point in which we use in our app to register our actions, and check to see if they are being called. namespace RInput { typedef enum { CONTROLLER_KEYBOARDMOUSE, CONTROLLER_GAMEPAD } Controllers_t; void Init(SDL_Window* pWindow); void InitSDL(const void *data); void SetActiveDevice(const Controllers_t& pDevice); Controllers_t GetActiveDevice(); const char* GetActiveDeviceAsString(); const char* GetGamePadDeviceAsString(const int pPort); const Sint8 GetGamePadCount(); void TestEvents(const SDL_Event& pEvent); void PollEvents(); // <- Use this function if you're not using SDL event polling. void Flush(const Controllers_t& pController); void FlushAll(); //==================================================================== typedef struct { Sint32 key; Uint8 button; bool bDown; bool bHit; } action_t; const float GetActionInput(action_t& pButton); void RegisterAction(const std::string& pActionName, Sint32 iKey, Uint8 iButton, bool bConistant); void ModifyAction(const std::string& pActionName, Sint32 iKey, Uint8 iButton); action_t& GetAction(const std::string& pActionName); bool LoadActionsFromFile(const char* pszPath); void UpdateGamePadStickAsMouse(const Sint32& pWhich, const Sint8& pAxis); } Actions can be bind to a with key and a button. bDown is used to check if the action is being held down while bHit is a flag to check if this is something that should be called once per pressed (Like a key to pick up a box or something.) One top of all this, Actions can have their key/button bindings changed via an XML file. Here's an example how to use this with Leadwerks. #include "Leadwerks.h" using namespace Leadwerks; #include "rinput/rinput.h" int main() { Leadwerks::Window* window = Window::Create(); RInput::InitSDL(window->hwnd); Leadwerks::Context* context = Context::Create(window); World* world = World::Create(); Camera* camera = Camera::Create(); camera->SetRotation(35, 0, 0); camera->Move(0, 0, -6); Light* light = DirectionalLight::Create(); light->SetRotation(35, 35, 0); light->SetShadowMode(0); Model* model = Model::Box(); model->SetColor(1.0, 0.0, 0.0); model->SetPosition(0, 0, 0); model->SetShadowMode(0); RInput::RegisterAction("moveforward", KEYBOARD_W, GAMEPAD_BUTTON_LSTICK_UP, true); RInput::RegisterAction("movebackward", KEYBOARD_S, GAMEPAD_BUTTON_LSTICK_DOWN, true); RInput::RegisterAction("moveleft", KEYBOARD_A, GAMEPAD_BUTTON_LSTICK_LEFT, true); RInput::RegisterAction("moveright", KEYBOARD_D, GAMEPAD_BUTTON_LSTICK_RIGHT, true); RInput::RegisterAction("jump", KEYBOARD_SPACE, GAMEPAD_BUTTON_A, false); RInput::LoadActionsFromFile("controller.xml"); while (window->Closed() == false) { RInput::PollEvents(); float x = 0; float z = 0; float u = RInput::GetActionInput(RInput::GetAction("moveforward")); float d = RInput::GetActionInput(RInput::GetAction("movebackward")); float l = RInput::GetActionInput(RInput::GetAction("moveleft")); float r = RInput::GetActionInput(RInput::GetAction("moveright")); if (u != 0) { z += 0.05 + (u /10); } if (d != 0) { z -= 0.05 + (d / 10); } if (l != 0) { x -= 0.05 + (l / 10); } if (r != 0) { x += 0.05 + (r / 10); } model->Move(x, 0, z); x = 0; z = 0; Leadwerks::Time::Update(); world->Update(); world->Render(); context->DrawStats(0, 0, false); context->Sync(false); } return 0; } The Result: There are many things I didn't add for the sake of time or I wasn't sure how to implement like supporting action for multiple controllers on the front end. But this does what I was set out to do, and although I haven't tried, I'm confident that with little to no work, this code will work on macOS and Linux. As long as there is SDL2 on the platform, this will work. Now no matter if the project is Leadwerks, Turbo or just an SDL2 project, I now have a portable input system with controller support which you can find here.
-
[4.6 Beta] Button always display as links.
reepblue replied to reepblue's topic in Leadwerks Engine Bug Reports
This was in a new 4.6 project. The build at the time had different GUI scripts. Reverting the scripts to the 4.5 versions fixed the issue. -
Luawerks has been updated to 1.2.7, making some small adjustments and fixes to the system. If you have previously purchased Luawerks, this update is available for free on the Leadwerks Marketplace. Please note: Luawerks is not ready for Leadwerks 4.6 and it's recommended to use Luawerks with Leadwerks 4.5. Following changes include: Added an optional Map selection menu. "New Game" will default call a panel in which all the maps in your Maps directory will be listed, Note: This will only work if the maps are not included in your zip as raw Lua functions are called. This will also not work if the Lua sandbox is enabled. Re-located error.mdl to a sub directory "Models/Developer" Added widget.mdl and axis.mdl for assistance for visualizing matrix results. When in-game, "Exit to Menu" will show instead of "Quit." This will release the world and the player will be returned to the main menu. Arrange locations of various functions. The names remain the same. Added various functions needed for this update. About Luawerks Luawerks is a Lua framework for video games developed on the Leadwerks Game Engine. It supplies developers with additional functions, handles the game loop and allows them to debug their code with a developers console. With all that out of the way, you can focus on making your game fun! You can purchase Luawerks from the Leadwerks Marketplace for $9.99. For documentation and bug reporting, please visit the GitHub page.
-
From my understanding, no. You need to call the use the Steamworks API with C++. You can always expose these classes yourself if you have the professional version.
-
[4.6 Beta] Crash when using Joint:Ball()
reepblue replied to tipforeveryone's topic in Leadwerks Engine Bug Reports
Yep, the code on that page just creates a Window and crashes. -
I've noticed that with the pickup system in the template FPS player is now very sloppy. With my code, it's much better with my system, but I've noticed a slow delay between updating the rotation of a clamped object between 4.5 and the 4.6 beta. Here is my Pickup Controller code if need be. It worked perfectly in 4.5.The SDK system is all rubberbandy and wack. if PickupController~=nil then return end PickupController={} function PickupController:Create(entity) if entity== nil then Debug:Error("PickupController: Entity cannot be nil!") end local pickupcontroller = {} pickupcontroller.entity = entity pickupcontroller.allowpickup = true pickupcontroller.maxdist = 2.5 pickupcontroller.carrydist = 1.75 pickupcontroller.carriedobj=nil pickupcontroller.effector=nil pickupcontroller.carrypos=Vec3(0) pickupcontroller.carryquat=Quat(0) for k,v in pairs(PickupController) do pickupcontroller[k] = v end return pickupcontroller end function PickupController:Reset() if self.effector ~= nil then self.effector:Release() self.effector = nil end if self.carriedobj ~= nil then local n = self.carriedobj:GetKeyValue("collisiontype") n = n tonumber(f) if n ~= nil then self.carriedobj:SetCollisionType(n) end self.carriedobj:SetKeyValue("collisiontype", "") self.carriedobj = nil end end function PickupController:Delete() self:Reset() --self.entity = nil self.effector=nil self.carrypos=nil self.carryquat=nil self.maxdist=nil self = nil end function PickupController:CanPickupObject(entity, masslimit) if not self.allowpickup then return false end if entity == nil then return false end if entity:GetMass() <= 0 then return false end if entity:GetShape() == nil then return false end if entity:GetAABB(Entity.LocalAABB).size.x > 1.28 or entity:GetAABB(Entity.LocalAABB).size.z > 1.28 or entity:GetAABB(Entity.LocalAABB).size.z > 1.28 then return false end if entity:GetAABB(Entity.GlobalAABB).size.x > self.carrydist or entity:GetAABB(Entity.GlobalAABB).size.z > self.carrydist then return false end if masslimit > 0 and entity:GetMass() > masslimit then return false end if entity:GetCollisionType() == Collision.Character or entity:GetCollisionType() == Collision.Scene then return false end return self:NotOnTopOfObject(entity) end -- Check to see if we're not on top of an object function PickupController:NotOnTopOfObject(object) if object ~= nil then local pickInfo = PickInfo() local p0 = self.entity:GetPosition() local p1 = Transform:Point(0,-1.0,0,self.entity,nil) if self.entity.world:Pick(p0, p1, pickInfo, 0.8, true, Collision.Debris ) then if pickInfo.entity == object then return false end end end return true end function PickupController:IsHoldingObject() if self.carriedobj == nil then return false end return true end function PickupController:PickupObject(entity, transformfrom) -- If we are already holding an object, don't call this function if self:IsHoldingObject() then return end self:Reset() self.carriedobj = entity -- Store it's original collision mode within the entity itself. self.carriedobj:SetKeyValue("collisiontype", tostring(self.carriedobj:GetCollisionType())) -- Change the object's collision type to "Debris" This has it's own issues, but it's less cost effective than raytraces. self.carriedobj:SetCollisionType(Collision.Debris) -- Play a sound on pickup.. local entscript = GetEntityScript(self.carriedobj) if entscript~=nil then if type(entscript.PlayImpactSound)=="function" then entscript:PlayImpactSound() end end self.carrypos = Transform:Point(0, 0, self.carrydist, transformfrom, nil) self.effector = Joint:Kinematic(self.carrypos.x, self.carrypos.y, self.carrypos.z, self.carriedobj) self.effector:SetFriction(1000, 1000) self.effector:SetTargetAngle(1) self.carriedobj:SetDamping(1, 1) self.carryquat = Transform:Rotation(self.carriedobj:GetQuaternion(true), nil, transformfrom) end function PickupController:UpdateHeldObject(transformfrom) if not self:IsHoldingObject() then return end -- Update the pickup position self.carrypos = Transform:Point(0, 0, self.carrydist, transformfrom, nil) local current_obj_pos = self.carriedobj:GetPosition(true) local diff = self.carrypos:DistanceToPoint(current_obj_pos) if diff > self.maxdist then self:DropObject() return end self.effector:SetTargetPosition(self.carrypos, 1) self.carriedobj:SetVelocity(self.carriedobj:GetVelocity() / 1.5) self.effector:SetTargetRotation(Transform:Rotation(self.carryquat, transformfrom, nil), 1) end function PickupController:DropObject() if not self:IsHoldingObject() then return end -- After our AABB test, if we can drop the object, do so local aabb = self.carriedobj:GetAABB(Entity.GlobalAABB) local player = self.entity:GetAABB(Entity.GlobalAABB) if not aabb:IntersectsAABB(player,0) then self.carriedobj:SetVelocity(self.carriedobj:GetVelocity() / 4) self.carriedobj:SetDamping(0.1, 0.1) self:Reset() end end function PickupController:Enable(b) self.allowpickup = b end
-
I was reviewing Luawerks for the 4.6 update and found that the GUI scripts have been updated.I was first greeted with an error. Figuring out what changed made me start the standard menu script and I was greeted with the buttons always being links. Here is Luawerks in 4.6 using the older GUI scripts. Also note that check boxes don't seem to show correctly ether. This seems to be due to you've made in Buttons.lua. Was this edit necessary? If there is going to be no fix for this, I'm just going to ship the older scripts with my package.
-
I personally just want a client/server soultion in which the application hosts a server localy and then creates a client to connect to the server; kind of what Source does. I have to experiment to see if it's practical. I still only wish to make Single player games, but I don't want to be limited. Having a system like described above will make any game multiplayer with a flip of a switch.
-
Just did a test with the default template. It seems like the PC without Steam was unable to create a Lobby. From what I understand the P2P class is Steam dependent but nothing suggests the Lobby is. It looks like I'd have to write my own system using the base client/server classes, which in that case I'll just use Turbo which as them as I'm interested in just sending packets over my network. Luckily, the Parameters for the P2P/Lobby is similar to the Client/Server.
-
Ok, thank you both. New to netcoding, so I'm really sorry for my lack of understanding on this topic.
-
To clarify, with "behind a router", I would have the two machines plugged into a router. Do you mean that I can't do this or you're just restating connecting to another PC on the internet is not possible without the aid of Steam? I simply just want to connect to another room in the house. I just want to understand what I'm getting myself into.
-
Hello, Is it possible to do a direct connection to another computer without Steam, or do both machines need Steam installed with their own accounts? I would like to test my net code within the same location to see if the right data is sending/receiving but the dependency with Steam kind of makes me uncertain. Thanks.
-
Again, not that familiar with the format. Just took for granted that text is slow. Interested in how this will turn out.
-
If the loading speed is long enough to make a sandwich and come back on something like The Zone, then you have a problem. Other than that, I'm looking forward to text formatted maps.?
-
Not to mention, it being text, it should be a lot easier to copy and paste data from one map to another. In theory, you will be able to load maps within other maps without compromising instead of the limited prefab system in LE4. It would be like how prefabs work in Hammer. You should be able to store flowgraph data in it too. A tad worried on the speed cost as this is the first time I heard you planning on something that doesn't prioritize speed. I would do benchmarks to see how slow this might be. Whatever you decide, I'm looking forward to seeing what you come up with.
-
Not a big JSON user, but a text format for maps hits close to home. I really liked WorldCraft/Hammer mapfiles because of this. Does that mean the maps need to be compiled into a binary format so the engine can read the data quicker?
-
What I was saying is that you still need MSVC to compile C++ code. Just having VSCode installed will not enable code compiling as it lacks a compiler to my knowledge. Pretty much, can't make VSCode the official IDE because you still need MSVC on Windows and I couldn't figure out how to download only clang/g++ without XCode on macOS. With Linux, it's not that big of a deal as the compiler is a small download away and your free to choose whatever compiler you want. My question is why request the end user to download 2 additional pieces of software?
-
How can you compile projects with just VSCode? I can see if you were using the Windows GCC stuff and used makefiles, but you need the complete VS2017 to build anything using MSVC as far as I know.
-
Really cool. This will help with users building the game with their own systems instead of fighting with any conflicting ones. Just keep the default plugs to a minimum and provide docs and examples. ?
-
I agree. You should just release what you were able to accomplish as a unsupported feature.
-
MSVCR100.dll is missing in windows 10
reepblue replied to darkmatterjesus's topic in General Discussion
Why does LE still need that dll to operate? Wouldn't use the newer redistributables? -
Will the spring improvements be implemented in 4.6 still? I was playing with them on a non-vehicle mechanic and it just bounced indefinitely.
-
Try building a game project and then execute it.
-
What worked? Please clarify. I took it as it compiled but will not launch die to the lack of the driver.