Weird Issue Quaternion Rotation in XNA Space Simulator - c#

I have spent 8 hours trying to find a solution.
So here is my problem. My ship is rotating like it's rotating around something, like a string. When I go farther and farther from the starting position, I start rotating more weirder and weirder. Like I am attached to a string.
Here is the code for Rotation and Movement.
public void MoveShip(List<InputAction> InputActionList, GameTime gameTime)
{
float second = (float)gameTime.ElapsedGameTime.TotalSeconds;
float currentTurningSpeed = second * TurningSpeed;
float leftRightRotation = 0;
float upDownRotation = 0;
float linearLeftRightRotation = 0;
foreach(InputAction action in InputActionList)
{
switch(action)
{
case InputAction.Left:
leftRightRotation -= currentTurningSpeed;
break;
case InputAction.Right:
leftRightRotation += currentTurningSpeed;
break;
case InputAction.Up:
upDownRotation += currentTurningSpeed;
break;
case InputAction.Down:
upDownRotation -= currentTurningSpeed;
break;
case InputAction.IncreaseSpeed:
if (ShipSpeed < MaxShipSpeed)
ShipSpeed += Acceleration;
break;
case InputAction.DecreaseSpeed:
if (ShipSpeed > MinShipSpeed)
ShipSpeed -= Acceleration;
break;
case InputAction.LinearLeft:
linearLeftRightRotation += currentTurningSpeed;
break;
case InputAction.LinearRight:
linearLeftRightRotation -= currentTurningSpeed;
break;
case InputAction.Fire1:
WeaponSystem2D.RequestFire(ShipPosition, ShipRotation);
break;
}
}
Quaternion currentRotation = Quaternion.CreateFromAxisAngle(new Vector3(0, 0, 1), leftRightRotation) *
Quaternion.CreateFromAxisAngle(new Vector3(1, 0, 0), upDownRotation) *
Quaternion.CreateFromAxisAngle(new Vector3(0, 1, 0), linearLeftRightRotation);
currentRotation.Normalize();
ShipRotation *= currentRotation;
ShipPosition *= Vector3.Transform(new Vector3(0, 0, 1), ShipRotation) * (ShipSpeed * second);
ShipWorld = Matrix.CreateFromQuaternion(ShipRotation) * Matrix.CreateTranslation(ShipPosition);
}
What is the problem? Why is it doing this? I want the ship to rotate on a dime, since it is space.
EDIT:
-The model is not an issue.
EDIT 2: Nevermind, the rotation was actually working, it was my skybox that was broken!

This code is actually perfect, my skybox made it look like it was broken.

Related

How to make object point and shoot another object?

asd.peeneje
Hello friends! I'm developing a game 2d platformer in #Unity, I need to make this object on the right side look at the other object on the left side and shoot in his direction. I don't know to do this. Can you help me in this? :D
I'm maked multiple attempts and I haven't made it. I try with this
if(isPointer) {
targetRotation = pointer.transform.position - transform.position;
angle = Mathf.Atan2(targetRotation.y, targetRotation.x) * Mathf.Rad2Deg;
gun.rotation = Quaternion.Euler(new Vector3(0,0, angle));
break;
}
void Shoot () {
if(shootTimer <= 0f) {
var Ball = Instantiate(ball, gun.position, transform.rotation, transform.parent);
var forward = transform.rotation * Vector3.forward;
targetRotation.z = 0;
if(isPointer) {
finalTarget = (forward.z * -transform.position).normalized;
break;
}
Ball.GetComponent<Rigidbody2D>().AddForce(finalTarget * speedBall, ForceMode2D.Impulse);
player.GetComponent<PlayerController>().ShootAni();
switch(weaponLoot1) {
case WeaponLoot1.glack:
shootTimer = 0.2f;
break;
case WeaponLoot1.silenced:
shootTimer = 0.2f;
break;
case WeaponLoot1.revolver:
shootTimer = 0.5f;
break;
case WeaponLoot1.shotgun:
shootTimer = 0.55f;
break;
case WeaponLoot1.mac10:
shootTimer = 0.15f;
break;
case WeaponLoot1.tommy:
shootTimer = 0.2f;
break;
case WeaponLoot1.ak47:
shootTimer = 0.2f;
break;
case WeaponLoot1.m4a1:
shootTimer = 0.2f;
break;
case WeaponLoot1.rifle:
shootTimer = 0.6f;
break;
case WeaponLoot1.bazooka:
shootTimer = 0.75f;
break;
}
}
}
You can use Quaternion.LookRotation
So you'll have
gun.rotation = Quaternion.LookRotation(pointer.transform.position - transform.position);

Why is my GetKeyUp not being detected in c#?

basically i am trying to move a character around so when i press W it goes forward but when i let go it doesn't stop(only once in a while). I am on Update void and not fixed Update.
private void Update()
{
if (controller.isGrounded)
{
if(Input.GetKey(KeyCode.W))
{
anim.SetInteger("condition", 1);
moveDir = new Vector3(0, 0, 1);
moveDir *= speed;
moveDir = transform.TransformDirection(moveDir);
}
if(Input.GetKeyUp (KeyCode.W))
{
anim.SetInteger("condition", 0);
moveDir = new Vector3(0, 0, 0);
}
}
rot += Input.GetAxis("Horizontal") * rotSpeed * Time.deltaTime;
transform.eulerAngles = new Vector3(0, rot, 0);
moveDir.y -= gravity * Time.deltaTime;
controller.Move (moveDir * Time.deltaTime);
}
}
Try looking at your animator and checking that Apply Root Motion is checked off.
Animator in Inspector
What root motion does is that it moves your character through the animation instead of through code. Here is a detailed explanation on root motion. What's root motion and how it works
I think I was able to recreate your issue and I was getting the same results. After I unchecked Apply Root Motion, my character stopped once I let go of "W".

When a user stops rotating the ship, how do I get it to smoothly rotate back?

So the question may not be clear, but the ship rotates with arrow keys perfectly, but when the arrow keys are released I want it to rotate back to the position (0, yRotation, 0) but in a smooth motion (the same motion for which the user rotates it in the first place), any idea how I can do this?
xRotation, yRotation and zRotation are all initialised to 0.
float xThrow = CrossPlatformInputManager.GetAxis("Horizontal");
if(xThrow > 0) {
transform.rotation = Quaternion.Euler(xRotation, yRotation + 0.6f, zRotation - 0.6f);
yRotation += 0.6f;
zRotation -= 0.6f;
}
else if (xThrow < 0)
{
transform.rotation = Quaternion.Euler(xRotation, yRotation - 0.6f, zRotation + 0.6f);
yRotation -= 0.6f;
zRotation += 0.6f;
}
else {
transform.rotation = Quaternion.Euler(0f, yRotation, zRotation);
while (zRotation > 0) {
zRotation -= 0.6f;
}
while (zRotation < 0) {
zRotation += 0.6f;
}
}
The code I have written takes it back to the required rotation position however it is not smooth at all and does it as a single frame. I want to achieve this, but in a very smooth motion instead of a single frame looking one.
Assuming you want to reset the rotation in the else block you should use a Coroutine. Attention since I also guess you are using this in an Update method be careful to not start multiple routines.
// set this in the Inspector
public float resetDuration;
// make sure there is only one routine running at once
private bool isResetting;
// ...
else
{
// if no routine is running so far start one
if(!isResetting) StartCoroutine(RotateToIdentity());
}
// ...
private IEnumerator RotateToIdentity()
{
isResetting = true;
// I recommend using this for rotations and not do them by manipulating
// 3 float values. Otherwise could also Lerp all three float values and use them for the rotation here as well
var currentRot = transform.localRotation;
var targetRot = Quaternion.Identity;
// than use those
// var currentX = xRotation;
// var currentY = yRotation;
// var currentZ = zRotation;
var timePassed = 0.0f;
while(timePassed <= resetDuration)
{
// interpolate between the original rotation and the target
// using timePassed / resetDuration as factor => a value between 0 and 1
transform.rotation = Quaternion.Lerp(currentRot, targetRot, timePassed / resetDuration);
// or with your rotations
// xRotation = Mathf.Lerp(currentX, 0, timePassed / resetDuration);
// yRotation = Mathf.Lerp(currentY, 0, timePassed / resetDuration);
// zRotation = Mathf.Lerp(currentZ, 0, timePassed / resetDuration);
// transform.rotation = Quaternion.Euler(xRotation, yRotation, zRotation);
// add passed time since last frame
timePassed += Time.deltaTtime;
// return to the mein thread, render the frame and go on in the next frame
yield return null;
}
// finally apply the target rotation just to be sure to avoid over/under shooting
transform.rotation = targetRot;
// if you really want to go on using xRotation, yRotation and zRotation also reset them when done
xRotation = 0;
yRotation = 0;
zRotation = 0;
isResetting = false;
}
You should also really consider using Time.deltaTime for all your rotations.
The one advantage of using the 3 individual lerps: as soon as the user interacts again he could interupt the reset routine
if(xThrow > 0)
{
StopAllCoroutines();
isResetting = false;
// ...
}
else if (xThrow < 0)
{
StopAllCoroutines();
isResetting = false;
// ...
}
// ---

C# procedural generation- how to do always a set number?

Ok, Working in Unity here and trying to get out this core game dynamic. Basically I have all these 3D platforms that have certain weights to them (weight meaning how often they appear in the array from which game can select next platform) -
right now each platform has a set of the 4 cardinal directions (plus up/down but all have those) where it can spawn the next platform for player to walk onto, else they fall. This is an enum and I set this manually.
Before player first steps on a platform, it is halfway alpha, so it just looks like a marker. After they step, it turns 1 alpha and thus doesn't look like a "marker", see here:
As the player walks via joystick, I want the platforms to spawn in square "tiers" - say of length 10 platforms - and I'll do something when tier is full. My problem is I've tried a bunch of different systems but do not know how to implement this. Model picture where there are different configurations but ultimately a 10x10 limit/bounds:
Here's my method of spawning based on direction - problem is direction is subjective, based on player object's point of view:
foreach(Direction d in directionsAvailable)
{
Vector3 pos = transform.position;
float dist = container.GetComponent<Renderer> ().bounds.size.x;
switch (d) {
case Direction.Backward:
pos = new Vector3 (pos.x, pos.y, pos.z-dist);
break;
case Direction.Forward:
pos = new Vector3 (pos.x, pos.y, pos.z+dist);
break;
case Direction.Left:
pos = new Vector3 (pos.x-dist, pos.y, pos.z);
break;
case Direction.Right:
pos = new Vector3 (pos.x+dist, pos.y, pos.z);
break;
case Direction.Down:
pos = new Vector3 (pos.x, pos.y-(2*dist), pos.z);
break;
case Direction.Up:
pos = new Vector3 (pos.x, pos.y+(2*dist), pos.z); //hits itself, might have to do more dist
break;
default:
break;
}
Here is how I test if a platform is at a position or position is open:
public Platform PlatAtPos(Vector3 pos)
{
platformsSpawned = GameObject.FindObjectsOfType<Platform>();
foreach(Platform p in platformsSpawned)
{
if(p.originPos == pos || p.transform.position == pos) //or just delete one of them
{
return p;
}
}
return null;
}
public void checkForPlatsAround()
{
gameController = GameObject.FindObjectOfType<GameController> ();
float dist = container.GetComponent<Renderer> ().bounds.size.x;
foreach (Platform.Direction dir in Enum.GetValues(typeof(Platform.Direction))) {
Vector3 pos = transform.position;
switch (dir) {
case Direction.Backward:
pos = new Vector3 (pos.x, pos.y, pos.z-dist);
break;
case Direction.Forward:
pos = new Vector3 (pos.x, pos.y, pos.z+dist);
break;
case Direction.Left:
pos = new Vector3 (pos.x-dist, pos.y, pos.z);
break;
case Direction.Right:
pos = new Vector3 (pos.x+dist, pos.y, pos.z);
break;
case Direction.Down:
pos = new Vector3 (pos.x, pos.y-(2*dist), pos.z);
break;
case Direction.Up:
pos = new Vector3 (pos.x, pos.y+(2*dist), pos.z); //hits itself, might have to do more dist
break;
default:
break;
}
if(gameController.PlatAtPos(pos) != null)
{
gameController.PlatAtPos (pos).showAsMarker ();
}
}
}
Is there a better/clearer way to go about this? How can I do this procedurally?

Get random direction for object to move within a maze

I am trying to get a few gameobject to randomly walk around a maze. I currently have it working properly, where the objects can go left/right/forward. The issue I am having is when the have the opportunity to go forward and left/right the always choose to turn left or right, they never choose to go forward, and I can not figure out why... What am I missing here?
public float speed;
public bool changed = false;
public bool forward, left, right;
protected Transform frontRaycast, leftRaycast, rightRaycast;
void Update(){
if(!changed){
forward = Physics2D.Linecast(transform.position, frontRaycast.position, 1 << LayerMask.NameToLayer("Wall"));
left = Physics2D.Linecast(transform.position, leftRaycast.position, 1 << LayerMask.NameToLayer("Wall"));
right = Physics2D.Linecast(transform.position, rightRaycast.position, 1 << LayerMask.NameToLayer("Wall"));
List<int> possibleDirs = new List<int>();
if(!forward){
possibleDirs.Add(0);
}
if(!left){
possibleDirs.Add(1);
}
if(!right){
possibleDirs.Add(2);
}
int dir = 0;
//Debug.Log(Random.Range(0, possibleDirs.Count));
if(possibleDirs.Count > 0){
dir = (int)possibleDirs[Random.Range(0, possibleDirs.Count)];
}
Debug.Log(dir);
switch(dir){
case 0:
transform.Rotate(new Vector3(0,0,0));
break;
case 1:
transform.Rotate(new Vector3(0,0,90));
changed = true;
Invoke("reset", 0.5f);
break;
case 2:
transform.Rotate(new Vector3(0,0,-90));
changed = true;
Invoke("reset", 0.5f);
break;
}
}
transform.Translate(Vector2.right * Time.deltaTime * speed);
}
void reset(){
changed = false;
}

Categories

Resources