Created
June 8, 2019 17:52
-
-
Save plasma-effect/9e1f5a8e41c31005d49356d20b7ca95d to your computer and use it in GitHub Desktop.
音ゲーの譜面っぽいやつを連番pngで出力するやつ
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
2 256 | |
0 90 | |
128 360 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Collections.Generic; | |
using System.Text; | |
using System.Threading.Tasks; | |
using System.Drawing; | |
using System.IO; | |
using static System.Linq.Enumerable; | |
namespace MusicGameMovieMaker | |
{ | |
class Note : IComparable<Note> | |
{ | |
public int Time { get; } | |
public int Line { get; } | |
public Note(int time, int line) | |
{ | |
this.Time = time; | |
this.Line = line; | |
} | |
public int CompareTo(Note other) | |
{ | |
var p = this.Time.CompareTo(other.Time); | |
if (p != 0) | |
{ | |
return p; | |
} | |
return this.Line.CompareTo(other.Line); | |
} | |
} | |
static class Program | |
{ | |
const int height = 480;//画面の高さ | |
const int width = 640;//画面の幅 | |
const int noteSize = 20;//各ノーツのサイズ | |
const double distanceBase = 7.5;//HiSpeed x1.0での表示距離 | |
const int border = 20;//判定の位置 | |
const int maxDisplay = height - border;//表示される限界の位置 | |
const int horizonDistance = 75;//各列の幅 | |
const double left = width / 2 - horizonDistance * 1.5;//左端の列 | |
//C++のstd::partition_pointに似た挙動をする関数(詳しくはcpprefjpを見よ) | |
static int PartitionPoint<T>(List<T> list, Func<T, bool> pred) | |
{ | |
var min = 0; | |
var max = list.Count; | |
while (max - min > 1) | |
{ | |
var mid = (min + max) / 2; | |
if (pred(list[mid])) | |
{ | |
min = mid; | |
} | |
else | |
{ | |
max = mid; | |
} | |
} | |
return max; | |
} | |
static (int, int) ReadTuple2(TextReader reader) | |
{ | |
var ar = reader.ReadLine().Split(' ').Select(int.Parse).ToArray(); | |
return (ar[0], ar[1]); | |
} | |
//BPMのデータを読み込む | |
static List<int> ReadBPMList(string path) | |
{ | |
using (var stream = new StreamReader(path)) | |
{ | |
var (N, maxTime) = ReadTuple2(stream); | |
var ret = new List<int>(); | |
var impl = new List<(int Time, int BPM)>(); | |
foreach(var i in Range(0, N)) | |
{ | |
impl.Add(ReadTuple2(stream)); | |
} | |
impl.Add((maxTime, int.MaxValue)); | |
for (var (index, time) = (0, 0); time < maxTime; ++time) | |
{ | |
if (time == impl[index + 1].Time) | |
{ | |
++index; | |
} | |
ret.Add(impl[index].BPM); | |
} | |
return ret; | |
} | |
} | |
//32分刻みでのノーツのデータを読み込む | |
static List<Note> ReadNoteList(string path) | |
{ | |
using(var stream = new StreamReader(path)) | |
{ | |
var ret = new List<Note>(); | |
var N = int.Parse(stream.ReadLine()); | |
foreach(var i in Range(0, N)) | |
{ | |
var (time, line) = ReadTuple2(stream); | |
ret.Add(new Note(time, line)); | |
} | |
ret.Sort(); | |
return ret; | |
} | |
} | |
static void Main(string[] args) | |
{ | |
var BPMList = ReadBPMList("bpmdata.txt"); | |
var noteData = ReadNoteList("notedata.txt"); | |
var minIndex = 0; | |
var bpmIndex = 0; | |
var hispeed = 1.5; | |
var line = 0.0; | |
var (changeTime, realBPMList) = BPMCheck(BPMList); | |
minIndex = SaveImage(noteData, minIndex, hispeed, line, 0); | |
// 1.0/60秒ずつ進むことを仮定する(ほぼ誤差の範囲だが厳密には60FPSにはならないことに注意せよ) | |
const double minTime = 1.0 / 60; | |
var realTime = 0.0; | |
for (var frame = 1; minIndex < noteData.Count; ++frame) | |
{ | |
var time = minTime; | |
while (time != default) | |
{ | |
// BPMがxのときy秒で8*x*y/60回だけ32分を刻むことができる | |
line += Math.Min(changeTime[bpmIndex] - realTime, time) * realBPMList[bpmIndex] * 8 / 60; | |
time -= Math.Min(changeTime[bpmIndex] - realTime, time); | |
if (time != default) | |
{ | |
++bpmIndex; | |
} | |
} | |
realTime += minTime; | |
minIndex = SaveImage(noteData, minIndex, hispeed, line, frame); | |
} | |
} | |
static Pen Pen = new Pen(Color.Red, noteSize / 4); | |
private static int SaveImage(List<Note> noteData, int minIndex, double hispeed, double line, int index) | |
{ | |
// ノーツの中心と判定ラインの距離を返す | |
double GetPosition(Note note) | |
{ | |
return (note.Time - line) * hispeed * distanceBase; | |
} | |
var pIndex = PartitionPoint(noteData, n => GetPosition(n) < maxDisplay + noteSize); | |
using (var bitmap = new Bitmap(width, height)) | |
{ | |
using (var g = Graphics.FromImage(bitmap)) | |
{ | |
foreach (var i in Range(0, 4)) | |
{ | |
g.DrawRectangle(Pens.Red, (int)(left + (horizonDistance * i) - noteSize), border - noteSize, 2 * noteSize, 2 * noteSize); | |
} | |
for (var i = minIndex; i < pIndex; ++i) | |
{ | |
var pos = GetPosition(noteData[i]); | |
if (pos < -noteSize - border) | |
{ | |
minIndex = i + 1; | |
} | |
else | |
{ | |
var noteLine = noteData[i].Line; | |
g.FillRectangle(Brushes.Blue, (int)(left + (horizonDistance * noteLine) - noteSize), (int)(pos + border - noteSize), 2 * noteSize, 2 * noteSize); | |
g.DrawRectangle(Pen, (int)(left + (horizonDistance * noteLine) - noteSize), (int)(pos + border - noteSize), 2 * noteSize, 2 * noteSize); | |
} | |
} | |
} | |
bitmap.Save($"image/{index + 1}.png", System.Drawing.Imaging.ImageFormat.Png); | |
return minIndex; | |
} | |
} | |
// BPMが変わる時間とそれに対応するBPMのリストをセットを返す | |
private static (List<double> Change, List<int> RealBPMList) BPMCheck(List<int> BPMList) | |
{ | |
var bpmChange = new List<double>(); | |
var realBpmList = new List<int> | |
{ | |
BPMList[0] | |
}; | |
var prev = BPMList[0]; | |
var time = 60.0 / (8.0 * prev); | |
foreach (var bpm in BPMList.Skip(1)) | |
{ | |
if (bpm != prev) | |
{ | |
bpmChange.Add(time); | |
realBpmList.Add(bpm); | |
} | |
prev = bpm; | |
time += 60.0 / (8.0 * bpm); | |
} | |
bpmChange.Add(double.MaxValue); | |
return (bpmChange, realBpmList); | |
} | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
75 | |
0 0 | |
0 1 | |
6 0 | |
8 1 | |
12 2 | |
16 3 | |
17 2 | |
18 3 | |
19 2 | |
20 3 | |
22 0 | |
24 3 | |
26 0 | |
30 0 | |
32 1 | |
36 3 | |
38 1 | |
40 0 | |
43 1 | |
43 3 | |
46 1 | |
46 3 | |
48 3 | |
50 1 | |
54 0 | |
56 1 | |
64 0 | |
64 3 | |
68 2 | |
70 1 | |
72 0 | |
74 1 | |
76 2 | |
80 3 | |
81 0 | |
82 3 | |
83 0 | |
84 3 | |
86 0 | |
88 1 | |
90 2 | |
92 2 | |
92 3 | |
96 3 | |
99 2 | |
102 3 | |
105 1 | |
108 1 | |
108 3 | |
112 0 | |
115 2 | |
118 0 | |
121 1 | |
124 0 | |
124 1 | |
128 0 | |
128 3 | |
144 2 | |
152 3 | |
160 1 | |
164 0 | |
168 1 | |
176 2 | |
192 0 | |
200 1 | |
208 2 | |
212 3 | |
216 2 | |
224 0 | |
224 1 | |
232 1 | |
232 2 | |
240 0 | |
240 1 | |
256 1 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment