Skip to content

Commit adf1705

Browse files
authored
Merge pull request #50 from Project-Funk-Engine/note-effects
Note effects
2 parents ee4dc88 + 8e3ab6c commit adf1705

17 files changed

Lines changed: 372 additions & 16 deletions

Funk Engine.csproj

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,9 @@
66
<EnableDynamicLoading>true</EnableDynamicLoading>
77
<RootNamespace>FunkEngine</RootNamespace>
88
</PropertyGroup>
9+
<ItemGroup>
10+
<Content Include="SaveData\SaveData.json" />
11+
</ItemGroup>
912
<Target Name="Husky" BeforeTargets="Restore;CollectPackageReferences" Condition="'$(HUSKY)' != 0">
1013
<Exec Command="dotnet tool restore" StandardOutputImportance="Low" StandardErrorImportance="High" />
1114
<Exec Command="dotnet husky install" StandardOutputImportance="Low" StandardErrorImportance="High" WorkingDirectory="." />

Globals/Scribe.cs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,17 @@ public partial class Scribe : Node
2828
director.Enemy.TakeDamage((int)timing);
2929
}
3030
),
31+
new Note(
32+
"PlayerDouble",
33+
null,
34+
1,
35+
(director, note, timing) =>
36+
{
37+
// can change later, but I want it like this instead of changing base
38+
// in case we have some relic that messes with timing
39+
director.Enemy.TakeDamage(2 * (int)timing);
40+
}
41+
),
3142
};
3243

3344
public static readonly RelicTemplate[] RelicDictionary = new[]

SaveData/SaveData.json

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
{
2+
"AccountName": null,
3+
"Notes": {
4+
"PlayerBase": 2,
5+
"PlayerDouble": 1
6+
},
7+
"Relics": {},
8+
"Settings": {}
9+
}

SaveData/SaveSystem.cs

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
using System.Collections.Generic;
2+
using System.IO;
3+
using System.Text.Json;
4+
using Godot;
5+
6+
// TODO: implement saving
7+
8+
public static class SaveSystem
9+
{
10+
private static string SavePath => "res://SaveData/SaveData.json"; // Update if needed
11+
12+
// Loads only the notes section
13+
public static Dictionary<string, int> LoadNotes()
14+
{
15+
var saveData = LoadSaveData();
16+
if (saveData != null && saveData.Notes != null)
17+
{
18+
return saveData.Notes;
19+
}
20+
else
21+
{
22+
return new Dictionary<string, int>();
23+
}
24+
}
25+
26+
// This method loads the entire save data
27+
public static SaveData LoadSaveData()
28+
{
29+
string path = ProjectSettings.GlobalizePath(SavePath);
30+
if (!File.Exists(path))
31+
{
32+
GD.PrintErr("Can't load save game");
33+
return null;
34+
}
35+
36+
string json = File.ReadAllText(path);
37+
SaveData data = JsonSerializer.Deserialize<SaveData>(json);
38+
return data;
39+
}
40+
}
41+
42+
public class SaveData
43+
{
44+
public string AccountName { get; set; }
45+
public Dictionary<string, int> Notes { get; set; } = new Dictionary<string, int>();
46+
public Dictionary<string, object> Relics { get; set; } = new Dictionary<string, object>();
47+
public Dictionary<string, float> Settings { get; set; } = new Dictionary<string, float>();
48+
}

scenes/BattleDirector/scripts/BattleDirector.cs

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,19 +32,31 @@ public partial class BattleDirector : Node2D
3232

3333
private SongData _curSong;
3434

35+
[Export]
36+
private NoteQueue NQ;
37+
3538
#endregion
3639

3740
#region Note Handling
3841
private void PlayerAddNote(ArrowType type, int beat)
3942
{
40-
GD.Print($"Player trying to place {type} typed note at beat: " + beat);
43+
//TODO: note that should be added from the queue
44+
Note note = NQ.GetCurrentNote();
45+
if (note == null)
46+
{
47+
GD.Print("No notes in queue");
48+
return;
49+
}
50+
51+
GD.Print($"Player trying to place {note.Name}:{type} typed note at beat: " + beat);
4152
if (!NotePlacementBar.CanPlaceNote())
4253
return;
43-
if (CD.AddNoteToLane(type, beat % CM.BeatsPerLoop, false))
54+
if (CD.AddNoteToLane(type, beat % CM.BeatsPerLoop, note, false))
4455
{
4556
NotePlacementBar.PlacedNote();
4657
NotePlaced?.Invoke(this);
4758
GD.Print("Note Placed.");
59+
NQ.DequeueNote();
4860
}
4961
}
5062

scenes/BattleDirector/scripts/Conductor.cs

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ private bool IsNoteActive(ArrowType type, int beat)
4242
return _laneData[(int)type][beat] != null && _laneData[(int)type][beat].IsActive;
4343
}
4444

45-
public bool AddNoteToLane(ArrowType type, int beat, bool isActive = true)
45+
public bool AddNoteToLane(ArrowType type, int beat, Note note, bool isActive = true)
4646
{
4747
beat %= CM.BeatsPerLoop;
4848
//Don't add dupe notes //Beat at 0 is too messy.
@@ -54,12 +54,18 @@ public bool AddNoteToLane(ArrowType type, int beat, bool isActive = true)
5454
NoteArrow arrow;
5555
if (isActive)
5656
{
57-
arrow = CM.AddArrowToLane(type, beat, Notes.Length - 1);
57+
arrow = CM.AddArrowToLane(type, beat, Notes.Length - 1, note);
5858
arrow.NoteIdx = 1;
5959
}
6060
else
6161
{
62-
arrow = CM.AddArrowToLane(type, beat, Notes.Length - 1, new Color(1, 0.43f, 0.26f));
62+
arrow = CM.AddArrowToLane(
63+
type,
64+
beat,
65+
Notes.Length - 1,
66+
note,
67+
new Color(1, 0.43f, 0.26f)
68+
);
6369
arrow.NoteIdx = 0;
6470
}
6571

@@ -85,22 +91,22 @@ private void AddExampleNotes()
8591
GD.Print(CM.BeatsPerLoop);
8692
for (int i = 1; i < 15; i++)
8793
{
88-
AddNoteToLane(ArrowType.Up, i * 4);
94+
AddNoteToLane(ArrowType.Up, i * 4, Scribe.NoteDictionary[0]);
8995
}
9096

9197
for (int i = 1; i < 15; i++)
9298
{
93-
AddNoteToLane(ArrowType.Left, 4 * i + 1);
99+
AddNoteToLane(ArrowType.Left, 4 * i + 1, Scribe.NoteDictionary[0]);
94100
}
95101

96102
for (int i = 0; i < 10; i++)
97103
{
98-
AddNoteToLane(ArrowType.Right, 3 * i + 32);
104+
AddNoteToLane(ArrowType.Right, 3 * i + 32, Scribe.NoteDictionary[0]);
99105
}
100106

101107
for (int i = 0; i < 3; i++)
102108
{
103-
AddNoteToLane(ArrowType.Down, 8 * i + 16);
109+
AddNoteToLane(ArrowType.Down, 8 * i + 16, Scribe.NoteDictionary[0]);
104110
}
105111
}
106112

scenes/BattleDirector/test_battle_scene.tscn

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,21 @@
1-
[gd_scene load_steps=7 format=3 uid="uid://b0mrgr7h0ty1y"]
1+
[gd_scene load_steps=9 format=3 uid="uid://b0mrgr7h0ty1y"]
22

33
[ext_resource type="Script" path="res://scenes/BattleDirector/scripts/BattleDirector.cs" id="1_cwqqr"]
44
[ext_resource type="PackedScene" uid="uid://dfevfib11kou1" path="res://scenes/ChartViewport/ChartViewport.tscn" id="2_cupb3"]
55
[ext_resource type="Script" path="res://scenes/BattleDirector/scripts/Conductor.cs" id="2_pcp76"]
66
[ext_resource type="Texture2D" uid="uid://ci0g72j8q4ec2" path="res://scenes/BattleDirector/assets/CoolBG.jpg" id="4_13o87"]
77
[ext_resource type="PackedScene" uid="uid://duhiilcv4tat3" path="res://scenes/BattleDirector/NotePlacementBar.tscn" id="7_3ko4g"]
8+
[ext_resource type="PackedScene" uid="uid://bvhpon5liybd1" path="res://scenes/CustomNotes/NoteQueue.tscn" id="8_7wwxo"]
89
[ext_resource type="AudioStream" uid="uid://cv6lqjj6lu36h" path="res://Audio/335571__magntron__gamemusic_120bpm.mp3" id="8_caqms"]
910

10-
[node name="ProtoBattleDirector" type="Node2D" node_paths=PackedStringArray("CM", "NotePlacementBar", "CD", "Audio")]
11+
[node name="ProtoBattleDirector" type="Node2D" node_paths=PackedStringArray("CM", "NotePlacementBar", "CD", "Audio", "NQ")]
1112
process_mode = 1
1213
script = ExtResource("1_cwqqr")
1314
CM = NodePath("SubViewport")
1415
NotePlacementBar = NodePath("NotePlacementBar")
1516
CD = NodePath("Conductor")
1617
Audio = NodePath("AudioStreamPlayer")
18+
NQ = NodePath("NoteQueue")
1719

1820
[node name="UILayer" type="CanvasLayer" parent="."]
1921

@@ -58,3 +60,14 @@ offset_right = 613.0
5860
offset_bottom = 188.0
5961
theme_override_font_sizes/font_size = 10
6062
text = "Relics:"
63+
64+
[node name="NoteQueue" parent="." instance=ExtResource("8_7wwxo")]
65+
anchors_preset = 0
66+
anchor_right = 0.0
67+
anchor_bottom = 0.0
68+
offset_left = 100.0
69+
offset_top = 140.0
70+
offset_right = 100.0
71+
offset_bottom = 140.0
72+
grow_horizontal = 1
73+
grow_vertical = 1

scenes/ChartViewport/ChartManager.cs

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -102,11 +102,12 @@ public NoteArrow AddArrowToLane(
102102
ArrowType type,
103103
int beat,
104104
int noteIdx,
105+
Note note,
105106
Color colorOverride = default
106107
)
107108
{
108-
var newNote = CreateNote(type, beat);
109-
var loopArrow = CreateNote(type, beat + BeatsPerLoop); //Create a dummy arrow for looping visuals
109+
var newNote = CreateNote(type, note, beat);
110+
var loopArrow = CreateNote(type, note, beat + BeatsPerLoop); //Create a dummy arrow for looping visuals
110111
if (colorOverride != default)
111112
{
112113
newNote.Modulate = colorOverride;
@@ -116,11 +117,11 @@ public NoteArrow AddArrowToLane(
116117
return newNote;
117118
}
118119

119-
private NoteArrow CreateNote(ArrowType arrow, int beat = 0)
120+
private NoteArrow CreateNote(ArrowType arrow, Note note, int beat = 0)
120121
{
121122
var noteScene = ResourceLoader.Load<PackedScene>("res://scenes/NoteManager/note.tscn");
122123
NoteArrow newArrow = noteScene.Instantiate<NoteArrow>();
123-
newArrow.Init(IH.Arrows[(int)arrow], beat);
124+
newArrow.Init(IH.Arrows[(int)arrow], beat, note);
124125

125126
_arrowGroup.AddChild(newArrow);
126127
newArrow.Bounds = (float)((double)beat / BeatsPerLoop * (ChartLength / 2));

scenes/CustomNotes/NoteQueue.cs

Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using Godot;
4+
5+
public partial class NoteQueue : Node
6+
{
7+
[Export]
8+
private Sprite2D _currentNote;
9+
10+
[Export]
11+
private Sprite2D _nextNote;
12+
13+
private Queue<Note> _noteQueue = new Queue<Note>();
14+
private Dictionary<string, Texture2D> _noteSprites = new Dictionary<string, Texture2D>();
15+
16+
public override void _Ready()
17+
{
18+
_noteSprites["PlayerBase"] = GD.Load<Texture2D>(
19+
"res://scenes/CustomNotes/assets/single_note.png"
20+
);
21+
_noteSprites["PlayerDouble"] = GD.Load<Texture2D>(
22+
"res://scenes/CustomNotes/assets/double_note.png"
23+
);
24+
25+
LoadQueueFromSave();
26+
ScrambleQueue();
27+
UpdateQueue();
28+
}
29+
30+
// Loads the notes from SaveData.json, and adds them to the queue
31+
public void LoadQueueFromSave()
32+
{
33+
Dictionary<string, int> savedNotes = SaveSystem.LoadNotes();
34+
foreach (var noteEntry in savedNotes)
35+
{
36+
string noteName = noteEntry.Key;
37+
int numNotes = noteEntry.Value;
38+
39+
for (int i = 0; i < numNotes; i++)
40+
{
41+
GD.Print($"Creating note from noteName: {noteName}");
42+
AddNoteToQueue(CreateNoteFromName(noteName));
43+
}
44+
}
45+
}
46+
47+
// Creates a note from a string of the note's name.
48+
private Note CreateNoteFromName(string noteName)
49+
{
50+
if (noteName == "PlayerBase")
51+
return Scribe.NoteDictionary[1];
52+
53+
if (noteName == "PlayerDouble")
54+
return Scribe.NoteDictionary[2];
55+
56+
GD.Print($"Failed to create not from noteName: {noteName}");
57+
return null;
58+
}
59+
60+
public void AddNoteToQueue(Note noteType)
61+
{
62+
_noteQueue.Enqueue(noteType);
63+
UpdateQueue();
64+
}
65+
66+
// Returns current note, and removes it from the queue
67+
public Note GetCurrentNote()
68+
{
69+
if (_noteQueue.Count > 0)
70+
{
71+
return _noteQueue.Peek();
72+
}
73+
return null;
74+
}
75+
76+
public void DequeueNote()
77+
{
78+
_noteQueue.Dequeue();
79+
UpdateQueue();
80+
}
81+
82+
// Updates the queue's graphics
83+
private void UpdateQueue()
84+
{
85+
if (_noteQueue.Count > 0 && _noteSprites.ContainsKey(_noteQueue.Peek().Name))
86+
_currentNote.Texture = _noteSprites[_noteQueue.Peek().Name];
87+
else
88+
_currentNote.Texture = null;
89+
90+
if (_noteQueue.Count > 1)
91+
{
92+
Note[] notes = _noteQueue.ToArray();
93+
if (_noteSprites.ContainsKey(notes[1].Name))
94+
_nextNote.Texture = _noteSprites[notes[1].Name];
95+
else
96+
_nextNote.Texture = null;
97+
}
98+
else
99+
{
100+
_nextNote.Texture = null;
101+
}
102+
}
103+
104+
// Fisher-Yates shuffle from: https://stackoverflow.com/a/1262619
105+
public void ScrambleQueue()
106+
{
107+
List<Note> tempList = new List<Note>(_noteQueue);
108+
Random rng = new Random();
109+
110+
int n = tempList.Count;
111+
while (n > 1)
112+
{
113+
n--;
114+
int k = rng.Next(n + 1);
115+
(tempList[k], tempList[n]) = (tempList[n], tempList[k]);
116+
}
117+
118+
_noteQueue = new Queue<Note>(tempList);
119+
}
120+
121+
//TODO: MAYBE? implement saving the notequeue to savedata
122+
}

scenes/CustomNotes/NoteQueue.tscn

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
[gd_scene load_steps=5 format=3 uid="uid://bvhpon5liybd1"]
2+
3+
[ext_resource type="Script" path="res://scenes/CustomNotes/NoteQueue.cs" id="1_jeqam"]
4+
[ext_resource type="Texture2D" uid="uid://cnyr5usjdv0ni" path="res://scenes/CustomNotes/assets/temp_note_queue.png" id="2_0p21a"]
5+
[ext_resource type="Texture2D" uid="uid://c3chrsxrulapd" path="res://scenes/CustomNotes/assets/single_note.png" id="3_ewo1s"]
6+
[ext_resource type="Texture2D" uid="uid://caw70lr5e1yiq" path="res://scenes/CustomNotes/assets/double_note.png" id="4_7sgy6"]
7+
8+
[node name="NoteQueue" type="Control" node_paths=PackedStringArray("_currentNote", "_nextNote")]
9+
layout_mode = 3
10+
anchors_preset = 15
11+
anchor_right = 1.0
12+
anchor_bottom = 1.0
13+
grow_horizontal = 2
14+
grow_vertical = 2
15+
script = ExtResource("1_jeqam")
16+
_currentNote = NodePath("CurrentNote")
17+
_nextNote = NodePath("NextNote")
18+
19+
[node name="NoteQueueSprite" type="Sprite2D" parent="."]
20+
texture = ExtResource("2_0p21a")
21+
22+
[node name="CurrentNote" type="Sprite2D" parent="."]
23+
position = Vector2(-14, -1)
24+
texture = ExtResource("3_ewo1s")
25+
26+
[node name="NextNote" type="Sprite2D" parent="."]
27+
position = Vector2(16, -2)
28+
texture = ExtResource("4_7sgy6")

0 commit comments

Comments
 (0)