I am trying to use zoom with two fingers but unfortunately whenever I place two fingers together, the starting value of camera.fieldOfView changes drastically. As in it is not able to read the current value. I feel it goes to some other value. It should start from the current value. What am I doing wrong here?
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.InputSystem.EnhancedTouch;
using Touch = UnityEngine.InputSystem.EnhancedTouch.Touch;
public Camera camera;
float touchDist = 0;
float lastDist = 0;
public float maxAngle = 60;
public float minAngle = 30;
private void Start()
{
EnhancedTouchSupport.Enable();
}
public void Update()
{
if (Touch.activeFingers.Count == 2)
{
Touch activeTouch = Touch.activeFingers[0].currentTouch;
Touch touch1 = Touch.activeFingers[0].currentTouch;
Touch touch2 = Touch.activeFingers[1].currentTouch;
if (touch1.phase == UnityEngine.InputSystem.TouchPhase.Began && touch2.phase == UnityEngine.InputSystem.TouchPhase.Began)
{
lastDist = Vector2.Distance(touch1.screenPosition, touch2.screenPosition);
}
if (touch1.phase == UnityEngine.InputSystem.TouchPhase.Moved && touch2.phase == UnityEngine.InputSystem.TouchPhase.Moved)
{
float newDist = Vector2.Distance(touch1.screenPosition, touch2.screenPosition);
touchDist = lastDist - newDist;
lastDist = newDist;
// Your Code Here
camera.fieldOfView += touchDist * 0.05f;
if (camera.fieldOfView > maxAngle)
{
camera.fieldOfView = maxAngle;
}
if (camera.fieldOfView < minAngle)
{
camera.fieldOfView = minAngle;
}
}
}
}
}
Related
So, I created a game, where I need to simulate fog. The fog is supposed to be displayed when rain >= 50 mm. I implemented the logic as follows, please refer the part where I commented as //What needs to be added here so as the Fog will start to be displayed at rain >= 50 on "_slider" slider
P.s., the block:
public void _FogIntensity(float newHeightDensity)
{
heightDensity = newHeightDensity;
}
is used in the file "GlobalFog.cs" and function "public void SliderLogic()" , given below: to control the Fog Intensity with respect to slider, I need to activate the slider when rain count >=50 mm; else, not.
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
using UnityEngine.UI;
using TMPro;
using static UnityStandardAssets.ImageEffects.GlobalFog;
namespace UnityStandardAssets.ImageEffects
{
[ExecuteInEditMode]
[RequireComponent (typeof(Camera))]
[AddComponentMenu ("Image Effects/Rendering/Global Fog")]
class GlobalFog : PostEffectsBase
{
[SerializeField] private Slider _slider;
[SerializeField] private Slider _sliderFog;
[SerializeField] private TextMeshProUGUI _sliderText;
[SerializeField] private TextMeshProUGUI WarnText;
[SerializeField] private TextMeshProUGUI Subtitles;
[Tooltip("Apply distance-based fog?")]
public bool distanceFog = true;
[Tooltip("Exclude far plane pixels from distance-based fog? (Skybox or clear color)")]
public bool excludeFarPixels = true;
[Tooltip("Distance fog is based on radial distance from camera when checked")]
public bool useRadialDistance = false;
[Tooltip("Apply height-based fog?")]
public bool heightFog = true;
[Tooltip("Fog top Y coordinate")]
public float height = 1.0f;
[Range(0.001f,10.0f)]
public float heightDensity = 1.0f;
[Tooltip("Push fog away from the camera by this amount")]
public float startDistance = 0.0f;
public Shader fogShader = null;
private Material fogMaterial = null;
public override bool CheckResources ()
{
CheckSupport (true);
fogMaterial = CheckShaderAndCreateMaterial (fogShader, fogMaterial);
if (!isSupported)
ReportAutoDisable ();
return isSupported;
}
[ImageEffectOpaque]
void OnRenderImage(RenderTexture source, RenderTexture destination)
{
if (CheckResources() == false || (!distanceFog && !heightFog))
{
Graphics.Blit(source, destination);
return;
}
Camera cam = GetComponent<Camera>();
Transform camtr = cam.transform;
Vector3[] frustumCorners = new Vector3[4];
cam.CalculateFrustumCorners(new Rect(0, 0, 1, 1), cam.farClipPlane, cam.stereoActiveEye, frustumCorners);
var bottomLeft = camtr.TransformVector(frustumCorners[0]);
var topLeft = camtr.TransformVector(frustumCorners[1]);
var topRight = camtr.TransformVector(frustumCorners[2]);
var bottomRight = camtr.TransformVector(frustumCorners[3]);
Matrix4x4 frustumCornersArray = Matrix4x4.identity;
frustumCornersArray.SetRow(0, bottomLeft);
frustumCornersArray.SetRow(1, bottomRight);
frustumCornersArray.SetRow(2, topLeft);
frustumCornersArray.SetRow(3, topRight);
var camPos = camtr.position;
float FdotC = camPos.y - height;
float paramK = (FdotC <= 0.0f ? 1.0f : 0.0f);
float excludeDepth = (excludeFarPixels ? 1.0f : 2.0f);
fogMaterial.SetMatrix("_FrustumCornersWS", frustumCornersArray);
fogMaterial.SetVector("_CameraWS", camPos);
fogMaterial.SetVector("_HeightParams", new Vector4(height, FdotC, paramK, heightDensity * 0.5f));
fogMaterial.SetVector("_DistanceParams", new Vector4(-Mathf.Max(startDistance, 0.0f), excludeDepth, 0, 0));
var sceneMode = RenderSettings.fogMode;
var sceneDensity = RenderSettings.fogDensity;
var sceneStart = RenderSettings.fogStartDistance;
var sceneEnd = RenderSettings.fogEndDistance;
Vector4 sceneParams;
bool linear = (sceneMode == FogMode.Linear);
float diff = linear ? sceneEnd - sceneStart : 0.0f;
float invDiff = Mathf.Abs(diff) > 0.0001f ? 1.0f / diff : 0.0f;
sceneParams.x = sceneDensity * 1.2011224087f; // density / sqrt(ln(2)), used by Exp2 fog mode
sceneParams.y = sceneDensity * 1.4426950408f; // density / ln(2), used by Exp fog mode
sceneParams.z = linear ? -invDiff : 0.0f;
sceneParams.w = linear ? sceneEnd * invDiff : 0.0f;
fogMaterial.SetVector("_SceneFogParams", sceneParams);
fogMaterial.SetVector("_SceneFogMode", new Vector4((int)sceneMode, useRadialDistance ? 1 : 0, 0, 0));
int pass = 0;
if (distanceFog && heightFog)
pass = 0; // distance + height
else if (distanceFog)
pass = 1; // distance only
else
pass = 2; // height only
Graphics.Blit(source, destination, fogMaterial, pass);
}
//Changes made in the below line
public void _FogIntensity(float newHeightDensity)
{
heightDensity = newHeightDensity;
}
// Start is called before the first frame update
public void SliderLogic()
{
_slider.onValueChanged.AddListener((v) =>
{
_sliderText.text = v.ToString("0.0") + "mm/hour";
//On case of moderate Rain
else if (_slider.value >= 2 && _slider.value <= 10)
{
WarnText.text = "Moderate Rainfall";
Subtitles.SetText("(Take out your umbrellas.)");
}
//In case if Heavy Rain
else if (_slider.value >= 10 && _slider.value <= 50)
{
WarnText.text = "Heavy Showers";
Subtitles.SetText("(Orange Alert; Exercise Caution!.)");
}
//In case if Extreme Downpour
else if (_slider.value >= 50 || (_sliderFog.value > 0))
{
WarnText.text = "Violent Showers";
Subtitles.SetText("(Heavy precipitation. Do not venture out unless absolutely necessary!.)");
//What needs to be added here so as the Fog will start to be displayed at rain >= 50 on "_slider" slider
}
});
}
}
}
I am trying to convert pinch to zoom from old input to new Input system using EnhancedTouch.Touch. Unfortunately I am clueless as to how to move forward from here? I am getting error as Operator '==' cannot be applied to operands of type 'TouchPhase' and 'TouchPhase'. How do I fix this?
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.InputSystem.EnhancedTouch;
using Touch = UnityEngine.InputSystem.EnhancedTouch.Touch;
public class ZoomTouch : MonoBehaviour {
public Camera camera;
float touchDist = 0;
float lastDist = 0;
public void Update () {
if (Input.touchCount == 2) {
Touch touch1 = Touch.activeFingers[0].currentTouch;
Touch touch2 = Touch.activeFingers[0].currentTouch;
if (touch1.phase == TouchPhase.Began && touch2.phase == TouchPhase.Began) {
lastDist = Vector2.Distance (touch1.position, touch2.position);
}
if (touch1.phase == TouchPhase.Moved && touch2.phase == TouchPhase.Moved) {
float newDist = Vector2.Distance (touch1.position, touch2.position);
touchDist = lastDist - newDist;
lastDist = newDist;
camera.fieldOfView += touchDist * 0.1f;
}
}
}
}
I hope this code works. However, I did not have a touch device to test it. This simple code works, takes the distance between the present and the past, and zooms in on their delta.
public float lastDistance;
public float distance;
void Update()
{
if (Input.touchCount < 2) return;
var touch1 = Input.GetTouch(0);
var touch2 = Input.GetTouch(1);
distance = Vector2.Distance(touch1.position, touch1.position);
if (Mathf.Abs(lastDistance-distance) >= 10) lastDistance = distance; // for avoiding sharp zooms on first touch
Camera.main.fieldOfView += distance-lastDistance * 0.1f;
lastDistance = distance;
}
I'm trying to programm my own little game in Unity, I'm not new to programming but new to Unity and C#. The problem is that I wrote my own classes to handle the game map and I am trying to connect these classes to the MonoBehaviour Scripts in Unity.
I have a script called InputManager, which is supposed to handle the input via mouse and keyboard etc. and in this script I want to create an object of the class MapManager which has access to my tiles and stuff. The problem I'm getting is that I can't seem to create an instance of MapManager in InputManager, not with the common new MapManager() anyway. When I use this a NullPointer of some sort is created, I guess?
I do not get a compiling error but an error once the game is launched which is:
NullReferenceException: Object reference not set to an instance of an object
InputManager.Update () (at Assets/Scripts/InputManager.cs:55)
Thank you for your help!
!UPDATE!:
I tried using a workaround so that it does not matter if Start() or Update() is called first, meaning that I just instantiate MapManager in the first Update() call. However, when I run the program the error is still the same. My conclusion is that somehow my constructor is not working or the Monobehaviour script somehow does not allow using the standard constructor... Any ideas?
Here is my code:
InputManager.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Tilemaps;
public class InputManager : MonoBehaviour
{
public int mapRightBorder = 10;
public int mapLeftBorder = -10;
public int mapTopBorder = 8;
public int mapBottomBorder = -4;
public double camSpeed = 0.2;
public double mouseSensitivity = 0.3;
public double scrollSensitivity = 2;
public double maxZoomIn = -3;
public double maxZoomOut = -12;
public Tilemap ground, overlays, buildings;
public Tilemap selected;
public AnimatedTile animatedTile;
private double detectionBorder;
private double leftRightCorrection;
private MapManager mapManager;
// Start is called before the first frame update
void Start()
{
detectionBorder = 50;
leftRightCorrection = 1.2;
mapManager = new MapManager();
mapManager.ground = ground;
mapManager.overlays = overlays;
mapManager.buildings = buildings;
mapManager.selected = selected;
mapManager.animatedTile = animatedTile;
Cursor.lockState = CursorLockMode.Confined;
}
// Update is called once per frame
void Update()
{
moveCam();
checkMouse();
mapManager.updateTilemaps();
}
private void moveCam()
{
double moveX = Camera.main.transform.position.x;
double moveY = Camera.main.transform.position.y;
double moveZ = Camera.main.transform.position.z;
double xPos = Input.mousePosition.x;
double yPos = Input.mousePosition.y;
double zDelta = Input.GetAxis("Mouse ScrollWheel");
if (Input.GetKey(KeyCode.LeftArrow))
{
moveX -= camSpeed * leftRightCorrection;
}
else if (xPos >= 0 && xPos < detectionBorder)
{
moveX -= camSpeed * mouseSensitivity * leftRightCorrection;
}
else if (Input.GetKey(KeyCode.RightArrow))
{
moveX += camSpeed * leftRightCorrection;
}
else if (xPos <= Screen.width && xPos > Screen.width - detectionBorder)
{
moveX += camSpeed * mouseSensitivity * leftRightCorrection;
}
if(moveX > mapRightBorder || moveX < mapLeftBorder)
{
moveX = Camera.main.transform.position.x;
}
if (Input.GetKey(KeyCode.DownArrow))
{
moveY -= camSpeed;
}
else if (yPos >= 0 && yPos < detectionBorder)
{
moveY -= camSpeed * mouseSensitivity;
}
else if (Input.GetKey(KeyCode.UpArrow))
{
moveY += camSpeed;
}
else if (yPos <= Screen.height && yPos > Screen.height - detectionBorder)
{
moveY += camSpeed * mouseSensitivity;
}
if(moveY > mapTopBorder || moveY < mapBottomBorder)
{
moveY = Camera.main.transform.position.y;
}
if (!(moveZ + zDelta * scrollSensitivity > maxZoomIn || moveZ + zDelta * scrollSensitivity < maxZoomOut))
{
moveZ += zDelta * scrollSensitivity;
}
Vector3 newPos = new Vector3((float)moveX, (float)moveY, (float) moveZ);
Camera.main.transform.position = newPos;
}
private void checkMouse()
{
if (Input.GetMouseButtonDown(0))
{
mapManager.selectTile(Input.mousePosition);
}
}
}
MapManager.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Tilemaps;
public class MapManager
{
public int mapWidth = 16;
public int mapHeight = 16;
public Tilemap ground, overlays, buildings;
public Tilemap selected;
public AnimatedTile animatedTile;
private Vector3Int currentlySelected;
private OwnTilemap tilemap;
public MapManager()
{
tilemap = new OwnTilemap(mapWidth, mapHeight, ground, overlays, buildings);
currentlySelected = new Vector3Int(-1, -1, 0);
}
private Vector3Int mouseToTilemap(Vector3 mousePosition)
{
Ray ray = Camera.main.ScreenPointToRay(mousePosition);
// create a plane at 0,0,0 whose normal points to +Y:
Plane hPlane = new Plane(Vector3.forward, Vector3.zero);
// Plane.Raycast stores the distance from ray.origin to the hit point in this variable:
float enter = 0.0f;
if (hPlane.Raycast(ray, out enter))
{
//Get the point that is clicked
Vector3 hitPoint = ray.GetPoint(enter);
Vector3Int cell = ground.WorldToCell(hitPoint);
return cell;
}
return new Vector3Int(-1, -1, 0);
}
private bool isInBorders(Vector3Int p)
{
if (p.z != 0) return false;
if (p.x < 0 || p.x >= mapWidth) return false;
if (p.y < 0 || p.y >= mapHeight) return false;
return true;
}
public void updateTilemaps()
{
tilemap.updateTilemaps();
}
public void previewBuilding()
{
}
public void selectTile(Vector3 mousePosition)
{
if(currentlySelected != new Vector3Int(-1, -1, 0))
{
selected.SetTile(currentlySelected, null);
}
if (isInBorders(mouseToTilemap(mousePosition)))
{
selected.SetTile(mouseToTilemap(mousePosition), animatedTile);
currentlySelected = mouseToTilemap(mousePosition);
}
}
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class MoveCameraBehind : MonoBehaviour
{
public GameObject camera;
public List<GameObject> targets = new List<GameObject>();
public float cameraDistance = 10.0f;
public bool behindMultipleTargets = false;
public string cameraWarningMsgs = "";
public string targetsWarningMsgs = "";
// Use this for initialization
void Start()
{
if (camera == null)
{
var cam = GetComponent<Camera>();
if (cam != null)
{
cameraWarningMsgs = "Gettig camera component.";
camera = transform.gameObject;
}
else
{
cameraWarningMsgs = "Creating a new camera component.";
GameObject NewCam = Instantiate(new GameObject(), transform);
NewCam.name = "New Camera";
NewCam.AddComponent<Camera>();
camera = NewCam;
}
}
if(targets.Count == 0)
{
targetsWarningMsgs = "No targets found.";
}
}
void FixedUpdate()
{
if (targets.Count > 0)
{
MoveCameraToPosition();
}
}
public void MoveCameraToPosition()
{
if (targets.Count > 1 && behindMultipleTargets == true)
{
var center = CalculateCenter();
transform.position = new Vector3(center.x, center.y + 2, center.z + cameraDistance);
}
if (behindMultipleTargets == false)
{
Vector3 center = targets[0].transform.position - targets[0].transform.forward * cameraDistance;
transform.position = new Vector3(center.x, center.y + 2, center.z);
}
}
private Vector3 CalculateCenter()
{
Vector3 center = new Vector3();
var totalX = 0f;
var totalY = 0f;
foreach (var target in targets)
{
totalX += target.transform.position.x;
totalY += target.transform.position.y;
}
var centerX = totalX / targets.Count;
var centerY = totalY / targets.Count;
center = new Vector3(centerX, centerY);
return center;
}
}
The CalculateCenter function make the targets(objects) to change positions and vanish away far away. Even if there is only one single target.
What I want to do is if there is one object for example one 3d cube position the camera behind the cube. And if there are more cubes for example two or ten and the camera is somewhere else calculate the middle position behind the targets and position the camera in the middle behind them.
To show what I mean in this example the view(like a camera) is behind the two soldiers in the middle position between them from behind.
But what if there are 5 soldiers how can I find the middle position and then position the camera behind them like this example in the screenshot ?
This is my old script version was working fine but only for 1 or 2 targets. But if there are 5 targets(soldiers) how can I position the camera behind them in the middle ? Like in the screenshot example.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class MoveCameraBehind : MonoBehaviour
{
public GameObject camera;
public List<GameObject> targets = new List<GameObject>();
public float cameraDistance = 10.0f;
public bool behindTwoTargets = false;
public string warningMsgs = "";
// Use this for initialization
void Start()
{
if (camera == null)
{
var cam = GetComponent<Camera>();
if (cam != null)
{
warningMsgs = "Gettig Camera omponent.";
camera = transform.gameObject;
}
else
{
warningMsgs = "Creating a new camera component.";
GameObject NewCam = Instantiate(new GameObject(), transform);
NewCam.name = "New Camera";
NewCam.AddComponent<Camera>();
camera = NewCam;
}
}
camera.transform.Rotate(0, 180, 0);
}
void FixedUpdate()
{
if (targets.Count > 0)
{
MoveCameraToPosition();
}
}
public void MoveCameraToPosition()
{
if (targets.Count == 2 && behindTwoTargets == true)
{
Vector3 center = ((targets[0].transform.position - targets[1].transform.position) / 2.0f) + targets[1].transform.position;
camera.transform.position = new Vector3(center.x, center.y + 2, center.z + cameraDistance);
}
if (behindTwoTargets == false)
{
Vector3 center = targets[0].transform.position - targets[0].transform.forward * cameraDistance;
camera.transform.position = new Vector3(center.x, center.y + 2, center.z);
}
}
}
This is my last version of my working code still using the CalculateCenter function :
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
public class CameraLook : MonoBehaviour
{
public GameObject camera;
public List<GameObject> targets = new List<GameObject>();
public float cameraDistance = 10.0f;
public float cameraHeight = 2f;
public float rotateTime = 2f;
public bool multipleTargets = false;
public bool changeRandomTarget = false;
public bool behindFront = false;
public bool targetsRandomRot = false;
public string cameraWarningMsgs = "";
public string targetsWarningMsgs = "";
private List<Vector3> vectors = new List<Vector3>();
//Random move rotation timer part
Quaternion qTo;
float speed = 3f;
float timer = 0.0f;
// Use this for initialization
void Start()
{
qTo = Quaternion.Euler(new Vector3(0.0f, Random.Range(-180.0f, 180.0f), 0.0f));
if (camera == null)
{
var cam = GetComponent<Camera>();
if (cam != null)
{
cameraWarningMsgs = "Gettig camera component.";
camera = transform.gameObject;
}
else
{
cameraWarningMsgs = "Creating a new camera component.";
GameObject NewCam = Instantiate(new GameObject(), transform);
NewCam.name = "New Camera";
NewCam.AddComponent<Camera>();
camera = NewCam;
}
}
if (targets.Count == 0)
{
targetsWarningMsgs = "No targets found.";
}
else
{
foreach(GameObject vector in targets)
{
vectors.Add(vector.transform.position);
}
}
}
void FixedUpdate()
{
if (targets.Count > 0)
{
MoveCameraToPosition();
if (targetsRandomRot == true)
{
RotateTargetsRandom();
}
}
}
public void MoveCameraToPosition()
{
Vector3 center = CalculateCenter();
camera.transform.position = center;
if (behindFront == false)
{
camera.transform.rotation = Quaternion.LookRotation(-center, Vector3.up);
}
else
{
camera.transform.rotation = Quaternion.LookRotation(center, Vector3.up);
}
}
private Vector3 CalculateCenter()
{
Vector3 center = new Vector3();
var x = targets[0].transform.position.x;
var y = targets[0].transform.position.y;
var z = targets[0].transform.position.z;
if (multipleTargets == true)
{
for (int i = 1; i < targets.Count; i++)
{
x += targets[i].transform.position.x;
y += targets[i].transform.position.y;
z += targets[i].transform.position.z;
}
}
else
{
x += targets[0].transform.position.x;
y += targets[0].transform.position.y;
z += targets[0].transform.position.z;
}
if(changeRandomTarget == true)
{
for (int i = 1; i < targets.Count; i++)
{
x += targets[i].transform.position.x;
y += targets[i].transform.position.y;
z += targets[i].transform.position.z;
}
}
x = x / targets.Count;
y = y / targets.Count;
z = z / targets.Count;
if (behindFront == false)
{
center = new Vector3(x, y + cameraHeight, z + cameraDistance);
}
else
{
center = new Vector3(x, y + cameraHeight, z - cameraDistance);
}
return center;
}
private void RotateTargetsRandom()
{
timer += Time.deltaTime;
if (timer > rotateTime)
{ // timer resets at 2, allowing .5 s to do the rotating
qTo = Quaternion.Euler(new Vector3(0.0f, Random.Range(-180.0f, 180.0f), 0.0f));
timer = 0.0f;
}
foreach (var target in targets)
{
target.transform.rotation = Quaternion.Slerp(target.transform.rotation, qTo, Time.deltaTime * speed);
}
}
}
And now I want to add and use the bool flag changeRandomTarget :
But not sure how to do it :
if(changeRandomTarget == true)
{
for (int i = 1; i < targets.Count; i++)
{
x += targets[i].transform.position.x;
y += targets[i].transform.position.y;
z += targets[i].transform.position.z;
}
}
I want that each X seconds it will pick a random center and change the camera position according to it. For example the first item in the targets List the last item and all the items so each X seconds the center will be once behind targets[0] or targets1 or targets[i]
Not sure how to do it with my code or with derHugo solution.
Surely you just find the average
so
if (mobcount > 1)
{
var x=mob[0].position.x;
var y=mob[0].position.y;
var z=mob[0].position.z;
for(int i=1; i<mobcount; i++)
{
x += mob[i].position.x;
y += mob[i].position.y;
z += mob[i].position.z;
}
x = x / mobcount;
y = y / mobcount;
z = z / mobcount;
}
therefore the camera should look at the position x,y,z.. and perhaps set the distance to be a fixed distance behind the nearest mob...
Actually you don't even need to do it component wise:
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
...
private static Vector3 Average(IReadOnlyCollection<Vector3> vectors)
{
if(vectors == null) return Vector3.zero;
switch (vectors.Count)
{
case 0:
return Vector3.zero;
case 1:
return vectors.First();
default:
var average = Vector3.zero;
foreach(var vector in vectors)
{
average += vector;
}
return average / vectors.Count;
}
}
Or directly using Linq aggregate
private static Vector3 Average(IReadOnlyCollection<Vector3> vectors)
{
if(vectors == null) return Vector3.zero;
switch (vectors.Count)
{
case 0:
return Vector3.zero;
case 1:
return vectors.First();
default:
var average = vectors.Aggregate(Vector3.zero, (current, vector) => current + vector);
return average / vectors.Count;
}
}
Now I'm using the F key to make it scale up or down.
But I want to add another method for example AutoScaling that when calling it in Update it will scale up first once finished scaling up it will scale down and then up again and so no nonstop.
The Scaling script :
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Scaling : UnityEngine.MonoBehaviour
{
public GameObject objectToScale;
public GameObject lookAtTarget;
public float duration = 1f;
public Vector3 minSize;
public Vector3 maxSize;
public bool scaleUp = false;
public Coroutine scaleCoroutine;
public bool scalingHasFinished = false;
public void Inits()
{
scalingHasFinished = false;
objectToScale.transform.localScale = minSize;
}
public IEnumerator scaleOverTime(GameObject targetObj, Vector3 toScale, float duration, Camera objectToScaleCamera)
{
float counter = 0;
Vector3 startScaleSize = targetObj.transform.localScale;
while (counter < duration)
{
counter += Time.deltaTime;
targetObj.transform.localScale = Vector3.Lerp(startScaleSize, toScale, counter / duration);
if (scaleUp)
{
var lookPos = lookAtTarget.transform.position - objectToScale.transform.position;
lookPos.y = 0;
var rotation = Quaternion.LookRotation(lookPos);
objectToScale.transform.rotation = Quaternion.Slerp(objectToScale.transform.rotation, rotation, counter / duration);
}
else
{
var lookPos = lookAtTarget.transform.position - objectToScale.transform.position;
lookPos.y = 0;
var rotation = Quaternion.LookRotation(objectToScaleCamera.transform.forward);//SwitchCameras.GetCurrentCamera().transform.forward);//Camera.main.transform.forward);
objectToScale.transform.rotation = Quaternion.Slerp(objectToScale.transform.rotation, rotation, counter / duration);
}
yield return null;
}
scalingHasFinished = true;
}
public IEnumerator scaleOverTime(GameObject targetObj, Vector3 toScale, float duration, float rotationSpeed)
{
float counter = 0;
Vector3 startScaleSize = targetObj.transform.localScale;
while (counter < duration)
{
counter += Time.deltaTime;
targetObj.transform.localScale = Vector3.Lerp(startScaleSize, toScale, counter / duration);
targetObj.transform.Rotate(Vector3.up * rotationSpeed * Time.deltaTime, Space.Self);
yield return null;
}
}
}
And the script that use the scaling :
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class ObjectsManipulation : UnityEngine.MonoBehaviour
{
//Camera
public Camera playerCamera;
//Scaling
private bool canScale = true;
private Scaling scaling;
//Lights
public DimLights dimlights;
private Coroutine lightCoroutine;
//Colors
private Colors colors;
//Rotating
private bool stopRotation = false;
private Rotating rotating;
private void Start()
{
scaling = GetComponent<Scaling>();
scaling.Inits();
colors = GetComponent<Colors>();
colors.Start();
rotating = GetComponent<Rotating>();
}
// Use this for initialization
void Update()
{
if (playerCamera != null)
{
//Scaling
if (Input.GetKeyDown(KeyCode.F) && canScale == true)
{
Scaling();
}
}
//Rotate
if (Input.GetKey(KeyCode.R) && !scaling.scaleUp)
{
rotating.x += Time.deltaTime * rotating.rotationSpeed;
scaling.objectToScale.transform.localRotation = Quaternion.Euler(0, 0, rotating.x);
rotating.keyPressed = true;
}
if (Input.GetKeyUp(KeyCode.R))
{
rotating.keyPressed = false;
}
if (!rotating.keyPressed && !scaling.scaleUp && rotating.rotateBack == false
&& DetectInteractable.detected == false)
{
scaling.objectToScale.transform.rotation = Quaternion.LookRotation(playerCamera.transform.forward);
}
if (DetectInteractable.detected == true && !scaling.scaleUp && stopRotation == false)
{
rotating.x += Time.deltaTime * rotating.rotationSpeed;
scaling.objectToScale.transform.localRotation = Quaternion.Euler(0, 0, rotating.x);
}
}
public void Scaling()
{
//Flip the scale direction when F key is pressed
scaling.scaleUp = !scaling.scaleUp;
//Stop old coroutine
if (scaling.scaleCoroutine != null)
StopCoroutine(scaling.scaleCoroutine);
if (lightCoroutine != null)
StopCoroutine(lightCoroutine);
//Scale up
if (scaling.scaleUp)
{
//Start new coroutine and scale up within 5 seconds and return the coroutine reference
rotating.rotateBack = false;
scaling.scaleCoroutine = StartCoroutine(scaling.scaleOverTime(scaling.objectToScale, scaling.maxSize, scaling.duration, playerCamera));
if (dimlights.lightsOnOff == false)
lightCoroutine = StartCoroutine(dimlights.dimLightOverTime(1, scaling.duration));
}
//Scale Down
else
{
//Start new coroutine and scale up within 5 seconds and return the coroutine reference
rotating.rotateBack = true;
scaling.scaleCoroutine = StartCoroutine(scaling.scaleOverTime(scaling.objectToScale, scaling.minSize, scaling.duration, playerCamera));
if (dimlights.lightsOnOff == false)
lightCoroutine = StartCoroutine(dimlights.dimLightOverTime(0, scaling.duration)); ;
}
}
}
And in third script I want to call a method that will be in the ObjectsManipulation script maybe the same method Scaling maybe he will get a bool and if the bool is true make it scaling up/down automatic if it's not true make it use a key.
This is the script for testing the Scaling :
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class ScalingTest : MonoBehaviour
{
ObjectsManipulation om;
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
void Update()
{
om.Scaling();
}
}
For example in the Update maybe to do : om.Scaling(false); for using the F key and om.Scaling(true); for automatic.
Update of what I have tried :
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using UnityEditor;
using UnityEngine;
public class ConversationTrigger : MonoBehaviour
{
public List<Conversation> conversations = new List<Conversation>();
[HideInInspector]
public int dialogueIndex;
[HideInInspector]
public int conversationIndex;
private bool triggered = false;
private bool activateButton = false;
private DialogueManager dialoguemanager;
private bool startDialogue = false;
private void Start()
{
dialogueIndex = 0;
dialoguemanager = FindObjectOfType<DialogueManager>();
}
public IEnumerator PlayConversation(int index)
{
this.conversationIndex = index;
if (conversations.Count > 0 &&
conversations[index].Dialogues.Count > 0)
{
for (int i = 0; i < conversations[index].Dialogues.Count; i++)
{
if (triggered == false)
{
if (dialoguemanager != null)
{
dialoguemanager.StartDialogue(conversations[index].Dialogues[i]);
}
while (DialogueManager.dialogueEnded == false)
{
yield return null;
}
}
}
}
}
public void SaveConversations()
{
string jsonTransform = JsonHelper.ToJson(conversations.ToArray(), true);
File.WriteAllText(#"d:\json.txt", jsonTransform);
}
public void LoadConversations()
{
string jsonTransform = File.ReadAllText(#"d:\json.txt");
conversations.Clear();
conversations.AddRange(JsonHelper.FromJson<Conversation>(jsonTransform));
}
}
And using it like this :
StartCoroutine(conversationTrigger.PlayConversation(0));
Where conversationTrigger is public ConversationTrigger conversationTrigger;
But it's not working good at all. It's starting the conversation index 0 but then play only the first dialogue sentences twice and then never continue to the next dialogue there are two dialogues in this case. And then it stop.
It should play all the dialogues of the current conversation.
Something in the PlayConversation method is wrong.
I'm sorry to say your post is long and contains many redundant codes, so I haven't carefully read it, this is a simple reference about making a zoom animation by script.
float minScale; // Minimum scale value
float maxScale; // Maximum scale value
Transform target; // Target to scale
void Update()
{
float scale = Mathf.PingPong(Time.time, maxScale - minScale) + minScale;
target.localScale = new Vector3(scale, scale, scale);
}