I wrote a demo to simulate the elastic collision of small balls and posted it first.
Scenario Description:
Randomly generate n balls, random initial speed, initial direction, quality, size, and color.
Each ball is regarded as a particle. The collision between the ball and the ball, the ball and the wall is elastic (I .e., after the collision, the X and Y axes are reversed, and the size remains unchanged), and kinetic energy conservation.
Left-click the mouse and stop the movement. The Arrow is used to identify the current direction of movement. Click again to start the movement.
Right-click and reinitialize the scenario and start again.
The program consists of a ball class, game class, And mainform.
Mainform provides the "canvas" of the scenario, and game controls the ball movement.
Form code:
Using system; <br/> using system. collections. generic; <br/> using system. componentmodel; <br/> using system. data; <br/> using system. drawing; <br/> using system. LINQ; <br/> using system. text; <br/> using system. windows. forms; </P> <p> namespace bils <br/>{< br/> Public partial class form1: form <br/>{< br/> private game _ game = NULL; </P> <p> Public form1 () <br/>{< br/> initializecomponent (); <br/>}</P> <p> Private void form1_load (Object sender, eventargs e) <br/>{</P> <p >}</P> <p> private void form1_shown (Object sender, eventargs e) <br/>{< br/> _ game = new game (this. panel1.creategraphics (); <br/> _ game. start (); <br/>}</P> <p> private void timereffectick (Object sender, eventargs e) <br/>{< br/> _ game. refresh (); <br/>}</P> <p> private void panel=mousedown (Object sender, mouseeventargs e) <br/> {<B R/> If (E. Button = mousebuttons. Left) <br/>{< br/> This. timer1.enabled =! This. timer1.enabled; <br/> If (! This. timer1.enabled) <br/> _ game. pause (); <br/>}< br/> else if (E. button = mousebuttons. right) <br/>{< br/> dialogresult result = <br/> MessageBox. show ("restart this game? "," Bils ", <br/> messageboxbuttons. okcancel, messageboxicon. question, <br/> messageboxdefaultbutton. button2); <br/> If (result = dialogresult. cancel) <br/> return; <br/> _ game = new game (this. panel1.creategraphics (); <br/> _ game. start (); <br/>}</P> <p >}< br/>
Game Code:
Using system; <br/> using system. collections. generic; <br/> using system. LINQ; <br/> using system. text; <br/> using system. drawing; </P> <p> namespace bballs <br/> {<br/> class game <br/> {<br/> private list <ball> bballs = new list <ball> (); <br/> private graphics _ g = NULL; <br/> private int _ Top = 0; <br/> private int _ Bottom = 0; <br/> private int _ left = 0; <br/> private int _ Right = 0; <br/> private in T _ seqenceno = 0; <br/> private list <point> locations = new list <point> (); </P> <p> Public game (Graphics g) <br/>{< br/> _ g = g; <br/> _ Top = convert. toint32 (_ g. visibleclipbounds. top); <br/> _ Bottom = convert. toint32 (_ g. visibleclipbounds. bottom); <br/> _ left = convert. toint32 (_ g. visibleclipbounds. left); <br/> _ Right = convert. toint32 (_ g. visibleclipbounds. right); </P> <p> int x = convert. toint32 (_ g. VI Sibleclipbounds. width/4); <br/> int y = convert. toint32 (_ g. visibleclipbounds. height/5); </P> <p> for (INT I = 0; I <4; I ++) <br/> {<br/> for (Int J = 0; j <5; j ++) <br/>{< br/> point P = new point (); <br/> P. X = I * X; <br/> P. y = J * Y; <br/> locations. add (p); <br/>}</P> <p> Public void start () <br/>{< br/> _ g. clear (color. white); <br/> _ seqenceno = 0; <br/> bils. clear (); <B R/> int ballnum = (new random ()). next (2, 10); <br/> for (INT I = 0; I <ballnum; I ++) <br/>{< br/> system. threading. thread. sleep (500); <br/> generateball (); <br/>}</P> <p> Public void pause () <br/>{< br/> _ g. clear (color. white); <br/> foreach (ball B in bballs) <br/> {<br/> B. move (); <br/> B. drawwithdirection (); <br/>}</P> <p> Public void refresh () <br/>{< br/> _ g. clear (color. wh ITE); <br/> foreach (ball B in bballs) <br/> {<br/> B. checked = false; <br/>}</P> <p> foreach (ball B in bils) <br/>{< br/> B. move (); <br/> checkballandball (B); <br/> checkballandwall (B); <br/> B. draw (); <br/>}</P> <p> private void checkballandball (ball B1) <br/>{< br/> foreach (ball B2 in bballs) <br/>{< br/> If (b1.sequenceno = b2.sequenceno) <br/> continue; </P> <p> int distanceofball S = b1.distance (B2); </P> <p> point newspeed1 = b1.speed; <br/> point newspeed2 = b2.speed; <br/> point newposition1 = b1.position; <br/> point newposition2 = b2.position; </P> <p> If (distanceofbils <= b1.radius + b2.radius) <br/> {<br/> int totalweight = b1.weight + b2.weight; <br/> double s1_x = (b1.weight-b2.weight) * b1.speed. X + 2 * b2.weight * b2.speed. x; <br/> s1_x = math. round (s1_x/Tota Lweight, midpointrounding. awayfromzero); </P> <p> double s1_y = (b1.weight-b2.weight) * b1.speed. Y + 2 * b2.weight * b2.speed. y; <br/> s1_y = math. round (s1_y/totalweight, midpointrounding. awayfromzero); </P> <p> double s2_x = (b2.weight-b1.weight) * b2.speed. X + 2 * b1.weight * b1.speed. x; <br/> s2_x = math. round (s2_x/totalweight, midpointrounding. awayfromzero); </P> <p> double s2_y = (b2.weight -B1.weight) * b2.speed. Y + 2 * b1.weight * b1.speed. y; <br/> s2_y = math. round (s2_y/totalweight, midpointrounding. awayfromzero); </P> <p> newspeed1.x = convert. toint32 (s1_x); <br/> newspeed1.y = convert. toint32 (s1_y); <br/> newspeed2.x = convert. toint32 (s2_x); <br/> newspeed2.y = convert. toint32 (s2_y); <br/> b1.speed = newspeed1; <br/> b2.speed = newspeed2; </P> <p> int val = b1.radius + b2.radius -Distanceofbils; <br/> int x = convert. toint32 (Val * Math. ABS (math. cos (b1.angle); <br/> int y = convert. toint32 (Val * Math. ABS (math. sin (b1.angle); <br/> If (newspeed1.x! = 0) <br/> X = x * newspeed1.x/math. ABS (newspeed1.x); <br/> else <br/> X = x *-1; </P> <p> If (newspeed1.y! = 0) <br/> Y = y * newspeed1.y/math. ABS (newspeed1.y); <br/> else <br/> Y = y *-1; </P> <p> newposition1.x = newposition1.x + X; <br/> newposition1.y = newposition1.y + Y; <br/> b1.position = newposition1; </P> <p> b1.move (); <br/> b2.move (); <br/> If (b1.distance (B2) <= b1.radius + b2.radius) <br/> {<br/> console. writeline ("======="); <br/> console. writeline (b1.tostring (); <br/> console. writeline (b2.tostring (); <br/> console. writeline ("======= "); <br/>}</P> <p> private void checkballandwall (ball B) <br/> {<br/> point newspeed = B. speed; <br/> point newposition = B. position; </P> <p> If (B. position. x <_ left | B. position. X + B. radius * 2> _ Right) <br/> {<br/> newspeed. X = B. speed. x * (-1); <br/> If (B. position. x <_ left) <br/> newposition. X = _ left; <br/> If (B. position. X + B. radius * 2> _ Right) <br/> newposition. X = _ Right-B. radius * 2; <br/>}</P> <p> If (B. position. Y <_ top | B. position. Y + B. radius * 2> _ bottom) <br/> {<br/> newspeed. y = B. speed. y * (-1); <br/> If (B. position. Y <_ top) <br/> newposition. y = _ top; <br/> If (B. position. Y + B. radius * 2> _ bottom) <br/> newposition. y = _ bottom-B. radius * 2; <br/>}</P> <p> B. speed = newspeed; <br/> B. position = newposition; <br/>}</P> <p> private void generateball () <br/>{< br/> random RDM = new random (); </P> <p> int radius = RDM. next (10, 30); <br/> int Weight = RDM. next (10, 50); <br/> int Red = RDM. next (0,255); <br/> int Green = RDM. next (0,255); <br/> int Blue = RDM. next (0,255); <br/> color = color. fromargb (red, green, blue); </P> <p> int locationidx = RDM. next (0, locations. count-1); <br/> point P = locations [locationidx]; <br/> locations. remove (p); </P> <p> point speed = new point (); <br/> speed. X = convert. toint32 (RDM. next (-200,200)/20); <br/> speed. y = convert. toint32 (RDM. next (-200,200)/20); </P> <p> _ seqenceno = _ seqenceno + 1; </P> <p> ball = new ball (_ g, p, speed, radius, weight, color, _ seqenceno); <br/> bils. add (ball); <br/>}</P> <p >}< br/>}
Ball code:
Using system; <br/> using system. collections. generic; <br/> using system. LINQ; <br/> using system. text; <br/> using system. drawing; </P> <p> namespace bils <br/> {<br/> class ball <br/> {<br/> private graphics _ g; <br/> private point _ position; <br/> private point _ coreposition; <br/> private int _ radius; <br/> private point _ speed; <br/> private int _ weight; <br/> private color _ color; <br/> private double _ angle; <br/> private int _ sequenceno; <br/> private bool _ checked; </P> <p> Public bool checked <br/>{< br/> get {return _ checked ;} <br/> set {_ checked = value ;} <br/>}</P> <p> Public int sequenceno <br/>{< br/> get {return _ sequenceno ;} <br/>}</P> <p> Public point coreposition <br/>{< br/> get {return _ coreposition ;} <br/>}</P> <p> Public point position <br/>{< br/> get {return _ position ;} <br/> set <br/>{< br/> _ Position = value; <br/> _ coreposition. X = _ position. X + _ radius; <br/> _ coreposition. y = _ position. Y + _ radius; <br/>}</P> <p> Public point speed <br/>{< br/> get {return _ speed ;} <br/> set <br/>{< br/> _ speed = value; <br/> _ angle = math. atan2 (0-_ speed. y, _ speed. x) * (180/math. pi); <br/> If (_ angle <0) <br/> _ angle = 360 + _ angle; <br/>}</P> <p> Public int radius <br/>{< br/> get {return _ radius ;} <br/>}</P> <p> Public double angle <br/>{< br/> get {return _ angle ;} <br/>}</P> <p> Public int weight <br/>{< br/> get {return _ weight ;} <br/>}</P> <p> Public ball (Graphics g, point position, point speed, int radius, int weight, color, int seqno) <br/>{< br/> _ sequenceno = seqno; <br/> _ g = g; <br/> _ radius = radius; <br/> _ Position = position; </P> <p> _ coreposition = new point (); <br/> _ coreposition. X = _ position. X + _ radius; <br/> _ coreposition. y = _ position. Y + _ radius; </P> <p> _ speed = speed; <br/> _ Weight = weight; <br/> _ color = color; <br/> _ angle = math. atan2 (0-_ speed. y, _ speed. x) * (180/math. pi); </P> <p> If (_ angle <0) <br/> _ angle = 360 + _ angle; <br/> drawwithdirection (); <br/>}</P> <p> Public void draw () <br/>{< br/> _ g. drawellipse (new pen (color. black, 3), _ position. x, _ position. y, 2 * _ radius, 2 * _ radius); <br/> _ g. fillellipse (New solidbrush (_ color), _ position. x, _ position. y, 2 * _ radius, 2 * _ radius); <br/>}</P> <p> Public void drawwithdirection () <br/>{< br/> draw (); <br/> displaydirection (this. _ coreposition, _ angle, 20); <br/>}</P> <p> private void displaydirection (point P, double angle, int length) <br/>{< br/> point P2 = drawlinebyangle (p, angle, length); </P> <p> If (angle <180) <br/>{< br/> drawlinebyangle (P2, 180 + angle-30, 5); <br/> drawlinebyangle (P2, 180 + angle + 30, 5 ); <br/>}< br/> else if (angle = 180) <br/>{< br/> drawlinebyangle (P2, 180 + angle-30, 5 ); <br/> drawlinebyangle (P2,-180 + angle + 30, 5 ); <br/>}< br/> else <br/> {<br/> drawlinebyangle (P2,-180 + angle-30, 5 ); <br/> drawlinebyangle (P2,-180 + angle + 30, 5 ); <br/>}</P> <p> private point drawlinebyangle (point P1, double A, int length) <br/>{< br/> double angle = math. ABS (a); <br/> If (angle> 360) <br/> Angle-= 360; </P> <p> double radians = angle * (math. PI/180); </P> <p> int offsetx = math. ABS (convert. toint32 (length * Math. cos (radians); <br/> int offsety = math. ABS (convert. toint32 (length * Math. sin (radians); </P> <p> point P2 = new point (); <br/> P2 = p1; </P> <p> If (angle> = 0 & angle <= 90) <br/>{< br/> p2.x = p1.x + offsetx; <br/> p2.y = p1.y-offsety; <br/>}< br/> else if (angle> 90 & angle <= 180) <br/>{< br/> p2.x = p1.x-offsetx; <br/> p2.y = p1.y-offsety; <br/>}< br/> else if (angle> 180 & angle <= 270) <br/>{< br/> p2.x = p1.x-offsetx; <br/> p2.y = p1.y + offsety; <br/>}< br/> else if (angle> 270 & angle <= 360) <br/>{< br/> p2.x = p1.x + offsetx; <br/> p2.y = p1.y + offsety; <br/>}</P> <p> _ g. drawline (new pen (color. red), P1, P2); <br/> return P2; <br/>}</P> <p> Public void move () <br/>{< br/> _ position. X = _ position. X + _ speed. x; <br/> _ position. y = _ position. Y + _ speed. y; <br/> _ coreposition. X = _ position. X + _ radius; <br/> _ coreposition. y = _ position. Y + _ radius; <br/>}</P> <p> Public int distance (ball B2) <br/>{< br/> double value1 = math. pow (_ coreposition. x-b2.coreposition. x), 2); <br/> double value2 = math. pow (_ coreposition. y-b2.coreposition. y), 2); <br/> double distance = math. SQRT (value1 + value2); <br/> int distanceofbils = convert. toint32 (math. round (distance, midpointrounding. awayfromzero); <br/> return distanceofbils; <br/>}</P> <p> Public int nextdistance (ball B2) <br/>{< br/> double value1 = math. pow (_ coreposition. X + _ speed. x-b2.coreposition. X + b2.speed. x), 2); <br/> double value2 = math. pow (_ coreposition. Y + _ speed. y-b2.coreposition. Y + b2.speed. y), 2); <br/> double distance = math. SQRT (value1 + value2); <br/> int distanceofbils = convert. toint32 (math. round (distance, midpointrounding. awayfromzero); <br/> return distanceofbils; <br/>}</P> <p> Public override string tostring () <br/> {<br/> return "Ball (" + _ sequenceno. tostring () + ") M:" + _ weight. tostring () + ", R:" + _ radius. tostring () + ", s_x:" + _ speed. X + ", s_y:" + _ speed. y; <br/>}< br/>