I'm looking to put together a sort of arcade in my Unity game, which would be a selection of fun little mini-games to play. The job I'm hiring for here is to create one of those games. The game could be just about anything you want to pursue, but there are a few simple rules that will need to be adhered to in order that your game can be loaded as a module into my main game. A module template will be provided to get you started and allow for seamless integration. The rules I mention are spelled out in the template README and also provided below.
The central dynamic and unifying thread of all of these mini-game modules will be that they revolve around audio. Not that your game needs to have audio, only that they must all utilize EQ data in interesting ways (think of the EQ bars on the interface of a stereo, bass on the one side and treble on the other). This EQ data will be provided to your module from the main game.
You can see an example of what I'm talking about in the following video. This is the first module in the arcade, the aptly named Space Fight. The audio you hear is coming from the main program and being played by the user on a MIDI keyboard. All the Space Fight module is doing is taking the EQ data streaming into it and visualizing it in a creative way on-screen (the template provides a function for easily accepting this data). This is the only thing your module needs to take in from anywhere outside of it; you don't even need to worry about controller or keyboard input.
an excerpt from the start of a Space Fight game. The action gets much more frenzied later on
You can see that the developer of this module chose to display the EQ data as classic EQ bars, but that absolutely doesn't have to be the case. They could cause different places on the screen to light up with varying intensities or affect the speed with which objects move around, anything at all, as long as it facilitates interesting dynamics and strategies when you play. In Space Fight it's all about getting the EQ bars to overlap at the right time. But the thing to notice is that each different sound has a unique shape to its EQ data, making them almost like individual "weapons" with their own advantages and disadvantages in the moment.
It may not be easy to know what dynamics will be fun right off the bat, but if you have an idea you think could be cool, let me hear it and if I think so too, I will be glad to take a chance on it and see it developed. I think the strategy will tend to emerge on its own as the game progresses. That's how it was with Space Fight; he had an idea and we talked about it, refining it as we went along, and I think it turned out great. I intend to work closely with any developer I hire throughout the process and would be glad to brainstorm ideas with you.
If you want to, you could first think of it as a simple song visualizer. Just make something that's pretty and captivating to look at. Ideally something you could watch endlessly and never see the same thing happen twice. But one could then imagine continuing to add any number of arbitrary rules to the mix that gradually turn it into much more of a game.
Consider that the song being visualized could be one played actively by an instrument you hold in your hands and the line between visualizer and game begins to blur. With your keyboard or drum set as your controller, a whole new angle of intentionality comes into the picture and all sorts of emergent strategies could come into existence, as any sort of game you could imagine starts to evolve. All the while, the soundtrack for this game is being actively written in real-time by the players themselves. This is the novel idea I'm trying to pursue.
Some random points/suggestions
- The EQ data will come from different sources: human players as well as loops recorded from them in real-time. Therefore a really interesting feedback loop could start occurring, depending on the rules you create.
- The multiple sources means your game must be multiplayer; there will always be at least one computer player (recorded loop) for each human. The game must accommodate the possibility of a lot of players, both human and computer, being present. I would say at least 9 total, but a typical game will probably have more like 4-6.
- The EQ data will be labeled by source. The leading integer will be negative for humans, positive for loops and 0 in the case of a backing track. Space Fight chose to pit the humans against the computer (loops) as teams, but I would actually like to encourage a free-for-all scenario, where every source competes against every other. This way the game could run by itself and the computers could play against each other, still providing something very interesting to watch.
- There could be NPCs running around to kill or defend, terrain to traverse, levels to beat and environments to explore, ways to lose and ways to win: anything you might expect from an ordinary video game.
- If you want the game to end under certain conditions or a player to be eliminated, that's entirely up to you. The template also provides functionality for numerical scorekeeping if you want to use it.
- It might be best to think of it as a rhythm game (like Guitar Hero or my favorite, Crypt of the Necrodancer), since audio is generally going to pulse with the beat of the music playing. Therefore you could consider moments when the beat of a computer's EQ data matches up with that of a player's to trigger certain consequences, either beneficial or detrimental.
- It might help to come up with a central mechanic and think of everything in terms of that. So every decision that needs to be made (layout, etc.) could be made to maximize the number of interesting ways that mechanic could come into play. With it as densely woven around one mechanic as possible, the players' control over the game will feel nice and articulate and the gameplay responsive.
- You don't need to be musical in any way to take this project on. My system is intended for novice/nonmusicians and I will provide you with test files that can "play" the game for you, even without controllers.
- As a side note, I am also very much interested in having this same exact concept implemented in a Minecraft mod (think Crypt of the Necrodancer, but 3D) so get a hold of me if that sounds like something you'd like to make. The difference would be there is no template for that, so the first thing would be to set the mod up to receive OSC, which is how the EQ data would arrive from my existing back-end.
The module requirements, as outlined in the template README
a) When creating a new module, follow these steps:
1. Copy this folder into your assets folder.
The folder contains a simplified set of functionalities of the Amanuensis main game to allow developers to create modules for it.
It also contains TextMesh Pro as it is required for the template to work.
2. Add a "Resources" folder to the project. Inside that folder, create a data container for your module: Right Click -> "Create" -> "Amanuensis" -> "ScriptModuleData".
This file contains important data about your module:
"Is Selectable": Whether or not the module will be selectable in the main game options menu. Don't change this value to false.
"Spawn Prefab": This prefab will be spawned on the startup of the main game. This gameobject needs to contain your main ScriptModule script and it is enabled/disabled when the game mode gets changed in the main game.
Whatever you change inside a scene in your project will not be reflected in the main game.
Every gameobject that your game mode requires (except for the gameobjects that the template provides) has to be a child of this prefab, so look at it as your root object.
"Game Mode Name": The visible name of your module that is shown inside the options menu of the main game.
"Camera Orthographic Size": This camera orthographic size will be set to the main camera when your module is selected.
Since you cannot create your own main camera, this is a handy way to tell the main game what camera size your module requires.
3. Create a script that is derived from "ScriptModule" (e.g. "TestModule : ScriptModule" instead of "TestModule : MonoBehaviour"). This is your main script that has to be on the main prefab. This is the connection between the main game and your module.
Your module has to implement the "void OnEQData(int track, float[] amplitudes)" function to receive EQ data.
You can open "ScriptModule.cs" inside the "Scripts" folder to get further information about it.
4. You are free to do whatever you need to do within Unity with a few exceptions:
1) You cannot change anything that is not bound to your asset files as these are the only files that can be put into the main game's Unity project.
Some examples of what you can and cannot do:
1) You cannot use custom layers since they are bound to the project and wouldn't be reflected in the main game.
2) You CAN use Script Execution Order as this is bound to the specific .cs files that are inside your assets folder, and thus will work inside the main game.
Except for this, you are free to use whatever you need as long as the changes are reflected by the assets instead of the Unity project configs.
5. Add a namespace to all your scripts. This is to make sure that different modules, that have the same name for a script, do not conflict with each other.
So just add "namespace <your project name> { }" around any script that you create. E.g:
"
using Amanuensis;
using UnityEngine;
namespace MyTestModule
{
public class TestModule : ScriptModule
{
}
}
"
6. For total compatibility, use Unity version 2019.2.11f1.
b) When uploading the module, upload everything inside your assets folder except for the "DoNotUpload" folder and its .meta file.
c) The functionality provided by the template files:
These functionalities are optional to use.
Color Utility:
The Amanuensis.Utils.ColorUtility class provides you with the colors of the tracks and teams as they are inside the main game.
Use Amanuensis.Utils.ColorUtility.Instance to access the singleton of this class.
To see the functions of this utility, open "ColorUtility.cs" inside the "Scripts" folder.
Scoreboard:
The Amanuensis.Scoreboard class provides functions to access and manipulate the scoreboard.
Use Amanuensis.Scoreboard.Instance to access the singleton of this class.
The scoreboard is dynamic and you can add new lines to it by calling the "SetValue" function with a new "key" that doesn't yet exist.
The scoreboard lines are formatted in the following way:
"<title> <text>"
An example:
Amanuensis.Scoreboard.Instance.SetValue(key: "test", title: "score", text: "1337", titleColor: Color.cyan);
This will create a new line on the scoreboard, "score 1337" where the title "score" is colored in cyan color.
This score can later be manipulated by using the key "test" again.
To see the functions of this utility, open "Scoreboard.cs" inside the "Scripts" folder.
Score Texts:
The Amanuensis.ScoreTextManager class provides functions to create score popups (e.g. a floating "1" when an enemy gets hit).
Use Amanuensis.ScoreTextManager.Instance to access the singleton of this class.
You can create a new score popup at any point on the screen using "Amanuensis.ScoreTextManager.Instance.CreateScoreText":
Amanuensis.ScoreTextManager.Instance.CreateScoreText(position: Vector3.zero, score: 1337, color: Color.blue);
This will create a score popup, showing a blue "1337", at the center of the screen.
As mentioned in a3), the void OnEQData(int track, float[] amplitudes)
function is how you retrieve the EQ data. The data comes as a list of 26 numbers, the 1st being an indicator of source (also referred to as "track", negative integers for players, positive for loops and 0 for a backing track) and the following 25 being floats representing the EQ data, varying between 0 and 1 (or maybe a little higher sometimes).
We can discuss an appropriate deadline for the project but I am most concerned simply that we stay in constant communication about its progress.
All code will need to be clean, organized and very well-commented. Please contact me if you have any questions or would like clarification about anything! If you see a better way to do something than what I'm suggesting, please bring it up!