so the thing is: i have a sensor that makes a rigidbody rotate, the problem is that i can't calculate the speed in which it was rotated (If the sensor was moved fast the object would also move fast but when it collides with another gameobject it won't apply the speed/force which with it has been rotated)
Is there any way I can calculate the speed/force in which it has recently rotated so that i can apply that speed/force to another object when it collides?
note: im not entirely sure if what i need is speed or force
float rot = float.Parse (sp.ReadLine());
transform.eulerAngles = new Vector3 (0, 90, rot);
note: because of how the object was designed it has to be rotated by default in 90 degrees. Basically what im doing is receiving information from a Gyroscope and puting it in the object rotation.
The sensor gives values from -90 to 90 in the form of Float, when it is rotated to the left it gives values from -90 to 0, when rotated to the right it gives values from 0 to 90. this values should be used to graphically rotate the object and also aply the speed in which it was rotated when it collides whith another gameobject (if it was moved fast from -90 to -20 for example it should apply more force than if it was moved slowly from -90 to -50 to -20)
When trying to cause believable physical interaction between objects, you never want to manipulate the transform directly. Instead, you should be making use of the various methods available to physically influence an attached Rigidbody.
To apply rotation in this case, you're going to want to use Rigidbody.AddTorque(). Here's an idea of how you might use it:
// Probably get this value in Start() and save it for later
Rigidbody rb = GetComponent<Rigidbody>();
float rot = float.Parse (sp.ReadLine());
// transform.forward is the unit vector corresponding to the local z-axis of the object
Vector3 rotationAxis = transform.forward * rot;
rb.AddTorque(rotationAxis);
Hope this helps! Let me know if you have any questions.
Related
I have a laser turret in Unity3D, which I'd like to turn towards the enemies. The turret consists of a "leg" and a "head" (selected on the picture 1). The head can pan and tilt around a spherical joint.
I do the following:
Vector3 targetDir = collision.gameObject.transform.position - turretHead.transform.position;
float step = turnSpeed * Time.deltaTime;
Vector3 newDir = Vector3.RotateTowards(turretHead.transform.forward, targetDir, step, 0.0f);
turretHead.transform.rotation = Quaternion.LookRotation(newDir);
The problem is that since the pivot of the head is not aligned with the laser beam, the turret turns into the almost right direction, but it shoots above the target. (It would hit perfectly, if the laser would come out of the red axis of the pivot.)
Is there a builtin method or some trick to achieve the correct functionality other then doing the calculation myself?
Okay, here's the quick and easy way to do this. It's probably "better" to do it with proper trig, but this should give you the result you want pretty quick:
If you don't already have a transform aligned with the barrel, then create an empty GameObject and line it up (make sure it's a child of the turret so they move together). Add a reference to your script for it's transform.
Then, in your first line, calculate from the new Barrel transform instead of the turretHead transform. Leave everything else the same. This way it calculates from the turret barrel, but moves the turret head.
Now, this approach isn't perfect. If the pivot center is too offset from the barrel transform, then it would be less accurate over large moves, or when aiming at something close by, because the expected position when aiming would be different than the initial position due to the rotation pivot being elsewhere. But this can be solved with iteration, as the calculation would become more accurate the closer it is to it's desired goal.
The code that rotate the turret is kind simple:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Rotateturret : MonoBehaviour
{
public Transform target;
public Transform partToRotate;
public float turnSpeed = 10f;
private void Update()
{
transform.LookAt(target);
}
}
The target in this case is rotatingaround the turret in fixed speed but changing the height randomly.
If this script RotateTurret if I attach it to the Turret child part it will rotate and will look at the target. Like doing LookAt.
This is a screenshot of the Turret part:
And if I attach the script to the Pylon part it will rotate slowly and will always stay behind the target it will not rotate fast enough.
Screenshot of the Pylon part:
My problems are: What part of the turret should I rotate ? The logic say the Pylon I think.
Second is how should I calculate the speed the turret should rotate ? Does it always should facing perfect to the target ? Or sometimes if the target is moving in random speeds the turret will not facing it all the time 100% ? What is the logic in this case ? Just using LookAt is not enough. And I'm not using physics yet that's another problem I guess. If both turret and target will use physics but for now not sure how to do the turret logic (Or should I call it AI).
For testing I tried this script too:
public class Rotateturret : MonoBehaviour
{
public Transform target;
public Transform partToRotate;
public float turnSpeed = 10f;
private void Update()
{
Debug.DrawRay(transform.position, transform.forward, Color.green, 1000);
Vector3 dir = target.position - transform.position;
Quaternion lookRotation = Quaternion.LookRotation(dir);
Vector3 rotation = Quaternion.Lerp(partToRotate.rotation, lookRotation, Time.deltaTime * turnSpeed).eulerAngles;
partToRotate.rotation = Quaternion.Euler(0f, rotation.y, 0f);
}
}
And again if I will rotate the Turret it will be more accurate but if the pylon it will be behind the target. And who said the speed of the rotating of the turret should be 10 and 20 or 50 or 1 ? There is no much logic in this script either I guess.
Another thing is that in the future I will want also to rotate the Gun to shoot bullets. So the rate fire and when to start firing that's another problem maybe that will be another question, But I guess the firing shooting bullets is also relevant to the turret rotating logic.
Firstly, note that from your screenshot, the Pylon gameobject's forward direction (blue arrow) is perpendicular to the turret barrel's direction. Thus, attaching your script on that gameobject will not produce your desired behaviour.
When it comes to the implementation of a turret's movement, it depends greatly on the context of your game.
For example, if the turret is to be used in a Tower Defence game where it should never miss, then typically the turret's rotation and shooting animation should just be an effect. Your actual damage dealing to the target will be done via script directly (e.g searching for viable target in range and sending an onShoot event). In this case, a transform.lookAt() is good enough, as it produces a reasonable visual effect.
However, if your turret is to be used in a First Player Shooter game, expect then that it's rotation will be controlled by the player (either via transform or rigidbody physics). Whether or not the turret should deal damage to the enemy depends on whether the projectile (simulated via physics with rigidbody and collider) hits the enemy or not. In this case, you have to limit your turret's maximum rotation speed. How much the threshold is depends on how realistic you want it to be.
Firstly, there is a LookRotation overload that takes the axis as a second parameter, so if you try
Quaternion lookRotation = Quaternion.LookRotation(dir,Vector3.up);
the rotation will always be around a vertical axis. This way you can split up motion into seperate axis as you would with a mechanical device (i.e. the pylon only rotates around a vertical axis)
As for the second part, i.e. how to make the turret hit the target, there's several approaches you can take:
You could, for example take the distance between the turret and the target, divide bullet velocity by target velocity, and take target.transform.forward multiplied by that ratio and the distance (this is from head, but you get the idea).
A bit more interesting alternative is to take the opportunity to learn about PID controllers, turrets are a fantastic example of how much can you do with a very simple controller.
PID stands for Proportional, Integral and Deriviative, and you compute your actuator output (i.e. force that drives your rotation) based on those three ways of looking at values.
In the most simplitied form it works like that: Proportional is your direct delta - how much of an angle away from your target angle you are (or from the target forward point). Than you average out that parameter (i.e. lerp the current value towards the target or using moving average) by a signifficant amount, this is your integral part - it will follow the target in a much slower way. Now if you subtract your averaged (integrated) value from your current (propoprtional) value, you get something that represents your change, this can be used as a deiviative component. Now this last part is what makes the turrent react to when the target is changing trajectory, you can make the output overshoot the change, or tune it in multiple other ways
I am writing the enemy class of a 3d game I am making and am working on making the enemy follow the player. I want the enemy to basically rotate itself in the direction of the player a little bit every frame and move forward a bit every frame. I tried to use Lerping to accomplish this as seen in the code below, but I can't seem to get it to work. When playing, the enemies don't even appear in my field of view or chase me at all. Here is my code from my enemy class below.
Note: p is a reference to a player object that I am chasing, world is the enemy object's world matrix, quaternion is this enemy object's quaternion.
My current strategy is finding the direction vector in between the forward vector of my enemy and the location vector3 of the player and then lerping that by an amount determined by the velocity variable. Then, I try to find the perpendicular vector to the plane determined by the enemy's forward vector and that new lerped vector I call midVector.Then, I update my quaternion for the player to be rotated about that perpendicular vector. Here is the code below:
//here I get the direction vector in between where my enemy is pointing and where the player is located at
Vector3 midVector = Vector3.Lerp(Vector3.Normalize(world.Forward), Vector3.Normalize(Vector3.Subtract(p.position,this.position)), velocity);
//here I get the vector perpendicular to this middle vector and my forward vector
Vector3 perp=Vector3.Normalize(Vector3.Cross(midVector, Vector3.Normalize(world.Forward)));
//here I am looking at the enemy's quaternion and I am trying to rotate it about the axis (my perp vector) with an angle that I determine which is in between where the enemy object is facing and the midVector
quaternion = Quaternion.CreateFromAxisAngle(perp, (float)Math.Acos(Vector3.Dot(world.Forward,midVector)));
//here I am simply scaling the enemy's world matrix, implementing the enemy's quaternion, and translating it to the enemy's position
world = Matrix.CreateScale(scale) * Matrix.CreateFromQuaternion(quaternion) * Matrix.CreateTranslation(position);
//here i move the enemy forward in the direciton that it is facing
MoveForward(ref position, quaternion, velocity);
}
private void MoveForward(ref Vector3 position, Quaternion rotationQuat, float speed)
{
Vector3 addVector = Vector3.Transform(new Vector3(0, 0, -1), rotationQuat);
position += addVector * speed;
}
My question is both, what is wrong with my current strategy/implementation and is there an easier way for me to accomplish this (the first part is more important)?
You aren't storing your object's orientation from frame to frame. I think you are thinking that the quaternion you are creating is oriented in the objects new direction. But actually, it's just a quaternion that only represents the rotational difference between last frame and the current frame, not the overall orientation.
So what needs to happen is your new quat has to be applied to last frame's orientation quaternion to get a current frame orientation.
In other words, you are creating an inter-frame update quaternion, not the final orientation quaternion.
You need to do something like this:
enemyCurrentOrientation = Quaternion.Concatenate(lastFrameQuat, thisNewQuat);
There's probably is an easier way but if this way's working for you, no need to change it.
My gameObject does not rotate while jumping. I used GetComponent().rotation = Quaternion.identity; for rotation but the gameObject still does not rotate. What is the problem? And how do I adjust the speed of the rotation? Here's my jump script:
Quaternion.identity means no rotation {0,0,0,0}, whenever this code block is called the gameObject's rotation will become the standard rotation value.
If this was intentional and the rotation of the gameObject is not {0,0,0,0} then perhaps you are modifying the rotation elsewhere?
GetComponent().rotation = Quaternion.identity;
Couple issues with this line. First off, just use transform.rotation... no need to call GetComponent() here. Also, Quaternion.identity is just the 'zero' rotation. What kind of rotation are you actually trying to apply here because you shouldn't see anything using identity.
http://docs.unity3d.com/ScriptReference/Quaternion-identity.html
To apply real rotation use something like (where "speed" is a float var where you can set how fast you want your cube to rotate):
transform.Rotate(Vector3.up, speed * Time.deltaTime);
I want to allow a boat in my 3D simulation of a ship to rotate and be moved on all axes. However, the way that I have the boat's movement programmed makes this impossible.
The way it moves:
this.transform.Translate(Vector3.left * Time.smoothDeltaTime * speed);
The way it turns:
this.transform.Rotate(Vector3.forward * Time.smoothDeltaTime * (int)horizontal)
The shape of the boat also makes it impossible to simply move it on a solid base, since it does have the triangular shape (for underwater collisions).
So what I want to do is allow the boat to be affected by gravity, but still float on the water. Then, when the boat hits something, it needs to be able to "roll" and then eventually return to its normal position.
So, is there any way to make an object slowly return to its normal rotation(z rotation of 0) after it hit something, and not be affected by gravity once it reaches a certain elevation. (Y value of 34.75)
The boat has a Rigidbody and a Mesh Collider
I'm not sure if the player would be able to move when he gets hit, but you could save the current values to local variables (for example: Transform transformOnHit). After you complete the roll, you can use your own provided code to translate and rotate back to the original transform.