Jump to content
  • Advertisement
Sign in to follow this  
obi-wan shinobi

Pong collision problem

This topic is 4566 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

I'm in the process of coding Pong using Managed DirectX, but my collision detection is having problems. What I know so far is that there's an issue with how I'm implementing velocity and that it sometimes goes through the paddle depending on the speed. Depending on the value of xv (x-velocity), the ball will always hit the paddles(8), go right through(6 or 10), hang on the right paddle(5), or not move at all(4). When the ball does move, it appears to travel to the left faster than to the right, even though I think I'm only changing the x-velocity by keeping the same number and switching between +/-. Note that I'm not using any threads or other timing mechanisms. The source is below, made so that you can copy and paste into a VC#/#develop project, referencing the DirectX libraries. If you spot a problem, state clearly what it is and if possible, how it can be fixed.
using System;
using System.Text;
using System.Drawing;
using System.Windows.Forms;
using Microsoft.DirectX;
using Microsoft.DirectX.Direct3D;
using Microsoft.DirectX.DirectInput;
using dx = Microsoft.DirectX;
using d3d = Microsoft.DirectX.Direct3D;
using din = Microsoft.DirectX.DirectInput;

public class pong : Form
{
    private Rectangle[] rects;
    private Point[] points;
    private d3d.Device d3ddev;
    private din.Device dindev;
    private Graphics gfx;
    private int xv, yv, dir;
    private int p1, p2;
    private System.Random srand;

    public pong()
    {
        this.ClientSize = new Size(800, 600);
        this.Text = "Pong in Direct3D";
        this.gfx = this.CreateGraphics();
        rects = new Rectangle[3];
        points = new Point[3];
        points[0] = new Point(0, 250);
        points[1] = new Point(398, 298);
        points[2] = new Point(790, 250);
        rects[0].Location = points[0];
        rects[0].Width = 10;    rects[0].Height = 100;
        rects[1].Location = points[1];
        rects[1].Width = 4;     rects[1].Height = 4;
        rects[2].Location = points[2];
        rects[2].Width = 10;    rects[2].Height = 100;
        xv = 6;
        yv = 0;
        p1 = p2 = 0;
        srand = new System.Random();
    }

    public void initgfx()
    {
        d3d.PresentParameters d3dpp = new PresentParameters();
        d3dpp.Windowed = true;
        d3dpp.SwapEffect = SwapEffect.Discard;
        d3ddev = new d3d.Device(0, d3d.DeviceType.Hardware, this, CreateFlags.SoftwareVertexProcessing, d3dpp);
    }

    public void initkey()
    {
        dindev = new din.Device(SystemGuid.Keyboard);
        dindev.SetCooperativeLevel(this, CooperativeLevelFlags.NonExclusive | CooperativeLevelFlags.Background);
        dindev.Acquire();
    }

    public void getinput()
    {
        foreach (Key k in dindev.GetPressedKeys())
        {
            if (k == Key.W && points[0].Y>0)    points[0].Y-=4;
            if (k == Key.S && points[0].Y<500)  points[0].Y+=4;
            if (k == Key.O && points[2].Y>0)    points[2].Y-=4;
            if (k == Key.L && points[2].Y<500)  points[2].Y+=4;
        }
    }

    public void startup()
    {
        int b = 0;
        while (b == 0)
        {
            gfx.DrawString("Press 'b' to begin the game.", new System.Drawing.Font(FontFamily.GenericSerif, 20),
                Brushes.Red, new Point(50, 100));
            foreach (Key k in dindev.GetPressedKeys())
                if (k == Key.B) b = 1;
        }
    }

    public void checkhit()
    {
        if (rects[1].Left == rects[0].Right)
        {
            xv = -xv;
        }
        if (rects[1].Right == rects[2].Left)
        {
            xv = -xv;
        }
    }

    public void update()
    {
        rects[0].Y = points[0].Y;
        rects[2].Y = points[2].Y;
        int xn = points[1].X + xv;
        if (xv > 0)
        {
            while (points[1].X + 4 < xn)
            {
                points[1].X++;
                checkhit();
                gfx.DrawString(xv.ToString(), new System.Drawing.Font("Arial", 12), Brushes.Yellow, new Point(0, 512));
            }
        }
        if (xv < 0)
        {
            while (points[1].X > xn)
            {
                points[1].X--;
                checkhit();
                gfx.DrawString(xv.ToString(), new System.Drawing.Font("Arial", 12), Brushes.Yellow, new Point(0, 128));
            }
        }
        if (xv == 0)
            gfx.DrawString("?", new System.Drawing.Font("Arial", 12), Brushes.Orange, new Point(0, 0));
    //    points[1].X += xv;
    //    points[1].Y += yv;
        rects[1].X = points[1].X;
        rects[1].Y = points[1].Y;
    }

    public void render()
    {
        getinput();
        checkhit();
        update();
        d3ddev.Clear(ClearFlags.Target, Color.Black, 1.0f, 0);
        d3ddev.BeginScene();
        gfx.FillRectangles(Brushes.White, rects);
        d3ddev.EndScene();
        d3ddev.Present();

    }

    public void play()
    {
        this.initgfx();
        this.initkey();
        this.Show();
        this.startup();
        while (this.Created)
        {
            this.render();
            Application.DoEvents();
        }
    }

    public static void Main()
    {
        pong p = new pong();
        p.play();
    }
}

Share this post


Link to post
Share on other sites
Advertisement
Hi.
If you look closely at your checkhit function, you will easily see one problem: your are checking for strict equality between a paddle side and the ball side.
This leads to the ball going through the paddles (if the distance between each paddle is not a multiple of the xv speed).
I advise to change it thus:

public void checkhit()
{

if (rects[1].Left <= rects[0].Right)
{
xv = -xv;
//do not forget to reposition the ball so that
//it does not look like as though it bit the paddle
}

if (rects[1].Right => rects[2].Left)
{
xv = -xv;
//do not forget to reposition the ball so that
//it does not look like as though it bit the paddle
}
}



Now look closely at your update function: when xv is positive, you add 4 to your ball x position. This looks like legacy code since it nullifies the xn calculation when the xv is 4. Another problem is that your update function increments in a loop the ball x position but never gets rendered: this is a waste of code. I understand you wanted to do fine check against each paddle, but with the modification I gave you above, it is unnecessary.
I suggest the following:


public void update()
{
//update paddles and ball position
rects[0].Y = points[0].Y;
rects[2].Y = points[2].Y;
points[1].X += xv;

//check for hit
checkhit();

if (xv == 0)
gfx.DrawString("?", new System.Drawing.Font("Arial", 12), Brushes.Orange, new Point(0, 0));
else
gfx.DrawString(xv.ToString(), new System.Drawing.Font("Arial", 12), Brushes.Yellow, new Point(0, 512));

//update ball rect
rects[1].X = points[1].X;
rects[1].Y = points[1].Y;
}



Try those out. It should be better. When you have such a problem, trace your program manually on a sheet of paper and test the critical cases (ball against paddle, ball near paddle, ball with velocity xv, etc...). Most often in such cases you will soon see logic bugs.
Ghostly yours,
Red.

Share this post


Link to post
Share on other sites
Thanks for the tip. I improved the checkhit and update functions to make it more playable, though the flicker is still there when I call GDI+ in Managed DirectX. Next, I'll work on timing, scorekeeping, and some GUI work.

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!