Showing posts with label c#. Show all posts
Showing posts with label c#. Show all posts

Sunday, November 20, 2011

Finished, but just barely...

Here's the proof:



http://dl.dropbox.com/u/8791050/Magecrawl%20-%20Arena%20.1.zip

This version has the correct SDL libraries bundled so you don't need the SDL dev libraries installed.

http://dl.dropbox.com/u/8791050/Magecrawl%20-%20Arena%20.11.zip

Tomorrow I'll have a legitimate posting with instructions and the like. I just wanted to get something up tonight.

You'll need the .NET 4 runtime or the equivalent mono. You probably need the SDL development libraries installed as well. I'll try to clean things up tomorrow and shove out a better release.

Go go 4DRL.

Saturday, November 19, 2011

Hello...is this thing on...

I just received a comment wondering what the status of anything I've been working on, since I haven't posted in forever. This was ironic, since I was thinking about making a post tomorrow anyway.

The wife was out of town for a business conferences, so I decided to see what I could hack out in two after-work timeslots and Saturday/Sunday.


You might notice the stubbed out "action bar" at the bottom, but I have a lot working. I've "stolen" chunks of code from previous "iterations" of the game, but the "core" is all new.

It's written in C# and using SDL C#. My goal was to get something playable by end of the day tomorrow, so I've kept many things simple (but functional).

Things working so far:
  • Turn based movement with a "party" of player characters and various enemy monsters
  • Line of Sight and Pathfinding
  • "Animations" done in a way that for once makes me not want to cry
  • AI decision making is done off the UI thread to keep the game responsive.
Things to finish by tomorrow "hopefully"
  • Melee/Ranged combat with animations and targetting
  • "Skills" of some basic type
  • Multiple different monster types
  • Different "rounds" in the arena
Wish me luck on my 4DRL.

Tuesday, April 19, 2011

Spinning Up The Time Machine

So, I'm still playing with python. Not sure I'm going to write an entire roguelike in it, but figured I'd hack out to the step 4 (walking around a room) on the 15 steps to a roguelike.

I noticed the number of files/lines of code seemed to be much smaller than I remembered, so I pulled up the equivalent submission in magecrawl.

The python copy looks like this:


While the magecrawl looked similar to this (this was from a few weeks later, similar idea though)



Here is the comparision (excluding test code). This isn't comparing to the map generator picture above, just the walking around an empty room.

Python - 3 source files, 127 lines of code.
C# - 13 source files, 503 lines of code.

Much of that difference comes from the verbosity of C#. Some of it comes from the use of interfaces in C# compared to duck typing in python. The rest comes from an effort to implement the minimum needed and keep things simplier.

As a side note, pygame is pretty awesome. I might pull in libtcod for line of sight and pathfinding, but since I want "tiles" graphics, pygame made that crazy easy.

Sunday, August 1, 2010

Class vs Struct - It actually can matter

So, the second of my optimization realizations today involves the difference between structs and classes. For those who've been with this blog for awhile, you might remember a post I made half a year ago, here. In that post, I realized that a list of structs uses a lot less memory than a list of classes when each item is crazy small and there are a huge number of them.

Today, I've ran into the inverse. I made Point a struct back when I made that realization, thinking that it was small and therefore memory savings were worth the savings. However, when you stick an item into a dictionary as a key, it apparently makes a copy if it is a struct. It also makes a copy if you query the dictionary with a struct as the key. This meant I could rack up half a million or more point copies by scrolling for 15 seconds in my skill tree. This caused the memory manager to go crazy, and introduce the lag I was seeing. Switching it to a class helped a bunch.

When should you use struct vs when should you use class? Here's my current huristic:

If the item is large or you won't be having a crazy huge number of them - Use class, the possible optimization isn't worth it.
If a large number of the items will be stored in memory in a list - Try struct, as you'll save a pointer sized (4 or 8 bytes) amount for each item.
If you will be using it as a key (or value to a lesser extent) in a dictionary - Use a class, as each query on the dictionary and every access will make a copy.

GetHashCode's preformance really matters if you use it as a dictionary key alot

Just a quick post about a surprisingly small change that improved performance in magecrawl's skill tree view. I have a custom point class since there doesn't exist one inside c# outside of some GUI toolkits I don't want to force dependencies on.Since I overrode Equals, the compiler told me to override GetHashCode. I did so the naive way:
public override int GetHashCode()
{
    return X ^ Y ^ base.GetHashCode();
}

I have a spot in a tight loop that needs to lookup information based upon its position. I was previously using a List with a where LINQ call, which was insanely slow when I scaled up the number of skills. I figured this out using profiling and changed it to a dictionary. However, it was still too slow, so I read up on GetHashCode more and realized I could change GetHashCode for point to read:

public override int GetHashCode()
{
    return X ^ Y;
}

I didn't keep track of the numbers, but this very visibly made a huge difference. Keep GetHashCode in mind when you have data structures that are used as keys in large dictionaries. A small change can make a big improvement.

Sunday, January 31, 2010

Non-English operating systems, InvariantCulture, and You

As previously mentioned, Magecrawl's 2nd tech demo was released yesterday. I received multiple reports of crashes during map generation. After some detective work, it became clear that all of the reporters were using non-English versions of Windows (Polish and French). This issue can be boiled down to this simple string:

"10.0"

In some languages, the period there is replaced with a comma. All of the .NET languages by default, defaults to using the system language. This creates problems when text written using one separator is read by a program using another. The text is read fine, but when you try to parse it to a number, an exception is thrown.

The solution easy (arguably hacky) solution that somebody showed me is to tell .NET to "stop doing that".

            CultureInfo previousCulture = Thread.CurrentThread.CurrentCulture;
            Thread.CurrentThread.CurrentCulture = CultureInfo.InvariantCulture;
            //Your code here that depends on reading/writing text between languages.
            Thread.CurrentThread.CurrentCulture = previousCulture;

What we're doing here is saving off the current thread's "culture" and setting it to InvariantCulture. Then we can do our operation, and reset it back when we're done. In my case, I wrap the functions save/load functions and those that read spell/item/monster information.

If you've been bitten by this issue in Magecrawl, grab the new release here. If you use an English OS, there isn't a behavior change.

Sunday, November 22, 2009

LINQ is awesome

So, after some prodding at work, I learned enough LINQ to be dangerous. Boy, it makes some code shorter and easier to read.

From:
public bool Operate(Character characterOperating, Point pointToOperateAt)
{
bool didAnything = false;

foreach (MapObject obj in m_map.MapObjects)
{
OperableMapObject operateObj = obj as OperableMapObject;
if (operateObj != null && operateObj.Position == pointToOperateAt)
{
operateObj.Operate();
m_timingEngine.ActorDidAction(characterOperating);
didAnything = true;
}
}

return didAnything;
}


To:
public bool Operate(Character characterOperating, Point pointToOperateAt)
{
    OperableMapObject operateObj = m_map.MapObjects.OfType<OperableMapObject>().
SingleOrDefault(x => x.Position == pointToOperateAt);
    if (operateObj != null)
    {
        operateObj.Operate();
        m_timingEngine.ActorDidAction(characterOperating);
        return true;
    }
    return false;
}

It doesn't seem like a lot, but multiple it a few dozen times and you get some serious space savings. It also helped me realize that the previous code was allowing for multiple map objects in a given square, which violates one of my map invariants.

Wednesday, November 18, 2009

Shallow copying a stack

I needed to shallow copy a data structure that contained a few stacks in c#. Without thinking i did the following:

public Foo(Foo p)
{
Stack = new Stack(p.Stack);
}

However, this doesn't do what you'd expect. The stack is converted into an enumerable, and then read into the new stack. However, it's backwards. There is no "copy" constructor for stacks.

Here was my easy solution:

public Foo(Foop)
{
// There is no Stack constructor that take a stack, just the enumerable one
// Since we want a shallow copy, we'll just reverse the list and use that
Stack = new Stack(p.Stack.Reverse());
}

Since LINQ has a reverse method, we just get the enumerable and reverse it. Then the stack will be created with the same ordering.

Hello World

In the beginning, the programmer wrote "Hello World". And he saw that it was good. Then then the programmer wanted to tell others about it, so he found a humorous title and started a blog. And thus, IfErrorThrowNewBrick was born.

It's here that I hope to write on my experiences on programming in general, and specifically on my work on my pet roguelike game, magecrawl. I've been programming in c# for about about a year a a half at least, mostly at home but now at work as well. It's now my favorite language to write in, with the exception of using python to hack out rough tools.

Well that's enough of an introduction.