Until now all geometry was generated and processed beforehand, which is a bad thing for a number of reasons. Firstly, generating a small asteroid (about 200 meters in diameter) with an acceptable vertex density for a camera situated at 50 meters was producing a total of 327k triangles. That's foolish. Now if I wanted to show more than one asteroid at the same time I'd be screwed. Another major problem was the asteroid size. If I had an asteroid double the size (400 meters in diameter) the vertex density would be halved, so maintaining the mesh resolution will produce 327k x 2 triangles.
Because of these huge limitations I decided to add some form of LOD (level of detail) to the engine,, meaning that visible geometry will be rendered with the appropiate number of triangles based on the distance to the camera.
I've uploaded a video showing my first attempt at Chunked LOD.
The fun thing here is that the whole cube is rendered using the same single quad (4 vertices and 2 triangles)
Yabadevanindie
Yet another blog about developing an indie game with the Unity 3D engine.
0 Something to show
I've posted some screenshots of procedurally-generated asteroids. They still look quite spherical but I have a few ideas about how to squeeze them a little so they look more like... you know... asteroids.
I'm also still tweaking the shaders, but they already pretty much look like I want.
So, have a look to the gallery!
I'm also still tweaking the shaders, but they already pretty much look like I want.
So, have a look to the gallery!
0 Unity and the Garbage Collector
This is something I knew I had to deal with sooner or later. Not that this is the right moment to start worrying about memory or performance, but I felt the need to at least understand how this is going to affect the game when it comes the time.
I like to write declarative code and C# is very good at it, which is kind of evil if you ask me. In imperative languages you write code that describes how things have to be done. In declarative languages you write code that describes what's to be done no matter how, which basically means: the more you move away from imperative towards declarative, the more you allow your programming language, run-time or compiler do things its way, not yours.
In the case of Mono for Unity, letting it to do things its way will result in hundreds of thousands of little memory allocations, which is not a big deal since allocating memory on these platforms is really cheap, The problem is that this massive amount of allocations causes the garbage collector to kick-in quite often. While garbage collection is not a bad thing in itself, it's definitely something you want to avoid at all costs in FPS-sensitive games.
There are three main sources of declarative awesomeness that will feed the garbage collector heavily:
Every time a closure is called, the CLR will allocate memory to create an object which contains all the captured state. Place this within a tight loop and there you have it. Since I love the succint and concise code you can write with them, I tried to get around this limitation. I came up with a solution which consists of just stripping out the state and turning them into mere anonymous functions like this:
It's hard to imagine how much evil is hidden under this keyword. Unless the underlying type is known at compile time to be an array, two things will happen:
-Due to a bug, each call to foreach (not every iteration!) will cause the returned Enumerator object
to be boxed, thus eating 24 bytes of memory in the way. This is an ancient known bug but it's still not fixed in Unity 4.6
-For every iteration, the 'MoveNext()' function is called, which performs some kind of validation. A lot of people will argue that this is not an issue, but in my case, using iterators within high-frequency functions (which is quite common in video-games) will kill the frame rate.
Using LINQ extension methods is just like using 1. and 2. but on steroids. Nearly every function in there will not only allocate closures and foreach calls, but also a lot of temporary arrays and lists.
If you want to be safe, try to stay away from the declarative part of C# and just make your sensible code look like C++.
I like to write declarative code and C# is very good at it, which is kind of evil if you ask me. In imperative languages you write code that describes how things have to be done. In declarative languages you write code that describes what's to be done no matter how, which basically means: the more you move away from imperative towards declarative, the more you allow your programming language, run-time or compiler do things its way, not yours.
In the case of Mono for Unity, letting it to do things its way will result in hundreds of thousands of little memory allocations, which is not a big deal since allocating memory on these platforms is really cheap, The problem is that this massive amount of allocations causes the garbage collector to kick-in quite often. While garbage collection is not a bad thing in itself, it's definitely something you want to avoid at all costs in FPS-sensitive games.
There are three main sources of declarative awesomeness that will feed the garbage collector heavily:
1. Closures
/// <summary> /// Turning a closure into an anonymous function /// </summary> public void DoSomething( string _name ) { // this will capture the parameter _name, thus creating an object Closure( () => _name ); // this version will 'capture' _name as a parameter, // thus turning the closure into a mere local anonymous function ClosureNOT( _name, _n => _n ); } public void Closure( Func<string> _getStrFn ) { var str = _getStrFn(); // ... } public void ClosureNOT( string _str, Func<string, string> _getStrFn ) { var str = _getStrFn( _str ); // ... }
2. The 'foreach' keyword
It's hard to imagine how much evil is hidden under this keyword. Unless the underlying type is known at compile time to be an array, two things will happen:
-Due to a bug, each call to foreach (not every iteration!) will cause the returned Enumerator object
to be boxed, thus eating 24 bytes of memory in the way. This is an ancient known bug but it's still not fixed in Unity 4.6
-For every iteration, the 'MoveNext()' function is called, which performs some kind of validation. A lot of people will argue that this is not an issue, but in my case, using iterators within high-frequency functions (which is quite common in video-games) will kill the frame rate.
3. LINQ:
If you want to be safe, try to stay away from the declarative part of C# and just make your sensible code look like C++.
It's been a lot of time since I updated this blog for the last time. It would seem that the project had been abandoned. Far from it. I've been actively working on this project but I realized that maintaining a blog requires a lot of work and energy and I just don't have the time.
During the past few months I've been working on the prototype and now I can say I have something going on. I've also found a couple of people who are willing to help with design so I can focus on programming.
That's all I can say for now...
During the past few months I've been working on the prototype and now I can say I have something going on. I've also found a couple of people who are willing to help with design so I can focus on programming.
That's all I can say for now...
0 Scripting with Unity 3D: Coding "into" Unity vs. Coding "in" Unity
Looks like Unity is going to stay around for a while. It's getting better with every version. Much wanted features are added, new platforms are supported, better performance, better graphics... and the list goes on. If I were to create a start-up today, Unity 3D will be my tool of choice hands down.
However, let's not forget it's a tool and it's not going to last forever. Eventually, some other tools will flourish, embracing new technologies, new devices, new platforms, better languages, or just being cheaper or having an editor with all beautiful colors. Of course this doesn't mean you'll quit making games. This means you'll go through the painful path of learning new ways of doing the same old stuff. It's always been like this. Although there's no way to get rid of this learning curve, wouldn't it be nice to try and minimize the impact? Certainly you can't prepare yourself for an imaginary tool that doesn't exist yet, but you can do things that will help you in the future.
In object-oriented programming, when some part of a program needs to interact with some other part, it's usually done in the most abstract way possible, normally through interfaces or abstract classes. A lot of the cool features found in OOP, if not all, stem from sheer common sense, so wouldn't it be wise to apply common sense for everything? My common sense dictates me that while coding into Unity, or whatever medium for that matter, I try at the same time to stay away from that medium as much as I can. I usually code as if I had to port my game to a different medium tomorrow, forcing me to separate medium-agnostic code from medium-dependent code, which in turn forces me to first think in medium-agnostic terms and thus not producing medium-dependent thoughts.
Following this premise, my common sense also tells me to not put all my code in scripts. Because not every piece of code needs to be a script. I regard scripts as if they were little wrappers encapsulating some medium-specific features, like manipulating some GameObject's transform, playing a sound, reading input, tweaking some camera's properties... you get the idea. I put the rest of the code in normal classes and make sure these classes don't reference medium-dependent assemblies. (In practice this is usually not feasible since you'll probably be using some of the medium's basic types for everything, like Unity's Vector3, but I like to think of them as coincidental dependencies)
But, why bother? Doing things like this will make you slightly slower, probably. Let's say it makes you 10% slower. If you look at the final product, it may seem you wasted 10% of your resources by doing it in a different way just for the sake of it, but it's not the case. Actually you've invested that amount in modeling, sharpening and polishing your own tools, like your way of approaching problems and the way of coming up with solutions. Not a waste at all. Even if Unity is here to stay forever.
However, let's not forget it's a tool and it's not going to last forever. Eventually, some other tools will flourish, embracing new technologies, new devices, new platforms, better languages, or just being cheaper or having an editor with all beautiful colors. Of course this doesn't mean you'll quit making games. This means you'll go through the painful path of learning new ways of doing the same old stuff. It's always been like this. Although there's no way to get rid of this learning curve, wouldn't it be nice to try and minimize the impact? Certainly you can't prepare yourself for an imaginary tool that doesn't exist yet, but you can do things that will help you in the future.
"Programmers who program "in" a language limit their thoughts to constructs that the language directly supports. If the language tools are primitive, the programmer's thoughts will also be primitive.I think this is true not only for languages, but for any means to an end. I'm not saying that Unity is primitive, but it's just a medium and thus it's limiting by its own nature. Knowledge and experience are never replaced but tools and technologies are, so I'd rather put technology at the service of knowledge and not the other way around.
Programmers who program "into" a language first decide what thoughts they want to express, and then they determine how to express those thoughts using the tools provided by their specific language."
(Steve McConnell - Code Complete)
In object-oriented programming, when some part of a program needs to interact with some other part, it's usually done in the most abstract way possible, normally through interfaces or abstract classes. A lot of the cool features found in OOP, if not all, stem from sheer common sense, so wouldn't it be wise to apply common sense for everything? My common sense dictates me that while coding into Unity, or whatever medium for that matter, I try at the same time to stay away from that medium as much as I can. I usually code as if I had to port my game to a different medium tomorrow, forcing me to separate medium-agnostic code from medium-dependent code, which in turn forces me to first think in medium-agnostic terms and thus not producing medium-dependent thoughts.
Following this premise, my common sense also tells me to not put all my code in scripts. Because not every piece of code needs to be a script. I regard scripts as if they were little wrappers encapsulating some medium-specific features, like manipulating some GameObject's transform, playing a sound, reading input, tweaking some camera's properties... you get the idea. I put the rest of the code in normal classes and make sure these classes don't reference medium-dependent assemblies. (In practice this is usually not feasible since you'll probably be using some of the medium's basic types for everything, like Unity's Vector3, but I like to think of them as coincidental dependencies)
But, why bother? Doing things like this will make you slightly slower, probably. Let's say it makes you 10% slower. If you look at the final product, it may seem you wasted 10% of your resources by doing it in a different way just for the sake of it, but it's not the case. Actually you've invested that amount in modeling, sharpening and polishing your own tools, like your way of approaching problems and the way of coming up with solutions. Not a waste at all. Even if Unity is here to stay forever.
Labels:
Programming
,
Source code
,
Unity
Today I received an e-mail from technorati which said that my blog claim process was now complete. That's nice except for the fact I claimed it a week ago. Looks like everything in Technorati is slow.
0 Hansel Script
This is one of the first (if not the first) script I wrote using GuayScript instead of MonoBehavior. It wasn't created for anything in particular, but it'll surely end up being part of some enemy's behavior.
It keeps track of its GameObject position, and will send a notification every time it's has traveled a certain distance. The interesting part about it it's that it shows how notifications can be edited by the level designer for maximum flexibility.
It keeps track of its GameObject position, and will send a notification every time it's has traveled a certain distance. The interesting part about it it's that it shows how notifications can be edited by the level designer for maximum flexibility.
/// <summary> /// Hansel script will drop a pebble (trigger an event) whenever a certain distance has been covered /// </summary> public class HanselScript : GuayScript { /// <summary> /// Distance between pebbles /// </summary> public float DistBetweenPebbles; /// <summary> /// Event notified everytime the distance is covered /// </summary> public Notification DropPebbleEvent = "pebbleDropped"; /// <summary> /// Ctor, /// </summary> public HanselScript() { var lastPosition = new Vector3(); var accDistance = 0f; OnAwake = _properties => lastPosition = GameObject.transform.position; OnUpdate = _deltaTime => { accDistance += (GameObject.transform.position - lastPosition).magnitude; if( accDistance >= DistBetweenPebbles ) { accDistance -= DistBetweenPebbles; Notify( DropPebbleEvent ); } lastPosition = GameObject.transform.position; }; } }
Labels:
GuayScript
,
Source code
,
The Guay Framework
0 The Message System
Messaging is at the core of any component-based system. Rather than directly calling other component's methods, you send messages to a postal address instead. If there happens to be a component listening to these messages from that address, it will receive them.
All this functionality is offered by the PostOffice class. This class works at a very low level. It doesn't know about the Guay Framework or Unity. It just knows about addresses and message ids.
To listen to a specific message, you provide an address, a message identifier and a message callback. The callback will be called whenever someone sends that message to that address.
Likewise, to send a message you call the following method specifying an address, a message id and a list of parameters:
You can also can broadcast a message through the method:
Let's see an example:
This example shows what working with the typical message system looks like. However, this class is not directly exposed to the game code. Instead, the Guay Framework makes use of the PostOffice class internally, presenting a Unity-friendly interface which makes messaging really easy to use from scripts. You can find more information about this in the description of the GuayScript script.
All this functionality is offered by the PostOffice class. This class works at a very low level. It doesn't know about the Guay Framework or Unity. It just knows about addresses and message ids.
To listen to a specific message, you provide an address, a message identifier and a message callback. The callback will be called whenever someone sends that message to that address.
public void Subscribe( object _address, string _message, MessageCallback _callback ) { .... }
Likewise, to send a message you call the following method specifying an address, a message id and a list of parameters:
public void Send( object _address, string _message, params object[] _params ) { ... }
You can also can broadcast a message through the method:
public void Broadcast( string _message, params object[] _params ) { ... }
Let's see an example:
public class Player { public Player() { ExampleApp.PostOffice.Subscribe( "gameAddress", "gameStart", ( _event, _params ) => { Debug.WriteLine( "The game has started!!" ); } ); } } public class Game { public void Start() { ExampleApp.PostOffice.Send( "gameAddress", "gameStart" ); } } public class ExampleApp { private static PostOffice mPostOffice; /// <summary> /// Retrieves the post office /// </summary> public static PostOffice PostOffice { get { return mPostOffice ?? (mPostOffice = new PostOffice( false )); } } public ExampleApp() { // a game is created var game = new Game(); // player is created. it will subscribe to the "gameStart" message var player = new Player(); // the game starts, sending the "gameStart" message to the address "gameAddress", // the message will be queued. game.Start(); } public void Update() { // once per frame, the post office is updated, delivering all queued messages. // Player will get the "gameStart" message PostOffice.Update(); } }
This example shows what working with the typical message system looks like. However, this class is not directly exposed to the game code. Instead, the Guay Framework makes use of the PostOffice class internally, presenting a Unity-friendly interface which makes messaging really easy to use from scripts. You can find more information about this in the description of the GuayScript script.
Labels:
GuayScript
,
Messaging
,
Source code
,
The Guay Framework
,
Unity
0 The Guay Framework explained
I'm preparing a series of articles about each of the important aspects of the Guay Framework, namely:
- The messaging system.
- The GuayScript.
- Sending/receiving messages.
- Dynamic Properties.
Labels:
GuayScript
,
The Guay Framework
0 A quick glance at GuayScript
GuayScript is the of the central piecea of the Guay Framework. Its main goal is to provide your scripts a clean and very intuitive API to interface with a real component-based environment. The example below shows how simple is to communicate with the system. There's no need of looking for specific components, thus avoiding the creation of ugly dependencies.
I'll explain it all in detail in future posts.
Example of a typical GuayScript script
I'll explain it all in detail in future posts.
Example of a typical GuayScript script
// // Health script. Makes a GameObject to have 'life' // 'Implements' the HealthInterface interface // public class Health : GuayScript { GameObject OtherGameObject; public float MaxCapacity; public float Amount; public Health() { var dead = false; var currentHealth = Amount; OnAwake = _properties => { Messages[ HealthInterface.CmdIncrease ] = ( _id, _args ) => currentHealth += _args.Get(); Messages[ HealthInterface.CmdDecrease ] = ( _id, _args ) => currentHealth -= _args.Get (); Messages[ HealthInterface.CmdRefill ] = ( _id, _args ) => currentHealth = MaxCapacity; Messages[ HealthInterface.CmdDie ] = ( _id, _args ) => currentHealth = 0; }; OnUpdate = _deltaTime => { if( dead ) return; if( currentHealth <= 0 ) { dead = true; // components say interesting things through the Notify function Notify( HealthInterface.EvDead ); // components can also say interesting things to other objects OtherGameObject.Send( HealthInterface.EvDead ); } }; } }
Labels:
GuayScript
,
Messaging
,
Source code
,
The Guay Framework
,
Unity
0 Unity and The Component-Based Model
When I began fiddling with Unity I found that everything looked pretty familiar to me. Almost every game we've done in the past at my company has used an in-house component-based model. You don't get this model right away, specially if you've been writing games in a more traditional way. Getting it right requires a good understanding of some of the most important pillars of OOP: Abstraction, Strong cohesion and Loose Coupling to name a few. If you aren't familiar with these concepts I strongly recommend you to have a look at them.
To make the most out of a component-based approach, there's a few things to keep in mind:
You want each component to dedicate to a single and simple task. You want each component to just operate on a single problem domain. You want them to be as independent and self-sufficient as possible, and at the same time you want to design them in a way that lets you place them together seamlessly to work for a higher cause. The benefits of designing components like this are pretty obvious. They can be added, removed, changed or tweaked without causing much trouble to other components around them, if at all.
However, there's still an important aspect about them: Some of them talk. Some of them listen. Some say things about interesting events happening to them and some listen to these events and do interesting things in turn; or they simply ask other components to do something for them. What does this mean? If they communicate, they must use some kind of channel to do so. In 99% of the examples on the internet, this channel is a specific method call made to a specific component, found by any of the GetComponent() family of methods. This means that the caller has to know about the recipient's components. This means that a programmer has to know what components a level designer has put within the GameObject, thus creating not only a dependency in source code, but an inter-departmental dependency! Well, this is pure evil and actually defeats the whole purpose of the component-based model itself. There's a reason you design your classes using abstraction and encapsulation. Why wouldn't you do the same with your components?
So, how do we communicate to other components then? Through messaging. Messaging provides us a decoupled channel for communication. The responsibility of the sender is just to send a message through the proper channel. Sender does not need to know about the recipient's identity. Likewise, the responsibility of the recipient is to subscribe to the messages it wants to handle, without knowing about the sender identity.
Unity's Monobehavior does, in fact, support a half baked way to communicate to other components through messaging, but it's not to be trusted. It uses reflection which means it's incredibly slow. Yes, it's incredibly slow. If you go the messaging way, you'd be using messages for everything. Don't buy the "Ok, it's slow but it's meant to be used just here and there" argument. There's also strange methods like "SendMessageUpwards" which basically invites you to create a dependency within the lovingly-crafted-by-a-level-designer object hierarchy.
I honestly think Unity 3D has no real support for messaging, and out of the box, it's certainly near to impossible to take advantage of the many cool features that real component-based systems offer. That's why I decided to write this lightweight framework called "The Guay Framework".
I'll write more about this in future posts.
You want each component to dedicate to a single and simple task. You want each component to just operate on a single problem domain. You want them to be as independent and self-sufficient as possible, and at the same time you want to design them in a way that lets you place them together seamlessly to work for a higher cause. The benefits of designing components like this are pretty obvious. They can be added, removed, changed or tweaked without causing much trouble to other components around them, if at all.
However, there's still an important aspect about them: Some of them talk. Some of them listen. Some say things about interesting events happening to them and some listen to these events and do interesting things in turn; or they simply ask other components to do something for them. What does this mean? If they communicate, they must use some kind of channel to do so. In 99% of the examples on the internet, this channel is a specific method call made to a specific component, found by any of the GetComponent() family of methods. This means that the caller has to know about the recipient's components. This means that a programmer has to know what components a level designer has put within the GameObject, thus creating not only a dependency in source code, but an inter-departmental dependency! Well, this is pure evil and actually defeats the whole purpose of the component-based model itself. There's a reason you design your classes using abstraction and encapsulation. Why wouldn't you do the same with your components?
So, how do we communicate to other components then? Through messaging. Messaging provides us a decoupled channel for communication. The responsibility of the sender is just to send a message through the proper channel. Sender does not need to know about the recipient's identity. Likewise, the responsibility of the recipient is to subscribe to the messages it wants to handle, without knowing about the sender identity.
Unity's Monobehavior does, in fact, support a half baked way to communicate to other components through messaging, but it's not to be trusted. It uses reflection which means it's incredibly slow. Yes, it's incredibly slow. If you go the messaging way, you'd be using messages for everything. Don't buy the "Ok, it's slow but it's meant to be used just here and there" argument. There's also strange methods like "SendMessageUpwards" which basically invites you to create a dependency within the lovingly-crafted-by-a-level-designer object hierarchy.
I honestly think Unity 3D has no real support for messaging, and out of the box, it's certainly near to impossible to take advantage of the many cool features that real component-based systems offer. That's why I decided to write this lightweight framework called "The Guay Framework".
I'll write more about this in future posts.
Labels:
Programming
,
The Guay Framework
,
Unity
0 It won't happen to me!
I was googling about the percentage of newly created blogs that are abandoned. It looks like most of them don't get past their first month, which is really sad.
0 Man at work
As I said, maintaining a blog is definitely hard work. But the hardest part is setting it up. Still writing things I feel are needed in order for this blog to make sense. Tempted to press the 'Publish' button a couple times!
Labels:
General
,
Musings
,
The Sidewalk
0 In case you haven't noticed yet...
... my mother tongue is not English, (I'm Spanish). I'm always trying to do my best but I guess it'll be inevitable to find some awkwardly/poorly expressed sentences. I don't mind to be corrected at all. I'm serious, correct me or I'll never learn. You can even make fun of me.
0 On programming
I love programming, a lot. It's what I do all the time. It's what I've been doing for the last 25 years. What I do best is to dissect complex abstractions/concepts/problems into working, beautiful and harmonic pieces of code (ahem). I can also spend hours trying to come up with the correct name for a class or a method. This makes me a rather slow programmer. On extremely rare occasions I also fuck things up but hey...
0 C#
I started using it about 6 years ago (maybe more). Since then I've never written a single line of C++ code. (Luckily, my company also changed gears at the time and C++ was no longer needed).
I won't be probably using Unity at all if it had no C#.
Or not.
Who knows.
I don't.
I won't be probably using Unity at all if it had no C#.
Or not.
Who knows.
I don't.
0 Breaking things down
There's a wide range of things I'd like to talk about, so I've defined a few categories (labels) for tagging posts, like C#, Unity 3D, The Game, Programming, etc. Additionally, I'll be creating some extra pages to put content that won't change too much but will be essential for this blog to make any sense.
Subscribe to:
Posts
(
Atom
)