Take the 2-minute tour ×
Game Development Stack Exchange is a question and answer site for professional and independent game developers. It's 100% free, no registration required.

In my game, I have

  1. Player class
  2. Enemy class
  3. Wall class
  4. GameComponents class ( Which is the base class for Player, Enemy and Wall)

The rules are

  • Enemy chase Player, if collided with Walls, destroy Walls
  • Player run away from Enemy, Player can generate Walls

Currently, I have the code for Enemy to destroy Wall setup. For it, after detected that it has intersected with Walls, it has a function to deduct the Wall's HP. Meanwhile, I set the speed for the Enemy to 0, so it stops moving. And after checking the Wall's HP is less than 1, Enemy's speed become 1 again ( Default speed )

Now, to Player, the Player cannot destroy Walls. So he has to move away from them. I use the function collision(Vector tempPos, bool shouldBeSolid) for collision detection & collision response. But due to the way it's setup, even though after the Wall has been "destroyed" by the Enemy. My Player still couldn't pass through them. I'm having difficulties of getting rid of the Walls ( Or their Rectangle ). I have thought of resetting the Rectangle ( Rectangle.Empty, basically reset all the values it has to 0 , which is x, y, width , height ), but that doesn't work.

So right now I'm asking for some better collision response method than the current function I use...

The codes are here...

GameComponents class class GameComponents { #region Variable protected Texture2D texture; public Rectangle area; protected string textureName; public bool isSolid = false;

    public Vector2 pos;
    public bool spawned = true;
    public float speed = 0.0f;
    public float rotation = 0.0f;
    public float scale = 1.0f;
    public Color color = Color.White;
    public SpriteEffects effect = SpriteEffects.None;

    protected bool enableDebugMessage = false;
    protected int currentFrameX = 0;
    protected int currentFrameY;
    protected int spritesCount = 1;
    protected int animationSpeed = 1;
    protected Point spritesFrame;
    protected Rectangle size;
    protected bool execMoveFunction = true;
    protected Rectangle newArea;
    #endregion

    public GameComponents(Vector2 pos) 
    {
        this.pos = pos;
    }

    public virtual void LoadContent(ContentManager c)
    {
        texture = c.Load<Texture2D>(this.textureName);
        area = new Rectangle(0, 0, texture.Width / spritesCount + 2, texture.Height + 2);
    }

    public virtual void Update()
    {
        if (!spawned) return;

        UpdateArea();

        if (execMoveFunction)
        {
            pushTo(speed, rotation);
        }
    }

    public virtual void Draw(SpriteBatch sb)
    {
        if (!spawned) return;

        Vector2 center = new Vector2(texture.Width / 2, texture.Height / 2);

        Animate();
        sb.Draw(texture, pos, size, color, MathHelper.ToRadians(rotation),
            center, scale, effect, 0);
    }

    public bool collideWith(Vector2 pos, bool dontCheckForSolidity)
    {
        foreach (GameComponents component in Factory.componentList)
        {
            if (component.isSolid || !dontCheckForSolidity)
            {
                if (component.area.Intersects(area))
                {
                    return true;
                }
            }
        }
        return false;
    }

    // The problem function
    public virtual bool collision(Vector2 tempPos, bool shouldBeSolid)
    {
        newArea = new Rectangle(area.X, area.Y, area.Width, area.Height);
        newArea.X += (int)tempPos.X;
        newArea.Y += (int)tempPos.Y;


        foreach (GameComponents component in Factory.componentList)
        {
            if (component.isSolid && shouldBeSolid)
            {
                if (component.area.Intersects(newArea))
                {
                    return true;
                }
            }
        }
        return false;
    }

    public void UpdateArea()
    {
        area.X = (int)pos.X - texture.Width / 2;
        area.Y = (int)pos.Y - texture.Height / 2;
    }

    public virtual void pushTo(float speed, float dir)
    {
        float newX = (float)Math.Cos(MathHelper.ToRadians(dir));
        float newY = (float)Math.Sin(MathHelper.ToRadians(dir));
        pos.X += speed * (float)newX;
        pos.Y += speed * (float)newY;
    }

    public bool intersects(Rectangle R1, Rectangle R2)
    {
        if (R1.Left <= R2.Right && R2.Left <= R1.Right
                                &&
            R1.Top <= R2.Bottom && R2.Top <= R1.Bottom)
        {
            return true;
        }

        return false;
    }

    private void Animate()
    {
        size = new Rectangle(currentFrameX * spritesFrame.X, currentFrameY * spritesFrame.Y, spritesFrame.X, spritesFrame.Y);

        if (currentFrameX < spritesCount - 1) 
        {
            currentFrameX += animationSpeed;
        }
        else
        {
            currentFrameX += -currentFrameX;
        }
    }

    public float point_direction(float x, float y, float x2, float y2)
    {
        float diffx = x - x2;
        float diffy = y - y2;
        float adj = diffx;
        float opp = diffy;
        float tan = opp / adj;
        float res = MathHelper.ToDegrees((float)Math.Atan2(opp, adj));
        res = (res - 180) % 360;
        if (res < 0) res += 360;
        return res;
    }
}

} Player class {

class Player : GameComponents
{
    private KeyboardState key;
    private int speed;
    private Vector2 prevPos;
    public static Vector2 position;
    public static int HP = 100;
    public static int maxHP = 100;

    public Player(Vector2 pos) : base(pos)
    {
        pos = this.pos;
        position = pos;
        speed = 4;
        textureName = "P";
        HP = maxHP;
    }

    public override void Update()
    {
        if (!spawned) return;
        key = Keyboard.GetState();

        Input(key);

        prevPos = pos;
        position = pos;
        base.Update();
    }

    private void Input(KeyboardState key) 
    {
        if (key.IsKeyDown(Keys.W)
            && !collision(new Vector2(0, -speed), true))
        {
            pos.Y -= speed;
        }
        if (key.IsKeyDown(Keys.A)
            && !collision(new Vector2(-speed, 0), true))
        {
            pos.X -= speed;
        }
        if (key.IsKeyDown(Keys.S)
            && !collision(new Vector2(0, speed), true))
        {
            pos.Y += speed;
        }
        if (key.IsKeyDown(Keys.D)
            && !collision(new Vector2(speed, 0), true))
        {
            pos.X += speed;
        }
    }
}

} Enemy class {

class Enemy : GameComponents
{
    private int seeingRange = 400;
    private int HP;
    private int MaxHP = 50;
    private float spd;

    public Enemy(Vector2 pos) : base(pos)
    {
        pos = this.pos;
        textureName = "EDebug";
        damage = 25;
        HP = MaxHP;
        spd = 1;
        execMoveFunction = false;
    }

    public override void Update()
    {
        if (HP < 0 ) 
        {
            spawned = false;
            HP = MaxHP;
        }
        MoveToPlayerIfInRange();
        DestroyWall();

        base.Update();
    }

    private void MoveToPlayerIfInRange()
    {
        if (DistanceBetween(Player.position.X, Player.position.Y, pos.X, pos.Y) < seeingRange)
        {
            // Rotate to face Player
            rotation = point_direction(pos.X, pos.Y, Player.position.X, Player.position.Y);
            MoveToPlayer();
        }
    }

    private void DestroyWall()
    {
        foreach ( GameComponents c in Factory.componentList)
        {
            if (c.GetType() == typeof(Wall))
            {
                if (intersects(area, c.area))
                {
                    spd = 0;
                    Wall w = (Wall)c;
                    if (w.HP > 0) w.Damage(1);
                    if (w.HP < 1) spd = 1;
                }
            }
        }
    }

    private void MoveToPlayer()
    {
        if (Player.position.X < pos.X) pos.X -= spd;
        if (Player.position.X > pos.X) pos.X += spd;
        if (Player.position.Y < pos.Y) pos.Y -= spd;
        if (Player.position.Y > pos.Y) pos.Y += spd;
    }

    public static float DistanceBetween(float x1, float y1, float x2, float y2)
    {
        float xSquare = (x1 - x2) * (x1 - x2);
        float ySquare = (y1 - y2) * (y1 - y2);
        double sumOfXYSquare = xSquare + ySquare;
        float dist = (float)Math.Sqrt(sumOfXYSquare);

        return dist;
    }
}

} Wall class {

class Wall : GameComponents
{
    public int HP;
    public static Vector2 position;

    public Wall (Vector2 pos) : base (pos) 
    {
        pos = this.pos;
        isSolid = true;
        textureName = "W";
        HP = MaxHP;
    }

    public override void Update()
    {
        if (!spawned) return;

        if ( hp < 1 )
        {
            spawned = false;
            HP = MaxHP;
        }

        position = pos;
        base.Update();
    }

    public void Damage(int damage)
    {
        HP -= damage;
    }
}

} Factory class {

class Factory
{
    public static List<GameComponents> componentList = new List<GameComponents>();

    public static void Initialize()
    {
        componentList.Add(new Player(new Vector2(100 + (39 * 3) , 140)));
        componentList.Add(new Cursor(new Vector2(50, 50)));

        componentList.Add(new Wall(new Vector2(100 + (39 * 5), 100 + (36 * 2))));
        componentList.Add(new Wall(new Vector2(100 + (39 * 5), 100 + (36 * 3))));

        componentList.Add(new Spawner(new Vector2(350, 50)));

        for (int i = 0; i < 1; i++)
        {
            Enemy e = new Enemy(Vector2.Zero);
            e.spawned = false;
            componentList.Add(e);
        }
        for (int i = 0; i < 32; i ++ )
        {
            GameComponents components = new Bullet(Vector2.Zero);
            components.spawned = false;
            componentList.Add(components);
        }
    }
}
share|improve this question

closed as too localized by Byte56, Anko, bummzack, Josh Petrie, msell Apr 18 '13 at 8:59

This question is unlikely to help any future visitors; it is only relevant to a small geographic area, a specific moment in time, or an extraordinarily narrow situation that is not generally applicable to the worldwide audience of the internet. For help making this question more broadly applicable, visit the help center.If this question can be reworded to fit the rules in the help center, please edit the question.

    
Have you thought about using tile maps? Collision detection is so simple with tile maps it's not even funny! –  Savlon Apr 14 '13 at 2:01
    
Erm..but the walls are dynamically generated lol... –  Xeon Apr 14 '13 at 5:41
    
That would not be an issue. What exactly are you having trouble with? Collision detection or collision response? –  Savlon Apr 14 '13 at 6:47
    
Collision response. After the Enemy destroyed the Walls, my Player still couldn't pass through them. Due to this line of code newArea = new Rectangle(area.X, area.Y, area.Width, area.Height); if (component.area.Intersects(newArea)) return true; If use a tile table, I have no idea how to spawn the Wall and add it into the spawned item list.. I edited the question, you can see the codes there, in Factory class –  Xeon Apr 14 '13 at 7:58
1  
ahhhh I see, Why dont you just have a getBounds() method in each of your entity classes? which returns a new Rectangle(x, y, width, height);?? and check for collision like that? That way when the wall is removed so is the rectangle? –  Savlon Apr 14 '13 at 8:31

1 Answer 1

up vote 1 down vote accepted

Ok so i'll post this in an answer to try and help you.

I'll write this in java. However, you could easily convert it to C#

Your entity classes will look something like this

public class Entity {

    private Vector2D position;
    private Vector2D velocity;

    private int width;
    private int height;

    public Entity(double x, double y) {
        position = new Vector2D(x, y);
        velocity = new Vector2D(0, 0);
        width = 32;
        height = 32;
    }

    //Getters and setters for position and velocity

    public Rectangle getBounds() {
            return new Rectangle((int)position.x, (int)position.y, width, height);
    }

}

Lets presume you would like to add 10 enemies, you would have something similar to this

List<Enemy> enemies = new ArrayList<Enemy>();

We will then add enemies to that array.

for (int i = 0; i < numberOfEnemy; i++) {
    Enemy enemy = new Enemy(randomX, randomY);
    enemies.add(enemy);
}

You would also have an array of walls too which can be added and taken away exactly the same as the enemy.

You could then loop through each enemy checking intersection with the wall and player

for (int i = 0; i < enemies.size(); i++) {
    Enemy tempEnemy = enemies.get(i);
    for (int j = 0; j < walls.size(); j++) {
        Wall tempWall = walls.get(i);

        if (tempEnemy.getBounds().intersects(tempWall.getBounds() {
            // Remove wall or whatever it is you want to do
        }

    }

    if (player.getBounds().intersects(tempEnemy.getBounds() {
        // --hp; etc...
    }
}

Are you picking up what i'm putting down? lol

Let me know if you need more clarification :)

share|improve this answer
1  
Oh, I get you now! +1 man! Duh, I feel like an idiot right now. Mmm...err, do you have any idea how to do that (check intersections within the for loop) in a foreach loop and all of the objects are actually within 1 single list? Sorry but I can't think these days, my brain is like dead or something <.< –  Xeon Apr 14 '13 at 14:04
1  
I'm not sure how it would work in C#. However, I would suggest creating an arraylist for each of your main components e.g. enemiesList, wallsList. If C# is like java then the foreach loop is purely "read-only". Therefore, entities in our case, would not be able to be changed inside this loop. This is simple enough to change and it will make your game more flexible. –  Savlon Apr 14 '13 at 20:15
    
Ah, I see. Alright, I will change it then! You know what? Thanks a lot dude, for both your help and your patience with me :) You're a great helper!! –  Xeon Apr 15 '13 at 5:16
1  
All good mate, good luck :) –  Savlon Apr 15 '13 at 5:35
    
Err.. Wait.. I noticed that the collision response ( For stopping the object from moving through the object that it's colliding with ) is missing. Example, Player collides with Wall, Player cannot go through the Wall. Like, playerCurrentPos = playerPreviousPos or something like that...?Sorry for the disturbance again :P –  Xeon Apr 15 '13 at 13:25

Not the answer you're looking for? Browse other questions tagged or ask your own question.