0

I've got 2+ objects that come from different inheritance trees, but I'd like them to share a common set of code IMoveable.

The IMoveable interface is looking good, and I'm happy with where I've got with it:

public interface IMoveable
{
  /// <summary>
  /// The speed the object travells between start and end
  /// </summary>
  int Speed { get; set; }

  /// <summary>
  /// The current velocity of the object
  /// </summary>
  Vector2 Velocity { get; set; }

  /// <summary>
  /// How far the object has travelled
  /// </summary>
  int DistanceTravelled { get; set; }

  /// <summary>
  /// The map the object is traversing
  /// </summary>
  Map Map { get; set; }

  /// <summary>
  /// Where the object was when they started moving
  /// </summary>
  Rectangle StartRectangle { get; set; }

  /// <summary>
  /// Where the object is right now
  /// </summary>
  Rectangle CurrentRectangle { get; }

  /// <summary>
  /// Where the object will be after moving
  /// </summary>
  Rectangle EndRectangle { get; set; }

  /// <summary>
  /// What will happen if the object walks to the "EndRectangle"
  /// </summary>
  Map.CollisionResults CollisionResult { get; set; }

  /// <summary>
  /// What happens if the object triggers a battle
  /// </summary>
  Action OnBattle { get; set; }

  /// <summary>
  /// How the object determines their movement
  /// </summary>
  Action SetMovement { get; set; }
}

With that interface I have a method:

 private static void Move(IMoveable moveableOjb)
  {
    moveableOjb.Speed = 4;

    if (moveableOjb.DistanceTravelled > 0)
    {
      moveableOjb.DistanceTravelled += moveableOjb.Speed;

      if (moveableOjb.DistanceTravelled > Map.TileWidth)
      {
        moveableOjb.DistanceTravelled = 0;
        moveableOjb.Velocity = new Vector2();
      }
      else
      {
        return;
      }
    }

    moveableOjb.SetMovement();

    if (moveableOjb.Velocity != Vector2.Zero)
    {
      moveableOjb.StartRectangle = moveableOjb.CurrentRectangle;
      moveableOjb.EndRectangle = new Rectangle(
        moveableOjb.CurrentRectangle.X + ((int)moveableOjb.Velocity.X * 10),
        moveableOjb.CurrentRectangle.Y + ((int)moveableOjb.Velocity.Y * 10),
        moveableOjb.CurrentRectangle.Width,
        moveableOjb.CurrentRectangle.Height);

      moveableOjb.CollisionResult = moveableOjb.Map.GetValue(moveableOjb.EndRectangle);

      switch (moveableOjb.CollisionResult)
      {
        case Map.CollisionResults.None:
          break;
        case Map.CollisionResults.Colliding:
          moveableOjb.Velocity = new Vector2();
          break;
        case Map.CollisionResults.Battle:
          moveableOjb.OnBattle();
          moveableOjb.Velocity = new Vector2();
          break;
        case Map.CollisionResults.OffRight:
        case Map.CollisionResults.OffLeft:
        case Map.CollisionResults.OffTop:
        case Map.CollisionResults.OffBottom:
          moveableOjb.Speed = 0;
          break;
        default:
          break;
      }
    }

    if (moveableOjb.Velocity != Vector2.Zero)
      moveableOjb.DistanceTravelled += moveableOjb.Speed;
  }

The problem I'm facing is this code is just weird. I've gotten a static Move method and I don't know where to put it, and I feel like I've gone about this the completely wrong way.

An alternative I have to this is rewrite my classes so instead of them coming from different inheritance, they are in the same tree. I could do that, but it will take some time to restructure.

I guess my main question is - am I going about this the wrong way, or am I close to following a coding practice that I can't quite figure out?

Example of implementation:

public class ClassA : Sprite, IMoveable
{
  // interface implementation

  public override Update(GameTime gameTime)
  {
    // Stuff

    Move(this);        

    // More stuff
  }
}

EDIT:

I've been informed that is C# 8 you can have default interface methods. I think that may be exactly what I need!

Oyyou
  • 610
  • 5
  • 13
  • What you've actually stumbled upon here is the first signs of the "deep hierarchy" problem. This is a problem for a lot of software, but it's particularly difficult with games. There are many design patterns you can use but one that you'll find in a lot of game engines these days is known as the ["entity component system"](https://en.wikipedia.org/wiki/Entity_component_system). Be warned though, if you go down this route it can be a steep learning curve. – craftworkgames Oct 18 '19 at 13:00
  • You could turn it into an extension method like so `static void Move(this IMoveable moveableOjb)`. You might want to take a look at [this answer](https://stackoverflow.com/a/178368/585968) as it looks like you are trying to do composition but not quite correctly –  Nov 19 '19 at 23:35

1 Answers1

0

You are confusing what static means. When a method affects a specific instance, like in this case, it should be non static. This is where the "weirdness" comes from.

Static methods are for general operations or, though with pros and cons, as a surrogate for singletons.

Instead of a static method, define it as a member of the class that implements IMoveable or as a default interface method. With no instance as parameter. That way the instance, this, will be moving. You will be able to move by calling it from that instance, which makes more sense semantically:

IMoveable moveableObj = //constructor here...
moveableObj.Move();

If every class implementing the interface moves in the same way, you can still avoid putting the reference to the instance as a parameter and use this. Perhaps the parameters are best used for information about the movement, if needed.

Attersson
  • 4,755
  • 1
  • 15
  • 29
  • Hey, so the "Move" method is called inside of the object. I'll chuck an example in the question – Oyyou Oct 17 '19 at 11:40
  • Well, does every class implementing IMoveable move in the same exact way? In that case, the default interface method will be indeed better... but you can get rid of the parameter and use `this`. – Attersson Oct 17 '19 at 11:43
  • Yeah, the contents of the "Move" method will be the same every time. The interface method looks exactly to be what I need! – Oyyou Oct 17 '19 at 11:44
  • Yes make it non static and `this.Move()` – Attersson Oct 17 '19 at 11:45