Pagina's

Sunday, 10 February 2019

A collision problem with monsters and walls

Alright, I knew the monster would come back to bite me and it's giving me problems. I had a factory script build me a small 10x10 level which looks like this:


The stick figure in the left bottom corner, that's me. There's a couple of walls, a door, a health box and two monsters. I already made a script allowing the stick figure to walk through the level using keys, avoiding the walls and the door.

Now I added a script (bottom of this post) to the Monster class that makes it walk in a random direction (up, down, left or right) until it hits a collider. Then it decides another random direction (never the one it was already going) and moves on. I have this script. Note that Monster inherits from Enemy. All Enemy does is make sure a variable level contains an animation from the factory class. That happens in the base Awake.

This code results in the two monsters moving which is correct. The monster in the middle-right of the screen will go up and down and the one at the top will start moving places until it gets stuck in a corner like this:


As you see in the code, I added a Debug.Log to find out what is happening and it appears that the monster not only collides with the wall to its left and top, but also the one to the top-left.  I suspect that the monster had its direction until it hit one of those walls, backs off in the OnCollisionEnter2D function and decides to hit the other two walls.

My question is if there's a way to get this thing to work: when the moveDir is decided, can the script predict immediate collisions without triggering them? I have this thing in the DecideMoveDir-method where I make sure the randomNumber is never the same as previousNumber so that the monster does not re-bump into the wall and get stuck. Can I broaden this while loop (or other thing) to make sure the resulting moveDir does not cause problems?

Or, maybe I'm just thinking wrong, does this phenomenon have another cause? Is that fixable? All I want to have here is the monsters walking in a random direction and chancing course randomly when they hit a wall, a door or each other. When they hit the player, something else will have to happen, but that's gonna be ugly.

Here's the entire Monster class script:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Monster : Enemy
{
    private Sprite[] currentAnimation;
    private int currentFrame = 0;
    private float frameRate = .2f;
    private float timer;
    private SpriteRenderer spriteRenderer;

    public Sprite[] monsterIdleAnimation;
    private Vector3 moveDir;
    private float speed = 2f;
    private float speedTimer;
    private int previousNumber;
    

    protected override void Awake()
    {
        base.Awake();
        monsterIdleAnimation = level.monsterIdleAnimation;
        HealthSystem healthSystem = new HealthSystem(50);

        currentAnimation = monsterIdleAnimation;
        spriteRenderer = gameObject.GetComponent<SpriteRenderer>();

        moveDir = DecideMoveDir();
    }

    void Update()
    {
        MoveMonster(moveDir);
        DecideMonsterAnimation();
        AnimateMonster();
    }

    private void OnCollisionEnter2D(Collision2D collision)
    {
        Debug.Log(gameObject.name + " / " + collision.gameObject.name + " nr:" + previousNumber);
        transform.position -= moveDir;

        moveDir = DecideMoveDir();
    }

    private int RandomNumberGenerator(int a, int b)
    {
        int getal = Random.Range(a, b);
        return getal;
    }

    private Vector3 DecideMoveDir()
    {
        Vector3 direction = new Vector3();

        //nooit twee keer dezelfde richting bepalen.
        int randomNumber = RandomNumberGenerator(1, 4);
        while (randomNumber == previousNumber)
        {
            randomNumber = RandomNumberGenerator(1, 4);
        }
        previousNumber = randomNumber;

        switch (randomNumber)
        {
            case 1:
                direction = Vector3.up;
                break;
            case 2:
                direction = Vector3.down;
                break;
            case 3:
                direction = Vector3.left;
                break;
            case 4:
                direction = Vector3.right;
                break;
            default:
                direction = Vector3.zero;
                break;
        }

        direction *= speed * Time.deltaTime;
        return direction;
    }

    public void MoveMonster(Vector3 direction)
    {
        transform.position += moveDir;
    }

    private void DecideMonsterAnimation()
    {
         //does nothing yet.
    }

    private void AnimateMonster()
    {
        timer += Time.deltaTime;
        if (timer >= frameRate)
        {
            timer -= frameRate;
            currentFrame = (currentFrame + 1) % currentAnimation.Length;
            spriteRenderer.sprite = currentAnimation[currentFrame];
        }
    }
}


No comments:

Post a Comment