Skip to content

neogeek/rhythm-game-utilities

Repository files navigation

Caution

This package is in early development and should not be used in production.

Rhythm Game Utilities

Tests Build Join the chat at https://discord.gg/nNtFsfd

This library is a collection of utilities for creating rhythm games like Tap Tap Revenge, Guitar Hero, and Rock Band. It is meant to be used within any game engine that supports loading C++ libraries, such as Unity, Unreal, and Godot.

Prototype game built using these utilities.

Social

Table of Contents

Install

Unity

Add package via git URL https://github.com/neogeek/rhythm-game-utilities.git?path=/UnityPackage.

Unreal

Coming soon.

Godot

Coming soon.

HandcrankEngine

Coming soon.

Platforms

This library aims to offer support for multiple platforms through a single codebase. This is highly ambitious, so if you run into an issue with your platform of choice during development, please leave a detailed bug report with as much information as possible. Also, as this library is relatively new, mobile platforms will be fully supported after all other platforms are complete.

Engine Platform Tested
Unity macOS âś…
Unity Windows âś…
Unity WebGL ❌
Unreal macOS -
Unreal Windows -
Godot 4 macOS -
Godot 4 Windows -
Godot 4 WebGL -
HandcrankEngine macOS -
HandcrankEngine Windows -

Usage

Audio

Audio.ConvertSamplesToWaveform

using RhythmGameUtilities;

var samples = new float[_audioSource.clip.samples * _audioSource.clip.channels];

_audioSource.clip.GetData(samples, 0);

var color = Color.red;
var transparentColor = new Color(0, 0, 0, 0);

var waveform = Audio.ConvertSamplesToWaveform(samples, _texture2D.width, _texture2D.height);

for (var x = 0; x < waveform.Length; x += 1)
{
    for (var y = 0; y < waveform[x].Length; y += 1)
    {
        _texture2D.SetPixel(x, y, waveform[x][y] == 1 ? color : transparentColor);
    }
}

_texture2D.Apply();

Song

Song.FromChartFile

using RhythmGameUtilities;

var contents = File.ReadAllText("notes.chart", Encoding.UTF8);
var song = RhythmGameUtilities.Song.FromChartFile(contents);

Song.FromJSON

using RhythmGameUtilities;

var json = File.ReadAllText("notes.json", Encoding.UTF8);
var song = RhythmGameUtilities.Song.FromJSON(json);

Parsers

Read more about .chart files: https://github.com/TheNathannator/GuitarGame_ChartFormats/blob/main/doc/FileFormats/.chart/Core%20Infrastructure.md

Parsers.ParseSectionsFromChart

using RhythmGameUtilities;

var sections = Parsers.ParseSectionsFromChart(contents);

Parsers.ParseBpmFromChartChartSection

using RhythmGameUtilities;

var sections = Parsers.ParseSectionsFromChart(contents);

var bpm = Parsers.ParseBpmFromChartChartSection(sections[NamedSection.SyncTrack]);

Parsers.ParseTrackEventsFromChartSection

using RhythmGameUtilities;

var sections = Parsers.ParseSectionsFromChart(contents);

var trackEvents =
    Parsers.ParseTrackEventsFromChartSection(sections[$"{Difficulty.Expert}Single"], TypeCode.Event);

Parsers.ParseNotesFromChartSection

using RhythmGameUtilities;

var sections = Parsers.ParseSectionsFromChart(contents);

var notes = Parsers.ParseNotesFromChartSection(sections[$"{Difficulty.Expert}Single"]);

Parsers.ParseLyricsFromChartSection

using RhythmGameUtilities;

var sections = Parsers.ParseSectionsFromChart(contents);

var lyrics = Parsers.ParseLyricsFromChartSection(sections[NamedSection.Events]);

Utilities

Utilities.ConvertTicksToSeconds

using RhythmGameUtilities;

const int tick = 2784;
const int resolution = 192;
const int bpm = 124;

var seconds = Utilities.ConvertTicksToSeconds(tick, resolution, bpm);

Utilities.ConvertSecondsToTicks

using RhythmGameUtilities;

const float seconds = 7.01f;
const int resolution = 192;
const int bpm = 124;

var ticks = Utilities.ConvertSecondsToTicks(seconds, resolution, bpm);

Utilities.CalculateNoteHitAccuracy

using RhythmGameUtilities;

var note = new Note { Position = 2884 };

const int buffer = 60;

var accuracy = Utilities.CalculateNoteHitAccuracy(ref note, buffer, currentTick);

var score = Mathf.CeilToInt(Mathf.Lerp(0, 100, accuracy));

Utilities.CalculateScale

using RhythmGameUtilities;

const int baseBpm = 160;
const float speed = 5;

var scale = Utilities.CalculateScale(baseBpm, 120, speed);

Utilities.Lerp

using RhythmGameUtilities;

var position = Utilities.Lerp(0, 10, 0.5f);

Utilities.InverseLerp

using RhythmGameUtilities;

var percentage = Utilities.InverseLerp(0, 10, 5);

Architecture

graph LR;
    chartFile["Chart File"]
    chartFileParserCpp["Chart File Parser"]
    chartFileParserCsharp["Chart File Parser"]
    chartFileRender["Chart File Renderer"]

    audioFile["Audio File"]
    audioFileWaveformParserCpp["Audio File Waveform Parser"]
    audioFileWaveformParserCsharp["Audio File Waveform Parser"]
    audioFileWaveformRenderer["Audio File Waveform Renderer"]

    trackRenderer["Track Renderer"]

    userInput["User Input"]
    userInputCheck["User Input Check"]

    subgraph cpp ["C++"]
        chartFileParserCpp
        audioFileWaveformParserCpp
    end

    subgraph csharp ["C#"]
        chartFileParserCsharp
        audioFileWaveformParserCsharp
    end

    subgraph unity ["Unity"]
        chartFileRender
        audioFileWaveformRenderer
        trackRenderer
        userInput
        userInputCheck
    end

    chartFile-->chartFileParserCsharp
    audioFile-->audioFileWaveformParserCsharp

    chartFileParserCpp-->chartFileParserCsharp
    chartFileParserCsharp-->chartFileRender
    audioFileWaveformParserCpp-->audioFileWaveformParserCsharp
    audioFileWaveformParserCsharp-->audioFileWaveformRenderer

    chartFileRender-->trackRenderer
    audioFileWaveformRenderer-->trackRenderer

    userInput-->userInputCheck
    chartFileParserCsharp-->userInputCheck

Git Hooks

The git hooks that run are quick file comparisons to ensure the files in the dotnet project and the UnityProject are the same and that the build files haven't changed.

$ git config --local core.hooksPath .githooks/

Testing

Run all tests via make test.

  • Tests for the C++ library are authored using the C++ native library cassert.
  • Tests are run automatically via GitHub Actions on each new PR.
  • For you add a new feature or fix a bug, please include the benchmark output in the PR along with your device stats.

If you want to test the projecet from within Unity, add the test namespace to your project by adding the following to your Packages/manifest.json file:

{
...
    "testables": ["com.scottdoxey.rhythm-game-utilities"]
...
}

Build

Warning

Do not commit any build changes to the repo. The build files are automatically generated via GitHub Actions.

macOS

When developing on macOS, make sure that Mac is selected in the bottom right-hand corner of Visual Studio Code or C++ Intellisense will not work.

./bin/build.sh

Windows

When developing on Windows, make sure that Win32 is selected in the bottom right-hand corner of Visual Studio Code or C++ Intellisense will not work.

Run from x64 Native Tools Command Prompt for VS:

call "./bin/build.bat"

Contributing

Be sure to review the Contributing Guidelines before logging an issue or making a pull request.

Community Roadmap

This project aims to help you build your rhythm game as fast as possible without needing to learn the complexities of a new library. Instead, you can utilize comprehensive examples and simple code recipes If you have feature requests or bugs, please create an issue and tag them with the appropriate tag. If an issue already exists, vote for it with đź‘Ť.

License

The MIT License (MIT)

About

A collection of utilities for creating rhythm games.

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Sponsor this project