Saw this and decided to make a little spinoff with some physics of mine. Enjoy!
Simulate Ball + Elastic in console window
// draw two lines and a circle on your console screen
// original BCX basic code by Sir Joe Caverly
// translated to C code and modified to work with Dev-C++
// link with GDI32.lib or with Dev-C++ link libgdi32.a via
// Project>>Project Options>>Parameters>>Add Lib>>libgdi32.a
// this is a Windows Console Application
#include <windows.h> // Win32API Header File
#include <cstring>
#include <cmath>
using namespace std;
#define Red RGB (255,0,0)
#define Lime RGB (206,255,0)
#define Blue RGB (0,0,255)
static HWND hConWnd;
int BCX_Line (HWND,int,int,int,int,int=0,HDC=0);
int BCX_Circle (HWND,int,int,int,int=0,int=0,HDC=0);
struct Ball
{
static float radius;
float x, y, vx, vy;
};
float Ball::radius = 20.0f;
void BallElastic(Ball *ball, float xa, float ya, float xb, float yb)
{
// Ball radius
float r = Ball::radius;
// pointA Coords
float x1 = xa;
float y1 = ya;
// pointB Coords
float x2 = xb;
float y2 = yb;
// Ball Coords
float cx = ball->x;
float cy = ball->y;
// Gives you the angle between pointA and pointB
float angleAB = atan2(y2 - y1, x2 - x1);
// Pre-calculate cosine and sine
float cosine = cos( angleAB );
float sine = sin( angleAB );
// Distances between ball and elastic center
float dbex = ball->x - (x2 + x1) / 2;
float dbey = ball->y - (y2 + y1) / 2;
// Find position of ball relative to
// the elastic (and it's rotation)
float px1 = cosine * dbex + sine * dbey;
float py1 = cosine * dbey - sine * dbex;
float maxPerpDist = sqrt( (x2-x1)*(x2-x1) + (y2-y1)*(y2-y1)) / 2;
if ( -py1 < r && px1 > -maxPerpDist && px1 < maxPerpDist )
{
// Distances from ball to pointA
float dx1 = cx - x1;
float dy1 = cy - y1;
// Distances from ball to pointB
float dx2 = cx - x2;
float dy2 = cy - y2;
// Calculate exact distances (LEFT)
float h1 = sqrt( dx1*dx1 + dy1*dy1 );
float p1 = sqrt( h1*h1 - r*r);
// Calculate exact distances (RIGHT)
float h2 = sqrt( dx2*dx2 + dy2*dy2 );
float p2 = sqrt( h2*h2 - r*r );
// don t continue if the ball touches points
if ( h1 < r || h2 < r ) {
return;
}
// Calculate angles (LEFT)
float a1 = atan2( dy1, dx1 );
float b1 = asin( r / h1 );
// Calculate angles (RIGHT)
// Small adjustment needed to find tangent
// on opposite side of ball
// (hence -r = opposite radius)
float a2 = atan2( dy2, dx2 );
float b2 = asin( -r / h2 );
// Tangent/Ball intersection coordinates (LEFT)
float ix1 = cos( a1+b1 ) * p1 + x1;
float iy1 = sin( a1+b1 ) * p1 + y1;
// Tangent/Ball intersection coordinates (RIGHT)
float ix2 = cos( a2+b2 ) * p2 + x2;
float iy2 = sin( a2+b2 ) * p2 + y2;
float mpx = (ix1 + ix2) / 2;
float mpy = (iy1 + iy2) / 2;
// Calculate acceleration based on the offset
// to the average of the 2 intersections
float accAngle = atan2( mpy-cy, mpx-cx );
// Power is dependent on how far the
// elastics been stretched
float power = py1 / 100;
ball->vx -= cos(accAngle) * power;
ball->vy -= sin(accAngle) * power;
// Draw lines
BCX_Line( hConWnd, (int)x1, (int)y1, (int)ix1, (int)iy1, Lime );
BCX_Line( hConWnd, (int)x2, (int)y2, (int)ix2, (int)iy2, Lime );
}
else
{
// No collision detected...
// simply draw a line from pointA to pointB
BCX_Line( hConWnd, (int)x1, (int)y1, (int)x2, (int)y2, Lime );
}
}
int main()
{
hConWnd = GetConsoleWindow();
if (hConWnd)
{
// be creative here, draw your own circles or lines
//// Okay!
Ball ball = { 140.0f, 100.0f, 0.0f, 0.0f }; // x,y,vx,vy
while ( 1 )
{
// Clear
RECT clearRect = {0,0,600,500};
FillRect( GetDC(hConWnd), &clearRect, CreateSolidBrush(0) );
// Draw
BallElastic( &ball, 0, 200, 500, 260 );
BCX_Circle( hConWnd, ball.x, ball.y, Ball::radius, Lime );
BCX_Line( hConWnd, 500, 0, 500, 500, Lime );
ball.x += ball.vx;
ball.y += ball.vy;
ball.vy += 0.2f;
if ( ball.x < Ball::radius )
{
ball.x = Ball::radius;
ball.vx *= -1;
}
else if ( ball.x > 500 - Ball::radius )
{
ball.x = 500 - Ball::radius;
ball.vx *= -1;
}
Sleep( 20 );
}
}
return 0;
}
int BCX_Line (HWND Wnd,int x1,int y1,int x2,int y2,int Pen,HDC DrawHDC)
{
int a,b=0;
HPEN hOPen;
// penstyle, width, color
HPEN hNPen = CreatePen(PS_SOLID, 2, Pen);
if (!DrawHDC) DrawHDC = GetDC(Wnd), b = 1;
hOPen = (HPEN)SelectObject(DrawHDC, hNPen);
// starting point of line
MoveToEx(DrawHDC, x1, y1, NULL);
// ending point of line
a = LineTo(DrawHDC, x2, y2);
DeleteObject(SelectObject(DrawHDC, hOPen));
if (b) ReleaseDC(Wnd, DrawHDC);
return a;
}
// converts circle(centerX,centerY,radius,pen) to WinApi function
// ellipse inside box with upper left and lower right coordinates
int BCX_Circle(HWND Wnd,int X,int Y,int R,int Pen,int Fill,HDC DrawHDC)
{
int a, b = 0;
if (!DrawHDC) DrawHDC = GetDC(Wnd), b = 1;
// penstyle, width, color
HPEN hNPen = CreatePen(PS_SOLID, 2, Pen);
HPEN hOPen = (HPEN)SelectObject(DrawHDC, hNPen);
HBRUSH hOldBrush;
HBRUSH hNewBrush;
// if true will fill circle with pencolor
if (Fill)
{
hNewBrush = CreateSolidBrush(Pen);
hOldBrush = (HBRUSH)SelectObject(DrawHDC, hNewBrush);
}
else
{
hNewBrush = (HBRUSH)GetStockObject(NULL_BRUSH);
hOldBrush = (HBRUSH)SelectObject(DrawHDC, hNewBrush);
}
a = Ellipse(DrawHDC, X-R, Y+R, X+R, Y-R);
DeleteObject(SelectObject(DrawHDC, hOPen));
DeleteObject(SelectObject(DrawHDC, hOldBrush));
if (b) ReleaseDC(Wnd, DrawHDC);
return a;
}
Be a part of the DaniWeb community
We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.