Particle and Physics problem.

Posted by Quincy on Game Development See other posts from Game Development or by Quincy
Published on 2011-03-13T11:51:42Z Indexed on 2011/03/13 16:17 UTC
Read the original article Hit count: 287

Filed under:
|
|
|

This was originally a forum post so I hope you guys don't mind it being 2 questions in one.

I am making a game and I got some basic physics implemented. I have 2 problems, 1 with particles being drawn in the wrong place and one with going through walls while jumping in corners.

Skip over to about 15 sec video showing the 2 problems : http://youtube.com/watch?v=Tm9nfWsWfiM

So the problem with the particles seems to be coming from the removal, as soon as I remove that piece of code it instantly works, but there shouldn't be a problem since they shouldn't even draw when their energy gets to 0 (and then they get removed)

So my first question is, how are these particles getting warped all over the screen ?

Relevant code :

Particle class :

class Particle
{
    //Physics
    public Vector2 position = new Vector2(0,0);
    public float direction = 180;
    public float speed = 100;
    public float energy = 1;
    protected float startEnergy = 1;

    //Visual
    public Sprite sprite;
    public float rotation = 0;
    public float scale = 1;
    public byte alpha = 255;
    public BlendMode blendMode
    {
        get
        {
            return sprite.BlendMode;
        }
        set
        {
            sprite.BlendMode = value;
        }
    }


    public Particle()
    {  
    }

    public virtual void Think(float frameTime)
    {
        if (energy - frameTime < 0)
            energy = 0;
        else
            energy -= frameTime;

        position += new Vector2((float)Math.Cos(MathHelper.DegToRad(direction)), (float)Math.Sin(MathHelper.DegToRad(direction))) * speed * frameTime;
        alpha = (byte)(255 * energy / startEnergy);
        sprite.Rotation = rotation;
        sprite.Position = position;
        sprite.Color = new Color(sprite.Color.R, sprite.Color.G, sprite.Color.B, alpha);
    }

    public virtual void Draw(float frameTime)
    {
        if (energy > 0)
        {
            World.camera.DrawSprite(sprite);
        }
    }
// Basic particle implementation
    class BasicSprite : Particle
    {
        public BasicSprite(Sprite _sprite)
        {
            sprite = _sprite;
        }
    }

Emitter :

    class Emitter
{
    protected static Random rand = new Random();
    protected List<Particle> particles = new List<Particle>();

    public BaseEntity target = null;
    public Vector2 position = new Vector2(0, 0);
    public bool Active = true;
    public float timeAlive = 0;
    public int particleCount = 0;
    public int ParticlesPerSeccond
    {
        get
        {
            return (int)(1 / particleSpawnTime);
        }
        set
        {
            particleSpawnTime = 1 / (float)value;
        }
    }
    public float dieTime = float.MaxValue;

    float particleSpawnTime = 0.05f;
    float spawnTime = 0;

    public Emitter()
    {

    }

    public virtual void Think(float frametime)
    {
            spawnTime += frametime;

            if (dieTime != float.MaxValue)
            {
                timeAlive += frametime;
                if (timeAlive >= dieTime)
                    Active = false;
            }

            if (Active)
            {

                if (target != null)
                    position = target.Position;

                while (spawnTime > particleSpawnTime)
                {
                    spawnTime -= particleSpawnTime;
                    AddParticle();
                    particleCount++;
                }

            }
            for (int i = 0; i < particles.Count; i++)
            {
                particles[i].Think(frametime);
                if (particles[i].energy <= 0)
                {
                    particles.Remove(particles[i]); // As soon as this is removed, it works
                    particleCount--;
                }
            }
    }

    public virtual void AddParticle()
    {

    }

    public virtual void Draw(float frametime)
    {
        foreach (Particle particle in particles)
        {
            particle.Draw(frametime);
        }
    }
}
class BloodEmitter : Emitter
{
    Image image;

    public BloodEmitter()
    {
        image = new Image(@"Content/Particles/TinyCircle.png");
        image.CreateMaskFromColor(new Color(255, 0, 255, 255));
        this.dieTime = 0.5f;
        this.ParticlesPerSeccond = 100;
    }

    public override void AddParticle()
    {
        Sprite sprite = new Sprite(image);
        sprite.Color = new Color((byte)(rand.NextDouble() * 255), (byte)(rand.NextDouble() * 255), (byte)(rand.NextDouble() * 255));

        BasicSprite particle = new BasicSprite(sprite);
        particle.direction = (float)rand.NextDouble() * 360;
        particle.position = position;
        particle.blendMode = BlendMode.Alpha;
        particles.Add(particle);
    }
}

The seccond problem is the physics problem, for some reason I can get through the right bottom corner while jumping. I think this is coming from me switching animations but I thought I made it compensate for that.

Relevant code : PhysicsEntity :

    class PhysicsEntity : BaseEntity
{
    // Horizontal movement constants
    protected const float maxHorizontalSpeed = 1000;
    protected const float horizontalAcceleration = 15;
    protected const float horizontalDragAir = 0.95f;
    protected const float horizontalDragGround = 0.95f;

    // Vertical movement constants
    protected const float maxVerticalSpeed = 1000;
    protected const float verticalAcceleration = 20;

    // Everything needed for movement and correct animations
    protected float movement = 0;
    protected bool onGround = false;
    protected Vector2 Velocity = new Vector2(0, 0);
    protected float maxSpeed = 0;
    float lastThink = 0;
    float thinkTime = 1f/60f;

    public PhysicsEntity(Vector2 position, Sprite sprite) :
        base(position, sprite)
    {

    }

    public override void Draw(float frameTime)
    {
        base.Draw(frameTime);
    }

    public override void Think(float frameTime)
    {
        CalculateMovement(frameTime);
        base.Think(frameTime);
    }

    protected void CalculateMovement(float frameTime)
    {
        lastThink += frameTime;

        while (lastThink > thinkTime)
        {
            onGround = false;

            Velocity.X = MathHelper.Clamp(Velocity.X + horizontalAcceleration * movement, -maxHorizontalSpeed, maxHorizontalSpeed);
            if (onGround)
                Velocity.X *= horizontalDragGround;
            else
                Velocity.X *= horizontalDragAir;

            if (maxSpeed < Velocity.X)
                maxSpeed = Velocity.X;

            Velocity.Y = MathHelper.Clamp(Velocity.Y + verticalAcceleration, -maxVerticalSpeed, maxVerticalSpeed);

            lastThink -= thinkTime;
            DoCollisions(thinkTime);
            DoAnimations(thinkTime);
        }
    }
    public virtual void DoAnimations(float frameTime)
    {

    }
    public void DoCollisions(float frameTime)
    {
        Position.Y += Velocity.Y * frameTime;
        Vector2 tileCollision = GetTileCollision();
        if (tileCollision.X != -1 || tileCollision.Y != -1)
        {
            Vector2 collisionDepth = CollisionRectangle.DepthIntersection(
                new Rectangle(
                    tileCollision.X * World.tileEngine.TileWidth,
                    tileCollision.Y * World.tileEngine.TileHeight,
                    World.tileEngine.TileWidth,
                    World.tileEngine.TileHeight
                )
            );
            Position.Y += collisionDepth.Y;
            if (collisionDepth.Y < 0)
                onGround = true;

            Velocity.Y = 0;
        }

        Position.X += Velocity.X * frameTime;
        tileCollision = GetTileCollision();
        if (tileCollision.X != -1 || tileCollision.Y != -1)
        {
            Vector2 collisionDepth = CollisionRectangle.DepthIntersection(
                new Rectangle(
                    tileCollision.X * World.tileEngine.TileWidth,
                    tileCollision.Y * World.tileEngine.TileHeight,
                    World.tileEngine.TileWidth,
                    World.tileEngine.TileHeight
                )
            );
            Position.X += collisionDepth.X;
            Velocity.X = 0;
        }
    }
    public void DoCollisions(Vector2 difference)
    {
        CollisionRectangle.Y = Position.Y - difference.Y;
        CollisionRectangle.Height += difference.Y;
        Vector2 tileCollision = GetTileCollision();
        if (tileCollision.X != -1 || tileCollision.Y != -1)
        {
            Vector2 collisionDepth = CollisionRectangle.DepthIntersection(
                new Rectangle(
                    tileCollision.X * World.tileEngine.TileWidth,
                    tileCollision.Y * World.tileEngine.TileHeight,
                    World.tileEngine.TileWidth,
                    World.tileEngine.TileHeight
                )
            );
            Position.Y += collisionDepth.Y;
            if (collisionDepth.Y < 0)
                onGround = true;

            Velocity.Y = 0;
        }

        CollisionRectangle.X = Position.X - difference.X;
        CollisionRectangle.Width += difference.X;
        tileCollision = GetTileCollision();
        if (tileCollision.X != -1 || tileCollision.Y != -1)
        {
            Vector2 collisionDepth = CollisionRectangle.DepthIntersection(
                new Rectangle(
                    tileCollision.X * World.tileEngine.TileWidth,
                    tileCollision.Y * World.tileEngine.TileHeight,
                    World.tileEngine.TileWidth,
                    World.tileEngine.TileHeight
                )
            );
            Position.X += collisionDepth.X;
            Velocity.X = 0;
        }
    }

    Vector2 GetTileCollision()
    {
        int topLeftTileX = (int)(CollisionRectangle.TopLeft.X / World.tileEngine.TileWidth);
        int topLeftTileY = (int)(CollisionRectangle.TopLeft.Y / World.tileEngine.TileHeight);
        int BottomRightTileX = (int)(CollisionRectangle.DownRight.X / World.tileEngine.TileWidth);
        int BottomRightTileY = (int)(CollisionRectangle.DownRight.Y / World.tileEngine.TileHeight);

        if (CollisionRectangle.DownRight.Y % World.tileEngine.TileHeight == 0) // If your exactly against the tile don't count that as being inside the tile
            BottomRightTileY -= 1;
        if (CollisionRectangle.DownRight.X % World.tileEngine.TileWidth == 0) // If your exactly against the tile don't count that as being inside the tile
            BottomRightTileX -= 1;

        for (int i = topLeftTileX; i <= BottomRightTileX; i++)
        {
            for (int j = topLeftTileY; j <= BottomRightTileY; j++)
            {
                if (World.tileEngine.TileIsSolid(i, j))
                {
                    return new Vector2(i, j);
                }
            }
        }

        return new Vector2(-1, -1);
    }
}

Player :

   enum State
{
    Standing,
    Running,
    Jumping,
    Falling,
    Sliding,
    WallSlide
}

class Player : PhysicsEntity
{
    private State state
    {
        get
        {
            return currentState;
        }
        set
        {
            if (currentState != value)
            {
                currentState = value;
                animationChanged = true;
            }
        }
    }

    private State currentState = State.Standing;
    private BasicEmitter basicEmitter = new BasicEmitter();
    public bool flipped;
    public bool animationChanged = false;

    protected const float jumpPower = 600;

    AnimationManager animationManager;
    Rectangle DrawRectangle;
    public override Rectangle CollisionRectangle
    {
        get
        {
            return new Rectangle(
                Position.X - DrawRectangle.Width / 2f,
                Position.Y - DrawRectangle.Height / 2f,
                DrawRectangle.Width,
                DrawRectangle.Height
            );
        }
    }

    public Player(Vector2 position, Sprite sprite) :
        base(position, sprite)
    {
        // Only posted the relevant bit
        DrawRectangle = animationManager.currentAnimation.drawingRectangle;
    }

    public override void Draw(float frameTime)
    {
        World.camera.DrawSprite(
            Sprite, 
            Position + new Vector2(DrawRectangle.X, DrawRectangle.Y),
            animationManager.currentAnimation.drawingRectangle
        );
    }

    public override void Think(float frameTime)
    {
        //I only posted the relevant stuff
        if (animationChanged)  
        {
            // if the animation has changed make sure we compensate for the change in with and height
            animationChanged = false;
            DoCollisions(animationManager.getSizeDifference());
        }
        DoCustomMovement();
        base.Think(frameTime);
        if (!onGround && Velocity.Y > 0)
        {
            state = State.Falling;
        }
    }

    void DoCustomMovement()
    {
        if (onGround)
        {
            if (World.renderWindow.Input.IsKeyDown(KeyCode.W))
            {
                Velocity.Y = -jumpPower;
                state = State.Jumping;
            }
        }
    }
    public override void DoAnimations(float frameTime)
    {
        string stateName = Enum.GetName(typeof(State), state);

        if (!animationManager.currentAnimationIs(stateName))
        {
            animationManager.PlayAnimation(stateName);
        }

        animationManager.Think(frameTime);

        DrawRectangle = animationManager.currentAnimation.drawingRectangle;
        Sprite.Center = new Vector2(
            DrawRectangle.X + DrawRectangle.Width / 2,
            DrawRectangle.Y + DrawRectangle.Height / 2
        );
        Sprite.FlipX(flipped);
    }

So why am I warping through walls ?

I have given this some thought but I just can't seem to find out why this is happening.

Full source if needed : source : http://www.mediafire.com/?rc7ddo09gnr68zd (download link)

© Game Development or respective owner

Related posts about c#

Related posts about physics