开发者

Find a subclass in a list

开发者 https://www.devze.com 2023-02-18 07:17 出处:网络
Hi I\'m in quite some problem at the moment, I currently have a class \"Ship\" with subclasses \"Player\" & \"Enemy\" both of them are in the List \"Ships\"

Hi I'm in quite some problem at the moment, I currently have a class "Ship" with subclasses "Player" & "Enemy" both of them are in the List "Ships"

What I'm trying to do is extract the "Player thePlayer" from the list of "Ships" I've tried using List.Find() without any succes, is it just me using it wrong or is it the wrong way of dealing with this problem?

    for (int i = 0; i < HomingBullets.Count; i++)
    {
        HomingBullet h = HomingBullets.ElementAt(i);
        Player thePlayer = ??? List.Find ???
        h.Update(gameTime, thePlayer.position);
    }

the h.Update takes the two arguments (gameTime & Vector2) I'm trying to extract the Vector2 using the code above.

Keep in开发者_如何转开发 mind I've only used C# since the start of this year although I have a few years of experience of programming in various languages.


You can use LINQ's OfType<> operator to return only objects of a specific type from a list or IEnumerable in general. E.g. you can write

Ships.OfType<Player>()

to return only the instances of type Player.

This is a very inefficient way to search though, as it iterates over all Ships. I suspect that player ships are only a very small percentage of the total ships. It would be better to keep a separate list of Player ships that references the Ship instances in the Ship collection.


list.Find(sh => sh is Player);

This is equivalent to creating a method like:

bool IsPlayer(Ship sh)
{
  return sh is Player;
}

And then iterating through until that method returns true when called on each item (or null if no such item is found.


You can test whether an object is an instance of a given class using the is keyword: x is Player will be true for your player object and false for the instances of Enemy in the list.

It may be better style to define an isPlayer method on your Ship class (with definitions in Player and Enemy returning different values), or -- if in fact there's always exactly one Player object -- to hold it somewhere else rather than repeatedly looking for it in your list.


Arguably, a much better solution than any here is to use a GameComponent (or DrawableGameComponent) and GameServices. This would allow you to be able to grab the Player object without needing a hard reference to it at all times. Instead, you only need a reference to the Game object.

Other references

  • http://www.nuclex.org/articles/4-architecture/6-game-components-and-game-services
  • http://www.innovativegames.net/blog/blog/2008/10/09/engine-tutorial-1/


The simplest solution would be to add a readonly property to the Ship class:

class Ship
{
    public abstract bool IsPlayer { get; }
}

class Player : Ship
{
    public override bool IsPlayer { get { return true; } }
}

class Enemy : Ship
{
    public override bool IsPlayer { get { return false; } }
}

Then you could do

var thePlayer = (Player)shipList.Find(s => s.IsPlayer);

The cast to Player could possibly go if you can use that object as a general Ship instead of the more specific Player (I am assuming that shipList is a List<Ship>, right?).

Other solutions (such as using the is keyword, or the equivalent LINQ shipList.OfType<Player>().Single() will work just as well, but checking for runtime type will be much slower than the IsPlayer property check.

0

精彩评论

暂无评论...
验证码 换一张
取 消