Dinamically rescale GameObject Unity3D - c#

I need to rescale a GameObject in Unity3D, basing on a speed value. I am trying to do it through the transform.localScale, and computing a size ratio basing on the highest speed and dimension values; however, it does not work as it should.
The problem I have is that with the starting size of {0.5, 0.5, 0.5}, and with speedValues = {0.8, 0.5, 0.2}, I have that _sizeRatio = 0.625 and the object is not kept to its original scale but is rescaled. I do not know how to solve this issue.
Here is a sample of the code:
using UnityEngine;
using UnityEngine.Input;
using System.Linq;
public class Example : MonoBehaviour
{
[SerializeField] private GameObject objectToResize;
[SerializeField] private float[] speedValues;
private int _speedIndex;
private float _sizeRatio;
private Vector3 _originalSize;
private void Start(){
_speedIndex = 0;
_originalSize = objectToResize.transform.localScale;
_sizeRatio = _originalSize.x / GetMaxValue(v);
ScaleObject();
}
private void Update(){
if(Input.GetKeyDown(KeyCode.W){
_speedIndex++
if(_speedIndex == speedValues.Length){
_speedIndex = 0:
}
ScaleObject();
}
}
private void ScaleObject(){
var newScale = new Vector3(_originalSize.x * _sizeRatio * speedValues[_speedIndex],
_originalSize.y * _sizeRatio * speedValues[_speedIndex],
_originalSize.z * _sizeRatio * speedValues[_experimentManager.SpeedIndex]);
objectToResize.transform.localScale = newScale;
}
private float GetMaxValue(float[] v) => v.Max();
}

Related

Find an angle and velocity to launch the projectile with to reach a specific point

I am trying to make a cannon that shoots a target located in a 3D world in Unity... I hava a LaunchConfig enum ->
public enum LauncherConfig
{
CalculateNone = 0,
CalculateAngle = 1,
CalculateVelocity = 2,
CalculateBoth = 3
}
When CalculateAngle is selected the user can input the Initial Velocity for the projectile and the angle the projectile needs to be launched at to reach the target has to be calculated.
Same for CalculateVelocity.
CalculateNone allows the user to input both the values and CalculateBoth calculates both the values.
What equations do I use to calculate the values so that they line up, i.e. when CalculateAngle is selected the velocity calculated should be such that the projectile looks natural coming out of the barrel. Same for CalculateBoth, the angle should be calculated so that the velocity calculated will launch the projectile strait out the barrel and not any other direction.
I have my current location (Vector3), target location (Vector3).
The calculated angle will affect the x-rotation of the cannon.
The y-rotation is lined up with the target already so that it faces the target;
Here is the code for the class
using System;
using UnityEngine;
public class Launcher : MonoBehaviour
{
[SerializeField] private LauncherSettings settings = default;
[SerializeField] private Transform target = default;
private Transform partToRotateY;
private Transform partToRotateX;
private Transform projectileSpawnPosition;
private float x;
private float y;
private Vector3 velocity;
private void Awake()
{
partToRotateX = transform.GetChild(0);
partToRotateY = transform.GetChild(1);
projectileSpawnPosition = partToRotateX.GetChild(0);
settings.inputController = new InputActions.Launcher();
settings.inputController.Automatic.Launch.performed += _ => Shoot();
}
private void Update()
{
CalculateVelocity();
CalculateAngle();
LookAtTarget();
Shoot();
}
private void OnEnable()
{
settings.inputController.Enable();
}
private void OnDisable()
{
settings.inputController.Disable();
}
private void LookAtTarget()
{
Vector3 direction = target.position - transform.position;
Quaternion lookRotation = Quaternion.LookRotation(direction);
y = lookRotation.eulerAngles.y;
Quaternion rotationY = Quaternion.Euler(0f, y, 0f);
Quaternion rotationX = Quaternion.Euler(-x, y, 0f);
partToRotateY.rotation = Quaternion.Slerp(partToRotateY.rotation, rotationY, Time.deltaTime * settings.rotationSpeed);
partToRotateX.rotation = Quaternion.Slerp(partToRotateX.rotation, rotationX, Time.deltaTime * settings.rotationSpeed);
}
private float nextTimeToFire = 0f;
private void Shoot()
{
nextTimeToFire -= Time.deltaTime;
if (!(nextTimeToFire <= 0f)) return;
nextTimeToFire = 1 / settings.fireRate;
var rb = Instantiate(settings.projectilePrefab, projectileSpawnPosition.position, Quaternion.identity).GetComponent<Rigidbody>();
rb.velocity = velocity;
}
private void CalculateAngle()
{
if (settings.launcherConfig == LauncherConfig.CalculateVelocity ||
settings.launcherConfig == LauncherConfig.CalculateNone)
{
x = Mathf.Clamp(settings.launchAngle, -20f, 80f);
}
else
{
var position = target.position;
var position1 = transform.position;
var dist = Math.Sqrt(Mathf.Pow((position.x - position1.x), 2) + Mathf.Pow((position.y - position1.y), 2));
var a = Physics.gravity.y * Mathf.Pow((float) dist, 2) / (2 * Mathf.Pow(velocity.magnitude, 2));
var b = (float) -dist;
var c = position.z - position1.z + a;
x = (float) Math.Atan2(QuadraticRoot(a, b, c), 1);
Debug.Log(x);
}
}
private void CalculateVelocity()
{
if (settings.launcherConfig == LauncherConfig.CalculateAngle ||
settings.launcherConfig == LauncherConfig.CalculateNone)
{
velocity = partToRotateX.forward * settings.velocity;
}
else
{
float h;
if (settings.launcherConfig == LauncherConfig.CalculateBoth && settings.calculateMaxHeight)
{
h = Mathf.Abs(target.position.y - partToRotateX.position.y * settings.maxHeightMultiplier);
}
else
{
h = settings.maxHeight;
}
var position = partToRotateX.position;
var position1 = target.position;
var gravity = Physics.gravity.y;
var displacementY = position1.y - position.y;
var displacementXZ = new Vector3 (position1.x - position.x, 0, position1.z - position.z);
var time = Mathf.Sqrt(-2*h/gravity) + Mathf.Sqrt(2*(displacementY - h)/gravity);
var velocityY = Vector3.up * Mathf.Sqrt (-2 * gravity * h);
var velocityXZ = displacementXZ / time;
velocity = velocityXZ + velocityY * -Mathf.Sign(gravity);
}
}
private double QuadraticRoot(double a, double b, double c){
double D = Math.Pow(b, 2) - (4 * a * c);
return (-b + Math.Sqrt(D)) / (2 * a);
}
}
The LauncherSettings Class...
using Attributes.DrawIf;
using Attributes.DrawIfAndOr;
using UnityEngine;
[CreateAssetMenu]
public class LauncherSettings : ScriptableObject
{
public InputActions.Launcher inputController;
public LauncherConfig launcherConfig = LauncherConfig.CalculateVelocity;
public GameObject projectilePrefab = default;
public float rotationSpeed = 5f;
public float fireRate = 5f;
[DrawIfAndOr(nameof(launcherConfig), LauncherConfig.CalculateAngle, LauncherConfig.CalculateNone)]
public float velocity = 200f;
[DrawIfAndOr(nameof(launcherConfig), LauncherConfig.CalculateVelocity, LauncherConfig.CalculateNone)]
public float launchAngle = 0f;
[DrawIf(nameof(launcherConfig), LauncherConfig.CalculateBoth)]
public bool calculateMaxHeight = true;
[DrawIf(nameof(calculateMaxHeight), false)]
public float maxHeight;
[DrawIf(nameof(calculateMaxHeight), true)]
public float maxHeightMultiplier = 5f;
}
The DrawIf and DrawIfAndOr are attributes that hide the vaule in inspector if the first paramerter is equal to the other. You can completely ignore them. The calculation of Velocity is by
Sebastian Lague (https://www.youtube.com/channel/UCmtyQOKKmrMVaKuRXz02jbQ) in his Kinematic Equations (E03: ball problem) (https://youtu.be/IvT8hjy6q4o). The calculation of the angle is from an answer on my other question (Find an angle to launch the projectile at to reach a specific point).
Any help is appreciated...
Thanks...

How can I keep the object to rotate in the range from it's original position/rotation and not to add/remove each time a new rotation?

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Rotateturret : MonoBehaviour
{
public enum RotateOnAxis { rotateOnX, rotateOnY, rotateOnZ };
public bool randomRotation = false;
[Range(0, 360)]
public int rotationRange = 70;
private void Start()
{
}
private void Update()
{
if (randomRotation == true)
{
var rr = Random.Range(-rotationRange, rotationRange);
transform.Rotate(Vector3.up, rr);
}
}
}
What it does now it keep adding or removing a random number to the rotation so in some cases the rotation can be 230 or 450 or 21 it's adding/removing in range of -70 to 70 but I want it to add/remove but only 70/-70 from the original start position/rotation.
For example if the game started and the object rotation is at 20 so add/remove 70 the rotation will be randomly between 20+70 and 20-70 maximum it can get to 90 and minimum to -50.
Rotate will act relative to the current rotation so you're actually accumulating rotations there. Try this instead;
Quaternion initialRotation;
void Start ()
{
// Save initial rotation
initialRotation = transform.rotation;
}
void Update ()
{
// Compute random angle in the range of +- rotationRange
var delta = (Random.value * 2f - 1f) * rotationRange;
// Compute rotation from the initial rotation and delta
transform.rotation = initialRotation * Quaternion.Euler(0f, delta, 0f);
}
I believe using a "currentRotation" variable and a "startRotation" variable and adding the random value to it will work. I added it to your existing script in the section below.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Rotateturret : MonoBehaviour
{
public enum RotateOnAxis { rotateOnX, rotateOnY, rotateOnZ };
public bool randomRotation = false;
[Range(0, 360)]
public int rotationRange = 70;
public int startRotation = 20; //create a startRotation value.
public int currentRotation = 20; //create a currentRotation value in case you need to access it later.
private void Update()
{
if (randomRotation == true)
{
var rr = Random.Range(-rotationRange, rotationRange);
currentRotation = startRotation + rr; //Add the random value to the start value. This also works for negative values.
transform.Rotate(Vector3.up, currentRotation); //use the combined value instead of just rr.
}
}
}

Using AudioListener.GetSpectrumData will not work on particle system script

Using AudioListener.GetSpectrumData to get an audio spectrum to use to modulate the Max Particles in a particle system. I use this exact method with other parts of my sketch to modulate the intensity of Lighting, the size of Cubes, Spheres, and Text...) but this will not work on the Particle System. Any ideas?
using UnityEngine;
public class Max_Particles_Blow_Spectrum : MonoBehaviour {
[Range(1.0f, 30000.0f)]
public float phi = 0.0f;
private ParticleSystem ps;
void Start()
{
ps = GetComponent<ParticleSystem>();
}
void Update()
{
float[] phi = AudioListener.GetSpectrumData(1024, 0, FFTWindow.Hamming);
var main = ps.main;
float amplitude = Mathf.RoundToInt(phi[1]) ;
// i thought it was an issue with the float array to I tried converting it to an int
main.maxParticles = Mathf.RoundToInt(amplitude);
}
void OnGUI()
{
phi = GUI.HorizontalSlider(new Rect(25, 25, 100, 30), phi, 1f, 30000.0f);
}
}

Unity camera starting position

Hello so I created a camera for a RTS game I'm making but on start the camera is on the minHight position and I cant figure out how to change it hope someone helps the code is a bit of a mess its just for a test here is the code I want it to start from the maxHight position that is given and not on the minHight .
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class RtsCamera : MonoBehaviour {
public float zoomSensitivy = 15;
private Transform m_Transform;
public float screenEdgeBorder = 25f;
public bool useScreenEdgeInput = true;
public float screenEdgeMovementSpeed = 3f;
// zoom stuff
public float heightDampening = 5f;
public float scrollWheelZoomingSensitivity = 25f;
public float maxHeight = 10f; //maximal height
public float minHeight = 15f; //minimnal height
public LayerMask groundMask = -1;
public bool autoHeight = true;
public bool limitMap = true;
public float limitX = 50f; //x limit of map
public float limitZ = 50f; //z limit of map
private float zoomPos = 0; //value in range (0, 1) used as t in Matf.Lerp
public bool useScrollwheelZooming = true;
Vector3 tempPos;
public string zoomingAxis = "Mouse ScrollWheel";
private float ScrollWheel
{
get { return Input.GetAxis(zoomingAxis); }
}
private Vector2 MouseAxis
{
get { return new Vector2(Input.GetAxis("Mouse X"), Input.GetAxis("Mouse Y")); }
}
private Vector2 MouseInput
{
get { return Input.mousePosition; }
}
private void Start()
{
m_Transform = transform;
}
// Update is called once per frame
void Update () {
Move();
LimitPosition();
HeightCalculation();
}
private void Move()
{
if (useScreenEdgeInput)
{
Vector3 desiredMove = new Vector3();
Rect leftRect = new Rect(0, 0, screenEdgeBorder, Screen.height);
Rect rightRect = new Rect(Screen.width - screenEdgeBorder, 0, screenEdgeBorder, Screen.height);
Rect upRect = new Rect(0, Screen.height - screenEdgeBorder, Screen.width, screenEdgeBorder);
Rect downRect = new Rect(0, 0, Screen.width, screenEdgeBorder);
desiredMove.x = leftRect.Contains(MouseInput) ? -1 : rightRect.Contains(MouseInput) ? 1 : 0;
desiredMove.z = upRect.Contains(MouseInput) ? 1 : downRect.Contains(MouseInput) ? -1 : 0;
desiredMove *= screenEdgeMovementSpeed;
desiredMove *= Time.deltaTime;
desiredMove = Quaternion.Euler(new Vector3(0f, transform.eulerAngles.y, 0f)) * desiredMove;
desiredMove = m_Transform.InverseTransformDirection(desiredMove);
m_Transform.Translate(desiredMove, Space.Self);
}
}
private void LimitPosition()
{
if (!limitMap)
return;
m_Transform.position = new Vector3(Mathf.Clamp(m_Transform.position.x, -limitX, limitX),
m_Transform.position.y,
Mathf.Clamp(m_Transform.position.z, -limitZ, limitZ));
}
private void HeightCalculation()
{
float distanceToGround = DistanceToGround();
if (useScrollwheelZooming)
zoomPos += ScrollWheel * Time.deltaTime * scrollWheelZoomingSensitivity;
zoomPos = Mathf.Clamp01(zoomPos);
float targetHeight = Mathf.Lerp(minHeight, maxHeight, zoomPos);
float difference = 0;
if (distanceToGround != targetHeight)
difference = targetHeight - distanceToGround;
m_Transform.position = Vector3.Lerp(m_Transform.position,
new Vector3(m_Transform.position.x, targetHeight + difference, m_Transform.position.z), Time.deltaTime * heightDampening);
}
private float DistanceToGround()
{
Ray ray = new Ray(m_Transform.position, Vector3.down);
RaycastHit hit;
if (Physics.Raycast(ray, out hit, groundMask.value))
return (hit.point - m_Transform.position).magnitude;
return 0f;
}
}
Set the value of the variable zoomPos on line 25 to either 1 or 0 depending on whether you want it at the min height or the max height, you could do this either in the Start() or just at the declaration of the variable.
This is because in the HeightCalculation function it sets the height to somewhere between the min and max based off the value of zoomPos, as you use the scrollwheel this value changes and so does the zoom. Altering zoomPos before you run the game allows you to effectively set a default starting height.

Why Isn't ray collisions working in unity

So I was working through this tutorial.
https://www.youtube.com/watch?v=OBtaLCmJexk
and I can't find the error in my code anywhere
The problem is just that after working on the vertical ray collisions I run the program and the block just falls through the obstacle.
here is the player code:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
[RequireComponent(typeof(Controller2D))]
public class Player : MonoBehaviour {
float gravity = -20;
Vector3 velocity;
Controller2D controller;
void Start() {
controller = GetComponent<Controller2D>();
}
void Update() {
velocity.y += gravity * Time.deltaTime;
controller.Move(velocity * Time.deltaTime);
}
}
and here is the Controller2D code:
using UnityEngine;
[RequireComponent(typeof(BoxCollider2D))]
public class Controller2D : MonoBehaviour {
public LayerMask collisionMask;
const float skinWidth = .015f;
public int horizontalRayCount = 4;
public int verticalRayCount = 4;
float horizontalRaySpacing;
float verticalRaySpacing;
BoxCollider2D collider;
RaycastOrigins raycastOrigins;
void Start() {
collider = GetComponent<BoxCollider2D>();
CalculateRaySpacing();
}
public void Move(Vector3 velocity) {
UpdateRaycastOrigins();
VerticalCollisions(ref velocity);
transform.Translate(velocity);
}
void VerticalCollisions(ref Vector3 velocity) {
float directionY = Mathf.Sign(velocity.y);
float rayLength = Mathf.Abs(velocity.y) + skinWidth;
for (int i = 0; i < verticalRayCount; i++) {
Vector2 rayOrigin = (directionY == -1) ? raycastOrigins.bottomLeft : raycastOrigins.topLeft;
rayOrigin += Vector2.right * (verticalRaySpacing * i + velocity.x);
RaycastHit2D hit = Physics2D.Raycast(rayOrigin, Vector2.up * directionY, rayLength, collisionMask);
Debug.DrawRay(raycastOrigins.bottomLeft + Vector2.right * verticalRaySpacing * i, Vector2.up * -2, Color.red);
if (hit) {
velocity.y = (hit.distance - skinWidth) * directionY;
rayLength = hit.distance;
}
}
}
void UpdateRaycastOrigins() {
Bounds bounds = collider.bounds;
bounds.Expand(skinWidth * -2);
raycastOrigins.bottomLeft = new Vector2(bounds.min.x, bounds.min.y);
raycastOrigins.bottomRight = new Vector2(bounds.max.x, bounds.min.y);
raycastOrigins.topLeft = new Vector2(bounds.min.x, bounds.max.y);
raycastOrigins.topRight = new Vector2(bounds.max.x, bounds.max.y);
}
void CalculateRaySpacing() {
Bounds bounds = collider.bounds;
bounds.Expand(skinWidth * -2);
horizontalRayCount = Mathf.Clamp(horizontalRayCount, 2, int.MaxValue);
verticalRayCount = Mathf.Clamp(verticalRayCount, 2, int.MaxValue);
horizontalRaySpacing = bounds.size.y / (horizontalRayCount - 1);
verticalRaySpacing = bounds.size.y / (verticalRayCount - 1);
}
struct RaycastOrigins {
public Vector2 topLeft, topRight;
public Vector2 bottomLeft, bottomRight;
}
}
Edit: The code is (as I understand from a half an hour tutorial.) just defining attributes to a quad(player) so that it can collide with another quad(obstacle). at the moment the code should only work vertically. so I am testing it by drawing the obstacle under the player and pressing play. the player should come to rest on the obstacle but instead, it sinks straight through it.
My screen after selecting the player block
and asking about debugging, I dont understand the language well enough to not break anything while trying to debug it.
I just got someone on discord to help and it turns out I didn't have the obstacle set with boxcollider2D
Many Thanks all who tried.

Categories