PDA

View Full Version : Asteroids Game, need help moving ship



Krovlar
6th April 2012, 16:11
Hello all,

I have a school group project to create an Asteroids game. We've managed to get most of the game going by following tutorials and messing with the code. Sadly however most of my group has given up at this point as we can't figure out a few fundamental problems. As such I was wondering if you fine people could help me with the main problem, moving the ship. I have a theory, but I'm not sure of the math behind it.

My theory:
I draw the ship, which is a polygon triangle, inside a QRect. The ship already turns using the left and right arrows keys, and it changes a parameter called angle. If I can find a mathematical equation to change the center coordinates of the QRect, based on the current angle, then it should work just fine.

I'll have to figure out exactly how to do that, like for every second of holding down the up arrow the ship would move ____ distance or something, but this should at least get the ship moving around the screen.

I can't include the full code in here, at it's several files and is kind of long, so I've just included the file that I feel is most important. The rest of the program, ready to run, is in the zip file linked at the bottom of the post. Please if you have a chance help, this is due Monday and I don't think we're going to make it. Thank you.




//Sets the angle of the ship
void CannonField::setAngle(int angle)
{
if (currentAngle == angle)
return;
currentAngle = angle;
update(cannonRect());
emit angleChanged(currentAngle);
}

void CannonField::paintEvent(QPaintEvent * /* event */)
{
QPainter painter(this);

if (gameEnded) {
painter.setPen(Qt::black);
painter.setFont(QFont("Courier", 48, QFont::Bold));
painter.drawText(rect(), Qt::AlignCenter, tr("Game Over"));
}
paintCannon(painter);
if (isShooting())
paintShot(painter);
if (!gameEnded)
paintTarget(painter);
}

void CannonField::paintCannon(QPainter &painter)
{
//setPen determines if there is an outline I believe.
painter.setPen(Qt::NoPen);
//setBrush determines color.
painter.setBrush(Qt::blue);


painter.save();
//Translate the coordinates to that the center of the play
//field is (0, 0)
painter.translate(width()/2, height()/2);
//Rotates the ship
painter.rotate(-currentAngle);
//creates the dimensions for Polygon
QPolygon polygon;
polygon << QPoint(-10, 0) << QPoint(10, 0) << QPoint(0, -20);
//draws the ship
painter.drawPolygon(polygon);
painter.restore();
}

QRect CannonField::cannonRect() const
{
//cannonRect should be around the ship, as a
//sort of hit box and way to move the ship.
QRect result(0, 0, 500, 500);
//we should use something like this to move the box
//and our ship would automatically move with it, since
//it would always paint inside the box
result.moveBottomLeft(rect().bottomLeft());
return result;
}

QRect CannonField::targetRect() const
{
//QRect is set up for the target/asteroid, and it starts at the bottom
//left corner, and is 20 wide and 10 high.
QRect result(0, 0, 20, 10);
//It is moved from it's center by a certain amount.
result.moveCenter(QPoint(target.x(), height() - 1 - target.y()));
return result;
}

Link to the rar file containing my QT4 project ready to compile and run. Thank you again for any help you can offer.
http://www.box.com/s/4898353af9c9e12e9fd0

wayfaerer
6th April 2012, 18:04
Looks like a good opportunity to bust out some high school geometry.

http://en.wikipedia.org/wiki/Trigonometric_functions

Pretty sure it would be:

sin(angle) = yAmount / distance
(solve for yAmount)

cos(angle) = xAmount / distance
(solve for xAmount)

xAmount and yAmount will give you the coordinate you need in order to go the given distance at the given angle.

ChrisW67
6th April 2012, 23:16
In your existing code your angles would appear to be in degrees. For the C++ trigonometry functions (actually for most programming languages) the angles need to be expressed in radians (http://en.wikipedia.org/wiki/Radian). Bear that in mind when following wayfaerer's lead.

Krovlar
7th April 2012, 01:58
First of all, thank you both VERY much. I just got off a LONG day of work and I can't get my eyes to focus, let alone think enough to implement that. I'll see if I can get it working tomorrow morning, but the theory is solid. Thank you both so much.

One more quick (I hope) question, how would I go about painting specifically INSIDE a QRect? That way I can just move the QRect and the painted item will automatically work with it. Thanks again.
Billy

ChrisW67
7th April 2012, 07:04
You have defined a fixed size for the triangular shape of the cannon. As you rotate this cannon it will extend over different ranges of x and y coordinates. Assuming you are rotating about (0,0)... at zero rotation the x ranges from -10 to 10 and y from -20 to 0. Rotate clockwise by 90 degrees then the bounds are x -20 to 0 and y -10 to 10. You could work out a single rectangle large enough to hold the triangle no matter what orientation it is in but this will be larger than it needs to be much of the time. So, the question really is, "How do I determine the smallest bounding rectangle for the cannon at a certain rotation?" If you rotate the three vertices by n degrees then find the minimum and maximum in the x and y direction you have your bounding box.

If you made the cannon an triangle with vertices at points around a circle of radius r centered on 0,0 then then "fits any rotation" box would be QRect(-r, -r, 2*r, 2*r) and rotation around (0,0) would probably seem more natural.

There may be an easier way to draw and manage this using Qt's QGraphicsView: Ported Asteroids Example. I do not know whether you are permitted to use this method.

Krovlar
7th April 2012, 18:25
Ok, I've got it fitting inside the box no matter how it rotates, but I can't get it to paint INSIDE the box. What I mean by this is, perhaps the bottom left of the box is at (20,20) and I want to paint the polygon inside the box like so:

QPolygon polygon;
polygon << QPoint(0,0) << QPoint(20, 0) << QPoint(10, 20);
painter.drawPolygon(polygon);

so that no matter where I move the QRect, say the bottom left is not at (30,5) my polygon will still be painted correctly inside the QRect, not at the bottom left corner of the entire screen.
Thank you again for any help.

ChrisW67
9th April 2012, 01:13
You have a polygon that draws correctly with respect to an origin. If you translate the painter the triangle can be drawn at an arbitrary location without changing the polygon definition (with some thought this can do rotation for you also but you will learn more if you do it yourself). Wrap translating and drawing the polygon in save() and restore() calls and the translation will not have any effect on other painting.

The usual reason for wanting a bounding box is not drawing but collision (or overlap) detection.