I made a script for moving an object to the position indicated by the mouse click. If I don't choose to click to another location to move towards, I would like to stop my object if it reaches the previously mentioned position. However, the object doesn't stop when reaching the position and it continues moving.
Here is the code I wrote. I would be grateful if somebody knows how to fix this issue.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerController : MonoBehaviour
{
public float moveSpeed;
private Vector3 targetPos;
private Rigidbody2D rb;
private bool isMoving;
private Vector2 direction;
public float changeDirCooldown;
private float changeCool;
private bool canChangeDir;
void Start()
{
rb = GetComponent<Rigidbody2D>();
changeCool=changeDirCooldown;
canChangeDir =true;
}
void Update()
{
if (Input.GetMouseButton(0) && canChangeDir)
{
changeDirCooldown = changeCool;
SetTargetPosition();
}
if (changeDirCooldown<=0)
{
canChangeDir = true;
}
else
{
changeDirCooldown -= Time.deltaTime;
}
}
private void FixedUpdate()
{
if (isMoving)
{
Move();
}
if (this.transform.position == this.targetPos)
{
isMoving = false;
rb.velocity = Vector2.zero;
}
}
private void SetTargetPosition()
{
targetPos = Camera.main.ScreenToWorldPoint(Input.mousePosition);
targetPos.z = transform.position.z;
direction = targetPos - this.transform.position;
direction = direction.normalized;
isMoving = true;
}
private void Move()
{
rb.velocity = direction * moveSpeed;
canChangeDir = false;
}
}
It's probabily a problem with float number tolerance. This line
this.transform.position == this.targetPos
will almost never result to true, so instead you should do something like this:
Mathf.Abs(this.transform.position.x - this.targetPos.x) < float.Epsilon &&
Mathf.Abs(this.transform.position.y - this.targetPos.y) < float.Epsilon
Related
I'm working on a platformer game, and I instantiate my character after he gets hit by an enemy object. The problem is, my character is instantiating twice. Here's my code.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;
public class PlayerMove : MonoBehaviour
{
public GameObject player;
private Rigidbody2D rb;
private SpriteRenderer sprite;
private BoxCollider2D coll;
private Animator anim;
public float Speed;
public float JumpForce;
private float dirX = 0f;
private float fJumpPressedRemember = 0f;
private float fJumpPressedRememberTime = 0.2f;
[SerializeField] private LayerMask jumpableGround;
// Start is called before the first frame update
void Start()
{
rb = GetComponent<Rigidbody2D>();
anim = GetComponent<Animator>();
sprite = GetComponent<SpriteRenderer>();
coll = GetComponent<BoxCollider2D>();
}
// Update is called once per frame
void Update()
{
dirX = Input.GetAxisRaw("Horizontal");
rb.velocity = new Vector2(dirX * Speed, rb.velocity.y);
fJumpPressedRemember -= Time.deltaTime;
if (Input.GetButtonDown("Jump"))
{
fJumpPressedRemember = fJumpPressedRememberTime;
}
if ((fJumpPressedRemember > 0) && isGrounded())
{
fJumpPressedRemember = 0;
rb.velocity = new Vector2(rb.velocity.x, JumpForce);
}
UpdateAnimation();
}
private bool isGrounded()
{
return Physics2D.BoxCast(coll.bounds.center, coll.bounds.size, 0f, Vector2.down, .1f, jumpableGround);
}
void OnCollisionEnter2D(Collision2D spikeCol)
{
if (spikeCol.gameObject.tag.Equals("DamageDealer") == true)
{
Instantiate(player, new Vector3(-10, 1, 0), Quaternion.identity);
Destroy(player);
}
if (spikeCol.gameObject.tag.Equals("End") == true)
{
SceneManager.LoadScene("Level2", LoadSceneMode.Single);
}
if (spikeCol.gameObject.tag.Equals("End2") == true)
{
SceneManager.LoadScene("Level1", LoadSceneMode.Single);
}
}
private void UpdateAnimation()
{
if (dirX > 0f)
{
anim.SetBool("running", true);
sprite.flipX = false;
}
else if (dirX < 0f)
{
anim.SetBool("running", true);
sprite.flipX = true;
}
else
{
anim.SetBool("running", false);
}
}
}
It's supposed to instantiate once after dying. I don't know what's happening, but it only started after I added animation code, so I think that's the issue. Thanks to anyone who can help!
OnCollisionEnter2D is called twice.
Reasons why this can be described here: Why is OnCollisionEnter getting called twice?
You can add instantiate method double call check, like this:
private bool isInited;
void OnCollisionEnter2D(Collision2D spikeCol)
{
if (spikeCol.gameObject.tag.Equals("DamageDealer") == true)
{
if (isInited)
{
return;
}
isInited = true;
Instantiate(player, new Vector3(-10, 1, 0), Quaternion.identity);
Destroy(player);
}
...
}
I am trying to keep my character always idle-animated, even when User stretches his arm by pulling it with touchscreen. The character's arms are purely fists and body, with an obi rope in-between. Body animation works with obi-rope until any hand is being stretched,then the hand part of animation breaks, and it keeps moving but the hand is static. Same applies to another hand and legs :(
I don't know how to even describe it in 1 sentence, so googling didn't help me much. Please, help me out. I don't want to turn off animation when my character stretches arms, it look super artificial
If the code would be of any use:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class PlayerHit : MonoBehaviour
{
[SerializeField] private Image circleThisBodyPart;
private Vector3 startScale;
private Vector3 firstPosition;
private Vector3 lastPosition;
private Quaternion startRotation;
private bool isHit = false;
private bool isFirstAttack = true;
private int stage = 0;
private Vector3 posAfterMouseUp;
private void Start()
{
startRotation = transform.rotation;
startScale = transform.localScale;
firstPosition = transform.position;
}
private void LateUpdate()
{
if (isHit)
{
this.transform.rotation = startRotation;
this.transform.localScale = startScale;
if (stage == 1)
{
this.gameObject.transform.position = Vector3.MoveTowards(transform.position, new Vector3(lastPosition.x, lastPosition.y, lastPosition.z), 20f * Time.deltaTime);
if (this.transform.position == lastPosition)
{
stage = 2;
}
}
if (stage == 2)
{
this.gameObject.transform.position = Vector3.MoveTowards(transform.position, firstPosition, 20f * Time.deltaTime);
transform.localScale = startScale;
if (this.transform.position == firstPosition)
{
PlayerAttackBody.isAttack = false;
GlobalEvents.ShowPlayerCircles?.Invoke();
stage = 0;
}
}
}
}
private void OnMouseDown()
{
if (isFirstAttack)
{
GlobalEvents.StartGame?.Invoke();
isFirstAttack = false;
}
PlayerAttackBody.isAttack = true;
GlobalEvents.HidePlayerCircles?.Invoke(circleThisBodyPart);
GlobalEvents.ChangePosToCameraDistance?.Invoke(this.gameObject);
}
private void OnMouseDrag()
{
this.transform.localScale = startScale;
this.transform.rotation = startRotation;
}
private void OnMouseUp()
{
posAfterMouseUp = transform.position;
GlobalEvents.ChangePosToCameraDistance?.Invoke(null);
Vector3 currentPos = this.transform.position;
lastPosition = new Vector3(-currentPos.x, -currentPos.y+2.9f, -currentPos.z);
isHit = true;
stage = 1;
}
}
Please tell me, when I move the character with the joystick, the character will get stuck in a regular wall. What could be the problem?
Below is a video demonstration.
When moving with the buttons, the character does not get stuck.
https://www.youtube.com/watch?v=9SiQzLAq-kU
Thanks in advance)
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class MovePersonal : MonoBehaviour
{
public float speedMove;
public float jumpPower;
private float gravityForce;
private Vector3 moveVector;
private CharacterController ch_controller;
private Animator ch_animator;
private MobileController mContr;
// Start is called before the first frame update
private void Start()
{
ch_controller = GetComponent<CharacterController>();
ch_animator = GetComponent<Animator>();
mContr = GameObject.FindGameObjectWithTag("joy").GetComponent<MobileController>();
}
// Update is called once per frame
private void Update()
{
CharacterMove();
GamingGravity();
}
private void CharacterMove() {
if (ch_controller.isGrounded) {
moveVector = Vector3.zero;
moveVector.x = mContr.Horizontal() * speedMove;
moveVector.z = mContr.Vertical() * speedMove;
if(Vector3.Angle(Vector3.forward, moveVector)>1f || Vector3.Angle(Vector3.forward, moveVector) == 0) {
Vector3 direct = Vector3.RotateTowards(transform.forward, moveVector, speedMove, 0.0f);
transform.rotation = Quaternion.LookRotation(direct);
}
}
else {
}
moveVector.y = gravityForce;
ch_controller.Move(moveVector * Time.deltaTime);
}
private void GamingGravity() {
if (!ch_controller.isGrounded) gravityForce -=20f * Time.deltaTime;
else gravityForce = -1f;
if(Input.GetKeyDown(KeyCode.Space) && ch_controller.isGrounded) gravityForce = jumpPower;
}
}
I'm kind of new in the 2D environment of Unity.
I'm trying to create a platformer. For now, I have a simple map and my player.
My simple map and my player
My player have one script attached :
public class Player : MonoBehaviour
{
public float speed;
public float jump;
public GameObject raycastPoint; // Positioned at 0.01 pixel below the player
private SpriteRenderer spriteRenderer;
private Rigidbody2D body; // Gravity Scale of the Rigidbody2D = 50
private Animator animator;
private void Start()
{
spriteRenderer = GetComponent<SpriteRenderer>();
body = GetComponent<Rigidbody2D>();
animator = GetComponent<Animator>();
}
private void Update()
{
float horizontal = Input.GetAxisRaw("Horizontal");
if (horizontal == 1 && spriteRenderer.flipX)
{
spriteRenderer.flipX = false;
}
else if (horizontal == -1 && !spriteRenderer.flipX)
{
spriteRenderer.flipX = true;
}
body.velocity = new Vector2(horizontal * speed, body.velocity.y);
animator.SetFloat("Speed", Mathf.Abs(horizontal));
float vertical = Input.GetAxisRaw("Vertical");
if (vertical == 1)
{
RaycastHit2D hit = Physics2D.Raycast(raycastPoint.transform.position, Vector2.down, 0.01f);
if (hit.collider != null)
{
body.AddForce(new Vector2(0f, jump));
}
}
}
}
For now I have achieved the right and left movements.
For the jump, I have a child gameobject just under the player and I'm firing a raycast to the bottom so I can know if my player is grounded or not.
I have two problems.
PROBLEM NUMBER ONE.
Sometimes I feel like my "AddForce" line is executed multiple times my player is jumping really high
Problem number one image
PROBLEM NUMBER TWO.
When I'm jumping to the left or right wall, if I keep pressing the left or right key my player is not falling anymore and stay against the wall.
Problem number two image
I tried to put my code into the FixedUpdate method (I know it's better) but I had the same results.
And I tried to set the Collision Detection on Continuous but I had the same results.
Try this code for your first problem :
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
[RequireComponent(typeof(BoxCollider2D))]
[RequireComponent(typeof(Rigidbody2D))]
[RequireComponent(typeof(Animator))]
public class Player_Controller : MonoBehaviour {
private Rigidbody2D body;
private bool canJump, facingRight;
private Animator anim;
[SerializeField]
private float moveSpeed, jumpForce;
void Start ()
{
SetStartValues();
}
void FixedUpdate ()
{
float horizontal = Input.GetAxis("Horizontal");
animator.SetFloat("Speed", Mathf.Abs(horizontal));
Flip(horizontal);
Move(horizontal);
Jump();
}
private void SetStartValues()
{
body = GetComponent<Rigidbody2D>();
anim = GetComponent<Animator>();
canJump = true;
facingRight = true;
}
private void Jump()
{
if (Input.GetKeyDown(KeyCode.Space) && canJump)
{
body.AddForce(new Vector2(0, jumpForce));
canJump = false;
}
}
private void Move(float x)
{
body.velocity = new Vector2(x * moveSpeed * Time.deltaTime, body.velocity.y);
}
private void Flip(float x)
{
if (x > 0 && !facingRight|| x < 0 && facingRight)
{
facingRight = !facingRight;
transform.localScale = new Vector2(transform.localScale.x * -1, transform.localScale.y) ;
}
}
private void OnCollisionEnter2D(Collision2D collision)
{
if (collision.gameObject.tag == "Ground")
{
canJump = true;
}
}
}
And don't forget to put the "Ground" tag on your ground object.
How would I be able to set the speed for going forward and back in the Void FixedUpdate? Or is there a better way for doing this? I need to use the character controller though.
using UnityEngine;
using System.Collections;
public class CharacterControllerz : MonoBehaviour {
public float speed;
private CharacterController playerController;
void Start()
{
playerController = GetComponent<CharacterController>();
}
void Update()
{
}
void FixedUpdate()
{
if (Input.GetKey("right"))
{
playerController.Move (Vector3.forward);
Debug.Log ("RIGHT");
}
if (Input.GetKey("left"))
{
playerController.Move (Vector3.back);
Debug.Log ("LEFT");
}
playerController.Move (Vector3.left);
}
}
public float speed = 5f;
public float jumpStrenght = 8f;
public float gravity = 20f;
private Vector3 moveDirections = new Vector3();
private Vector3 inputs = new Vector3();
void FixedUpdate()
{
CharacterController cc = GetComponent<CharacterController>();
if (cc.isGrounded)
{
if (Input.GetKey("right"))
inputs.z = 1;
if (Input.GetKey("left"))
inputs.z = -1;
if (Input.GetKey("up"))
inputs.y = jumpStrenght;
moveDirections = transform.TransformDirection(inputs.x, 0, inputs.z) * speed;
}
moveDirections.y = inputs.y - gravity;
cc.Move(moveDirections * Time.deltaTime);
}
I think that's what you want but you may have to switch the axis.
Edit: Why is TransformDirection used? Because we want to move the object in a direction which shouldn't be relativ to the object's rotation.