commit 8e6966bfcd8f35c615231af44aacd7fee7804c98 Author: muskit <15199219+muskit@users.noreply.github.com> Date: Sun Jul 30 00:22:03 2023 -0700 Initial commit diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..8ad74f7 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,2 @@ +# Normalize EOL for all files that Git considers text files. +* text=auto eol=lf diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..4709183 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +# Godot 4+ specific ignores +.godot/ diff --git a/Scenes/DebugChartLoader.tscn b/Scenes/DebugChartLoader.tscn new file mode 100644 index 0000000..c37d76d --- /dev/null +++ b/Scenes/DebugChartLoader.tscn @@ -0,0 +1,73 @@ +[gd_scene load_steps=2 format=3 uid="uid://bqhdw2o5vq7ny"] + +[ext_resource type="Script" path="res://Scripts/Scenes/DebugChartLoader.cs" id="1_hjgpd"] + +[node name="DebugChartLoader" type="MarginContainer" node_paths=PackedStringArray("inputField", "soundField", "difficultyButton", "playButton")] +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +grow_horizontal = 2 +grow_vertical = 2 +theme_override_constants/margin_left = 32 +theme_override_constants/margin_top = 32 +theme_override_constants/margin_right = 32 +theme_override_constants/margin_bottom = 32 +script = ExtResource("1_hjgpd") +inputField = NodePath("VBoxContainer/HBoxContainer/PathLineEdit") +soundField = NodePath("VBoxContainer/HBoxContainer3/SoundLineEdit") +difficultyButton = NodePath("VBoxContainer/HBoxContainer/DifficultyOptionButton") +playButton = NodePath("VBoxContainer/HBoxContainer2/PlayButton") + +[node name="VBoxContainer" type="VBoxContainer" parent="."] +layout_mode = 2 +theme_override_constants/separation = 8 + +[node name="HBoxContainer" type="HBoxContainer" parent="VBoxContainer"] +layout_mode = 2 +size_flags_vertical = 3 +alignment = 1 + +[node name="PathLineEdit" type="LineEdit" parent="VBoxContainer/HBoxContainer"] +custom_minimum_size = Vector2(0, 35) +layout_mode = 2 +size_flags_horizontal = 3 +size_flags_vertical = 8 +size_flags_stretch_ratio = 5.97 +text = "AkiraComplex - Ether Strike" +placeholder_text = "Folder path relative to \"user://songs/\"" + +[node name="DifficultyOptionButton" type="OptionButton" parent="VBoxContainer/HBoxContainer"] +custom_minimum_size = Vector2(0, 35) +layout_mode = 2 +size_flags_horizontal = 3 +size_flags_vertical = 8 +item_count = 4 +selected = 0 +popup/item_0/text = "0. Normal" +popup/item_0/id = 0 +popup/item_1/text = "1. Hard" +popup/item_1/id = 1 +popup/item_2/text = "2. Expert" +popup/item_2/id = 2 +popup/item_3/text = "3. Inferno" +popup/item_3/id = 3 + +[node name="HBoxContainer3" type="HBoxContainer" parent="VBoxContainer"] +layout_mode = 2 +alignment = 1 + +[node name="SoundLineEdit" type="LineEdit" parent="VBoxContainer/HBoxContainer3"] +layout_mode = 2 +size_flags_horizontal = 3 +text = "music.wav" +placeholder_text = "Name of audio file in the folder specified above with extension" + +[node name="HBoxContainer2" type="HBoxContainer" parent="VBoxContainer"] +layout_mode = 2 +size_flags_vertical = 3 +alignment = 1 + +[node name="PlayButton" type="Button" parent="VBoxContainer/HBoxContainer2"] +layout_mode = 2 +size_flags_vertical = 0 +text = "Play" diff --git a/Scenes/Play.tscn b/Scenes/Play.tscn new file mode 100644 index 0000000..82c6330 --- /dev/null +++ b/Scenes/Play.tscn @@ -0,0 +1,13 @@ +[gd_scene format=3 uid="uid://bqh00ot0csqmk"] + +[node name="Play" type="Node"] + +[node name="Node3D" type="Node3D" parent="."] + +[node name="Camera3D" type="Camera3D" parent="Node3D"] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 4.09161) +fov = 60.0 +near = 0.001 +far = 100.0 + +[node name="Node2D" type="Node2D" parent="."] diff --git a/Scenes/_STARTUP.tscn b/Scenes/_STARTUP.tscn new file mode 100644 index 0000000..64d3de3 --- /dev/null +++ b/Scenes/_STARTUP.tscn @@ -0,0 +1,6 @@ +[gd_scene load_steps=2 format=3 uid="uid://bef4fdycrfvls"] + +[ext_resource type="Script" path="res://Scripts/Scenes/Startup.cs" id="1_yd1au"] + +[node name="Control" type="Node"] +script = ExtResource("1_yd1au") diff --git a/Scripts/Configuration/PlaySettings.cs b/Scripts/Configuration/PlaySettings.cs new file mode 100644 index 0000000..6508a69 --- /dev/null +++ b/Scripts/Configuration/PlaySettings.cs @@ -0,0 +1,7 @@ +namespace WacK.Configuration +{ + public class PlaySettings + { + public static float playSpeedMultiplier = 2f; + } +} \ No newline at end of file diff --git a/Scripts/Configuration/PlaySettings.cs.meta b/Scripts/Configuration/PlaySettings.cs.meta new file mode 100644 index 0000000..6bde4d4 --- /dev/null +++ b/Scripts/Configuration/PlaySettings.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: dee0701f4dec1e53681db1444842f032 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Scripts/Constants.cs b/Scripts/Constants.cs new file mode 100644 index 0000000..bd3adb8 --- /dev/null +++ b/Scripts/Constants.cs @@ -0,0 +1,8 @@ +namespace WacK +{ + public class Constants + { + public const float SCROLL_MULT = 3f; + public const float NOTE_DRAW_DISTANCE = 10; + } +} \ No newline at end of file diff --git a/Scripts/Data/Chart.meta b/Scripts/Data/Chart.meta new file mode 100644 index 0000000..f507915 --- /dev/null +++ b/Scripts/Data/Chart.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 25140b91ea8636ea5acb3ff90421f11a +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Scripts/Data/Chart/Chart.cs b/Scripts/Data/Chart/Chart.cs new file mode 100644 index 0000000..fe95ec8 --- /dev/null +++ b/Scripts/Data/Chart/Chart.cs @@ -0,0 +1,332 @@ +using System; +using System.Linq; +using System.Collections.Generic; + +using WacK.Data.Mer; + +using Godot; + +namespace WacK.Data.Chart +{ + /// + /// Chart data. + /// + public class Chart + { + public static bool doneLoading { get; private set; } = false; + // [ms] = List (list for chord marking creation) + public SortedList> playNotes { get; private set; } + public SortedList> timeSigChgs { get; private set; } + public SortedList> tempoChgs { get; private set; } + public SortedList> events { get; private set; } + + public Chart() + { + doneLoading = false; + } + + // place notes and events relative to the previous + public void Load(Mer.Mer chart) + { + playNotes = new SortedList>(); + + List tempo = new List(); + List tempoChangeMeasures = new List(); + List tempoChangeBeats = new List(); + + // TODO: switch to MeasureBeat + List beatsPerMeasure = new List(); + List bpmChangeMeasures = new List(); + + tempo.Add(0); + tempoChangeMeasures.Add(0); + tempoChangeBeats.Add(0); + + beatsPerMeasure.Add(0); + bpmChangeMeasures.Add(0); + + float queuedTempo = -1; + int queuedBPM = -1; + + // timing info of the previous beat + float prevTime = 0; + int prevMeasure = 0; + int prevBeat = 0; // (/1920 beats per measure) + + Note prevNote = null; + Note curNote = null; + var prevHoldPoint = new System.Collections.Generic.Dictionary(); // + var curHoldNote = new System.Collections.Generic.Dictionary(); // + + // Notes and Events // + foreach (var measure in chart.notes) // `measure` = measure: List + { + foreach (var chartNote in measure.Value) // `chartNote` = beat, ChartNote + { + var curTime = prevTime + Util.NoteTime(measure.Key - prevMeasure, chartNote.Item1 - prevBeat, tempo.Last(), beatsPerMeasure.Last()); + var mb = new MeasureBeat(measure.Key, chartNote.Item1); + + if (prevMeasure != measure.Key && prevBeat != chartNote.Item1) + { + if (queuedTempo != -1) + { + tempo.Add(queuedTempo); + tempoChangeMeasures.Add(measure.Key); + tempoChangeBeats.Add(chartNote.Item1); + queuedTempo = -1; + } + + if (queuedBPM != -1) + { + beatsPerMeasure.Add(queuedBPM); + bpmChangeMeasures.Add(measure.Key); + queuedBPM = -1; + } + } + + // notetype-dependent operations + switch (chartNote.Item2.noteType) + { + // Beat map data + case MerType.Tempo: + if (tempo.Count == 1) + { + tempo.Add(float.Parse(chartNote.Item2.value)); + tempoChangeMeasures.Add(measure.Key); + tempoChangeBeats.Add(chartNote.Item1); + } + else + queuedTempo = float.Parse(chartNote.Item2.value); + this.tempoChgs.Add( + curTime, + new NoteEvent ( + curTime, mb, + NoteEventType.Tempo, + value: float.Parse(chartNote.Item2.value) + )); + break; + case MerType.TimeSignature: + var words = chartNote.Item2.value.Split(); + var nu = int.Parse(words[0]); + var de = int.Parse(words[1]); + if (beatsPerMeasure.Count == 1) + { + beatsPerMeasure.Add(int.Parse(chartNote.Item2.value)); + bpmChangeMeasures.Add(measure.Key); + } + else + queuedBPM = int.Parse(chartNote.Item2.value); + this.timeSigChgs.Add( + curTime, + new NoteEvent<(int, int)> ( + curTime, mb, + NoteEventType.TimeSignature, + value: (nu, de) + )); + break; + // Playable notes + case MerType.Touch: + curNote = new NotePlay( + curTime, mb, + chartNote.Item2.position, chartNote.Item2.size + ); + break; + case MerType.HoldStart: + curNote = new NoteHold( + curTime, mb, + chartNote.Item2.position, chartNote.Item2.size, + holdIndex: chartNote.Item2.holdIdx, + holdNext: chartNote.Item2.holdNextIdx + ); + var nh = curNote as NoteHold; + prevHoldPoint[chartNote.Item2.holdNextIdx] = (NotePlay) curNote; + curHoldNote[chartNote.Item2.holdNextIdx] = nh; + break; + case MerType.HoldMid: + curNote = new NotePlay( + curTime, mb, + chartNote.Item2.position, chartNote.Item2.size, + type: NotePlayType.HoldMid, + holdIndex: chartNote.Item2.holdIdx, + holdNext: chartNote.Item2.holdNextIdx + ); + prevHoldPoint[chartNote.Item2.holdNextIdx] = (NotePlay) curNote; + curHoldNote[chartNote.Item2.holdNextIdx] = curHoldNote[chartNote.Item2.holdIdx]; + break; + case MerType.HoldEnd: // TODO: draw end note on cone texture + curNote = new NotePlay( + curTime, mb, + chartNote.Item2.position, chartNote.Item2.size, + type: NotePlayType.HoldEnd, + holdIndex: chartNote.Item2.holdIdx + ); + break; + case MerType.Untimed: + curNote = new NotePlay( + curTime, mb, + chartNote.Item2.position, chartNote.Item2.size, + type: NotePlayType.Untimed + ); + break; + case MerType.SwipeIn: + curNote = new NotePlay( + curTime, mb, + chartNote.Item2.position, chartNote.Item2.size, + type: NotePlayType.SwipeIn + ); + break; + case MerType.SwipeOut: + curNote = new NotePlay( + curTime, mb, + chartNote.Item2.position, chartNote.Item2.size, + type: NotePlayType.SwipeOut + ); + break; + case MerType.SwipeCW: + curNote = new NotePlay( + curTime, mb, + chartNote.Item2.position, chartNote.Item2.size, + type: NotePlayType.SwipeCW + ); + break; + case MerType.SwipeCCW: + curNote = new NotePlay( + curTime, mb, + chartNote.Item2.position, chartNote.Item2.size, + type: NotePlayType.SwipeCCW + ); + break; + // Events (invisible modifier notes) + case MerType.BGAdd: + curNote = new NoteEvent( + curTime, mb, + NoteEventType.BGAdd, + chartNote.Item2.position, chartNote.Item2.size, + value: int.Parse(chartNote.Item2.value) + ); + break; + case MerType.BGRem: + curNote = new NoteEvent( + curTime, mb, + NoteEventType.BGRem, + chartNote.Item2.position, chartNote.Item2.size, + value: int.Parse(chartNote.Item2.value) + ); + break; + } + + if (curNote == null || curNote == prevNote) continue; + + /* Handle our crafted curNote, storing it somewhere in this Chart */ + // NotePlay + var np = curNote as NotePlay; + if (np != null) + { + // hold point handling + if (np.type == NotePlayType.HoldMid || np.type == NotePlayType.HoldEnd) + { + curHoldNote[np.holdIdx].points[curTime] = np; + } + + // add note + if (!playNotes.ContainsKey(curTime)) + { + playNotes[curTime] = new List(); + } + playNotes[curTime].Add(np); + } + + // NoteEvent -- tempo changes + var nef = curNote as NoteEvent; + if (nef != null) + { + if (nef.type == NoteEventType.Tempo) + this.tempoChgs[curTime] = nef; + else + GD.Print($"Didn't add NoteEvent of type {nef.type}"); + } + + // NoteEvent<(int, int)> -- time signature changes + var neii = curNote as NoteEvent<(int, int)>; + if (neii != null) + { + this.timeSigChgs[curTime] = neii; + } + + // NoteEvent + var nei = curNote as NoteEvent; + if (nei != null) + { + this.events[curTime] = nei; + } + + // update previous states + prevNote = curNote; + prevTime = curTime; + prevBeat = chartNote.Item1; + prevMeasure = measure.Key; + } + } + + // chords + foreach (KeyValuePair> pair in playNotes) + { + List chordableNotes = new List(); + foreach (NotePlay n in pair.Value) + { + if (n.type != NotePlayType.HoldEnd && n.type != NotePlayType.Untimed) + if (!(new NotePlayType[] { NotePlayType.HoldEnd, NotePlayType.Untimed, NotePlayType.HoldMid }).Contains(n.type)) + chordableNotes.Add(n); + } + if (chordableNotes.Count >= 2) + { + GD.Print($"Found chord: {string.Join(", ", chordableNotes)}"); + // TODO: draw chord indicators "Chordify" + } + } + + // Measure Lines // + // TODO: adapt to tempo changes in the middle of a measure + // int tempoIdx = 1; + // int bpmIdx = 1; + // for (int curMeasure = 0; curMeasure < chart.notes.Count; curMeasure++) + // { + // while (curMeasure >= bpmChangeMeasures[bpmIdx] && bpmIdx < bpmChangeMeasures.Count - 1) + // ++bpmIdx; + // GD.Print($"{curMeasure}: {bpmIdx}"); + + // // last tempo change / only one tempo change exists + // if (tempoIdx == tempoChangeMeasures.Count - 1) + // { + // float pos = tempoChangePositions[tempoIdx] + Util.NotePosition(curMeasure - tempoChangeMeasures[tempoIdx], 0, tempo.Last(), beatsPerMeasure[bpmIdx]); + // var ml = measureLine.Instance(); + // measureScroll.AddChild(ml); + // ml.Translation = new Vector3(0, 0, pos); + // ml.Text = $"{curMeasure}"; + // } + // else if (tempoIdx < tempoChangeMeasures.Count) + // { + // // TODO: adapt to key signature changes + // while (curMeasure == tempoChangeMeasures[tempoIdx]) + // { + // int measuresToCreate = tempoChangeMeasures[tempoIdx] - tempoChangeMeasures[tempoIdx - 1]; + // for (int i = 0; i < measuresToCreate; ++i) + // { + // int measureNum = tempoChangeMeasures[tempoIdx - 1] + i; + // // GD.Print($"{tempoIdx} / {tempoChangePositions.Count}, {tempo.Count}"); + // float pos = Util.InterpFloat(tempoChangePositions[tempoIdx - 1], tempoChangePositions[tempoIdx], (float)i/measuresToCreate); + + // var ml = measureLine.Instance(); + // measureScroll.AddChild(ml); + // ml.Translation = new Vector3(0, 0, pos); + // ml.Text = $"{curMeasure}"; + // } + // tempoIdx = Mathf.Clamp(tempoIdx + 1, 0, tempo.Count - 1); + // } + // } + // } + + doneLoading = true; + } + } +} \ No newline at end of file diff --git a/Scripts/Data/Chart/Chart.cs.meta b/Scripts/Data/Chart/Chart.cs.meta new file mode 100644 index 0000000..dc3ce32 --- /dev/null +++ b/Scripts/Data/Chart/Chart.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 562cc671f5a30839c8769855d8d0483f +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Scripts/Data/Chart/Difficulty.cs b/Scripts/Data/Chart/Difficulty.cs new file mode 100644 index 0000000..22294fd --- /dev/null +++ b/Scripts/Data/Chart/Difficulty.cs @@ -0,0 +1,9 @@ +using System; + +namespace WacK.Data.Chart +{ + public enum DifficultyLevel + { + Normal, Hard, Expert, Inferno + } +} diff --git a/Scripts/Data/Chart/Difficulty.cs.meta b/Scripts/Data/Chart/Difficulty.cs.meta new file mode 100644 index 0000000..96aa7a8 --- /dev/null +++ b/Scripts/Data/Chart/Difficulty.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 02342af085b6384489297bdfaaff13f1 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Scripts/Data/Chart/MeasureBeat.cs b/Scripts/Data/Chart/MeasureBeat.cs new file mode 100755 index 0000000..d7171c2 --- /dev/null +++ b/Scripts/Data/Chart/MeasureBeat.cs @@ -0,0 +1,121 @@ +using System; + +namespace WacK.Data.Chart +{ + /// + /// Represents a non-timed chart position in measure and beat as a fraction of the measure. + /// + public class MeasureBeat + { + public const int DENOMINATOR = 1920; + + public int measure { get; private set; } + /// + /// Beat in the measure, represented as beat/1920 of a measure. + /// + public int beat { get; private set; } + + public MeasureBeat(int measure, int beat) + { + this.measure = measure; + this.beat = beat; + Normalize(); + } + + public void Normalize() + { + // beats larger than denominator + if (Math.Abs(beat) >= DENOMINATOR) + { + measure += beat / DENOMINATOR; + beat %= DENOMINATOR; + } + // positive measure, negative beats + if (beat < 0 && measure > 0) + { + measure--; + beat += DENOMINATOR; + } + } + + public override string ToString() + { + return $"MeasureBeat({this.measure}, {this.beat}/{DENOMINATOR})"; + } + + public override int GetHashCode() + { + return measure*DENOMINATOR + beat; + } + + public override bool Equals(object tgt) + { + if (tgt == null) return false; + + return this == (MeasureBeat)tgt; + } + + /* STATIC CONSTANTS */ + public readonly static MeasureBeat ZERO = new MeasureBeat(0, 0); + + /* STATIC OPERATORS */ + public static MeasureBeat operator +(MeasureBeat a) => a; + public static MeasureBeat operator -(MeasureBeat a) + => new MeasureBeat(-a.measure, -a.beat); + + public static MeasureBeat operator +(MeasureBeat a, MeasureBeat b) + { + var meas = a.measure + b.measure; + var beat = a.beat + b.beat; + return new MeasureBeat(meas, beat); + } + + public static MeasureBeat operator -(MeasureBeat a, MeasureBeat b) + { + return a + -b; + } + + public static bool operator ==(MeasureBeat a, MeasureBeat b) + { + return a.measure == b.measure && a.beat == b.beat; + } + + public static bool operator !=(MeasureBeat a, MeasureBeat b) + { + return !(a == b); + } + + public static bool operator <(MeasureBeat a, MeasureBeat b) + { + if (a.measure < b.measure) return true; + + if (a.measure == b.measure) + { + return a.beat < b.beat; + } + + return false; + } + + public static bool operator >(MeasureBeat a, MeasureBeat b) + { + if (a != b) + { + return !(a < b); + } + return false; + } + + public static bool operator <=(MeasureBeat a, MeasureBeat b) + { + if (a == b) return true; + return a < b; + } + + public static bool operator >=(MeasureBeat a, MeasureBeat b) + { + if (a == b) return true; + return a > b; + } + } +} \ No newline at end of file diff --git a/Scripts/Data/Chart/MeasureBeat.cs.meta b/Scripts/Data/Chart/MeasureBeat.cs.meta new file mode 100644 index 0000000..a2ea869 --- /dev/null +++ b/Scripts/Data/Chart/MeasureBeat.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: f19917e007c0523e9a5ccccea23e9524 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Scripts/Data/Chart/Note.cs b/Scripts/Data/Chart/Note.cs new file mode 100755 index 0000000..e4fd040 --- /dev/null +++ b/Scripts/Data/Chart/Note.cs @@ -0,0 +1,43 @@ +using System.Collections.Generic; + +namespace WacK.Data.Chart +{ + /// + /// Base class for various in-play note types. + /// + public abstract class Note + { + /// + /// Time in milliseconds which the note occurs. + /// + public double time = 0; + + /// + /// Time of the note in MeasureBeat. + /// + public MeasureBeat measureBeat; + + /// + /// The note's radial position out of 60. + /// + public int? position; + + /// + /// The radial size of the note. + /// 1 <= size <= 60 + /// + public int? size; + + public Note(double time, MeasureBeat measureBeat, int? position = null, int? size = null) + { + this.time = time; + this.measureBeat = measureBeat; + this.position = position; + this.size = size; + } + + public Note() + { + } + } +} \ No newline at end of file diff --git a/Scripts/Data/Chart/Note.cs.meta b/Scripts/Data/Chart/Note.cs.meta new file mode 100644 index 0000000..404365d --- /dev/null +++ b/Scripts/Data/Chart/Note.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 1ed8bb3e1326d18f9927b087b6e8fe7c +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Scripts/Data/Chart/NoteEvent.cs b/Scripts/Data/Chart/NoteEvent.cs new file mode 100755 index 0000000..4bcf519 --- /dev/null +++ b/Scripts/Data/Chart/NoteEvent.cs @@ -0,0 +1,36 @@ +using System; + +using System.Collections.Generic; + +namespace WacK.Data.Chart +{ + public enum NoteEventType + { + Tempo, + TimeSignature, + ScrollSpeedMultiplier, + BGAdd, + BGRem, + } + + /// + /// Represents an unplayable event with some associated data value. + /// + /// The value's type. + public class NoteEvent : Note + { + public NoteEventType type; + + /// + /// A value whose function will vary depending on the type of note. + /// + public T value; + + public NoteEvent(double time, MeasureBeat measureBeat, NoteEventType type, int? position = null, int? size = null, T value = default(T)) : + base(time, measureBeat, position, size) + { + this.value = value; + this.type = type; + } + } +} diff --git a/Scripts/Data/Chart/NoteEvent.cs.meta b/Scripts/Data/Chart/NoteEvent.cs.meta new file mode 100644 index 0000000..26934cf --- /dev/null +++ b/Scripts/Data/Chart/NoteEvent.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: f133260cfe1efeb06bc84818f1f694c0 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Scripts/Data/Chart/NoteHold.cs b/Scripts/Data/Chart/NoteHold.cs new file mode 100755 index 0000000..389b006 --- /dev/null +++ b/Scripts/Data/Chart/NoteHold.cs @@ -0,0 +1,20 @@ +using System; +using System.Collections.Generic; +using System.Linq; + +namespace WacK.Data.Chart +{ + /// + /// A hold note. Notably contains data about hold points. + /// + public class NoteHold : NotePlay + { + public SortedList points; + + public NoteHold(double time, MeasureBeat measureBeat, int position, int size, int holdIndex, int holdNext, bool bonus = false) + : base(time, measureBeat, position, size,holdIndex, holdNext, type: NotePlayType.HoldStart, bonus: false) + { + // points = (SortedList)holdPoints.Skip(1); + } + } +} diff --git a/Scripts/Data/Chart/NoteHold.cs.meta b/Scripts/Data/Chart/NoteHold.cs.meta new file mode 100644 index 0000000..57d1c40 --- /dev/null +++ b/Scripts/Data/Chart/NoteHold.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 74c839480bb719c9b96e11709817d2e6 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Scripts/Data/Chart/NotePlay.cs b/Scripts/Data/Chart/NotePlay.cs new file mode 100755 index 0000000..85197d3 --- /dev/null +++ b/Scripts/Data/Chart/NotePlay.cs @@ -0,0 +1,38 @@ +using System.Collections.Generic; + +namespace WacK.Data.Chart +{ + public enum NotePlayType + { + Touch, + HoldStart, + HoldMid, + HoldEnd, + Untimed, + SwipeIn, + SwipeOut, + SwipeCW, + SwipeCCW, + } + + /// + /// Represents playable notes. + /// + public class NotePlay : Note + { + public NotePlayType type { get; private set; } + public bool isBonus { get; private set; } + public int holdIdx { get; private set; } + public int holdNextIdx { get; private set; } + + public NotePlay(double time, MeasureBeat measureBeat, int position, int size, int holdIndex = -1, int holdNext = -1, + NotePlayType type = NotePlayType.Touch, bool bonus = false) + : base(time, measureBeat, position, size) + { + this.type = type; + this.isBonus = bonus; + this.holdIdx = holdIndex; + this.holdNextIdx = holdNext; + } + } +} \ No newline at end of file diff --git a/Scripts/Data/Chart/NotePlay.cs.meta b/Scripts/Data/Chart/NotePlay.cs.meta new file mode 100644 index 0000000..a7458c3 --- /dev/null +++ b/Scripts/Data/Chart/NotePlay.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: ccfc6a251580ee67a83e2269870a227c +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Scripts/Data/Mer.meta b/Scripts/Data/Mer.meta new file mode 100644 index 0000000..a6ae7fc --- /dev/null +++ b/Scripts/Data/Mer.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 0ed6e3a31145daf8597c9bd80394d64d +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Scripts/Data/Mer/Mer.cs b/Scripts/Data/Mer/Mer.cs new file mode 100644 index 0000000..7cb711a --- /dev/null +++ b/Scripts/Data/Mer/Mer.cs @@ -0,0 +1,146 @@ +/** + * Chart.cs + * Representation of a chart, constructed from a .mer file. + * + * by muskit + * July 1, 2022 + **/ + +using System; +using System.Collections.Generic; + +namespace WacK.Data.Mer +{ + /// + /// Structurized representation of a .mer file. + /// + public class Mer + { + /// + /// HIERARCHY: + /// Key is measure. + /// Value is List of (beat/1920, Notes) tuples. + /// + public SortedList> notes = new SortedList>(); + + public int playableNoteCount { get; private set; } + + /// + /// Construct Chart from contents of .mer file. + /// + /// Contents of a .mer file. + public Mer(string str) + { + if (str == String.Empty) return; + + playableNoteCount = 0; + + List lines = new List(str.Split('\n')); + foreach (var line in lines) + { + List tokens = new List(line.Split(new string[] { " " }, StringSplitOptions.RemoveEmptyEntries)); + if (tokens.Count == 0) continue; + if (tokens[0][0] == '#') continue; + + int currentMeasure = int.Parse(tokens[0]); + int currentBeat = int.Parse(tokens[1]); + + if (!notes.ContainsKey(currentMeasure)) + { + notes[currentMeasure] = new List<(int, MerNote)>(); + } + + switch (tokens[2]) + { + case "1": // common note types + switch(tokens[3]) + { + case "1": // touch + notes[currentMeasure].Add((currentBeat, new MerNote(int.Parse(tokens[5]), int.Parse(tokens[6]), type: MerType.Touch))); + ++playableNoteCount; + break; + case "2": // touch w/ bonus + notes[currentMeasure].Add((currentBeat, new MerNote(int.Parse(tokens[5]), int.Parse(tokens[6]), type: MerType.Touch, bonus: true))); + ++playableNoteCount; + break; + case "20": // touch w/ bonus (+ "big effect") + notes[currentMeasure].Add((currentBeat, new MerNote(int.Parse(tokens[5]), int.Parse(tokens[6]), type: MerType.Touch, bonus: true))); + ++playableNoteCount; + break; + case "16": // untimed + notes[currentMeasure].Add((currentBeat, new MerNote(int.Parse(tokens[5]), int.Parse(tokens[6]), type: MerType.Untimed))); + ++playableNoteCount; + break; + case "26": // untimed w/ bonus + notes[currentMeasure].Add((currentBeat, new MerNote(int.Parse(tokens[5]), int.Parse(tokens[6]), type: MerType.Untimed, bonus: true))); + ++playableNoteCount; + break; + case "3": // swipe in (red) + notes[currentMeasure].Add((currentBeat, new MerNote(int.Parse(tokens[5]), int.Parse(tokens[6]), type: MerType.SwipeIn))); + ++playableNoteCount; + break; + case "21": // swipe in w/ bonus + notes[currentMeasure].Add((currentBeat, new MerNote(int.Parse(tokens[5]), int.Parse(tokens[6]), type: MerType.SwipeIn, bonus: true))); + ++playableNoteCount; + break; + case "4": // swipe out (blue) + notes[currentMeasure].Add((currentBeat, new MerNote(int.Parse(tokens[5]), int.Parse(tokens[6]), type: MerType.SwipeOut))); + ++playableNoteCount; + break; + case "22": // swipe out w/ bonus + notes[currentMeasure].Add((currentBeat, new MerNote(int.Parse(tokens[5]), int.Parse(tokens[6]), type: MerType.SwipeOut, bonus: true))); + ++playableNoteCount; + break; + case "7": // swipe CCW + notes[currentMeasure].Add((currentBeat, new MerNote(int.Parse(tokens[5]), int.Parse(tokens[6]), type: MerType.SwipeCCW))); + ++playableNoteCount; + break; + case "8": // swipe CCW w/ bonus + notes[currentMeasure].Add((currentBeat, new MerNote(int.Parse(tokens[5]), int.Parse(tokens[6]), type: MerType.SwipeCCW, bonus: true))); + ++playableNoteCount; + break; + case "5": // swipe CW + notes[currentMeasure].Add((currentBeat, new MerNote(int.Parse(tokens[5]), int.Parse(tokens[6]), type: MerType.SwipeCW))); + ++playableNoteCount; + break; + case "6": // swipe CW w/ bonus + notes[currentMeasure].Add((currentBeat, new MerNote(int.Parse(tokens[5]), int.Parse(tokens[6]), type: MerType.SwipeCW, bonus: true))); + ++playableNoteCount; + break; + case "9": // hold start + notes[currentMeasure].Add((currentBeat, new MerNote(int.Parse(tokens[5]), int.Parse(tokens[6]), holdIndex: int.Parse(tokens[4]), holdNext: int.Parse(tokens[8]), type: MerType.HoldStart))); + break; + case "25": // hold start (w/ bonus) + notes[currentMeasure].Add((currentBeat, new MerNote(int.Parse(tokens[5]), int.Parse(tokens[6]), holdIndex: int.Parse(tokens[4]), holdNext: int.Parse(tokens[8]), type: MerType.HoldStart, bonus: true))); + ++playableNoteCount; + break; + case "10": // hold middle + notes[currentMeasure].Add((currentBeat, new MerNote(int.Parse(tokens[5]), int.Parse(tokens[6]), holdIndex: int.Parse(tokens[4]), holdNext: int.Parse(tokens[8]), type: MerType.HoldMid))); + break; + case "11": // hold end + notes[currentMeasure].Add((currentBeat, new MerNote(int.Parse(tokens[5]), int.Parse(tokens[6]), holdIndex: int.Parse(tokens[4]), type: MerType.HoldEnd))); + break; + case "12": // BG add + notes[currentMeasure].Add((currentBeat, new MerNote(int.Parse(tokens[5]), int.Parse(tokens[6]), value: tokens[8], type: MerType.BGAdd))); + break; + case "13": // BG rem + notes[currentMeasure].Add((currentBeat, new MerNote(int.Parse(tokens[5]), int.Parse(tokens[6]), value: tokens[8], type: MerType.BGRem))); + break; + + } + break; + case "2": // tempo + notes[currentMeasure].Add((currentBeat, new MerNote(value: tokens[3], type: MerType.Tempo))); + break; + case "3": // beats per measure + notes[currentMeasure].Add((currentBeat, new MerNote(value: $"{tokens[3]} {tokens[4]}", type: MerType.TimeSignature))); + break; + } + } + foreach (var measure in notes) + { + measure.Value.Sort((x, y) => x.Item1.CompareTo(y.Item1)); + } + } + } +} diff --git a/Scripts/Data/Mer/Mer.cs.meta b/Scripts/Data/Mer/Mer.cs.meta new file mode 100644 index 0000000..4ed5e08 --- /dev/null +++ b/Scripts/Data/Mer/Mer.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 03f65fd134dbd18faba49dbb870b3450 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Scripts/Data/Mer/MerNote.cs b/Scripts/Data/Mer/MerNote.cs new file mode 100644 index 0000000..a867d5b --- /dev/null +++ b/Scripts/Data/Mer/MerNote.cs @@ -0,0 +1,38 @@ +/** + * Note.cs + * A struct representing a note. + * + * by muskit + * July 1, 2022 + **/ + +namespace WacK.Data.Mer +{ + public enum MerType + { + Touch, HoldStart, HoldMid, HoldEnd, Untimed, SwipeIn, SwipeOut, SwipeCW, SwipeCCW, Tempo, TimeSignature, BGAdd, BGRem + } + public struct MerNote + { + public MerType noteType { get; private set; } + public bool isBonus { get; private set; } + + // Radial values in minutes + public int position { get; private set; } + public int size { get; private set; } // 1 <= size <= 60 + public string value { get; private set; } + public int holdIdx { get; private set; } + public int holdNextIdx { get; private set; } + + public MerNote(int position = 0, int size = 1, string value = "", int holdIndex = -1, int holdNext = -1, MerType type = MerType.Touch, bool bonus = false) + { + this.position = position; + this.size = size; + this.value = value; + this.holdIdx = holdIndex; + this.holdNextIdx = holdNext; + this.noteType = type; + this.isBonus = bonus; + } + } +} \ No newline at end of file diff --git a/Scripts/Data/Mer/MerNote.cs.meta b/Scripts/Data/Mer/MerNote.cs.meta new file mode 100644 index 0000000..84590cb --- /dev/null +++ b/Scripts/Data/Mer/MerNote.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: f03d973b6879b96a5b79467d1dd3cbfc +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Scripts/Scenes/DebugChartLoader.cs b/Scripts/Scenes/DebugChartLoader.cs new file mode 100644 index 0000000..2dee1df --- /dev/null +++ b/Scripts/Scenes/DebugChartLoader.cs @@ -0,0 +1,68 @@ +using Godot; +using System; + +namespace WacK.Scenes +{ + public partial class DebugChartLoader : Node + { + [Export] + private LineEdit inputField; + + [Export] + private LineEdit soundField; + + [Export] + private OptionButton difficultyButton; + + [Export] + private Button playButton; + + + // Called when the node enters the scene tree for the first time. + public override void _Ready() + { + playButton.Pressed += PlayClicked; + } + + private void PlayClicked() + { + // TODO: globally accessible verify song folder and chart/audio function + var songPath = $"user://songs/{inputField.Text}"; + var chartPath = $"{songPath}/{difficultyButton.Selected}.mer"; + var soundPath = $"{songPath}/{soundField.Text}"; + GD.Print($"Song: {songPath}\nChart: {chartPath}\nSound: {soundPath}"); + + // folder check + using var dir = DirAccess.Open(songPath); + if (dir == null) + { + GD.PrintErr($"Error occurred opening song folder!\n{DirAccess.GetOpenError()}"); + return; + } + + // chart check + using var chartFile = FileAccess.Open(chartPath, FileAccess.ModeFlags.Read); + if (chartFile == null) + { + GD.PrintErr($"Error occurred opening chart!\n{FileAccess.GetOpenError()}"); + return; + } + + // sound check + using var soundFile = FileAccess.Open(soundPath, FileAccess.ModeFlags.Read); + if (soundFile == null) + { + GD.PrintErr($"Error occurred opening sound!\n{FileAccess.GetOpenError()}"); + return; + } + + Play.playParams = new PlayParameters(chartPath, soundPath); + GetTree().ChangeSceneToFile("res://Scenes/Play.tscn"); + } + + public override void _ExitTree() + { + playButton.Pressed -= PlayClicked; + } + } +} diff --git a/Scripts/Scenes/Play.cs b/Scripts/Scenes/Play.cs new file mode 100644 index 0000000..3d8886f --- /dev/null +++ b/Scripts/Scenes/Play.cs @@ -0,0 +1,35 @@ +using Godot; + +namespace WacK.Scenes +{ + public class PlayParameters + { + /* TODO: store song ID from internal database + public string songID; + public Difficulty diff; + */ + public string chartPath; + public string soundPath; + + public PlayParameters(string chPath, string snPath) + { + chartPath = chPath; + soundPath = snPath; + } + } + public partial class Play : Node + { + // initialized by another scene, BEFORE loading this one! + public static PlayParameters playParams; + + private void Start() + { + + } + + private void OnDestroy() + { + playParams = null; + } + } +} \ No newline at end of file diff --git a/Scripts/Scenes/Startup.cs b/Scripts/Scenes/Startup.cs new file mode 100644 index 0000000..b5281ba --- /dev/null +++ b/Scripts/Scenes/Startup.cs @@ -0,0 +1,46 @@ +using Godot; +using System; + +namespace WacK.Scenes +{ + public partial class Startup : Node + { + // Called when the node enters the scene tree for the first time. + public override void _Ready() + { + GD.Print($"User directory: {OS.GetUserDataDir()}"); + using var songDir = DirAccess.Open("user://songs"); + if (songDir != null) + { + GD.Print("Successfully opened songs directory!"); + // load songs + } + else + { + GD.Print("Could not find songs directory! Creating it..."); + + DirAccess.MakeDirAbsolute("user://songs"); + using var newSongDir = DirAccess.Open("user://songs"); + + if (newSongDir != null) + { + GD.Print("Songs folder created successfully!"); + // create note + var note = "Place song folders here. Nested folders supported for organization.\n"; + using var f = FileAccess.Open($"{newSongDir.GetCurrentDir()}/note.txt", FileAccess.ModeFlags.Write); + f.StoreString(note); + + // TODO: add in-game notice + } + else + { + GD.PrintErr($"Could not create the songs directory!\n{DirAccess.GetOpenError()}"); + } + + } + + // Change scenes + GetTree().ChangeSceneToFile("res://Scenes/DebugChartLoader.tscn"); + } + } +} diff --git a/Scripts/Util.cs b/Scripts/Util.cs new file mode 100644 index 0000000..82162ed --- /dev/null +++ b/Scripts/Util.cs @@ -0,0 +1,147 @@ +/** + * Util.cs + * Various conversion functions. + * + * by muskit + * July 26, 2022 + **/ + +using System; + +using Godot; + +using WacK.Configuration; + +namespace WacK +{ + public static class Util + { + public static float Seg2Rad(float seg) + { + return Mathf.DegToRad(6f * seg); + } + public static float Rad2Seg(float angle) + { + return Mathf.RadToDeg(angle / 6f); + } + + public static int InterpInt(int a, int b, float ratio) + { + if (a == 0 && b == 0) + return 0; + return (int)Math.Round(a + (b - a) * ratio); + } + + public static float InterpFloat(float a, float b, float ratio) + { + if (a == 0 && b == 0) + return 0; + return a + (b - a) * ratio; + } + + // Returns an equivalent destination angle that's closest to the origin. + public static float NearestAngle(float origin, float destination) + { + float result = destination; + + float plus = destination + 2f * Mathf.Pi; + float minus = destination - 2f * Mathf.Pi; + float minusDelta = Mathf.Abs(minus - origin); + float normDelta = Mathf.Abs(destination - origin); + float plusDelta = Mathf.Abs(plus - origin); + if (plusDelta < normDelta) + result = plus; + if (minusDelta < normDelta) + result = minus; + + return result; + } + + // Return an equivalent minute that's closest to the origin. + public static float NearestMinute(int origin, int destination) + { + int result = destination % 60; + + int plus = destination + 60; + int minus = destination - 60; + int minusDelta = Math.Abs(minus - origin); + int normDelta = Math.Abs(destination - origin); + int plusDelta = Math.Abs(plus - origin); + if (plusDelta < normDelta) + result = plus; + if (minusDelta < normDelta) + result = minus; + + return result; + } + + public static float ScreenPixelToRad(Vector2 pos) + { + var resolution = DisplayServer.WindowGetSize(); + var origin = new Vector2(resolution.X / 2 - 1, resolution.Y / 2 - 1); + + return Mathf.Atan2(pos.Y - origin.Y, pos.X - origin.X); + } + + public static int TouchPosToSegmentInt(Vector2 pos, Vector2 touchResolution) + { + var origin = new Vector2(touchResolution.X / 2 - 1, touchResolution.Y / 2 - 1); + var angle = Mathf.Atan2(pos.Y - origin.Y, pos.X - origin.X); + + if (angle > 0) + angle = 2f * Mathf.Pi - angle; + + return Mathf.FloorToInt(Mathf.Abs(angle) / 2f * Mathf.Pi * 60) % 60; + } + + public static int ScreenPixelToSegmentInt(Vector2 pos) + { + var angle = ScreenPixelToRad(pos); + if (angle > 0) + angle = 2f * Mathf.Pi - angle; + + return Mathf.FloorToInt(Mathf.Abs(angle) / 2f * Mathf.Pi * 60) % 60; + } + + public static float NoteTime(int measure, int beat, float tempo, int beatsPerMeasure) + { + if (tempo == 0) return 0; // avoid divide by 0 + + return 60f / tempo * beatsPerMeasure * ((float)measure + (float)beat / 1920f); + } + + public static float NotePosition(int measure, int beat, float tempo, int beatsPerMeasure) + { + if (tempo == 0) return 0; // avoid divide by 0 + return TimeToPosition(60f / tempo * beatsPerMeasure * ((float)measure + (float)beat / 1920f)); + } + + public static float TimeToPosition(float time) + { + return time * PlaySettings.playSpeedMultiplier * Constants.SCROLL_MULT; + } + + public static float PositionToTime(float pos) + { + return pos / PlaySettings.playSpeedMultiplier / Constants.SCROLL_MULT; + } + + // TODO: notes scale to scroll position instead of strikeline + // (where calibration offsets can be applied) + public static Vector3 NoteScale(float zPos, float zOrigin = 0) + { + var val = zPos - zOrigin; + if (val <= Constants.NOTE_DRAW_DISTANCE) + { + var ratio = Mathf.Clamp((Constants.NOTE_DRAW_DISTANCE - val) / Constants.NOTE_DRAW_DISTANCE, 0, 1); + return new Vector3(ratio, ratio, 1); + } + return Vector3.Zero; + } + + public static string DifficultyValueToString(float diffPoint) + { + return Mathf.FloorToInt(diffPoint).ToString() + (diffPoint > Mathf.Floor(diffPoint) ? "+" : ""); + } + } +} \ No newline at end of file diff --git a/Things/TunnelObjects/2D/Background/Background.tscn b/Things/TunnelObjects/2D/Background/Background.tscn new file mode 100644 index 0000000..68d6a51 --- /dev/null +++ b/Things/TunnelObjects/2D/Background/Background.tscn @@ -0,0 +1,3 @@ +[gd_scene format=3 uid="uid://b7dhdsryff4rn"] + +[node name="TunnelObjects" type="Node2D"] diff --git a/Things/TunnelObjects/2D/Background/BackgroundSegment.tscn b/Things/TunnelObjects/2D/Background/BackgroundSegment.tscn new file mode 100644 index 0000000..69792e2 --- /dev/null +++ b/Things/TunnelObjects/2D/Background/BackgroundSegment.tscn @@ -0,0 +1,3 @@ +[gd_scene format=3 uid="uid://cvxp0w0urvyhj"] + +[node name="BackgroundSegment" type="Node2D"] diff --git a/WacK.csproj b/WacK.csproj new file mode 100644 index 0000000..8ee8c44 --- /dev/null +++ b/WacK.csproj @@ -0,0 +1,6 @@ + + + net6.0 + true + + \ No newline at end of file diff --git a/WacK.sln b/WacK.sln new file mode 100644 index 0000000..a8d2bb6 --- /dev/null +++ b/WacK.sln @@ -0,0 +1,19 @@ +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 2012 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WacK", "WacK.csproj", "{2797AE7C-0780-47EF-B89B-1F339403C89F}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + ExportDebug|Any CPU = ExportDebug|Any CPU + ExportRelease|Any CPU = ExportRelease|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {2797AE7C-0780-47EF-B89B-1F339403C89F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {2797AE7C-0780-47EF-B89B-1F339403C89F}.Debug|Any CPU.Build.0 = Debug|Any CPU + {2797AE7C-0780-47EF-B89B-1F339403C89F}.ExportDebug|Any CPU.ActiveCfg = ExportDebug|Any CPU + {2797AE7C-0780-47EF-B89B-1F339403C89F}.ExportDebug|Any CPU.Build.0 = ExportDebug|Any CPU + {2797AE7C-0780-47EF-B89B-1F339403C89F}.ExportRelease|Any CPU.ActiveCfg = ExportRelease|Any CPU + {2797AE7C-0780-47EF-B89B-1F339403C89F}.ExportRelease|Any CPU.Build.0 = ExportRelease|Any CPU + EndGlobalSection +EndGlobal diff --git a/icon.svg b/icon.svg new file mode 100644 index 0000000..b370ceb --- /dev/null +++ b/icon.svg @@ -0,0 +1 @@ + diff --git a/icon.svg.import b/icon.svg.import new file mode 100644 index 0000000..752497a --- /dev/null +++ b/icon.svg.import @@ -0,0 +1,37 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://cprfryf1c7kr2" +path="res://.godot/imported/icon.svg-218a8f2b3041327d8a5756f3a245f83b.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://icon.svg" +dest_files=["res://.godot/imported/icon.svg-218a8f2b3041327d8a5756f3a245f83b.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 +svg/scale=1.0 +editor/scale_with_editor_scale=false +editor/convert_colors_with_editor_theme=false diff --git a/project.godot b/project.godot new file mode 100644 index 0000000..09d6ec6 --- /dev/null +++ b/project.godot @@ -0,0 +1,32 @@ +; Engine configuration file. +; It's best edited using the editor UI and not directly, +; since the parameters that go here are not all obvious. +; +; Format: +; [section] ; section goes between [] +; param=value ; assign values to parameters + +config_version=5 + +[application] + +config/name="WacK" +run/main_scene="res://Scenes/_STARTUP.tscn" +config/features=PackedStringArray("4.1", "C#", "Mobile") +config/icon="res://icon.svg" + +[display] + +window/size/viewport_width=1920 +window/size/viewport_height=1080 +window/stretch/mode="canvas_items" +window/stretch/aspect="expand" +window/vsync/vsync_mode=3 + +[dotnet] + +project/assembly_name="WacK" + +[rendering] + +renderer/rendering_method="mobile"