0
\$\begingroup\$

I am making a simple space simulator, where the player can control a ship using 2 controls, one for pitch and one for bank. The ship is properly rotated but I cannot figure out how to make the ship move forward based on that angle. Here's what the code looks like right now:

func renderer(renderer: SCNSceneRenderer, updateAtTime time: NSTimeInterval) { let t=CGFloat(time - lastTime) ship!.transform = CATransform3DRotate(CATransform3DRotate(CATransform3DRotate(ship!.transform, ud*t, -1, 0, 0), 0.00, 0, 1, 0), lr*t, 0, 0, 1); ship!.position = ? } 

I tried every combination of vector, euler angles, matrices, quaternions that I could think of/read about with no success. I am probably missing something stupid but cannot find what it is.

The code is in Swift using Scenekit, but language doesn't matter that much to me and I can translate any algorithm. It's also worth noting it does not work like Unity and Quarternions/Vectors don't have properties like .forward() etc.

Thank you for your help!

\$\endgroup\$
5
  • \$\begingroup\$ Please avoid using variable names like t, ud, lr when you ask, this makes your code hard to understand. transform is misleading, because generally, a transform includes the rotation and the translation. Is your transform really a transform or is it a rotation only? \$\endgroup\$ Commented Jan 28, 2016 at 17:52
  • \$\begingroup\$ Scaling also included in transform :) \$\endgroup\$ Commented Jan 28, 2016 at 18:34
  • \$\begingroup\$ @AlexandreVaillancourt: Thanks for the tip, I was just prototyping so I forgot to name them properly before posting... \$\endgroup\$ Commented Jan 28, 2016 at 19:49
  • 1
    \$\begingroup\$ @HamzaHasan you're right, the scaling (and shearing) are also included in a transformation matrix, I forgot about that. \$\endgroup\$ Commented Jan 28, 2016 at 21:24
  • \$\begingroup\$ I have updated my answer, if you're still interested. In your situation, you just add a 3rd dimension. \$\endgroup\$ Commented Feb 3, 2016 at 2:22

2 Answers 2

1
\$\begingroup\$

You will need a forward vector which represent the forward direction of your ship, and the velocity of your ship.

// Stuff that you need (or already have) vec3 shipForwardVector; // This is according to your game infrastructure // and ship model; make it a unit vector. mat4 worldSpaceRotationMat; // assuming ship!.transform is only the rotation. float maxVeolicityPerSecond; // Your game settings float requestedVelocityRatio; // User request; from a keyboard, it's 0 or 1, // from a joystick, 0..1 // Computation vec3 rotatedForward = worldSpaceRotationMat * shipForwardVector; float requestedVelocity = maxVeolicityPerSecond * requestedVelocityRatio; // scale the movement according to the time that has passed vec3 displacementThisFrame = rotatedForward * (t * requestedVelocity) ship.position = ship.position + displacementThisFrame 

Based on Jon's comment, here is an addendum.

This is an implementation with the suggestion I have already made:

// Assuming the following: float mSideThrustersRadPerSec;// Used to compute how much a ship can turn per second Matrix mTransform; // Used to track the orientation of the ship Vector2 mFrontVector; // Used to determine where your ship model is pointing in its // local space float mRearThrustersKmPerSec; // How much are your thrusters able to push the ship Vector2 mPosition; // Position of the ship. if ( sf::Keyboard::isKeyPressed( sf::Keyboard::Left ) ) mTransform = mTransform.rotate( sfUtil::radiansToDegrees( -mSideThrustersRadPerSec * Global::GetInstance().getFrameTime() ) ); if ( sf::Keyboard::isKeyPressed( sf::Keyboard::Right ) ) mTransform = mTransform.rotate( sfUtil::radiansToDegrees( mSideThrustersRadPerSec * Global::GetInstance().getFrameTime() ) ); if ( sf::Keyboard::isKeyPressed( sf::Keyboard::Up ) ) { sf::Vector2f offset = mFrontVector * ( mRearThrustersKmPerSec * Global::GetInstance().getFrameTime() ); sf::Vector2f orientedOffset = mTransform * offset; mPosition = mPosition + orientedOffset; } 

Here is the result:

enter image description here

And this is based on if your ship has a velocity and no external resistance.

// Assuming the following: float mSideThrustersRadPerSec; // Used to compute how much a ship can turn per second Matrix mTransform; // Used to track the orientation of the ship Vector2 mFrontVector; // Used to determine where your ship model is pointing in // its local space float mRearThrustersKmPerSec; // How much are your thrusters able to push the ship float mFrontThrustersKmPerSec; // How much are your thrusters able to slow the ship (and // eventually make it go reverse) Vector2 mPosition; // Position of the ship. Vector2 mVelocity; // Speed and direction of the ship float mSpeedMax; // Maximum speed of the ship if ( sf::Keyboard::isKeyPressed( sf::Keyboard::Left ) ) mTransform = mTransform.rotate( sfUtil::radiansToDegrees( -mSideThrustersRadPerSec * Global::GetInstance().getFrameTime() ) ); if ( sf::Keyboard::isKeyPressed( sf::Keyboard::Right ) ) mTransform = mTransform.rotate( sfUtil::radiansToDegrees( mSideThrustersRadPerSec * Global::GetInstance().getFrameTime() ) ); bool shouldApplyOffset = false; sf::Vector2f offset; if ( sf::Keyboard::isKeyPressed( sf::Keyboard::Up ) && sf::Keyboard::isKeyPressed( sf::Keyboard::Down ) ) { offset = ( mFrontVector * ( mRearThrustersKmPerSec * Global::GetInstance().getFrameTime())) + ( -mFrontVector * ( mFrontThrustersKmPerSec * Global::GetInstance().getFrameTime())); shouldApplyOffset = true; } else if ( sf::Keyboard::isKeyPressed( sf::Keyboard::Up ) ) { offset = mFrontVector * (mRearThrustersKmPerSec * Global::GetInstance().getFrameTime()); shouldApplyOffset = true; } else if ( sf::Keyboard::isKeyPressed( sf::Keyboard::Down ) ) { offset = -mFrontVector * (mFrontThrustersKmPerSec * Global::GetInstance().getFrameTime()); shouldApplyOffset = true; } if ( shouldApplyOffset ) { sf::Vector2f orientedOffset = mTransform * offset; mVelocity += orientedOffset; float currentSpeed = sfUtil::lenght( mVelocity ); if ( currentSpeed > mSpeedMax ) { sf::Vector2f direction = mVelocity / currentSpeed; mVelocity = direction * mSpeedMax; } } mPosition = mPosition + mVelocity; 

With the result:

enter image description here

You can get the working VC2013 code here (it uses SFML).

\$\endgroup\$
6
  • \$\begingroup\$ What if the ship turns towards a direction that is not its current velocity? \$\endgroup\$ Commented Jan 28, 2016 at 18:11
  • \$\begingroup\$ @Jon that's a bit more complex you have to modify the velocity vector according to thrusters strength and use the velocity vector instead of the ships orientation (rotation) to change the position of the ship; I'll be able to expand on this later tonight. \$\endgroup\$ Commented Jan 28, 2016 at 18:16
  • \$\begingroup\$ Yeah I am just giving you a hard time. :P \$\endgroup\$ Commented Jan 28, 2016 at 18:32
  • \$\begingroup\$ @Jon I know :P Because I know that you know very well how to achieve this hehe :P \$\endgroup\$ Commented Jan 28, 2016 at 18:34
  • \$\begingroup\$ Thank you for the code! I see that you are multiplying a Matrix by a Vec3, which is I'm afraid impossible in the engine I'm using... I'll try to make it work and get back to you! \$\endgroup\$ Commented Jan 28, 2016 at 19:51
0
\$\begingroup\$

Well, I generally use to ask this questions in interviews :)

Although I don't know Swift but I can give you a general idea about to achieve this.

You have to play with some trigonometry to get current direction vector according to your current angle.

Here is the pseudo code.

float speed = 0.01 void GameLoop() { // I don't know that how Vector2 works at your end, but I hope you will get this. Vector2 currentPosition = currentPositionOfObject; float currentAngle = currentAngleOfObject; float directionX = Cos (currentAngle); // check if your Cos method takes angle in radians of degrees. float directionY = Sin (currentAngle); // check if your Sin method takes angle in radians of degrees. Vector2 newPosition = (currentPosition.x + (directionX * speed),currentPosition.y + (directionY * speed)); currentPositionOfObject = newPosition; } 

I have already answered the same question but in Unity (C#) here. Just for reference if you want more details.

\$\endgroup\$
3
  • \$\begingroup\$ Thank you for the tip! It works great, but sadly I need it in 3D... My fault for not being precise about it... Sorry! \$\endgroup\$ Commented Jan 28, 2016 at 19:52
  • \$\begingroup\$ oww.. Would your object move in open space (ant-where) or x-z plane? \$\endgroup\$ Commented Jan 28, 2016 at 20:11
  • \$\begingroup\$ Then I will turn my gun in that direction :) \$\endgroup\$ Commented Jan 28, 2016 at 20:21

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.