I'm trying to come up with a generic rule that I can add to any GameObject. Items like tables, chairs etc that once collided and interacted fade in the white text, then after a few seconds the text fades out.
Ideally I'd be able to offset the position of this text with a Vector3 so I can position it around my character
At the moment I have, some code but the CrossFade.Alpha doesn't seem to work. this might or might not be the best way to go about this, I'm open to new ideas
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class Qwerty : MonoBehaviour
{
public float Radius = 1f;
public Text TextToUse;
[SerializeField] private LayerMask playerMask;
private bool isInSphere;
// Start is called before the first frame update
void Start()
{
isInSphere = false;
}
// Update is called once per frame
void Update()
{
isInSphere = Physics.CheckSphere(transform.position, Radius, playerMask);
if (isInSphere && Input.GetKey(KeyCode.F) == true)
{
// Check if collision is detected and F is pressed
isInSphere = true;
Debug.Log("Hello");
//Fade in over 2 seconds
TextToUse.CrossFadeAlpha(1, 2f, false);
}
else if (!isInSphere && !Input.GetKey(KeyCode.F))
{
//Fade out on leave over 2 seconds
isInSphere = false;
TextToUse.CrossFadeAlpha(0, 2f, false);
}
}
}
Description
Tweens the alpha of the CanvasRenderer color associated with this Graphic.
Creates a fading effect on a Graphic with a CanvasRenderer attached. Choose an alpha level to fade to, and pick the speed of the fade to see a smooth fade over time. UI Images and Text are some of the elements that you are able to apply this effect to.
CrossFade.Alpha needs a canvas that has CanvasRenderer attached to work.
Related
I am trying to get my Spawner.cs script to work in Unity on a flappy bird game I am making. I am following this tutorial.
For some reason only one set of pipes will cross the screen and none others appear. I am a beginner and appreciate any help in this matter. Here is the code for the Spawner.cs:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class spawner : MonoBehaviour
{
public float queueTime = 1.5f;
private float time = 0;
public GameObject ObstaclePipes;
public float height;
void Start () {
GameObject newpipe = Instantiate(ObstaclePipes);
newpipe.transform.position = transform.position + new Vector3(0, Random.Range(-height, height), 0);
}
// Update is called once per frame
void Update()
{
if(time > queueTime)
{
GameObject go = Instantiate(ObstaclePipes);
go.transform.position = transform.position + new Vector3(0, Random.Range(-height, height), 0);
time = 0;
Destroy(go, 10);
}
time += Time.deltaTime;
}
}
Here is the code for the obstacles.cs:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class obstacles : MonoBehaviour
{
// Start is called before the first frame update
public float speed;
// Update is called once per frame
void Update()
{
transform.position += ((Vector3.left * speed) * Time.deltaTime);
}
}
Given that the obstacles are spawning and not visible on the screen, the obstacle sprite renderers are rendered behind the background. This behavior is common when working with 2D games. To solve this, we have to use sorting layers.
Sorting layer allows us to set the render order of sprites. In your case, we have to set the order of sorting layer for your obstacles so that they spawn in front of the background instead of behind it.
Hence in the sprite renderer component of the obstacle, set its Order In Layer to a value more than 0 as 0 is the default value which was the same for both background and obstacle. In our case, let's set it to 1. Now, the obstacles are rendered first, and then the background which lets us see the obstacles on the screen.
Is there a way to activate a fade animation every time the game changes from one scene to the other, without the user doing somthing specific like hiting a pre-determined key?
Basically the transtions needs to start just because there is a change in scenes.
I have a bunch of scenes and i need to add a fade to black transition between them.
All tutorials i found need some specific key input or something happening while i only have a few videos with no possible interaction with the user (in most cases).
Just in case that's not possible (or inpractical for rookies) I guess i could hook up the animations to the user pushing buttons that send you to other scenes (could use help with that aswell). And the first scene could work with a timer/delay.
*Unity and visual studio update to latest stable builds.
So every time you need to change scene you actually need to first fade-out your screen, then run scene change and after new scene is loaded - fade screen in. You can do it like that:
1) Create new Canvas object in start scene of your project. Set canvas mode to "Screen Space - Overlay" and make sure Sort Order is set high enough so your canvas will be on top always.
new Canvas object
2) Create an empty Image on this Canvas and size it so it covers all the scree. Set Color to transparent. Dont forget to toggle "Raycast Target" of image off (or you won't be able to mouseclick through it)
new Image object
3) Add this script to your Canvas object:
using System.Collections;
using UnityEngine;
using UnityEngine.SceneManagement;
using UnityEngine.UI;
public class SceneChanger : MonoBehaviour
{
enum FadeStatus
{
fading_id,
fading_out,
none
}
public static SceneChanger Instance;
public Image fadeImage;
public float fadeDuration;
private FadeStatus currentFadeStatus = FadeStatus.none;
private float fadeTimer;
private string sceneToLoad;
void Start()
{
if (Instance == null)
{
Instance = this;
SceneManager.sceneLoaded += OnSceneLoaded;
}
else
Destroy(gameObject);
DontDestroyOnLoad(gameObject);
}
void OnSceneLoaded(Scene scene, LoadSceneMode mode)
{
//scene loaded, running fade-in
currentFadeStatus = FadeStatus.fading_id;
}
public void ChangeScene(string _name)
{
sceneToLoad = _name;
currentFadeStatus = FadeStatus.fading_out;
}
void Update()
{
if(currentFadeStatus != FadeStatus.none)
{
fadeTimer += Time.deltaTime;
if(fadeTimer > fadeDuration) //done fading
{
fadeTimer = 0;
if (currentFadeStatus == FadeStatus.fading_out)
{
SceneManager.LoadScene(sceneToLoad);
fadeImage.color = Color.black;
}
else
fadeImage.color = Color.clear;
currentFadeStatus = FadeStatus.none;
}
else //still fading
{
float alpha = 0;
if (currentFadeStatus == FadeStatus.fading_out)
alpha = Mathf.Lerp(0, 1, fadeTimer / fadeDuration);
else
alpha = Mathf.Lerp(1, 0, fadeTimer / fadeDuration);
fadeImage.color = new Color(0, 0,0, alpha);
}
}
}
}
4) Go back to Editor and assign your transparent Image to its field on SceneChanger script and adjust fadeDuration (time of one fade in seconds)
5) Now you can change scenes from code using
SceneChanger.Instance.ChangeScene("YourSceneName");
6) Don't forget to add all needed scenes to build settings, otherwise it won't work.
build settings
7) You DON'T need to add SceneChanger on other scenes, it will be saved between scenes due to DontDestroyOnLoad().
I need little help with function WorldToScreenPoint(position), Could somebody guide me little bit ? I am using this function to display name of the city:
public class LabelsTest : MonoBehaviour
{
[SerializeField]
private Text nameLabel;
// Update is called once per frame
void Update()
{
Vector3 cameraPos = Camera.main.WorldToScreenPoint(transform.position);
nameLabel.transform.position = cameraPos;
}
}
But problem is that I see UI with text two times, one above the plane which is perfect:
but when I face away from the plane, I can see the label there, too.:
I don't know if I am doing something wrong or it just not working as it should.
Thanks for help.
You need to prevent the Text from rendering while it is behind the camera. Luckily, WorldToScreenPoint gives you a z component that tells you how far in front of the camera the point is. So, just set the Text to be enabled when z>0 and disabled when z<=0:
public class LabelsTest : MonoBehaviour
{
[SerializeField]
private Text nameLabel;
// Update is called once per frame
void Update()
{
Vector3 cameraPos = Camera.main.WorldToScreenPoint(transform.position);
nameLabel.transform.position = cameraPos;
nameLabel.enabled = cameraPos.z>0;
}
}
That's because your 'Plane' is culling the backface, meaning when the Plane is up at a certain point higher than the Camera's Y position it goes invisible.
Here's a GIF of the problem.
https://gyazo.com/d22c51951d1e8abd07a354af7f48ffef
First a screenshot of my Hierarchy :
Everything is inside a one scene name The :
The game start when Main Game is disabled. Inside Main Game sit all the game objects. The Main Menu and Game Manager are enabled.
When running the game first time, When the game start there is short animation of the player for 5 seconds. The player start from some rotating degrees on Z. Z = 50 when x and y both are 0. Then the player is rotating slowly over the Z to 0.
It's like the player is sleeping and awake up.
I'm using post processing stack by unity.
And here is the first problem. While the player is rotating on the Z and post processing effect is working if I press the Escape key it will bring me back to the Main Menu but then if I press the Escape key again it will start the game over again from the begin.
But if I'm waiting in my game for the player to finish rotating on the Z and the post processing effect is finished and then pressing on Escape it will bring the main menu and second time will resume the game from the same point.
I can't figure out why when the player is rotating and the post process is working the escape key make it start the game over again from the being ?
This is a screenshot of the game when start and after finish the rotating and the process stack :
Another problem I noticed now. After the game start using the post process and the player rotating finished if I press Escape it will go to main menu and escape again will be back to the game but for example in the second screenshot the conversation is not continue. It will return to the same point in the game but things not seems to continue like the conversation.
On the Back to main menu object I have a script attached to it :
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;
public class BackToMainMenu : MonoBehaviour
{
private bool _isInMainMenu = false;
public GameObject mainGame;
public GameObject mainMenu;
void Update()
{
if (Input.GetKeyDown(KeyCode.Escape))
{
if (!_isInMainMenu)
{
// -- Code to freeze the game
mainGame.SetActive(false);
mainMenu.SetActive(true);
}
else
{
// -- Code to unfreeze the game
mainGame.SetActive(true);
mainMenu.SetActive(false);
}
_isInMainMenu = !_isInMainMenu;
}
}
}
On the Main Menu object under Main Menu I have attached this script :
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;
public class MainMenu : MonoBehaviour
{
public GameObject mainGame;
public GameObject mainMenu;
public void PlayGame()
{
mainGame.SetActive(true);
mainMenu.SetActive(false);
}
public void QuitGame()
{
Application.Quit();
}
}
On the PLAY button I'm using this script method PlayGame from the MainMenu script.
In the Main Game object on the Player object attached to thew Player I have some scripts the controller :
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerController : MonoBehaviour
{
public float speed = 10.0f;
// Update is called once per frame
void Update()
{
float translatioin = Input.GetAxis("Vertical") * speed;
float straffe = Input.GetAxis("Horizontal") * speed;
translatioin *= Time.deltaTime;
straffe *= Time.deltaTime;
transform.Translate(straffe, 0, translatioin);
}
}
Player Lock Manager :
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerLockManager : MonoBehaviour
{
public PlayerCameraMouseLook playerCameraMouseLook;
public PlayerController playerController;
// Start is called before the first frame update
public void PlayerLockState(bool LockPlayer, bool LockPlayerCamera)
{
if (LockPlayer == true)
{
playerController.enabled = false;
}
else
{
playerController.enabled = true;
}
if (LockPlayerCamera == true)
{
playerCameraMouseLook.enabled = false;
}
else
{
playerCameraMouseLook.enabled = true;
}
}
}
And Mouse Lock State :
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class MouseLockState : MonoBehaviour
{
public bool lockState = true;
private void Start()
{
LockState(lockState);
}
private void Update()
{
}
public void LockState(bool lockState)
{
if (lockState == false)
{
Cursor.visible = true;
Cursor.lockState = CursorLockMode.None;
}
else
{
Cursor.visible = false;
Cursor.lockState = CursorLockMode.Locked;
}
}
}
Under the Player as child I have the Player Camera object and attached to the Player Camera also some scripts :
Player Camera Mouse Look :
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerCameraMouseLook : MonoBehaviour
{
public float sensitivity = 5.0f;
public float smoothing = 2.0f;
private GameObject player;
private Vector2 mouseLook;
private Vector2 smoothV;
// Use this for initialization
void Start()
{
player = this.transform.parent.gameObject;
}
// Update is called once per frame
void Update()
{
var md = new Vector2(Input.GetAxisRaw("Mouse X"), Input.GetAxisRaw("Mouse Y"));
md = Vector2.Scale(md, new Vector2(sensitivity * smoothing, sensitivity * smoothing));
smoothV.x = Mathf.Lerp(smoothV.x, md.x, 1f / smoothing);
smoothV.y = Mathf.Lerp(smoothV.y, md.y, 1f / smoothing);
mouseLook += smoothV;
mouseLook.y = Mathf.Clamp(mouseLook.y, -90f, 90f);
transform.localRotation = Quaternion.AngleAxis(-mouseLook.y, Vector3.right);
player.transform.localRotation = Quaternion.AngleAxis(mouseLook.x, Vector3.up);
}
}
And Depth Of Field script :
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.PostProcessing;
public class DepthOfField : MonoBehaviour
{
public GameObject player;
public PostProcessingProfile postProcessingProfile;
public bool dephOfFieldFinished = false;
public PlayerLockManager playerLockManager;
private Animator playerAnimator;
private float clipLength;
// Start is called before the first frame update
void Start()
{
playerAnimator = player.GetComponent<Animator>();
AnimationClip[] clips = playerAnimator.runtimeAnimatorController.animationClips;
foreach (AnimationClip clip in clips)
{
clipLength = clip.length;
}
var depthOfField = postProcessingProfile.depthOfField.settings;
depthOfField.focalLength = 300;
StartCoroutine(changeValueOverTime(depthOfField.focalLength, 1, clipLength));
postProcessingProfile.depthOfField.settings = depthOfField;
}
IEnumerator changeValueOverTime(float fromVal, float toVal, float duration)
{
playerLockManager.PlayerLockState(true, true);
float counter = 0f;
while (counter < duration)
{
var dof = postProcessingProfile.depthOfField.settings;
if (Time.timeScale == 0)
counter += Time.unscaledDeltaTime;
else
counter += Time.deltaTime;
float val = Mathf.Lerp(fromVal, toVal, counter / duration);
dof.focalLength = val;
postProcessingProfile.depthOfField.settings = dof;
yield return null;
}
playerAnimator.enabled = false;
dephOfFieldFinished = true;
}
}
I have under Main Game also a object name Openning Scene and attached to it :
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class OpeningCutscene : MonoBehaviour
{
public NaviConversations naviConversation;
public DepthOfField dephOfField;
// Update is called once per frame
void Update()
{
if (dephOfField.dephOfFieldFinished == true)
{
naviConversation.PlayNaviConversation(0);
dephOfField.dephOfFieldFinished = false;
}
}
}
It's a bit long but everything is connected.
The game start with the main menu.
When clicking the PLAY button a new game start.
When a new game start the script Depth Of Field is in action using the post processing. Also I'm locking the player so the player will not be able to move either the mouse or the player it self.
When the depth of field script finished his work a conversation between Navi and the Player start. When a conversation is in action the player can move the mouse 360 degrees but cant move the player to any direction.
When the conversation ended the player can also move to any direction.
Problems :
When start a new game while the depth of field script is in work pressing escape will bring the main menu but pressing escape again will not resume the depth of field script but will start it all over again.
When waiting the conversation to end if not pressing escape until the conversation ended then when moving around and pressing escape it will bring the main menu and again will resume the game from the same point.
The problems is when the game is doing something like the depth of field it will start the game over again instead resuming or when in conversation in the middle the conversation will never continue.
The ides with the escape key is once to get to main menu and second to resume the game.
The PLAY button is what should only start a new game and not the escape key.
It's a bit long but everything is connected.
I can't see which objects you hooked up to mainGame and mainMenu in BackToMainMenu from your hierarchy, so I have some conjecture in here.
Sounds like you want Escape key to pause, and unpause, as well as bring up a menu, you want Play button in the menu to restart your game.
However, in both MainMenu and BackToMainMenu you use the same code:
mainGame.SetActive(true);
mainMenu.SetActive(false);
This just turns the objects on and off in the hierarchy. This means the first time you do one of these things, all objects turned on under the gameobject referenced by mainGame will run their Awake and Start methods, but not the second time. Also depending which objects are active (like I said I can't fully see what component is on what object and which objects are referenced by which serialized field) you might be able to introduce a state error on BackToMainMenu._isInMainMenu because that field isn't changed when you hit play. Here is a fantastic image showing execution timeline in Unity:
Monobehavior Timeline
In summary:
The second time you run the game DepthOfField won't call Start a second time. Instead try OnEnable.
The conversation and game logic is not shown in your post, but likely it also is initializing in Start and won't run a second time.
A bit of trickiness around Coroutines is likely to blame here. When DepthOfField starts it also starts a coroutine. That coroutine keeps going even if you set the gameobject inactive. So you run the game once, that coroutine starts, you turn the object off when you hit escape, the coroutine finishes, you hit play again, but DepthOfField.dephOfFieldFinished == true and your playerAnimator is disabled and won't enable again.
Also 5. This kind of behavior can be tricky and is usually dependent on what else you have going on in your scene. Since you have one scene with everything at once, you need to watch out for putting stuff in Awake and Start since this will only run once. Instead you can try a number of things, my favorite is usually to set up a singleton or static class that works as a state machine for the whole scene. It will call custom Initialize functions in your behaviors instead of using Awake and Start.
Keep references to your coroutines by doing things like:
private Coroutine depthOfFieldRoutineRef;
private OnEnable()
{
if (depthOfFieldRoutineRef != null)
{
StopCoroutine(depthOfFieldRoutineRef);
}
depthOfFieldRoutineRef =
StartCoroutine(changeValueOverTime
(depthOfField.focalLength, 1, clipLength));
// Don't forget to set depthOfFieldRoutineRef to null again at the end of routine!
}
For simple pausing behavior you can also try setting Time.timescale = 0; and back to 1 when you want play to resume.
Less a question than a set of problems, hopefully this set of solutions helps!
Tutorial on Awake and Start
Docs on Coroutines
Docs on Time.timescale
I'm following this tutorial right now: https://unity3d.com/learn/tutorials/projects/roll-ball-tutorial/moving-camera?playlist=17141
I've managed to implement a 3rd person camera view button, but I'm having trouble figuring out how to do the same for a 1st person camera view. Below is a camera control script that I attached to the main camera:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class cameraControls : MonoBehaviour
{
public GameObject player;
private Vector3 offset;
public bool thirdPerson;
public bool firstPerson;
void OnGUI()
{
// 3rd person camera view
if (GUI.Button(new Rect(20, 50, 140, 40), "3rd Person Camera"))
{
thirdPerson = true;
}
// 1st person camera view
if (GUI.Button(new Rect(20, 110, 140, 40), "1st Person Camera"))
{
firstPerson = false;
}
}
// Start is called before the first frame update
void Start()
{
offset = transform.position - player.transform.position;
}
// Update is called once per frame
void Update()
{
if (thirdPerson == true)
{
transform.position = player.transform.position + offset;
}
}
}
Well, while it might be okay for such a small tutorial:
you should not use the GUI and OnGUI stuff for ingame UI. unity released in version 4.6 (years ago) a better UI system.
you could have 2 cameras, one for 3rd person one for 1st person. when pressing one of your buttons, you disable one camera and enable the other.
based on your edit:
you currently have 2 bool variables there, one for "firstPerson" one for "thirdPerson", thats redundant.
what do you do if both are true? or both are false? just have one variable e.g. "thirdPerson" true -> use 3rd person, false -> use 1st person.
also i see that you have decided to change the cameras position instead of using 2 cameras. this is also is a possible way to accomplish your goal
You can use a single camera and change its position based on which viewing angle should be active. Try to attatch two empty objects as children to your player object and add a reference to them in your script (your camera also needs to be a child of your player for this to work). Then drag & drop them from the hierarchy to the inspector and just switch between those positions like so:
public Transform firstPersonPosition;
public Transform thirdPersonPosition;
public Camera camera;
private void GoFirstPerson()
{
camera.transform.position = firstPersonPosition.position;
}
private void GoThirdPerson()
{
camera.transform.position = thirdPersonPosition.position;
}
You can basically use them as "waypoints" for your camera to jump to.
//Edit:
If you are having problems with understanding how your code affects your GameObjects during Play Mode just switch to Scene View during play and look at your objects and where they are in the scene. I bet your first person camera is somewhere in your player model because you set its position to your players position.