very basic 2.5d rope physics - c#

So I want to make a 2.5d grappling rope that lets the player swing around objects for quicker turning, but the code that I wrote doesn't work. The player just stops all velocity after a short amount of time.
public Transform player;
private float tikTok;
public LayerMask layerMask;
Vector3 tetherPoint;
Transform tetherObject;
Vector3 currentTether;
float tetherLength;
bool isTethered;
Vector3 previousPlayerPosition;
if (Input.GetKey(KeyCode.Space) && Time.time >= tikTok && !isTethered) {
// this part works fine and dandy
Ray ray = new Ray(player.position, player.forward);
if (Physics.Raycast(ray, out RaycastHit hit, float.MaxValue, layerMask)) {
tetherPoint = hit.point;
tetherObject = hit.transform;
currentTether = tetherObject.position;
tetherLength = Vector3.Distance(player.position, tetherPoint);
isTethered = true;
}
} else if (isTethered && Input.GetKey(KeyCode.Space)) {
// this part does not
if (Vector3.Distance(player.position, tetherPoint) > tetherLength) {
player.position -= (Vector3.Distance(player.position, tetherPoint) - tetherLength) * (player.position - tetherPoint).normalized;
print((player.position - previousPlayerPosition).normalized);
player.gameObject.GetComponent<Rigidbody>().velocity = player.gameObject.GetComponent<Rigidbody>().velocity.magnitude * (player.position - previousPlayerPosition).normalized;
}
} else if (isTethered && !Input.GetKey(KeyCode.Space)) {
isTethered = false;
tetherPoint = Vector3.zero;
tetherObject = null;
currentTether = Vector3.zero;
tetherLength = 0;
}
if (tetherObject != null) {
if (currentTether != tetherObject.position) {
tetherPoint += currentTether - tetherObject.position;
currentTether = tetherObject.position;
}
}
previousPlayerPosition = player.position;```

Related

How to make the player to look at multiple targets depending on the closest target using Inverse Kinematics (IK)?

In lookObjects I have two cubes and each cube is rotating around the player in a different speed, but the player is looking only the second cube in the list lookObjects and never looking at the first cube.
I want that the player will know to switch between the lookObjects depending on the one that is closest because now even if the second cube is behind the player and he is not looking at it it's not switching to the first cube that is in front of the player at the moment.
The logic should be that if one of the cube is out of the player sight switch to the other one if the other one is in the player sight.
why it's not switching between lookObjects?
what to do if both cubes(lookObjects) are in front of the player how to decide on which one to look at ? what should be the logic in that case?
The code is attached to the player:
using UnityEngine;
using System;
using System.Collections;
using System.Collections.Generic;
[RequireComponent(typeof(Animator))]
public class IKTests : MonoBehaviour
{
public Transform finger;
public List<Transform> lookObjects = new List<Transform>();
public float weightDamping = 1.5f;
private Animator animator;
private Transform lastPrimaryTarget;
private float lerpEndDistance = 0.1f;
private float finalLookWeight = 0;
private bool transitionToNextTarget = false;
void Start()
{
animator = GetComponent<Animator>();
}
private void Update()
{
}
private void OnDrawGizmos()
{
if (finger != null && lookObjects != null && lookObjects.Count > 0)
{
Gizmos.color = Color.green;
Gizmos.DrawLine(finger.position, lookObjects[0].position);
}
}
// Callback for calculating IK
void OnAnimatorIK()
{
if (lookObjects != null)
{
Transform primaryTarget = null;
float closestLookWeight = 0;
// Here we find the target which is closest (by angle) to the players view line
foreach (Transform target in lookObjects)
{
Vector3 lookAt = target.position - transform.position;
lookAt.y = 0f;
float dotProduct = Vector3.Dot(new Vector3(transform.forward.x, 0f, transform.forward.z).normalized, lookAt.normalized);
float lookWeight = dotProduct;
closestLookWeight = float.MinValue;
if (lookWeight > closestLookWeight)
{
primaryTarget = target;
}
animator.SetIKPositionWeight(AvatarIKGoal.RightHand, 1);
animator.SetIKRotationWeight(AvatarIKGoal.RightHand, 1);
animator.SetIKPosition(AvatarIKGoal.RightHand, target.position);
animator.SetIKRotation(AvatarIKGoal.RightHand, target.rotation);
}
if (primaryTarget != null)
{
if ((lastPrimaryTarget != null) && (lastPrimaryTarget != primaryTarget) && (finalLookWeight > 0f))
{
// Here we start a new transition because the player looks already to a target but
// we have found another target the player should look at
transitionToNextTarget = true;
}
}
// The player is in a neutral look position but has found a new target
if ((primaryTarget != null) && !transitionToNextTarget)
{
lastPrimaryTarget = primaryTarget;
finalLookWeight = Mathf.Lerp(finalLookWeight, closestLookWeight, Time.deltaTime * weightDamping);
float bodyWeight = finalLookWeight * .75f;
animator.SetLookAtWeight(0.5f, 0.5f, 1f);//finalLookWeight, bodyWeight, 1f);
animator.SetLookAtPosition(primaryTarget.position);
}
// Let the player smoothly look away from the last target to the neutral look position
if ((primaryTarget == null && lastPrimaryTarget != null) || transitionToNextTarget)
{
finalLookWeight = Mathf.Lerp(finalLookWeight, 0f, Time.deltaTime * weightDamping);
float bodyWeight = finalLookWeight * .75f;
animator.SetLookAtWeight(0.5f, 0.5f, 1f);//finalLookWeight, bodyWeight, 1f);
animator.SetLookAtPosition(lastPrimaryTarget.position);
if (finalLookWeight < lerpEndDistance)
{
transitionToNextTarget = false;
finalLookWeight = 0f;
lastPrimaryTarget = null;
}
}
}
}
}
Create a for loop
Use Vector3.Distance(Transform A, Transform B) on every Transform to get the look order
then you can use transform.LookAt(Transform target) to look at the object

Rotate Object Smoothly

i am trying to rotate object to 90 degrees smoothly on swipe here in my code its rotate instantly, how do i rotate object smoothly at given speed.
void Update()
{
if (fingerDown == false && Input.GetMouseButtonDown(0))
{
startPos = Input.mousePosition;
fingerDown = true;
}
if (fingerDown)
{
if (Input.mousePosition.x >= startPos.x + pixelDistToMove)
{
startPos = Input.mousePosition;
Vector3 rotationToAdd = new Vector3(0, 0, 90);
transform.Rotate(rotationToAdd);
fingerDown = false;
}
if (Input.mousePosition.x <= startPos.x - pixelDistToMove)
{
startPos = Input.mousePosition;
Vector3 rotationToAdd = new Vector3(0, 0, -90);
transform.Rotate(rotationToAdd);
fingerDown = false;
}
}
if (fingerDown && Input.GetMouseButtonUp(0))
{
fingerDown = false;
}
}
Thank you
transform.Rotate() rotates the object without animating it's rotation.
If you want it to rotate smoothly, you have to implement either an animation, or a turning state, or an IEnumerator.
My C# is a bit rusty, but I cooked this up:
public Vector3 desired_angle = Vector3.zero; // Turn the Gameobject to this angle
public float turn_time = 1f; // How long should turning take
public float rate = 60;
private void Update ()
{
if (Input.GetKeyDown(KeyCode.Space))
{
StartCoroutine(TurnTo());
}
}
IEnumerator TurnTo ()
{
Vector3 original_angle = transform.rotation.eulerAngles;
for (float i = 0f; i < 1f + turn_time / rate; i += turn_time / rate)
{
transform.rotation = Quaternion.Euler(Vector3.Lerp(original_angle, desired_angle, i));
yield return new WaitForSeconds(turn_time/rate);
}
}

Move Object Using Raycast

I am trying to move the y position of a UI element in it's local space by clicking and dragging with the SteamVR controller and a raycast. I am getting what appear to me to be unpredictable results.
I am trying to get the position of the raycast at the start of the drag and move it the distance between where it is and where it was started while dragging.
Here is my code:
if (hit.transform.name == "Content" && scrollSet == false)
{
content = hit.transform;
scrollSet = true;
scrollPos = hit.transform.position ;
}
if (scrollSet == true)
{
if (rController.triggerPressed)
{
y = hit.transform.position.y - scrollPos.y;
content.transform.localPosition = new Vector3(content.transform.localPosition.x, content.localPosition.y + y, content.transform.localPosition.z);
}
else
{
scrollSet = false;
}
}
you can convert the .MovePosition to .MoveTowards. But it still jumped around. It turns out that the code was only executing during the frame in which you right-clicked, so move it out of the if statement.
Here's the entire script placed into the main camera. You always need to have a target selected, so to prevent errors you need to put a gameObject with a rigidbody into "bTarg".
public class ClickTarget : MonoBehaviour {
private GameObject target; private Vector3 destination; private float distance; private Vector3 tTrans;
public GUIText targetDisplay; public float speed; public GameObject bTarg;
void Start () { targetDisplay.text = ""; distance = 0.0f; target = bTarg; }
void Update () { if(Input.GetButtonDown("Fire1")){ Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition); RaycastHit hit; if(Physics.Raycast(ray, out hit)){ if(hit.collider != null){ if(hit.collider.tag == "Unit"){ target = hit.collider.gameObject; targetDisplay.text = "Unit: " + hit.collider.gameObject.name; destination = target.transform.position; target.rigidbody.freezeRotation = false; } if(hit.collider.tag == "Building"){ target = hit.collider.gameObject; targetDisplay.text = "Building: " + hit.collider.gameObject.name; } } } } }
void FixedUpdate(){ if (Input.GetButtonDown ("Fire2") && target.tag == "Unit" && GUIUtility.hotControl == 0) { Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition); RaycastHit hit; if(Physics.Raycast(ray,out hit)){ destination = hit.point; } }
tTrans = target.transform.position;
distance = Vector3.Distance (tTrans, destination);
if(target.tag == "Unit"){
if (distance > .2f) {
target.transform.LookAt (destination);
target.transform.position = Vector3.MoveTowards (target.transform.position, destination, speed);
target.rigidbody.freezeRotation = true;
}
}
} }

touch control to move cube (in an array that generates them) left and right

I am moving an object that consists of two cubes: left and right. These cubes are randomly generated on the y-axis upwards.
I am able to move them left and right with no problem, however, when I move one of the cubes left or right they all move.
How am I able to only move one of the cubes when touched only left or right rather than all of them? Here is my code below:
Generate cubes code:
public Transform block;
public Transform player;
private float objectSpawnedTo = 5.0f;
public static float distanceBetweenObjects = 5.0f;
private float nextCheck = 0.0f;
private ArrayList objects = new ArrayList();
void Start () {
maintenance(0.0f);
}
void Update () {
float playerX = player.position.y;
if(playerX > nextCheck)
{
maintenance(playerX);
}
}
private void maintenance(float playerX)
{
nextCheck = playerX + 30;
for (int i = objects.Count-1; i >= 0; i--)
{
Transform blck = (Transform)objects[i];
if(blck.position.y < (transform.position.y - 30))
{
Destroy(blck.gameObject);
objects.RemoveAt(i);
}
}
spawnObjects(5);
}
private void spawnObjects(int howMany)
{
float spawnX = objectSpawnedTo;
for(int i = 0; i<howMany; i++)
{
Vector3 pos = new Vector3(-3.5f,spawnX, 0);
//float firstRandom = Random.Range(-6.0f, 1.0f);
Transform blck = (Transform)Instantiate(block, pos, Quaternion.identity);
//blck.localScale+=new Vector3(firstRandom*2,0,0);
objects.Add(blck);
//pos = new Vector3(0,spawnX, 0);
//blck = (Transform)Instantiate(block, pos, Quaternion.identity);
//blck.localScale +=new Vector3((8.6f-firstRandom)*2,0,0);
//objects.Add(blck);
spawnX = spawnX + distanceBetweenObjects;
}
objectSpawnedTo = spawnX;
}
}
Cube-control code:
public float speed = 5;
// Use this for initialization
void Start () {
}
void Update() {
if (Input.touchCount > 0 && Input.GetTouch(0).phase == TouchPhase.Moved) {
// Get movement of the finger since last frame
Vector3 touchDeltaPosition = Input.GetTouch(0).deltaPosition;
// Move object across XY plane
transform.Translate(touchDeltaPosition.x * speed, 0, 0);
Vector3 boundaryVector = transform.position;
boundaryVector.x = Mathf.Clamp (boundaryVector.x, -5.5f, -2.8f);
transform.position = boundaryVector;
}
}
}
The problem is your cube-control code has no condition in it about which cube is selected : you simply wait for Input.touchCount to be > 0 and then move the cube. So all the cube having this script will move.
I think what you need to do is a raycast to check which cube has been "touched" and then only move it if raycast is successful :
[SerializeField]
private float speed = 0.5f;
private int MAX_TOUCH_COUNT = 5;
private bool[] touched;
protected void Start()
{
touched = new bool[MAX_TOUCH_COUNT];
}
void Update()
{
if (Input.touchCount > 0)
{
for(int i = 0; i < (Input.touchCount <= MAX_TOUCH_COUNT ? Input.touchCount : MAX_TOUCH_COUNT); i++)
{
if(touched[i] && Input.GetTouch(i).phase == TouchPhase.Ended)
{
touched[i] = false;
}
else if (!touched[i] && Input.GetTouch(i).phase == TouchPhase.Began)
{
Ray ray = Camera.main.ScreenPointToRay(Input.GetTouch(i).position);
RaycastHit hitInfo;
if (Physics.Raycast(ray, out hitInfo))
{
if (hitInfo.transform.GetComponentInChildren<*YOUR_CUBE_CONTROL_CLASS_NAME*>() == this)
{
touched[i] = true;
}
}
}
else if (touched[i] && Input.GetTouch(i).phase == TouchPhase.Moved)
{
// Get movement of the finger since last frame
Vector3 touchDeltaPosition = Input.GetTouch(i).deltaPosition;
// Move object across XY plane
transform.Translate(touchDeltaPosition.x * speed, 0, 0);
Vector3 boundaryVector = transform.position;
boundaryVector.x = Mathf.Clamp (boundaryVector.x, -5.5f, -2.8f);
transform.position = boundaryVector;
}
}
else
{
touched = false;
}
}
}
Hope this help,

Moving object along a raycast in unity using c#

I want to move an object along a ray gradually,
I have the following code so far which moves it in 1 frame to the destination rather than smoothly gliding there.
If I remove the Destroy(projectile.rigidbody2D) line from the end it sort of does it but then bounces around all over the place?
Any help would be much appreciated!
void Update ()
{
if (Input.GetMouseButtonUp (1)) {
if (Hand.transform.childCount == 1){
projectile.gameObject.transform.parent = null;
Ray ray = new Ray(spawn.position,spawn.up);
RaycastHit hit;
float shotDistance = shotdistance;
if (Physics.Raycast(ray,out hit, shotDistance)) {
shotDistance = hit.distance;
}
projectile.AddComponent<Rigidbody2D>();
projectile.rigidbody2D.gravityScale = 0;
projectile.rigidbody2D.AddForce(Vector2.up * 5);
projectile.transform.position = Vector3.MoveTowards(projectile.transform.position,ray.direction * shotDistance,shotDistance);
Debug.DrawRay(ray.origin,ray.direction * shotDistance,Color.red,1);
Destroy(projectile.rigidbody2D);
}
}
}
private float lerpValue = 0;
public float speed;
private Vector3 startPosition;
private bool isMoving;
void Update ()
{
if (Input.GetMouseButtonUp (1))
{
if (Hand.transform.childCount == 1)
{
lerpValue = 0;
startPosition = projectile.transform.position;
projectile.gameObject.transform.parent = null;
Ray ray = new Ray(spawn.position,spawn.up);
RaycastHit hit;
float shotDistance = shotdistance;
if (Physics.Raycast(ray,out hit, shotDistance) && !isMoving)
{
isMoving = true;
shotDistance = hit.distance;
//speed = distance / time
//therefore: time = distance / speed
float time = shotDistance / speed;
StartCoroutine(ProjectileMotion(hit.point, time));
}
}
}
}
IEnumerator ProjectileMotion(Vector3 endPosition, float time)
{
while(lerpValue < time)
{
lerpValue += Time.deltaTime;
projectile.transform.position = Vector3.Lerp(startPosition, endPosition, lerpValue / time);
}
isMoving = false;
}

Categories