Jump to content

Blogs

Our community blogs

  1. Previously I talked about array textures acting as "bindless" textures, but there is an actual OpenGL extension that allows a shader to access any texture without the stupid texture binding / slot convention that limits OpenGL 4.0 shaders to a minimum of 16 textures. Implemenation was surprisingly easy, although Mac hardware apparently does not support this extension. When combined with the multi-draw commands in OpenGL 4.3, and some other tricks, it is possible to render multiple sets of objects in one single draw call. Below you can see six instances of three different objects, with different materials applied to them, all rendered in one single command, for ultimate performance.

    This is basically the final goal of the whole crazy architecture I've been working on for over a year.

    I will test this a bit more, release an update for the new engine beta, and then at that point I think it will be time to move everything over to Vulkan / Metal.

    Image1.thumb.jpg.74ed97ae8fe1071334fb95e855772191.jpg

  2. Admin
    Latest Entry

    By Admin,

    The beta branch on Steam is now updated. Version 4.6 introduces peer-to-peer multiplayer capabilities with a new multiplayer game template. Check out the new features in the documentation:

    The physics library is updated to the latest version of Newton.

    The editor has some enhancements as well:

    • Model editor view range is calculated from model extents, so if you load a model that is huge it won't be invisible.
    • Model editor displays number of limbs as well as vertices and triangles.
    • Settings file is now saved any time changes are made in the project manager or the options editor.
    • Menu added for Leadwerks Marketplace. Paid Workshop items are no longer accepted.
    • Menu item added for Discord chat.

    Please test this out and report any errors in the bug reports forum, as this is pretty close to the final version 4.6.

  3. 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.

    • 1
      entry
    • 1
      comment
    • 83
      views

    Recent Entries

    Sharlenwar
    Latest Entry

    "My Return" would imply that I've been away for some time. To be honest here, I've been using the Leadwerks editor since before it was an official "game engine". Before you would use it to create your items to then import into another game engine. I've been always interested in creating games, since the late 90's. I remember using a few other older editors whose names I've long forgotten with the sands of time. I have always wanted to create an RPG, as that's my favorite genre of games. So the name of this blog implies that the Demurian empire has long survived and thus, a sort of resurgence of this project might happen.

    I figure, a blog is a great way to stay motivated and to in a way, focus you on developing a game. Many of us "hobbyists" suffer a disease of not finishing our projects that we started with. You see this in every forum out there, for any of these game engines. There is always a small group of dedicated users of the engine, but the majority of the time you see shells of what once was. Ideas that lay dormant for someone in the future to come across.

    I just want to thank the developer of this engine, he has done an amazing job and with my return, I imagine that this engine should still continue into the future. The website looks wonderful, and I like the way that everything integrates with Steam. So as I sit here typing, my mind is moving fast with ideas and I figure it's time to go back to the engine and start working on something. Something to brush the dust off, to maybe utilize the assets I've purchased as DLC on Steam.

    Well, I hope you'll join me on this journey, and let's see what happens in 2019 here.

  4. That's what I obtained for driving experience with 4.6.

    For me it's ok, just the distance of the wheels to the cars are growing too much while getting speed.

    Sounds have to get upgraded too

     

    I add a video that show car driving possibilities in the down-scaled world I want to create with an own scaled character controller. The idea is to obtain with this a bigger world lol

    So everything is under scaled, the car too.

    It's not GTA 6 but it's very ok for what I expect because I like when the car you drive is shaking on the road, as too much polished is not realistic enough, as you could not feel the ruggedness of the world you are playing in . I think the cars in gta 5 are definitvly too polished as you cannot reverse them for example, making the game a way too sanitized.

     

     

     

     

    Progress of this update 02/2019:

     

     

     

     

     

     

     

     

  5. Hi Leadwerkers ⚙️,

    today I have a cool announcement to make. In the past two years I was working on the Phodex Framework, which is a set of helpful tools, utilities and systems, created to unleash Leadwerk's true power and potential, to be able to create the games I had in mind. Now, that I have released my first Leadwerks game Bladequest: The First Chapter and the Phodex Framework has proven its worth in practice, I thought it is time to share some parts of the framework, especially those I think everyone could make use of.

    I step by step will release different components of the framework, some of them are free, some of them paid. The best is, the first component, the very powerful and flexible Event System is already available for free. If used correctly, it can massively improve the structure of your code and also offers you the opportunity, to build your own powerful systems upon it. For the future I also plan to produce some video tutorials to explain everything more detailed. For now you can read the documentation, that comes with each component.

    The following components are planned to be released in the future:

        🔹 Advanced Animation Manager

        🔹 Advanced Debugging Functions

        🔹 Easy Raycaster System

        🔹 Helper Functions

        🔹 Input Manager

        🔹 Object Orientation for LUA

        🔹 Save & Load System

    Together, those systems will massively improve your Leadwerks experience. I can't imagine working without them anymore and am sure you will feel them same once you use them.

    As always stay cool and have a nice day :)

    Markus from Phodex Games

    • 2
      entries
    • 1
      comment
    • 518
      views

    Recent Entries

    Lethal Raptor Games
    Latest Entry

    TheSeventhWorld_Logo.png.65e491c60dde3031ecfddfceb267a9c7.png

     

    After three weeks of work, Pre-Alpha v1.1 is ready.

     

    Terrain

    The terrain has seen some behind the scenes improvements with speed as well as visual improvements to geometry and texturing.  When I manage to get Texture Arrays working I will be able to finish of the new texturing shader that will include Tessellation and over 16 different texture maps as well as various masks that will paint according to erosion and forest locations.

    Screenshot_05.png.d627b7a3a6559c86bf16ef3931234367.pngAn image of one of the mountains randomly placed in the First World, textured with two 4k textures.  The way the generator works is there is a predefined list of terrain features, like mountains, rivers and valleys.  Based on a low resolution base map which is unique for each fragment, these features are placed at different scales, positions and rotations.  They will also merge with one another to provide enough variation that it will be hard to see any similarities.

    At the moment though there are not enough maps to make this unnoticeable.

     

     

     

     

     

    Saving and Loading

    Screenshot_06.png.91b7a9d0c653ea07fdf919e422ee6ecb.pngI have now implemented the ability to save and load a game.  Currently the only states that are saved are the players position, stats and inventory.

    Each slot shows the date and time that it was saved on as well as the save name and version number.  Slots can be deleted and overwritten.  The version number will change over the course of the updates, but the ability to load older versions will always be available.  And to save a new game, click the empty slot then click save.

    Now that this mechanic is done I can work on more game play.

     

     

     

     

     

     

    What's Next

    The next step is to improve the blacksmith and general store.  These two places will be the first to provide work opportunities for the player.  These opportunities will improve skill and eventually allow you to buy and use crafting equipment outside of the towns.

    I will also be implementing some other mercenary characters and animals to hunt.  The mercenaries will just offer some fun conflict to begin with and the animals will offer another source of income.  I hope to have a deer and wolf done by the next update in a few weeks.

     

    The full change log is packaged with the game, here.

  6. aiaf
    Latest Entry

    Entry for tournament is on 😎

    Check game information on link below and tell me this is not an odd game haha.

    I had  a limited amount of time for this because i go in holiday.Now its done was pretty painful even if i kept things simple , especially the debugging.

    Has multiplayer , and one way to capture territories.

    I will continue with this after tournament.

     

    Future plans:

    Ai clients.
    Adding more ways to capture territories.

    Alerts to players so they know they losing teritories.
    Host a single master server for everyone to play.
    Add end game and reset server data or increase the worlds count , ive not decided yet.

    Code cleanup

     

     

    Cheers

  7. Now, I wrote a single script that creates suspension, steer and traction

    You have to create the chassis, 4 wheels, set this script to each one of the wheels and then paly with the configurable parameters.

    Enjoy:

    --[[
    	Autor Juan Ignacio Odriozola (charrua)
    	Purpose:
    		A script that facilitates the making of a simple car
    		all you need is a chassis and 4 wheels
    		assing this scrip to each wheel and set the object chassis
    		then adjust some of the configurable parameters
    
    	Parent: chassis
    	entity : wheel
    	
    	3 joints and 2 auxiliary entities are created the chain is:
    	
    	Parent      Slider            Pivot          Hinge       Pivot        Hinge
    	chassis -suspensionJoint- suspensionPivot -steerJoint- steerPivot -wheelJoint- wheel
    		
    	suspension uses pin 010		(Y axis)
    	steer      uses pin 010		(Y axis)
    	wheel      pin 				(must be set depends of wheel orientation)
    	
    	up/down keys are defaults for forward and backward
    	left/right keys are defaults for steer left/right
    	space key is default for brakes
    	
    	steer velocity and start/end angle must be set
    	suspension lenght must be set
    	wheel friction must be set
    
    	steerAngle set both limits to +/- steerAngle/2
    	if no key (left/right) is pressed then, target angle is 0 : straight
    	suspensionLenght set both limits to +/- suspensionLength/2 and target distance is set to 0
    
    	suspension strength defaults to 1000
    		which is too much strenght for a light weight car (20 of mass) and not to much for a 200 car of mass
    	each joint is created with a mass of 1, which should be taking into accoung
    	(so for a 4 wheels car, you have a mass of 8 on the 8 joints).
    
    	there are so many other parameters that may be adjusted: Spring, Strength, Stiffness ... not too much documented :)
    	
    
    ]]--
    
    Script.currspeed = 0
    
    Script.chassis = nil--Entity "chassis"
    Script.pin = Vec3(0,0,1) --Vec3 "wheel Pin"
    Script.motorspeed=500--float "max motor speed"
    Script.velcontrolled=false--bool "velControl"
    Script.suspensionLength=0.2--float "suspension"
    
    
    Script.steerAngle=90--float "steer angle"
    Script.steerSpeed=100--float "steer velocity"
    
    Script.friction=1--float "wheel friction"
    
    Script.steerPivot=nil
    Script.suspensionPivot=nil
    
    Script.steerJoint=nil
    Script.suspensionJoint=nil
    Script.wheelJoint=nil
    
    function Script:Start()
    
    	local pos = self.entity:GetPosition(false)	--true for global
    
    	if self.chassis ~= nil then
    
    		self.suspensionPivot = Pivot:Create()
    		self.suspensionPivot:SetPosition(pos)
    		self.suspensionPivot:SetMass(1)
    		self.suspensionPivot:SetCollisionType(Collision.None)
    		
    		self.steerPivot = Pivot:Create()
    		self.steerPivot:SetPosition(pos)
    		self.steerPivot:SetMass(1)
    		self.steerPivot:SetCollisionType(Collision.None)
    		
    		--joints creation
    		self.suspensionJoint = Joint:Slider(pos.x, pos.y, pos.z, 0, 1, 0, self.chassis, self.suspensionPivot)
    		self.steerJoint = Joint:Hinge(pos.x, pos.y, pos.z, 0, -1, 0, self.suspensionPivot, self.steerPivot)
    		self.wheelJoint = Joint:Hinge(pos.x, pos.y, pos.z, self.pin.x, self.pin.y, self.pin.z, self.steerPivot, self.entity)
    
    		--suspension
    		self.suspensionJoint:EnableLimits() 
    		self.suspensionJoint:SetLimits(-self.suspensionLength/2,self.suspensionLength/2)	--steerAngle=0 means no steer
    		self.suspensionJoint:SetTargetAngle(0)	--at the middle
    		self.suspensionJoint:SetMotorSpeed(1)	-- 1 m/s
    		self.suspensionJoint:SetStrength(100)	--defatul is 1000
    		self.suspensionJoint:EnableMotor()
    
    		--steer
    		self.steerJoint:EnableLimits() 
    		self.steerJoint:SetLimits(-self.steerAngle/2,self.steerAngle/2)	--steerAngle=0 means no steer
    		self.steerJoint:SetMotorSpeed(self.steerSpeed)
    		self.steerJoint:EnableMotor()
    
    		--wheel
    		self.entity:SetFriction(self.friction, self.friction)
    
    	else
    		Debug:Error("no chassis assigned")
    	end
    end
    
    
    function Script:setMotorSpeed(speed)
    	if self.velcontrolled then
    		--System:Print("setMotorSpeed: "..speed)
    		self.currspeed = speed
    		if speed~=0 then
    			self.wheelJoint:EnableMotor()
    		end
    		self.wheelJoint:SetMotorSpeed(self.currspeed)
    	end
    end
    
    function Script:UpdateWorld()
    
    	if self.motorspeed>0 then
    		self.wheelJoint:SetAngle(self.wheelJoint:GetAngle()+100)
    	else
    		self.wheelJoint:SetAngle(self.wheelJoint:GetAngle()-100)
    	end
    
    	if App.window:KeyDown(Key.Space) then
    		self:setMotorSpeed(0)
    	end
    
    	if self.velcontrolled then
    		if App.window:KeyDown(Key.Up) then
    			self.currspeed = self.currspeed + 10
    			if self.currspeed>self.motorspeed then
    				self.currspeed=self.motorspeed
    			end
    			if self.currspeed == 10 then self.wheelJoint:EnableMotor() end
    			self.wheelJoint:SetMotorSpeed(self.currspeed)
    			
    		end
    		if App.window:KeyDown(Key.Down) then
    			self.currspeed = self.currspeed - 10
    			if self.currspeed<-self.motorspeed then
    				self.currspeed=-self.motorspeed
    			end
    			self.wheelJoint:SetMotorSpeed(self.currspeed)
    		end
    	end
    
    	if self.steerAngle>0 then
    		local direction=0
    		if App.window:KeyDown(Key.Left) then
    			direction=-self.steerAngle/2
    		end
    		if App.window:KeyDown(Key.Right) then
    			direction=self.steerAngle/2
    		end
    		self.steerJoint:SetAngle(direction)
    	else
    		self.steerJoint:SetAngle(0)
    	end
    end

     

    In the other maps i was using a box as a floor to which I set the desired friction, testing this new script i use a terrain and have to figure it out how to set the friction to the terrain...

    Did some searches and ended with:

    local n
    	for n=0,self.world:CountEntities()-1 do
    		local entity = self.world:GetEntity(n)
    		if entity:GetClassName()=="Terrain" then
    			terrain = entity
    			System:Print("terrain found!")
    			terrain:SetFriction(10,10)
    			break
    		end
    	end

    insert this in the app.lua (after load map) and then you can play with terrain friction, the video shows how the car behaves with the defaul terrain friction and then whit a friction of 10,10

    Always learning something new 

     

    A word about some parameters::)

    If you are using a hinge, when you specity speed (SetMotorSpeed) the number means degrees per second. So if you use 3600 as max speed you get 10 revoluions per second.

    If your tire has, 64cm then d*pi aprox 2 meters per revolution, 10 revolutions per secon aprox 20 meters per second... and if you are lucky 72Km/h

    If you are using a slider, then speed is un meters per second. 

    Other parameter which is very important is the hinge/slider "pin" which is a vector that tells the direction of movement of the slider or over which plane de hinges open/close

    For a common door, we need to use the Y axis, so the pin is 0,1,0

    I use this pin for the suspension and for the steer but for this script, you must tell the traction pin, which sould be 1,0,0 or 0,0,1 depending on the orientation of your tires

    If your tires are not facing X nor Z axis, then you have to do some math to get the proper x,z component of the pin

    In the script I use a Strenght of 100, instead of the 1000 which is default, my car is light weight : 5 + 4*3 = 17 of Mass

    chassis has 5, each wheel has 1 and the 2 auxiliary pivots has 1 each one

    whith a friction of 10 on each tire and with a friction of 10 on the terrain looks ok for me (better than I spected at first). 

    Juan

  8. Ok I'm finally done with my obligations to my University as a student. Now it's time to come back to game dev and finish up (hopefully) the Border Recon development. 

    While I was busy in University, I did do a bit of work on the game here and there. I added a spectator feature that allows the players to spectate others in free mode and third person while waiting to respawn after dying. Pretty cool.

    Also, I think some of us have seen the earlier changes with the style of the graphics... I changed the style of the graphics from HQ to just flat pastel colours resulting in a cartoony look in-game. I like it... requires less work on the level design details and it actually looks quite nice.

    Another thing that's cool coming in the next version: soundtracks! I found this cool soundtrack from gamedevmarket website and I think it fits perfectly to the game's theme. I'm going to work on that so I can add a bit of music to the game.

    Link to the soundtrack here: https://www.gamedevmarket.net/asset/brass-attacks/

    Also, I'm working on the muzzle flash feature for the weapons, it's half done now and it looks kick ***.

    Screenshots coming soon!

    Thanks for reading folks!

     

     

     

  9. I have been using Visual Studio Code for a couple of years now and it is my defacto text editor next to Notepadd++. I mainly use it however to write Lua scripts. 

     

     

    Leadwerks extension

    Personally I would love to see it if Visual Studio Code would be the default code editor for Leadwerks (either with 4.x or 5.x). So I got started on working on a custom Leadwerks extension.  You can download it here: https://marketplace.visualstudio.com/items?itemName=aggror.Leadwerks

    Todo list:

    • Done: Leadwerks extension has a dependency on the Lua extension. So this Lua extension is automatically installed when you install the Leadwerks extension.
    • Done: Snippets. Every time you create a new script in the Leadwerks editor, you get a couple of default scripts like Function Script:Start(), UpdateWorld(), PostRender(context). Using a very simple snippet, these kind of functions can be inserted with ease.
      • prop[type] : Creates Leadwerk editor properties
      • print: Shortcut for System:Print("")
      • lescripts: Inserts all entity script functions (commented)
      • class: Creates a basic class objects with example functions
      • start: Start function of an entity script
      • updateworld: UpdateWorld function of an entity script
      • updatephysics: UpdatesPhysics function of an entity script
      • collision: Collision function of an entity script with all parameters
      • PostRender: PostRender function of an entity script with the context parameter
      • function: Creates a function for either a custom object or for the specific script
      • if
      • for
      • pair
      • ipar
    • For instance: just type 'col' followed by 1 tab and you get: 
    • function Script:Collision(entity0,entity1,position,normal,speed)
      
      end

       

    • Partially done: Supporting intellisense (sort of) with Leadwerks entities.
      • Lua is a typeless language (not a strong typed language), which makes intellisense not really possible. 
      • VS code is smart enough to recognise some functions that are available in your script, but it is not as complete as when you would work with C# or C++.
      • Done: Generate snippets for the entire Leadwerks API. 
        • Snippets are created per object and a second one without the object. For instance
          • Entity:SetPosition()
          • SetPosition()
        • TODO: Classes with parents, would require matching functions. For instance: a pivot is an entity and thus requires Pivot:SetPosition()
      • Done: parameters into placeholder slots.
      • If I can extend the intellisense so that it recognises Leadwerks entities, perhaps we could see correct variables and functions of those entities.
    • TODO: Loading in the API documentation in a split screen. 
      • The API documentation is written in an XML format which I can retrieve in VS code. I can display it in a splitscreen. 
      • I would have to play with the styling a bit but in general this should work really fast
      • API documentation can be cached if in online mode. Documentation could also be periodically fetched. Moving the API documentation to Github would help improve this process. (newer file versions etc)
    • Debugging
      • Josh stated that he is getting someone to make this for him. So fingers crossed. :)
      • The biggest issue at the moment is the lack of debugging support. Visual studio has debugging options of course, but it can't communicate with the Leadwerks editor.
      • If you have an error in your script while running from the editor, the default Lua editor is opened. :(
  10. Hi,

    the last weeks in office are very bussy. But today i have some time to work on my project.

    In Akt 3 i  would imlement a Mortar.

    I found a nice free model that i rework in blender and exported as mdl file

    also i searched for some sounds and mixed them together.

    For the sound i use "Audacity" becaus i get some errors in leadwerks with this sound i converted sounds with "Audio online converter"

    then i work on the scirpts.

    i use some parts from einlanders grenade script. and changed the projectile script and saved it to Mortal Ammo script.

    at the moment it is a little buggy and i dont know what i have to chage. i think the problem is in this part:

                                            if bullet~=nil then												
                                                    bullet:Show()
    												bullet:SetFriction(10000,10000)
    												bullet:SetCollisionType(Collision.Projectile)
                                                    bullet:SetPosition(self.muzzle:GetPosition(true),true)
                                                    bullet:SetRotation(self.muzzle:GetRotation(true),true)
    												bullet:SetMass(1)
    												Force = Vec3(0,3000,0)
    												bullet:AddForce(Force)
                                                    if bullet.script~=nil then
                                                            bullet.script.owner = self
                                                            if type(bullet.script.Enable)=="function" then
                                                                    bullet.script:Enable()
                                                            end
                                                            bullet:Turn(Math:Random(-3,3),Math:Random(-3,3),0)

    the bullet is not always transformed into an explosion when it hits the ground. If it hits the player, then it always works.

     

    here is the result. Sometimes it is funny how crazy the bullet goes. But now i have to look video with my daughter so i will work later on it. :D

    if anyone knows how i align the force at the distance of the player, about help or hints i would be glad.

    Also on a note why the bullet does not always explode on the ground, I would be glad. As always sorry for my english. By the way Act 3 is progressing. Below are a few pictures.

     

     

    screenshot61.jpg

    screenshot62.jpg

    • 1
      entry
    • 1
      comment
    • 563
      views

    Recent Entries

    tjheldna
    Latest Entry

    My latest entry for the Leadwerks Tournament "Dwarf Beard". This entry is really the product of a merge of a lot of work I have done over the many years.

    The code template I used goes all the way back to my first game created in Leadwerks "Mages Alchemy". The Template has seen many iterations, updates as my skills increased or I just work out a more better way of doing things. For this tournament I've made many new improvements focusing on character controls, AI and handling animations. Making both of those changes has really made the character code manageable and readable which was my focus coming back to this code from not looking at it for over a year and re-understanding it.

    Artwork taken from various graveyards of projects.

    Its playable now after a few tasks in particular are complete i'll upload the project. For now here are some action screens.

    db1.png

    db2.thumb.png.85f67e2d76854bc5746b887b167fe2cb.pngdb3.thumb.png.0a204843d33ca019f43a5e2380acfb44.pngdb4.thumb.png.85b343726981ce39d7d3469db9511db7.pngdb5.thumb.png.d3e06a4552fcd2d24d801a9a3b5f53e1.png

  11. Having a good set of tools is highly important. Just ask any mechanic. A good set of tools can save you a ton of time, just to prove this, try changing a water pump with a crescent wrench.

    The back story...
    There is some sort of issue with my project in GIT from the windows perspective in which it doesn't let me add source files to GIT without using the -f option. The last few months of development I haven't been creating "new" things, just working on content. This means that my new changes didn't make it into my version control


    I just recently switched to linux as my main OS. I got tired of the instability with windows. With this I started converting my Visual Studio project in to a CMake project, since that's what CLion supports.


    While working on a CMake file I wanted to test a compile change, so I decided to "make clean".

    Well some how "make clean" removed all my source files.

    Since I forgot to add a few source files to my GIT repo manually (the stuff I have been working on for the last 2 months), I was in panic mode. Researching tools in Linux to undelete a file was also difficult.

    CLion to the rescue!


    Luckily I started up CLion on my project as I use the Jetbrains Suite at work, I figured I should also try it at home. CLion maintained its own local history of my project. With a few clicks of the mouse I could go back and undo the delete.

    So for any of you making games in a commercial sense, maybe $650 for a good IDE is a small price to pay for saving your *** some day

  12. I have made a small class for helping with reading and writing parameters between C++ and LUA and also calling LUA functions from C++. I'm sharing this little thing here.

     

    blogentry-395-0-01293300-1488719654_thumb.png

     

    Using the class is quite simple as shown below

     

    LUA - part

    blogentry-395-0-18534700-1488720057.png

     

    C++ - part

    blogentry-395-0-59572000-1488719924_thumb.png

     

    I have included is a test project which looks like this in the editor

    blogentry-395-0-25132300-1488720141_thumb.png

     

    And like this when executed

    blogentry-395-0-63899000-1488720151_thumb.png

     

    Here is the LuaBridge class source

    LuaBrigde.h

    LuaBrigde.cpp

     

    And the complete test project

    LuaBridge.zip

     

    Note: Its says 'Click for next test', should be 'Hit Spacebar for next test'

  13. There is a problem with the default TextArea.lua widget script.
    Your game will crash when you click on an empty TextArea.

    Fix:
    look for the Function "Script:GetCaretCoord(caret)"
    after:

    local text = self.lines[self.currentline]--self.widget:GetText()

    add:

    if text == nil then return 0 end

     

     

    More will be added when/if discovered...

  14. Hello Leadwerks Forum its me again. The guy who releases too early

    Theres going to be a new game inspired by the Polybius pasta in the player soon. I just wanted to explain the core mechanics of the game and why it is more important than my free time. For some time, I have developed games on other Engines but the tournament got me back to my haven again ,where I am the most confident with my skills. This is why I can try new or more absurd game Ideas like an "intense psychoactive and addictive" effect provoking retro game. But with less focus on the "psycho" and more on the caffeine effect :D. Of course I run into problems because leadwerks is not made for this wireframe look or twodimensional games, so I dropped it already :(... Just kidding, (no really I did but troughout the day more fixes came to my mind) - like using transparent images for rendering them instead of trying to make a skybox background which itself is also wire... you get the idea.

    59e0fc1da32aa_giphy(1).gif.0ba2fcd3fab046c461757a3b5e4bf731.gif

    THE GAME !:

    The game is split into multiple minigames.All have the feeling of an arcade or retro game from the 80's , but who am I to know how they really were like :). For example, if you "loose" at one of these, it automatically switches to the next endless minigame which gets harder and harder with more movement and colors. One of these games, which will hopefully playable at the end of the tournament is almost done to its core. Its an wormhole simulator in which the player travels with a spaceship and needs to gather blue cristals which differ from other objects that you are not allowed to hit: (outdated)

    9F442C6E36C3D82450A949988A8D434FFF524E09

     

  15. Restarted my networking framework yet again. This time I gave it a new name 'Hexe'. The old name was 'Overwatch'. It was named long before the Overwatch game came out. It was based off the Half-Life Overwatch. It oversaw the players, ai spawning, contained a secondary path-finding system, but had no networking as it was not native to the LUA side of Leadwerks. 'Hexe' is German for 'witch'. I don't really know why I chose the name but I have the feeling I will be able to put it to good use. Maybe I'll even mix in some Anglish into it.

    This restart occurred because the framework became too cumbersome. I had the entity synchronization working correctly, but it did not differentiate between player and an object in the world. That wasn't really that bad, what made messed it up was that a lobby system and teams were needed and there was no space to squeeze any other components into the mix.

     This rewrite will focus on the player/client and foremost. The components that are currently being written or are complete are:

    • The server browser.
      • This was a side project created out of necessity. I did not want to have to hard code the ip every time.
      • Anytime I wanted to test multiple clients I had to change the code depending on which computer was running the server. 
      •  PITFALL: Since Leadwerks does not expose the servers local ip address via code, you will need to get it manually from you computer, or use some creative workarounds
    • Network Manager
      • Hexe is split up between a server class and a client class. Both classes use a network manager class that can automatically handle hosting or connecting to a server. The network manager currently handles the handshake and the beginnings of the lobby system.
      • When a client joins it initiates and handles the handshake between the server and client. It also raises events so the server or client can react accordingly if need be. After the handshake is completed, the network manager starts the lobby system
    • The connection handshake.
      • This is was saved from the last version. It makes sure the server and client are using the same protocol version. It will then register the client on the server and give it an incremental number (similar to the source engine) that allows the client state to be manipulated    
    • The Lobbying system:
      • This is completely new. After the handshake is complete, it will send a command launching the lobbying system. The network manager only makes sure that a client is in the servers lobby and nothing more. The client and server manually handle the team creation and player switching on their own.
      •  Teams are not part of the network manager because it would require large amounts of rewrites depending on the type of game being created.

    When the lobbying system is complete the client input will be added. So far things are going well and maybe soon I wont be staring at console output for feedback.
     

  16. GorzenDev
    Latest Entry

    Finished and added Field functionality meaning its now possible to set the Fields for each widget.
    for example the style for a button (Push,Link,Checkbox), or backgroundcolor for panels etc.

    below is a screenshot of the fields in action
    guieditor_prev4.thumb.JPG.b6841efab04c2ef17284105bf42ed76a.JPG

     

    Next will be finishing support for custom widgets which i already started on as you can see in the screenshot above(colorlabel).

    At the moment the way to add your custom widgets is a 3 step process.


    First step is adding the widget name to the config.ini like

    [DefineTypes]
    CustomTypeCount=2
    name_0=ColorLabel
    name_1=MultiListView


    Next is adding a type_file with content like so

    [Base]
    name=ColorLabel
    ;allow other widgets to use this as a parent
    allowparent=false
    ;allow addItem
    islistType=false
    ;location of the widget script in your leadwerks project - only used while exporting
    wScript=Scripts/GUI/ColorLabel.lua
    ;location of the widget script for this editor
    eScript=ElementTypes/Custom/Editor/editorColorLabel.lua
    ;default size
    defWidth=80
    defHeight=20
    ;amount of 'extras' defined
    dCount=6
    [Define_0]
    name=align
    type=String
    [Define_1]
    name=valign
    type=String
    [Define_2]
    name=wordwrap
    type=Bool
    [Define_3]
    name=border
    type=Bool
    [Define_4]
    name=bordercolor
    type=Vec4
    [Define_5]
    name=textcolor
    type=Vec4


    And last but not least you need to edit a copy of your script and disable any EventQueue::Emit events,
    and add some mouseMove,mousDown,mouseUp events for the editor to interact with the widget.

     

    So a custom widget colorlabel would look like this when exported.

    //GUI Editor Generated
    #include "MenuClass.h"
        
    MenuClass::MenuClass(Context* context)
    {
        gui = GUI::Create(context);
        
        //Panel
        Panel = Widget::Create("", 0, 0, 1024, 100, gui->GetBase(), "Scripts/GUI/Panel.lua");
        Panel->SetAlignment(false, false, false, false);
        //Button
        Button = Widget::Create("Template", 81, 38, 150, 20, Panel, "Scripts/GUI/Button.lua");
        Button->SetAlignment(false, false, false, false);
        //Button1
        Button1 = Widget::Create("Template", 338, 38, 150, 20, Panel, "Scripts/GUI/Button.lua");
        Button1->SetAlignment(false, false, false, false);
        //ColorLabel
        ColorLabel = Widget::Create("colorlabel", 710, 39, 80, 20, Panel, "Scripts/GUI/ColorLabel.lua");
        ColorLabel->SetAlignment(false, false, false, false);
        ColorLabel->SetString("align","Center");
        ColorLabel->SetString("valign","Center");
        ColorLabel->SetBool("border",true);
        ColorLabel->SetObject("bordercolor", new Vec3(1,0,0,0));
        ColorLabel->SetObject("textcolor", new Vec3(0,0,1,1));
        //Panel1
        Panel1 = Widget::Create("", 342, 328, 300, 200, gui->GetBase(), "Scripts/GUI/Panel.lua");
        Panel1->SetAlignment(false, false, false, false);
        Panel1->SetObject("backgroundcolor", new Vec3(0.2,0.2,0.2,1));
        //Button2
        Button2 = Widget::Create("exit", 80, 156, 150, 20, Panel1, "Scripts/GUI/Button.lua");
        Button2->SetAlignment(false, false, false, false);
        //Button3
        Button3 = Widget::Create("options", 77, 98, 150, 20, Panel1, "Scripts/GUI/Button.lua");
        Button3->SetAlignment(false, false, false, false);
        //Button4
        Button4 = Widget::Create("load", 76, 33, 150, 20, Panel1, "Scripts/GUI/Button.lua");
        Button4->SetAlignment(false, false, false, false);
    }
    MenuClass::~MenuClass()
    {
        Button4->Release();
        Button3->Release();
        Button2->Release();
        Panel1->Release();
        ColorLabel->Release();
        Button1->Release();
        Button->Release();
        Panel->Release();
        gui->Release();
    }
    //
    bool MenuClass::ProcessEvent(Event event)
    {
        if (event.id == Event::WidgetAction)
        {
            //
        }
        return true;
    }
    //
    bool MenuClass::Update()
    {
        return true;
    }


     

  17. In my other blog (https://www.leadwerks.com/community/blogs/entry/1908-top-10-celebrities-who-use-component-architecture/) I talked about the component architecture I was using. I've since teamed up with Roland on this idea and together we have fleshed it out more. It's not 100% ready to be released yet but I realized that we've come a long way and that where we are today might seem confusing to someone if they weren't along for the ride. So I thought I'd use this blog to start down the journey we went on.

    The main goal for our journey was as follows:

    - Components will NEVER depend on other components. Decoupling as much as possible was priority #1. So the idea of events and actions(functions) is still at the core of the system. Now components need to work together obviously but the lowest level of dependencies the system has is via the arguments that events send along to actions. If you're hooking an action to an event you need to know what args that    event is sending you. This is primitive data vs classes and it's as decoupled as you can get while still allowing interactions between components.
        
    Coroutines!

    One day Josh asked about coroutines and if anyone knew anything about them. I've used coroutines in the past so I replied and did some examples (still need to finish that for him). Then one day on my way home from work it hit me. Since we have a common communication method in having actions (functions) being called from events we had a centralized place where all component actions (functions) were being called (the event class). This meant incorporating coroutines into our system was simple. Thanks to Roland for fleshing the idea out, all component actions are now coroutines automatically created (no work on the component creator's part). This was very exciting as it meant action functionality that required sequential coding could be done right in the action directly. This helped eliminate the need for most components needing an update() method that might not be doing anything except in certain situations. Situations that are now all handled in an action itself. It also meant a lot less state variables were needed to manage this sequential code. Roland had a doAddHealth() action where he instantly added the value passed in to the players health. This resulted in a snapping of the UI to the new health value. While that clearly works and you can do it that way, the test of our system was to make that health slowly increase to the final value over time, giving it a nice visual animation of increasing health. We were able to do it directly in that doAddHealth() function with about 2-3 more lines of code. It was insanely easy and much more logical in nature. Roland had never used coroutines before and he was able to get it working in a couple mins because it's just very logical and intuitive to work with when you don't have to deal with the details of the coroutine setup and management. You simple work with coroutine.yield() inside your action and that's all you really need to understand. This is an idea I'd like to see Josh think about with normal LE script functions as I think it can make life easier. Tim and I are working on a turn based game. Everything in the game is basically a sequence of actions over time so this idea of all actions are coroutines has been HUGE for our game. More on that at the end of Aug.

    Entity to Entity Communication!

    We fleshed out the entity to entity communication. My last blog talked about component communication with other components inside the same entity (the event system). This works great because all the components are inside the same entity and can access each others events and actions to hook up. But how can a component in entity A do something because a component in entity B wants it to, without those components knowing anything about each other? It was a challenge to get the right idea for this. We wanted to stay with the idea of events for this but we also didn't want entities to know about each other's internals.Decoupling of entities is important or else you end up with dependency hell and tigh coupling. We ended up with giving entities a SendMessage() function and an onReceiveMessage event. So from entity B we can hook up one of it's components events to the entity action SendMessage. The arguments for these required 2 special variables. Dest and Message. Dest is the entity to send the Message to. To get the Dest entity you're component is doing some kind of picking or GetNeighbors(). Dest can be 1 entity or a table of entities. On the receiving entity(s) the onReceiveMessage event is raised so that you can hook it's component actions to a received message. So all communication is done via the event system in some way.

    This introduced 2 needed features to our event system. When you get an event onReceiveMessage is raised no matter what event you got. However you'd only want certain events to trigger certain component actions. This requires some kind of routing of string messages to actions being called. We did this currently with a filter function on the event's subscribe() method. When the event is raised and a filter function exists it'll call the function passing in the arguments of the event and if the function returns true, raise call the action method. If false it wont call the action method. So generally what you do is pass a function that checks the args.Message for the value you want to call the action.

    self.onReceiveMessage:subscribe(self.healthComponent, self.healthComponent.doHurt, function(args)
            if args.Message == "hurt" then
                return true
            end
            
            return false
        end)

    In the above event hookup when the Message is "hurt" then we hook it up to our healthComponent doHurt action. Because this is a very common thing to do, it can be bloated to have to define the function that does exactly this but for different string messages, you can just pass a string instead of a function to make it more streamlined:

    self.onReceiveMessage:subscribe(self.healthComponent, self.healthComponent.doHurt, "hurt")

    As you can see communication is NOT done inside the component. We didn't want components handling communication. We view component functionality and how that functionalty is communicated as 2 different types of coding. Communication is done inside the event hookups and functionality is done inside the component. Because of this and staying with the SendMessage/onReceiveMessage idea, we introduced another idea to the event subscribe() function. Another callback that is called before the action is fired. This also passes in the args and exists to let you modify the args before the action is called. This is used mostly when hooking a component event to SendMessage so that at that point you can give the string Message value. This way the component itself isn't concerning itself with the message which helps keep it more generic. This makes communication implementation specific to YOUR game and not the component. The component is just doing it's ONE job and raising events. That's it. What that means to your game is up to you to code. An example of this is:

    -- nil is the routing/filter function we talked about above which we don't need because we are sending out not receiving in
    self.inputComponent.onPicked:subscribe(self, self.SendMessage, nil, function(args)
            args.Message = "use"
        end)
    

    The inputComponent will raise an onPicked event when an entity is picked by left clicking. It doesn't care what you want to do with that. That's your part of coding your game and is game specific. It will fill in the args.Dest value with the entity but we need a place outside the component to specify what we want our message to be for our game. The supplied function does just that. It let's us create the Message variable on the args and fill it in. On the receiving side then it's up to us to hook up to that entities components when the message is "use" like above in the onReceiveMessage examples. This idea of 2 types of coding I think really helps create more separation and isolation of code which helps with maintainability and reusability. If components were to define the Message value inside then their influence starts to leak out as another component needs to be programmed to deal with that exact Message. We don't want that. We want the messages to be game specific and decided on by the user of the component system not the component creators. There is an alternative syntax to the above code where instead of a function you can specify a table. This table will be merged into the args parameter.

    self.inputComponent.onPicked:subscribe(self, self.SendMessage, nil, { Message = "use" })

    So to summarize entity communication, when sending messages the arguments callback function (or table that gets merged) is useful. When receiving messages the filter/routing callback function (or string message) is useful.

    Cool Side Effects!

    And interesting side effect to to the event system is that they are raised in the order they were subscribed to. You can use that to your advantage if you want to modify the args in any way between multiple components. Tim and I use this concept in our game. When we get a "hurt" message come into a character entity we first pass it through a Stats component which stores information about the player armor and other defenses. The args has a value property on it that is how much damage we should take, but by first running through our Stats component we can reduce that value by our armor. The 2nd component it's hooked up to is the health component which will reduce our health by the value property but now it's less because our Stats component reduced it. Since args is a table and tables are passed by reference the change to an args property in one component is visible to subsequent components.
     

    Summary

    Having a common communication protocol between components and entities has been a big help in structuring my code for maintainability, adding new features, and reusability. One of the benefits of Lua is that table properties can be accessed via their string name. So something you might notice about event hookups to actions given knowing that Lua table properties can be accessed via string names, is that hooking up events is really just configuration. Even though the above examples is code that code can be made very generic where the property names are string values stored in a file. For example the above inputComponent hookup is the same as:

    self["inputComponent"]["onPicked"]:subscribe(self, self["SendMessage"], nil, { Message = "use" })

    Because it's a common structure all event hookups follow the same pattern. So imagine this information is coming from a json file and that json file is built from a visual editor. You would code your components in a code editor but hookup your components in a visual editor as you select the event source, event, action source and action from drop down menus. Thanks to Roland, we will have more to come on that in the next few months...

     

    • 2
      entries
    • 13
      comments
    • 3046
      views

    Recent Entries

    Mattline1
    Latest Entry

    Main post available here

     

    I first presented my PBR work about a year ago, since then I've been tweaking and making improvements.

     

    Over the past 6 months Leadwerks has had some great updates for graphics junkies like me tongue.png .The HDRi and environment probe features look great and have helped with 2 of the main issues with the last PBR system. Now what you see in the editor is what you get in the game, and HDR means proper tonemapping and a wider range of possible light intensities. Both of which are important for realistic PBR.

     

    I currently plan on using this for my current project, so expect consistent updates as I battle test it.

    The current build is available on github. Any issues and suggestions to help improve it are welcome.

    Sponza.jpg

     

     

     

     

     

    Limitations / improvements

    • Requires a gamma-correction post process shader. Not a huge issue, adding a pp is pretty easy but still something to remember.
    • Currently the built in environment probes are stored in a low dynamic range. This leads to clamping and precision errors as HDR values move towards extremes. this limits the usefulness of HDR. This is an engine issue.
    • Probes also use simple mipmapping for different roughness values, PBR often performs a convolution on stored cube-maps to better match reflection blurring due to roughness. A fix may be possible for this, but would require C++.

     

    Racer.jpg

    </p>

  18. Hi! It has been a while. Here's an update on my networking library EvayrNet which is available for C++ users of Leadwerks:

     

    While implementing it into the test project in Leadwerks, I saw that the use case had some flaws which made it really hard to debug what's going on. I figured that I should be spending some time on fixing some flaws. After a few weeks I came up with the following upgrades:

    1. Debugging class
    2. Simulation mode
    3. More debugging information available

    Here's some detailed explanation:

     

    Debugging class

    I was using a lot of "printf" before which made it hard to:

    • Find out where it's being called
    • Disable whenever I don't need it anymore

    This is when I decided to make a debugging class. I replaced the printf with a custom Print function which allows you to do the same as before - except you can disable any kind of printing whenever you want (like during release builds).

     

    I also realized that capturing data is a pretty cool feature to have, which makes it easier to visualize the data you want to debug. For that I created a SaveText function which accepts a string and a filename as arguments so you can separate data like "Pings per interval", "Bytes sent per second", etc.

     

    Here is an example what you can do with it:

    blogentry-358-0-42708300-1490806770_thumb.png

     

    Simulation mode

    This is an interesting one that I just had to implement. A connection cannot always perfect, and it can be hard to always expect a good outcome (while you might not notice it because of your tests on localhost). This is why I introduced the manipulation of the following networking stats:

    1. Minimum latency (in ms)
    2. Random latency (in ms)
    3. Packet drop percentage
    4. Packet duplication percentage

    It's also very easy to activate and deactivate. All you have to do is NetworkManager::StartSimulation(...) and StopSimulation(). Here is it in the command line when you activate it:

    blogentry-358-0-27976100-1490807270_thumb.png

     

    More debugging information available

    At last I added more ways to debug the network statistics to really see what is going on. Are you not receiving data anymore? Are you flooding the network? The following information is now ready to be displayed:

    • Newest ping (either to the server or from a specific client)
    • Average ping (this as well^)
    • Incoming amount of packets per second
    • Outgoing amount of packets per second
    • Packets per second lost
    • Incoming data per second (in bytes)
    • Outgoing data per second (in bytes)
    • Current active connections (primarily for the server)

    That's... quite a lot more than before! Previously you could only see if you're connected and if you're the server. I hope this information will make it easier for users to visualize traffic and debug any problems they might be having. And of course, you can mix this up with the debugging class to make cool graphs like above!

     

    Final words

    I'm still planning on making some extra information, like on specifics to see what kind of message is creating the amount of bytes send/received. This should help debugging even more. Other than that there are still some enhancements I'd like to put in such as encryption. These can be seen here.

     

    I hope you liked this blog post! Next time I will probably be showing how to implement EvayrNet into your C++ Leadwerks project, so you can toy around with it. wink.png

    • 2
      entries
    • 7
      comments
    • 1239
      views

    Recent Entries

    aiaf
    Latest Entry

    Ive decided to plan better and fix milestones so i can actually finish this game, the main problem is lack of time.But i have patience.

     

    I got a domain and in the process to setup a website and a blog.The plan is to have a small release every 15 days.

    Will see how it goes, it would be nice to work full time on this but not possible at this time, still have to go to work for a living.

     

    Currently im about to finish a somewhat starcraft like resource gathering mechanic.

    A mine has a 1 transporter that gather resources from asteroids.

    I limited to just 1 resource transporter per mine so that the user has incentive to expand (build mines) for more resources.

     

    Will come back with a movie.

     

    For development stuff i want to say Object::GetAddress method is great.

    Besides the debugger, really helped to investigate some strange crashes.

     

    http://www.leadwerks.com/werkspace/page/api-reference/_/object/objectgetaddress-r26

     

     

    Cya

  19. blog-0568459001486305707.jpg

    One More Day - Performance Updates

     

    So it’s been a while since my last blog update on One More Day but recently I had a look to see if I could do anything with improving the performance of the game. As it turns out there were still some optimisations to be made that have helped boost performance.

     

    V0.1.6 on the Game Launcher

     

    Here are the main performance related changes I’ve made which were recently published to the Game Launcher:

    1. I changed some of the furniture models to lower poly versions. Some of these models were about 3000polys and are now replaced with lower poly versions with no real visual difference in-game. So about 10 or so models that were repeated more than once around the level were shaved in poly detail by about a third.
    2. I halved the draw distance on camera range and increased the fog a bit to compensate. I believe this helped more for when you are some distance outside the town but less so when you are in the town.
    3. I removed some rogue geometry in the map (wasn’t much), and also a few objects that weren’t really needed.
    4. I went back over every object to ensure it’s viewing range was as minimal as I could afford without creating too much pop-up. This is something I have always done but still sometimes you end up missing a few things.
    5. I spaced out some detailed areas on the map (ie. the power station got moved out further) to try to reduce the number of objects being shown at any one time.
    6. I made sure physics shapes set in model viewer were as simple as possible and removed collision from some small objects.
    7. I removed some workshop objects that had very big textures.

     

    All these changes stacked on to the latest version of Leadwerks which also includes performance improvements have given a noticeable performance improvement to the game.

     

    One thing I had to add in (sparingly) was some grass using the vegetation system as I felt it added nice detail to the level and was worth a small performance hit. That’s what makes optimising the game hard, trying to balance between good visuals, content and good performance. Unfortunately sometimes sacrifices have to be made. But even with the grass added the new version is running better than before. I would like to add volumetric spot lights for light coming in the windows but for now I resist that temptation as they would add up to a significant performance hit. Maybe I will add them as a high graphics option in the future.

     

    Other Improvements

     

    As well as performance improvements the game download size is now smaller thanks to the newly added ogg support and also removal of some unused files that were being published. One thing I noticed when publishing a game in Leadwerks is that if you have files with the same filename in two different folders both files will be packaged even if only one of them is used. So there were some unneeded texture files etc. being packaged from unused workshop content. Going forward I will have to keep an eye out for duplicate filenames.

     

    More performance in the works

     

    The following changes are in my current dev build which hasn’t been released yet but are showing even more performance increases:

     

    1. Converted the CSG houses and bungalows to models. Simplifying and reducing object/entity count. This should allow me to add more houses to the map with less of a performance impact.
    2. Further reduced the camera range and increased the fog to compensate. This allows me to reduce the view range on many bigger outdoor objects and buildings from Max to Far whilst minimizing popup and also reduce the vegetation view range. This will result in a much more foggy look to the game (see screenshot) which will create a slightly different atmosphere than previous versions and with less viewing distance it might make approaching zombies a bit more dangerous.
    3. I identified SSAO was making quite a performance impact so I have disabled this for now and might re-introduce it as a high graphics option when I get around to creating an options menu. For outdoor map SSAO is probably not as important or worth the hit but it is nice to have when inside the buildings.

     

    After all these performance improvements and v1.7 is released I am optimistic that most people should get at least a 30fps game experience with OMD. Fingers crossed!

×