1

This is my first time asking a question here at StackOverflow.

I have finished the Unity 3D official "Roguelike 2D" tutorial, and trying to expand on it on my own. When the Player tries to walk into a wall, he damages it instead, eventually breaking through.

I have removed sounds and animator commands for clarity.

protected override void OnCantMove<T> (T component)
{
    Wall hitWall = component as Wall;
    hitWall.DamageWall (wallDamage);
}

And when the Enemy tries to walk into the Player, it damages him instead, hurting him.

protected override void OnCantMove <T> (T component)
{
    Player hitPlayer = component as Player;
    hitPlayer.LoseFood (playerDamage);
}

playerDamage is set by the Enemy script, and wallDamage is set by the Player script (meaning both are set by the one doing the damage.) LoseFood and DamageWall are set by the Player and the Wall scripts (meaning both are set by the one receiving the damage.)

I want the Enemy to be able to damage Walls, like the Player is. So, I tried changing the Enemy script's OnCantMove part to something like this:

protected override void OnCantMove<T> (T component)
{
    Wall hitWall = component as Wall;
    hitWall.DamageWall (wallDamage);
    Player hitPlayer = component as Player;
    hitPlayer.LoseFood (playerDamage);
}

and this:

protected override void OnCantMove<T> (T component)
{
    Wall hitWall = component as Wall;
    Player hitPlayer = component as Player;
    if (hitWall) {hitWall.DamageWall (wallDamage);}
    else if (hitPlayer) {hitPlayer.LoseFood (playerDamage);}
}

Neither worked the way I wanted them to do. I even tried to replace the OnCantMove function of the Enemy to be the same as when the Player hits the walls, but that only removed the ability the Enemy had to hit the Player, without enabling it to hit walls. What should I try next, to see if I can solve this problem?

If I manage to get this to work, I'm hoping I can continue to expand on this game in other ways as well, but I am very new at this. Thank you for any help and advice.

deinonychusaur
  • 7,094
  • 3
  • 30
  • 44
Josse Klev
  • 11
  • 2

2 Answers2

1

The problem lies in the MoveEnemy-method of the enemy script. It calls AttemptMove<Player>, so it will only ever send in a player object to the OnCantMove-method. Not sure how I'd solve it, but you probably need to re-build a bit to get the behaviour you want.

Jonatan Hedborg
  • 4,382
  • 21
  • 30
1

Thank you! I had also finished this tutorial and decided to expand the game to learn a bit more about Unity. Thanks to this challenge, I was able to re-factor the code and put it working as expected (see result here)

Indeed, the issue was related to the AttempMove<Player> as Jonatan Hedborg pointed out.

Because of the generic type in AttemptMove <T> (int xDir, int yDir) function in MovingObject.cs I decided to make it return an integer to tell if it hit the mentioned component or not, likewise:

protected virtual int AttemptMove <T> (int xDir, int yDir)
where T : Component
{
    RaycastHit2D hit;
    bool canMove = Move(xDir, yDir, out hit);

    if (hit.transform == null)
        return MOVE_ATTEMPT_NO_HIT;

    T hitComponent = hit.transform.GetComponent<T>();

    if (!canMove && hitComponent != null)
    {
        OnCantMove(hitComponent);
        return MOVE_ATTEMPT_HIT;
    }

    return MOVE_ATTEMPT_NO_HIT;
}

MOVE_ATTEMPT_HIT and MOVE_ATTEMPT_NO_HIT are simply integer constants defined in MovingObject.cs as:

public const int MOVE_ATTEMPT_NO_HIT  = 0;
public const int MOVE_ATTEMPT_HIT     = 1;

Then it was just a simple matter of changing MoveEnemy() from Enemy.cs to check if the player was hit, if not then attempting to move him against a wall, likewise:

....
// Check if player was hit
int hitCode = AttemptMove<Player>(xDir, yDir);

// if player was hit, exit (don't forget to skip next move)
if (hitCode == MOVE_ATTEMPT_HIT)
{
    skipMove = true;
    return;
}

// else, check if a wall was hit
else if (hitCode == MOVE_ATTEMPT_NO_HIT)
    AttemptMove<Wall>(xDir, yDir);

skipMove = true;
}

Skipping a move, as in the tutorial's original code, is important. Otherwise, since the zombies can reach a point where they have no walls blocking the way, the player can really get stuck forever!

Community
  • 1
  • 1