2
\$\begingroup\$

I'm making a 2d space game in Javascript with canvas. In this game there's a bunch of spaceships, positioned in world space, with turrets, positioned relative to their parent ships. These objects also have an orientation.

How do I efficiently calculate the position of a turret in world coordinates? (i.e. when it fires and I need to know where to place a bullet in the world)? Calculating the turrets orientation is trivial - I just add the turrets relative angle to its parents. For position though, I guess I could do a bunch of trigonometry but this MUST be a common problem with a good/fast general solution?

Should I be relearning how to do matrix math again? :)

Update:

Following the answers below I went away and read up on matrix math - to that end I can highly recommend "3D Math Primer for Graphics and Game Development" by Fletcher Dunn and Ian Parberry. The neat thing about matrices is you dont need to understand the maths involved in each transform, just how to use them.

As my project is in javascript I also needed a matrix library and went with gl-matrix.js as it is fast and has a clean (to my tastes) API. Sylvester.js is also very feature rich and worth a look, although not as fast as gl-matrix

\$\endgroup\$

2 Answers 2

1
\$\begingroup\$

Transform matrices is a common solution to this problem, yes, since you can concatenate rotation, translation and scaling into one matrix and then multiply the childs transform with its parent to get world coordinates.

You don't necessarily have to use actual matrices for this though, you could simply move the turrets center using its local coordinate compared to its parent, then rotate this point with the parents rotation to then finally add the parents coordinates.

This is what the matrix math would have done as well, in simple cases this would work just as well, but if you want to make a ship that can change shape (folding out wings, or such) you would wind up adding another step to this. Then perhaps having multiple cannon barrels and you would have to do another translation. After too many good ideas your positioning code will be unmaintainable, doing it with matrices would allow you greater flexibility without running into this particular problem.

\$\endgroup\$
1
  • \$\begingroup\$ Thanks, both answers told me what i needed to know but have accepted yours as you answered first. Cheers :) \$\endgroup\$
    – MrGreg
    Jun 26, 2012 at 22:15
0
\$\begingroup\$

I'm making a 2D top-down shooter too, so I faced the same problems you have. ;)

The first thing I did was separate the two positions an object can have: a world position and a render position. For example, the player ship determines the position of the camera. So its render position stays roughly the same, but the world position is relative to the root.

After each GameObject has determined its final position (after collisions and such), a matrix is created from the object's rotation and position:

m_TransformRender.SetRotation(m_DirectionMoving.GetAngle());
m_TransformRender.SetTranslation(m_Position);

This matrix is then passed to subsystems that require it, for instance the sprite drawing module and the particles module. The particles module is the interesting one, because it creates world positions for the particles. If it used relative coordinates, the effects would look really weird, because the particles would rotate with the ship. So the ParticleEmitter has a position that is relative to its root, which is in this case a ship.

For instance, the Enemy class creates the following ParticleEmitter's:

m_Particles->CreateEmitter("Exhaust", tb::Vec2(-16.f, -16.f), 512);
m_Particles->CreateEmitter("Exhaust", tb::Vec2( 16.f, -16.f), 512);

So it has two emitters, each at the back of the object.

Here's how a ParticleEmitter spawns a particle:

m_PropertyPosition[index] = m_Transform.Transform(m_Position);

And now you have a particle in world coordinates.

You can use this principle for your turrets: give your turret a relative offset to the ship and use a matrix to transform them to world coordinates. Note: your turret could have its own transformation matrix:

tb::Mat3x3 local_to_world = m_ParentShip->GetTransform() * m_TransformLocal;
\$\endgroup\$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .