Steering Wheel code in Unity Engine using C# - c#

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.EventSystems;
public class SteeringWheel : MonoBehaviour, IDragHandler, IPointerUpHandler, IPointerDownHandler
{
public bool Wheelbeingheld = false;
public RectTransform Wheel; //makes a gameobject treat like an object like of a rectangular shape, so that we could use many functionalities of the RECT feature, such as worldToScreenPoint, object.position, etc.
public float WheelAngle = 0f;
public float LastWheelAngle = 0f; //the previous angle of the wheel
private Vector2 center;
public float MaxSteerAngle = 200f;
public float ReleaseSpeed = 300f;
public float OutPut; // the output angle with which the steering wheel is rotated.
void Start()
{
}
// Update is called once per frame
void Update()
{
if(!Wheelbeingheld && WheelAngle != 0f)
{
float DeltaAngle = ReleaseSpeed * Time.deltaTime; //distance = speed * time; ...as angle is the distance between from and to position on the axis of the object.
if(Mathf.Abs(DeltaAngle)>Mathf.Abs(WheelAngle)) //Mathf.abs - removes the negative sign if there in the float value and return the ABSOLUTE value.
WheelAngle = 0f; //wheelangle will always end to 0. not more or less than that.
else if (WheelAngle>0f) //wheel coming back code how it will through these values and functions, so that wheels comes back to (0,0) position like that.
WheelAngle -= DeltaAngle; //wheel back, while on right side steered as wheel angle greater than 0
else
WheelAngle += DeltaAngle; //wheel back, while on left side steered as wheel angle greater than 0
}
Wheel.localEulerAngles = new Vector3(0, 0, -WheelAngle); //the animation - how the wheel will rotate if it will. Or Vector3.back * wheelAngle; wheel angle will be 0; the wheel is rotating on z axis so thats why written on the z axis place; and minus sign on wheel angle, becuz the wheel has to come back from wherever it is in the opposite direction.
OutPut = WheelAngle/MaxSteerAngle; //returns value through rotation of wheel, from -1 to 1.
}
public void OnPointerDown(PointerEventData data)
{
Wheelbeingheld = true;
center = RectTransformUtility.WorldToScreenPoint(data.pressEventCamera, Wheel.position); //world to screen point.
LastWheelAngle = Vector2.Angle(Vector2.up, data.position - center); //Syntax: Vector2.Angle(Vector2 from, Vector2 to)
}
public void OnDrag(PointerEventData data)
{
float NewAngle = Vector2.Angle(Vector2.up, data.position - center);
if((data.position - center).sqrMagnitude >= 400)
{
if(data.position.x > center.x)
WheelAngle += NewAngle - LastWheelAngle;
else
WheelAngle -= NewAngle - LastWheelAngle;
}
WheelAngle = Mathf.Clamp(WheelAngle, -MaxSteerAngle, MaxSteerAngle); //Clamp(float value, float min, float max)
LastWheelAngle = NewAngle;
}
public void OnPointerUp(PointerEventData data)
{
OnDrag(data); // Performs one last DragEvent, just in case. As when you leave the wheel, the wheel rotates back, so till then also it will assess the wheel angle and run the code of drag.
Wheelbeingheld = false;
}
}
Got this code from somewhere online and it works absolutely fine and as expected. The comments are of my own for my understanding. Check if possible if I have understood things right.
I am not able to understand 5 things for which I would love if anyone helps me with it:
"Wheel Angle" and "Last Wheel Angle" - Why is it needed if "New Angle" accurately does the job? And why not also put that in update function?
What is the speed as in frames per second of "OnPointerDown" or "...Up" and "OnDrag" functions if refreshed. Do they compare to Update or FixedUpdate?
What is data.pressEventCamera and why is it used? It's not even in the syntax of "WorldToScreenPoint" function.
What does "sqr.Magnitude" actually do? I have a guess but want to confirm.
Why is Delta Angle used and what actually is with that name?
Hoping for satisfying answers soon.

1: It is on OndDrag to stop the wheel from spinning when it has not been rotated by the user. If it was in Update it would rotate every frame. The newangle doesn't take into consideration the current angle, so is then added to the current angle to give a smoother rotation.
2: OnPointerDown is called when the pointer is pressed down on the scrollbar.
3: The camera associated with the last OnPointerPress event.
4: sqr.Magnitude is, well, the magnitude of the vector squared
5: delta anything means the change in. This is the change in the steering wheels angle.
Please do note that most of these answers came from the unity docs - you could always do a search on them: https://docs.unity3d.com/2018.3/Documentation/ScriptReference/index.html

Related

Movement in unity; Non diagonal, zelda like

So I'm testing around with Unity and Visual Studio, and as a starter project I'm working to replicate Zelda (NES) and I'm starting with movement.
So far, with much jank, I've figured out how to prevent diagonal movement, but I'm having trouble figuring out the next part. In the game, if favors vertical movement when there are 2 inputs, but if you hit a wall, it lets you move horizontally until nothing is blocking your vertical movement.
I do not know enough to even think about how to do this. Anyone have an idea that can set me the right direction? Or perhaps just a better way of doing it? I'm still learning C#
public float MoveSpeed;
public Rigidbody2D rb;
Vector2 movement;
void Update() {
MovementInput();
}
private void FixedUpdate() {
rb.velocity = movement * MoveSpeed;
}
void MovementInput() {
float mx = Input.GetAxisRaw("Horizontal");
float my = Input.GetAxisRaw("Vertical");
//This makes diagonal impossible, favoring vertical.
if (my != 0) {
mx = 0;
}
movement = new Vector2(mx, my).normalized;
}
Try to compare the horizontal and the vertical axis absolute value. The highest would gives you the good direction.
if (Math.Abs(my) > Math.Abs(mx)) {
// up or down
} else {
// left or right
}

Change direction but not affecting force

Im struggling with this, tried adding force but its not working the way I wanted, tried also changing direction but it changes by 45degrees which in my case is not what I wanted. Im thinking about adding the wind zone in the direction of arrwos, but came here to ask if theres any other(better) way to do it. Any help would be great! Thanks and have a great day!
Heres image for easier understainding
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class ArrowGrass : MonoBehaviour
{
public Rigidbody ball;
public float arrowPower;
public float stoppingPower;
private void OnTriggerStay(Collider other)
{
if (other.gameObject.CompareTag("Player"))
{
Vector3 direction = ball.velocity.normalized;
float speed = ball.velocity.magnitude;
Vector3 currentVelocity = ball.velocity;
Vector3 desiredDirection = new Vector3(-1, 0, 0); // set this to the direction you want.
Vector3 newVelocity = desiredDirection.normalized * currentVelocity.magnitude;
ball.AddForce(newVelocity - currentVelocity, ForceMode.VelocityChange);
/*
ball.angularDrag = stoppingPower;
Debug.Log("Colided");
ball.AddForce(new Vector3(-1, 0, 0) * arrowPower * stoppingPower, ForceMode.VelocityChange);
*/
}
}
}
Separate the Forces.
private float userForce = 0f;
void FixedUpdate()
{
if(userForce > 0.1f) // define a minimum force, as we won't reach actual 0.
{
userForce *= 0.95; // no need for Time.deltaTime as we are in FixedUpdate!
}else{
// we can shoot again. User-Force has ended.
userForce = 0; // just make it stop completely eventually.
}
rb.AddForce(userForce * velocity * direction); // you have to define velocity and direction.
}
The OnTriggerStay logic is on the conveyor belt itself, where you can define the force strenght and direction. It is applied to the Physx system and affects the players Rigidbodies velocity. But we can track our userforce whilst ignoring other forces. So the ball can continue to move or at least get pushed to a wall etc.
In the end you can just apply the same principle to a timer as well. Either checking timestamps, or just decreasing a variable using Time.deltaTime and checking if it's < 0.

How to make a ground object follow a flying object in unity?

I'm trying to make an object on the ground follow a flying object, for example a drone leading a human (for now i'm just using shapes - a cube and a capsule). My cube follows the capsule like i desire but i want the cube to follow the capsule on the ground only, rather than go up on the y-axis with the capsule. Right now, it follows the capsule everywhere, I want the capsule to lead while the cube follows along on the ground.
I have done some research on Google and Youtube but I have not seen any results. Please let me know how I can achieve this.
This is the code script attached to the cube(ground object)
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class follow_target : MonoBehaviour
{
public Transform mTarget;
float mSpeed = 10.0f;
const float EPSILON = 0.1f;
Vector3 mLookDirection;
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
void Update()
{
mLookDirection = (mTarget.position - transform.position).normalized;
if((transform.position - mTarget.position).magnitude > EPSILON)
transform.Translate(mLookDirection * Time.deltaTime * mSpeed);
}
}
If the ground is planar, you can just set the y component to 0 (or whatever the ground y vector is).
If the ground changes in topology, you can do a raycast down from the capsule to get the hit point (vector3). You can use the hit point y component for the height. After that you will need to set the cubes rotation so that it is aligned to the ground. You could do that with a raycast as well, there are a number of examples of that online.
I hope that helps get you in the right direction.
Assuming a flat ground on Y = 0
either make sure your objects sticks to the ground so set
private const float EPSILONSQR = EPSILON * EPSILON;
void Update()
{
var difference = mTarget.position - transform.position;
mLookDirection = difference.normalized;
if(difference.sqrmagnitude > EPSILONSQR)
{
// In general be aware that Translate by default moves in the
// objects own local space coordinates so you probably would rather
// want to use Space.World
transform.Translate(mLookDirection * Time.deltaTime * mSpeed, Space.World);
var pos = transform.position;
// reset the Y back to the ground
pos.y = 0;
transform.position = pos;
}
}
or simply already map the direction down on the XZ plane (ignoring any difference in Y) like
private const float EPSILONSQR = EPSILON * EPSILON;
void Update()
{
var difference = mTarget.position - transform.position;
mLookDirection = difference.normalized;
// simply ignore the difference in Y
// up to you if you want to normalize the vector before or after doing that
mLookDirection.y = 0;
if(difference.sqrmagnitude > EPSILONSQR)
{
transform.Translate(mLookDirection * Time.deltaTime * mSpeed, Space.World);
}
}

Calculating changing Mathf.Clamp() values for object of changing size

I've been wracking my brain over this problem for a while. I have a controllable object (only moveable up and down) that I have clamped on the top and bottom. However, every time a certain trigger is activated, the object shrinks 10% until it is 90% of the original size. The problem comes in when I shrink it. When it shrinks, the min and max values of the clamp don't change at all and this results in the object clamping to soon on the min and max. They need to decrease and increase respectively so that it clamps in the exact same place. How would one do this? I've tried so many different methods but to no avail...
This is the way I shrink my player:
playerWidth /= 1.1f;
playerHeight /= 1.1f;
Vector3 scale = new Vector3(playerWidth, playerHeight, 1f);
playerOneShrink.transform.localScale = scale;
Many Thanks!
EDIT 1:
Let me give an example using a game that might help get my point across better. Basically think flappy bird, but the player uses the up and down arrows to move and not space-bar. When the bird dies, the bird would reset but become smaller. It seems that because the bird is smaller it now moves 'less' up and down, and doesn't touch the top and bottom of the screen anymore. I want the bird to still be touching the top and bottom of the screen.
EDIT 2:
So apparently my first edit didn't clarify as much as I thought so I'm going to show my code for a test scene I'm trying this all in. I haven't shown the changing of minValue and maxValue because that's what I'm struggling with...
private static Rigidbody2D playerOneRB;
GameObject player1;
float verticalMovement = 0;
public static float playerHeight = 0.3417f;
public static float playerWidth = 0.05400001f;
public float minValue = 0;
public float maxValue = 10;
public static float p1VerticalSpeed = 3;
public GameObject playerOneShrink;
// Start is called before the first frame update
void Start()
{
playerOneRB = GameObject.FindGameObjectWithTag("P1 Normal").GetComponent<Rigidbody2D>();
player1= GameObject.Find("P1 Normal");
}
// Update is called once per frame
void Update()
{
verticalMovement = Input.GetAxis("Player 1 V"); //Looking for axis defined in our input manager
playerOneRB.velocity = new Vector3(0f, verticalMovement * p1VerticalSpeed, playerOneRB.velocity.x);
Vector3 scale1 = new Vector3(playerWidth, playerHeight, 1f);
Vector3 position = transform.position;
player1.transform.position = new Vector3(player1.transform.position.x, (Mathf.Clamp(player1.transform.position.y, minValue, maxValue)), 0f); //Restricting how far the players can move (aka, not off the screen)
if (Input.GetKeyDown(KeyCode.Alpha1))
{
playerWidth /= 1.1f;
playerHeight /= 1.1f;
scale1 = new Vector3(playerWidth, playerHeight, 1f);
paddleOneShrink.transform.localScale = scale1;
}
}
Here's a photo of what's happening:
1. Photo of position it reaches before shrinking
2. Photo of position it reaches after shrinking
I want the player in image 2 to be able to get to the same top position as in image 1 after it shrinks.
It sounds like you want to scale the object, but keep it pivoted, so if it's at the top most position, and scales, it stays at the top most position? If so, the code and answers here will help:
https://answers.unity.com/questions/14170/scaling-an-object-from-a-different-center.html
You'll of course need to add in some conditional code to check whether it's a top or bottom pivot.
Hope I understood your problem.
So let's assume the scale of the player is 1 unit and you have to clamp in y axis between 0 and 10.
so you will have to clamp the Y position of player like
Vector3 scale = new Vector3(playerWidth, playerHeight, 1f);
Vector3 position = transform.position;
position.y = mathf.clamp(0 + scale.x ,10 - scale.x ,position.y );
transform.position = position;
so if the player's scale is 1 then it will limit the y position between 1 (0+1) and 9 (10-1).
if the player's scale is 0.9 then it will be between 0.9 (0+0.9 ) and 9.1 (10-0.9)
if the scale is 3 then between 3 (0+3) and 7 (10-3)

Steering behaviors: Why is my wandering algorithm not working as intended?

We're learning about steering behaviors in my artificial intelligence for games class, and I figured I'd try my hand at implementing some of them. I've mainly been reading The Nature of Code to familiarize myself with the topics.
Here is the repository for my Unity project. The relevant scene is under Assets/Scenes/Wandering.unity.
Here's the associated script:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Wandering : MonoBehaviour
{
public float maxSpeed;
private float speed;
public float maxForce;
public float radius;
private Rigidbody body;
void Awake()
{
body = gameObject.GetComponent<Rigidbody>();
speed = maxSpeed;
body.velocity = new Vector3(5, 0, 5);
}
void Update()
{
// Get future position
Vector3 futurePosition = GetFuturePosition();
// Select random point on circle of radius "radius" around the future position
Vector3 target = GeneratePointOnCircle(futurePosition);
// Compute desired velocity as one pointing there
Vector3 desiredVelocity = GetDesiredVelocity(target);
// Get the steering force vector
Vector3 steerForce = desiredVelocity - body.velocity;
steerForce.y = 0;
// Cap the force that can be applied (lower max force = more difficult to turn)
if (Vector3.Magnitude(steerForce) > maxForce)
{
steerForce = Vector3.Normalize(steerForce) * maxForce;
}
// Apply the force to the body
body.AddForce(steerForce);
}
/* Returns a random point on a circle positioned at the given center and radius.
*/
Vector3 GeneratePointOnCircle(Vector3 center)
{
Vector3 point = center;
float angle = Random.Range(0, 360) * Mathf.Deg2Rad;
point.x += radius * Mathf.Cos(angle);
point.z += radius * Mathf.Sin(angle);
return point;
}
/* Computes and returns the future, predicted position of this object, assuming
* it continues traveling in its current direction at its current speed.
*/
Vector3 GetFuturePosition()
{
// We have a current velocity
// We have a time elapsed
// We have a current position
// Future position = current position + current velocity * delta time
return transform.position + body.velocity * Time.deltaTime;
}
/* The desired velocity is simply the unit vector in the direction of the target
* scaled by the speed of the object.
*/
Vector3 GetDesiredVelocity(Vector3 target)
{
return Vector3.Normalize(target - transform.position) * speed;
}
}
Values set in the editor:
maxSpeed: 40
maxForce: 20
radius: 60
When I run this, the agent does not behave as intended. The main problem is that instead of traveling smoothly, it stutters around in brief bursts, seems to pause, and then starts moving again. This random behavior is still pretty neat, and sort of mimics that of a disoriented rodent, but I'm looking for more intelligent-seeming behavior.
Is there a flaw in my script or logic that's forcing the agent to behave in this erratic manner? Any advice would be greatly appreciated.
It seems the problem was my use of Time.deltaTime for calculating the predicted point in the future if the agent were to continue at its current velocity.
Since this is really the time elapsed since the last frame update, it's quite a small number. Thus, using it for predicting the future point was misleading and would produce points very close to the agent (hence the "stuttering" behavior).
Instead, I opted to use a fixed "lookahead" time (say 2) to predict further into the future.

Categories