This is a hack (It only works with reflection) to let you achieve garbage free string concatenation in C#, Mono:
using System;
using System.Collections.Generic;
using System.Text;
using System.Reflection;
public class StringReference
{
public int MaxSize
{
get;
private set;
}
public int SpaceLeft
{
get { return MaxSize - StringLength; }
}
public int StringLength
{
get { return StringBuilder.Length; }
}
public string StringHandle
{
get;
private set;
}
public StringBuilder StringBuilder
{
get;
private set;
}
public StringReference(int maxSize=32)
{
Resize(maxSize);
}
public void Resize(int maxSize)
{
MaxSize = maxSize;
StringBuilder = new StringBuilder(maxSize, maxSize);
var initialized = false;
try
{
// This should work in Mono (Unity3D)
var typeInfo = StringBuilder.GetType().GetField("_str", BindingFlags.NonPublic | BindingFlags.Instance);
if(typeInfo != null)
{
StringHandle = (string)typeInfo.GetValue(StringBuilder);
initialized = true;
}
}
catch
{
try
{
// This might work on a .NET platform
var typeInfo = StringBuilder.GetType().GetField("_cached_str", BindingFlags.NonPublic | BindingFlags.Instance);
if (typeInfo != null)
{
StringHandle = (string)typeInfo.GetValue(StringBuilder);
initialized = true;
}
}
catch
{
throw new Exception("Can't get access to StringBuilders internal string.");
/*
* Uncomment this section to get a clue on how to get a reference to the underlying string:
*
Type t = StringBuilder.GetType();
foreach (var f in t.GetFields(BindingFlags.NonPublic | BindingFlags.Instance))
UnityEngine.Debug.Log(f.Name);
*/
}
}
}
public void Clear()
{
StringBuilder.Remove(0, StringBuilder.Length);
}
public void SetText(string text, bool fillOverflow = true)
{
SetText(ref text, fillOverflow);
}
public void SetText(ref string text, bool fillOverflow = true)
{
Clear();
var max = SpaceLeft;
if (text.Length >= SpaceLeft)
{
StringBuilder.Append(text, 0, max);
}
else
{
StringBuilder.Append(text);
if(fillOverflow) FillOverflow();
}
}
public void Append(ref string text)
{
var max = SpaceLeft;
if (text.Length >= SpaceLeft)
StringBuilder.Append(text, 0, max);
else
StringBuilder.Append(text);
}
public void Append(string text)
{
Append(ref text);
}
public void FillOverflow(char character = ' ')
{
var overflow = SpaceLeft;
if (overflow > 0)
StringBuilder.Append(character, overflow);
}
}
How to use:
StringReference str = null;
str = new StringReference(128);
str.StringBuilder.Append("This is an example of garbage-");
str.StringBuilder.Append("free string concatenation.");
Debug.Log(str.StringHandle);
Rapid { games }
Game development by Henrik Johansson
Monday, February 11, 2013
Saturday, August 25, 2012
Graphical Analyzing in Unity
The tool can help programmers visually measure, compare and analyze values that change over time. (This part was lazily copied straight from the product description page by the way).
Okay but what does it actually do?
Well the first part of the plugin keeps track of these graphs that you create (they automatically get created the first log call you do) and uses them to record values, both in memory (fixed amount) and also streamed to disk (endless) while your game is running.
While this is happening you can view these recorded values drawn as lines on a timeline in the editor window included in the package, the second part of the plugin.
Since the values are streamed to disk, after the game is stopped - all your recorded graphs will appear in a list which you can select and load in to look at in detail.
Why is this necessary? I can just use Debug.Log() to display a value, or use break points in the code and step through my code while I see what the values are. I can also just look at my inspector in Unity to see what the values of variables are at any time.
Well of course, you're absolutely right about that!
But let me give you a little back story as to why I created this tool and why it kept me from pulling out my hair while discovering some hard to find errors in my project.
So in this project I was working on (and still are) that's essentially a fighting game - not the standard 1 on 1 street fighter kind - but for the sake of this post It should give you a rough idea of what I'm talking about.
In this game I have a class that runs logic for a character that a player controls and this class has a LOT of states it can be in depending on if it's been hit, if it's on the ground, what animation is playing, how long a player holds certain buttons, etc. The list goes on.
So naturally there's a lot of timers being counted simultaneously, being constantly reset, sub states being turned on or off, and while in the middle of coding this thing I started having problem with a quick turn move the player could do to change direction while running causing the x velocity to spasm out for some unknown reason.
Because the amount of conditions this was relying on, I was having a really hard time figuring out what the heck was going on by just relying on the typical debugging methods.
Debug.Log calls would instantly become a cluster fuck because the sheer amount of calls flooding the console log, I had absolutely no idea where to look and for what number anomaly, so that was clearly not an option.
Using breakpoints to step though the code was also off the list, I had no idea when the conditions would become invalid and what method and calculation caused the problem.
So we are left with looking at the inspector trying to get a glimpse of what caused the anomaly. So while trying to play the game I kept my eyes looking at the inspector values frantically changing to see what was going on.
This also failed miserably, the timers had such short intervals that my eyes could barely could process the numbers being swapped per millisecond. Hmm - if that's the problem I'll just run the game in slow motion I thought! This was almost close too solving the problem but the new problem I was facing now was that I still didn't know exactly what to look for.
What was that value 3 frames before this? Did it change the expected amount in relation to that other timer that I saw was reset last frame? My memory could simply not keep track of all the little changes that happened each frame of the game. My memory is not that bad, just try to keep track of 5 of these "0.0019584" type's of values yourself! It's not that easy.
Well then I thought, what now? Should I just go through the code line by line and try to process the math in my brain with hypothetical numbers?
Then I remembered this article I read a while back about debugging using 'graphs' or something...
After a quick search I rediscovered this article, and after reading it I started coding on what was a very simple tool based on what I just read.
In the first version I tried using the web page approach, not even considering that I could use the editor to directly draw the graphs inside Unity. It was very cumbersome to use. I couldn't really see the graphs while the game was running. I had to stop the game, refresh the page and then try to analyze the graphs based on my latest run.
It suddenly hit me that why wouldn't I just use the wonderful editor and just code an extension so I don't even have to do these steps at all!
Then after some more tinkering it just came to me that this was simply meant to be shared, so it was clear that I should put this on the asset store so others could gain from this as well.
After some tweaking, some polish and even more tweaking I had the first version ready and now it's my first release on the asset store. Im very happy of how it turned out :)
I hope you will find this tool useful for your own projects and that it will save you from similar situations as I was in. I'm sure almost all game projects could seriously benefit from having the tool at their disposal (but then again, I'm obviously quite biased about this so I shall wait for reviews and see what people think).
- EDIT
New to version 1.1 is a feature called graph linking:
Thanks for reading, and as a final note, thanks Herman Tulleken for writing such an excellent article!
Wednesday, June 27, 2012
Garbage Collection
When programming games or any other kind of real time application in a managed environment (Ala .NET) one must pay extreme attention to the garbage collector if you care about this thing called performance, or, constant frame rate. I've seen plenty of blogs on the internet talk about this topic and give some examples of when garbage occur, but I thought I would gather some thoughts and experiences on the subject that I have managed to collect myself (see what I did there?).
I will also be talking from a Unity 3D perspective as it is the engine I use, which means it's not really MS .NET I'm talking about, it's really the Mono implementation. Actually, it's not even the official release of mono, Unity keeps their own version of mono to assure compatibility with all their beloved code, but it should apply to other implementations as well. Just don't take my word for it.
Before we jump in, the basic knowledge you must have is the difference between value types and reference types.
Value types get's put on the stack which is like a fast access buffer you could say.
These include:
* Any Number type (byte, short, int, long, float, double etc.).
* The DateTime struct.
* Or any other struct type
Reference types on the other hand will be put on the heap when created and when no longer used by the program, they will need to be collected and destroyed from memory, hence the term garbage collection. The most obvious cases include:
* Any class type
* Arrays (It doesn't matter what is stored in the array, the array itself is a reference type)
* Strings
If you want to know all the ins and outs of stack vs heap, value types vs reference types: I suggest you google the subject and get a good explanation from someone with the proper knowledge. MSDN is a good place to look.
Also, just to clarify; this example shows when a garbage collection will occur, it will not happen until you specifically are not using a certain object by nulling it's pointer, or in other terms, not having a variable in your program that holds a reference to the object in memory:
object obj = new object();
// do some stuff with our brand spankin' new object!
obj = null; // we no longer need this object, let the garbage collector deal with cleaning up after us.
Example using unity objects:
GameObject obj = new GameObject();
// do stuff
Destroy(obj);
The garbage collecting process won't happen instantly, it is instead run on interval's usually in seconds in between or so.
So sometimes it remains unclear what other things generates garbage and I thought I might shed light on as many things as possible, so here follows a list of things that will feed the garbage collector that you need to be careful about:
* Casting a value type to reference type. This is called boxing. Example:
int number = 5;
object obj = (object)number; // This will generate garbage
* Using a struct by passing it as a reference type. This is also called boxing. Example:
bool CompareTwoThings(IComparable a, IComparable b){ return a.Equals(b); }
int number1 = 15, number2 = 9;
CompareTwoThings(number1, number2); // This causes boxing and therefore generates garbage
- The workaround is to specify a value type constraint:
void CompareTwoThings<TComparable>(TComparable a, TComparable b) where TComparable : stuct, IComparable{ return a.Equals(b); }
* Using ToString() on any object or value type
* Concatenating strings. Example:
string a = "hello", b = " sir.";
Print(a + b);
* Using the System.Convert class (In some cases, will elaborate later)
* Using the BitConverter class (Again, haven't checked all cases)
* Some collections that provides an IEnumerable<> that you can enumerate on using foreach().
Collections that are safe to itterate on include: Arrays, List
* Declaring an IEnumerable<> method that uses yield return(s)
* Passing and calling delegates to a method (this includes anonymous methods as well). Example:
bool IsEven(int val) { return val % 2 == 0; }
private delegate bool EvaluateValue(int val);
void EvaluateSomething(EvaluateValue method, int loops)
{
for (int i = 0; i < loops; i++)
{
if (method(i))
{
//Debug.Log("Value " + i + " passed evaluation");
}
}
}
void Update()
{
if (Input.GetKeyDown(KeyCode.Space))
{
EvaluateSomething(IsEven, 32000); // This call produced 52 bytes of garbage in my tests
}
if (Input.GetKeyDown(KeyCode.Period))
{
EvaluateSomething(delegate(int val) { return val % 2 == 0; }, 32000); // Anonymous methods are the same generating 52 bytes of garbage
}
}
There's more stuff that I didn't have on top of my head, and not so much about unity yet; but I will fill in the missing things the next break I let my self have.
I will update this list as I stumble on little things that feeds the garbage collector and also correct myself for corner cases where I might have miss spoken.
Monday, March 19, 2012
Tile Lighting test
Over the past ~two days Iv'e been implementing a tile lighting system much like the one in Terraria. There's still some lighting artifacts (making it look "blocky"), due to lighting falloff against walls.
It is also possible to adjust the falloff that controls how much lighting will be reduced when traversing walls to make the light look as natural as possible as well as preventing light go through thick walls.
It is also possible to adjust the falloff that controls how much lighting will be reduced when traversing walls to make the light look as natural as possible as well as preventing light go through thick walls.
Wednesday, March 14, 2012
Noise Tool "completed"
A couple of hard days work later and it's done! (Well like 98% done anyway).
You can now save and load hierarchies (as xml files) and also spit out a png file if you wish.
Also added a couple of modules I thought was missing, Random (which makes absolutely random noise), LinearGradient (a horizontal/vertical gradient) and Split (takes a range of values and outputs only two values selected by a threshold).
The only thing left really annoying me is that when you load in a hierarchy, all the windows positions get's reset, so you have to drag them back in position.
A undo/redo history would be nice but out of scope for the time being.
An screenshot of the finished tool:
Example use case:
You can now save and load hierarchies (as xml files) and also spit out a png file if you wish.
Also added a couple of modules I thought was missing, Random (which makes absolutely random noise), LinearGradient (a horizontal/vertical gradient) and Split (takes a range of values and outputs only two values selected by a threshold).
The only thing left really annoying me is that when you load in a hierarchy, all the windows positions get's reset, so you have to drag them back in position.
A undo/redo history would be nice but out of scope for the time being.
An screenshot of the finished tool:
Example use case:
Friday, March 9, 2012
Noise Tool part 1
So, basically, I got a bit carried away with LibNoise when I discovered it's capabilities. Using a 3rd party GUI solution called Squid (not released yet, see: http://www.ionstar.org/), I just kept adding features to my tool. It's now completely graphical, you simply drag n drop the modules you want to generate noise with (as opposed to before when I had to make changes to the code to edit the result). Once placed, you can hook up different modules with lines to "chain link" them together to get just the result your looking for. By changing a parameter either by entering a value or dragging a slider for example, the image changes immediately making it straightforward to tweak the result in an intuitive manner.
It's not a completely finished tool, you can't save and load hierarchies or the final image just yet (Won't be hard though), also the lines connecting the modules are drawn underneath the windows which is just a minor annoyance. And some parameters doesn't show up yet in some modules. But all in all, the functionality is there and I'm going to enjoy using this tool for my procedural generation needs in future projects.
It's not a completely finished tool, you can't save and load hierarchies or the final image just yet (Won't be hard though), also the lines connecting the modules are drawn underneath the windows which is just a minor annoyance. And some parameters doesn't show up yet in some modules. But all in all, the functionality is there and I'm going to enjoy using this tool for my procedural generation needs in future projects.
Thursday, March 1, 2012
Make some Noise!
Recently downloaded LibNoise for .NET and it was surprisingly easy to get started with.
Just had to write a conversion utility to convert the data to a Unity3D texture.
Here are some example screenshots:
Here's the link to LibNoise http://libnoisedotnet.codeplex.com/
Subscribe to:
Posts (Atom)