Unity Zoom In And Out 2D - c#

Been trying for a while now and I just need to make it so I can zoom in and out using the camera's FOV.
When I try this nothing happens.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class cameraZoom : MonoBehaviour
{
private Camera cameraFreeWalk;
public float zoomSpeed = 20f;
public float minZoomFOV = 10f;
public void ZoomIn()
{
if (Input.GetAxis("Mouse ScrollWheel") > 0)
{
cameraFreeWalk.fieldOfView -= zoomSpeed;
if (cameraFreeWalk.fieldOfView < minZoomFOV)
{
cameraFreeWalk.fieldOfView = minZoomFOV;
}
}
}
}

(1) Since there is nothing calling the ZoomIn() function, nothing will happen. You should move the Input-check into the Update() method since it is called by Unity in every frame, and you can then call the ZoomIn() function when the mouse-wheel is turned up.
private void Update()
{
if (Input.GetAxis("Mouse ScrollWheel") > 0)
{
ZoomIn();
}
}
public void ZoomIn()
{
cameraFreeWalk.fieldOfView -= zoomSpeed;
if (cameraFreeWalk.fieldOfView < minZoomFOV)
{
cameraFreeWalk.fieldOfView = minZoomFOV;
}
}
(2) You need to set the cameraFreeWalk field. You can either make it visible in the editor by adding the attribute "SerializeField", and then in the editor drag the Camera into the exposed field...
[SerializeField]
private Camera cameraFreeWalk;
... or you can collect the Camera component automatically. In this example, we tell Unity that there must be a Camera component on the same game object and we collect a reference to it in the Awake() method. If you want to be extra careful, check that you really have got a reference by doing an Assert() check. A bit redundant because of the RequiredComponent attribute, but I like to check all fields I am working with.
[RequireComponent(typeof(Camera))]
public class cameraZoom : MonoBehaviour
{
....
private void Awake()
{
cameraFreeWalk = GetComponent<Camera>();
Assert.IsNotNull(cameraFreeWalk);
}
(3) Finally, to be sure that the script works, you should also in the Awake() method, check that someone hasn't changed the camera to Orthographic - since then FOV will not be used. Personally, I like the Assert() method as you can see...
Assert.IsFalse(cameraFreeWalk.orthographic, "There isn't a FOV on an orthographic camera.");
The complete solution would then be something like this...
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Assertions;
[RequireComponent(typeof(Camera))]
public class cameraZoom : MonoBehaviour
{
[SerializeField]
private Camera cameraFreeWalk;
public float zoomSpeed = 20f;
public float minZoomFOV = 10f;
public float maxZoomFOV = 160f;
private void Awake()
{
cameraFreeWalk = GetComponent<Camera>();
Assert.IsNotNull(cameraFreeWalk);
Assert.IsFalse(cameraFreeWalk.orthographic, "There isn't a FOV on an orthographic camera.");
}
private void Update()
{
if (Input.GetAxis("Mouse ScrollWheel") > 0)
{
ZoomIn();
}
else if (Input.GetAxis("Mouse ScrollWheel") < 0)
{
ZoomOut();
}
}
public void ZoomIn()
{
cameraFreeWalk.fieldOfView -= zoomSpeed;
if (cameraFreeWalk.fieldOfView < minZoomFOV)
{
cameraFreeWalk.fieldOfView = minZoomFOV;
}
}
public void ZoomOut()
{
cameraFreeWalk.fieldOfView += zoomSpeed;
if (cameraFreeWalk.fieldOfView > maxZoomFOV)
{
cameraFreeWalk.fieldOfView = maxZoomFOV;
}
}
}

Related

C# Unity 2D Topdown Movement Script not working

I have been working on a unity project where the player controls a ship. I was following along with a tutorial and have made an input script and a movement script that are tied together with unity's event system. As far as I can tell my script and the script in the tutorial are the same, but the tutorial script functions and mine doesn't.
Script to get player input
using UnityEngine;
using System.Collections;
using System;
using UnityEngine.Events;
public class PlayerInput : MonoBehaviour
{
public UnityEvent<Vector2> OnBoatMovement = new UnityEvent<Vector2>();
public UnityEvent OnShoot = new UnityEvent();
void Update()
{
BoatMovement();
Shoot();
}
private void Shoot()
{
if(Input.GetKey(KeyCode.F))
{
OnShoot?.Invoke();
}
}
private void BoatMovement()
{
Vector2 movementVector = new Vector2(Input.GetAxis("Horizontal"), Input.GetAxis("Vertical"));
OnBoatMovement?.Invoke(movementVector.normalized);
}
}
Script to move player
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Events;
public class Movement : MonoBehaviour
{
public Rigidbody2D rb2d;
private Vector2 movementVector;
public float maxspeed = 10;
public float rotatespeed = 50;
private void Awake()
{
rb2d = GetComponent<Rigidbody2D>();
}
public void HandleShooting()
{
Debug.Log("Shooting");
}
public void Handlemovement(Vector2 movementVector)
{
this.movementVector = movementVector;
}
private void FixedUpdate()
{
rb2d.velocity = (Vector2)transform.up * movementVector.y * maxspeed * Time.deltaTime;
rb2d.MoveRotation(transform.rotation * Quaternion.Euler(0, 0, -movementVector.x * rotatespeed * Time.fixedDeltaTime));
}
}
Any help would be appreciated!
You need to attach your Handlers (HandleShooting and Handlemovement) to corresponding events. Easiest way would be to make events static in PlayerInput
public static UnityEvent<Vector2> OnBoatMovement = new UnityEvent<Vector2>();
public static UnityEvent OnShoot = new UnityEvent();
and attach corresponding handlers to them in Movement.Awake
private void Awake(){
rb2d = GetComponent<Rigidbody2D>();
PlayerInput.OnBoatMovement += Handlemovement;
PlayerInput.OnShoot += HandleShooting;
}
Also in PlayerInput.BoatMovement you should probably check
if(movementVector.sqrMagnitude > 0){
OnBoatMovement?.Invoke(movementVector.normalized);
}
Or else random shit may happen when trying to normalize Vector with magnitude 0 (I compare sqr magnitude to aviod calculating root which is never desired)

Unity. Help. Created a skiript for the enemy, in which hp decreases for all objects on which it hangs

I'm making a unity shooter. The task was to remove hp from each enemy in its own way.
My code:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.AI;
public class monster_animation : MonoBehaviour
{
public GameObject player;
public float dist;
NavMeshAgent nav;
public float Radius = 40f;
public static int health = 100;
// Start is called before the first frame update
void Start()
{
nav = GetComponent<NavMeshAgent>();
}
// Update is called once per frame
void Update()
{
if (GameObject.Find("HitEffect(Clone)") != null)
{
health -= 25;
Destroy(GameObject.Find("HitEffect(Clone)"));
}
dist = Vector3.Distance(player.transform.position, transform.position);
if(dist <= Radius)
{
if (dist <= 4)
{
nav.enabled = false;
if (health <= 0)
{
nav.enabled = false;
gameObject.GetComponent<Animator>().SetTrigger("dead");
}
else
{
gameObject.GetComponent<Animator>().SetTrigger("attack");
}
}
else
{
if (health <= 0)
{
nav.enabled = false;
gameObject.GetComponent<Animator>().SetTrigger("dead");
}
else
{
nav.enabled = true;
nav.SetDestination(player.transform.position);
gameObject.GetComponent<Animator>().SetTrigger("run");
}
}
}
if(dist > Radius)
{
nav.enabled = false;
gameObject.GetComponent<Animator>().SetTrigger("idle");
}
}
}
Hang this script on different enemies, after hitting the hp should be taken from a specific enemy, not all.I tried to convert health to static - it didn't help. I made the private variable-it didn't help either. I searched for this answer on the Internet.
As this is not the full code, I assume a few things. Please correct me if I'm wrong.
It seems like you create a HitEffect(Clone) when the bullet hits the enemy, right?
With this approach you the enemy does never know if the HitEffect which was created is next to it or to another player.
It would be easier to do this with physics. Please check on the OnCollisionEnter Function.
This function can be set eather to the enemy or the bullet, (I would do it to the bullet for Class based programming reasons) and check if the other part is a enemy.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class bullet_collision : MonoBehaviour
{
public int damage = 25;
void OnCollisionEnter(Collision collision)
{
monster_animation m = collision.GetComponent<monster_animation>();
if (m != null)
{
m.health -= damage;
}
}
}

Unity - character starts to fly up when there should be gravity

I am developing a 2D platform game, where the character is a ball and should be able to move right and left, and to jump. It now does all that, but for some reason which i do not understand (as i am complitely new to Unity) sometimes it flies up like if the gravity was negative.
Here is the code of my first script Move2D:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Move2D : MonoBehaviour
{
public float moveSpeed = 5f;
public bool isGrounded = false;
[SerializeField] private Rigidbody2D rigidbody;
private Vector2 currentMoveDirection;
private void Awake()
{
rigidbody = GetComponent<Rigidbody2D>();
currentMoveDirection = Vector2.zero;
}
public void Jump()
{
if (isGrounded)
{
rigidbody.AddForce(new Vector3(0f, 5f), ForceMode2D.Impulse);
}
}
private void FixedUpdate()
{
rigidbody.velocity = (currentMoveDirection + new Vector2(0f, rigidbody.velocity.y)).normalized * moveSpeed;
}
public void TriggerMoveLeft()
{
currentMoveDirection += Vector2.left;
}
public void StopMoveLeft()
{
currentMoveDirection -= Vector2.left;
}
public void TriggerMoveRight()
{
currentMoveDirection += Vector2.right;
}
public void StopMoveRight()
{
currentMoveDirection -= Vector2.right;
}
}
And this is the code of the second script:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.EventSystems;
using UnityEngine.UI;
public class ContinuesButton : MonoBehaviour, IPointerDownHandler, IPointerUpHandler
{
[SerializeField] private Button targetButton;
[SerializeField] private Move2D playerMovement;
[SerializeField] private bool movesLeft;
private readonly bool isHover;
private void Awake()
{
if (!targetButton) targetButton = GetComponent<Button>();
}
public void OnPointerDown(PointerEventData eventData)
{
if (movesLeft)
{
playerMovement.TriggerMoveLeft();
} else
{
playerMovement.TriggerMoveRight();
}
}
public void OnPointerUp(PointerEventData eventData)
{
if (movesLeft)
{
playerMovement.StopMoveLeft();
} else
{
playerMovement.StopMoveRight();
}
}
}
I noticed that the ball starts to fly up as soon as the movement controller or some collider makes it go up a bit. For example when i make it jump, it just keeps going up, or when in the game i try to make it "walk" up a hill, it immediately starts flying up.
Any help or information is really appreciated, I really do not see the problem.
The issue I lies in normalized. This might unexpectedly increase the Y velocity. Especially in cases when you set the X velocity to 0 the Y component is taken into account to much.
I guess you should rather use something like
currentDirection * moveSpeed + Vector2.up * rigidbody.velocity.y;
In order to simply keep the current Y velocity.
Also be careful with these currentDirection += ...! I would suggest rather use single methods and use fixed values like e.g.
public void DoMove(bool right)
{
currentDirection = (right ? 1 : -1) * Vector2.right;
}
public void StopMove()
{
currentDirection = Vector2.zero;
}
And then rather call them like
public void OnPointerDown(PointerEventData eventData)
{
playerMovement.DoMove(!movesLeft);
}
public void OnPointerUp(PointerEventData eventData)
{
playerMovement.StopMove();
}

How would I implement navmesh pathfinding into this AI following code. C# Unity

I have this code that makes the enemy follow my player(And attack etc) but im not sure how to add navmesh into this so it can navigate obstacles. Currently, it goes forward and gets stuck on walls and obstacles.
I have never used navmesh before.
How would I implement navmesh pathfinding into this code.
Thank you.
using UnityEngine;
using System.Collections;
public class wheatleyfollow : MonoBehaviour {
public GameObject ThePlayer;
public float TargetDistance;
public float AllowedRange = 500;
public GameObject TheEnemy;
public float EnemySpeed;
public int AttackTrigger;
public RaycastHit Shot;
void Update() {
transform.LookAt (ThePlayer.transform);
if (Physics.Raycast (transform.position, transform.TransformDirection (Vector3.forward), out Shot)) {
TargetDistance = Shot.distance;
if (TargetDistance < AllowedRange) {
EnemySpeed = 0.05f;
if (AttackTrigger == 0) {
transform.position = Vector3.MoveTowards (transform.position, ThePlayer.transform.position, EnemySpeed);
}
} else {
EnemySpeed = 0;
}
}
if (AttackTrigger == 1) {
EnemySpeed = 0;
TheEnemy.GetComponent<Animation> ().Play ("wheatleyattack");
}
}
void OnTriggerEnter() {
AttackTrigger = 1;
}
void OnTriggerExit() {
AttackTrigger = 0;
}
}
To start off, we will require a NavMeshAgent on the object that will hold this script and we will then save a reference to the agent. We will also need a NavMeshPath to store our path (This isn't an attachable component, we will create it within the code).
All we need to do is update the path using CalculatePath and SetPath. You may need to fine tune the code some, but this is the very basics. You can use CalculatePath to generate a path then decide if you want to execute that path by using SetPath.
Note: We could use SetDestination, but if you have many AI units it can become slow if you need instant paths, which is why I normally use CalculatePath and SetPath.
Now all that is left is to make your navmesh Window -> Navigation. In there you can finetune your agents and areas. One required step is to bake your mesh in the Bake tab.
Unity supports navmeshes on components for prefabs and other things, however, these components are not yet built into Unity, as you will need to download them into your project.
As you can see all of your speed and movement has been removed since it is now controlled by your NavMeshAgent.
using UnityEngine;
using UnityEngine.AI;
[RequireComponent(typeof(NavMeshAgent))]
public class wheatleyfollow : MonoBehaviour {
public GameObject ThePlayer;
public float TargetDistance;
public float AllowedRange = 500;
public GameObject TheEnemy;
public int AttackTrigger;
public RaycastHit Shot;
private NavMeshAgent agent;
private NavMeshPath path;
void Start() {
path = new NavMeshPath();
agent = GetComponent<NavMeshAgent>();
}
void Update() {
if (Physics.Raycast(transform.position, transform.TransformDirection(Vector3.forward), out Shot)) {
TargetDistance = Shot.distance;
if (TargetDistance < AllowedRange && AttackTrigger == 0) {
agent.CalculatePath(ThePlayer.transform.position, path);
agent.SetPath(path);
}
}
if (AttackTrigger == 1) {
TheEnemy.GetComponent<Animation>().Play("wheatleyattack");
}
}
void OnTriggerEnter() {
AttackTrigger = 1;
}
void OnTriggerExit() {
AttackTrigger = 0;
}
}
Side Note: You should remove any using's that you are not using, as this can bloat your final build.

Unity - How can I use a flag to decide whether all the objects rotate at once or each one individually?

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
[System.Serializable]
public class SpinableObject
{
[SerializeField]
private Transform t;
[SerializeField]
private float rotationSpeed;
[SerializeField]
private float minSpeed;
[SerializeField]
private float maxSpeed;
[SerializeField]
private float speedRate;
private bool slowDown;
public void Rotate()
{
if (rotationSpeed > maxSpeed)
slowDown = true;
else if (rotationSpeed < minSpeed)
slowDown = false;
rotationSpeed = (slowDown) ? rotationSpeed - 0.1f : rotationSpeed + 0.1f;
t.Rotate(Vector3.forward, Time.deltaTime * rotationSpeed);
}
}
public class SpinObject : MonoBehaviour
{
private bool slowDown = false;
private GameObject[] allPropellers;
public bool rotateAll = false;
public float rotationSpeed;
public float slowdownMax;
public float slowdownMin;
public SpinableObject[] objectsToRotate;
// Use this for initialization
void Start()
{
allPropellers = GameObject.FindGameObjectsWithTag("Propeller");
}
// Update is called once per frame
void Update()
{
if (rotateAll == false)
{
for (int i = 0; i < objectsToRotate.Length; i++)
{
objectsToRotate[i].Rotate();
}
}
else
{
objectsToRotate = new SpinableObject[allPropellers.Length];
for (int i = 0; i < allPropellers.Length; i++)
{
objectsToRotate[i].Rotate();
}
}
}
}
In the else in this part I want that all the objects will rotate with the global variables settings. And if the rotateAll is false each one will rotate with their own options settings.
objectsToRotate = new SpinableObject[allPropellers.Length];
for (int i = 0; i < allPropellers.Length; i++)
{
objectsToRotate[i].Rotate();
}
But here I'm only make instance for more places in the objectsToRotate they are all null. And I'm not sure using objectsToRotate is good to rotate them all at once.
Update: This is what i tried now:
I changed the SpinableObject script to:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
[System.Serializable]
public class SpinableObject
{
public Transform t;
public float rotationSpeed;
public float minSpeed;
public float maxSpeed;
public float speedRate;
public bool slowDown;
}
public class SpinObject : MonoBehaviour
{
public SpinableObject[] objectsToRotate;
private Rotate _rotate;
private int index = 0;
private bool rotateAll;
// Use this for initialization
void Start()
{
}
// Update is called once per frame
void Update()
{
var _objecttorotate = objectsToRotate[index];
_rotate.t = _objecttorotate.t;
_rotate.rotationSpeed = _objecttorotate.rotationSpeed;
_rotate.minSpeed = _objecttorotate.minSpeed;
_rotate.maxSpeed = _objecttorotate.maxSpeed;
_rotate.speedRate = _objecttorotate.speedRate;
_rotate.slowDown = _objecttorotate.slowDown;
index++;
}
}
And created a new script name Rotate:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Rotate : MonoBehaviour
{
public Transform t;
public float rotationSpeed;
public float minSpeed;
public float maxSpeed;
public float speedRate;
public bool slowDown;
// Use this for initialization
void Start ()
{
}
// Update is called once per frame
void Update ()
{
RotateObject();
}
public void RotateObject()
{
if (rotationSpeed > maxSpeed)
slowDown = true;
else if (rotationSpeed < minSpeed)
slowDown = false;
rotationSpeed = (slowDown) ? rotationSpeed - 0.1f : rotationSpeed + 0.1f;
t.Rotate(Vector3.forward, Time.deltaTime * rotationSpeed);
}
}
The idea is to feed the variables and settings in the script Rotate from the script SpinableObject.
But i messed it up it's not working and give me some null exception.
Is it a good way ? And how can i fix the scripts to work with each other so the SpinableObject will feed the Rotate with data.
This is how I would approach your problem.
I will define a global variable to determine if objects are rotating all at the same time or independently.
Then I will create a script called rotation and I will add it to each GameObject in your scene which will rotate.
In this script I will just include the
...
Update()
{
if (rotateAll == false)
{
Rotate(allProperties)
}else{
Rotate(particularProperties)
}
}
//Here you can implement the Rotate function passing the attributes you consider to make the rotation different for each case
...
And about global variables in Unity. One possible approach is to define a class like:
public static class GlobalVariables{
public static boolean rotationType;
}
Then you can access and modigy this variable from another script like:
GlobalVariables.rotationType = true;
if(GlobalVariables.rotationType){
...
}
After Edit:
I canĀ“t really tell what you are doing wrong, but if there is a null exception it may be you are not calling properly from the script the gameObjects you want to rotate. It could be you are not linking them correctly in the inspector. If you have declare
public SpinableObject[] objectsToRotate;
It is possible you forgot to drag and drop in the inspector the GamesObjets into the array to populate it. But I can't be sure if the problem is just that.

Categories