Cannot move object with MoveTowards in Unity - unity3d

I am trying to move my gun towards to a new position where the "Aim Position" is located at, but It won't work.
Here's my code:
public Transform aimPosition;
private float aimSpeed = 2f;
private void GunManager()
{
if (Input.GetMouseButton(1))
{
transform.position = Vector3.MoveTowards(transform.position, aimPosition.position, aimSpeed * Time.deltaTime);
}
}

Related

Why is my Controller drifting with Slerp?

I've been working on this Controller, where I walk around a small planet. I'm using Quaternion.Slerp, and when I'm at certain points on the planet, the controller slowly drifts, rotating around the Y axis. My thought is that it is holding a value based on my starting position, and so when I move to different points, the Slerp function is trying to spin me toward that location? I've tried messing around with the script, moving different portions to their own custom methods to pinpoint the issue, but I'm a bit lost at this point. Any help would be appreciated!
I think the issue is going to be somewhere in the bottom two methods NewRotation, or RunWalkStand.
`
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerController : MonoBehaviour
{
[SerializeField] private LayerMask _groundMask;
[SerializeField] private Transform _groundCheck;
[SerializeField] private Transform cam;
public float jumpCooldown = 1f;
public float groundCheckRadius = 0.3f;
private float speed = 8;
private float runSpeed = 2;
private float turnSpeed = 800f;
private float jumpForce = 500f;
private Rigidbody rb;
private Vector3 direction;
private GravityBody _gravityBody;
private Animator playerAnimator;
private GameObject planetRecall;
void Start()
{
_gravityBody = transform.GetComponent<GravityBody>();
playerAnimator = GetComponent<Animator>();
planetRecall = GameObject.FindGameObjectWithTag("Planet Recall");
}
void Update()
{
bool isCloseToGround = Physics.CheckSphere(_groundCheck.position, groundCheckRadius, _groundMask);
NewRotation();
if (Input.GetKeyDown(KeyCode.Space) && isCloseToGround)
{
Jump();
}
}
void FixedUpdate()
{
RunWalkStand();
}
private void OnCollisionEnter(Collision collision)
{
if(collision.gameObject == planetRecall)
{
playerAnimator.SetBool("Grounded", true);
}
}
private void Jump()
{
rb.AddForce(-_gravityBody.GravityDirection * jumpForce, ForceMode.Impulse);
playerAnimator.SetTrigger("Fly_trig");
playerAnimator.SetBool("Grounded", false);
}
private void NewRotation()
{
rb = transform.GetComponent<Rigidbody>();
Vector3 mouseRotationY = new Vector3(0f, Input.GetAxisRaw("Mouse X"), 0f);
Quaternion rightDirection = Quaternion.Euler(0f, mouseRotationY.y * (turnSpeed * Time.deltaTime), 0f).normalized;
Quaternion newRotation = Quaternion.Slerp(rb.rotation, rb.rotation * rightDirection, Time.deltaTime * 1000f);
rb.MoveRotation(newRotation);
//Move Side to Side
Vector3 sideToSide = transform.right * Input.GetAxisRaw("Horizontal");
rb.MovePosition(rb.position + sideToSide * (speed * Time.deltaTime));
}
private void RunWalkStand()
{
direction = new Vector3(0f, 0f, Input.GetAxisRaw("Vertical")).normalized;
Vector3 forwardDirection = transform.forward * direction.z;
bool isRunning = direction.magnitude > 0.1f;
//Walking
if (isRunning && !Input.GetKey(KeyCode.LeftShift))
{
rb.MovePosition(rb.position + forwardDirection * (speed * Time.deltaTime));
playerAnimator.SetFloat("Speed_f", 0.5f);
}
//Running
else if(isRunning && Input.GetKey(KeyCode.LeftShift))
{
rb.MovePosition(rb.position + forwardDirection * (speed * runSpeed * Time.deltaTime));
playerAnimator.SetFloat("Speed_f", 1f);
}
//Standing
else if(isRunning == false)
{
playerAnimator.SetFloat("Speed_f", 0f);
}
}
}
`
it might be because a slerp is not a lineair line so its velocity is less when you are close to the endpoint maybe try Quaternion.RotateTowards.
I "Mostly" solved this issue, and it's an unexpected solution. The drift was solved by freezing rotation on the player in the inspector (Still don't know what was causing the player to spin though) However this caused extra jitter. I found two issues.
If I've selected ANY game object in the hierarchy, and play the game, the game is jittery, but if I click off of it onto nothing, the game runs smoother (Not completely better, but much smoother).
I'm using a Gravity script for the planet that applies gravity to the player's Rigidbody, and I believe with multiple things acting on the RB at the same time, it causes jitter. I'm thinkin of trying to greatly simplify the project, but putting the different methods from the scripts into different Update methods helps a good bit depending on the combination (Not as simple as Physics movement in FixedUpdate and camera in LateUpdate unfortunately).

Inverse Kinematics (IK) Foot Placement

I have a problem with my humanoid character's Foot IK.
I'm building an Isometric Top-Down game with NavMesh to move the Player on click, and I wanted to add some life to the characters so I decided to add IK Foot Placement by following this tutorial.
It worked well, but I wanted to go further by making it more sensitive to colliders so the player's foot gets placed on the ground's surface perfectly.
This script below works well when the ground is rotated.
I tried to fix it a lot but it still doesn't work.
[ Preview Images ]
Here's my script:
using UnityEngine;
using UnityEngine.AI;
public class IKFootPlacement : MonoBehaviour
{
public bool ikActive = false;
public Animator anim;
public NavMeshSurface navmesh;
public LayerMask layerMask;
public Transform LeftFoot_Transform;
public Transform RightFoot_Transform;
public float LeftFoot_DistanceToGround;
public float RightFoot_DistanceToGround;
public float footGap = 0.0f;
private Vector3 L_TargetPosition;
private Vector3 R_TargetPosition;
private Ray L_Ray;
private Ray R_Ray;
void Start()
{
anim = GetComponent<Animator>();
}
void OnAnimatorIK(int layerIndex)
{
if (anim)
{
// Vector3 LeftFoot_position = anim.GetIKPosition(AvatarIKGoal.LeftFoot);
// Vector3 RightFoot_Position = anim.GetIKPosition(AvatarIKGoal.RightFoot);
float IKLeftWeight = anim.GetFloat("IKLeftFootWeight");
anim.SetIKPositionWeight(AvatarIKGoal.LeftFoot, IKLeftWeight);
anim.SetIKRotationWeight(AvatarIKGoal.LeftFoot, IKLeftWeight);
float IKRightWeight = anim.GetFloat("IKRightFootWeight");
anim.SetIKPositionWeight(AvatarIKGoal.RightFoot, IKRightWeight);
anim.SetIKRotationWeight(AvatarIKGoal.RightFoot, IKRightWeight);
//~ Left Foot
if (LeftFoot_Transform)
{
RaycastHit L_Hit;
L_Ray = new Ray(LeftFoot_Transform.position + Vector3.up, Vector3.down);
if (Physics.Raycast(L_Ray, out L_Hit, 2f, layerMask))
{
L_TargetPosition = L_Hit.point;
LeftFoot_DistanceToGround = Vector3.Distance(LeftFoot_Transform.position, L_TargetPosition);
if (LeftFoot_DistanceToGround > 0.15)
L_TargetPosition.y -= LeftFoot_DistanceToGround;
else
L_TargetPosition.y += LeftFoot_DistanceToGround;
L_TargetPosition.y += footGap;
anim.SetIKPosition(AvatarIKGoal.LeftFoot, L_TargetPosition);
anim.SetIKRotation(AvatarIKGoal.LeftFoot, Quaternion.LookRotation(transform.forward, L_Hit.normal));
}
}
//~ Right Foot
if (RightFoot_Transform)
{
RaycastHit R_Hit;
R_Ray = new Ray(RightFoot_Transform.position + Vector3.up, Vector3.down);
if (Physics.Raycast(R_Ray, out R_Hit, 2f, layerMask))
{
R_TargetPosition = R_Hit.point;
RightFoot_DistanceToGround = Vector3.Distance(RightFoot_Transform.position, R_TargetPosition);
if (RightFoot_DistanceToGround > 0.15)
R_TargetPosition.y -= RightFoot_DistanceToGround;
else
R_TargetPosition.y += RightFoot_DistanceToGround;
R_TargetPosition.y += footGap;
anim.SetIKPosition(AvatarIKGoal.RightFoot, R_TargetPosition);
anim.SetIKRotation(AvatarIKGoal.RightFoot, Quaternion.LookRotation(transform.forward, R_Hit.normal));
}
}
}
}
void OnDrawGizmos()
{
Gizmos.color = Color.magenta;
Gizmos.DrawWireSphere(L_TargetPosition, 0.05f);
Gizmos.DrawWireSphere(R_TargetPosition, 0.05f);
Gizmos.color = Color.red;
Gizmos.DrawRay(L_Ray);
Gizmos.DrawRay(R_Ray);
}
}

Trying to get reversed movement on collision on Unity2

so I am trying to make a shooting machine that shoots bullet and bullet gets back from the same way it went through when hitting the wall without speeding up and without changing angle (just the opposite way)
i added force and tried many ways but nothing works , please help
here is my code (the last one) even though i normalized the force but i still feel like its speeding up
public Rigidbody2D rb;
private float bulletForce = 20f;
private bool collided;
Vector2 dir;
private void Awake()
{
instance = this;
rb = gameObject.GetComponent<Rigidbody2D>();
dir = transform.up;
}
void Update()
{
rb.AddForce(dir.normalized * bulletForce * Time.deltaTime, ForceMode2D.Impulse);
}
private void OnCollisionEnter2D(Collision2D other)
{
if (other.gameObject.CompareTag("Edge"))
{
dir = Vector2.Reflect(rb.position, other.contacts[0].normal);
rb.velocity = dir.normalized * bulletForce;
transform.up = dir.normalized;
}
}
this is wanted results explanation
this is current results explanation
If you just want to exactly invert the direction than
rb.velocity = -rb.velocity;
transform.up = rb.velocity;
and of course it is speeding up since you constantly add force in
void Update()
{
rb.AddForce(dir.normalized * bulletForce * Time.deltaTime, ForceMode2D.Impulse);
}
why don't you just disable any friction for this bullet and set an initial velocity once?
public class CollideReflector : MonoBehaviour
{
[SerializeField] Rigidbody2D rb;
[SerializeField] Vector2 direction;
[SerializeField] float bulletForce = 20f;
[SerializeField]float smooth;
private bool collided;
// STARTER
private void Awake()
{
instance = this;
rb = gameObject.GetComponent<Rigidbody2D>();
direction = transform.up;
}
void Update()
{
rb.AddForce(direction.normalized * bulletForce * Time.deltaTime, ForceMode2D.Impulse);
}
private void OnCollisionEnter2D(Collision2D other)
{
if (other.gameObject.CompareTag("Edge"))
{
var x = Quaternion.Euler(transform.eulerAngles.x, transform.eulerAngles.y, transform.eulerAngles.z);
Quaternion target = -x;
transform.rotation = Quaternion.Slerp(transform.rotation, x, Time.deltaTime * smooth);
rb.AddForce(-direction.normalized * bulletForce * Time.deltaTime, ForceMode2D.Impulse);
}
}
}

Gun Script Creates Bullet But Bullet Travel in All Different Directions

I am trying to create a gun script however after the bullet prefab instantiates, it doesn't travel in the correct direction(Straight). The function used to create bullets in Shoot() which is called when the Update loop gets the input from GetMouseButton(0).
public class CharController : MonoBehaviour {
[SerializeField]
float moveSpeed = 4f;
public float aimSpeed;
Vector3 mousePos;
Vector3 forward, right;
public GameObject bulletSpawnPoint;
public GameObject bullet;
public float bullet_Speed;
public float fireRate;
void Start () {
forward = Camera.main.transform.forward;
forward.y = 0;
forward = Vector3.Normalize(forward);
right = Quaternion.Euler(new Vector3(0, 90, 0)) * forward;
}
void Update () {
if (Input.GetMouseButton(0))
{
transform.position += (-transform.position + mousePos).normalized * aimSpeed * Time.deltaTime;
transform.position = new Vector3(transform.position.x, 2.5f, transform.position.z);
Shoot();
}
}
void Shoot()
{
GameObject temp_Bullet_Handler;
temp_Bullet_Handler = Instantiate(bullet, bulletSpawnPoint.transform.position, bulletSpawnPoint.transform.rotation) as GameObject;
//temp_Bullet_Handler.transform.Rotate(Vector3.left * 90);
Rigidbody temp_Rigidbody;
temp_Rigidbody = temp_Bullet_Handler.GetComponent<Rigidbody>();
temp_Rigidbody.AddForce(Vector3.forward * Time.deltaTime * 10f);
Destroy(temp_Bullet_Handler, 10.0f);
}
}
If anyone has any information on what causes the bullets not to travel in a straight direction from the instantiation point, I would love to have your input.
Thanks in advance
Your Update moves the bullet in a direction which is based on it's position. Change that into a direction vector, like your "forward" instead of transform.position.

Unity: Diagonal movement issue

I have a test 2D game where my player moved from left to right and when he reached the end of the screen it would just transform on the other side. I had a change of heart and made my player move diagonally. It did work, but I have no idea how to make the player stop when it hits the end of the screen. I don't want it to transform on the other side, but rather just stop. So far all my results are either some glitching on the edges or not stopping at all. I have provided my PlayerController script. Right now my player moves diagonally and he will just continue after the edge of the screen. If anyone can assist me I would be very grateful. I never thought I will deal with diagonal movement, but I really want to learn how to do it.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class PlayerController : MonoBehaviour {
public float speed = 7;
public float speedy = 7;
public event System.Action OnPlayerDeath;
float screenHalfWidthInWorldUnits;
Rigidbody2D rb;
void Start () {
rb = GetComponent<Rigidbody2D>();
float halfPlayerWidth = transform.localScale.x / 2f;
screenHalfWidthInWorldUnits = Camera.main.aspect * Camera.main.orthographicSize;
}
void Update()
{
float inputX = Input.GetAxisRaw("Horizontal");
float velocity = inputX * speed;
transform.Translate(Vector2.right * velocity * Time.deltaTime);
}
public void MoveRight()
{
rb.velocity = new Vector2(speed, speedy);
}
public void MoveLeft()
{
rb.velocity = new Vector2(-speed, -speedy);
}
public void Stop()
{
rb.velocity = Vector2.zero;
}
void OnTriggerEnter2D(Collider2D triggerCollider)
{
if (triggerCollider.tag =="Box")
{
if (OnPlayerDeath != null)
{
OnPlayerDeath();
}
Destroy(gameObject);
}
}
}
You can check if the player is at what you define as the border of the map.
If you check this for the x and y axis respectively, you can then lock his x or y axis to the border and not further.
Here is an example of a script I made earlier that does that.
If I understand you correctly you would like to be able to move diagonally. In my sample script below you can move both straight and diagonally, you can also warp between the edges or stop at the edges as you spoke of wanting to.
This script is a bit more advanced than what you need probably, so let me know if something about it confuses you.
Please note that if you set the boolean _ShouldWarp to false he will stop at the border, otherwise he will warp from edge to edge of the map.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Player : MonoBehaviour
{
public float _Speed = 5f;
public WorldBounds _WorldBounds;
public bool _ShouldWarp; //If _ShouldWarp is false, will block players movement instead.
void Update()
{
Move();
WarpIfAtBoundary();
}
void Move()
{
float horizontal = Input.GetAxisRaw("Horizontal");
float vertical = Input.GetAxisRaw("Vertical");
transform.Translate(Vector3.right * Time.deltaTime * _Speed * horizontal);
transform.Translate(Vector3.up * Time.deltaTime * _Speed * vertical);
}
void WarpIfAtBoundary()
{
//X Axis
//If player is at positive X boundary
if (transform.position.x > (_WorldBounds.xPlus + _WorldBounds.xBuffer))
{
if (_ShouldWarp) //Teleport/warp player is set to enabled
{
transform.position = new Vector3(_WorldBounds.xMinus, transform.position.y, transform.position.z);
}
else //Otherwise keep player in border position
{
transform.position = new Vector3(_WorldBounds.xPlus + _WorldBounds.xBuffer, transform.position.y, transform.position.z);
}
}
//Else if player is at negative X boundary
else if (transform.position.x < (_WorldBounds.xMinus - _WorldBounds.xBuffer))
{
if (_ShouldWarp)//Teleport/warp player is set to enabled
{
transform.position = new Vector3(_WorldBounds.xPlus, transform.position.y, transform.position.z);
}
else //Otherwise keep player in border position
{
transform.position = new Vector3(_WorldBounds.xMinus - _WorldBounds.xBuffer, transform.position.y, transform.position.z);
}
}
//Y Axis
//If player is at positive Y boundary
if (transform.position.y > (_WorldBounds.yPlus + _WorldBounds.yBuffer))
{
if (_ShouldWarp)//Teleport/warp player is set to enabled
{
transform.position = new Vector3(transform.position.x, _WorldBounds.yMinus, transform.position.z);
}
else //Otherwise keep player in border position
{
transform.position = new Vector3(transform.position.x, _WorldBounds.yPlus + _WorldBounds.yBuffer, transform.position.z);
}
}
//Else if player is at negative Y boundary
else if (transform.position.y < (_WorldBounds.yMinus - _WorldBounds.yBuffer))
{
if (_ShouldWarp)//Teleport/warp player is set to enabled
{
transform.position = new Vector3(transform.position.x, _WorldBounds.yPlus, transform.position.z);
}
else //Otherwise keep player in border position
{
transform.position = new Vector3(transform.position.x, _WorldBounds.yMinus - _WorldBounds.yBuffer, transform.position.z);
}
}
}
}
//Set as serializable so it displays correctly in Unity's inspector window.
[System.Serializable]
public class WorldBounds
{
[Header("Bounds")]
public float xMinus = -9.4f;
public float xPlus = 9.4f;
public float yMinus = -9.4f;
public float yPlus = 9.4f;
[Header("BufferZone")]
public float xBuffer = 1f;
public float yBuffer = 1f;
}
EDIT:
With your additions will I be able to assign the movement to my two buttons. One is up and right and the other is down and left.
void Move()
{
float horizontal = Input.GetAxisRaw("Horizontal");
transform.Translate(Vector3.right * Time.deltaTime * _Speed * horizontal);
transform.Translate(Vector3.up * Time.deltaTime * _Speed * horizontal);
}
This should work to move diagonally left and down as well as up and right.
The change i made is to use the Horizontal input for both X and Y movement.
I don't need the warp. Just to step at the defined borders
You can set the Warp boolean to false or remove the warp parts from the code then :-), should work.