Advertisement
Guest User

Untitled

a guest
Jun 19th, 2019
66
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 7.26 KB | None | 0 0
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Text;
  4. using System.Threading.Tasks;
  5. using System.Drawing;
  6. using System.IO;
  7. using static System.Linq.Enumerable;
  8.  
  9. namespace MusicGameMovieMaker
  10. {
  11. class Note : IComparable<Note>
  12. {
  13. public int Time { get; }
  14. public int Line { get; }
  15.  
  16. public Note(int time, int line)
  17. {
  18. this.Time = time;
  19. this.Line = line;
  20. }
  21.  
  22. public int CompareTo(Note other)
  23. {
  24. var p = this.Time.CompareTo(other.Time);
  25. if (p != 0)
  26. {
  27. return p;
  28. }
  29. return this.Line.CompareTo(other.Line);
  30. }
  31. }
  32.  
  33. static class Program
  34. {
  35. const int height = 480;//画面の高さ
  36. const int width = 640;//画面の幅
  37. const int noteSize = 20;//各ノーツのサイズ
  38. const double distanceBase = 7.5;//HiSpeed x1.0での表示距離
  39. const int border = 20;//判定の位置
  40. const int maxDisplay = height - border;//表示される限界の位置
  41. const int horizonDistance = 75;//各列の幅
  42. const double left = width / 2 - horizonDistance * 1.5;//左端の列
  43.  
  44. //C++のstd::partition_pointに似た挙動をする関数(詳しくはcpprefjpを見よ)
  45. static int PartitionPoint<T>(List<T> list, Func<T, bool> pred)
  46. {
  47. var min = 0;
  48. var max = list.Count;
  49. while (max - min > 1)
  50. {
  51. var mid = (min + max) / 2;
  52. if (pred(list[mid]))
  53. {
  54. min = mid;
  55. }
  56. else
  57. {
  58. max = mid;
  59. }
  60. }
  61. return max;
  62. }
  63.  
  64. static (int, int) ReadTuple2(TextReader reader)
  65. {
  66. var ar = reader.ReadLine().Split(' ').Select(int.Parse).ToArray();
  67. return (ar[0], ar[1]);
  68. }
  69. //BPMのデータを読み込む
  70. static List<int> ReadBPMList(string path)
  71. {
  72. using (var stream = new StreamReader(path))
  73. {
  74. var (N, maxTime) = ReadTuple2(stream);
  75. var ret = new List<int>();
  76. var impl = new List<(int Time, int BPM)>();
  77. foreach(var i in Range(0, N))
  78. {
  79. impl.Add(ReadTuple2(stream));
  80. }
  81. impl.Add((maxTime, int.MaxValue));
  82. for (var (index, time) = (0, 0); time < maxTime; ++time)
  83. {
  84. if (time == impl[index + 1].Time)
  85. {
  86. ++index;
  87. }
  88. ret.Add(impl[index].BPM);
  89. }
  90. return ret;
  91. }
  92. }
  93. //32分刻みでのノーツのデータを読み込む
  94. static List<Note> ReadNoteList(string path)
  95. {
  96. using(var stream = new StreamReader(path))
  97. {
  98. var ret = new List<Note>();
  99. var N = int.Parse(stream.ReadLine());
  100. foreach(var i in Range(0, N))
  101. {
  102. var (time, line) = ReadTuple2(stream);
  103. ret.Add(new Note(time, line));
  104. }
  105. ret.Sort();
  106. return ret;
  107. }
  108. }
  109. static void Main(string[] args)
  110. {
  111. var BPMList = ReadBPMList("bpmdata.txt");
  112. var noteData = ReadNoteList("notedata.txt");
  113. var minIndex = 0;
  114. var bpmIndex = 0;
  115. var hispeed = 1.5;
  116. var line = 0.0;
  117. var (changeTime, realBPMList) = BPMCheck(BPMList);
  118. minIndex = SaveImage(noteData, minIndex, hispeed, line, 0);
  119. // 1.0/60秒ずつ進むことを仮定する(ほぼ誤差の範囲だが厳密には60FPSにはならないことに注意せよ)
  120. const double minTime = 1.0 / 60;
  121. var realTime = 0.0;
  122. for (var frame = 1; minIndex < noteData.Count; ++frame)
  123. {
  124. var time = minTime;
  125. while (time != default)
  126. {
  127. // BPMがxのときy秒で8*x*y/60回だけ32分を刻むことができる
  128. line += Math.Min(changeTime[bpmIndex] - realTime, time) * realBPMList[bpmIndex] * 8 / 60;
  129. time -= Math.Min(changeTime[bpmIndex] - realTime, time);
  130. if (time != default)
  131. {
  132. ++bpmIndex;
  133. }
  134. }
  135. realTime += minTime;
  136. minIndex = SaveImage(noteData, minIndex, hispeed, line, frame);
  137. }
  138. }
  139.  
  140. static Pen Pen = new Pen(Color.Red, noteSize / 4);
  141. private static int SaveImage(List<Note> noteData, int minIndex, double hispeed, double line, int index)
  142. {
  143. // ノーツの中心と判定ラインの距離を返す
  144. double GetPosition(Note note)
  145. {
  146. return (note.Time - line) * hispeed * distanceBase;
  147. }
  148. var pIndex = PartitionPoint(noteData, n => GetPosition(n) < maxDisplay + noteSize);
  149. using (var bitmap = new Bitmap(width, height))
  150. {
  151. using (var g = Graphics.FromImage(bitmap))
  152. {
  153. foreach (var i in Range(0, 4))
  154. {
  155. g.DrawRectangle(Pens.Red, (int)(left + (horizonDistance * i) - noteSize), border - noteSize, 2 * noteSize, 2 * noteSize);
  156. }
  157. for (var i = minIndex; i < pIndex; ++i)
  158. {
  159. var pos = GetPosition(noteData[i]);
  160. if (pos < -noteSize - border)
  161. {
  162. minIndex = i + 1;
  163. }
  164. else
  165. {
  166. var noteLine = noteData[i].Line;
  167. g.FillRectangle(Brushes.Blue, (int)(left + (horizonDistance * noteLine) - noteSize), (int)(pos + border - noteSize), 2 * noteSize, 2 * noteSize);
  168. g.DrawRectangle(Pen, (int)(left + (horizonDistance * noteLine) - noteSize), (int)(pos + border - noteSize), 2 * noteSize, 2 * noteSize);
  169. }
  170. }
  171. }
  172. bitmap.Save($"image/{index + 1}.png", System.Drawing.Imaging.ImageFormat.Png);
  173. return minIndex;
  174. }
  175. }
  176.  
  177. // BPMが変わる時間とそれに対応するBPMのリストをセットを返す
  178. private static (List<double> Change, List<int> RealBPMList) BPMCheck(List<int> BPMList)
  179. {
  180. var bpmChange = new List<double>();
  181. var realBpmList = new List<int>
  182. {
  183. BPMList[0]
  184. };
  185. var prev = BPMList[0];
  186. var time = 60.0 / (8.0 * prev);
  187. foreach (var bpm in BPMList.Skip(1))
  188. {
  189. if (bpm != prev)
  190. {
  191. bpmChange.Add(time);
  192. realBpmList.Add(bpm);
  193. }
  194. prev = bpm;
  195. time += 60.0 / (8.0 * bpm);
  196. }
  197. bpmChange.Add(double.MaxValue);
  198. return (bpmChange, realBpmList);
  199. }
  200. }
  201. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement