I think I've configured Box2d to have some sort of maximum velocity for any body, but I'm not sure. I apply an impulse like (100000000, 100000000), and the body moves just as fast as (100, 100) - which is not that fast at all.
I'm using the Box2d XNA C# port.
My game is a top-down 2d.
Here is some code that may be relevant:
private readonly Vector2 GRAVITY = new Vector2(0, 0);
public void initializePhysics(ContactReporter contactReporter)
{
world = new World(GRAVITY, true);
IContactListener contactListener = contactReporter;
world.ContactListener = contactListener;
}
public void Update(GameTime gameTime)
{
// ...
worldState.PhysicsWorld.Step((float)gameTime.ElapsedGameTime.TotalSeconds, 10, 10);
//...
}
Here is some example code that applies the impulse:
private void ApplyImpulseFromInput()
{
Vector2 movementImpulse = new Vector2();
if (inputReader.ControlActivation(ActionInputType.MOVE_LEFT) == 1f)
{
movementImpulse.X = -Constants.PLAYER_IMPULSE_CONSTANT;
} else if (inputReader.ControlActivation(ActionInputType.MOVE_RIGHT) == 1f)
{
movementImpulse.X = Constants.PLAYER_IMPULSE_CONSTANT; ;
}
if (inputReader.ControlActivation(ActionInputType.MOVE_UP) == 1f)
{
movementImpulse.Y = -Constants.PLAYER_IMPULSE_CONSTANT; ;
} else if (inputReader.ControlActivation(ActionInputType.MOVE_DOWN) == 1f)
{
movementImpulse.Y = Constants.PLAYER_IMPULSE_CONSTANT; ;
}
model.Body.ApplyImpulse(movementImpulse, model.Position);
}
If Constants.PLAYER_IMPULSE_CONSTANT is anywhere from 1000f to 1000000000f, the player can move at most (-120, -120) to (120, 120). If the constant is less, like 1f, the player will move more slowly.
This code is used to set up physics for everything in the game world:
controller.Model.BodyDef = new BodyDef();
controller.Model.BodyDef.type = controller.Model.Mobile ? BodyType.Dynamic : BodyType.Static;
controller.Model.Body = worldState.PhysicsWorld.CreateBody(controller.Model.BodyDef);
controller.Model.Body.SetLinearDamping(10.0f);
Could it possibly be the linear damping? I changed it from 10.0f to 0, with no effect.
UPDATE: Weirdness with linear damping: I have made these observations on the body that is moved with the apply impulse method above:
Linear Damping Max Speed
0f 120
10f 120
50f 120
55f 90
60f 0
70f 0
100f 0
100000f 0
Why is there a range of sensitivity in linear damping between 50f and 60f?
That's not the way to fix that problem. You are supposed to scale down your objects when creating them in the box2D world. Then you can just scale the information that box2D gives you back to the size of your world.
Let's say for example that a box in my world is 120 pixels long. If I scaled the object down by 30 times so that it can be simulated by box2d properly then the length of my box in the box2D world would be 4 "pixels" long (120 / 30 or size of your object / scale). Now, let's say that box2D calculates that my box moved 3 "pixels" in the box2d world. I could then grab that information and scale it back up to my world's size which would mean that the box just moved 90 pixels (3 * 30). I hope that didn't sound too confusing. I usually find it hard to explain myself.
I have the same problem with version 2.1a
i found out that changing line 128 in b2Settings.as can help.
Change static public const b2_maxTranslation:Number = 2.0 to a higher number.
sure that this isn't the right way, but right now dont really know how to do it correctly.
Related
I am trying to make a first-person game on Monogame and so far all I have come with or found on the internet didn't meet my standards.
this is how I am currently handling the mouse:
private void HandleMouse()
{
Vector2 mouseDifference;
mouseNow = Mouse.GetState();
if (mouseNow.X != mouseDefaultPos.X || mouseNow.Y != mouseDefaultPos.Y)
{
mouseDifference.X = mouseDefaultPos.X - mouseNow.X;
mouseDifference.Y = mouseDefaultPos.Y - mouseNow.Y;
leftrightRot += mouseSens * mouseDifference.X;
updownRot += mouseSens * mouseDifference.Y;
Mouse.SetPosition((int)mouseDefaultPos.X, (int)mouseDefaultPos.Y);
UpdateViewMatrix();
}
}
private void UpdateViewMatrix()
{
Matrix cameraRotation = Matrix.CreateRotationX(updownRot) * Matrix.CreateRotationY(leftrightRot);
Vector3 cameraOriginalTarget = new Vector3(0, 0, -1);
Vector3 cameraOriginalUpVector = new Vector3(0, 1, 0);
Vector3 cameraRotatedTarget = Vector3.Transform(cameraOriginalTarget, cameraRotation);
Vector3 cameraRotatedUpVector = Vector3.Transform(cameraOriginalUpVector, cameraRotation);
viewMatrix = Matrix.CreateLookAt(new Vector3(0,0,0), cameraRotatedTarget, cameraRotatedUpVector);
}
My problem is that while this solution works, it is extremely inconsistent when it comes to how far the camera should rotate.
for example, happens when I make circles with the mouse and see that sometimes the mouse randomly jumps more than expected.
My main assumptions inconsistencies in fps that cause the time between frames to change, thus affecting the distance the mouse can move within that time.
I don't know if this is the reason or if my assumption can even cause this, but I would like to find a way to get consistent mouse movement.
I can provide a video of the problem if needed.
Thank you in advance.
The mouse in Windows is updated 240 times per second. The game loop runs at 60 frames per second. The discrepancy can lead to large mouse deltas. The solution is to limit the change in the mouse delta:
Vector2 mouseDifference;
const float MAXDELTA = 6; // Set to the appropriate value.
mouseNow = Mouse.GetState();
if (mouseNow.X != mouseDefaultPos.X || mouseNow.Y != mouseDefaultPos.Y)
{
mouseDifference.X = Math.Min(MAXDELTA, mouseDefaultPos.X - mouseNow.X);
mouseDifference.Y = Math.Min(MAXDELTA, mouseDefaultPos.Y - mouseNow.Y);
leftrightRot += mouseSens * mouseDifference.X;
updownRot += mouseSens * mouseDifference.Y;
Mouse.SetPosition((int)mouseDefaultPos.X, (int)mouseDefaultPos.Y);
UpdateViewMatrix();
}
This is an old thread, but I figured I would share a solution. The solution that's worked for me to use the GameTime object to relate how much the player should rotate by. In other words, rotate by (delta * rotationSpeed * GameTime.ElapsedTime.TotalSeconds) so that each rotation is relative to how much time has passed since the last frame. This protects it against frame drops, which I've found has been the problem for me.
This question already has answers here:
Rotate GameObject over time
(2 answers)
Closed 5 years ago.
So I am trying to rotate an object on key press (if I press "a" rotate left by 90 degree, if I press "d" rotate right by 90 degree).
I can't make it to work, I have tried a few things but I ended up not solving the problem. As you will see in the next example I only figure out how to rotate TO 90 degree, not more or less, I actually want to rotate the object BY 90 degrees, from whichever degree was currently on. For example:
from 90 degree to 180 degree
from 23 degree to 113 degree and so on...
here is my code:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class ModuleBehaviour : MonoBehaviour {
public bool rotating = false;
private void Update()
{
if (rotating)
{
RotatePlatform();
}
}
private void RotatePlatform()
{
Vector3 target = new Vector3(0,0,90);
if (transform.eulerAngles.z > 90)
{
transform.rotation = Quaternion.Euler(target);
}
transform.Rotate(target * Time.deltaTime);
}
}
(Don't bother about the rotating variable, I am changing it in another script, it get's true whenever I press the "d" key. I only need to know how to rotate in the right direction, after that I will figure it out how to apply for left rotation)
Thank you;
This will do what you want:
private IEnumerator RotatePlatform(float dir) {
Vector3 target = new Vector3(0, 0, (transform.eulerAngles.z + dir + 360) % 360);
while(Mathf.Abs(transform.eulerAngles.z - target.z) >= Mathf.Abs(dir * Time.deltaTime * 2)) {
transform.Rotate(new Vector3(0,0,dir) * Time.deltaTime);
yield return null;
}
transform.eulerAngles = target;
rotating = false;
}
The key things to take away from this is that I encapsulated the "make it animate" code into a coroutine so that the object rotates to the desired direction from any starting rotation to any rotation in either direction. The reason this works is that the coroutine's local variables hold their state between iterations (the Unity scheduled task system will halt executing the code on a yield instruction and resume at a later time: in this case, null means it will resume on the next frame). This way we can store the starting rotation and target rotation without having to do anything crazy.
It does this by getting the current rotation, adding the rotation amount, then making that value lie within 0-360: transform.eulerAngles.z + dir + 360) % 360. transform.eulerAngles.z will already be [0,360], subtracting 90 from that would leave [-90,270], then by adding 360 we insure that the value will always be greater than 0 (without affecting the resulting angle), then % 360 effectively subtracts off any excess quantities of 360.
The Mathf.Abs(transform.eulerAngles.z - target.z) >= Mathf.Abs(dir * Time.deltaTime * 2) statement checks to see if the "distance we have yet to rotate" is "greater than the amount we're going to rotate by" with some buffer: we don't want to overshoot and have our "how far do we need to go" be 358 degrees!
The other important change was that we want to use new Vector3(0,0,dir) rather than target as our value to rotate by so that the speed remains constant.
The last 2 instructions make sure the rotation actually achieves the desired value and, of course, toggle back the bool tracking whether or not pressing keys does anything (we only want 1 instance of our coroutine).
Then here's the Update() method I used to control it:
private void Update() {
if(!rotating) {
if(Input.GetKeyDown(KeyCode.D)) {
rotating = true;
StartCoroutine(RotatePlatform(90));
}
if(Input.GetKeyDown(KeyCode.A)) {
rotating = true;
StartCoroutine(RotatePlatform(-90));
}
}
}
To rotate in the other direction, subtract 90.
void Update()
{
if (Input.GetKeyDown(KeyCode.D))
transform.Rotate(0, 0, transform.rotation.z + 90);
}
so I'm a bit new to C# with random math and I learned how to make a rifle, pistol, etc. But I want to learn how to make a shotgun with raycast, not with projectile. With raycast's I tired to do more then 1 raycast but didn't know how to make them random so now I'm just stuck with 1 raycast. I want to make a random spread when I shoot. Here is the script:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class ShotGun : MonoBehaviour {
private int pellets = 9;
private float spreadAngle = 10f;
private float damage = 10f;
private float range = 1000f;
private Camera fpsCam;
// Use this for initialization
void Start ()
{
}
// Update is called once per frame
void Update ()
{
if (Input.GetButtonDown("Fire1"))
{
ShotgunRay();
}
}
private void ShotgunRay()
{
RaycastHit hit;
if (Physics.Raycast(fpsCam.transform.position, fpsCam.transform.forward, out hit, range))
{
Health_Armor target = hit.transform.GetComponent<Health_Armor>();
if (target != null)
{
target.TakeDamage(damage);
}
}
}
}
Multiple shots:
int amountOfProjectiles = 8;
if (Input.GetButtonDown("Fire1"))
{
for(int i = 0; i < amountOfProjectiles; i++)
{
ShotgunRay();
}
}
For the Randomness:
using Random = UnityEngine.Random;
Vector3 direction = fpsCam.transform.forward; // your initial aim.
Vector3 spread = Vector3.zero;
spread+= fpsCam.transform.up * Random.Range(-1f, 1f); // add random up or down (because random can get negative too)
spread+= fpsCam.transform.right * Random.Range(-1f, 1f); // add random left or right
// Using random up and right values will lead to a square spray pattern. If we normalize this vector, we'll get the spread direction, but as a circle.
// Since the radius is always 1 then (after normalization), we need another random call.
direction += spread.normalized() * Random.Range(0f, 0.2f);
RaycastHit hit;
if (Physics.Raycast(fpsCam.transform.position, direction, out hit, range))
{
// etc...
To see your results, use Debug.DrawRay and DrawLine. We want to include the missed shots. (We draw for 1s, so it's easier to see)
if (Physics.Raycast(fpsCam.transform.position, direction, out hit, range))
{
Debug.DrawLine(fpsCam.transform.position, hit.point, Color.green, 1f);
}
else
{
Debug.DrawLine(fpsCam.transform.position, fpsCam.transform.position + direction * range, Color.red, 1f);
}
DrawLine draws (in case of hit) to the actual hitpoint in green. the missed shots get drawn in the length of range and in red.
Result:
Well this will be dependant on the gauge of the shotgun in question. I am going to suppose you have a 12 gauge shotgun, which normally has around 8 pellets. For this, you would need 8 separate raycasts, and 8 different "hit" objects. At approximately 25 yards, a standard 12 gauge shell will have spread roughly 40 inches in diameter, and its effective range (range before it slows down too much to hurt anything) is about 125 yards. This is not absolute, but it gives you a rough idea of what you're aiming for.
So, in pseudocode, I would create 8 raycasts, each with it's own respective "hit" object. All raycasts should have a length 114.3 units (unity uses meters as its unit of measurement, so 125 yards is 114.3 meters), then what you want to do is start every raycast at the center of the barrel and create a "random" rotation that would simulate a 40 inch (1.016 unity units) spread every 25 yards (or 22.86 unity units). You can achieve this by combining Random() with Quaternion.AngleAxis() until you get a good (realistic, but still very random) spread.
Also, I'd just like to point out. These values are based off of shooting a SLUG shell out of a rifled barrel. Using a rifled barrel with a slug gives the maximum amount of stopping power with a shotgun. So, you can consider these MAX values, with the MIN amount of weapon handling (as a slug can nearly blow your arm off). If, in your game, you want a plethora of shotguns and shells available for use, and you want the maximum level of realism, you will need to take into account if the current shell being shot is buckshot, birdshot, or a slug, and you also would need to take the type of barrel into account. Buck/birdshot may not be as effective at a farther range, but their handling is much improved.
I'm making a 3D game in unity where the object should move forward and backward as the android device moves/accelerates in the Z axes. ie. When the player moves the devise in the direction of the +ve Z axis, the object should move forward, and when the player moves the devise in the direction of the -ve Z axis, the object should move backward.
This game is a multiplayer game, and the players will move in a large football field.
My idea to do this is using the accelerometer to calculate the acceleration of the device, then integrate the data of acceleration to get the device speed in the Z axis. and use the speed to move the device.
Using this equation
V2=V1 + ΔA . ΔT
Where
V2 : final velocity.
V1 : initial velocity.
ΔA : difference between the initial and final acceleration.
ΔT : difference between the initial and final time.
At first I tried to use kinematic equations to calculate the final speed, but I realized then that it can be only used when acceleration is constant. So a friend of me who studies physics differentiated this equation for me to use it when acceleration is variable.
I know that there will be some error in calculating the accurate displacement, and that the error will increase after the integration of acceleration, but this small percentage of error is okay for my application; I thought at first in using GPS instead of accelerometer but I found that GPS accuracy will be less than the sensors.
I know also that the error will be incredibly high after some time, so I reset the values of acceleration and velocity every 10 seconds. I'm also using a low-pass filter to reduce the noise of the sensor.
public class scriptMove : MonoBehaviour
{
const float kFilteringFactor = 0.1f;
public Vector3 A1;
public Vector3 A2;
public Vector3 A2ramping; // for the low-pass filter
public Vector3 V1;
public Vector3 V2;
public int SpeedFactor=1000; //this factor is for increasing acceleration to move in unity world
void resetAll()
{
Input.gyro.enabled = true;
A2 = Vector3.zero;
V1 = Vector3.zero;
V2 = Vector3.zero;
A2ramping = Vector3.zero;
}
// Use this for initialization
void Start()
{
InvokeRepeating("resetAll", 0, 10);
}
//http://stackoverflow.com/a/1736623
Vector3 ramping(Vector3 A)
{
A2ramping = A * kFilteringFactor + A2ramping * (1.0f - kFilteringFactor);
return A - A2ramping;
}
void getAcceleration(float deltaTime)
{
Input.gyro.enabled = true;
A1 = A2;
A2 = ramping(Input.gyro.userAcceleration) * SpeedFactor;
V2 = V1 + (A2 - A1) * deltaTime;
V1 = V2;
}
//Update is called once per frame
void Update()
{
getAcceleration(Time.deltaTime);
float distance = -1f;
Vector3 newPos = transform.position;
transform.Translate(Vector3.forward * Time.deltaTime * V2.z * distance);
}
}
The problem:
My code doesn't work always as expected when I move with the device;
Sometimes when I move forward (in the +ve Z axis of the device) the object moves forward also, but sometimes it doesn't move at all.
Sometimes when I'm still in my position the object moves alone by itself.
Sometimes when I move forward and suddenly stop, the object does not stop.
My questions:
Are those strange behaviors because of the accuracy of the device, or is there something I'm missing in my code.
If I'm missing something in my code, What is it?
I searched a lot about methods to get the most accurate position of the device, and I found that I can integrate GPS with accelerometer, how can I do this with my code in unity?
I don't know if you still need it but if anyone in the future need I will post what I found:
When I first used the Unity accelerometer I was thinking that the output was simply the device's rotation, and in a way is, but more than that it give us the acceleration but in order to have this value your must filter the gravity then you have the value.
I created a plugin for Android and get the Android's Accelerometer and Linear Accelerometer, the standard accelerometer give us a similar value of Unity accelerometer, the main difference is that is raw, and unity give us some refined output, for example if your game is Landscape unity automatically inverts X and Y axis, while the Android raw information don't. And the Linear accelerometer that is a fusion of sensors including the standard accelerometer, the output is acceleration without the gravity but the speed is terrible, while both (Unity and Android) accelerometer are updated every frame, the Linear accelerometer was updated every 4 to 5 frames what is a terrible rate for user's experience.
But going for Android plugin was great because it gave the light how to solve my problem of removing gravity from Unity Accelerometer, as you can find here:
https://developer.android.com/reference/android/hardware/SensorEvent.html
Under Sensor.TYPE_ACCELEROMETER
If we tilt the device, Unity Accelerometer gives you a value, for example 6, and while you hold in that position this is the value, is not a wave, if you tilt back really fast or really slowly it will give the value from 6 to 0 (supposing you move back to zero), what I wanted and accomplished with the code I'm sharing below is, when you turn it does a wave, returns the acceleration and back to zero, so is a acceleration deceleration curve, if you turn it really slow the acceleration returned is almost zero, if you turn it fast the response reflects this speed. If this is the result you are looking for you just need to create this class:
using UnityEngine;
public class AccelerometerUtil
{
public float alpha = 0.8f;
public float[] gravity = new float[3];
public AccelerometerUtil()
{
Debug.Log("AccelerometerUtil Init");
Vector3 currentAcc = Input.acceleration;
gravity[0] = currentAcc.x;
gravity[1] = currentAcc.y;
gravity[2] = currentAcc.z;
}
public Vector3 LowPassFiltered()
{
/*
https://developer.android.com/reference/android/hardware/SensorEvent.html
gravity[0] = alpha * gravity[0] + (1 - alpha) * event.values[0];
gravity[1] = alpha * gravity[1] + (1 - alpha) * event.values[1];
gravity[2] = alpha * gravity[2] + (1 - alpha) * event.values[2];
linear_acceleration[0] = event.values[0] - gravity[0];
linear_acceleration[1] = event.values[1] - gravity[1];
linear_acceleration[2] = event.values[2] - gravity[2];
*/
Vector3 currentAcc = Input.acceleration;
gravity[0] = alpha * gravity[0] + (1 - alpha) * currentAcc.x;
gravity[1] = alpha * gravity[1] + (1 - alpha) * currentAcc.y;
gravity[2] = alpha * gravity[2] + (1 - alpha) * currentAcc.z;
Vector3 linearAcceleration =
new Vector3(currentAcc.x - gravity[0],
currentAcc.y - gravity[1],
currentAcc.z - gravity[2]);
return linearAcceleration;
}
}
Once you have this class, just create it into your MonoBehaviour:
using UnityEngine;
public class PendulumAccelerometer : MonoBehaviour
{
private AccelerometerUtil accelerometerUtil;
// Use this for initialization
void Start()
{
accelerometerUtil = new AccelerometerUtil();
}
// Update is called once per frame
void Update()
{
Vector3 currentInput = accelerometerUtil.LowPassFiltered();
//TODO: Create your logic with currentInput (Linear Acceleration)
}
}
Notice that the TODO on MonoBehaviour is to be implemented, is up to you create an algorithm how to handle this values, in my case I found really useful to create a Graphic output and analise my acceleration before write it.
Really hope it helps
The movement is based on acceleration, so it will be dependant on how quickly you rotate your device. This is also why the object does not stop when you do. Suddenly stopping your device is a lot of acceleration, which then gets added to the amount the object is translating, which causes it to move a much greater distance than you intend.
I think what may be easier for you is to use the attitude of the gyro rather than the userAcceleration. The attitude returns a quaternion of the rotation of the device.
https://docs.unity3d.com/ScriptReference/Gyroscope-attitude.html
(You'll have to do a bit of experimenting, because I don't know what (0,0,0,0) on the attitude is. It could mean the device is flat on a table, or that it is sideways being held in front of you, or it could simply be the orientation of the device when the app first starts, I don't know how Unity initialises it.)
Once you have that Quaternion, you should be able to adjust velocity directly based off of how far in either direction the user is rotating the device. So if they rotate +ve Z-axis, you move forwards, if they move more, it moves faster, if they move -ve Z-axis, it slows down or moves backwards.
Regarding the GPS coordinates, you need to use LocationService for that.
http://docs.unity3d.com/ScriptReference/LocationService.html
You'll need to start LocationServices, wait for them to initialise (this bit is important), and then you can query the different parts using LocationService.lastData
I am trying to do the same thing as you. It is not trivial to get device's linear acceleration using just one sensor. You will need to implement a solution using both the accelerometer and the gyroscope (sensor fusion). Google has an android specific solution which behaves differently according to how sophisticated your device is. It uses multiple sensors as well as low/high pass filters (see Android TYPE_LINEAR_ACCELERATION sensor - what does it show?).
Google's Tango tablet should have sensors to address such issues.
If you want to get accelerometer data in Unity, try:
public class scriptMove : MonoBehaviour{
private float accelX;
private float accelY;
private float accelZ;
void Update(){
accelX = Input.acceleration.x;
accelY = Input.acceleration.y;
accelZ = Input.acceleration.z;
//pass values to your UI
}
}
What I am currently trying is to port Google's solution to Unity using IKVM.
This link might be helpful too:
Unity3D - Get smooth speed and acceleration with GPS data
I have the model representing the player's ship gradually leaning when the player strafes. For instance, here's the code that leans the ship right:
In Update() of the Game class:
if (ship.rightTurnProgress < 1 && (currentKeyState.IsKeyDown(Keys.D)))
{
ship.rightTurnProgress += (float)gameTime.ElapsedGameTime.TotalSeconds * 30;
}
In Update() of the Ship class:
if (currentKeyState.IsKeyDown(Keys.D))
{
Velocity += Vector3.Right * VelocityScale * 10.0f;
RotationMatrix = Matrix.CreateRotationX(MathHelper.PiOver2) *
Matrix.CreateRotationY(0.4f * rightTurnProgress);
}
This is what I'm attempting to do to make it ease back out of the lean when it stops strafing:
In Update() of the Game class:
if (ship.rightTurnProgress > 0 && currentKeyState.IsKeyUp(Keys.D))
{
ship.rightTurnProgress -= (float)gameTime.ElapsedGameTime.TotalSeconds * 30;
}
In Update() of the Ship class:
if (currentKeyState.IsKeyUp(Keys.D) && rightTurnProgress > 0)
{
RotationMatrix = Matrix.CreateRotationX(MathHelper.PiOver2) *
Matrix.CreateRotationY(-0.4f * rightTurnProgress);
}
Since easing into the lean works no problem, I thought easing out of the lean would be a simple matter of reversing the process. However, it tends to not go all the way back to the default position after a long strafe. If you tap the key, it snaps all the way back to the full lean of the -opposite- direction. This isn't what I expected at all. What am I missing here?
I suggest you represent the rotation of you ship as a quaternion. That way you can use an interpolation function such as slerp. Simply have a second quaternion that represents you targeted lean angle and the ship will smoothly rotate until it achieves the targeted angle.
Here's a good tutorial on quaternions. If you want to avoid quaternions use MathHelper.Lerp to smoothly transition from the current value to the target.
if (currentKeyState.IsKeyDown(Keys.D))
{
ship.TurnProgress = MathHelper.Lerp(ship.TurnProgress, 1, somefloat * timeDelta);
}
else if (currentKeyState.IsKeyDown(Keys.a))
{
ship.TurnProgress = MathHelper.Lerp(ship.TurnProgress, -1, somefloat * timeDelta);
}
else (currentKeyState.IsKeyDown(Keys.D))
{
ship.TurnProgress = MathHelper.Lerp(ship.TurnProgress, 0, somefloat * timeDelta);
}
Edit: Also there is a GameDev stack overflow so check it out if you have more questions.
Unless you know how long the turn is or you have some kind of acceleration vector you will have to wait until the turn is stopped before returning the sprite angle to neutral, then what happens when the player turns left before the sprite has reached its neutral position? I assume that when you turn right using RightTurnProgress you also have a LeftTurnProgress I suggest you combine them into one variable to keep it smooth and avoid the snapping effect you are getting.
You are creating an 'absolute' rotation matrix so you don't need to flip the sign to -0.4f. Why not just have a variable called ship.lean and calculate the rotation matrix every update. Then you just need logic to ease ship.lean between -1 (left lean) and 1 (right lean) or 0 for no lean.