• entries
    65
  • comments
    96
  • views
    20,532

Entries in this blog

Rick

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

 

Rick

The last blog I posted was Nov 2013. The blog section seemed stale for for a week or so so thought I'd share a change in design I recently did for our Dead Anyway game to spark conversation and ideas.

 

Our player script was just getting too massive and was doing too many different things directly inside of it. Adding features or modifying existing features was scary as hell. All the "helper" variables were adding up and the amount of hunting for what I needed in the script was pissing me off. So I decided to re-look at component architecture. After putting this into practice it's really makes programming more fun and changing things a lot easier and less fearful.

 

The first task was to look at this monster player code and break it down into domains. That meant looking at the high level functionality.

  • Play sounds
  • Take input
  • Camera controls
  • Movement controls
  • Inventory
  • FPS arms
  • HUD
  • Handle stats like health, hunger, thirst, etc

All of this was happening right in 1 script. Not cool. So I first hand to break all this functionality into their own scripts. However all this functionality works off each other. Even though they are separate when to do what and code X needs to know stuff about Y still exists. So if we want to break code out into it's own domain (and scripts) and reduce coupling on each other to avoid making fragile code AND they need to know about each other in various ways how would I do that?

 

Enter events. I treat each component as it's own little library that is designed to do it's one specific thing related to the game. So it of course has functions that act on it's data. But how would those functions get called? They would get called when events from other components were raised. So now a component has events to tell the outside world that something happened inside this component and functions to act on this components state. It doesn't care how it's functions get called and it doesn't care who is listening to it's events. It's blind to the outside world.

 

An example is the PlayerSound component. It loads sounds in it's init function and then it has functions like WalkForward(), WalkBackward(), StopWalking(), StrafeLeft(), StrafeRight(), Jump(), Eat(), Drink(). These functions simply play the right sounds. The PlayerSound code doesn't care about the input code and when you're in the PlayerSound script you don't either. Your mindset is just all about sound code at that point. You're thinking about what functions do I need for sound, and what possible events should I fire that have to do with sound? The sound script right now is about 100 lines of code (but it will grow in the future). It's nice and contained as it's own component.

 

Every component is like this. PlayerInput converts actions to events. It doesn't care who uses those events. It also has functions to map keys to actions. Who is calling those functions? Who cares. It's not my concern when I'm in coding the PlayerInput component. I just know I want to do that functionality at some point.

 

So how does this all get wired up you may ask? That's the interesting part. Your player script, instead of being an if nested disaster, simply becomes configuration code of linking component events to component functions (I call them actions). I noticed something interesting happen when I did this. Looking at the player script revealed what it's doing much simpler. It provided a nice high level overview of what the player is doing at a glance. I didn't have to read state variables and loops and branch statements to figure it out. I saw it all revealed to me. I feel like it works better with our brains. We think, when this happens do x, y, z. That's the component architecture with events exactly. That's all you see 1 line at a time. When this happens do this. Very little interpretation is needed.

 

Here is an example of what my player script looks like now:

 

PlayerLooting.onLooting:Subscribe(PlayerHUD, PlayerHUD.ShowProgressBar)
PlayerLooting.onLooting:Subscribe(PlayerCamera, PlayerCamera.DisableUpdate)
PlayerLooting.onLooting:Subscribe(PlayerController, PlayerController.DisableUpdate)
PlayerLooting.onCancelLooting:Subscribe(PlayerController, PlayerController.EnableUpdate)
PlayerLooting.onCancelLooting:Subscribe(PlayerCamera, PlayerCamera.EnableUpdate)
PlayerLooting.onCancelLooting:Subscribe(PlayerHUD, PlayerHUD.HideProgressBar)

 

 

The PlayerLooting component has an event onLooting and onCancelLooting and those other components are subscribing to those events and telling those PlayerLooting events what functions they could call when that event is raised from within the PlayerLooting component.

 

You can plainly see the HUD shows the progressbar and the camera and controller controls are disabled. If we cancel looting we hide the progressbar and the controls are enable again.

 

Want to add a sound when looting? Just think about how easy that is to think about. No hunting for the right section and state in the old giant player script that is 1000+ lines. You simply:

  1. Add a loot sound variable and load a loot sound inside the PlayerSound script (you know exactly where to do this. if it's a sound it's done in PlayerSound component. easy right?)
  2. Make a function in PlayerSound to play said sound
  3. Make a function in PlayerSound to stop said sound
  4. Link the onLooting event to the PlayerSound play looting function
  5. Link the onCancelLooting event to the PlayerSound stop looting function

It's much more compartmentalized than the traditional design of putting all that stuff into the player script.

 

 

Here is the event code that I use:

 

if EventManager ~= nil then return end

EventManager = {}

function EventManager:Create(owner)
local obj = {}

obj.handlers = {}
obj.owner = owner

for k, v in pairs(EventManager) do
obj[k] = v
end

return obj
end

function EventManager:Subscribe(owner, method)
table.insert(self.handlers, { owner = owner, method = method })
end

function EventManager:Raise(args)
for i = 1, #self.handlers do
self.handlers[i].method(self.handlers[i].owner, self.owner, args)
end
end

 

 

Inside a component to create an event you simply do:

 

-- note I just wanted to use Event but Josh exposed that for his UI stuff so I ended up with EventManager instead
self.onmoveForward = EventManager:Create(self)  

-- events have a table that is an argument that will get passed to the function subscribed to events
-- interestingly enough because it's a table, it's passed by reference so inside your action function if
-- you change a value the component that raised the event can read that to perhaps act accordingly.
-- I do that in a few instances
self.onmoveFoward:Raise({ shiftKeyDown = false })

 

Then to subscribe to the event in the player script where all the components come together you simply call the Subscribe() function on said event passing in the component object and the component objects function/action to get called when that event is raised:

 

PlayerInput.onmoveFoward:Subscribe(PlayerSound, PlayerSound.PlayMoveFowardSound)

 

My future for this is to have an editor that reads all component events/actions and visually allows you to hook up events to actions. Then the player script simply reads the output file of said editor to hook things up. Then we'd have a nice visual of how our game works at a high level.

 

This was a long one but I'm really excited about making the switch. It was an easy transition to make and it makes adding/changing functionality really simple, and it gives me a high level overview of what's going on with the player which was increasingly getting more complex.

 

If you read this far on a weekend then go outside :)

Rick

Dynamic properties!

I like the idea of being able to add dynamic properties at run-time. The following code shows how you can set this up. Instead of declaring a hardcoded amount of variables in a class you could just give it 1 Properties class and it can be dynamic!

 

#include <string>
#include <map>

using namespace std;

class Prop
{
public:
virtual ~Prop()
{
}
};

template<typename T>
class Property : public Prop
{
private:
T data;
public:
virtual ~Property()
{
}

Property(T d)
{
data = d;
}

T GetValue()
{
return data;
}
};

class Properties
{
private:
map<string, Prop*> props;
public:
~Properties()
{
map<string, Prop*>::iterator iter;

for(iter = props.begin(); iter != props.end(); ++iter)
delete (*iter).second;

props.clear();
}

template<typename T>
void Add(string name, T data)
{
props[name] = new Property<T>(data);
}

template<typename T>
T Get(string name)
{
Property<T>* p = (Property<T>*)props[name];

return p->GetValue();
}
};

int main()
{
Properties p;

p.Add<int>("age", 10);
int age = p.Get<int>("age");

return 0;
}

Rick

[EDIT]

Now with sound!

 

 

I'm making a game that revolves 100% around old school final fantasy battle style fighting. I thought about what often slows me down and kills my motivation in games I've tried to make in the past. My conclusion was that dealing with graphics (models, UI, animations, etc) often slows me down in various ways. So as an experiment for this game I'm going to first code the entire core gameplay in a console application with a basic text based interface first.

 

I'm hoping this will allow me to quickly tweak the battle system to both balance the game and make encounters fun and challenging.

 

I'm also taking a very iterative approach to making this game. I wrote down the basic idea of the game and I'm leaving the details to be defined as I'm writing the code. I write the basic functionality in a crude way, then I go back and factor the hell out of that. Rinse and repeat until I get something I think it fun.

 

I'm hoping that once I have the core gameplay done in this manner that transferring the code over to C++ and introducing graphics via LE won't be a ton of work.

 

Below is a link to a very raw implementation of a battle. It's in .NET so as to be developed quicker since it has some built-in features like text color to help describe things more while in the console environment.

 

The blogs have been pretty dead lately so thought I'd just share something smile.png

 

 

https://dl.dropboxusercontent.com/u/1293842/RPG/RPG.rar

Rick

Thought I'd share my experience like Aggror did.

 

 

First I'd like to say that it's a bummer that only 11 people voted so far. It's not a very big sample size and I hope many more will vote in the next day. I'm open to leaving the poll open for longer to let more people try the games available. Maybe over the weekend or so as people might have more time then.

 

I'm also bummed out that only Aggror and myself have exe's to try. Was hoping for a better turnout and if he and I win it's a little awkward since we were providing the Steam prices.

 

 

Physics

 

I'm with Aggror on this one. There is for sure something wrong with the Physics. Everything about my game ran very slow for me. It was very frustrating to test the game each time with the poor physics performance. This needs to be looked at. There is no way I should be getting -20 fps on my little game where if I did the same in LE 2 I was getting 100+.

 

 

 

Scripting

 

I used pure Lua for my game and I'd say it was a love hate relationship. I loved already having the structure of entity scripts and the flowgraph integration, but there were many bugs that were very frustrating. As Aggror pointed out if you work in Lua enough in the game engine you'll eventually see that the script tab will show other script properties than what you know it should have. I would also create scripts by right clicking in the Scripts folder and using the menu and I noticed if I made more than a couple scripts that way it would end up overwriting the filename of the previous script instead of the newly created file. Very frustrating and would force me to just go into the file system and fix things that way.

 

That being said, I love working with the flowgraph. I used a couple scripts I placed in the Assets section a few months ago without issue. I connected my scene loaded script to my sound script to start the creepy music you hear at the start. When a frostball collides with the fire, the fire triggers an onPutOut event that I hooked up to the fire particles to stop playing the emitter, hooked up to the smoke emitter to play it, and to the key model to enable it to be picked up. I wanted to play a sizzle sound like the fire was being put out, but I couldn't find the sound effect, but it would have taken about 15 seconds to set that up.

 

What I disliked about the flowgraph is when I modify the scripts that are exposed to the flowgraph the connections are removed. Very frustrating as I'd forget this after making a change, run the game only to notice nothing happening. I had a fairly simple flowgraph but my scene was also very small. Even with a normal size level the flowgraph could get somewhat big, and remember what was connected to what would be very frustrating. This has to be fixed to be considered usable in any real game.

 

 

Security

 

Since I used purchased models I had to password protect them. Seems I was the first to give this a try in Leadwerks 3. I'll say that it leaves something to be desired when you need to package the game up. I had to manually make zip files from the folders in the base directory. You can't include the base folders, but only the stuff inside of it. You then name the zip file the same as the folder. However, the editor will not read zip files, so for development you need your normal folders then you have to do this zip method. I moved the base folders out and left the zip files hoping to make an install package that would include the zip files, but no such luck on my part which is why the game is in a rar file instead of an installer. A more user friendly approach would be either to have the engine read password protected zip files, or to have the publish option zip/password protect the base folders automatically for us and only place in the package so that your development environment stays untouched. Because I opened the project without the base folders and just the zip files, and I promise you I didn't save anything once I saw that it didn't work right, the project seems to be corrupt now. I'll spend some more time this weekend trying to get it to work as I'd like to expand on the game.

 

 

Overall

 

Like others I didn't have as much time as I wanted. What you see with my game is probably 8-10 hours of work where a good deal was spent on learning the physics of opening the door (which sometimes crashes still. would be nice to have PhysicsMove() function for stuff like this) and the particle editor (as it seemed I needed to modify the text mat file with a property that isn't in the material editor. how was I supposed to know that :) ). I had much more planned that included enemies that had some strategy in killing, and 1 more bigger puzzle. However, the ability to create the gameplay interactions to give the game some life was really easy and efficient. For anything physics based though I think LE 3 has a little ways to go yet, and I hope the performance can be worked out.

Rick

LCP 2.0

There is no question that LCP (Leadwerks Community Project) 1 had some issues. I think we learned a lot from working on it and I'd like to apply those lessons and give LCP another try with LE 3. I'm thinking with CSG, "automatic" pathfinding, and a better scripting system that LE 3 has to offer will greatly increase the speed and quality of another LCP project.

 

This blog entry is to get a feel for people interested and to give a basic overview of the game and requirements. Unlike the last LCP there will be no voting on what people want. The goal is to duplicate the last LCP in scope and design so all that stuff is already created for us. In terms of the programming needed, I plan on being the puppet master but not directly do any coding (unless required because of lack of people). What I do plan on providing is leadership, organization, and design how the scripts should interact with each other to hopfully provide a smooth project with a great result!

 

Please let me know below if you are interested and what role you could fill. Note you aren't signing your name in blood here. This isn't a kick off or anything it's more about letting people see what this project would be about and let me know if interested.

 

I'm going to list out a bunch of "facts" about what LCP 2.0 will be/use

  • LCP will be Lua based (we will use entity scripts that are pretty self contained)
  • LCP will be a First Person Shooter
  • LCP will be 1 level taking place in a Subway
  • LCP will have 1 zombie model for the enemies
  • LCP will have 1 gun weapon (type TBD)
  • LCP's gameplay will be to similar to L4D. Get to the goal alive!
  • People who work on LCP will work on their own copies and promote their additions/changes to me where I will combine to make the final product

 

What we'll need

  • 4 programmers (FPS script, Weapon script, Zombie script, Menu/HUD script)
  • 1-2 CSG Level designers (Subway level AND level materials)
  • 2-3 modellers/artists/animators (we will be reusing as much as we can from LCP 1. zombie, weapons, props for level designer. if anyone knows where the source files for these are please let me know)
  • 1 sound person (weapons, environment, etc. Shouldn't be a huge demand on this persons time)

 

I'm not asking for a ton of time from the people on this project. In fact, it'll seem like you are more of a contractor because I'll have 90% of the design done and be asking for very specific things from each person and hopfully in the order so people don't have to wait very long to get what they need.

 

On the programming side each person will be given 1 script to make. I'll define how the interactions should work (the interface of the scripts so when they interact it'll all come together).

 

We don't plan to sell the game at this time. I won't be making any money from this. It's more to get a demo level up and running in LE3 as a community. Everyone who works on this will be recognized for thier hard work here and in the credits.

 

The idea is to keep the tasks small enough so people are able to stay focused but big enough to make them feel like they really contributed to the game. I also want to use the primary skills that people have. Often we are forced to wear multiple hats in the indie world, but here I'd like to give a feel for what can happen when you are able to focus on your primary skill.

 

I will primarily work individually with each person giving their tasks and the requirements around the task. There won't be many group meetings that you need to make.

 

The golden rule: No prima donnas. All I ask is to do your task to the best of your ability and nothing more.

 

I will give a deadline when I know who will be on the team and make a kick off post. Again, the way I plan on structuring this it shouldn't take a ton of your time.

 

Reply here or PM me if interested.

 

[EDIT]

Note that 2.0. The plan is to start simple with 2.0, but evolve it and add to it over time as well to have a 2.1, 2.2, etc. However all that at this time is out of scope, and when we get to those stages I'll do another post to see who wants to join (could be same or get some new people) and we add/change stuff.

Rick

RTS/Tower Defense

I like reading blogs and Josh has been the only one spamming them recently (j/k I know we all love hearing about LE3) so I figure other people like reading blogs too. So I thought why not make one about what I'm working on.

 

Over the last month or so I had pathfinding working using basically a 2D grid over a terrain using A*. Being able to move actors around like that just feels so inspiring and feels like the sky is the limit which what you can do with that. I had so much fun with just that alone. All along I was thinking about what could I make with this that wouldn't be to much to do for 1 person, would keep my attention, and would have some nice "replayability".

 

I really wanted to make a tower defense game, but most of these are pretty meh. I recently got back into Age of Empires 3 and would build up a nice big army only to crush the AI (even on the hardest mode). Often I had to go to their base to even get somewhat of a challenge as they never came to me with anything of value, and pretty much never on multiple fronts. It wasn't satisfying for me at all. There was no challenge there.

 

I like gathering resources (for some reason) and I like building up an army and placing them in strategic locations preparing for a big invasion and then having an "epic" battle. So that's the task I've set out to do. There won't be any "ages" or levels of progression. The game will be about the waves of enemies getting bigger and badder. You'll have some time between waves to manage your resources and prepare your armies for the next wave. Waves will start coming from multiple fronts. The music for each wave will get more intense and epic. The game will be about if you can survive all x number of waves.

 

The setting is a medieval style so some of the units will be knights, assassins, wizards, and some towers. You'll have orcs tarus, undead, and other creatures with each wave. Also some mini "boss" of sorts mixed in for each wave.

 

I have the pathfinding complete. When you start the game you place your "town hall" anywhere you want on the map. I have trees for wood, gold and stone mines. Still need to work on food like bushes and animals. Currently you can select your units and move them around the map and make them chop a tree for wood.

 

I created a task system much like The Sims. When you give commands Tasks are pushed onto a queue for the Actor. Each Task includes the Actor doing it, the GameObject being done to (if there is one), and an Action doing the actual work. I have Actions like MoveTo & Chop. If I select an Actor and right click a tree, the game will find the closest open node to that tree, then push a MoveTo & a Chop passing the tree in question to that Actors queue and the actor will move to the location, then pop that task off, then start doing the chop. When the Chop tasks starts it registers itself to an OnResourceDepleted event from the ResourceProvider (tree) so when that tree no longer has any resources it notified all Actions working on it, which will inform the Actors indirectly to stop, or pop that task off. It works pretty slick and adding new actions that can be done is really fast, easy, and organized.

 

 

Next on the plate:

==============

1. I don't want actor collision so they aren't considered in the pathfinding. However, when sent to gather a resources I want to spread them out around the resources so going to make an array for the grid of where villagers are. It'll be used when searching for the closest "open" node next to a resource when the user sends a villager to gather from that resource. Currently it finds the closest open node which means they all pretty much stack up on top of each other if they were all coming from the same general direction.

 

2. If a resource is depleted while gathering a villager will look for other resources in an AABB around it of the same resource type to just automatically MoveTo and start gathering to reduce the amount of micro managing requires for the villagers.

 

3. Basic UI in place so I can start making other buildings with resources by clicking on these buildings.

 

 

 

So far going pretty strong with this game. Pathfinding makes all the difference with me. Seeing a game have some kind of life moving around is exciting.

 

 

rts.tower.png

Rick

Start of flowgraph dev

<?xml version="1.0" ?>
<root>
<behavior name="create_cube" >
	<result type="Entity" value="cube1" />
</behavior>
</root>

 

These 6 lines are the start of a flowgraph system I'm working on. I've been playing with UDK's Kismet and enjoying what it can do. Now UDK's Kismet is pretty specific to UDK functionality for the most part. They have things like SpawnPlayer, which LE obviously doesn't have. LE gives you much lower level control than SpawnPlayer type stuff. So what I've decided to do is create every function LE has into an xml tag, that can be read in and executed. Then a flowgraph UI can be placed on top of that as the editor that lets you visually generate said xml. The user however, never needs to be concerned with the underlying xml.

 

In UDK functionality is split into a few things. Namely Actions & Events. It also lets you create variables. My flowgraph will function the same way. Like in the above xml, you would have dragged the CreateCube action onto your canvas. Then created a variable object of type Entity, and linked it to the result node sticking out of the CreateCube action. Now when it's called, you have a variable that you can reference anywhere else. For example, you can then drag in a PositionEntity action and use the prior created variable as the entity parameter to this.

 

So the result is just how a person would program LE, but it would be visual. If people will like this I don't know, but it's fun and interesting to get it working.

Rick

Component prefabs

So I was able to get prefabs working with the component design. It's really easy too! A prefab is just an xml file that describes the different components and their attributes that make a game object.

 

For example, in the editor I added an empty game object to my scene, then attached a spotlight component to it. This provides spotlight functionality. It creates an LE spotlight and exposes some attributes to control the spotlight. I then right click the game object and choose Save As Prefab. I provide it a name (SpotLight) and it saves an xml file named SpotLight which has the components required for that game object and saves the attributes that were set. Now when I go to add a game object I have another menu option named Prefabs, which lists all available prefabs. SpotLight shows up! I select it and it adds a game object to the scene and automatically attaches the spotlight component to it and sets the default settings. It's that easy. Distribute your prefab xml file and any component dll's that depend on it and people can add your game objects to their scene with a click of a button.

 

The editor will also validate if a dependent component is missing or not and inform you of the missing component.

 

This is getting exciting ;)

 

More to come!

Rick

The Goal: To be able to open a world of game functionality to non programmers, and to allow programmers to create this functionality. To give drop and drag with configurable functionality without restricting possibilities in any way.

 

The Design: This approach uses the component design along with an attribute design. The attributes represent the data a component wants to expose. A component is a smaller behavior piece that is attached to a game object. Components expose events. Events drive everything in this design. It's the cornerstone for component communication with other components. Components themselves are completely isolated from each other. Inside a component it only knows about itself. The exception to this rule would be a factory type component that creates things dynamically. This type of component would store the game objects it creates dynamically.

 

 

F.A.Q.

=====

Q. If a component doesn't know about any other component, how can we create game functionality with these components?

 

A. Components are made up of 3 pieces. Attributes, Events, & Exposed Methods.

Attributes are data that the component wants to expose to other components giving them the ability to change.

Events are fired by components when certain things happen. Components have a set of default events, but the component author creates event relavent to their component also. In the component code, they define what causes an event to fire. For example a health component might fire an OnDead event when it's health attribute reaches 0.

Exposed Methods are the functions that work on that given component and are exposed for other components to call. So let's say we have a spot light component. We might give an exposed method called TurnOff, which basically turns off the LE spotlight entity that's created from this component.

 

So the functionality is created by linking events of one component with methods of another (or itself). Since Attributes, Events, and Exposed Methods are all accessed via their string name, this makes it really easy to create a UI to make this very easy. The results are stored in xml files.

 

Q. How can I handle game objects that persist through scenes?

 

A. This is a good question and something that bothers me with some other engines. Game objects in other engines seem to be focused in the scene only. The solution with this design is to only change 1 thing. The scope at which persitent objects are created. Everything else stays the same. I call these global game objects and they are created at startup and stay in scope until the end. Game objects in scenes are loaded and unloaded with the scene, but global game objects stick around. Global game objects are also usable in every scene in the game. Nothing about global games objects change between scenes.

 

Q. How do I program a component?

 

A. You use C# to create a dll. Derive from a base component class that provides some basic functionality like creating events, attributes, & exposed methods. What this component is and does is 100% up to you. There will be a fine art of making components. You don't want to go to low level or high level with components. Finding a nice middle is preferred. A component ideally is some kind of general behavior that can be reused. Examples might be:

MousePickComponent - A component that is looking for being picked by the mouse and fires events

when it is. You could attach this to any game object that you want to be mouse picked.

LoadLevelComponent - A component that loads a new scene.

GUIButtonComponent - A component that looks for the mouse being pressed down and within a certain

area on the screen and fires an OnClick event when that happens.

 

 

A very primitive setup of this has been create to validate it. I will be working on getting the editor up and looking more professional.

 

 

med_gallery_112_32_2199.jpg

Rick

Warlords - 2/22/2010

I implemented rising numbers of the amount of damage or healing that is happening to a unit. I spent a decent amount of time to have it like a billboard so it had depth but I think I'm better off just using DrawText() instead. It looks better. I made the the Shield Slam cause 5 damage and it worked very well. Just 1 minor bug with the way the health bar is drawn on the right hand side. Instead of the just the width to worry about like the left hand side I need to change the x value and the width.

 

Everything seems setup to just mass add abilities so that's what I'll be doing over the next few weeks. Time to just start brainstorming on all sorts of different abilities. I'm open for suggestions also.

Rick

Warlords

This will be my dev blog for Warlords. It's coming along very nicely and I'm very proud of what I have so far. This is a game that has been in my head for a long time. I've made past attempts to make this game but they all failed because when I would find a "bug" in Leadwerks that would set me back I would just stop. This time I'm determined to complete this game. Players don't care about if you had to hack something together and now either will I. If Leadwerks has a bug or doesn't do something and there is a way to hack around it I will use that. I can't let these little things stop my dream of completing this game. I think this game will bring many hours of enjoyment to many people and I want to be able to give them that.

 

So about the development. The first ability is up and working. The Protector class has a Shield Slam ability that knocks back their target. I'm very excited about it because it works really nice. It'll play into the Protectors role of, well, protecting their teammates. Here is a brief description of each class in the game.

 

Protector : Protectors use their one-handed sword and shield to help protect their teammates. They have a ton of hit points and a ton of armor but don't do much damage. The Protector lives for the front line. They have abilities that will transfer damage to them when done to their teammates, to force the enemy to attack it, & to give their teammates a chance to retreat for help.

 

Cleric : Clerics are healers and buffers. They have the ability to heal their teammates directly or over turns. They are pretty squishy though. It doesn't take many hits to bring the Cleric to it's knees. Because of this they also have buffs that they can put on themselves or their teammates to help ease the damage. Clerics generally like to sit in the back away from danger and heal their teammates. They also have the ability to bring fallen enemies back to life, although at a great cost to themselves.

 

Archer : Archers sit in the back also. They like to pick away at people from a distance. They don't have much armor, but can do a ton of damage. If you get close to an archer though, they don't have many defenses to protect themselves.

 

Assassin : Assassin are sneaky and sly. They have the ability to go into the shadows and become invisible. They can strike at any time and when they do strike it's with great power. Once exposed the assassin has very little defenses which make it an easy target.

 

Wizard : Wizards are great magicians that strike down the enemy with magic power from a distance. They also have powerful debuffs at their disposal to weaken the enemy over turns. Like Clerics, Wizards are very squishy, so it doesn't take much to bring one down.

 

 

With these 5 classes and all their abilities the battle is on. Knowing your abilities and when to use them is huge in this tactical battle of Warlords!

Rick

I got all 3 of these functions working. I'm working on an script to show how these 3 will work.

 

DoSound(cr, 'abstract::hello.wav')

DoMoveTo(cr, fw.main.camera, GetEntityByName("pivot01"), .05, 1) -- moving the camera to the pivot named pivot01 at a rate of 0.5 and it'll stop when it's at a distance of 1. This move function doesn't use physics. Another function will use physics for movement.

Rick

DoWait() working

So I was able to get DoWait() working. It's not 100% ideal because you have to piggy back off another entities Update() method because of the limitation of not being able to have any global values. If you would like to try it out I'll give the steps here.

 

1. Make a file under the /Scripts directory named cr.lua and paste this code in it:

tblWait = {}
waitID = 1

clsWait = {}
clsWait.__index = clsWait

function clsWait.create(tm, func)
local wait = {}
setmetatable(wait, clsWwait)

wait.interval = tm
wait.cr = func
wait.createTime = AppTime()

return wait
end

function Init()
-- clear the table
for i=1, table.getn(tblWait) do
	table.remove(tblWait, i)
end

SetGlobalNumber("game", 2)
end

function RunScript(func)
cr = coroutine.create(func)

coroutine.resume(cr, cr)
end

function DoWait(cr, interval)
a = clsWait.create(interval, cr)
tblWait[waitID] = a
waitID = waitID + 1

coroutine.yield()
end

function UpdateCR()
local tblDeleteWait = {}
local i = 1

for k, v in pairs(tblWait) do
	if(AppTime() - v.createTime > v.interval) then
		coroutine.resume(v.cr, v.cr)

		tblDeleteWait[i] = i
	end

	i = i + 1
end

for k, v in pairs(tblDeleteWait) do
	table.remove(tblDeleteWait, v)
end
end

 

2. Replace your fpscontroller.lua code with the below code: (note backup your file :D )

All I did was create 2 global numbers and changed how the loop ends. You can end it with an escape if you like

dofile("Scripts/constants/collision_const.lua")
dofile("Scripts/constants/engine_const.lua")
dofile("Scripts/LinkedList.lua")
dofile("Scripts/filesystem.lua")
dofile("Scripts/math.lua")
dofile("scripts/classes/bullet.lua")

fw=GetGlobalObject("framewerk")

if fw==nil then
Notify("Null framewerk object.",1)
return
end

--Variables
dx=0.0
dy=0.0
camerapitch=0.0
camerayaw=0.0
move=0.0
strafe=0.0

--Create a player controller
controller=CreateController(1.8,0.45,0.25,45)
controller:SetCollisionType(COLLISION_CHARACTER,0)
controller:SetPositionf(0,2,0,0)
controller:SetMass(10)

controller:SetPosition(fw.main.camera.position)
camerapitch=fw.main.camera.rotation.x
camerayaw=fw.main.camera.rotation.y
controller:Move(Vec3(0,-0.9,0))

local gunscale=0.6
local vwep = LoadMesh("abstract::vwep_hands.gmf")
LoadMesh("abstract::vwep_gun.gmf",vwep)
vwep:SetParent(fw.main.camera,0)
vwep:SetPosition(Vec3(-0.18*gunscale,-0.03*gunscale,0.37*gunscale),0)
vwep:SetScale(Vec3(0.04*gunscale,0.04*gunscale,0.04*gunscale))
local gundisplayposition = vwep:GetPosition()
sound_gunshot = LoadSound("abstract::gunshot.ogg")
source_gunshot = CreateSource(sound_gunshot)
source_gunshot:SetVolume(0.5)
vwep :SetShadowMode(0,1)
local displayposition=Vec3(-0.26/2.0,-0.03,0.19)
local muzzleflash = CreatePointLight(3)
muzzleflash:SetParent( vwep )
muzzleflash:SetColor(Vec4(1,0.6,0.0,1.0))
muzzleflash:SetPosition( displayposition )
muzzleflash:SetShadowMode(0)

HideMouse()
MoveMouse(GraphicsWidth()/2,GraphicsHeight()/2)
FlushKeys()
FlushMouse()

local pick
local camera = fw.main.camera
local remainingtime
local starttime=AppTime()
local gameduration=2--length of game in minutes
local gamemode=0

gunpos = vwep.position:Copy()

local smoothedgunswayamplitude=0.0
local smoothedgunswayspeed	=0.0
local guntime = 0.0
local recoil = 0.0
local lastfiretime=0.0
local smoothrecoil=0.0
local swaydamping=0.0
local smoothswaydamping=0.0
local lightsmoothing =0.0
local gunlight = 0.0

--Flashlight
flashlight = {}
flashlight.light = CreateSpotLight(8)
flashlight.light:Hide()
flashlight.sound_switch = LoadSound("abstract::switch.wav")
flashlight.state=0
flashlight.light:SetConeAngles(30,35)
flashlight.light:SetRotation(Vec3(5,0,0))
flashlight.light:SetShadowmapSize(512)
flashlight.light:Paint(LoadMaterial("abstract::flashlight.mat"))

function flashlight:SetState( state )
if state~=self.state then
	self.state=state
	if state==0 then
		self.light:Hide()
	else
		self.light:Show()
	end
	if self.sound_switch~=nil then
		self.sound_switch:Play()
	end
end
end


function ShootBullet( position, direction )
--	local speed=100.0
--	local pick = LinePick( position, Vec3(position.x+direction.x * speed) )
end


SetGlobalNumber("game", 1)
SetGlobalNumber("runGame", 1)


--main function
--while KeyHit(KEY_ESCAPE)==0 do
while GetGlobalNumber("runGame") == 1 do
jump=KeyHit(KEY_SPACE)*6.0
if controller:IsAirborne()==1 then jump=0 end

if KeyHit(KEY_ESCAPE) == 1 then
	SetGlobalNumber("runGame", 2)
end

local time = AppTime()/3200.0
local frame = time*(179.0-96.0)+96.0
frame=clamp( frame, 96, 179 )
vwep:Animate(96,1,0,1)


--Camera look
gx=round(GraphicsWidth()/2)
gy=round(GraphicsHeight()/2)
dx=Curve((MouseX()-gx)/4.0,dx,3.0/AppSpeed())
dy=Curve((MouseY()-gy)/4.0,dy,3.0/AppSpeed())
MoveMouse(gx,gy)
camerapitch=camerapitch+dy
camerayaw=camerayaw-dx
camerapitch=math.min(camerapitch,90)
camerapitch=math.max(camerapitch,-90)
fw.main.camera:SetRotationf(camerapitch,camerayaw,0,1)

movespeed=6
movesmoothing=10
if controller:IsAirborne()==1 then
	movesmoothing=200
end

--Player movement
move=Curve( (KeyDown(KEY_W)-KeyDown(KEY_S))*movespeed,move,movesmoothing)
strafe=Curve( (KeyDown(KEY_D)-KeyDown(KEY_A))*movespeed,strafe,movesmoothing)

--Use objects
if KeyHit(KEY_E)==1 then
	pick=CameraPick(camera,Vec3(GraphicsWidth()/2,GraphicsHeight()/2,2.0),0,0)
	if pick~=nil then
		repeat
			if pick.entity:GetClass()==ENTITY_MODEL then
				break
			end
			pick.entity=pick.entity.parent
		until pick.entity==nil
		if pick.entity~=nil then
			pick.entity:SendMessage("use",controller,0)
		end
	end
end

--Update controller
controller:Update(camerayaw,move,strafe,jump,40,10)

fw:Update()

if KeyHit(KEY_F)==1 then
	flashlight:SetState(1-flashlight.state)
end

--Position camera
camera:SetPositionf(controller.position.x,controller.position.y+0.8,controller.position.z,1)

time=AppTime()
gunfirefrequency=80
gunswayspeed=0.001*20.0
gunoffset = gunpos:Copy()
gunswayamplitude = 0.02
if KeyDown(KEY_W)==1 or KeyDown(KEY_D)==1 or KeyDown(KEY_A)==1 or KeyDown(KEY_S)==1 then
	gunswayamplitude = 0.03
	gunswayspeed=0.005*20.0
end
smoothedgunswayamplitude = Curve( gunswayamplitude, smoothedgunswayamplitude,8.0  )
smoothedgunswayspeed = Curve( gunswayspeed, smoothedgunswayspeed,8.0 )
if smoothrecoil<0.001 then
	guntime = guntime + AppSpeed() * smoothedgunswayspeed * math.max(0.0,1.0 - smoothswaydamping)
end
gunoffset.z = gunoffset.z - smoothrecoil * 0.05
--smoothedgunswayamplitude = smoothedgunswayamplitude * (1.0 - smoothswaydamping)
gunoffset.x = gunoffset.x + math.sin( guntime ) * smoothedgunswayamplitude * gunscale
gunoffset.y = gunoffset.y + (1.0-math.cos( guntime*2.0 )) * 0.005 * gunscale-- * math.min(1.0,1.0 - smoothswaydamping))
vwep:SetPosition( gunoffset )
recoil = recoil-0.1
swaydamping = math.max( swaydamping - 0.05, 0.0 )
recoil = math.max(recoil,0.0)
smoothrecoil=Curve(recoil,smoothrecoil,3.0)
smoothswaydamping = inc( swaydamping ,smoothswaydamping,0.01 )
gunlight = math.max( gunlight- 0.2, 0.0 )
lightsmoothing =gunlight-- Curve(gunlight,lightsmoothing,8.0)
muzzleflash:SetColor(Vec4(1.0*lightsmoothing,0.6*lightsmoothing,0.0,1.0))
if lightsmoothing <0.01 then
	muzzleflash:Hide()
end
if MouseDown(1)==1 then
	if AppTime()-lastfiretime>gunfirefrequency then
		recoil = 1.0
		lastfiretime=AppTime()+math.random(0,20)
		gunswayspeed=0.0
		gunlight = 1.0
		source_gunshot:Play()
		source_gunshot:SetPitch(1.0 + (math.random()-0.5)*0.05 )
		swaydamping = 1.0
		muzzleflash:Show()

		CreateBullet(vwep:GetPosition(1) , fw.main.camera.mat:K():Scale(300))

	end
end

UpdateBullets()

flashlight.light:SetPosition(fw.main.camera:GetPosition(1))
flashlight.light:SetRotationf( curveangle( fw.main.camera.rotation.x, flashlight.light.rotation.x, 3.0/AppSpeed() ), curveangle( fw.main.camera.rotation.y, flashlight.light.rotation.y, 3.0/AppSpeed() ) )
flashlight.light:Movef(-0.07,-0.04,0.02)

print("Testing")
fw:Render()
Flip(0)

end

controller:Free()
ShowMouse()

 

3. Open up the editor.

4. Create a terrain.

5. Drop the Monstertruck model class into your scene.

6. Open up the monsterstruck lua file from the editor and replace the code. Note, you may want to backup this file also.

 

dofile("scripts/base.lua")
dofile("scripts/cr.lua")



function Spawn(model)
local entity=base_Spawn(model)
local pivot
local suspensionlength=0.25
local springconstant=30.0
local springdamper=100.0

Print("Inside Spawn")
init = false
Init()

entity.vehicle=CreateVehicle(model)
entity.tire={}
entity.model.userdata = entity.vehicle

pivot=entity.model:FindChild("tireL1")
if pivot~=nil then
	tireradius=pivot.aabb.h/2.0
	entity.vehicle:AddTire(TFormPoint(pivot.position,pivot.parent,model),tireradius,suspensionlength,springconstant,springdamper)
	entity.tire[0]=LoadMesh("abstract::vehicle_monstertruck_tire_left.gmf")
	pivot:Hide()
end

pivot=entity.model:FindChild("tireL2")
if pivot~=nil then
	tireradius=pivot.aabb.h/2.0
	entity.vehicle:AddTire(TFormPoint(pivot.position,pivot.parent,model),tireradius,suspensionlength,springconstant,springdamper)
	entity.tire[1]=LoadMesh("abstract::vehicle_monstertruck_tire_left.gmf")
	pivot:Hide()
end

pivot=entity.model:FindChild("tireR1")
if pivot~=nil then
	tireradius=pivot.aabb.h/2.0
	entity.vehicle:AddTire(TFormPoint(pivot.position,pivot.parent,model),tireradius,suspensionlength,springconstant,springdamper)
	entity.tire[2]=LoadMesh("abstract::vehicle_monstertruck_tire_right.gmf")
	pivot:Hide()
end

pivot=entity.model:FindChild("tireR2")
if pivot~=nil then
	tireradius=pivot.aabb.h/2.0
	entity.vehicle:AddTire(TFormPoint(pivot.position,pivot.parent,model),tireradius,suspensionlength,springconstant,springdamper)
	entity.tire[3]=LoadMesh("abstract::vehicle_monstertruck_tire_right.gmf")
	pivot:Hide()
end

function entity:UpdateTires()
	for n=0,3 do
		if self.tire[n]~=nil then
			self.tire[n]:SetMatrix( self.vehicle:GetTireMatrix(n) )
		end
	end
end

entity.model:SetKey("collisiontype",COLLISION_PROP)
entity.model:SetKey("mass",1.0)
return entity
end

function Kill(model)
local entity
entity=entitytable[model]
if entity~=nil then
	if entity.tire[0]~=nil then entity.tire[0]:Free() end
	if entity.tire[1]~=nil then entity.tire[1]:Free() end
	if entity.tire[2]~=nil then entity.tire[2]:Free() end
	if entity.tire[3]~=nil then entity.tire[3]:Free() end
end
end

function MyScript(cr)
Print("Inside MyScript() before DoWait()")
DoWait(cr, 10000)	-- wait 5 seconds
Print("Inside MyScript() after DoWait()")
SetGlobalNumber("runGame", 2)	-- exit the game
end

function Update(model)
local model
local entity
for model,entity in pairs(entitytable) do
	entity:UpdateTires()
end

if(init == false) then
	if(GetGlobalNumber("game") == 1) then
		Print("Running MyScript")
		init = true
		RunScript(MyScript)
	end
end

UpdateCR()

--Print("Inside monster truck")
end

 

7. Run the game from the editor and wait 10 seconds. The game will automatically end and go back to the editor after 5 seconds.

 

 

So what should you be looking for? in the monstertruck lua file I include cr.lua. This exposes some method and creates some tables. In the monster truck lua file I added UpdateCR() inside the Update() method. This is what I mean by piggy backing off another entities Update() method. If we would be able to have global variables you wouldn't need to do this step. In monstertruck I create a sort of init method. It makes it so when running in the game mode and the first time it calls Update() it'll run a function that defines the sequence you want to do. In this case it runs MyScript(). This is where the magic happens. It calls DoWait() and passes in 10000 (in ms 10 seconds). This is where it gets complicated to understand how it really works. If you take it at face value without knowing anything about programming it's easy. It means wait for 10 seconds but continue to run the game. Don't block the game for 10 seconds, that would be worthless.

 

If you study cr.lua you can see how coroutines work. Basically I assigned MyScript() as a coroutine. This allows me to jump out of MyScript() at any time with a call to coroutine.yield() when that's called from inside MyScript(). So then the question is how would we get back inside MyScript()? The answer is inside DoWait() & UpdateCR(). DoWait() adds an entry to the a table that stores the coroutine created, how long to wait, and the started app time. Inside UpdateCR() it loops through all entries in this table to see if the interval time has past. When it does it uses the coroutine stored to start up the MyScript() function again at where it left off.

 

So you can see how you can expand this to other functions. You can do a DoSound() that comes back after the sound file is completed. You can do a DoMove() which could move 1 entity to another at a given step and only come back into your sequence function when it reached it's destination. These 3 functions alone open up the door to so many interactive options that are easy to script.

Rick

Coroutines

I'm currently working on coroutines in lua. This will help people setup scripting sequences for their game. The cool part of this will be that you will use it in the editor like any other entity. Drag it into your scene and now in your other scripts you'll have access to these functions. Here is an example usage of what you would do in lua.

 

 

--- This defines the function that stores your script sequence
function MyScript01(cr)   -- cr is the coroutine to this function. The functions that pause execution of the script require it to be passed in
  MoveTo(cr, player, pivot1)   -- This method will move the player entity to the pivot1 entity and only return when it has reached it's destination
  PlaySound(cr, "hello.wav")   -- This method will return only after the hello.wav is finished playing
  PlayAnimation(cr, "animation") -- This method returns after the animation is complete
  Wait(cr, 2000)      -- This method will simply wait for 2 seconds before returning. Time is in ms.
end

-- When you are ready to run your script function simply pass the function to RunScriptFunction() and it'll start playing out
RunScriptFunction(MyScript01)

 

This can give us more interactive games than seen in the past with LE. You could create a volume trigger that runs a script when it's touched by the player, that moves an NPC to a location. Have it start talking. Have it play an animation, etc all in sequence. Maybe you make a button in game that when the player presses the 'use' key it runs a script. The script could do all sorts of things.

 

The main benefit of using coroutines like this is that the function where you define your script is actually "paused" until something restarts it again. This means that your game continues to run. That's where I come in. I'm defining the function that will pause and how they will start up again. I'm interested in hearing if people have other functions that would be useful to them that act like this. So far the functions I have are:

 

Wait()

MoveTo()

PlayAnimation()

PlaySound()

Rick

Character Thingoids

I've made and continue to work on 3 objects that you can drag into the editor and get player movement features in about 2 mins. I'll discuss them and their plans here. I prefix them with Pi because that's my sort of namespace so when you place these in your editor's path they won't have the same name as other objects you create/download. Pi is the start of my last name and I'm using it as a brand or sorts also.

 

Character

http://leadwerks.com/werkspace/index.php?app=downloads&showfile=46

 

This is a generic character object. Instead of creating objects for all your characters and placing them in your scene, you just need this object. It creates a character controller and allows you to assign a model. So you can have 100 of these objects in your scene and they can all have different models. This object also accepts some messages for moving the character controller. Right now this is pretty basic but it will get advance and something that should cover most character movement needs.

 

3rd Person Camera

http://leadwerks.com/werkspace/index.php?app=downloads&showfile=45

 

Drag this into your scene and give it a target (anything). Set some offsetting values and this will give you 3rd person camera controls on that target. The future of this is that it'll be able to handle any type of camera setting. 3rd perseon, first person, top/down etc just by setting some keys.

 

Character Keyboard Controls

http://leadwerks.com/werkspace/index.php?app=downloads&showfile=47

 

This will bring life to your Character object. It's meant to work out of the box with the Character object above, but it can work for any object you have as long as you receive some messages that the Keyboard control sends. This allows you to define which keys will move characters.

 

 

 

The part I'm not the most fond of is that the editor uses very specific game scripts. The fps, vehicle, and flythrough. I'm not a fan of how this is setup myself. I think the game script should be very basic and that objects that you drag into your scene are what builds how the game works. So in order for the above 3 objects to work correctly they need the following game script to be running when you run the game. The reason for this is because of keyboard controls and mouse controls. The default game scripts al do something with the keyboard and mouse and if you used them with the above objects they would be fighting for the camera and keyboard controls.

 

require("Scripts/constants/collision_const")
require("Scripts/constants/engine_const")
require("Scripts/LinkedList")
require("Scripts/filesystem")
require("Scripts/math/math")



if fw==nil then --we are not in Editor
       RegisterAbstractPath("")
       Graphics(800,600)		-- need a better way to get screen res
       fw=CreateFramework()
       scene=LoadScene("")		-- need a way to get a scene to load
       scene:SetCollisionType(COLLISION_SCENE)
       TFilter(1)
       AFilter(4)
end

-- set globals
SetGlobalString("mode", "GAME_MODE")
SetGlobalString("quit", "false")

FlushKeys()
FlushMouse()


--main function
while (KeyHit(KEY_ESCAPE) == 0) and (GetGlobalString("quit") == "false") do

       fw:Update()
       fw:Render()
       Flip(0)
end

-- reset values
SetGlobalString("mode", "DESIGN_MODE")
SetGlobalString("quit", "false")