Question not answered. Found another solution that bypassed the issue.
How to use structs in queues in C#?
I'm making a jukebox that plays different songs when selection buttons are pressed. On the controller, I have a struct containing an index value - associated with a song list - along with strings representing the animations for each selection. Each button contains unique values for these that are fed to the struct when it is pressed, and the struct is then enqueued so that multiple selections can be made. The problem is that I don't seem to be getting unique values out when I dequeue. The first selection gets queued, dequeued, and played. If I select one additional song while the first is playing, it gets dequeued and played when the first song ends. But if I select more than one song, they all get replaced by the last one selected - so if I select buttons 1, 2, and 3 while another song is playing, instead of playing songs 1, 2, and 3, song 3 will be played 3 times after the first song ends.
My best guess is that I'm not generating unique names or IDs for the queued structs, and the values they contain are being overwritten. So how do you generate unique queue entries from a common struct used to create them? Here are the relevant parts of my main script:
Struct and Queue setup:
//struct "SongSelection"
public struct SongSelection
{
public int buttonIndex;
public string jukeStart;
public string jukeStop;
public SongSelection(int i, string start, string stop)
{
buttonIndex = i;
jukeStart = start;
jukeStop = stop;
}
}
//struct instance "newSong"
public SongSelection nextSong;
//queue "songQueue"
public Queue<SongSelection> songQueue = new Queue<SongSelection>();
Dequeue selection:
//dequeue new selection
if (songQueue.Count > 0)
{
songQueue.Dequeue();
currentIndex = nextSong.buttonIndex;
jukeStart = nextSong.jukeStart;
jukeStop = nextSong.jukeStop;
StartCoroutine(PlaySong());
}
And here is what the button script does:
// this script goes on each button, and contains unique values for each song
public JukeboxControl mPlayer; // main jukebox control script
public int index = 1; // linked to song list
public string jButton = "button1_anim"; // button animation
public string jStart = "tray1_start_anim"; // start animation
public string jStop = "tray1_stop_anim"; // stop animation
private bool locked = false; // to prevent multiple triggers
void OnMouseUpAsButton()
{
if (!locked)
{
locked = true;
StartCoroutine(NewSelection());
}
}
public IEnumerator NewSelection()
{
mPlayer.animSourceButtons.GetComponent<Animation>().Play(jButton);
JukeboxControl.SongSelection nextSong = new JukeboxControl.SongSelection();
nextSong.buttonIndex = index;
nextSong.jukeStart = jStart;
nextSong.jukeStop = jStop;
mPlayer.nextSong = nextSong;
mPlayer.songQueue.Enqueue(nextSong);
mPlayer.selectNew = true;
yield return new WaitForSeconds (1);
locked = false;
}
Since I'm not that familiar with using structs or queues, and have only gotten this far by cobbling together scripts from various online guides and tutorials, I may be going about this all wrong. If there's a more elegant way to accomplish the same thing, by all means let me know.
Answer by lgarczyn · Dec 02, 2019 at 01:45 AM
First, you can use the constructor of your struct, so that you don't forget to initialize some values, and get easier to read code. You forgot to do they in the last code block.
Second if the struct is to serializable, you can edit a public var of that type in the editor.
Thank you for your response. To clarify, I didn't forget to use the constructor in the last code block. I don't know how - which is why I'm asking for help. As I said, I've cobbled this together from examples I've found elsewhere, and none of them showed the additional steps needed for this situation. They all assumed that each new instance of the struct would be explicitly stated in code, ins$$anonymous$$d of being generated on the fly from variables at run time. So each new instance was given a unique hard coded name right in the script. I can't do that in my case, since I use the same code sequence to create new instances from the values stored on each button. So in my button script, each new instance is called nextSong, ins$$anonymous$$d of nextSong1, nextSong2, etc. Is there a way to differentiate between each new instance when created this way, or do I need to write a different version of the button script for each button? If I've missed something, an example showing the correct way to do it would be helpful.
A constructor is just basically a function, except you call it with the keyword new
and the name of the type ins$$anonymous$$d of a function name. It will also call the constructors of the parent types, but that's only if you use inheritance. So, this is what you want to use:
new JukeboxControl.SongSelection(index, jStart, jStop)
The only reason you need JukeboxControl.
here is because the struct SongSelection is part of the type or namespace JukeboxControl, so out of this namespace you need to specify the full path.
New instances are not named. The name of the variable that contains the instance has no effect on the behavior of the variable.
But structs don't even have "instances", they act like integers or float, and are passed by value.
Unless your struct contains a field "name", it will not have a name.
I suggest you start learning C# from the ground up, following tutorials, ins$$anonymous$$d of copying random code.
Great. So now that I've properly constructed my struct, how do I Queue it? If I don't give it a name, presumably I need to place the whole constructor inside the Queue statement? If I say
mPlayer.songQueue.Enqueue(new JukeboxControl.SongSelection(index, jStart, jStop));
print("Index: " + index + ", jStart: " + jStart + ", jStop: " + jStop + " added");
in my button script, and
songQueue.Dequeue();
currentIndex = index;
jukeStart = jStart;
jukeStop = jStop;
print("Dequeued selection: " + index + ", " + jStart + ", " + jStop);
print("Index: " + currentIndex + ", Start: " + jukeStart + ", Stop: " + jukeStop);
in my main jukebox script, and hit button 5 for example, I get this:
Index: 4, jStart: Juke_Select_05, jStop: Juke_Reset_05 added to queue
Dequeued selection: 0, jStart: , jStop:
Index = 0, Start = , Stop =
Something is still missing here, and so far, none of the tutorials I've gone through in the last week and a half have been much help. The ones on queues don't mention structs, and the ones on structs don't mention queues. Without specific information on how they can be used together, I'm not sure how taking a year out of my life to learn C# from the ground up is going to help. I came here for help with a specific problem. If "Learn C#" is your answer, it must be really easy to answer pretty much anything anyone asks here.
On a side note, I've been learning C# from the ground up by actually doing things with it for over 5 years. This is the first time I've had to ask for help here due to a lack of good information elsewhere. Any suggestions related to my actual question are welcome. Otherwise, please check the sermons at the door.
Follow this Question
Related Questions
c# process that runs a batch file for blender exporting gets paused/stalled 0 Answers
Can not access an abstract class from another script! 0 Answers
Randomized array result from other scipt 2 Answers
How do I unparent a child object with C#? For Google VR 1 Answer
How can i disable/enable slowly the blur effect using the blur script ? 0 Answers