2

I am making this 2-D game where I want to be able to build structures. The player must be able to benefit from certain structures. Today the game looks like this:

enter image description here (the blue dot is the player, other dots are ais)

I have made a class named Structure and three other classes that inherits from Structure. These classes are more or less empty. The tiles of the game has there own class named Tile. In this class I have written some things but the code of interest is this:

public LinkedList<Structure> Structures = new LinkedList<Structure>();

When i build a structure (a fireplace for example) the code looks like this:

Bundle.map.tile[Bundle.player.X, Bundle.player.Y].Structures.
    AddFirst(new Fireplace());

The part I´m uncertain about is how I check if the list contain a fireplace for example (which is a class named Fireplace) or any other building. For example if a player finds a fireplace on a tile he/she will regain warmth. This does not work. Perhaps I have the wrong approach to all this, in either case please provide me with an code example.

Conclusion of answer:

bool anyFireplace = Bundle.map.tile[Bundle.player.X, Bundle.player.Y].Structures.OfType<Fireplace>().Any();
if (anyFireplace)
{
    Warmth = MaxWarmth;
}
else
{
if (Warmth > 0)
{
    Warmth--;
}
else
{
    HP--;
}
}

5 Answers5

2

I would suggest using the is keyword. It is used to check whether a variable has a certain type. For example:

object example = "Hello World!";
bool isString = example is string; // Evaluates to true

And you could use that in your code as such:

foreach (Structure s in Structures)
{
    if (s is FirePlace)
    {
        // Warmup the player
    }
}

Also, I would suggest using List<T> instead of LinkedList<T>, since List<T> is (generally) much faster.

As you might have gathered from some of the other answers, multiple ways lead to Rome here, many ways. However, according to this test, the is way of doing it outperforms all other suggested ways (thanks to Hogan btw for this test):

OfType time: .6702958, GetType time: .2268946, Property time: .1400208, Is time: .1112995

And this way is cleaner IMHO.

Community
  • 1
  • 1
antonijn
  • 5,702
  • 2
  • 26
  • 33
2

You could use, for example, Enumerable.OfType<TResult>() and Enumerable.Any(TSource) as follows:

LinkedList<Structure> structures = new LinkedList<Structure>();

// Add Different Types of Structures

Boolean anyFireplace = structures.OfType<Fireplace>().Any();

Just make sure you have:

using System.Linq;

in your using directives at the top of your source and a reference to the System.Core assembly module. You could also use Count() method if you need to know the exact number of fireplaces inside the LinkedList, otherwise Any() is more efficient in Linq objects.

Tommaso Belluzzo
  • 23,232
  • 8
  • 74
  • 98
1

You can use LINQ to Objects for this:

LinkedList<Structure> list = ...

List<Fireplace> fireplaces = list.OfType<Fireplace>().ToList();

fireplaces is then a list of all the elements in the list of type Fireplace - or an empty list if none exist.

If you just want to know if one exists or not, you can adapt this to:

bool hasFirplace = list.OfType<Fireplace>().Any();
Nick Butler
  • 24,045
  • 4
  • 49
  • 70
0

Maybe having the class name describe the object is not advisable. You will have to use reflection which is kinda slow. AND you only get one description (the class name). You will want more than just one. You might want to consider a base object like this:

public abstract class MapObject
{
   public int x,y;  // object location
   public string myclass;  // object class
   public string mytype;   // object type
   // etc

   // constructor
   public MapObject(string myclass, string mytype);

}

Then the a fireplace might look like this

public class FirePlace : MapObject
{
   public FirePlace() 
       : base("Builtin furniture", "Fireplace") { }
   // etc
}

Now you can loop over all MapObjects for ones of mytype = "Fireplace"

antonijn
  • 5,702
  • 2
  • 26
  • 33
Hogan
  • 69,564
  • 10
  • 76
  • 117
  • Apart from the fact that doesn't compile, I hope you're joking about using "magic" strings!!! – Nick Butler Jan 12 '13 at 17:29
  • `is` doesn't classify as reflection! And I think the performance of `is` would be about equal to this "workaround". – antonijn Jan 12 '13 at 19:43
  • Also, this won't compile. How can a class inherit from a constructor? – antonijn Jan 12 '13 at 19:49
  • @NicholasButler - What is wrong with using strings? Sure an enum is probably better, but they are both better than using the type name – Hogan Jan 12 '13 at 20:17
  • @AntonieBlom - I doubt that you have tested the performance of `is`. It should be quite slow vs a class property. I might just write a little test program and get some real numbers. – Hogan Jan 12 '13 at 20:19
  • @Hogan Of course it should be quite slow to properties in general, but comparing strings is done per character. Now that ain't fast either. I'll make a test when I have the opportunity. – antonijn Jan 12 '13 at 20:24
  • @AntonieBlom - Actually string compares are not done by character if you are testing for equality -- there is a CPU level op-code to do that on all x86 processors. – Hogan Jan 12 '13 at 20:27
  • @AntonieBlom - You are right, enjoy this gist : https://gist.github.com/4520437 - results: OfType time: .6702958, GetType time: .2268946, property time: .1400208, is time: .1112995 (can you see any bias in this test?) – Hogan Jan 12 '13 at 20:59
  • @Hogan Shows dedication mate (thanks btw, will add it to my answer :P). – antonijn Jan 12 '13 at 21:53
-1

You can use the Type to know that:

foreach(var s in Structures)
{
  var type = s.GetType();
  if(type == typeof(FirePlace)
  {
    (your code here)
  }
}

For a single method

public bool HasType<T>(IEnumerable<T> list, Type t)
{
    return list.Any(e=>e.GetType() == t);
}

The usage should be like:

if(HasType(Structures,typeof(FirePlace))
{
  (code here)
}

At last you can turn this into an extension method, but I leave that option to you ;)

DVD
  • 1,744
  • 3
  • 17
  • 34
  • 1
    As for the first example, you could use `is`, which can be up to 10 times faster than this (http://stackoverflow.com/questions/686412/c-sharp-is-operator-performance). – antonijn Jan 12 '13 at 19:45
  • 1
    `s.GetType() == typeof(FirePlace)` is not a good way to check for class membership. If `s` is an instance of a subclass of `FirePlace`, that will not work. Likewise for the second code snippet, you would be better off with `public bool HasType(IEnumerable list) { return list.Any(e => e is C; }`, then call it as `HasType(Structures)` – JLRishe Jan 12 '13 at 19:46