add bgm playback, scrolling based on bgm time
This commit is contained in:
@@ -0,0 +1,46 @@
|
||||
using Godot;
|
||||
using Godot.Collections;
|
||||
using System;
|
||||
|
||||
public partial class BGM : AudioStreamPlayer
|
||||
{
|
||||
public void LoadFromUser(string path)
|
||||
{
|
||||
if (!path.StartsWith("user://"))
|
||||
{
|
||||
GD.Print("Tried to load audio that isn't in user directory.");
|
||||
return;
|
||||
}
|
||||
|
||||
var f = FileAccess.Open(path, FileAccess.ModeFlags.Read);
|
||||
if (f == null)
|
||||
{
|
||||
GD.PrintErr($"Unable to open {path} for loading audio! {FileAccess.GetOpenError()}");
|
||||
return;
|
||||
}
|
||||
GD.Print("hi");
|
||||
var ext = path.Split('.')[^1].ToLower();
|
||||
switch (ext)
|
||||
{
|
||||
case "mp3":
|
||||
var mp3 = new AudioStreamMP3()
|
||||
{
|
||||
Data = f.GetBuffer((long)f.GetLength())
|
||||
};
|
||||
Stream = mp3;
|
||||
break;
|
||||
case "wav":
|
||||
case "wave":
|
||||
var wav = new AudioStreamWav()
|
||||
{
|
||||
Data = f.GetBuffer((long)f.GetLength())
|
||||
};
|
||||
Stream = wav;
|
||||
break;
|
||||
case "ogg":
|
||||
// TODO: implement
|
||||
GD.PrintErr("External OGGs not supported in Godot 4.1...");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
using Godot;
|
||||
using System;
|
||||
|
||||
public partial class SFX : Node
|
||||
{
|
||||
// Called when the node enters the scene tree for the first time.
|
||||
public override void _Ready()
|
||||
{
|
||||
}
|
||||
|
||||
// Called every frame. 'delta' is the elapsed time since the previous frame.
|
||||
public override void _Process(double delta)
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,137 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection.PortableExecutable;
|
||||
using Godot;
|
||||
using WacK.Configuration;
|
||||
using WacK.Data.Chart;
|
||||
using WacK.Data.Mer;
|
||||
using WacK.Things.TunnelObjects;
|
||||
|
||||
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;
|
||||
GD.Print($"Chart: {chartPath}\nSound: {soundPath}");
|
||||
}
|
||||
}
|
||||
public partial class Play : Node
|
||||
{
|
||||
// initialized by another scene, BEFORE loading this one!
|
||||
public static PlayParameters playParams;
|
||||
|
||||
// TunnelObjects we can instantiate
|
||||
public static PackedScene noteTouch = GD.Load<PackedScene>("res://Things/TunnelObjects/Notes/NoteTouch.tscn");
|
||||
public static PackedScene noteHold = GD.Load<PackedScene>("res://Things/TunnelObjects/Notes/NoteHold.tscn");
|
||||
public static PackedScene noteChain = GD.Load<PackedScene>("res://Things/TunnelObjects/Notes/NoteChain.tscn");
|
||||
|
||||
[ExportCategory("Audio")]
|
||||
[Export]
|
||||
private BGM bgmController;
|
||||
[Export]
|
||||
private SFX sfxController;
|
||||
|
||||
[ExportCategory("2D")]
|
||||
[ExportSubgroup("2D Things")]
|
||||
[Export]
|
||||
public Control noteDisplay;
|
||||
[Export]
|
||||
public Control scrollDisplay;
|
||||
[Export]
|
||||
public Background background;
|
||||
|
||||
[ExportSubgroup("Out-of-bounds Viewports")]
|
||||
[Export]
|
||||
public Viewport mainViewport;
|
||||
[Export]
|
||||
public Viewport leftViewport;
|
||||
[Export]
|
||||
public Viewport rightViewport;
|
||||
|
||||
private Chart chart;
|
||||
|
||||
// base scroll speed, which we can apply multipliers on
|
||||
public static readonly float BASE_PIXELS_PER_SECOND = 800;
|
||||
public static float scrollPxPerSec
|
||||
{
|
||||
get
|
||||
{
|
||||
return BASE_PIXELS_PER_SECOND * PlaySettings.playSpeedMultiplier.Value;
|
||||
}
|
||||
}
|
||||
|
||||
public override void _Ready()
|
||||
{
|
||||
// so we can see objects outside of the 0-60min. region
|
||||
leftViewport.World2D = mainViewport.World2D;
|
||||
rightViewport.World2D = mainViewport.World2D;
|
||||
|
||||
// parse mer and create chart for current play
|
||||
chart = new(playParams.chartPath);
|
||||
RealizeChart();
|
||||
|
||||
// audio setup
|
||||
bgmController.LoadFromUser(playParams.soundPath);
|
||||
bgmController.Play();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Instantiates necessary notes onto noteDisplay for the player to see.
|
||||
/// </summary>
|
||||
private void RealizeChart()
|
||||
{
|
||||
foreach (var msNote in chart.playNotes)
|
||||
{
|
||||
foreach (var note in msNote.Value)
|
||||
{
|
||||
THNotePlay nNote;
|
||||
switch (note.type)
|
||||
{
|
||||
case NotePlayType.HoldStart:
|
||||
nNote = noteHold.Instantiate<THNoteHold>();
|
||||
((THNoteHold)nNote).InitHold((NoteHold)note, scrollDisplay);
|
||||
break;
|
||||
case NotePlayType.Touch:
|
||||
nNote = noteTouch.Instantiate<THNotePlay>();
|
||||
break;
|
||||
case NotePlayType.Untimed:
|
||||
nNote = noteChain.Instantiate<THNotePlay>();
|
||||
break;
|
||||
default:
|
||||
continue;
|
||||
}
|
||||
nNote.Init(note);
|
||||
var nPos = nNote.Position;
|
||||
nPos.Y = msNote.Key * -scrollPxPerSec;
|
||||
nNote.Position = nPos;
|
||||
noteDisplay.AddChild(nNote);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override void _Process(double delta)
|
||||
{
|
||||
double time = bgmController.GetPlaybackPosition() + AudioServer.GetTimeSinceLastMix() - AudioServer.GetOutputLatency();
|
||||
|
||||
var nPos = noteDisplay.Position;
|
||||
nPos.Y = ((float)time * scrollPxPerSec) + 1920;
|
||||
noteDisplay.Position = nPos;
|
||||
scrollDisplay.Position = nPos;
|
||||
}
|
||||
|
||||
private void OnDestroy()
|
||||
{
|
||||
playParams = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user