I have been learning c# by making a basic ball bouncing simulation, kind of like the windows screensaver with the bubbles.
I have two balls bouncing around the screen, but when they collide they disappear, and I am not sure why.
I have done debugging using 'Console.WriteLine(value)', and found most values are equating to infinity after the collision.
I ended up scrapping that code, but need a better solution for ball collisions.
** NOTE ** This won't always be just two balls bouncing around a screen, this is just me trying to learn collisions ** NOTE **
Anyone with knowledge on Verlet Integration would be greatly appreciated, because I am very confused.
Here is some of my code & the version of C# I am using:
Screenshot from replit showing c# version
//+++ = I don't know what this is, a yt tutoriaol told me to use it
using System;
using System.Collections.Generic; //+++
using System.ComponentModel; //+++
using System.Data; //+++
using System.Drawing;
using System.Linq; //+++
using System.Text; //+++
using System.Threading.Tasks; //+++
using System.Windows.Forms; // This doesn't work in standard c#, only in mono for some reason.
public class Form1 : Form
{
float screenWidth;
float screenHeight;
float xpa = 0;
float ypa = 0;
float xva = 2;
float yva = 2;
float xpb; //later this is set to the width of the form minus the width of the ellipse this is marking the position of
float ypb; //later this is set to the height of the form, minus the height of the ellipse this is marking the position of
float xvb = -2;
float yvb = -2;
//...Unimportant code here...\\
var refreshTimer = new Timer();
refreshTimer.Interval = 1;
refreshTimer.Tick += new EventHandler(refreshTimer_Tick);
refreshTimer.Start();
}
//...Unimportant code here...\\
private void refreshTimer_Tick(object sender, EventArgs e)
{
this.Invalidate();
}
private void Form1_Paint(object sender, PaintEventArgs e)
{
Graphics g = e.Graphics;
//...Unimportant code here...\\
//Both ellipses bounce when in contact with the wall
//Ellipse A is located at coords (xpa, ypa) with width and height 50
//Ellipse A is located at coords (xpb, ypb) with width and height 50
//Collisions between A & B
float dx = (xpb + 25) - (xpa + 25);
float dy = (ypb + 25) - (ypa + 25);
float distance = (float)Math.Sqrt(dx * dx + dy * dy);
if (distance <= 50)
{
float angle = (float)Math.Atan2(dy, dx);
float sin = (float)Math.Sin(angle);
float cos = (float)Math.Cos(angle);
}
}
//...Rest of Code...\\
Does anyone know about Verlet Integration or any other techniques that could help me?
I simplified the code a lot by adding a
Ballclass and using the Vector2 Struct from the System.Numerics Namespace (I have included a minimal implementation for mono below).Vector2contains useful methods and operators for vector math. E.g., you can add two vectors withVector2 result = v1 + v2.The
Ballclass wraps all the state of a ball and some methods likeCollideWithWall. The advantage is that we have to write this code only once for all the balls.Ballnow stores the center coordinates of the ball, not the top left position. This makes it easier to reason about it. It also stores the radius, allowing us to have balls of different radii.For the collision I found a working solution from the user mmcdole. I adapted it to C# and your simulation. But the core of your simulation, the integration of the speeds to get the motion, remains the same.
then we can initialize the form with (in
Form1)Our Paint method now looks like this:
If you want to change the form properties in the forms designer, then you must also call
InitializeComponent();in the form's constructor.EDIT:
Since you are using mono that does not have the
Vextor2struct, here is a minimal version of it, implementing only the required stuff for the code above:Explanation
I am not going to explain the collision itself. Follow the link to mmcdole's code for this.
You are using a lot of variables like
xpa,ypa,xva,yva,xpb,ypb,xvb,yvb. Most of the changes I've made are to reduce the number of variables and avoid code duplication.For instance we have
float xpaandfloat ypastoring the position of objecta. TheVector2type stores both coordinates in itsXandYfields and requires only one variable. It also contains methods and operator overloads that allow performing arithmetic operations on them.Example:
Another problem is that a lot of code is duplicated because it must be applied to the
<whatever>avariables and the<whatever>bvariables. Especially in theForm1_Paintmethod.The idea is to wrap all the variables belonging to a ball in a
Ballobject (declared as class). Inside this object the variables (or properties with{ get; set; }) have the same name, no matter whether the object represents theaball or thebball.Methods inside this
Ballclass now work with the object's properties.Example:
It uses the
Brush,CenterandRadiusproperties of the object. I decided to store the color of the ball asBrush, sinceFillEllipserequires a brush.From outside, if we have two balls called
aandb, we can draw them with the calls:One code duplication eliminated! The same applies to
Move,CollideWithWallandCollideWith(colliding with another ball).This code works like yours, except for the ball-ball collision.
See also: