I am new to Unity and so far enjoy my journey. Right now I have accomplished my knife constant rotation within [-30;30] degrees range. However, after the user presses any key, my knife should be moving fast in the direction it currently faces.
How can I achieve the following behavior? I tried addForce, changing velocity, but no results... Perhaps it is even impossible to do?
Here my knife is facing the left angle and I would like to it to just move in that direction really fast. No fancy effects :)
Here is the initial knife position.
Here is source code:
public void HandleRotation()
{
if (transform.rotation.z >= 0.3f)
{
right = false;
}
else if (transform.rotation.z <= -0.3f)
{
right = true;
}
if (right)
{
begin = begin + 0.05f;
}
else
{
begin = begin - 0.05f;
}
var tiltAroundZ = begin * tiltAngle;
var target = Quaternion.Euler (0, 0, tiltAroundZ);
transform.rotation = Quaternion.Slerp(transform.rotation, target, Time.deltaTime * smooth);
}
Translate(transform.forward())? If forward is the wrong axis, you could try up or right.
There should also be a version of the Translate method that includes a space parameter, in this case you'd use Space.Self instead of Space.World, which it currently is defaulting to.
Related
Good times. How do I implement the NPC rotation towards the selected object?
public GameObject BufferObject;
public float MoveSpeed = 1f;
void Update()
{
float step = MoveSpeed * Time.deltaTime;
transform.position = Vector2.MoveTowards(transform.position, BufferObject.transform.position, step);
}
Here is the script for moving the NPC to the selected object (Buffer Object) and the movement works perfectly, but the implementation of the rotation causes Me difficulties, please advise.
For Unity2D.
Simply get the desired direction
var direction = (BufferObject.transform.position - transform.position).normalized;
and then the desired rotation using Quaternion.LookRotation like e.g.
var targetRotation = Quaternion.LookDirection(direction);
Then either apply it directly if you want it immediately
transform.rotation = targetRotation;
Or if you want it smooth you could use e.g. Quaternion.RotateTowards like
transform.rotation = Quaternion.RotateTowards(transform.rotation, targetRotation, anglePerSecond * Time.deltatime);
Have in mind though that it might look awkward if the rotation is too slow since your NPC could move back/sidewards already while still not fully looking towards the target ;)
So you might want to wait until
if(Quaternion.Angle(targetRotation, transform.rotation) <= certainThreshold)
{
... your movement code
}
So the answer and the solution from Me, albeit stupid, but working. In order to reflect the sprite, you need to get a variable, either 1 or -1 (For Scale). This code will show the distance from one NPC to the object:
BufferObject.transform.position.x - transform.position.x
And here I get a lot of values as if to the left of the NPC, then -x... , and if to the right, then x... thereby it is possible to determine which side of the object, so also level the value from here (Optional) to 1 or -1 and apply this result to transform.localScale and thereby solve the problem of how to reflect (Rotate the sprite) towards the object. Use it for your health :)
Complete code:
float localPositionAmount = BufferObject.transform.position.x - transform.position.x;
if (localPositionAmount >= 1)
{
gameObject.transform.localScale = new Vector3(1, transform.localScale.y, transform.localScale.z);
}
if (localPositionAmount <= -1)
{
gameObject.transform.localScale = new Vector3(-1, transform.localScale.y, transform.localScale.z);
}
if (localPositionAmount == 0)
{
gameObject.transform.localScale = new Vector3(transform.localScale.x, transform.localScale.y, transform.localScale.z);
}
Yes, the code is the simplest and without enumerations and other things, but it works perfectly. I still had to figure it out myself...
My character is a car and I try to rotate it the direction it move, so far so good I succeeded to do that but once I stop moving the character flips back to the direction it was on the start.
Also how can I make my turns from side to the opposite site smooth ?
Here is my code so far:
[SerializeField] float driveSpeed = 5f;
//state
Rigidbody2D myRigidbody;
// Start is called before the first frame update
void Start()
{
myRigidbody = GetComponent<Rigidbody2D>();
}
// Update is called once per frame
void Update()
{
Move();
}
private void Move()
{
//Control of velocity of the car
float HorizontalcontrolThrow = CrossPlatformInputManager.GetAxis("Horizontal"); // Value between -1 to 1
float VerticalcontrolThrow = CrossPlatformInputManager.GetAxis("Vertical"); // Value between -1 to 1
Vector2 playerVelocity = new Vector2(HorizontalcontrolThrow * driveSpeed, VerticalcontrolThrow * driveSpeed);
myRigidbody.velocity =playerVelocity;
**//Direction of the car**
Vector2 direction = new Vector2(HorizontalcontrolThrow, VerticalcontrolThrow);
float angle = Mathf.Atan2(direction.y, direction.x) * Mathf.Rad2Deg;
myRigidbody.rotation = angle;
}
I'm not sure about this, but maybe that last line "myRigidbody.rotation = angle" being called every frame is what is making your car reset its rotation.
Maybe change it to "myRigidbody.rotation *= angle" or "myRigidbody.rotation += angle".
It looks like it may be because HorizontalcontrolThrow and VerticalcontrolThrow are going to be reset when you release the controls. If it's resetting to its original orientation, then what's happening is that until you move, those two values are going to be at their default value. You then move and it affects the rotation. But when you release the controls, those values are back to the starting values again, and so is your rotation.
What you therefore need to do is try to separate the HorizontalcontrolThrow and VerticalcontrolThrow from the rest of the code, which should only be activated when at least one of these two variables are not at their default setting (I can't remember what the axis functions return at the moment).
Edit:
An IF statement should suffice (some rough pseudo code):
if (horizontalAxis != default || verticalAxis != default)
{
Rotate/Move
}
I solved the snap rotation using Quaternion at rotation, the issiu I had with it was to convert it from 3d to 2d, through the guide of this clip: youtube.com/watch?v=mKLp-2iseDc and made my adjustments it works just fine !
How do I best describe the direction vector to move an object left (or right/up/down) from its current position, factoring the current view perspective into the equation?
For example, imagine the box depicted in the following picture, placed at origin (0,0,0). If I wanted to move the point on top of the box to the left, I'd have to make a step in (-1,0,0) direction (i.e. currentPos = currentPos + Vector3.left).
If I looked at the box from behind, I'd have to make a step in (1,0,0) direction to continue moving in the same direction.
i.e. When I'm looking at this box, placed at origin, and press an input button LEFT, I need for the point to move left and continue moving in that direction for as long as I keep pressing the button. It ultimately wraps around the surface, i.e. if I keep pressing just LEFT the point will wrap around the cube and re-appear so to speak.
To indefinitly trace a decal around a cube:
private Transform Cube;
private Transform Decal;
void Update() {
Vector3 moveLocal = Vector3.zero;
// Set moveLocal from User Input
moveLocal += Vector3.left * Input.GetAxis("Left"); // etc
if (moveLocal.sqrMagnitude > 0) {
var decalDirection = (Decal.position - Cube.position).normalized;
var angle = Vector3.SignedAngle(Cube.forward, decalDirection, Cube.up);
// Align decal to correct cube face
if (angle < -135 || angle > 135) { // Rear face
Decal.forward = -Cube.forward;
}
else if (angle < -45) { // Left face
Decal.forward = -Cube.right;
}
else if (angle > 45) { // Right face
Decal.forward = Cube.right;
}
else { // Front Face
Decal.forward = Cube.forward;
}
// Now move decal in it's local space:
Decal.Translate(moveLocal, Space.Self);
}
}
Admittedly, this only rotates Left/Right, but I hope you get the idea =)
As i mentioned you in my opinion you can achieve this with surface normals. I cracked some code which is not an exact solution because i used collision normals and on corners that gives different results. In any case i share it so that it gives you the idea. You can go left and right with this code relative to camera(even though it does not use anything related to camera) because it depends on surface normals.
private Vector3 normal;
private Vector3 contact;
private Vector3 direction;
private GameObject obj;
void Start () {
}
void Update () {
if (obj == null)
return;
if( Input.GetKey(KeyCode.LeftArrow))
{
obj.transform.position += direction * Time.deltaTime;
}
if (Input.GetKey(KeyCode.RightArrow))
{
obj.transform.position -= direction * Time.deltaTime;
}
}
void OnCollisionEnter(Collision collision)
{
Debug.Log("Collided");
Debug.Log("If works");
obj = collision.gameObject;
normal = collision.contacts[0].normal;
contact = collision.contacts[0].point;
//Cross product of normal and up gives direction Right.
//This up can be cube's up as well in cases it is tilted
direction = (-Vector3.Cross(Vector3.up, normal));
}
You can also see how it works from images below:
In my scenario, I have a table (plane) that a ball will roll around on using nothing but physics giving the illusion that the mobile device is the table using Input.gyro.attitude. Taking it one step further, I would like this relative to the device origin at the time Start() is called, so if it is not being held in front of a face or flat on the table, but just relative to where it started, and may even be reset when the ball is reset. So the question is, is how do I get the difference between the current attitude and the origin attitude, then convert the X and Z(?) difference into a Vector3 to AddForce() to my ball object whilst capping the max rotation at about 30 degrees? I've looked into a lot of Gyro based input manager scripts and nothing really helps me understand the mystery of Quaternions.
I could use the relative rotation to rotate the table itself, but then I am dealing with the problem of rotating the camera along the same rotation, but also following the ball at a relative height but now with a tilted offset.
AddForce() works well for my purposes with Input.GetAxis in the Editor, just trying to transition it to the device without using a Joystick style UI controller.
Edit: The following code is working, but I don't have the right angles/euler to give the right direction. The game is played in Landscape Left/Right only, so I should only need a pitch and yaw axis (imagine the phone flat on a table), but not roll (rotated around the camera/screen). I may eventually answer my own question through trial and error, which I am sure is what most programmers do.... XD
Started on the right track through this answer:
Answer 434096
private Gyroscope m_Gyro;
private speedForce = 3.0f;
private Rigidbody rb;
private void Start() {
m_Gyro = Input.gyro;
m_Gyro.enabled = true;
rb = GetComponent<Rigidbody>();
}
private Vector3 GetGyroForces() {
Vector3 resultantForce = Vector3.zero;
//Quaternion deviceRotation = new Quaternion(0.5f, 0.5f, -0.5f, -0.5f) * m_Gyro.attitude * new Quaternion(0,1,0,0);
float xForce = GetAngleByDeviceAxis(Vector3.up);
float zForce = GetAngleByDeviceAxis(Vector3.right);
//float zForce = diffRot.z;
resultantForce = new Vector3(xForce, 0, zForce);
return resultantForce;
}
private float GetAngleByDeviceAxis(Vector3 axis) {
Quaternion currentRotation = m_Gyro.attitude;
Quaternion eliminationOfOthers = Quaternion.Inverse(Quaternion.FromToRotation(axis, currentRotation * axis));
Vector3 filteredEuler = (eliminationOfOthers * currentRotation).eulerAngles;
float result = filteredEuler.z;
if (axis == Vector3.up) {
result = filteredEuler.y;
}
if (axis == Vector3.right) {
result = (filteredEuler.y > 90 && filteredEuler.y < 270) ? 180 - filteredEuler.x : filteredEuler.x;
}
return result;
}
void FixedUpdate() {
#if UNITY_EDITOR
rb.AddForce(new Vector3(Input.GetHorizontal * speedForce, 0, Input.GetVertical * speedForce));
#endif
#if UNITY_ANDROID
rb.AddForce(GetGyroForces);
#endif
}
I have following simple scene: scaled box at (0, 0, 0) for floor and 1 size box at (0, 2, 0). I try to do simple gravity and use following code:
private float gravity = 1.0f;
private Vector3 moveVector;
void Update()
{
if (characterController.IsGrounded)
{
Debug.Log("is grounded");
verticalVelocity = 0;
}
else
{
Debug.Log("not grounded");
verticalVelocity -= gravity;
}
Debug.Log("vertical velocity:" + verticalVelocity);
moveVector.x = 0;
moveVector.y = verticalVelocity;
moveVector.z = 0;
characterController.Move(moveVector * Time.deltaTime);
}
I see in log that event when object is on the floor I have grounded/not grounded messages. Visually object is on the floor and not oscillating.
Why I don't have constant "is grounded" when object is on the floor?
Maybe it is how CharacterController works but I can't find anything about it in documentation.
You have to set Character Controller Min Move Distance to '0' (zero) or else you will always get this behavior, it is trying to limit how many times it checks if it's grounded, but at the end of the day gamers don't care, they will mash the jump button and call it buggy
Had the same issue
Just had some gravity when the character controller is grounded
Replace verticalVelocity = 0;
By
verticalVelocity = -gravity * Time.deltaTime;
Setting "Min Move Distance" to 0 in the Character Controller Inspector solved a very similar problem for me.
Strubble is right. You have to add some small gravity even if character is grounded.
if (characterController.IsGrounded)
{
// Press the character down to the floor to avoid jitter "true-false"
// of the isGrounded property.
// To do it, add some small gravity (or velocity in your terms).
verticalVelocity = -gravity * 0.1f;
}
just use a Raycast with Vector3.down because I've tired of fixing it and it's really unreliable to use even while prototyping.