Blogs

Our community blogs

  1. Leadwerks Game Engine 5 is being designed to make use of shared pointers.  This eliminates manual reference counting, which has probably been the most difficult part of programming games with Leadwerks.  Here are three concepts you must understand before you start using smart pointers in Leadwerks 5,

    Don't Create Multiple Shared Pointers from One Object

    When a shared pointer goes out of scope, it deletes the object it references.  If another smart pointer was created separately that references that object, the other smart pointer will now point to an object that has been deleted!  Set breakpoints in the example below and you will see the problem.  The object is deleted while the second smart pointer still references it.  Any attempt to use the second smart pointer will cause an error:

    class Thing
    {
    public:
    	~Thing();
    };
    
    Thing::~Thing() {}// <--------- set a breakpoint here
    
    int main(int argc, const char *argv[])
    {
    	Thing* thing = new Thing;
    
    	shared_ptr<Thing> p1 = shared_ptr<Thing>(thing);
    	shared_ptr<Thing> p2 = shared_ptr<Thing>(thing);
    
    	p1 = nullptr;
    	int k = 0;// <--------- set a breakpoint here
    }

    Instead, initialize a smart pointer once and copy it.  Here is the correct way:

    class Thing
    {
    public:
    	~Thing();
    };
    
    Thing::~Thing() {}// <--------- set a breakpoint here
    
    int main(int argc, const char *argv[])
    {
    	Thing* thing = new Thing;
    
    	shared_ptr<Thing> p1 = shared_ptr<Thing>(thing);
    	shared_ptr<Thing> p2 = p1;
    
    	p1 = nullptr;
    	int k = 0;// <--------- set a breakpoint here
    }

    It's even better to eliminate the new keyword entirely and create object and smart pointer in one step:

    class Thing
    {
    public:
    	~Thing();
    };
    
    Thing::~Thing() {}// <--------- set a breakpoint here
    
    int main(int argc, const char *argv[])
    {
    	shared_ptr<Thing> p1 = make_shared<Thing>();
    	shared_ptr<Thing> p2 = p1;
    
    	p1 = nullptr;
    	int k = 0;// <--------- set a breakpoint here
    }

    The point is, you create the first smart pointer and thereafter all code should pass that around.  You never need to access the pointer directly.

    Of course the use of auto makes everything a lot simpler:

    auto p1 = make_shared<Thing>();
    auto p2 = p1;

    Parent / Child Relationships

    If you have an object that is some kind of "child" of a parent object, you probably want that parent to keep a smart pointer to the child that keeps the child from being deleted.  However, if the child has a smart pointer to the parent you are creating a circular reference that will never be deleted from memory.  Think of the parent as the owner of the child.  Something other than the child must keep the parent in memory, but sometimes the child wants to retrieve the parent object in a bit of code.  Therefore, for the child member we will use a shared pointer, and for the parent member we will use a weak pointer:

    class Thing
    {
    public:
    	shared_ptr<Thing> child;
    	weak_ptr<Thing> parent;
    	~Thing();
    	shared_ptr<Thing> GetParent();
    };

    The GetParent() function would look like this:

    shared_ptr<Thing> Thing::GetParent()
    {
    	return parent.lock();
    }

    You can modify existing functions that access a parent by adding one line of code.  Here is one such function as it would appear in Leadwerks 4, where the parent member is just a regular old stupid pointer:

    void Thing::AccessParent()
    {
    	if (parent != NULL)
    	{
    		//do some stuff to parent here
    	}
    }

    The updated version for Leadwerks 4 creates a new shared_ptr<Thing> variable (with auto) and locks the weak pointer to make a shared pointer.  The rest of the code works seamlessly:

    void Thing::AccessParent()
    {
    	auto parent = this->parent.lock();
    	if (parent != NULL)
    	{
    		//do some stuff to parent here
    	}
    }

    Class Functions Should Never Returns Themselves

    The following code illustrates a problematic issue:

    class Thing
    {
    public:
    	shared_ptr<Thing> GetSelf()
    };
    
    shared_ptr<Thing> Thing::GetSelf()
    {
    	return shared_ptr<Thing>(this);
    }
    
    int main(int argc, const char *argv[])
    {
    	shared_ptr<Thing> p1 = make_shared<Thing>();
    	shared_ptr<Thing> p2 = p1->GetSelf();
    }

    The GetSelf() function creates a new shared pointer that has no relation to the first one.  Both of these shared pointers will attempt to delete the object when they go out scope.  Only one will win. :blink:

    I did a search throughout the entire Leadwerks Engine project and found only three instances of the phrase "return this;".  The easiest way to fix this problem would be to eliminate this type of behavior altogether by having a parent get the object instead of the object returning itself.  For example if you have a recursive function that is structured like this:

    Thing* Thing::FindChild(const std::string& name)
    {
    	if (name == this->name) return this;
    	for (auto it = kids.begin(); it != kids.end(); it++)
    	{
    		auto child = (*it)->FindChild(name);
    		if (child) return child;
    	}
    	return NULL;
    }

    You can restructure it like this:

    shared_ptr<Thing> Thing::FindChild(const std::string& name)
    {
    	for (auto it = kids.begin(); it != kids.end(); it++)
    	{
    		if (name == (*it)->name) return this;
    		auto child = (*it)->FindChild(name);
    		if (child) return child;
    	}
    	return NULL;
    }

    I considered deriving all complex objects from a "SharedObject" class with a weak pointer that referenced itself:

    class SharedObject
    {
    	weak_ptr<SharedObject> self;
    };

    However, this requires the "self" member to be set when the object is created and is tedious to use.  I think it's easier to just eliminate functions that return the object itself.

  2. Loading.thumb.jpg.53bedf3a49316884138ce8b6bba063d1.jpg

    Now to finish today, we see what is the loading screen of the first level. The idea is that between loads of levels, a different image is displayed. I do not have much to say, you use DrawRect, a variable increases the size of another DrawRect, and you do a dirty trick so that in a certain value the map is loaded.

    Sun 1.

    Good night.
    
    
    
  3. I work really hard on my new projekt. With the next Event from Josh i would show the first Alpha.

    Meanwhile, I can also program more in LUA. I am really happy because i modified Hancinators "MeleeScript" with patrols. I put in a search function so the NPC continue his Path if he lost sight to you. Also i programmed a "Effect Script" so the NPC make "something" if the Effect is "true"

    Also i try to voiceacting but this is in test at the moment   (Jorn is busy at the moment ;) )

    Here are some pictures

     

    Edit: If someone knows how I get the ammunition bar behind the Hud, I would be grateful for help here.

    20170819151915_1.jpg

    20170819153707_1.jpg

    20170819153725_1.jpg

  4. I've still got a lot to do before releasing a playable Alpha version of the game but I'm getting there fast. Below is the actual to-do list, in its rawest form, of tasks that I have to do to complete the early version of the game, some are yet to implemented and others are to be refined.

    I go through a maximum of 5 items on the list everyday. I cross out the items that I complete with a purple marker, it's satisfying to be able to do that once in a while.

    hwROMh6.jpg

    On the other note, some of the things I have been working on the game recently (as you can see on the paper, the marked items) are:

    1. I have fixed a bug in-game that corrupts the settings file when the player presses "Apply Configuration" button found in the settings page in the Pause Menu.
    2. I have implemented resupply stations where players can resupply and replenish their ammunition.
    3. Player movements are stopped when they open the scoreboard, class menu, equipment list, or chat box.
    4. I adjusted the view settings - the character model is not fully shown in front of the screen.
    5. Refined the text anti-alias on all of the menus.
    6. I have started working on the map "Border Town" and I've tweaked the character material settings - increased spectacular, added roughness, and a bit of metalness to emphasized the creases in the player model's clothing adding detail to the overall character instead of just a bland camouflaged colour. Ideally, a cell-shader would have done the job quite right but that's not available to me right now.

    Screenshots: Improved anti-alias on texts on the menus, tweaked character clothing material (increased roughness and metalness to emphasize clothing detail):

    VSKZaAx.jpg

    sYYRWzy.jpg

    There will be more updates to come soon. Don't forget to follow this page to receive the latest updates on Border Recon.

    - Jena

     

  5. My endless quest for ever-cheaper labor has brought me to the capitol city of Ukraine, Kiev.  Programmers and artists here can be hired for about $20,000-$30,000 a year, and I believe minimum wage (yay for interns!) is about $0.75 an hour.

    I've been to all the major city American cities, and spent time in several major European cities including London, Berlin, Stockholm, and Copenhagen, which I feel gives me a little perspective on what makes a metropolis tick.  So here are a few things you might not have ever heard about Ukraine.

    Ukrainians are Huge Fans of Half-Life 2

    This city is very clearly modeled after City 17 from the Half-Life series of games.  It's amazing that they were able to construct such detailed reproductions of City 17 in only ten years, since the game was released in 2006.  The attention to detail is truly remarkable, but I feel they kind of ripped off the entire aesthetic and should have done something of their own.

    IMG_1621.JPG.d50ac76f45a682f5b76f07aa04f1cf8b.JPG

    Total rip-off.

    This may have been the actual building that inspired the Citadel.

    It's been done!!!

    d1_trainstation_020012_1100550779.jpg.114f511a49832a36967f50fd1288d262.jpg

    Seriously though, it's very clear the Citadel was meant as a metaphor for the encroachment of modern technology (or capitalism) on an old culture steeped in tradition.

    Don't Judge a Book by its Cover

    After a 17 hour plane flight (actually, three planes), and a lost bag (more on this later), I finally made it into the city center to find my new accommodations, and was greeted by what looked like a nuclear bunker from the cold war.  When I saw the outside I seriously almost checked into a hotel because it looked so dirty and run-down.  I thought for sure there would be rats and people shooting up heroin inside.

    IMG_1626.JPG.279565624c5e064cb392bc73583411d2.JPG

    When I finally figured out the odd lock mechanism, the entrance was even worse.  This is a straight-up ripoff of S.T.A.L.K.E.R.:

    IMG_1666.JPG.29a43eeef33997fd5e024b8a9316252b.JPG

    Lame!

    IMG_1665.JPG.6a8444f2b811e996c2ffffa370dbd672.JPG

    But when I got into the apartment, everything was completely pristine:

    IMG_1630.JPG.6fb547ad5e3689d23acd3f0600215ba7.JPG

    Why Make a Crosswalk When You can Build an Underground Mini-Mall?

    The major intersections in Kiev do not use crosswalks at all, or pedestrian bridges, or anything else to move from one side to another.  Instead, they build tunnels under the roads for people to walk through.  I imagine at one time under the Soviet Union these were probably utilitarian tunnels, but since the onset of capitolism every extra square foot of space has been dedicated to selling you stuff.  Which is cool, because I got some really nice things there at low, low prices!

    IMG_1701.JPG.f8bad9b045cd5d041ce89d31c081d6f1.JPG

    The entrance looks like a subway station.

    IMG_1700.JPG.e2a582e2309a52a8f043558b4d922192.JPG

    The inside is a combination of an American strip mall and a Chinese bazarre.

    IMG_1620.JPG.39d95a01f82469ac98c64fc22eb32763.JPG

    Things get scarier at night.

    You Can Buy Animal Parts at the Grocery Store

    Ukrainian supermarkets are very modern and sophisticated.

    IMG_1705.JPG.81151384da1ca920a0a7bffa3eb60d04.JPG

    But like everything else compared to the west, it's just a little more brutal.

    IMG_1667.JPG.77e66459261837f06ef8cba1ac4bd805.JPG

    Texas chainsaw massacre-level.

    IMG_1669.JPG.5ceffa211f63cd200f99c4fc65bf6b6e.JPG

    Bambi's mother looks delicious.

    IMG_1704.JPG.f63de6cb7b0823454dfc3e275f59476d.JPG

    Mutant turkeys and pseudobunnies, presumably from the zone.

    The real question is, who has better quality food?  Although I am repulsed by the barbarity of the Ukrainian meat market, it involves less processing and thus fewer alterations and opportunities for introduction of bacteria.  Amazingly, I did not pick up any "rotten meat" stink at all, even though hundreds of pounds of dead animals were laying out in the open.

  6. 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;
    }


     

  7. reepblue
    Latest Entry

    Luawerks has been updated this morning, making the console more responsive and a new tab for the Options Menu for user's to bind keys to actions.

    Actions have always been part of Luawerks, but until now, there wasn't really a motive to use them. Now, the Action class look in the config to check what key the user binded to that action. You can read more on how this works here. Like the console, this may be improved more in the future. 

     

    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 Workshop Store for $9.99.

    For documentation and bug reporting, please visit the GitHub page.

    luawerksgui2.JPG

  8. In a previous developer blog I showed how I use spline paths inside the Leadwerks editor. The cool thing about splines as that they are extremely multipurpose. I started working on generating meshes based on the splines.  Think about ropes, wires, rivers, rollercoasters and of course roads

    Ropes and wires are in progress because I find them the coolest. Especially rope bridges are awesome to make and see in play. They require a lot of finetuning so I have put that on halt for now. In the meantime I also started working on road nodes. The Return to the Zone project uses terrain textures, but the original scene from Leadwerks 2.3 used the in-editor road tool. Time for some new roadfeatures.

    Roads
    The generic nature of the splines allows easy creation of meshes based on the spline. Constructing basic geometry was relatively easy. However, getting the road to appear on the terrain properly proved a little harder. When there is no terrain, the generation of the road is instantaneous. The roads that are created snap perfectly together and it is really satifying to see the result. Per node you can't only tweak the road with the spline handlers, but you can set a road width, a material and several terrain alignment options.

    When the node has to deal with terrain allignment the performance on startup is little slow at the moment, but the first results look promising. I want to add this feature to my winter game "On the road again", which makes cool random tracks from CSG brushes.  

    Another cool automatic feauture is that the road still functions as a path spline. You can attach a car to the road spline and it will follow the generated road. 

     

    Ropes and wires

    For a next video I will show the progress on the ropes and wires, with hopefully some working physics. Here is an older image based on the earlier splines to give you an idea on what I am going for:

    powerlines.png

  9. 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
    • 2194
      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>

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

  11. blog-0502497001488979347.png

    In an effort to further boost production values and the general quality of the cinematics in Enshrouded World I implemented facial animation for the characters and as the title suggests rather inelegantly.

     

     

     

     

    Below is one way of going about implementing facial animation but it's most likely not the best.

     

     

     

    - Sift through thousands of frames of mocap facial animation and export the model every five frames.

    - Load and release the vertex data of each of the hundreds of models needed for one cutscene to reduce RAM usage.

    - Set the positions of the vertices in the base face to the positions of the vertices in the next model (This requires interpolation and continues to the next model every 83 milliseconds).

     

     

    As you would expect the first step there was very tedious and despite my efforts there are still issues with the framerate whenever the facial animation is being rendered.

  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. It should be great if you can create a game world which has exact real-life object's dimensions. If you are using Blender to make game props for Leadwerks, these are some simple steps to help you archive the dimension match up.

     

    Step 1:

    - In Blender, go to Properties panel > Scene tab > Unit group

    - Choose "Meters" from list.

    - Make sure Length = Metric, Angle = Degree, Unit scale = 1

     

    Step 2:

    - This step is optional but can make you feel better with grid floor

    - In 3D View, Press N to open Properties region > Display group

    - Change Lines = 256, Scale = 0.1

     

    objectdimension1.jpg

     

    From now on, you can adjust object's dimensions parameters in Properties region to match real-life dimensions, it will be the dimensions when you import models into Leadwerks.

     

    Don't for get to Apply Transformation for object model, it is important. Do this before adjust object's dimensions. In blender Use Ctrl + A > Location / Rotation & Scale.

     

    objectdimension3.jpg

     

    Step 3: Fbx export

    - Menu File > Export > Fbx

    - Choose Version = FBX 7.4 binary

    - Scale = 0.01

     

    objectdimension2.jpg

     

    Step 4: Adjust exported model in Leadwerks Game Editor

    - Double click mdl file in Assets Explorer to open it in model editor.

    - Menu Tools > Collapse. This make sure model local rotation is correct.

    - Menu Files > Save.

     

    I attached my template .blend file below this post. It included a 1.7m height human model for better reference.

    • 2
      entries
    • 7
      comments
    • 514
      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

  14. 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!

  15. After going radio silent for a week I return with some really, really good news.

     

    First and foremost, the last level of the first episode is finished, I'm currently testing it out and seeing if I can break it before I upload a beta build to steam. After a couple days of it being there, if there aren't any issues, I will be launching the game on february 10th. Yes, you can quote me on that.

     

    3c5bdc3d87f763539e11a5dc8898de8920700fc3.jpg

    I have to tell you though, making this level was not easy at all, I had so many ideas that never saw the light of day, but I hope that the way I created things work out for the better and I hope to use those scrapped ideas in the future someway.

     

    So here's a bit of information for the last level for those of you who've been wanting to play it:

     

    There's a way to kill the demon.

    There's a way to escape without killing him.

    The last level has 5 different variations depending on what you do.

     

     

    It goes without saying that there are multiple endings for what happens when you finish the last level as well, but I'll leave that for you to find out.

     

    55ea894a743061a3d64b1a22cecaadcd093947cd.jpg

     

     

    That's it for now! I've probably already said too much so I hope you'll like what's in store for you.

  16. It's finally done!

     

    You can find it here on the workshop:

    http://steamcommunity.com/sharedfiles/filedetails/?id=843127624

     

    And now i'm going to share a bit about the progress of the last few weeks, stick around if you like :)

     

    I'm so glad i made it in time, there were still a few "optional" things i would've loved to add (like a final boss wave) but due some in real complications (losing my phone..) and overal internship time consumption i still managed to get quite a game here!

     

    I am pretty proud of it too, might sound silly for such small game but it's my second game that i marked as "complete"! Also special thanks to my wife for creating all the model textures & GUI textures!

     

    For both me and my wife it was the first time we actual worked with 3D models (creating them from scratch and texturing them from scratch) this was quite a cool experience, i'm really glad with the results

    and i got more experienced in the tools i can use to make things look nice without too much complications.

     

    I personally think the cartoon-ish style was a great start for the modeling / texturing matter as this are my first proper game models that i build from scratch like mentioned above. I did have a small glimpse and trying to add bones, but i personally left it aside for now as i didn't really need them and i wanted to invest my time more in the game to reach the finish line.

     

    Overal in general, the progression went smooth (sometimes a stupid mistake like uppercase instead of lowercase.. You know the deal hehe), this was also my first time actual creating a wave system which i enjoyed a lot! I must say, tweaking & balancing each wave was harder then i honestly expected at first but i think i found quite a balance :)

     

    I don't really know what more to add haha, perhaps writting this after a day programming session wasn't the best idea.

     

    Thanks for reading and i hope you guys enjoy the game as much as i did creating it!

    • 2
      entries
    • 8
      comments
    • 203
      views

    Recent Entries

    In my day job I get a lot of experience with different technologies. Mostly related to mobile or website, but there is a lot of bleed over in the game industry. I've done a few Ruby on Rails applications, it's not my primary toolbox, but it has some benefits. Mostly the ease and speed of development.

     

    I switched to using Ruby on Rails for the data management layer of my game. At the moment there isn't much data, only about 300 rows in a database for everything in the game. This is expected to more than triple within the next few months as I add achievements, more items, 7 new quests, and shops!

     

    Eventually this will go extremely large and hard coding all that data will become very error prone and next to impossible to manage.

     

    Ruby on Rails has the ability to have command line tasks which can be used to generate data.

     

    Sample task:

    namespace :codegen do
    task :achievement_types => :environment do
     erb = ERB.new(File.read('lib/tasks/codegen/achievement_types.erb'))
    
     params = binding
     params.local_variable_set(:achievementTypes, AchievementType.all)
    
     data = erb.result(params)
    
     f = File.new('codegen/AchievementType.h', 'w')
     f.write(data)
     f.close()
    end
    end
    

     

    What this code does is it loads an ERB file which is a templating file for Ruby.

    Queries the database for all AchievementType objects,

    Then creates a local binding scope for the template,

    Renders the template to a string

    Presto, Generated C++.

     

    Erb file in question:

    #ifndef ACHIEVEMENT_TYPE_H
    #define ACHIEVEMENT_TYPE_H
    <% achievementTypes.each do |at| %>
    #define <%= at.macroname %> <%= at.id %>
    <% end %>
    #endif
    

     

    Code generated:

    #ifndef ACHIEVEMENT_TYPE_H
    #define ACHIEVEMENT_TYPE_H
    
    #define ACHIEVEMENT_TYPE_WOODCUTTING 1
    #define ACHIEVEMENT_TYPE_FISHING 2
    #define ACHIEVEMENT_TYPE_MINING 3
    #define ACHIEVEMENT_TYPE_FIREMAKING 4
    
    #endif
    

     

    The use case above is fairly simple, but more complex situations can occur, such as Npc Conversations. Currently my NpcConversation_Gen.h file is 500 lines long. with lists of data similar to this:

     

    new NpcConversation(34, 0, "69488b5b-cfd1-4255-bd74-a6b7eeb0e939",
    {
     new NpcConversationAction(27, "AddInventoryItem", 39, 1),
     new NpcConversationAction(28, "CompleteMilestone", 3, 15),
    },
    {
     new NpcConversationConditional(12, "StartedQuest", 3, 0),
     new NpcConversationConditional(13, "HasItem", 57, 10),
    }
    ),
    

     

    Maintaining that code by hand would triple the amount of time to create quests.

     

    So if your game uses a large amount of data, I really recommend using a web framework (Ruby on Rails, Codeigniter, Cakephp, Revel, Django, Spring, ect) to manage all your game data!

  17. blog-0813764001483675955.png

    I've finished the main concept of my game "Ball Hopper", which you can play at http://www.leadwerks.com/werkspace/page/viewitem?fileid=831630240

     

    It was inspired by CS:GO surfing and the Impossible Game and your goal is to reach the checkpoints and get to the end. Checkpoints, for a lack of a better word aren't what you'd expect of them. They're really just points that you need to touch to be able to finish the level. Some level end points are right at the start, so would be a bit silly if you could just get to the finish and win, so that's what those are for. You don't actually respawn at those points.

     

    This blog post is mainly to gather feedback before the end of the tournament, so let me know if you have any suggestions.

  18. Hey!

     

    More stuff will come in the next version, my objective is to improve the Prologue to use as a demo for a Greenlight campaign to the next chapter. Much of the work this week (besides fixing stuff) was to detail the scenes a bit more to help you guys understand the water flood and how deep the water is.

     

    I removed the cars of the starting area, because floating cars in that place makes no sense.

     

    20161216133209_1-pzdpq8v2.jpg

    You can now even see the noisy bird (what a time to be alive!)

     

    The water in the game is really deep, the buildings you see in the game are the rooftops and the facility that you start the game barely survived to the cataclysm.

     

    Some additional rooms were planned for prologue but they were left out, I'll add them in the new version! So if you have already played the prologue you will have some surprises in the Uncut version.

     

    20161216133113_1-5vujssxw.jpg

  19. Ludum Dare 37 starts in 12 hours (as I type this)

     

    http://ludumdare.com/compo/

    https://ldjam.com/

     

    Most of you probably know (I think), but Ludum Dare is a game dev competition where you have to complete a game in 48 hours from scratch (no externals assets I think).

     

    The JAM portion of the event is a bit more relaxed and gives you 72 hours (if my memory serves me right - I really should check the rules) You can use external assets (I think - again I should have checked the rules before posting this right smile.png ).

     

    In the past I have sometimes participated unofficially and used it as a focus point to force myself to try to do a game in very tight timescale and so be forced to jettison most of the fluff you waste your time with normally.

     

    I think I might give the JAM (not the DARE) a go this year but probably just unofficially for my own benefit. Don't necessarily plan to submit anything as currently I already know I will have limited time over this weekend so it just might not happen. I suppose one outcome could be that I come up with the start of a small game I can enter into the Leadwerks Winter Tournament in just 2 days and can then either choose to submit that or continue on with my main idea.

     

    It can be a useful event to try out something that you've never got round to before in a bit of software (e.g. Leadwerks) and to refine your workflow.

     

    Sometimes there are also offers on software around this time which area usually highlighted on the site though I can't see any information on it at this time

     

    As I type this the theme is currently accepting voting still.

    https://ldjam.com/events/ludum-dare/37/theme

     

    Having a theme helps focus your mind but also think of things that might be outside your preferred area (space zombies etc.)

     

    If anyone decides to enter, officially or unofficially then good luck.

  20. Draws a box from one vector to another.

    To be used as some kind of arrow.

     

    Need feedback if its a better way to do this, but so far seem to be ok for my purposes.

     

    Example usage:

    ArrowUi *t = new ArrowUi(Vec3(0.0, 0.0, 0.0), testshadow->GetModel()->GetPosition());

     

    class ArrowUi {
       private:
        Model *model;
        Entity *pivot;
        Vec3 from;
        Vec3 to;
        float distance;
       public:
        ArrowUi();
        ArrowUi(Vec3 from, Vec3 to);
        void From(Vec3 from);
        void To(Vec3 to);
        void Draw();
    };
    
    
    ArrowUi::ArrowUi() {
       model = NULL;
       surface = NULL;
       pivot = NULL;
       from = NULL;
       to = NULL;
    }
    
    ArrowUi::ArrowUi(Vec3 from, Vec3 to) {
       this->from = from;
       this->to = to;
       Draw();
    }
    
    void ArrowUi::From(Vec3 from) {
       this->from = from;
    }
    
    void ArrowUi::To(Vec3 to) {
       this->to = to;
    }
    
    void ArrowUi::Draw() {
       pivot = Pivot::Create();
       pivot->SetPosition(from, true);
    
       distance = from.DistanceToPoint(to);
       model = Model::Box(0.05, 0.05, distance, pivot);
       model->Move(0, 0, distance/2);
    
       pivot->AlignToVector(to - from, 0);
       pivot->AlignToVector(to - from, 1);
       pivot->AlignToVector(to - from, 2);
    }
    

  21. blog-0128326001476525058.jpg

    TinyGom Racing PC Game is available !

     

    New demo : at: tinygom.sdmg-studio.eu (register)

     

    or if you have an account on indiedb.com :

    http://www.indiedb.com/games/tinygom

     

    lot of bugs corrected:

    • menu appearance now conform to what it should be
    • all sub-menus revisited
    • in game cosmetics adjustments
    • time trial mode now fully fonctionnal
    • screen resolution detection improved and working with multi monitors
    • no more bugs at the first launch of the demo

    SDMG-STUDIO production presents

    the fruit of my very long work,my completed game : TinyGom Racing

     

    Why 'TinyGom' ?

    because there are small tires... rolling !

     

    What is TinyGom Racing ?

    It is a solo PC game about driving remote control vehicles around levels in different environments.

    3 Game modes : Quick Race, Time Trial, Championship

    3 environments : School, Mall, Warehouse

    6 levels , 6 different rc vehicles with one mystery car (more levels and cars to come...)

     

    blogentry-37-0-84223800-1476525375_thumb.jpg

     

    Gameplay:

    All races will be different because of the random placement at start, Music and AI racing are changing randomly too.

    Passing through the semi-transparent "red gates" you will progress along the level and finally loop a lap.

    When a bonus is available, going through it will give you three ping-pong balls to throw at opponents, wisely.

     

    blogentry-37-0-79546400-1476525441_thumb.jpg

     

    Car abilities:

    Accelerate (!)

    direction left/right (good start, no ?)

    Brake

    Backward

    Flip car (in case of upside down)

    Replace car, Levels have saveposition tags, a "savepos message" will pop up when done.(see each mode for detail)

    Shooting balls (bonus gives you 3 balls to throw at opponents)

    Looking at 180° view right or left side of your car

    Position camera view from the rear of your car zooming + or -

    Pitch camera view angle from the rear (all positions of the camera are recorded and restored at start)

     

    blogentry-37-0-42949500-1476525474_thumb.jpg

     

    Game Modes:

    Quick Race mode : you just race for fun, 5 opponents and clock ticking though, level lap record to beat too,

    you can choose the number of laps to run before racing.Simple ranking will show at the end of the race.

    Replacing the car in this mode will replace your car at the last "saveposition" recorded, from 3 to 9 savepositions spots are placed according to each level.

    In this mode you can also looking for the mystery car parts scattered around all levels by the naughty clown.

    With all the parts gathered you will unlock the mystery car and then be able to drive around with it.

     

    blogentry-37-0-33485300-1476525501_thumb.jpg

     

    Time Trial mode : you will fight the clock and yourself with the ghost of your best lap running with you.

    If you beat the best ghost time, your lap will be recorded and you will racing against it then.

    At start in a new session you can choose to load the best ghost file so you will fight against it or

    if not, recording a new ghost as you drive and to race against it after the first lap, all over the session trying to improve it.

    If you ever beat the best ghost time (recorded in file and loaded in memory), you will then establish the new reference ghost record for future sessions.

    The game is, for now, solo but you can already exchange the ghost record files of your own with others players

    who have the game and then race against them through their ghost file.

    This is a fun part of this challenge.

    Replacing the car will replace you at the starting position of the level and restarting the clock.(no "saveposition" works in this mode)

     

    blogentry-37-0-77506400-1476525537_thumb.jpg

     

    Championship mode : is based on the player name you enter (or leaving to "none")

    so you can leave the championship after a race in a level, quit the game and resume the championship later using the same name of player.

    Helping you by hitting the "restore last session" option in the main menu to retrieve your last session and resume the championship where you leave it.

    Replacing the car will replace your car at the last "saveposition" recorded, from 3 to 9 savepositions spots are placed according to each level.

    You will need to race 5 laps on each level to complete the Championship.

    You wont be able to redo a specific race before completing Championship, you will need to restart a Championship to do that.

    Points are distributed according to the finish positions of each level race : 100 for position 1, 80 to 2, 60 to 3, 40 to 4, 30 to 5, 20 to 6, 10 to 7 and 0 to position 8 (last one)

    Ranking is made after finishing a race level.

    Podium with global ranking will close the Championship at the end of the last race. Congrats if you are on the first step !

     

    Various objects, sometimes, will be throwing at you and the others along the levels slowing your race, putting little spice in your meal...

    Some objects are movable but a lot don't, you'll see.

    Mystery Car parts are seldom hidden from the direct view, you will need to rub the walls with your vehicle to discover the part-item then.

     

    Supported devices:

    mouse (menu)

    standard keyboard

    joypad X360 microsoft® controller

    Supported OS:

    Windows 7, 8, 8.1, 10

     

    Is the game ready ?

    yes : http://tinygom.sdmg-studio.eu

    or here: https://sdmg-studio.itch.io/tinygomracing

     

    Demo ?

    yes : http://tinygom.sdmg-studio.eu

     

    on indiedb.com:

    http://www.indiedb.com/games/tinygom

     

     

    blogentry-37-0-41457400-1476525610_thumb.jpg

     

    Background:

    This project was seriously started several (more than 5) years ago, after toying with Leadwerks engine for a while,

    decided to find the "make a game(mine)" function and finally found it works !

    I have counted 13419 lines of lua code, sweating on some...not counted the polys though !

     

    Thankful to Leadwerks Engine for enduring all my trials and errors and to restitute fluidly the render from my ideas.

    I need to give credits to a lot of people here : first to my wife Pascale, for her patience and her presence

    second my son and my daughter who always encouraged me to progress at it.

     

    And for all technical parts, in not particular order (sorry for those i forget to mention) : Josh Klint for the Leadwerks Software Engine.

    Forum People : MackleBee, Rick, Marley's Ghost, Tyler_H, Aggror, Gordonramp, Pixel_perfect, Shadmar...

    All these folks helped me directly or not, special mentions to MackleBee giving always good advices and good code examples,

    Rick for coding the joystick.dll (without it, i would never be here) and to Marley's ghost who gave me a great piece of code base of my main mecanics.

    Finally thanks to the great Leadwerks community, where i found so much usefull posts.

     

    Started from nothing, bought one Pure3D starting pack, grabbing most textures from CGTextures.com others from my camera.

    Made all 3D models by myself, modeling,uvmapping,texturing and converting to gmf.

    Software used: Hexagon, Photoshop, 3DCoat, UU3D, Audacity, Leadwerks converting tools.

     

    I get a regular job so i have spent most of my spare time at my game.

    I started with Leadwerks 2.5 and stand with it because scene files (sbx) and all scripts in Lua

    would be a nightmare to redo and i love the 2.5 lighting (even if, the GI lighting Josh demonstrated is promising).

    Sure TinyGom is not perfect and could be more polished or more complete.

    My project is to extend the game even after the release, supporting bugs too.

    Hoping to compensate a bit the funds that i have put in this game, music bought at Partnersinrhyme®, pack from Pure3D® and the time dedicated,i have considered putting a fair price to the game,

    fee at a fast-food meal or a cinema ticket.

    Whatever happens, my reward is already there, accomplish the release of the game was my main objective,

    i am satisfied and relieved now.

     

    blogentry-37-0-11235600-1476525839.jpg

     

    Videos are also visible on my web site too.

     

    Hope you will enjoy the videos, test the demo if you want,

    feedback welcome at devtinygom@sdmg-studio.eu.

    The game and the demo are already available on my web site now : http://tinygom.sdmg-studio.eu

    Excuse my english.

    Thank you for reading.

    SDMG-STUDIO