Simulate Ball + Elastic in console window

William Hemsworth 1 Tallied Votes 437 Views Share

Saw this and decided to make a little spinoff with some physics of mine. Enjoy!

// 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;
}
William Hemsworth 1,339 Posting Virtuoso

9f7ed0944cf37b1d91a39c1318f3f30b

For anybody who's interested in the math, here's a tutorial (made with the Flash IDE in mind):

YassinTAH 0 Newbie Poster

Inline Code Example Here 137: GetConsoleWindow was not declared

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.