Char animation breaks when trying to manipulate one arm with Obi Rope in Unity(mobile game) - unity3d

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;
}
}

Related

The character freezes near the wall unity3d

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;
}
}

How to select an object to be picked up whenever the camera is pointed to that object?

I'm trying to pick up objects in unity. I have a gameObject called LookObject. Whenever the camera points to an object, the name of that object will be stored in LookObject, then when I press Space the object gets picked up. it is working but not completely. The issue I'm facing is that when I look at an object then look at another direction, the lookObject still shows the name of the object I was looking at (it doesn't update).
please see this image:
as shown in the image, the reticle is not pointing to the object. but it is still showing Cube as the Look Object.
Here is PlayerInteractions class:
GameObject[] targetObjects;
List<GameObject> targetObjectsList;
[Header("InteractableInfo")]
public float sphereCastRadius = 0.5f;
public int interactableLayerIndex;
private Vector3 raycastPos;
public GameObject lookObject;
private PhysicsObjects physicsObject;
private Camera mainCamera;
public GameObject winUI;
private InteractiveObjects interactiveObjects;
[Header("Pickup")]
[SerializeField] private Transform pickupParent;
public GameObject currentlyPickedUpObject;
private Rigidbody pickupRB;
[Header("ObjectFollow")]
[SerializeField] private float minSpeed = 0;
[SerializeField] private float maxSpeed = 300f;
[SerializeField] private float maxDistance = 8f;
private float currentSpeed = 0f;
private float currentDist = 0f;
[Header("Rotation")]
public float rotationSpeed = 100f;
// Quaternion lookRot;
[SerializeField] GameObject TargetsCanvas;
static bool strikeThrough = false;
private void Start()
{
mainCamera = Camera.main;
targetObjects = GameObject.FindGameObjectsWithTag("TargetObj");
targetObjectsList = new List<GameObject>();
foreach (var obj in targetObjects)
{
var mytext = CreateText(TargetsCanvas.transform);
mytext.text = "• Find The " + obj.name;
Debug.Log(""+ obj.name);
}
}
//A simple visualization of the point we're following in the scene view
private void OnDrawGizmos()
{
Gizmos.color = Color.yellow;
Gizmos.DrawSphere(pickupParent.position, 0.5f);
}
void Update()
{
//Here we check if we're currently looking at an interactable object
raycastPos = mainCamera.ScreenToWorldPoint(new Vector3(Screen.width / 2, Screen.height / 2, 0));
RaycastHit hit;
if (Physics.SphereCast(raycastPos, sphereCastRadius, mainCamera.transform.forward, out hit, maxDistance, 1 << interactableLayerIndex))
{
lookObject = hit.collider.transform.gameObject;
}
//if we press the button of choice
if (Input.GetKeyDown(KeyCode.Space))
{
//and we're not holding anything
if (currentlyPickedUpObject == null)
{
//and we are looking an interactable object
if (lookObject != null )
{
PickUpObject();
if (!targetObjectsList.Contains(lookObject.gameObject))
{
targetObjectsList.Add(lookObject.gameObject);
if (targetObjectsList.Count == targetObjects.Length)
{
// Time.timeScale = 0f;
// winUI.SetActive(true);
// SceneManager.LoadScene(SceneManager.GetActiveScene().buildIndex + 1);
// Time.timeScale = 1f;
}
}
}
}
//if we press the pickup button and have something, we drop it
else
{
BreakConnection();
}
}
}
private void FixedUpdate()
{
if (currentlyPickedUpObject != null)
{
currentDist = Vector3.Distance(pickupParent.position, pickupRB.position);
currentSpeed = Mathf.SmoothStep(minSpeed, maxSpeed, currentDist / maxDistance);
currentSpeed *= Time.fixedDeltaTime;
Vector3 direction = pickupParent.position - pickupRB.position;
pickupRB.velocity = direction.normalized * currentSpeed;
//Rotation//
// lookRot = Quaternion.LookRotation(mainCamera.transform.position - pickupRB.position);
// lookRot = Quaternion.Slerp(mainCamera.transform.rotation, lookRot, rotationSpeed * Time.fixedDeltaTime);
// pickupRB.MoveRotation(lookRot);
}
}
//Release the object
public void BreakConnection()
{
pickupRB.constraints = RigidbodyConstraints.None;
currentlyPickedUpObject = null;
lookObject = null;
physicsObject.pickedUp = false;
currentDist = 0;
}
public void PickUpObject()
{
physicsObject = lookObject.GetComponentInChildren<PhysicsObjects>();
currentlyPickedUpObject = lookObject;
pickupRB = currentlyPickedUpObject.GetComponent<Rigidbody>();
pickupRB.constraints = RigidbodyConstraints.FreezeRotation;
physicsObject.playerInteractions = this;
}
Here is the code attached to objects:
public float waitOnPickup = 0.2f;
public float breakForce = 35f;
[HideInInspector] public bool pickedUp = false;
[HideInInspector] public PlayerInteractions playerInteractions;
private void OnCollisionEnter(Collision collision)
{
if (pickedUp)
{
if (collision.relativeVelocity.magnitude > breakForce)
{
playerInteractions.BreakConnection();
}
}
}
//this is used to prevent the connection from breaking when you just picked up the object as it sometimes fires a collision with the ground or whatever it is touching
public IEnumerator PickUp()
{
yield return new WaitForSecondsRealtime(waitOnPickup);
pickedUp = true;
}
Here is an image of the object inspector:
how can I make it accurately showing the objects I'm looking at?
A simple fix for this would be to set lookObject to null if the SphereCast returns false since that would indicate you are no longer looking at a valid object. Simply adding else lookObject = null; to the end of the first if statement in your Update() method should do the trick.

Creating top down 2D whip mechanic

What Whip should look like
I'm trying to create a whip that can extend in any direction the mouse is facing after pressing a certain button. If there are "grabbable" objects in the way such as an enemy or box, it should latch onto those objects and pull them around to collide with other objects for a certain amount of time.
I know that I need the different sprite shots of the whip extending and latching for animation, but I have no idea how to implement this in code and how to get the whip to stop short if it detects a "grabbable" object.
Attach this script to your player, this should get the job done:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Player : MonoBehaviour
{
public Transform player = null;
public float speed = 30f;
public string grabbableTag = "grabbable";
private LineRenderer line = null;
private float timer = 0f;
private bool grabbing = false;
private bool reached = false;
private Vector2 from = Vector2.zero;
private Vector2 to = Vector2.zero;
private Vector2 target = Vector2.zero;
private Transform grabbable = null;
private void Start()
{
player = transform;
line = new GameObject("Line").AddComponent<LineRenderer>();
line.startColor = Color.red;
line.endColor = Color.red;
// Assign a material
line.gameObject.SetActive(false);
reached = false;
grabbing = false;
}
private void Update()
{
if(grabbing)
{
Grabbing();
}
else
{
if (Input.GetMouseButtonDown(0))
{
Grab();
}
}
}
private void Grab()
{
Vector3 mousePosition = Input.mousePosition;
mousePosition.z = Vector3.Distance(player.position, Camera.main.transform.position);
to = Camera.main.ScreenToWorldPoint(mousePosition);
from = player.position;
Vector2 direction = (to - from).normalized;
float distance = Vector2.Distance(from, to);
RaycastHit2D[] hits = Physics2D.RaycastAll(from, direction, distance);
grabbable = null;
for (int i = 0; i < hits.Length; i++)
{
if (hits[i].transform.tag == grabbableTag)
{
grabbable = hits[i].transform;
break;
}
}
if (grabbable != null)
{
distance = Vector2.Distance(player.position, grabbable.position);
to = from + direction * distance;
}
grabbing = true;
reached = false;
target = from;
timer = 0;
line.gameObject.SetActive(true);
line.positionCount = 2;
line.SetPosition(0, from);
line.SetPosition(1, from);
}
private void Grabbing()
{
if (reached)
{
target = Vector2.Lerp(target, from, speed * Time.deltaTime);
if (target == from)
{
GrabDone(grabbable);
grabbing = false;
line.gameObject.SetActive(false);
}
}
else
{
target = Vector2.Lerp(target, to, speed * Time.deltaTime);
if(target == to)
{
reached = true;
}
}
line.SetPosition(1, target);
if (reached && grabbable != null)
{
grabbable.position = target;
}
}
private void GrabDone(Transform grabbed)
{
if(grabbed != null)
{
// Do somthing ...
Destroy(grabbed.gameObject);
}
}
}

Problem with my object that does not stop moving

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

Unity: Touch Delay is too high

I want to make a game, where you can throw items in 2D via drag and drop. This works fine, but the tracking of grabbing them is very bad. If I touch them in the top half the tracking won't or barely work.
Are there other methods to prevent this?
public class DropsBehaviour : MonoBehaviour {
//Declaring Variables
public int force = 10;
float maxSpeedPreset = 5;
float maxSpeed = 5;
float MaxThrowSpeed = 8;
GameManager gm;
Rigidbody rig;
Camera cam;
bool selected = false;
bool once = false;
void Start() {
gm = GameManager.FindMe();
rig = GetComponent<Rigidbody>();
cam = Camera.main;
}
void Update() {
if (selected) {
rig.AddForce((cam.ScreenToWorldPoint(Input.mousePosition) - transform.position) * force);
rig.velocity = Vector3.zero;
} else {
if (!once) {
maxSpeed = maxSpeedPreset * gm.gameSpeed;
rig.velocity = new Vector3(Mathf.Clamp(rig.velocity.x, -maxSpeed, maxSpeed), Mathf.Clamp(rig.velocity.y, -maxSpeed, maxSpeed), Mathf.Clamp(rig.velocity.z, -maxSpeed, maxSpeed));
} else {
maxSpeed = maxSpeedPreset;
rig.velocity = new Vector3(Mathf.Clamp(rig.velocity.x, -MaxThrowSpeed, MaxThrowSpeed), Mathf.Clamp(rig.velocity.y, -MaxThrowSpeed, MaxThrowSpeed), Mathf.Clamp(rig.velocity.z, -MaxThrowSpeed, MaxThrowSpeed));
}
}
}
void OnMouseDown() {
if (tag != "NoInteract") {
selected = true;
once = true;
}
}
void OnMouseUp() {
selected = false;
}
}
I see quite a few issues in the code snippet you posted that could cause stuttering.
First, if you are making something in 2D, it's recommended to use Rigidbody2D and Collider2D.
Then, you shouldn't edit a rigidbody's velocity by hand, as stated in the doc. That's what add force is made for.
When updating anything related to physics, you should do it in FixedUpdate, not Update.
I assume you also forgot to put " once = false " on the first pass ? Really not sure about this one.
I edited your script following the points stated before, while keeping the rigidbody 3D. I dind't tested it, but hopefully it will correct the weird drag behavior you're experiencing! (note that I removed the GameManager part since i can't know what it does)
public class DropsBehaviour : MonoBehaviour
{
public int force = 10;
private const float MaxSpeedPreset = 5;
private float _maxSpeed = 5;
private const float MaxThrowSpeed = 8;
private Rigidbody _rig;
private Camera _cam;
private bool _selected;
private bool _once;
private Vector3 _targetVelocity;
private void Start()
{
_rig = GetComponent<Rigidbody>();
_cam = Camera.main;
}
private void Update()
{
if (_selected) return;
if (!_once)
{
_maxSpeed = MaxSpeedPreset * 10;
_targetVelocity = new Vector3(Mathf.Clamp(_rig.velocity.x, -_maxSpeed, _maxSpeed),
Mathf.Clamp(_rig.velocity.y, -_maxSpeed, _maxSpeed),
Mathf.Clamp(_rig.velocity.z, -_maxSpeed, _maxSpeed));
}
else
{
_maxSpeed = MaxSpeedPreset;
_targetVelocity = new Vector3(Mathf.Clamp(_rig.velocity.x, -MaxThrowSpeed, MaxThrowSpeed),
Mathf.Clamp(_rig.velocity.y, -MaxThrowSpeed, MaxThrowSpeed),
Mathf.Clamp(_rig.velocity.z, -MaxThrowSpeed, MaxThrowSpeed));
_once = false; //Dunno if it's intended or not ?
}
}
private void FixedUpdate()
{
if (_selected)
{
_rig.AddForce((_cam.ScreenToWorldPoint(Input.mousePosition) - transform.position) * force);
_rig.velocity = Vector3.zero;
return;
}
var velocity = _rig.velocity;
var velocityChange = _targetVelocity - velocity;
_rig.AddForce(velocityChange, ForceMode.VelocityChange);
}
private void OnMouseDown()
{
if (CompareTag("NoInteract")) return;
_selected = true;
_once = true;
}
private void OnMouseUp()
{
_selected = false;
}
}
On a side note, I personnaly don't like tags, I would use a LayerMask instead since it's somewhat related to physics. I'd probably replace the OnMouse events with a Raycast too, that way you would have a lot more control on what is happening on the physic side.