Archived

This topic is now archived and is closed to further replies.

aftermath

New smooth pong, My Engines first game

Recommended Posts

Heya! This is my first game that uses my brand new 2D game engine (using Direct3D). Please try it, its only like 227kb. (click on the image to downlaod) PS: the paddle movement is very smooth, thats why its called "Smoothey PONG"
[ my engine ][ my game ][ my email ] SPAM

Share this post


Link to post
Share on other sites
First, excellent job. Your engine seems to be comming along quite well. I have some suggestions for you tho.

1. Physics. The collision detection of the ball agains the walls and against the paddles needs some work. Right now you seem to be using the method of reversing the ball's x velocity when the ball is detected within the rectangle. This doesn't work for a fair portion of the possibilities in which the ball colides with the paddle. When the ball intercepts the paddle along either of the horizontal sides, the ball becomes trapped within the paddle for the durration of the paddle length. This doesn't necessarily hinder the game, but in the interest of representing the game's world most accurately, you would probabaly want to take a look at finding the intercept of the ball with all the paddle's sides and then reflecting the ball's direction as is correct for each situation.

EDIT: I don't know how to do that cool GDNet code control, so I'll have to email you with my code if you want to see it. OneHotCoconut@cs.com.

I found that that provided the most realistic 'pong' physics. It's far more intensive processor wise, but unless your running your program on a gameboy, it won't affect the speed. Note that this collision detection comes after the addition of the ball velocity to the ball, and before the rendering to the screen.

2. Consider increasing the volocity modifier for the paddles that you apply when the player hits the directional key for either paddle. Currently, the animation is very smooth, but it can handle a bit more of an increase without losing it's smoothness to increase gameplay.

3. Maybe you might remove the fluidity of the paddle's interaction with the top and bottom of the screen. Currently you have an excellent representation of kinetics, but it subtracts from the gameplay because it is nearly impossible to time the paddles decent to catch the ball just as it passes the bottom/top of the screen.

4. For gameplay results, maybe you could minutely increase the ball's velocity each time it hits the players paddles. This would be a small fractional increase, so as to not speed up gameplay too swiftly. Could add difficulty to the game.

5. Make the ball, well, a ball. Equations for drawing a circle with line equations can be found easily on the internet, or I could give you my code for it. Took me 3 months to finally figure it out on my own. It would be far easier for you to just get it off the internet. Search for "Scan Line Conversion", "Raster Graphics", or "Drawing 2D Primitives" for the equations/code.

These are merely suggestions for improvement, and hopefully I've helped you at least a little. Seriously, that is an excellent program for someone who is just beginning to write games, and I applaud you for your efforts. Just out of curriosity, did you use any physics from Andre Lamothe's book?

EDIT: Can someone show me how to use the GDNet source-code control? I could really use it sometimes... Thanks

-Brent Robinson

[edited by - Coconut on March 17, 2002 4:29:22 PM]

Share this post


Link to post
Share on other sites
Also, running the game in windowed mode causes distortions and graphical artifacts such as tearing and variations in the background image. General inconsistancies in the entire window.

-Brent Robinson

Share this post


Link to post
Share on other sites
quote:
Original post by Coconut
EDIT: Can someone show me how to use the GDNet source-code control? I could really use it sometimes... Thanks


Enclose the code in [ source ] [ /source ], without the spaces.

Share this post


Link to post
Share on other sites
After running Pong, what appears is... well... not exactly pong.

Here's a picture of what's happening:



The middle low vertex of the middle triangle in that picture moves as if it was the ball.

Edit: Thanks

--------------------
Matthew Calabrese
Realtime 3D Orchestra:
Programmer, Composer,
and 3D Artist/Animator
"I can see the music..."

[edited by - Matt Calabrese on March 17, 2002 5:13:28 PM]

[edited by - Matt Calabrese on March 17, 2002 5:56:29 PM]

Share this post


Link to post
Share on other sites
quote:
Original post by Matt Calabrese
Edit: what are all of the tags for displaying pictures/etc. and why is that not in the FAQ (or am I missing them in some place obvious)!?

I believe to place images and links you must simply put in standard HTML tags (not special forum tags).
For an image it would be:
<img src="the address of the image">

John B

Share this post


Link to post
Share on other sites
WOW!
Thanks for all the replys.
Coconut -
Thanks for the long reply *sight*. The colision detection was a problem for me last night, around 3am . I did try vereuse techneques to try to colide with the base of the paddle, the top side, and the bottom side. I couldnt do anything exept colide agaist the base of the paddle.
So you are saying that I need to process my paddles before i process my balls? OK. Or is it vis-verce?
I didnt work on the whole game alot (the logis part took like 1 houre to implement), but I spent some time debuging the engine. My goal wasent to realy make a bugg-free game that good or whatever. I just wanted to try the engines, and tweek it and soforth.
Durring tha making, I did fix some time bugs though
quote:
Make the ball, well, a ball.

The ball is acualy 2 triangles, and I dont have any sphere/circle rendering interfaces in the engine, YET.
(I might solve that by creating a texture with a pic with a circle. If there is any way of drawing curcles in d3d, tell me please)
I did not use anything from LeMothe at all, I realy dont like that guys whatsoever. All the "phisics" (if you want to call it that) were simple veliscity and acceleration changing, so, yeh, phisics!

quote:
After running Pong, what appears is... well... not exactly pong

Yeh, I just found out that was a problem because I didnt clear the Z-buffer (and not have a depth buffer at all). You can downlaod the fixed vertion now. here, (or on the pic above)
heres what i got last time i tryed making it harder


[ my engine ][ my game ][ my email ]
SPAM

Share this post


Link to post
Share on other sites
Nope, same problem -- refer to the pic above.

I''m running Direct X 8.1 so that''s not the problem. I don''t know what could be wrong.

--------------------
Matthew Calabrese
Realtime 3D Orchestra:
Programmer, Composer,
and 3D Artist/Animator
"I can see the music..."

Share this post


Link to post
Share on other sites
What I meant by when to process, is that you calculate the collisions after you''ve added the velocity values to the paddles and ball. This way you can make sure that they are all where they should physically be before you render the frame. That would mean you do such things as:

ball_x += ball_velocity_x;
etc...

then:

if(ball_x >= paddle_left && ball_x <= paddle_right)
ball_velocity_x = -ball_velocity_x;

then render.

That''s not the collision detection I''d use, just an example. Now that I can use the source control, here''s my source for collision detection:

  
bool PerformClipping()
{
RECT paddle;
RECT block;
RECT ball;
POINT Ballp; //coords of previous ball position

BLOCK *pBlock;

Ballp.x = Ball.x - Ballv.x;
Ballp.y = Ball.y - Ballv.y;

paddle.top = Paddle.y - BALL_RADIUS / 2;
paddle.left = Paddle.x - BALL_RADIUS / 2;
paddle.bottom = Paddle.y + PADDLE_HEIGHT + BALL_RADIUS / 2;
paddle.right = Paddle.x + PADDLE_WIDTH + BALL_RADIUS / 2;

ball.top = ((Ballp.y < Ball.y)? Ballp.y : Ball.y);
ball.left = ((Ballp.x < Ball.x)? Ballp.x : Ball.x);
ball.bottom = ((Ballp.y > Ball.y)? Ballp.y : Ball.y);
ball.right = ((Ballp.x > Ball.x)? Ballp.x : Ball.x);

if(Level < PADDLE_HEIGHT && Level < PADDLE_WIDTH && ClipsToRect(Ball.x, Ball.y, &paddle))
{
// Clipping Scheme 1: Quadrant based. Combination of original Quadrant visibility and Segment Interception points.

if(Ballp.y < paddle.top && Ballp.x >= paddle.left && Ballp.x <= paddle.right)
{
Ballv.y = -Ballv.y;
Ball.y = paddle.top;
}
else if(Ballp.y > paddle.bottom && Ballp.x >= paddle.left && Ballp.x <= paddle.right)
{
Ballv.y = -Ballv.y;
Ball.y = paddle.bottom;
}
else if(Ballp.x < paddle.left && Ballp.y >= paddle.top && Ballp.y <= paddle.bottom)
{
Ballv.x = -Ballv.x;
Ball.x = paddle.left;
}
else if(Ballp.x > paddle.right && Ballp.y >= paddle.top && Ballp.y <= paddle.bottom)
{
Ballv.x = -Ballv.x;
Ball.x = paddle.right;
}
else if(Ballp.x < paddle.left && Ballp.y < paddle.top)
{
if(ClipsToBlockTop(&paddle, Ball.x, Ball.y, Ballp.x, Ballp.y))
{
Ballv.y = -Ballv.y;
Ball.y = paddle.top;
}
else if(ClipsToBlockLeft(&paddle, Ball.x, Ball.y, Ballp.x, Ballp.y))
{
Ballv.x = -Ballv.x;
Ball.x = paddle.left;
}
}
else if(Ballp.x > paddle.right && Ballp.y < paddle.top)
{
if(ClipsToBlockTop(&paddle, Ball.x, Ball.y, Ballp.x, Ballp.y))
{
Ballv.y = -Ballv.y;
Ball.y = paddle.top;
}
else if(ClipsToBlockRight(&paddle, Ball.x, Ball.y, Ballp.x, Ballp.y))
{
Ballv.x = -Ballv.x;
Ball.x = paddle.right;
}
}
else if(Ballp.x < paddle.left && Ballp.y > paddle.bottom)
{
if(ClipsToBlockBottom(&paddle, Ball.x, Ball.y, Ballp.x, Ballp.y))
{
Ballv.y = -Ballv.y;
Ball.y = paddle.bottom;
}
else if(ClipsToBlockLeft(&paddle, Ball.x, Ball.y, Ballp.x, Ballp.y))
{
Ballv.x = -Ballv.x;
Ball.x = paddle.left;
}
}
else if(Ballp.x > paddle.right && Ballp.y > paddle.bottom)
{
if(ClipsToBlockBottom(&paddle, Ball.x, Ball.y, Ballp.x, Ballp.y))
{
Ballv.y = -Ballv.y;
Ball.y = paddle.bottom;
}
else if(ClipsToBlockRight(&paddle, Ball.x, Ball.y, Ballp.x, Ballp.y))
{
Ballv.x = -Ballv.x;
Ball.x = paddle.right;
}
}

if(pKeyboard->IsKeyDown(P_LEFT))
Ballv.x += -1;
if(pKeyboard->IsKeyDown(P_RIGHT))
Ballv.x += 1;
}
else if(Level >= PADDLE_HEIGHT || Level >= PADDLE_WIDTH || ClipsToRect(Ball.x, Ball.y, &paddle))
{
// Clipping Scheme 2: Interception point based.

if(ClipsToBlockTop(&paddle, Ball.x, Ball.y, Ballp.x, Ballp.y))
{
Ballv.y = -Ballv.y;
Ball.y = paddle.top;
}
else if(ClipsToBlockBottom(&paddle, Ball.x, Ball.y, Ballp.x, Ballp.y))
{
Ballv.y = -Ballv.y;
Ball.y = paddle.bottom;
}
else if(ClipsToBlockLeft(&paddle, Ball.x, Ball.y, Ballp.x, Ballp.y))
{
Ballv.x = -Ballv.x;
Ball.x = paddle.left;
}
else if(ClipsToBlockRight(&paddle, Ball.x, Ball.y, Ballp.x, Ballp.y))
{
Ballv.x = -Ballv.x;
Ball.x = paddle.right;
}

if(pKeyboard->IsKeyDown(P_LEFT))
Ballv.x += -1;
if(pKeyboard->IsKeyDown(P_RIGHT))
Ballv.x += 1;
}
else
{
pIterator->MoveToFirst();
for(int i = 0; i < BLOCK_NUM; i++)
{
pBlock = (BLOCK*)pIterator->GetData();

if(pBlock->bDestroyed)
{
pIterator->MoveToNext();
continue;
}

block.top = pBlock->coords.y - BALL_RADIUS / 2;
block.left = pBlock->coords.x - BALL_RADIUS / 2;
block.bottom = pBlock->coords.y + BLOCK_HEIGHT + BALL_RADIUS / 2;
block.right = pBlock->coords.x + BLOCK_WIDTH + BALL_RADIUS / 2;

//1 if(ClipsToRect(Ball.x, Ball.y, &block))

{
if(ClipsToBlockTop(&block, Ball.x, Ball.y, Ballp.x, Ballp.y))
{
Ballv.y = -Ballv.y;
Ball.y = block.top;
}
else if(ClipsToBlockBottom(&block, Ball.x, Ball.y, Ballp.x, Ballp.y))
{
Ballv.y = -Ballv.y;
Ball.y = block.bottom;
}
else if(ClipsToBlockLeft(&block, Ball.x, Ball.y, Ballp.x, Ballp.y))
{
Ballv.x = -Ballv.x;
Ball.x = block.left;
}
else if(ClipsToBlockRight(&block, Ball.x, Ball.y, Ballp.x, Ballp.y))
{
Ballv.x = -Ballv.x;
Ball.x = block.right;
}
else
{
pIterator->MoveToNext();
continue;
}


PlayerScore += 50;
pBlock->bDestroyed = true;
BlockCount -= 1;
break;
}
pIterator->MoveToNext();
}
}

return false;
}

bool ClipsToBlockTop(RECT* pBlock, int x1Line, int y1Line, int x2Line, int y2Line)
{
DWORD InterFlag;
POINT temp;
RECT line;

line.top = ((y2Line < y1Line)? y2Line : y1Line);
line.left = ((x2Line < x1Line)? x2Line : x1Line);
line.bottom = ((y2Line > y1Line)? y2Line : y1Line);
line.right = ((x2Line > x1Line)? x2Line : x1Line);

// Find Intersection of Ball Segment with segment defining top of paddle

temp = FindIntersectionU(pBlock->left, pBlock->top, pBlock->right, pBlock->top, x1Line, y1Line, x2Line, y2Line, &InterFlag);

// Determine if the the intersection point is actualy contained in the segment

if(temp.x >= pBlock->left && temp.x <= pBlock->right && temp.y == pBlock->top && ClipsToRect(temp.x, temp.y, &line) && InterFlag != GD_DONT_INTERSECT)
return true;
else
return false;
}

bool ClipsToBlockBottom(RECT* pBlock, int x1Line, int y1Line, int x2Line, int y2Line)
{
DWORD InterFlag;
POINT temp;
RECT line;

line.top = ((y2Line < y1Line)? y2Line : y1Line);
line.left = ((x2Line < x1Line)? x2Line : x1Line);
line.bottom = ((y2Line > y1Line)? y2Line : y1Line);
line.right = ((x2Line > x1Line)? x2Line : x1Line);


// Find Intersection of Ball Segment with segment defining top of paddle

temp = FindIntersectionU(pBlock->left, pBlock->bottom, pBlock->right, pBlock->bottom, x1Line, y1Line, x2Line, y2Line, &InterFlag);

// Determine if the the intersection point is actualy contained in the segment

if(temp.x >= pBlock->left && temp.x <= pBlock->right && temp.y == pBlock->bottom && ClipsToRect(temp.x, temp.y, &line) && InterFlag != GD_DONT_INTERSECT)
return true;
else
return false;
}
bool ClipsToBlockLeft(RECT* pBlock, int x1Line, int y1Line, int x2Line, int y2Line)
{
DWORD InterFlag;
POINT temp;
RECT line;

line.top = ((y2Line < y1Line)? y2Line : y1Line);
line.left = ((x2Line < x1Line)? x2Line : x1Line);
line.bottom = ((y2Line > y1Line)? y2Line : y1Line);
line.right = ((x2Line > x1Line)? x2Line : x1Line);

// Find Intersection of Ball Segment with segment defining top of paddle

temp = FindIntersectionU(pBlock->left, pBlock->top, pBlock->left, pBlock->bottom, x1Line, y1Line, x2Line, y2Line, &InterFlag);

// Determine if the the intersection point is actualy contained in the segment

if(temp.y >= pBlock->top && temp.y <= pBlock->bottom && temp.x == pBlock->left && ClipsToRect(temp.x, temp.y, &line) && InterFlag != GD_DONT_INTERSECT)
return true;
else
return false;
}


bool ClipsToBlockRight(RECT* pBlock, int x1Line, int y1Line, int x2Line, int y2Line)
{
DWORD InterFlag;
POINT temp;
RECT line;

line.top = ((y2Line < y1Line)? y2Line : y1Line);
line.left = ((x2Line < x1Line)? x2Line : x1Line);
line.bottom = ((y2Line > y1Line)? y2Line : y1Line);
line.right = ((x2Line > x1Line)? x2Line : x1Line);

// Find Intersection of Ball Segment with segment defining top of paddle

temp = FindIntersectionU(pBlock->right, pBlock->top, pBlock->right, pBlock->bottom, x1Line, y1Line, x2Line, y2Line, &InterFlag);

// Determine if the the intersection point is actualy contained in the segment

if(temp.y >= pBlock->top && temp.y <= pBlock->bottom && temp.x == pBlock->right && ClipsToRect(temp.x, temp.y, &line) && InterFlag != GD_DONT_INTERSECT)
return true;
else
return false;
}


bool ClipsToRect(int x, int y, LPRECT pRect)
{
if((x >= pRect->left && x <= pRect->right) && (y >= pRect->top && y <= pRect->bottom))
return true;
else
return false;
}

There ya go if you want it. Really pretty simple, just a lot of white space and conditional''s.

About new version: You should probably use a point at the center of the ''ball'' for colision detection rather than the upper left hand corner. Did the clearing of the Z-buffer change the speed of the prgram THAT drastically? I get about 20 fps now on a P4 1.8 ghz with 128mb ram with 32mb GeForce2. If you speed up the game you can make the ball go faster without worrying about the visible artifacts of the ball positions being visibly disjointed through each sequential frame.

-Brent Robinson

Share this post


Link to post
Share on other sites
quote:
Original post by Matt Calabrese
Nope, same problem -- refer to the pic above.

I''m running Direct X 8.1 so that''s not the problem. I don''t know what could be wrong.

Try switching the dysplay mode to 32 BPP, tell me what you get. Now try fullscreen, NOW tell me what you get.



[ my engine ][ my game ][ my email ]
SPAM

Share this post


Link to post
Share on other sites