Folks...
I'm using the following code to transition between two videos.
public void loadMedia(Media media)
{
MediaPlayer newPlayer = new MediaPlayer(media);
newPlayer.setAutoPlay(true);
mediaView.setMediaPlayer(newPlayer);
player = newPlayer;
}
When I call loadMedia with the new video, the mediaplayer flashes white briefly. I'm guessing this has to do with the status taking time. But I need these transitions to go smoothly with no flash.
What to do?
Thanks,
GeePaw
As so often, I answered my own question shortly after. The trick is to wait for the status to be ready before you change the view's player:
public void loadMedia(Media media)
{
MediaPlayer newPlayer = new MediaPlayer(media);
newPlayer.setAutoPlay(true);
newPlayer.setOnReady(()->videoReady(newPlayer));
}
private void videoReady(MediaPlayer newPlayer)
{
mediaView.setMediaPlayer(newPlayer);
player = newPlayer;
}
Related
I am learning Color Switch Unity 2D game. When my player touches any color of obstacles, it dies. Although it hits the same color of obstacles, game is over. Player should not be dies. Could you help me out with that?
public class Obstacles : MonoBehaviour
{
private Player player;
void Start()
{
player = GameObject.FindObjectOfType<Player>();
}
void OnTriggerEnter2D(Collider2D target)
{
if (player.activeColor != this.tag)
{
player.GameOver();
}
}
}
With class OnTriggerEnter2D, my player dies even though it touches with the same color of obstacles. Without it, the player continues even it touches the obstacles.
P.S.: it seems so easy to fix it up. But I am a beginner in Unity.
I'm trying to develop a VR app where you can move around and interact with music (moving the audio sources, and so on). So, you can't actually die in this app, which is why a fade to black on trigger wouldn't help me. I'm trying to get a fade to black and show the credits after a certain amount of time (specifically, when the music is over). Maybe even a fade out (black) and a fade in (to another scene containing the credits) would do the trick. I know very little about programming, so I could really use some help.
I'm using Unity3D 2018.2.9f1
The app is for the Samsung's Gear VR
Timer
For any stuff using timers or wait I find Coroutines most of the time the best options.
You could either get the audio clip length and than wait for it
public AudioClip clip;
private void Start()
{
StartCoroutine(Wait(clip.length));
}
private IEnumerator Wait(float seconds)
{
yield return new WaitForSeconds(seconds);
// start fadeout here
}
or you could wait until it finishes playing
public AudioSource source;
// or wherever you start the music adioclip
private void Start()
{
source.Play ();
yield return new WaitUntil(()=> !source.isPlaying);
// start fadeout here
}
Fading
Here it depends a lot ... do you really switch Scenes by using LoadScene etc or do you just want to enable/disable certain content within one Scene?
And do you have 3D objects with materials and renderers or only 2D content using Unity.UI components?
The simplest solution for sure would be to place one overlay Canvas with the desired color as Image and simply fade it in and out. This is actually already available in the AssetStore and basically does
Uses an Overlay Canvas on top of everything with a certain color and animates it's alpha value (again using a Coroutine)
Makes sure that canvas is DontDestroyOnLoad so it isn't removed when we switch scenes
FadeIn the Canvas/Image => Fades out the current Scene
Load the other scene
FadeOut the Canvas/Image => Fades in the new Scene
Here is the source code (just cleaned it up a little)
using System.Collections;
using UnityEngine;
using UnityEngine.SceneManagement;
using UnityEngine.UI;
public class Fader : MonoBehaviour
{
private string _fadeScene;
private float _alpha;
private CanvasGroup _myCanvas;
private Image _bg;
private float _lastTime;
private bool _startedLoading;
private float _fadeInDuration;
//Set callback
private void OnEnable()
{
SceneManager.sceneLoaded -= OnLevelFinishedLoading;
SceneManager.sceneLoaded += OnLevelFinishedLoading;
}
//Remove callback
private void OnDisable()
{
SceneManager.sceneLoaded -= OnLevelFinishedLoading;
}
public void InitiateFader(CanvasGroup canvasGroup, Image image, string scene, Color fadeColor, float fadeInDuration, float fadeOutDuration)
{
DontDestroyOnLoad(gameObject);
_fadeInDuration = fadeInDuration;
_fadeScene = scene;
//Getting the visual elements
_myCanvas = canvasGroup;
_bg = image;
_bg.color = fadeColor;
//Checking and starting the coroutine
_myCanvas.alpha = 0.0f;
StartCoroutine(FadeIt(FadeDirection.Out, fadeOutDuration));
}
private enum FadeDirection
{
In,
Out
}
private IEnumerator FadeIt(FadeDirection fadeDirection, float fadeDuration)
{
var timePassed = 0.0f;
switch (fadeDirection)
{
case FadeDirection.Out:
do
{
_alpha = Mathf.Lerp(0, 1, timePassed / fadeDuration);
_myCanvas.alpha = _alpha;
timePassed += Time.deltaTime;
yield return null;
} while (timePassed < fadeDuration);
_alpha = 1;
SceneManager.LoadSceneAsync(_fadeScene);
break;
case FadeDirection.In:
do
{
_alpha = Mathf.Lerp(1, 0, timePassed / fadeDuration);
_myCanvas.alpha = _alpha;
timePassed += Time.deltaTime;
yield return null;
} while (timePassed < fadeDuration);
_alpha = 0;
Initiate.DoneFading();
Debug.Log("Your scene has been loaded , and fading in has just ended");
Destroy(gameObject);
break;
}
}
private void OnLevelFinishedLoading(Scene scene, LoadSceneMode mode)
{
//We can now fade in
StartCoroutine(FadeIt(FadeDirection.In, _fadeInDuration));
}
}
and
public static class Initiate
{
private static bool areWeFading;
//Create Fader object and assing the fade scripts and assign all the variables
public static void Fade(string scene, Color col, float fadeOutDuration, float fadeInDuration)
{
if (areWeFading)
{
Debug.Log("Already Fading");
return;
}
var init = new GameObject("Fader", typeof(Canvas), typeof(CanvasGroup), typeof(Image), typeof(Fader));
init.GetComponent<Canvas>().renderMode = RenderMode.ScreenSpaceOverlay;
var fader = init.GetComponent<Fader>();
areWeFading = true;
fader.InitiateFader(init.GetComponent<CanvasGroup>(), init.GetComponent<Image>(), scene, col, fadeOutDuration, fadeInDuration);
}
public static void DoneFading()
{
areWeFading = false;
}
}
than You call this in a dedicated component like in order to be able to do it e.g. in a button's onClick
public class DemoScript : MonoBehaviour
{
//name of the scene you want to load
public string TargetSceneName;
public Color LoadToColor = Color.black;
public float FadeInDuration = 1.0f;
public float FadeOutDuration = 1.0f;
public void GoFade()
{
Initiate.Fade(TargetSceneName, LoadToColor, FadeOutDuration, FadeInDuration);
}
}
or since it is static simply use
Initiate.Fade(TargetSceneName, LoadToColor, FadeOutDuration, FadeInDuration);
from anywhere.
Instead of the LoadSceneAsync you could also do your enabling and disabling stuff if you prefer to do it in only one scene.
However in VR it is actually a bad idea to fade to completely black and let the user see nothing. It might lead to disorientation and cybersickness ...
MovieTexture is finally deprecated after Unity 5.6.0b1 release and new API that plays video on both Desktop and Mobile devices is now released.
VideoPlayer and VideoClip can be used to play video and retrieve texture for each frame if needed.
I've managed to get the video working but coduldn't get the audio to play as-well from the Editor on Windows 10. Anyone know why audio is not playing?
//Raw Image to Show Video Images [Assign from the Editor]
public RawImage image;
//Video To Play [Assign from the Editor]
public VideoClip videoToPlay;
private VideoPlayer videoPlayer;
private VideoSource videoSource;
//Audio
private AudioSource audioSource;
// Use this for initialization
void Start()
{
Application.runInBackground = true;
StartCoroutine(playVideo());
}
IEnumerator playVideo()
{
//Add VideoPlayer to the GameObject
videoPlayer = gameObject.AddComponent<VideoPlayer>();
//Add AudioSource
audioSource = gameObject.AddComponent<AudioSource>();
//Disable Play on Awake for both Video and Audio
videoPlayer.playOnAwake = false;
audioSource.playOnAwake = false;
//We want to play from video clip not from url
videoPlayer.source = VideoSource.VideoClip;
//Set video To Play then prepare Audio to prevent Buffering
videoPlayer.clip = videoToPlay;
videoPlayer.Prepare();
//Wait until video is prepared
while (!videoPlayer.isPrepared)
{
Debug.Log("Preparing Video");
yield return null;
}
Debug.Log("Done Preparing Video");
//Set Audio Output to AudioSource
videoPlayer.audioOutputMode = VideoAudioOutputMode.AudioSource;
//Assign the Audio from Video to AudioSource to be played
videoPlayer.EnableAudioTrack(0, true);
videoPlayer.SetTargetAudioSource(0, audioSource);
//Assign the Texture from Video to RawImage to be displayed
image.texture = videoPlayer.texture;
//Play Video
videoPlayer.Play();
//Play Sound
audioSource.Play();
Debug.Log("Playing Video");
while (videoPlayer.isPlaying)
{
Debug.LogWarning("Video Time: " + Mathf.FloorToInt((float)videoPlayer.time));
yield return null;
}
Debug.Log("Done Playing Video");
}
Found the problem. Below is the FIXED code that plays Video and Audio:
//Raw Image to Show Video Images [Assign from the Editor]
public RawImage image;
//Video To Play [Assign from the Editor]
public VideoClip videoToPlay;
private VideoPlayer videoPlayer;
private VideoSource videoSource;
//Audio
private AudioSource audioSource;
// Use this for initialization
void Start()
{
Application.runInBackground = true;
StartCoroutine(playVideo());
}
IEnumerator playVideo()
{
//Add VideoPlayer to the GameObject
videoPlayer = gameObject.AddComponent<VideoPlayer>();
//Add AudioSource
audioSource = gameObject.AddComponent<AudioSource>();
//Disable Play on Awake for both Video and Audio
videoPlayer.playOnAwake = false;
audioSource.playOnAwake = false;
//We want to play from video clip not from url
videoPlayer.source = VideoSource.VideoClip;
//Set Audio Output to AudioSource
videoPlayer.audioOutputMode = VideoAudioOutputMode.AudioSource;
//Assign the Audio from Video to AudioSource to be played
videoPlayer.EnableAudioTrack(0, true);
videoPlayer.SetTargetAudioSource(0, audioSource);
//Set video To Play then prepare Audio to prevent Buffering
videoPlayer.clip = videoToPlay;
videoPlayer.Prepare();
//Wait until video is prepared
while (!videoPlayer.isPrepared)
{
Debug.Log("Preparing Video");
yield return null;
}
Debug.Log("Done Preparing Video");
//Assign the Texture from Video to RawImage to be displayed
image.texture = videoPlayer.texture;
//Play Video
videoPlayer.Play();
//Play Sound
audioSource.Play();
Debug.Log("Playing Video");
while (videoPlayer.isPlaying)
{
Debug.LogWarning("Video Time: " + Mathf.FloorToInt((float)videoPlayer.time));
yield return null;
}
Debug.Log("Done Playing Video");
}
Why Audio was not playing:
//Set Audio Output to AudioSource
videoPlayer.audioOutputMode = VideoAudioOutputMode.AudioSource;
//Assign the Audio from Video to AudioSource to be played
videoPlayer.EnableAudioTrack(0, true);
videoPlayer.SetTargetAudioSource(0, audioSource);
must be called before videoPlayer.Prepare(); not after it. This is took hours of experiment to find this this was the problem I was having.
Stuck at "Preparing Video"?
Wait 5 seconds after videoPlayer.Prepare(); is called then exit the while loop.
Replace:
while (!videoPlayer.isPrepared)
{
Debug.Log("Preparing Video");
yield return null;
}
with:
//Wait until video is prepared
WaitForSeconds waitTime = new WaitForSeconds(5);
while (!videoPlayer.isPrepared)
{
Debug.Log("Preparing Video");
//Prepare/Wait for 5 sceonds only
yield return waitTime;
//Break out of the while loop after 5 seconds wait
break;
}
This should work but you may experience buffering when the video starts playing. While using this temporary fix, my suggestion is to file for bug with the title of "videoPlayer.isPrepared always true" because this is a bug.
Some people also fixed it by changing:
videoPlayer.playOnAwake = false;
audioSource.playOnAwake = false;
to
videoPlayer.playOnAwake = true;
audioSource.playOnAwake = true;
Play Video From URL:
Replace:
//We want to play from video clip not from url
videoPlayer.source = VideoSource.VideoClip;
with:
//We want to play from url
videoPlayer.source = VideoSource.Url;
videoPlayer.url = "http://www.quirksmode.org/html5/videos/big_buck_bunny.mp4";
then Remove:
public VideoClip videoToPlay; and videoPlayer.clip = videoToPlay; as these are not needed anymore.
Play Video From StreamingAssets folder:
string url = "file://" + Application.streamingAssetsPath + "/" + "VideoName.mp4";
if !UNITY_EDITOR && UNITY_ANDROID
url = Application.streamingAssetsPath + "/" + "VideoName.mp4";
#endif
//We want to play from url
videoPlayer.source = VideoSource.Url;
videoPlayer.url = url;
All supported video formats:
ogv
vp8
webm
mov
dv
mp4
m4v
mpg
mpeg
Extra supported video formats on Windows:
avi
asf
wmf
Some of these formats don't work on some platforms. See this post for more information on supported video formats.
Similar to what the other answers have been saying. You could use callbacks for when preparing and end of video states. Rather than using coroutines and yield return.
videoPlayer.loopPointReached += EndReached;
videoPlayer.prepareCompleted += PrepareCompleted;
void PrepareCompleted(VideoPlayer vp) {
vp.Play();
}
void EndReached(VideoPlayer vp) {
// do something
}
I used #Programmer 's answer to play videos from a URL, but I couldn't get any sound to play. Eventually I found the answer in the comments of a YouTube tutorial.
To get the audio to play for a movie loaded via URL, you need to add the following line before the call to EnableAudioTrack:
videoPlayer.controlledAudioTrackCount = 1;
By now the VideoPlayer should be updated enough you don't need to write code to get to work correctly. Here are the settings I found to have the most desirable effect:
These settings are:
Video Player:
Play On Awake: True
Wait For First Frame: False
Audio Output Mode: None
Audio Source:
Play On Awake: True
Don't forget to have a VideoClip for the VideoPlayer and an AudioClip for the AudioSource. The file formats I found to work the best are .ogv for video and .wav for audio.
I want to wait until "next" button is pressed then continue
child.addChild(tmp);
childrenAdded.Push(tmp);
neighbor.GetComponent.<Renderer>().material.mainTexture = null;
-WAIT UNTIL CLICK ON NEXT BUTTON THEN CONTINUE-
toExpand.Push(tmp);
any idea? I tried:
while(true) {
if(GUI.Button(Rect(500,680 ,100,30),"Next"))
break
}
But it doesn't work; it freezes.
Instead of waiting, you can just have your code called when the button is clicked, like this:
void OnGUI() {
if(GUI.Button(Rect(500,680 ,100,30),"Next"))
toExpand.Push(tmp);
}
}
If possible, consider using Unity 4.6 or later so you can use the new UI which is much easier work with.
You can use Toggle button instead of button so you controll a boolean with toogle and loops what you need in your Update or LateUpdate function like this:
private Rect myRect = new Rect(500,680 ,100,30);
private bool myToggle = false;
void OnGui() {
myToggle = GUI.Toogle(myRect, myToggle, "Next");
}
void Update() {
if(myToggle){
// what I need to create while true;
}
}
Note that is not a good practice to create a new Rect every OnGUI cycle because it runs more than once per frame and it will create a performance issue.
Reading your code again may I could've misinterpreted your needing so if you could clarify what you really what your code to do would be easier to help.
Also, if you just need a "wizard" like sequence of actions I suggest you to take a look on delegates and use something like this:
delegate void MyDelegate();
private MyDelegate myDelegate;
private Rect myRect = new Rect(500,680 ,100,30);
void Start () {
myDelegate = FirstFunction;
}
void FirstFunction() {
// will execute until next button is clicked
}
void SecondFunction() {
// will execute after next button is clicked
}
void OnGui() {
if(GUI.Button(myRect, "Next")) {
myDelegate = SecondFunction;
}
}
In a scene of my quiz game I have an animation object that changes for another animation when a button to move to the next question is pressed (the button reload the scene). I would like to keep the animation, the last animation referenced to the object, after the scene is reloaded, but I don't know how. The object always returns to its normal state (the first animation).
I currently have a script called 'tower' referenced to the object where I make a static object and a DontDestroyOnLoad function:
public static SpriteRenderer towerAnimation;
void Awake()
{
DontDestroyOnLoad(gameObject);
towerAnimation = GetComponent<SpriteRenderer>();
}
And this code in the Update of 'GameManager' script:
public static int counterQuestionChances = 2;
void DestroyTower()
{
if (counterQuestionChances == 1)
{
Tower.towerAnimation.SetTrigger("error 1");
}
else
{
if (counterQuestionChances == 0)
{
Tower.towerAnimation.SetTrigger("error 2");
}
}
But it doesn't work. I'm taking shots in the dark because I don't know how to solve this. I'd appreciate if you could give me any ideas that can help me with this. Thanks!
You're going to have to use the SceneManagement library that Unity has so when the scene changes the method below called OnActiveSceneChanged gets called.
using UnityEngine.SceneManagement;
public class Tower : MonoBehaviour
{
public static SpriteRenderer towerAnimation;
public int storedCounter = 0;
void Awake()
{
DontDestroyOnLoad(gameObject);
towerAnimation = GetComponent<SpriteRenderer>();
SceneManager.activeSceneChanged += OnActiveSceneChanged;
}
private void OnActiveSceneChanged(UnityEngine.SceneManagement.Scene scene, UnityEngine.SceneManagement.Scene currentScene)
{
//tower animation stuff here
}
}