954,518 Members — Technology Publication meets Social Media
Username:
Password:
Lost login information?
Have something to say? Contribute New Article Reply to this Article

Pong and Particles, need some help.

I've been trying to better my lesser side of knowledge in the C# programming language by tackling graphics head on. I've learned a little bit, but I'm getting stumped right now because I can't explain 100% what's going on here. I've developed a Pong game to teach myself how to use the Graphics class; in this game I want particles to fly off into random locations when the ball hits a paddle or wall. This much I've managed myself, however I've encountered a problem. My particles are going away too quickly and are a position behind the ball. Below is my source code with the multiple classes I'm using. (Please note I've ported the Vector2 class from XNA and called it BallVelocity.

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Threading;
using System.Diagnostics;
using System.Drawing;

namespace PONG
{
    public partial class Form1 : Form
    {
        // Threads
        private Thread ParticleThread;
        private Thread GameThread;

        // Game State
        private GameState gsState = new GameState();

        // Objects
        private Rectangle rBall;
        private Rectangle rLeftPlayer;
        private Rectangle rRightPlayer;

        // Aspect Ratio
        private const int iWidth = 820;
        private const int iHeight = 422;

        // Movement
        private int iLeftY = iHeight / 2 - 50;
        private int iRightY = iHeight / 2 - 50;
        private int iBallX = iWidth / 2 - 5;
        private int iBallY = iHeight / 2 - 5;

        // Velocity
        private BallVelocity bvVelocity = BallVelocity.Zero;

        // Scoring
        private int[] iaScores = new int[2];

        // Game Started and Activate Particles Booleans
        private bool bGameStarted = false;
        private bool ActivateParticles = false;

        public Form1()
        {
            InitializeComponent();
            CreateEvents();
            SetGraphics();
        }

        internal void ParticleEngine()
        {
            try
            {
                for (; ; )
                {
                    Thread.Sleep(50);
                    List<Particle> ToBeRemoved = new List<Particle>();

                    lock (gsState.Particles)
                    {
                        foreach (Particle p in gsState.Particles)
                        {
                            if (p.PerformFrame(gsState))
                                ToBeRemoved.Add(p);
                        }
                    }

                    foreach (var p in ToBeRemoved)
                    {
                        gsState.Particles.Remove(p);
                    }
                }
            }

            catch (ThreadAbortException ex)
            {
                Debug.Print("Game ending.");
            }
        }

        private void CreateEvents()
        {
            this.KeyDown += new KeyEventHandler(MovePlayer);
        }

        private void SetGraphics()
        {
            rBall = new Rectangle(iWidth / 2, iHeight / 2, 15, 15);
            rLeftPlayer = new Rectangle(5, iHeight / 2, 15, 100);
            rRightPlayer = new Rectangle(iWidth - 15 - 5, iHeight / 2, 15, 100);
        }

        private void MovePlayer(object sender, KeyEventArgs e)
        {
            if (e.KeyCode == Keys.Up)
                iLeftY -= 5;

            else if (e.KeyCode == Keys.Down)
                iLeftY += 5;

            rLeftPlayer = new Rectangle(5, iLeftY, 15, 100);
        }

        private void UpdateBall()
        {
            rBall.X += (int)bvVelocity.X;
            rBall.Y += (int)bvVelocity.Y;

            if (rBall.Y < 0 || rBall.Y + rBall.Height > iHeight)
            {
                bvVelocity.Y = -bvVelocity.Y;

                PointF BallLocation = new PointF(rBall.X, rBall.Y);

                for (int i = 0; i < 25; i++)
                {
                    Particle NewParticle = new Particle(BallLocation, 1);
                    gsState.Particles.Add(NewParticle);
                }

                ActivateParticles = true;
            }

            if (rBall.IntersectsWith(rLeftPlayer) || rBall.IntersectsWith(rRightPlayer))
            {
                bvVelocity.X = -bvVelocity.X;

                PointF BallLocation = new PointF(rBall.X, rBall.Y);

                for (int i = 0; i < 25; i++)
                {
                    Particle NewParticle = new Particle(BallLocation, 1);
                    gsState.Particles.Add(NewParticle);
                }

                ActivateParticles = true;
            }

            if (rBall.X < 0)
            {
                iaScores[1]++;
                InitiateBall();
            }

            else if (rBall.X + rBall.Width > iWidth)
            {
                iaScores[0]++;
                InitiateBall();
            }
        }

        private void InitiateBall()
        {
            int iSpeed = 15;

            Random rRandom = new Random();

            switch (rRandom.Next(4))
            {
                case 0:
                    bvVelocity.X = iSpeed;
                    bvVelocity.Y = iSpeed;
                    break;

                case 1:
                    bvVelocity.X = -iSpeed;
                    bvVelocity.Y = iSpeed;
                    break;

                case 2:
                    bvVelocity.X = iSpeed;
                    bvVelocity.Y = -iSpeed;
                    break;

                case 3:
                    bvVelocity.X = -iSpeed;
                    bvVelocity.Y = -iSpeed;
                    break;
            }

            rBall.X = iWidth / 2 - 5;
            rBall.Y = iHeight / 2 - 5;
        }

        private void mComputer()
        {
            if (rBall.X > rRightPlayer.X - 200)
            {
                if (rRightPlayer.Y > rBall.Y)
                    rRightPlayer.Y = rRightPlayer.Y - 5;

                else
                    rRightPlayer.Y = rRightPlayer.Y + 5;
            }

            else
            {
                if (rRightPlayer.Y == iHeight / 2)
                    rRightPlayer.Y = iHeight / 2;

                else if (rRightPlayer.Y > iHeight / 2)
                    rRightPlayer.Y = rRightPlayer.Y - 5;

                else
                    rRightPlayer.Y = rRightPlayer.Y + 5;
            }
        }

        private void PaintObjectsAndKeepScore(object sender, PaintEventArgs e)
        {
            e.Graphics.DrawRectangle(new Pen(Brushes.Lime), rLeftPlayer);
            e.Graphics.FillRectangle(Brushes.Green, rLeftPlayer);

            e.Graphics.DrawRectangle(new Pen(Brushes.Red), rRightPlayer);
            e.Graphics.FillRectangle(Brushes.Maroon, rRightPlayer);

            e.Graphics.DrawEllipse(new Pen(Brushes.Gray), rBall);
            e.Graphics.FillEllipse(Brushes.White, rBall);

            if (ActivateParticles)
            {
                lock (gsState.Particles)
                {
                    foreach (Particle p in gsState.Particles)
                        p.DrawParticles(e.Graphics);
                }

                ActivateParticles = false;
            }
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            ParticleThread = new Thread(ParticleEngine);
            ParticleThread.Start();

            InitiateBall();
            Updater.Start();
        }

        private void EndGame(object sender, FormClosingEventArgs e)
        {
            ParticleThread.Abort();
            ParticleThread = null;
        }

        private void UpdateGame(object sender, EventArgs e)
        {
            UpdateBall();
            mComputer();

            Invoke((MethodInvoker)(() =>
            {
                this.Invalidate();
                this.Update();
            }));
        }
    }

    internal class Particle
    {
        private TimeSpan ParticleLife = new TimeSpan(0, 0, 3);
        private DateTime? ParticleBirth;

        internal PointF Location { get; private set; }
        internal PointF Velocity { get; private set; }

        internal static Random Random = new Random();

        internal static PointF RandomVector(float Speed)
        {
            float RandomAngle = (float)(Random.NextDouble() * (Math.PI * 2));
            Speed *= (float)(Random.NextDouble());

            return new PointF((float)Math.Sin(RandomAngle) * Speed, (float)Math.Cos(RandomAngle) * Speed);
        }

        internal Particle(PointF Location, float Speed)
            : this(Location, RandomVector(Speed))
        {

        }

        internal Particle(PointF Location, PointF Velocity)
        {
            this.Location = Location;
            this.Velocity = Velocity;
        }

        internal bool PerformFrame(GameState gs)
        {
            if (ParticleBirth == null) ParticleBirth = DateTime.Now;

            Location = new PointF(Location.X + Velocity.X, Location.Y + Velocity.Y);
            Velocity = new PointF(Velocity.X * 0.99f, Velocity.Y * 0.99f);

            return DateTime.Now - ParticleBirth > ParticleLife;
        }

        internal void DrawParticles(Graphics g)
        {
            g.DrawRectangle(new Pen(Brushes.White), Location.X - 2, Location.Y - 2, 5, 5);
        }
    }

    internal class GameState
    {
        internal List<Particle> Particles;

        internal GameState()
        {
            Particles = new List<Particle>();
        }
    }

    internal class BallVelocity
    {
        internal int X;
        internal int Y;

        internal static BallVelocity Zero = new BallVelocity(0, 0);

        internal BallVelocity(int X, int Y)
        {
            this.X = X;
            this.Y = Y;
        }
    }
}


All help is greatly appreciated on this matter.

Thanks,
Jamie

lxXTaCoXxl
Posting Whiz
300 posts since Mar 2011
Reputation Points: 22
Solved Threads: 18
 

I figured it out; remove the line setting ActivateParticles to false from the paint method.

lxXTaCoXxl
Posting Whiz
300 posts since Mar 2011
Reputation Points: 22
Solved Threads: 18
 

This question has already been solved

Post: Markdown Syntax: Formatting Help
You