void HandleMouse()
{
if(Input.GetMouseButton(0))
{
if(isTouching)
{
HandleDragging();
}
}
else
{
isTouching = false;
ResetKnob();
}
}
void HandleTouches()
{
}
protected virtual void HandleDragging()
{
//Get the target position for the knob
Vector2 wantedPosition = Vector2.zero;
RectTransformUtility.ScreenPointToLocalPointInRectangle(bounds, Input.mousePosition, null, out wantedPosition);
knob.anchoredPosition = Vector2.Lerp(knob.anchoredPosition, wantedPosition, Time.deltaTime * dragSpeed);
//Find the normalized Delta for the Knob
float xDelta = knob.anchoredPosition.x / (bounds.rect.width * 0.5f);
float yDelta = knob.anchoredPosition.y / (bounds.rect.height * 0.5f);
finalDelta = new Vector2(xDelta, yDelta);
finalDelta = Vector2.ClampMagnitude(finalDelta, 1f);
}
void ResetKnob()
{
knob.anchoredPosition = Vector2.Lerp(knob.anchoredPosition, Vector2.zero, Time.deltaTime * resetSpeed);
finalDelta = Vector2.zero;
}
I am trying to move a throttle up and down in the 3d space .I am using a 3d throttle object in side the cockpit to move up and down using mouse point i tried for moving the 2d sprite using above code it works fine but not working for moving a 3d throttle object.
spri
Mathf.Lerp(inputvalue, -10f, 10f);
I think your error is you are trying to interpolate your input to 10, when the Lerp function can only interpolate [0,1], Mathf.Lerp
You need to call it as Mathf.Lerp(-10, 10, inputValue);
Once you get the interpolation value just add that to the translation
var value = Mathf.Lerp(-10, 10, inputValue);
transform.position += Vector3.forward * value;
Find out how far your throttle is:
Vector2 throttleDownPosition = Vector2.zero; // Or whatever it is. I can't tell from your code.
Vector2 throttleUpPosition = new Vector2(0f,1f); // Or whatever it is. I can't tell from your code.
Vector2 throttleCurrentPosition = knob.anchoredPosition;
// Calculate ratio between current throttle / full throttle
float throttlePercentage =
Vector2.Distance(throttleCurrentPosition, throttleDownPosition)
/ Vector2.Distance(throttleUpPosition, throttleDownPosition);
Then, using what position and rotation your 3D throttle object should be when throttle is at 0%:
Vector3 startPosition
Quaternion startRotation
as well as the position and rotation your 3D throttle object should be when throttle is at 100%:
Vector3 endPosition
Quaternion endRotation
you can use Vector3.Lerp and Quaternion.Lerp to find the appropriate position and rotation for the current throttle setting:
Vector3 lerpedPosition = Vector3.Lerp(startPosition, endPosition, throttlePercentage);
Quaternion lerpedRotation = Quaternion.Lerp(startRotation, endRotation, throttlePercentage);
throttleObject.transform.position = lerpedPosition;
throttleObject.transform.rotation = lerpedRotation
Related
I'm really struggling with this. I have a turret that is mounted on a spaceship. It's a child object of the ship. The turret is allowed to point left, right, up, but not down, because that would be pointing through the spaceship.
So, I need to limit the rotation of the turret so it won't point down. I started with this code:
`
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class TurretScriptTest : MonoBehaviour
{
public float rotateSpeedBase = 1f;
public float rotateSpeedCurr = 1f;
public float yMin = 0;
public float yMax = 1;
public Transform target;
// Start is called before the first frame update
void Start()
{
rotateSpeedCurr = rotateSpeedBase;
}
// Update is called once per frame
void Update()
{
if (target && target.gameObject.activeSelf)
{
// Rotate
RotateWithLock();
}
}
public virtual void RotateWithLock()
{
if (target)
{
Vector3 targetDir = target.position - transform.position;
float step = rotateSpeedCurr * Time.deltaTime;
Vector3 newDir = Vector3.RotateTowards(transform.forward, targetDir, step, 0.0f);
newDir.y = Mathf.Clamp(newDir.y, yMin, yMax);
transform.rotation = Quaternion.LookRotation(newDir);
}
}
}
`
This works great except for one thing. The spaceship is also rotating all over the place. As soon as the parent spaceship goes off its original axis the above code is worthless. The turret will point through the spaceship or whatever else is in the way.
I'm assuming that what I need to do is convert everything to local rotation and position so that "down" for the turret will always be its base, not "down" in world space. So I try this code:
`
public virtual void RotateWithLock()
{
if (target)
{
Vector3 targetDir = target.position - transform.position;
float step = rotateSpeedCurr * Time.deltaTime;
Vector3 newDir = Vector3.RotateTowards(transform.forward, targetDir, step, 0.0f);
Vector3 newDirLocal = transform.InverseTransformDirection(newDir);
newDirLocal.y = Mathf.Clamp(newDirLocal.y, yMin, yMax);
transform.localRotation = Quaternion.LookRotation(newDirLocal);
}
}
`
Now the turret doesn't move at all. What to do?
If your turret's gun is a child of the turret's base, then you can just use "transform.localRotation" to get the rotation relative to the base.
If not, then try this:
If you have the Transform of the base, then you can use "Quaternion.Inverse" to get the inverse of the base's rotation. Then just take the LookRotation and multiply it by this inverse (Quaternion1 * Quaternion2 just adds them together). To convert that to a Direction Vector for the clamp calculations, just do "Quaternion * new Vector3(0, 0, 1)"
Vector3 targetDir = target.position - transform.position;
//Gets rotation to the target
Quaternion rotToTarget = Quaternion.LookRotation(newDirLocal);
float step = rotateSpeedCurr * Time.deltaTime;
//Gets new rotation
Quaternion newRot = Quaternion.RotateTowards(transform.rotation, rotToTarget, step);
//Gets the local rotation by adding (yes adding) the inverse of the base rotation
//Make sure to set the turretBase variable to the turret base's GameObject
newRot = newRot * Quaternion.Inverse(turretBase.transform.rotation);
//Gets a vector that points to the direction
Vector3 dirFromRot = newRot * new Vector3(0, 0, 1);
//This sets the y-limit. The yLimit should be less than 1.
//I am using your code, but a more effective way would be to limit the angle of the quaternion.
dirFromRot.y = Mathf.Clamp(dirFromRot.y, -yLimit, yLimit);
//Gets the LookRotation of this clamped Vector3 and sets the result.
transform.localRotation = Quaternion.LookRotation(dirFromRot.normalized);
I'm new to Raycasting so I might be going about this in a bad way, but I would to send a raycast outward to direction a gameobject is facing, bounce off the first object it hits and go a short distance before disappearing.
As far as I can tell there is no built in function for reflecting raycasts in Unity, so I have been trying to generate a another raycast where the first one hits but my luck hasn't been going well. Here's what I have so far:
public Gameobject firePoint; // I have an object attached to my main object that I use as a point of origin
void DrawLazer()
{
Vector2 origin = new Vector2(firePoint.transform.position.x, firePoint.transform.position.y);
Vector2 direction = transform.TransformDirection(Vector2.up);
RaycastHit2D hit = Physics2D.Raycast(origin, direction, 10f);
Debug.DrawLine(origin, direction *10000, Color.black);
if (hit)
{
Debug.Log("Hit: " + hit.collider.name);
var whatWeHit = new Vector2(hit.transform.position.x, hit.transform.position.y);
var offset = whatWeHit + hit.point;
offset.y = 0;
RaycastHit2D hit2 = Physics2D.Raycast(offset, Vector3.Reflect(direction, hit.normal) * -10000);
if (hit2)
{
Debug.DrawLine(offset, -Vector3.Reflect(direction, hit.normal) * -10000);
}
}
}
I call DrawLaxer(); in update.
This current script is sort of able to generate a 2nd raycast, however as you can see, the first raycast still does not stop when it hits something, and more importantly while this solution works well when it hits a flat object on a horizontal plane. But if it hits on object on a vertical or diagonal plane it applys several calculations to the wrong axis:
Any help would be greatly appreciated.
Here is a complete example monobehavior that uses Vector2.Reflect and SphereCast.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class ReflectionExample : MonoBehaviour
{
public GameObject firePoint;
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
void Update()
{
DrawPredictionDisplay();
}
private void DrawPredictionDisplay()
{
Vector2 origin = firePoint.transform.position; //unity has a built in type converter that converts vector3 to vector2 by dropping the z component
Vector2 direction = firePoint.transform.up;
float radius = 1.0f;
RaycastHit2D distanceCheck = Physics2D.Raycast(origin, direction);
RaycastHit2D hit = Physics2D.CircleCast(origin, radius, direction);
Debug.DrawLine(origin, direction * 10000, UnityEngine.Color.black);
DrawCircle(origin, 1.0f, UnityEngine.Color.black);
if (hit)
{
origin = hit.point + (hit.normal * radius);
direction = Vector2.Reflect(direction, hit.normal);
hit = Physics2D.CircleCast(origin, radius, direction);
Debug.DrawLine(origin, direction * 10000, UnityEngine.Color.blue);
DrawCircle(origin, 1.0f, UnityEngine.Color.blue);
}
}
private void DrawCircle(Vector2 center, float radius, UnityEngine.Color color)
{
Vector2 prevPoint = new Vector2(Mathf.Sin(0f), Mathf.Cos(0f));
for (float t = 0.1f; t < 2 * Mathf.PI; t = t + 0.1f)
{
var nextPoint = new Vector2(Mathf.Sin(t), Mathf.Cos(t));
Debug.DrawLine(center + prevPoint, center + nextPoint, color);
prevPoint = nextPoint;
}
}
}
I am following Survival Shooter unity tutorial and in the tutorial the down given code is used to make the camera follow the player.The code is working but how can i alter it so that it stops following the player at a given X and Y point.
code
public Transform target; // The position that that camera will be following.
public float smoothing = 5f; // The speed with which the camera will be following.
Vector3 offset; // The initial offset from the target.
void Start ()
{
// Calculate the initial offset.
offset = transform.position - target.position;
}
void FixedUpdate ()
{
// Create a postion the camera is aiming for based on the offset from the target.
Vector3 targetCamPos = target.position + offset;
// Smoothly interpolate between the camera's current position and it's target position.
transform.position = Vector3.Lerp (transform.position, targetCamPos, smoothing * Time.deltaTime);
}
Simply stop updating his position:
private bool followPlayer = true;
void FixedUpdate ()
{
if(followPlayer){
// Create a postion the camera is aiming for based on the offset from the target.
Vector3 targetCamPos = target.position + offset;
// Smoothly interpolate between the camera's current position and it's target position.
transform.position = Vector3.Lerp (transform.position, targetCamPos, smoothing * Time.deltaTime);
}
}
Change the value of followPlayer to false and it will stop following
To determine if the player is at given point, you need to check distance between the player and the point, e.g:
public Transform target; // player position
public Transform stopingPoint; // stopping point position
public double tolerance; // the "radius" of stopping point
private bool followPlayer = true;
...
void FixedUpdate ()
{
if(!followPlayer)
return;
followPlayer = Vector3.Distance(target.position, stopingPoint.position) <= tolerance;
...
Im thinking about it two days. I still did not made any progress.
I wonder how to do that objects fly away from mouse click position in 2D view?
I tried like that:
pos = Input.mousePosition;
Vector3 realWorldPos = Camera.main.ScreenToViewportPoint(pos);
print("MOuse pos: " + realWorldPos);
//print(realWorldPos);
Vector3 velo = GetComponent<Rigidbody2D>().velocity;
if (realWorldPos.x < 0.5)
{
velo = new Vector3((realWorldPos.x * speed), velo.y);
}
else if(realWorldPos.x > 0.5)
{
velo = new Vector3((realWorldPos.x * speed) * (-1), velo.y);
}
if (realWorldPos.y < 0.5)
{
velo = new Vector3(velo.x, realWorldPos.y * speed);
}
else if (realWorldPos.y > 0.5)
{
velo = new Vector3(velo.x, (realWorldPos.y * speed) * (-1));
}
GetComponent<Rigidbody2D>().velocity = velo;
But it doesnt work as I want.
Is it possible to do this?
For this to work your Rigidbody2D must have Gravity Scale set to 0.
This is a simple test code that works for me, is placed on a sprite object:
public class PushPlayer : MonoBehaviour
{
public float pushPower = 50.0f;
Rigidbody2D rb;
void Start()
{
rb = GetComponent<Rigidbody2D>();
}
void Update()
{
if(Input.GetMouseButtonDown(0))
{
Vector3 dir = transform.position - Camera.main.ScreenToWorldPoint(Input.mousePosition);
dir = dir.normalized;
rb.AddForce(dir * pushPower, ForceMode2D.Force);
// as alternative:
rb.velocity = dir * pushPower;
}
}
}
You need to adjust the values a bit, also in the regidbody (like drag) to get it the way you want.
Edit:
transform.position - Camera.main.ScreenToWorldPoint(Input.mousePosition): calculate the directional vector from the mouse position to the player position (have a look a vector algebra if you are not familiar with this) which is the direction away from the click (in a straight line).
dir.normalized: this shortens the vector to a length (= magnitude) of 1 (again have a look at vectors) so it really is just a direction. You could omit this and reduce the factor, but doing it this way your factor equals the force you use.
I'm making a 2D platformer game where the player has an arm that points towards the mouse cursor. This mechanism is used to aim the player's weapon. However, I am experiencing some glitches when rotating the arm.
I know the reason why I am getting these errors: The arm (in the hierarchy) is a child of the player, and what I'm doing to the player is flipping (inverting) its transform.localScale.x value whenever it moves in a specified direction, so that the player sprite looks in the given direction. Since the arm is a child of the player, its own transform is flipped as well, making it look in the same direction as the player, which is what I want. However, this causes some errors with the arm rotation. Since the arm's transform.localScale.x value is flipped, the rotation is all messed up, and I can't figure out how to solve it.
Here are some example scripts for moving the player and arm. They are simplified so that you can read it better.
// Update is called once per frame
void Update () {
var input = Input.GetAxis("Horizontal");
if(input > 0) {
if(!facingRight) {
ChangeOrientation(gameObject, new Vector3(-1,1,1));
facingRight = !facingRight;
}
}
if(input < 0) {
if(facingRight) {
ChangeOrientation(gameObject, new Vector3(-1,1,1));
facingRight = !facingRight;
}
}
rbody.velocity = new Vector2(speed * input, rbody.velocity.y);
}
public static void ChangeOrientation (GameObject g, Vector3 changeBy) {
var newTransform = g.transform.localScale;
newTransform.x *= changeBy.x;
newTransform.y *= changeBy.y;
newTransform.z *= changeBy.x;
g.transform.localScale = newTransform;
}
And my arm rotation script:
void Update () {
//rotation
Vector3 mousePos = Input.mousePosition;
mousePos.z = 0;
Vector3 objectPos = Camera.main.WorldToScreenPoint (transform.position);
mousePos.x = mousePos.x - objectPos.x;
mousePos.y = mousePos.y - objectPos.y;
float angle = Mathf.Atan2(mousePos.y, mousePos.x) * Mathf.Rad2Deg;
transform.rotation = Quaternion.Euler(new Vector3(0, 0,
(PlayerRunMovementController.facingRight ? angle : angle )));
}
Thanks for any help you can offer.