Josh Posted November 20, 2025 Author Posted November 20, 2025 Game Mechanics video tutorial series is added on Leadwerks Game Engine beta branch. The last three videos produce an error "Error 2" (?) but there does not seem to be any problem with audio or video playing. 1 Let's build cool stuff and have fun.
Josh Posted November 20, 2025 Author Posted November 20, 2025 Fixed the error in the last three videos. 2 Let's build cool stuff and have fun.
Josh Posted December 2, 2025 Author Posted December 2, 2025 5.0.1 beta The first build of version 5.0.1 is available on the beta branch. This revises brush picking so that brush faces of all sizes can be successfully picked in the editor. Only the editor is updated at this time. You must opt into the beta branch on Steam if you want to test this version before a new release goes out to the default branch. Right-click on the application in the Steam interface, select the Properties menu, and in the Betas section, select "Beta - Development branch for testing". 1 Let's build cool stuff and have fun.
Josh Posted December 2, 2025 Author Posted December 2, 2025 5.0.1 beta In this build, the requirement for an environment variable is removed, and a Visual Studio property sheet is used instead, The rules for environment variables on Windows are unclear, and even if I spend a lot of time studying and testing them, they could change at some point in the future, or potentially act differently on some configation. Having information in three different places (project folder, install directory, env var) is confusing. If you have a shared project, and two different people have Leadwerks installed in different locations, you will need to remove the PropertySheet.props file from the repo. This is a slight inconvenience, but that's not as bad as having a magic variable hidden in the Windows settings. Existing C++ projects will not be affected by this. If you want to modify them, place this in a file called "PropertySheet.props", then "Add an existing property sheet" and include this in your project: <?xml version="1.0" encoding="utf-8"?> <Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> <ImportGroup Label="PropertySheets" /> <PropertyGroup Label="UserMacros"> <LEADWERKS>C:/Program Files (x86)/Steam/steamapps/common/Leadwerks</LEADWERKS> </PropertyGroup> </Project> Let's build cool stuff and have fun.
Josh Posted December 3, 2025 Author Posted December 3, 2025 5.0.1 beta An update for the C++ programming library is available now. Fixes error reported in textfield hiding infinite loop, in some situations Includes new raycasting method for brush entities Brush::meshes member is now exposed, contains the visual meshes built to display the brush entity 2 1 Let's build cool stuff and have fun.
Josh Posted December 3, 2025 Author Posted December 3, 2025 5.0.1 beta Fixed crash in downloads manager 1 Let's build cool stuff and have fun.
Josh Posted December 3, 2025 Author Posted December 3, 2025 5.0.1 beta In this build, when you create a new map, the editor will select the create object mouse tool, and when you open a map file the editor will choose the Selection mouse tool. 1 Let's build cool stuff and have fun.
Josh Posted December 3, 2025 Author Posted December 3, 2025 5.0.1 beta Editor will now compile all shaders as soon as they go to the GPU, instead of waiting until they are about to be used. Editor starts in 2.3 secinds instead of 1.8, but there's no delay now when you enable tessellation on a material, for example. There is a compile error on one of the vertex shader variations right now, will fix. This will get extended to the engine soon. 1 Let's build cool stuff and have fun.
Josh Posted December 4, 2025 Author Posted December 4, 2025 5.0.1 beta Whole engine is updated to precompile shaders now, I'm going to see about that vertex shader fix now... 1 Let's build cool stuff and have fun.
Josh Posted December 4, 2025 Author Posted December 4, 2025 Shader fixed, that was very easy. 2 Let's build cool stuff and have fun.
Josh Posted December 4, 2025 Author Posted December 4, 2025 5.0.1 beta This update rolls back the always-precompile change I made. I think this will require more time to be done properly. 1 Let's build cool stuff and have fun.
Josh Posted December 5, 2025 Author Posted December 5, 2025 5.0.1 beta Fixed some JSON definition files for the C++ template that did not have "auto-generated" set to true, so they would not get updated automatically if the C++ code changes. 1 Let's build cool stuff and have fun.
Josh Posted December 8, 2025 Author Posted December 8, 2025 5.0.1 beta Fixed problem with new C++ projects referencing invalid files. Fixed bug that was printing an extra line return. 1 Let's build cool stuff and have fun.
Josh Posted December 8, 2025 Author Posted December 8, 2025 5.0.1 beta Several bugs are fixed in the editor, see the bug reports forum for details. 1 Let's build cool stuff and have fun.
Josh Posted December 9, 2025 Author Posted December 9, 2025 5.0.1 beta Full update of C++ lib and Lua EXEs. C++ header and entity definition files updated. Think it's time to release this on default branch soon. 1 Let's build cool stuff and have fun.
Josh Posted December 10, 2025 Author Posted December 10, 2025 5.0.1 Version 5.0.1 is now on the default branch. This removes the need for a system environment variable for C++ projects, and fixes several bugs. Beta and default are in sync. Version 5.0.0 is now archived. 1 Let's build cool stuff and have fun.
Josh Posted December 11, 2025 Author Posted December 11, 2025 5.0.2 beta Added option in general settings to not show the project name in the title bar. WASD keys can now be remapped, for users who don't have English keyboards with WASD keys in the top-left. Open the file "C:\ProgramData\Leadwerks\settings.json" and find the section called "controls". You can modify the navigation keys here. It's not the ideal user experience right now, but this is just the first step. "controls": { "back": 83, "down": 81, "forward": 87, "left": 65, "right": 68, "up": 69 }, 1 Let's build cool stuff and have fun.
Josh Posted December 12, 2025 Author Posted December 12, 2025 5.0.2 beta Adjusted the behavior of typing into editable comboboxes. 1 Let's build cool stuff and have fun.
Josh Posted December 12, 2025 Author Posted December 12, 2025 5.0.2 beta Adjusted the behavior of search and replace fields in script editor. Adjusted behavior of search field in project tab. Wildcards are no longer used, it just does a simple lower-case find/match for the search term. 1 Let's build cool stuff and have fun.
Josh Posted December 16, 2025 Author Posted December 16, 2025 5.0.1 beta I recompiled the current build, with the version marked 5.0.1. It's on the beta branch and it will go onto default tomorrow. This will be the stable build that goes out right before tournament time. 1 Let's build cool stuff and have fun.
Josh Posted December 18, 2025 Author Posted December 18, 2025 5.0.1 final is now on default branch, beta branch is in sync. 2 Let's build cool stuff and have fun.
Josh Posted December 21, 2025 Author Posted December 21, 2025 5.0.2 beta Added View > Show Terrain menu item and associated functionality. 1 Let's build cool stuff and have fun.
Josh Posted December 24, 2025 Author Posted December 24, 2025 5.0.2 beta Several bugs fixed. 1 Let's build cool stuff and have fun.
Josh Posted December 24, 2025 Author Posted December 24, 2025 5.0.2 beta Added experimental Camera:SetMouseLook command. This handles mouse looking in the rendering thread, right before a frame is drawn, in the same way that our VR orientation updating code operates. This will provide you with very low-latency mouse feedback, ideal for fast-paced games. The arguments are mode, speed, and smoothness and it should be called like this: camera:SetMouseLook(true, 0.1, 0.5)-- 0.1 degree / pixel moved, 0.5 smoothness Speed (second value) should be greater than zero. Smoothness (last value) should be less than 1.0, 0.0 for no smoothing. You only need to call this command once. You should not mix this with your own mouse look code. The camera rotation will be retrieved back from the rendering thread automatically. Note this does not yet handle objects parented to the camera, like a weapon view model. Here is a version of the CameraControls.lua script, adjusted to use this feature. Since the looking behavior is controlled in the rendering thread, you need to disable it before switching to the menu, or is it keep control of the mouse. Hit Alt + F4 to close the window if you get stuck. ---@class CameraControls : Entity CameraControls = {} CameraControls.mousesmoothing = 0.5--"Mouse smoothing" CameraControls.mouselookspeed = 1.0--"Look speed" CameraControls.movespeed = 4.0--"Move speed" ---@param self CameraControls function CameraControls:Start() local camera = Camera(self) if camera ~= nil then camera:SetMouseLook(true, self.mouselookspeed * 0.1, self.mousesmoothing) end self:ListenEvent(EVENT_WORLDPAUSE, self.world) self:ListenEvent(EVENT_WORLDRESUME, self.world) end ---@param self CameraControls ---@param event Event function CameraControls:ProcessEvent(event) local camera = Camera(self) if event.id == EVENT_WORLDPAUSE then if camera ~= nil then camera:SetMouseLook(false, self.mouselookspeed * 0.1, self.mousesmoothing) end elseif event.id == EVENT_WORLDRESUME then if camera ~= nil then camera:SetMouseLook(true, self.mouselookspeed * 0.1, self.mousesmoothing) end end end ---@param self CameraControls function CameraControls:Update() local window = ActiveWindow() if window == nil then return end local speed = self.movespeed / 60.0 if window:KeyDown(KEY_SHIFT) then speed = speed * 10.0 elseif window:KeyDown(KEY_CONTROL) then speed = speed * 0.25 end if window:KeyDown(KEY_E) then self:Translate(0, speed, 0) end if window:KeyDown(KEY_Q) then self:Translate(0, -speed, 0) end if window:KeyDown(KEY_D) then self:Move(speed, 0, 0) end if window:KeyDown(KEY_A) then self:Move(-speed, 0, 0) end if window:KeyDown(KEY_W) then self:Move(0, 0, speed) end if window:KeyDown(KEY_S) then self:Move(0, 0, -speed) end end 2 Let's build cool stuff and have fun.
Josh Posted December 26, 2025 Author Posted December 26, 2025 5.0.2 beta Added Display:GetRefreshRate method. Added Hmd:GetRefreshRate method. Fixed player physics to work the same at any update frequency. Improved timing and thread sychronization. This is experimental. If you don't want your workflow interupted, switch to the default branch now. In this build, timing works differently. The third command argument for World:Render has been replaced with a new value, syncedframes: World::Render(framebuffer, bool vsync = true, int syncedframes = -1) This value allows you to specify how many frames the rendering thread should draw before it waits for a new update from the main thread. The max framerate value this command previously supported will no longer be used, because this value is now calculated from the world update frequency and number of synced frames. Emulating 5.0.1 Standard Behavior The standard behavior previous builds use is a 60 hz game loop, and the rendering thread is allowed to go as fast as it wants. This will work with any display or VR headset refresh rate: world->Update(60); world->Render(framebuffer, true, 0); Or if you want to test the maximum framerate set VSync to false: world->Update(60); world->Render(framebuffer, false, 0); Improved Synchronization at 60 hz If you set syncedframes to 1, and the world update rate is 60, then for every one iteration of the game loop, one frame will be rendered. The main and rendering threads will still be running at the same time, but they will be more closely synchronized, for lower-latency input: world->Update(60); world->Render(framebuffer, true, 1); However, on high-frequency displays this will give you a framerate lower than the max refresh rate. Competitive E-Sports Games If want to adjust the game speed to support any display with minimal latency, you can do this: world->Update(window->display->GetRefreshRate()); world->Render(framebuffer, true, 1); This is the best setting for minimal latency for twitch shooters written in C++. Note that if a frequency other than 60 is used, you will need to multiply all the time-dependent values in your code by world->GetSpeed(). Velocity does not need to be modulated with this, because it is already in units of distance over time. If you want your game to run at a speed faster than the screen refresh rate, you can set vsync to false: world->Update(200); world->Render(framebuffer, false, 1); I believe this is how the timing in the newer Doom games works, and it explains why the game cannot run at a framerate faster than 200. Anything higher than that would probably start to affect how physics and other game code works, causing erratic behavior. Tight Synchronization with Varying Game and Rendering Frequencies The problem with perfectly synced timing on high-frequency displays is it decreases the amount of time your code has to run in the main thread. At 60 hz your game code has 16.667 milliseconds to run. If the screen refresh rate is 240 hz, that only allows 4.16 milliseconds for your game code to run. If there are a lot of enemies with complex code or if the game is written with Lua, this will probably cause the game to slow down. You might also want to always make the game update at 60 hz so that you don't have to multiply everything by world->GetSpeed(). You can combine a higher rendering frequency with a lower game frequency, by specifying more than one synced frames: world->Update(60); world->Render(framebuffer, false, 2); This will update the game at 60 hz, but render the world at 120 hz, drawing two frames for every game loop. The previous two orientations of each entity will be interpolated, so you have smooth motion even though two frames are rendered for every one iteration of the game loop. If you wanted the game to render at 180 hz, you could set the third argument to 3. To support any display frequency with close synchronization of frames, you might wish to do something like this: float refreshrate = window->display->GetRefreshRate(); int syncedframes = Floor(refreshrate / 60.0f); int updatespeed = Round(refreshrate / syncedframes); world->Update(updatespeed); world->Render(framebuffer, true, syncedframes); The above code will give you these values: Display refresh rate: 90 hz Update speed: 90 Synced frames: 1 Display refresh rate: 120 hz Update speed: 60 Synced frames: 2 Display refresh rate: 144 hz Update speed: 72 Synced frames: 2 Display refresh rate: 240 hz Update speed: 60 Synced frames: 4 If you are rendering at a faster speed than the game loop, you may wish to use the Camera::SetMouseLook feature to handle camera looking in the rendering thread. This will give you low-latency camera movement, with a few caveats: The player movement will still be updating at a lower frequency and might feel slightly mushier, but since player movement has inertia anyways it might not be very noticable. The camera rotation will be fed back to the main loop, so it will always be a few milliseconds behind. This could matter in E-sports type hyper-competitive shooters, but probably doesn't matter for regular FPS games. On the other hand, someone with a 240 hz display is likely to also have a top-of-the-line CPU, so maybe it all balances out. It's up to you. Default Behavior If you don't understand any of this, or don't care, then you can just not specify any parameter, and the engine will choose settings for you based on the display refresh rate. For 75% of players this will be 60 hz, so if your game loop is running at 60 hz and vsync is enabled, the engine will choose 1 for the number of synced frames, otherwise it will be set to 0. Visualizing the Technique This code provides a dramatic example that shows how varying game and rendering frequencies works. Here the game updates at just one update per second, but the renderer displays smooth motion at 120 frames per second, using just the inputted information! (Don't actually do this in your own games, this is just for learning.) #include "Leadwerks.h" using namespace Leadwerks; int main(int argc, const char* argv[]) { auto displays = GetDisplays(); auto window = CreateWindow("Leadwerks", 0, 0, 1280, 720, displays[0], WINDOW_CENTER | WINDOW_TITLEBAR); auto world = CreateWorld(); auto framebuffer = CreateFramebuffer(window); auto camera = CreateCamera(world); camera->SetClearColor(0.125); camera->SetPosition(0, 0, -2); auto light = CreateBoxLight(world); light->SetRotation(45, 35, 0); light->SetRange(-10, 10); light->SetColor(2); auto A = CreateBox(world); A->SetPosition(-1,0,0); A->SetColor(0, 0, 1); auto B = CreateBox(world); B->SetPosition(1, 0, 0); B->SetColor(0, 0, 1); while (window->Closed() == false and window->KeyDown(KEY_ESCAPE) == false) { // The box on the left will show smoothed motion A->Turn(0, 0, 22.5); // The box on the right will show the true state of the game B->Turn(0, 0, 22.5); B->Sync(); // Game updates once per second world->Update(1); // Game renders 120 frames, evenly spaced, for every one game loop iteration world->Render(framebuffer, false, 120); } return 0; } 1 Let's build cool stuff and have fun.
Recommended Posts