[HIRING] Create a game-like GUI for my project using Unity

in #utopian5 years ago (edited)

I'm looking to hire someone to put a game-like GUI on my Max/MSP project.

https://github.com/to-the-sun/amanuensis

Eventually I would like to build this into a full game with Unity, but for now I'm only looking for the very beginnings of one to be created. Just a bare-bones implementation, basically just a working prototype. For the time being it would actually function as more of a non-native GUI for my existing project and would receive all of its commands for what to display on-screen via OSC/UDP. You would only have to create a front-end and wouldn't have to worry about any real backend.

This project is destined to be a rhythm game not unlike Guitar Hero, except that you write the music you're playing to as you go. Below is a video of the system in action as it currently stands. I start playing and when it likes what it hears it starts building a song around me in real-time. If it's a little hard to differentiate what's what audibly, that's where this new visual interface will help.

The Proposal

There are essentially 4 things this first iteration needs to do:

  1. Have a UDP receiver set to a designated port on localhost, which will be the source of all your command messages.
  2. Like Guitar Hero, "targets" of some kind need to appear, fade in and disappear on the screen, denoting moments in the future to aim for when playing a note.
  3. Targets need to flash or show they were scored upon in some other way when users hit a note at the right time.
  4. When scored upon, a numeric score (e.g. +500) will need to pop up from the target and then disappear. A cumulative total of the scores will need to be kept track of in a simple text scoreboard off to the side, along with a few other metrics.

Targets

  • Every time the user plays a note, many targets will appear representing every possible rhythmic interval to aim for.
  • Unlike Guitar Hero, I don't think the targets should move down a fretboard until they reach the moment the player must act, or necessarily move it all, but rather fade in or otherwise alter/morph/grow in some way over the appropriate interval.
  • In this way, the movement on-screen will be an overall movement of many targets appearing in a sort of "cloud", running through their fade-in intervals, then disappearing. It will be this "cloud" that moves around the screen and starts pulsing with various rhythms rather than any individual targets moving.
  • When a target is successfully hit it will need to reenter into its fade-in interval. Therefore as the cloud moves around the screen it will probably be leaving trails of targets that continue to be hit at interval.
  • Cleanup messages will be delivered through OSC/UDP dictating when each target is no longer viable and can be removed from memory.
  • Targets need to vary by color based on which track they were associated with in the main program. The OSC/UDP messages will tell you which tracks these are.
  • You'll find the track numbers conveyed to you to be both positive and negative. Without getting into the reason for this, just know that targets from negative tracks will need to appear somehow brighter, bolder or bigger than their positive counterparts so they stand out by comparison, but still be of the same color.
  • In the simplest possible implementation new targets would appear on screen at completely random locations and this should be all that's necessary in this first prototype version.

Scoring

  • OSC/UDP messages will arrive whenever the user successfully hits a note at the right moment and scores on a target. The target will need to flash or explode in some way to signify this. Perhaps the easiest way to accomplish this would just be to have the target suddenly double in size and then blink away to nothing. Flashing another static image or shape over the target could work too; whatever you think is best.
  • Multiple targets can and will frequently be hit at once.
  • In the main program, it's possible for players to score on other players' tracks, which means the scoring flashes themselves will have their own associated track numbers (conveyed through OSC/UDP) and will often need to change color based on these numbers, using the same color scheme as the targets.
  • Scoring flashes associated with negative tracks will need to be somehow brighter, bolder or bigger than their positive counterparts, same as the targets themselves.
  • Very often targets will be hit in groups of "rhythmic succession" that include any number of targets that have already been hit in the past. These groups will be conveyed through the OSC/UDP and will need to be designated in some way visually. Perhaps the easiest way would be to draw lines of some kind between the targets as they flash, sort of like a constellation of stars.
  • These lines should connect the targets in a single chain from oldest to newest.

The Code

I really do see this project as being a video game, even if it's a bit lacking in the "video" department currently, and this interface for it should be treated as such as much as possible starting from the ground up. Therefore, it should be written like a game engine with a central main function that executes every frame and a target class as a separate file, instances of which would be created for each target that appears on screen.

OSC/UDP

All the information you need will be conveyed to you via OSC/UDP messages. You can watch a sampling of the messages as they're sent below.

The OSC/UDP messages are as follows:

amanuensis/wake/ i

  • An update to a variable called the wake, which is an integer denoting a number of milliseconds (see below).

amanuensis/tolerance/ i

  • An update to a variable called the tolerance, which is an integer denoting a number of milliseconds (see below).

amanuensis/played/ i i

  • Every time a note is played in the main program, this message will be sent.
  • The 1st argument is an integer denoting the source track. There are 16 possible tracks, each sending both positive and negative numbers.
  • The 2nd argument is a unique millisecond timestamp for the note denoting the exact moment it was played.
  • These timestamps will need to be stored in an array of some kind or dictionary, because there's a small amount of calculation that will need to be done with them before they're used. The incoming timestamp should be stored and then have each other stored timestamp subtracted from it. This series of numbers will be the fade-in intervals for each of the targets that should spawn at the moment this message comes in. Do not spawn targets for any interval that's over the number of milliseconds found in the wake variable.
  • Consider the track that targets are associated with to be the one in this message (1st argument).
  • For each target that spawns, its track number and interval will also need to be stored along vwith its timestamp for later reference.

amanuensis/hit/ i f l

  • Whenever targets are successfully hit the main program, this message will be sent.
  • The 1st argument is an integer denoting the track the scoring note took place on (not necessarily the track of the target(s)). Again, -16 through 16, excluding 0. Consider the track that scoring flashes are associated with to be the one in this 1st argument, not that of the target scored upon.
  • The 2nd argument is the interval of the successfully hit target(s).
  • The 3rd argument will be a list of any length, consisting of the timestamps of every target that was hit. If there is more than one, then these constitute a group of "rhythmic succession" as I mentioned in the Scoring section above.
  • Since a single note (and therefore a single timestamp) will spawn multiple targets, target objects on-screen will need to be looked up first by their timestamp, then by their interval, when determining which target(s) are about to flash. In the extremely rare case that two targets have both the same timestamp and interval, their track numbers will be different and can be used to uniquely identify them.
  • The interval (2nd argument) may not be exact. When looking for specific targets, you will need to assume +/- a few milliseconds when comparing against the value of stored intervals. Specifically, this few milliseconds will be equal to the variable tolerance, so the comparison will be incoming_interval - stored_interval <= abs(tolerance).
  • Each target that scores will need to have a numeric value (e.g. +500) pop up from it and then disappear. This value will be equal to its interval.

amanuensis/cleanup/ i

  • This message will come in eventually for every target, signaling when it can be removed from memory.
  • The 1st argument is the timestamp of the target(s) to be removed. Since more than one target can be associated with a single timestamp, when this message arrives it means all targets with this timestamp are ready to be removed.

Communication

Reply to this post for more details. I can also be found on discord @to_the_sun#5590 or you can message me at soundcloud.com/to_the_sun.