I have a problem that I can not solve. I have an object, and I want when I click somewhere near him to move with some force. something like the picture below.
I'd even want some idea!!!
Help!!!
public float speed;
public GameObject player;
Vector3 target;
private void Update()
{
if (Input.GetMouseButtonDown(0))
{
var mouseClick = Input.mousePosition;
mouseClick.z = player.transform.position.z - Camera.main.transform.position.z;
target = Camera.main.ScreenToWorldPoint(mouseClick);
var distanceToTarget = Vector3.Distance(player.transform.position, target);
if (distanceToTarget > 2)
{
target.z = 0;
player.GetComponent<Rigidbody2D>().AddForce(target * speed);
}
else
print("travelling COMPLETE");
}
}
Using the code you provided in your answer...
public float speed;
public GameObject player;
Vector3 directionVector;
private void Update()
{
if (Input.GetMouseButtonDown(0))
{
// Input.mousePosition is already in pixel coordinates so the z should already be 0.
Vector3 mouseWorldPosition = Camera.main.ScreenToWorldPoint(Input.mousePosition);
// Now that the mouse is a world position lets set his z to the same as the player
mouseWorldPosition.z = player.transform.position.z;
// Gives us a direction from the mouse to the player. So think of it as Player <- Mouse remove the < and you have the equation
directionVector = player.transform.position - mouseWorldPosition;
}
else
{
directionVector = Vector3.zero;
}
}
// Physics based movement should be done in FixedUpdate
private void FixedUpdate()
{
player.GetComponent<Rigidbody2D>().AddForce(directionVector.normalized * speed);
}
Related
It says it all in the title, really. I have a blend tree set up with 4 directions and the player moves and rotates perfectly, but if I turn to run directly in (for example) the left direction, the left strafe animation plays while running in that direction. The player is facing in the right direction it is just his legs are playing the wrong animation.
I have tried using "normalized" and "transform.Translate" but nothing seems to make a difference.
public class TwinStickMovement : MonoBehaviour
{
[SerializeField] private float playerSpeed = 5f;
[SerializeField] private float graityValue = -9.81f;
[SerializeField] private float controllerDeadZone = 0.1f;
[SerializeField] private float gamepadRotateSmoothing = 1000f;
[SerializeField] private bool isGamePad;
private CharacterController controller;
private Animator animator;
private Vector2 movement;
private Vector2 aim;
private Vector3 playerVelocity;
private Vector3 lookPoint;
private PlayerControls playerControls;
private PlayerInput playerInput;
private bool animLocked = false;
private void Awake()
{
controller = GetComponent<CharacterController>();
playerControls = new PlayerControls();
playerInput = GetComponent<PlayerInput>();
animator = GetComponent<Animator>();
}
private void FixedUpdate()
{
if (!animLocked && movement != Vector2.zero)
{
animator.SetFloat("moveX", movement.x);
animator.SetFloat("moveY", movement.y);
}
}
private void OnEnable()
{
playerControls.Enable();
}
private void OnDisable()
{
playerControls.Disable();
}
private void Update()
{
HandleInput();
HandleMovement();
HandleRotation();
}
private void HandleInput()
{
movement = playerControls.Controls.Movement.ReadValue<Vector2>();
aim = playerControls.Controls.Aim.ReadValue<Vector2>();
}
private void HandleMovement()
{
Vector3 move = new Vector3(movement.x, 0, movement.y);
controller.Move(move * Time.deltaTime * playerSpeed);
playerVelocity.y += graityValue * Time.deltaTime;
controller.Move(playerVelocity * Time.deltaTime);
}
private void HandleRotation()
{
if (isGamePad)
{
if (Mathf.Abs(aim.x) > controllerDeadZone || Mathf.Abs(aim.y) > controllerDeadZone)
{
Quaternion newrotation = Quaternion.LookRotation(new Vector3(aim.x, 0f, aim.y),Vector3.up);
transform.rotation = Quaternion.RotateTowards(transform.rotation, newrotation, gamepadRotateSmoothing * Time.deltaTime);
}
}
else
{
Ray ray = Camera.main.ScreenPointToRay(aim);
Plane groundPlane = new Plane(Vector3.up, Vector3.zero);
float rayDistance;
if (groundPlane.Raycast(ray, out rayDistance))
{
Vector3 point = ray.GetPoint(rayDistance);
LookAt(point);
}
}
}
private void LookAt(Vector3 point)
{
Vector3 heightCorrectPoint = new Vector3(lookPoint.x, transform.position.y, lookPoint.z);
transform.LookAt(heightCorrectPoint);
}
public void OnDeviceChange(PlayerInput pi)
{
isGamePad = pi.currentControlScheme.Equals("Gamepad") ? true : false;
}
}
I assume that you're using logic that is equivalent to if moveX > 0 and moveY approximatly 0 then play strafe animation. However this doesn't take the players orientation into account and as such only works correctly when you look up. You will need to transform your moveX and moveY into the localspace of lookX and lookY so that the animator can make the appropriate choice.
The left panel shows the information your animator is receiving and based on that it is making the wrong choice and says that your character is strafing. The right panel shows the vector after it was transformed. Here your animator would recognize that you are moving forward stronger than sideways and therefore the strafe is inappropriate and the forward walk animation should play.
I'll abridge the math to make it all work and skip to the interesting bits. Basically you want to transform a uv coordinate system into the xy system. For that you have two given perpendicular vectors (look direction and the "right") in the xy coordinates which you can note in two equations like so:
x = au+bv
y = cu+dv
You can use these to find u and v, which if you do it will be:
u = (by-dx)/(bc-da)
v = (ay-cx)/(cd-ab)
Plugging in all the values and inserting the coordinates that you want to transform into x and y will give you an answer in uv space, which is actually what you need to give to the animator.
Since math is hard and I probably didn't do a particularly good job explaining it, here's the code that does it in Unity:
private Vector2 MovementRelativeToLookdirection(){
float x = movement.x;
float y = movement.y;
float a = transform.forward.x;
float b = transform.forward.z;
float c = transform.right.x;
float d = transform.right.z;
float u = (b*y-d*x)/(b*c-d*a);
float v = (a*y-c*x)/(c*d-a*b);
Vector2 transformedVector = new Vector2(u, v);
return transformedVector;
}
private void FixedUpdate()
{
if (!animLocked && movement != Vector2.zero)
{
Vector2 actualDir = MovementRelativeToLookdirection();
animator.SetFloat("moveX", actualDir.x);
animator.SetFloat("moveY", actualDir.y);
}
}
If my assumption is actually the problem this should fix it.
My character has a chinemachine camera attached to it and it is moving perfectly fine. But when I move my mouse to change the camera direction it is not looking in that direction. And I can't figure out how to make it look in that direction.
I have a reference to the original camera at the top of the script by the name cam.
The script has different functions for movement, rotation, animation, etc.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
//so that unity recognises the callbacks ctx passed to the movementinput
using UnityEngine.InputSystem;
public class AnimationAndMovController : MonoBehaviour
{
public Transform cam;
public float speed;
//here we are creadting three vars for the animation
//vector2 currentMovementInput stores the input axis of the player
//vector3 store the current position of the player
PlayerInput playerInput;
CharacterController characterController;
Animator animator;
Vector2 currentMovementInput;
Vector3 currentMovement;
Vector3 currentRunMovement;
Vector3 moveDir;
bool isMovementPressed;
bool isRunPressed;
float rotationFactor = 15.0f;
// float turnSmoothtime = 0.1f;
// float turnSmoothVelocity ;
float runMultiplier = 4.0f;
int walkHash ;
int runHash ;
//runs before start function
void Awake(){
playerInput = new PlayerInput();
characterController = GetComponent<CharacterController>();
animator = GetComponent<Animator>();
// walkHash = Animator.StringToHash("Walking");
// runHash = Animator.StringToHash("run");
//now instead of writing the logic three times we pass the callback ctx to the movementInput() function
playerInput.CharacterControls.Move.started += movementInput;
playerInput.CharacterControls.Move.canceled += movementInput;
playerInput.CharacterControls.Move.performed += movementInput;
playerInput.CharacterControls.Run.started += handleRun;
playerInput.CharacterControls.Run.canceled += handleRun;
}
void handleRun(InputAction.CallbackContext ctx){
isRunPressed = ctx.ReadValueAsButton();
}
//we are going to handle rotations with quaternions
void handleRotation(){
Vector3 positionToLookAt;
positionToLookAt.x = currentMovement.x;
positionToLookAt.y = 0.0f ;
positionToLookAt.z = currentMovement.z;
Vector3 direction = new Vector3(positionToLookAt.x, 0.0f, positionToLookAt.z).normalized;
Quaternion currentRotation = transform.rotation;
//we take the current rotation and the target rotation and slerp them *FYI : Im still not sure how slerp works
if(isMovementPressed){
Quaternion targetRotation = Quaternion.LookRotation(positionToLookAt);
transform.rotation = Quaternion.Slerp(currentRotation, targetRotation, rotationFactor * Time.deltaTime);
}
}
//we are passing the callback ctx to this function so that we dont have to call the function everytime we start, cancel or perform the movement
void movementInput(InputAction.CallbackContext ctx){
//we are setting the movement input to the axis of the player
currentMovementInput = ctx.ReadValue<Vector2>();
currentMovement.x = currentMovementInput.x;
//we are setting the z axis to the y axis of the player because we move y axis on keyboard or joystick but in game we move in z axis
currentMovement.z = currentMovementInput.y;
//now we are setting the run movement to the current movement
currentRunMovement.x = currentMovementInput.x * runMultiplier;
currentRunMovement.z = currentMovementInput.y * runMultiplier;
isMovementPressed = currentMovementInput.x != 0 || currentMovementInput.y != 0;
}
void handleAnimation(){
bool walk = animator.GetBool("walking");
bool run = animator.GetBool("run");
if(isMovementPressed && !walk){
animator.SetBool("walking", true);
}
else if(!isMovementPressed && walk){
animator.SetBool("walking", false);
}
if((isMovementPressed && isRunPressed) && !run){
animator.SetBool("run", true);
}
else if((!isMovementPressed || !isRunPressed)&& run){
animator.SetBool("run", false);
}
}
void handleGravity(){
//we are setting the gravity to -9.8f because we are moving in y axis
if(characterController.isGrounded){
float groundGravity = -0.05f;
currentMovement.y = groundGravity;
currentRunMovement.y = groundGravity;
}
else{
float gravity = -9.8f;
currentMovement.y += gravity * Time.deltaTime;
currentRunMovement.y += gravity * Time.deltaTime;
}
}
// Update is called once per frame
void Update()
{
handleAnimation();
handleRotation();
handleGravity();
if(isRunPressed){
characterController.Move(currentRunMovement * Time.deltaTime);
}
else{
characterController.Move(currentMovement * Time.deltaTime);
}
}
//we are checking if the player script gets enabled or disabled and accordingly we are enabling or disabling the player input
void OnEnable(){
playerInput.CharacterControls.Enable();
}
void OnDisable(){
playerInput.CharacterControls.Disable();
}
}
That quite a lot of code to dive into.
I'd try:
Quaternion cameraRot = Camera.Main.transform.rotation;
transform.rotation = cameraRot;
Or if you have a target Quaternion.LookRotation:
Vector3 relativePos = target.position - transform.position;
// the second argument, upwards, defaults to Vector3.up
Quaternion rotation = Quaternion.LookRotation(relativePos, Vector3.up);
transform.rotation = rotation;
Hope that helps
Use Transform.LookAt, which points a Game Object's rotation towards a target's position.
In your case, this would be
transform.LookAt(cam);
here is the code that I use..
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class MoveCamera : MonoBehaviour
{
public float sensitivity = 1000f;
public float xRotation = 0f;
public Transform playerBody;
public Quaternion localRotate;
// Start is called before the first frame update
void Start()
{
Cursor.lockState = CursorLockMode.Locked;
}
// Update is called once per frame
void Update()
{
float MX = Input.GetAxis("Mouse X")*sensitivity*Time.deltaTime;
float MY = Input.GetAxis("Mouse Y")*sensitivity*Time.deltaTime;
xRotation -= MY;
xRotation = Mathf.Clamp(xRotation,-90f,90f);
transform.localRotation = Quaternion.Euler(xRotation,0f,0f);
localRotate = transform.localRotation;
playerBody.Rotate(Vector3.up * MX);
}
}
the player body you see is the player object to you character...
note that the camera is use is not In. cinema chine and is inside of the player...
I have a problem with rigidbody, This is a simple character controller script. the problem is i created some square floor tiles and each floor has mesh collider. soo when the character moving fast on thes floor tiles the charachter will going up a little bit or bounces when moving !! this is a image and a code of script
[]
public class character_controller : MonoBehaviour {
[Header("Speeds")]
public float move_speed;
public float move_smooth;
public float rotate_speed;
[Header("Physics")]
public float gravity_force = -10.0f;
[Header("Distances")]
public float ground_min_dis = 0.25f;
public float ground_max_dis = 100;
[Header("Layers")]
public LayerMask ground_layer;
[HideInInspector] public Rigidbody rb;
[HideInInspector] public Vector3 dir;
[HideInInspector] public Vector3 input;
[HideInInspector] public Vector3 input_smooth;
[HideInInspector] public bool move_to_direction;
[HideInInspector] public bool rotate_to_direction;
[HideInInspector] public bool can_move;
[HideInInspector] public bool is_on_ground;
private float ground_distance;
private RaycastHit ground_hit;
// method: start is called before the first frame update
void Start() {
rb = GetComponent<Rigidbody>();
can_move = true;
move_to_direction = true;
}
// method: update is called once per frame
void Update() {
move_input();
check_ground_distance();
}
// method: fixed update is called every fixed framerate frame
void FixedUpdate() {
if(
move_to_direction
) {
move();
}
}
// method: move input
private void move_input() {
input.x = Input.GetAxis("Vertical");
input.z = Input.GetAxis("Horizontal");
}
// method: move character
private void move() {
// input smooth for moving character smoothly
input_smooth = Vector3.Lerp(input_smooth, input, move_smooth * Time.deltaTime);
// get the forward facing direction of the character
var forward = Vector3.forward;
// get the left facing direction of the character
var right = Vector3.left;
// determine the direction
dir = (input_smooth.x * forward) + (input_smooth.z * right);
// normalize direction
if (
dir.magnitude > 1f
) {
dir.Normalize();
}
Vector3 target_position = rb.position + dir * move_speed * Time.deltaTime;
Vector3 target_velocity = (target_position - transform.position) / Time.deltaTime;
target_velocity.y = rb.velocity.y;
if(
can_move
) {
rb.velocity = target_velocity;
}
if(
input.magnitude > 0.01f
) {
// start rotate to direction
if(
rotate_to_direction == true
) {
start_rotate_to_direction(dir, rotate_speed);
}
}
}
// method: rotate character to direction
public void start_rotate_to_direction(
Vector3 dir,
float speed
) {
Vector3 forward;
Quaternion new_rotation;
forward = Vector3.RotateTowards(transform.forward, dir.normalized, speed * Time.deltaTime, 0.1f);
forward.y = 0;
new_rotation = Quaternion.LookRotation(forward);
transform.rotation = new_rotation;
}
// method: check ground distance
private void check_ground_distance() {
float distance;
Ray ray = new Ray(transform.position, Vector3.down);
// if the ray hit to the ground layer
if (
Physics.Raycast(ray, out ground_hit, ground_max_dis, ground_layer)
) {
if(
!ground_hit.collider.isTrigger
) {
distance = transform.position.y - ground_hit.point.y;
ground_distance = (float)System.Math.Round(distance, 2);
}
}
// check if character on the ground
if(
ground_distance <= ground_min_dis
) {
is_on_ground = true;
} else {
is_on_ground = false;
}
// apply force gravity when falling
if(
is_on_ground == false
) {
rb.AddForce(transform.up * gravity_force * Time.deltaTime, ForceMode.VelocityChange);
}
}}
Can you please read this manual page carefully?
I think, the page explains this phenomena (it is called ghost collision). Probably, your rigidbody hits to the border of mesh colliders just like described in manual.
Also, did you try to freeze motion along related axis by using inspector? It can be a quick solution.
I solved this problem by going into Edit > Project Settings > Physics from Physics tab you can set the Default Contact Offset value from 0.01 to 0.0001.
This has been asked about 1 million times, yet I can't find a solution to my issue, rather to my annoyance.
Help is very much appreciated as I'm not sure whats going wrong and how to solve it any more.
Script 1:
public class Something : MonoBehaviour {
[SerializeField]
private Rigidbody cannonballInstance;
public ProjectileController projectile;
public Transform firePoint;
[SerializeField]
[Range(10f, 80f)]
private float angle = 45f;
private void Update()
{
if (Input.GetMouseButtonDown(0))
{
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
RaycastHit hitInfo;
if (Physics.Raycast(ray, out hitInfo))
{
FireCannonAtPoint(hitInfo.point);
}
}
}
private void FireCannonAtPoint(Vector3 point)
{
var velocity = BallisticVelocity(point, angle);
Debug.Log("Firing at " + point + " velocity " + velocity);
ProjectileController newProjectile = Instantiate(cannonballInstance, transform.position, transform.rotation) as ProjectileController;
//cannonballInstance.transform.position = transform.position;
//cannonballInstance.velocity = velocity;
}
private Vector3 BallisticVelocity(Vector3 destination, float angle)
{
Vector3 dir = destination - transform.position; // get Target Direction
float height = dir.y; // get height difference
dir.y = 0; // retain only the horizontal difference
float dist = dir.magnitude; // get horizontal direction
float a = angle * Mathf.Deg2Rad; // Convert angle to radians
dir.y = dist * Mathf.Tan(a); // set dir to the elevation angle.
dist += height / Mathf.Tan(a); // Correction for small height differences
// Calculate the velocity magnitude
float velocity = Mathf.Sqrt(dist * Physics.gravity.magnitude / Mathf.Sin(2 * a));
return velocity * dir.normalized; // Return a normalized vector.
}
The following is called from the previos when instansiated, causes error is this due to the type i'm trying to create or what?
Script 2:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class ProjectileController : MonoBehaviour {
public float speed;
private Vector3 oldVelocity;
private Rigidbody rigidbodyTemp;
private int bounceLimit = 3;
// Use this for initialization
void Start () {
rigidbodyTemp = GetComponent<Rigidbody>();
rigidbodyTemp.isKinematic = false;
rigidbodyTemp.freezeRotation = true;
rigidbodyTemp.detectCollisions = true;
}
// Update is called once per frame
void FixedUpdate () {
rigidbodyTemp.AddForce(transform.forward * speed);
oldVelocity = rigidbodyTemp.velocity;
}
private void OnCollisionEnter(Collision collision)
{
bounceLimit -= 1;
if (collision.gameObject.tag == "Bulllet") // Check if hit another bullet
{
Destroy(this.gameObject);
}
else if (collision.gameObject.tag == "Crate") // Check if a Crate has been hit, will hold power ups
{
Destroy(this.gameObject);
Destroy(collision.gameObject);
PickUUpBounce.isActive = true;
}
else if (collision.gameObject.tag == "Player") // Check if hit a player
{
Destroy(this.gameObject);
}
else if (collision.gameObject.tag == "Enemy") // Check if enemy is hit
{
Destroy(this.gameObject);
Destroy(collision.gameObject);
}
else if (bounceLimit == 0) // check if bounce limit is reached
{
Destroy(this.gameObject);
}
else // bounce
{
Vector3 reflectedVelocity;
Quaternion rotation;
ContactPoint contact = collision.contacts[0]; // stores contact point for reflected velocity
reflectedVelocity = Vector3.Reflect(oldVelocity, contact.normal); // reflected velocity equals a reflection of the old velocity around the contact point
rigidbodyTemp.velocity = reflectedVelocity; // Change rigidbody velocity
rotation = Quaternion.FromToRotation(oldVelocity, reflectedVelocity); // old directyion -> new direction
transform.rotation = rotation * transform.rotation; // front face always facing the front
}
}
}
The prefab (cannonballInstance) you are instantiating is declared as Rigidbody. When you call the Instantiate function and pass cannonballInstance to it, it will return a Rigidbody not ProjectileController.
ProjectileController is a script. You can't cast the returned Rigidbody to ProjectileController. You have to use GetComponent to retrieve the ProjectileController instance that is attached to your prefab(cannonballInstance) .
ProjectileController newProjectile = Instantiate(cannonballInstance, transform.position, transform.rotation).GetComponent<ProjectileController>();
It's better to break that line of code into pieces to make it easier to debug just in case anything is null.
Rigidbody rg = Instantiate(cannonballInstance, transform.position, transform.rotation);
ProjectileController newProjectile = rg.GetComponent<ProjectileController>();
I am creating a 2D side-scroller video game in Unity using c#. I have created the script that makes the player face the direction that the arrow key that was pressed was pointing to (when the right arrow is pressed, the player faces right. When the left arrow is pressed, the player faces left).
However, I cannot figure out how to make the harpoon that the player shoots point in the direction the player is facing. I have found many questions on Stack Overflow asking questions like this, but none of their answers worked for me.
Can anyone please tell me how to make the harpoon the player shoots face the direction the player is facing? Thanks in advance!
Here is my code that I use-
PLAYER SCRIPT
using UnityEngine;
using System.Collections;
public class playerMove : MonoBehaviour {
// All Variables
public float speed = 10;
private Rigidbody2D rigidBody2D;
private GameObject harpoon_00001;
private bool facingRight = true;
void Awake () {
rigidBody2D = GetComponent<Rigidbody2D>();
harpoon_00001 = GameObject.Find("harpoon_00001");
}
void Update () {
if (Input.GetKeyDown(KeyCode.LeftArrow) && !facingRight) {
Flip();
}
if (Input.GetKeyDown(KeyCode.RightArrow) && facingRight) {
Flip();
}
}
void Flip () {
facingRight = !facingRight;
Vector3 theScale = transform.localScale;
theScale.x *= -1;
transform.localScale = theScale;
}
void FixedUpdate () {
float xMove = Input.GetAxis("Horizontal");
float yMove = Input.GetAxis("Vertical");
float xSpeed = xMove * speed;
float ySpeed = yMove * speed;
Vector2 newVelocity = new Vector2(xSpeed, ySpeed);
rigidBody2D.velocity = newVelocity;
if (Input.GetKeyDown("space")) {
GetComponent<AudioSource>().Play();
Instantiate(harpoon_00001,transform.position,transform.rotation);
}
}
}
HARPOON SCRIPT
using UnityEngine;
using System.Collections;
public class harpoonScript : MonoBehaviour {
// Public variable
public int speed = 6;
private Rigidbody2D r2d;
// Function called once when the bullet is created
void Start () {
// Get the rigidbody component
r2d = GetComponent<Rigidbody2D>();
// Make the bullet move upward
float ySpeed = 0;
float xSpeed = -8;
Vector2 newVelocity = new Vector2(xSpeed, ySpeed);
r2d.velocity = newVelocity;
}
void Update () {
if (Input.GetKeyDown(KeyCode.LeftArrow)) {
float xSpeed = -8;
}
if (Input.GetKeyDown(KeyCode.RightArrow)) {
float xSpeed = 8;
}
}
void OnTriggerEnter2D(Collider2D other) //hero hits side of enemy
{
Destroy(other.gameObject.GetComponent<Collider2D>()); //Remove collider to avoid audio replaying
other.gameObject.GetComponent<Renderer>().enabled = false; //Make object invisible
Destroy(other.gameObject, 0.626f); //Destroy object when audio is done playing, destroying it before will cause the audio to stop
}
}
You already defining a variable facingRight to know the direction of the the player. You can use that knowledge to control the harpoon.
For example:
// this line creates a new object, which has harpoonScript attached to it.
// In unity editor, you drag and drop this prefab(harpoon_00001) into right place.
// transform.position is used for the starting point of the fire. You can also add +-some_vector3 for better placement
// Quaternion.identity means no rotation.
harpoonScript harpoon = Instantiate(harpoon_00001,transform.position, Quaternion.identity) as harpoonScript;
// Assuming harpoon prefab already facing to right
if (!facingRight) {
// Maybe, not required
harpoon.transform.eulerAngles = new Vector3(0f, 0f, 180f); // Face backward
Vector3 theScale = harpoon.transform.localScale;
theScale.y *= -1;
harpoon.transform.localScale = theScale; // Flip on y axis
}