I'm creating a game in XNA that will work with lots of music loops over each other but I don't seem to be able to synchronize these sounds.
I always miss by a few milliseconds can you help me out?
This is my first try of synchronizing the sounds. Be aware I will need to work with dozens of sounds...
Might this sync problem be related with caching the sound?
Is there an external library to make it easier?
public SoundEffectInstance loop1, loop2;
public int auxControl = 0;
public bool auxB = false, auxA = false;
public void LoadContent()
{
SoundEffect temp1 = Game.Content.Load<SoundEffect>("sounds/Synctest_1");
loop1 = temp1.CreateInstance();
loop1.IsLooped = true;
loop2 = temp1.CreateInstance();
loop2.IsLooped = true;
}
public override void Update(GameTime gameTime)
{
// start first sound
if (auxA == false)
loop1.Play(); auxA = true;
// start counting until 2 seconds
if (auxA)
auxControl += gameTime.ElapsedGameTime.Milliseconds;
// if 2 seconds have passed after first sound start second sound
if (auxControl >= 2000 && auxB == false)
{
loop2.Play();
auxB = true;
}
base.Update(gameTime);
}
thank you
Don't know anything about C#, but usually it's hard to sync these sorts of things with millisecond accuracy if the API doesn't support it. The solution is to mix them yourself and use the API only for playback, that way you have control over exactly when they sounds play and how they are combined.
There may be a simpler solution in C#, but you can build something like this with http://www.PortAudio.com or a number of other interfaces. You may want to search for something like Game audio API on google.
For now I've decided that the best way to achieve this was using a condition inside the update, preferably the main update, so the verification is done the faster way it can be.
Still this brings a problem because you may hear a small "Tuk" between sounds but its hardly notice.
pseudo code would be something like this
Update(GameTime gameTime)
{
if (last sound ended)
{
play next;
decide on the next sound; // implement cache here if needed
}
}
Related
I'm trying to figure out how to get rid of my IndexOutOfRange error in Unity. I've tried a couple of different things, but I'm at a loss.
Its just that when I press tab, I cycle through my Game Objects array as planned, but then when you get to the last one, it throws that. I'd like for it to cycle back to the beginning, if possible. I've been plugging at this for probably 2 days now.
This is what I have so far (I only included the important variables, cause this script is huge)
int currentWindow = 0;
public GameObject theUI;
public GameObject[] windows;
void Update()
{
//Toggle Menu
if (Input.GetKeyDown(KeyCode.Escape))
{
if (theUI.activeInHierarchy)
{
theUI.SetActive(false);
}
else
{
theUI.SetActive(true);
windows[0].SetActive(true);
Refresh();
}
}
//Toggle Between Windows
if (theUI.activeInHierarchy)
{
if (Input.GetKeyDown(KeyCode.Tab))
{
ToggleWindow(currentWindow);
}
}
}
public void ToggleWindow(int windowNumber)
{
if (windowNumber == currentWindow)
{
windows[windowNumber].SetActive(!windows[windowNumber].activeInHierarchy);
Refresh();
currentWindow++;
windows[currentWindow].SetActive(!windows[currentWindow].activeInHierarchy);
}
}
If anyone has any insight as to what to do, please help! I've followed a few different things, but because my windows[] array is a GameObject rather than an int or anything else, it's made it quite difficult to figure out how to fix it using other sources.
currentWindow++;
windows[currentWindow]....
There is no check whatsoever if that index exceeds the array size.
For a simple wrap around you can use the remainder operator % often called 'modulo' (though only same for positive values)
currentWindow = (currentWindow + 1) % windows.Length;
So if the currentWindow reaches windows.Length it simply starts from 0 again.
Forewords
Firstly, I know posting graphical resources for codes is not encouraged in this platform. I will also post the code but, in this particular case, I think posting a video about it is much more helpful than just posting some arbitrary code because the structuring of game projects really vary depending on their requirements. However, I still respect the platform's rules so if a mod asks me to format my question according to the community rules, I can do that or they also can simply delete my question. I respect that.
The Issue
It's actually a simple issue but it's driving me crazy because of its simplicity. I just want to fade in when I load a scene and then fade out whenever I click a button. As to how I do that, this is the video about it.
To sum up, I load another scene called "Fader" which contains a ColorRect with a black color and AnimationPlayer to change ColorRect's alpha value.
The code is below with extra comments on relevant parts:
using Godot;
using System;
public class TitleScreen : Control
{
private Button[] buttons;
private Control fader; // the scene that I inject
public override void _Ready() // when title screen gets ready
{
GD.Print("Preparing TitleScreen...");
InitButtons();
InitFader(); // initialize fader
FadeIn(); // do fade in animation
}
private void InitFader() // initializing fader
{
GD.Print("Initializing fader...");
var faderScene = (PackedScene)ResourceLoader.Load("res://components/Fader.tscn"); // load external fader scene
fader = (Control)faderScene.Instance(); // instantiate the scene
fader.SetSize(OS.WindowSize); // set the size of fader scene to the game window, just in case
var rect = (ColorRect)fader.GetNode("rect"); // get "rect" child from fader scene
rect.SetSize(OS.WindowSize); // set "rect" size to the game window as well, just in case
fader.Visible = false; // set the visibility to false
AddChild(fader); // add initialized fader scene as a child of title screen
}
private void InitButtons()
{
GD.Print("Initializing buttons...");
buttons = new Button[3]{
(Button)GetNode("menu_container/leftmenu_container/menu/start_button"),
(Button)GetNode("menu_container/leftmenu_container/menu/continue_button"),
(Button)GetNode("menu_container/leftmenu_container/menu/exit_button"),
};
GD.Print("Adding events to buttons...");
buttons[0].Connect("pressed", this, "_StartGame");
buttons[2].Connect("pressed", this, "_QuitGame");
}
private void FadeIn()
{
GD.Print("Fading in...");
fader.Visible = true; // set visibility of fader to true
var player = (AnimationPlayer)fader.GetNode("player"); // get animation player
player.Play("FadeIn"); // play FadeIn animation
fader.Visible = false; // set visibility of fader to false
}
private void FadeOut()
{
// similar to FadeIn
GD.Print("Fading out...");
fader.Visible = true;
var player = (AnimationPlayer)fader.GetNode("player");
player.Play("FadeOut");
fader.Visible = false;
}
public void _StartGame() // whenever I click start game button
{
FadeOut(); // fade out
GetTree().ChangeScene("res://stages/Demo01.tscn");
}
public void _QuitGame() // whenever I click quit game button
{
FadeOut(); // fade out
GetTree().Quit();
}
}
Seems like I can't see something. Why does it not fade in and out?
Environment
Manjaro 19.0.2
Mono JIT Compiler 6.4.0 (if it is relevant)
Godot 3.2
So, the issue was Play method on AnimationPlayer object kinda runs like async (dunno if this is the correct term for it).
Luckily, there is a feature called signals in Godot. There are animation_started and animation_finished signals on AnimationPlayer objects. Basically, I created a C# script for Fader scene, hooked the signals from player to fader as in:
animation_started to _FaderAnimationStart
animation_finished to _FaderAnimationEnd
At the end, my script looks like below:
using Godot;
using System;
public class Fader : Control
{
private ColorRect rect;
private AnimationPlayer player;
public override void _Ready()
{
GD.Print("Initializing Fader...");
rect = (ColorRect)GetNode("rect");
player = (AnimationPlayer)GetNode("player");
SetSize(OS.WindowSize);
rect.SetSize(OS.WindowSize);
Visible = false;
}
private void _FaderAnimationStart(String anim_name)
{
Visible = true;
}
private void _FaderAnimationEnd(String anim_name)
{
Visible = false;
}
}
I solved it thanks to njamster's answer and Hans Passant's comment.
However, this only solves half of the problem. Yes, the scene now fades in when it loads but it does not fade out. Given that it executes kinda-async (again, I'm not sure if this is the correct term), changing scene interrupts while running the animation. I will update the answer when I solve that problem as well.
Update
Well, I cannot seem to solve the fade out part because it requires to access parent node from initialized child scene. There are some methods I can think of.
First one is to somehow parameterize "Fader" scene. This can be done in many ways but at the end, when you initialize it from another scene, you need to cast it to Fader and I don't know if this is a valid way to do it. Another concern is standardizing this in the codebase. A similar method is discussed in here.
Second one is to write it as a plugin which has it benefits and drawbacks. C# is not really battle-tested in this particular area.
Third one is to use a state management system. Here is a redux implementation for Godot. And you need to somehow integrate it for signals, which seems like a hassle.
So, overall, I still do not know how to fade out.
I've a 145 BPM sound with 137 milliseconds offset and I'm trying to sync a really fast animation with it... I was trying this way:
public class ActiveEpilepsy : MonoBehaviour {
public GameObject Epilepsy; //GameObject that carries the animation
float delay = 0.2f; //a fair time to disable the Epilepsy after the animation runs before active again
void Start()
{
InvokeRepeating("activeEpilepsy", 0.137f, 2.416f); //second parameter is the offset of the music and the third is the bpm/60;
}
void activeEpilepsy()
{
while(delay >= 0)
{
Epilepsy.SetActive(true);
delay -= Time.deltaTime;
}
Epilepsy.SetActive(false);
}
}
but doesn't activate the GameObject at all and returns A BEAUTIFUL CRASH in my Unity... Also, people tell that I shouldn't use strings to call methods (Invoke example), so what is wrong with my code and how can I make this works without using an Invoke?
Problem happens here:
void activeEpilepsy()
{
while(delay <= 0)
{
Epilepsy.SetActive(true);
delay -= Time.deltaTime;
}
Epilepsy.SetActive(false);
}
You have a while loop that will run as long as delay is less than 0. And you are decreasing that value inside. So either, delay is more than 0 and the loop does not enter. Or it is lower or equal to 0 and it will never leave.
Since delay is 0.2f, the loop is useless and the object deactivates right away. You need a coroutine or another invoke there:
void activeEpilepsy()
{
Epilepsy.SetActive(true);
Invoke("Reset", this.delay);
}
void Reset(){Epilepsy.SetActive(false);}
That is it for the inactive object problem. The crash is probably elsewhere, I can't see anything running wrong here.
For the method as string, it's not about calling with string, it's about how it is handled. I think (to be confirmed) Invoke uses reflection, so it calls on the assembly manifest to figure out if the method exists. This would be slow. If Unity was smart enough to add the method to a dictionary then calling by string has little to no impact.
I want to do
gradually stop car animation as it collildes with another car
gradually speed up car animation as it exit the collider
And I have two ways to acheive this thing(means to run my logic in).
Update
Co-routine
for coroutine I used this
IEnumerator IncreaseSpeedGradually1(AnimationControlSpeed lastGOHitScript)
{
//stop if decrease speed in progress
StopCoroutine("DecreaseSpeedGradually");
float decrementValue = ((lastHitVehicleSpeed / 2) * 2);
while (lastGOHitScript.Speed <= lastHitVehicleSpeed)
{
lastGOHitScript.Speed += decrementValue * Time.deltaTime;
yield return 0;
}
//setting speed to the last speed
lastGOHitScript.Speed = lastGOHitScript.iniSpeeed;
}
While for update I just make this criteria:
if (carAnimState == carAnimationState.starting)
{
carAnimState = carAnimationState.running;
}
if (carAnimState == carAnimationState.stoping)
{
carAnimState = carAnimationState.running;
}
These two ways I know but i want to ask that which is right way to do this job? to slow down animation speed and hence get my objective? I guess corroutine later can be problematic in my game and what are the performance concerns?
Not perfectly clear what your goal exactly is. What you describe is clear, but the two code snippets you posted do completely different things. BUT, basically, for something this small I would use Update() as it's easier to debug if something blows up and there's nothing -theoretically- in your code that wishes "threading" / "side tasking" (which coroutines are for, basically: do something -most probably a side task- async).
As a side note, the code in your Update() can be optimized a little so it will look something like this:
if (carAnimState == carAnimationState.starting) {
carAnimState = carAnimationState.running;
} else if (carAnimState == carAnimationState.stoping) {
carAnimState = carAnimationState.running;
} //this way the 2nd "if" won't be unnecessarily evaluated when animstate was .starting
I'd also add a method instead and call that from Update(). The pre-compiler will inline it most probably (cannot be forced in Unity) and your code is more readable.
This is the simple code inside of update. sadly it is not working for me. Even I have set Wrap Mode to clamp Forever.
if (trainGO.GetComponent<Animation>()["Start"].time >= trainGO.GetComponent<Animation>()["Start"].length)
{
blackTrain.SetActive(true);
redTrain.SetActive(false);
}
How can I check that animation clip have finished so that I can do some work? I don't want to use WaitForSeconds method, because I am working on Time and each time a new animation will be played,
Basically like this ...
PlayAnimation(); // Whatever you are calling or using for animation
StartCoroutine(WaitForAnimation(animation));
private IEnumerator WaitForAnimation ( Animation animation )
{
while(animation.isPlaying)
yield return null;
// at this point, the animation has completed
// so at this point, do whatever you wish...
Debug.Log("Animation completed");
}
You can trivially google thousands of QA about this example, http://answers.unity3d.com/answers/37440/view.html
If you do not fully understand coroutines in Unity, step back and review any of the some 8,000 full beginner tutorials and QA regarding "coroutines in Unity" on the web.
This is really the way to check an animation is finished in Unity - it's a standard technique and there's really no alternative.
You mention you want to do something in Update() ... you could possibly do something like this:
private Animation trainGoAnime=ation;
public void Update()
{
if ( trainGoAnimation.isPlaying() )
{
Debug.Log("~ the animation is still playing");
return;
}
else
{
Debug.Log("~ not playing, proceed normally...");
}
}
I strongly encourage you to just do it with a coroutine; you'll end up "in knots" if you try to "always use Update". Hope it helps.
FYI you also mention "actually the scenario is: at specified time (Time/clock separately running). I have to play an animation thats why i am using update to check the time and run animation accordingly"
This is very easy to do, say you want to run the animation 3.721 seconds from now...
private float whenToRunAnimation = 3.721;
it's this easy!
// run horse anime, with pre- and post- code
Invoke( "StartHorseAnimation", whenToRunAnimation )
private void StartHorseAnimation()
{
Debug.Log("starting horse animation coroutine...");
StartCoroutine(_horseAnimationStuff());
}
private IENumerator _horseAnimationStuff()
{
horseA.Play();
Debug.Log("HORSE ANIME BEGINS");
while(horseA.isPlaying)yield return null;
Debug.Log("HORSE ANIME ENDS");
... do other code here when horse anime ends ...
... do other code here when horse anime ends ...
... do other code here when horse anime ends ...
}