429 lines
13 KiB
C#
429 lines
13 KiB
C#
using System;
|
||
using System.Diagnostics;
|
||
using System.Runtime.InteropServices;
|
||
using System.Text;
|
||
using NAudio.Wave;
|
||
|
||
/// <summary>
|
||
/// The <c>ModelingMusic</c> namespace contains classes and methods for modeling and manipulating musical data.
|
||
/// </summary>
|
||
namespace Debug.ModelingMusic;
|
||
|
||
public class MusicFrom
|
||
{
|
||
|
||
// 导入kernel32.dll中的SetConsoleMode函数
|
||
[DllImport("kernel32.dll", SetLastError = true)]
|
||
public static extern bool SetConsoleMode(IntPtr hConsoleHandle, uint dwMode);
|
||
|
||
// 导入kernel32.dll中的GetStdHandle函数
|
||
[DllImport("kernel32.dll", SetLastError = true)]
|
||
public static extern IntPtr GetStdHandle(int nStdHandle);
|
||
|
||
// 定义控制台模式常量
|
||
private const uint ENABLE_ECHO_INPUT = 0x0004;
|
||
private const uint ENABLE_LINE_INPUT = 0x0002;
|
||
private const uint ENABLE_PROCESSED_INPUT = 0x0001;
|
||
|
||
// 导入kernel32.dll中的GetConsoleMode函数
|
||
[DllImport("kernel32.dll", SetLastError = true)]
|
||
public static extern bool GetConsoleMode(IntPtr hConsoleHandle, out uint lpMode);
|
||
|
||
// 定义标准输入句柄
|
||
private const int STD_INPUT_HANDLE = -10;
|
||
|
||
private long time = 0;
|
||
int MaxX = 0;
|
||
int MaxY = 0;
|
||
|
||
public MusicFrom()
|
||
{
|
||
setCharArry();
|
||
MaxY = Program.chars.GetLength(0);
|
||
MaxX = Program.chars.GetLength(1);
|
||
new Thread(PrintCharArray).Start();
|
||
new Thread(KeyboardMapping).Start();
|
||
new Thread(Run).Start();
|
||
|
||
// 恢复控制台输入模式
|
||
// mode |= ENABLE_ECHO_INPUT | ENABLE_LINE_INPUT | ENABLE_PROCESSED_INPUT;
|
||
// SetConsoleMode(hStdin, mode);
|
||
|
||
}
|
||
|
||
public void Run()
|
||
{
|
||
Thread.Sleep(500);
|
||
while (Program.IsWhile)
|
||
{
|
||
// 随机数
|
||
int random = Program.random.Next(0, 7);
|
||
switch (random)
|
||
{
|
||
case 0:
|
||
DownKey('D', 3);
|
||
break;
|
||
case 1:
|
||
DownKey('F', 10);
|
||
break;
|
||
case 2:
|
||
DownKey('G', 17);
|
||
break;
|
||
case 3:
|
||
DownKey('M', 24);
|
||
break;
|
||
case 4:
|
||
DownKey('J', 31);
|
||
break;
|
||
case 5:
|
||
DownKey('K', 38);
|
||
break;
|
||
case 6:
|
||
DownKey('L', 45);
|
||
break;
|
||
default:
|
||
break;
|
||
}
|
||
Thread.Sleep(1000);
|
||
}
|
||
}
|
||
class ZIFUKEY
|
||
{
|
||
public char key;
|
||
public bool isDown;//是否被按下
|
||
}
|
||
public void DownKey(char key, int x)
|
||
{
|
||
new Thread(() =>
|
||
{
|
||
var zIFUKEY = new ZIFUKEY() { key = key, isDown = false };
|
||
for (int i = 0; i < MaxY; i++)
|
||
{
|
||
Program.chars[i, x].Char = zIFUKEY.key;
|
||
Thread.Sleep(260);
|
||
Program.chars[i, x].Char = ' ';
|
||
if (zIFUKEY.isDown)
|
||
{
|
||
break;
|
||
}
|
||
}
|
||
}).Start();
|
||
}
|
||
|
||
readonly char[] jianpan = ['D', 'F', 'G', ' ', 'J', 'K', 'L'];
|
||
public void PrintCharArray()
|
||
{
|
||
|
||
// 获取标准输入句柄
|
||
IntPtr hStdin = GetStdHandle(STD_INPUT_HANDLE);
|
||
|
||
// 获取当前控制台输入模式
|
||
uint mode;
|
||
if (!GetConsoleMode(hStdin, out mode))
|
||
{
|
||
Console.WriteLine("无法获取控制台输入模式");
|
||
return;
|
||
}
|
||
|
||
// 禁用回显和行输入
|
||
mode &= ~(ENABLE_ECHO_INPUT | ENABLE_LINE_INPUT | ENABLE_PROCESSED_INPUT);
|
||
if (!SetConsoleMode(hStdin, mode))
|
||
{
|
||
Console.WriteLine("无法设置控制台输入模式");
|
||
return;
|
||
}
|
||
var stopwatch = new Stopwatch();
|
||
int frameCount = 0;
|
||
double totalTime = 0;
|
||
int i; int j;
|
||
// 获取字符数组的行数和列数
|
||
var a = Program.chars.GetLength(0);
|
||
var b = Program.chars.GetLength(1);
|
||
var buffer = new StringBuilder();
|
||
while (Program.IsWhile)
|
||
{
|
||
stopwatch.Restart();
|
||
Console.SetCursorPosition(0, 0);// 设定光标位置
|
||
Console.Clear();
|
||
buffer.Clear();
|
||
for (i = 0; i < a; i++)
|
||
{
|
||
for (j = 0; j < b; j++)
|
||
{
|
||
buffer.Append(Program.chars[i, j].Char);
|
||
time++;
|
||
if (time > 100000)
|
||
{
|
||
GC.Collect(); time = 0;
|
||
}
|
||
}
|
||
buffer.AppendLine();
|
||
}
|
||
Console.ForegroundColor = ConsoleColor.DarkBlue;
|
||
Console.Write(buffer.ToString());
|
||
buffer.Clear();
|
||
for (i = 0; i < b; i++)
|
||
{
|
||
buffer.Append('-');
|
||
}
|
||
// 打印ASDF HJKL
|
||
buffer.AppendLine();
|
||
Console.Write(buffer);
|
||
buffer.Clear();
|
||
// int totalLength = 50;
|
||
int totalAs = jianpan.Length;
|
||
int spaceBetweenAs = (b - totalAs) / (totalAs - 1);
|
||
|
||
for (i = 0; i < totalAs; i++)
|
||
{
|
||
buffer.Clear();
|
||
// if (isDown[3] && i == 3)
|
||
// {
|
||
// // 显示空格键
|
||
// // ConsoleKey.Spacebar
|
||
// buffer.Append("Spacebar");
|
||
// continue;
|
||
// }
|
||
for (j = 0; j < spaceBetweenAs / 2; j++)
|
||
{
|
||
buffer.Append(' ');
|
||
}
|
||
|
||
buffer.Append(jianpan[i]);
|
||
if (isDown[i])
|
||
{
|
||
Console.ForegroundColor = ConsoleColor.Red; // 设置颜色为红色
|
||
}
|
||
else
|
||
{
|
||
Console.ForegroundColor = ConsoleColor.Blue; // 设置颜色为白色
|
||
}
|
||
for (j = 0; j < spaceBetweenAs / 2; j++)
|
||
{
|
||
buffer.Append(' ');
|
||
}
|
||
Console.Write(buffer);
|
||
}
|
||
|
||
// 停止计时并计算本帧的处理时间
|
||
stopwatch.Stop();
|
||
double elapsedMilliseconds = stopwatch.Elapsed.TotalMilliseconds;
|
||
totalTime += elapsedMilliseconds;
|
||
frameCount++;
|
||
// 计算帧率
|
||
double fps = frameCount / (totalTime / 1000.0);
|
||
// Console.ResetColor();
|
||
Console.ForegroundColor = ConsoleColor.White;
|
||
buffer.Clear();
|
||
buffer.Append($" {fps:0} FPS ");
|
||
Console.WriteLine(buffer);
|
||
buffer.Clear();
|
||
buffer.Append($" {score.ToString("D10")} ");
|
||
Console.SetCursorPosition(49, 0);
|
||
Console.Write(buffer);
|
||
// 保持每秒约16.67ms(即大约60 FPS)的间隔
|
||
// Thread.Sleep(Math.Max(0, 60 - (int)elapsedMilliseconds));
|
||
//这样闪烁不会太严重
|
||
Thread.Sleep(50);
|
||
}
|
||
// 恢复控制台输入模式
|
||
mode |= ENABLE_ECHO_INPUT | ENABLE_LINE_INPUT | ENABLE_PROCESSED_INPUT;
|
||
SetConsoleMode(hStdin, mode);
|
||
}
|
||
private void setCharArry()
|
||
{
|
||
for (int i = 0; i < Program.chars.GetLength(0); i++)
|
||
{
|
||
for (int j = 0; j < Program.chars.GetLength(1); j++)
|
||
{
|
||
Program.chars[i, j] = new Point(); // 初始化每个元素
|
||
}
|
||
}
|
||
}
|
||
//分数long 000000000
|
||
private long score = 0;
|
||
readonly bool[] isDown = new bool[7];
|
||
// 导入user32.dll中的GetAsyncKeyState函数
|
||
[DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true)]
|
||
public static extern short GetAsyncKeyState(int vkey);
|
||
// 定义虚拟键码
|
||
const int VK_D = 0x44; // D键
|
||
const int VK_F = 0x46; // F键
|
||
const int VK_G = 0x47; // G键
|
||
const int VK_J = 0x4A; // J键
|
||
const int VK_K = 0x4B; // K键
|
||
const int VK_L = 0x4C; // L键
|
||
const int VK_SPACE = 0x20; // 空格键
|
||
const int VK_ENTER = 0x0D; // Enter键
|
||
const int VK_ESCAPE = 0x1B; // ESC键
|
||
/// <summary>
|
||
/// 键盘监听方法
|
||
/// </summary>
|
||
public void KeyboardMapping()
|
||
{
|
||
|
||
// 创建一个字典来跟踪每个按键的前一次状态
|
||
var keyStates = new Dictionary<int, bool>
|
||
{
|
||
{ VK_D, false },
|
||
{ VK_F, false },
|
||
{ VK_G, false },
|
||
{ VK_J, false },
|
||
{ VK_K, false },
|
||
{ VK_L, false },
|
||
{ VK_SPACE, false },
|
||
{ VK_ENTER, false },
|
||
{ VK_ESCAPE, false }
|
||
};
|
||
|
||
while (true)
|
||
{
|
||
// ConsoleKeyInfo keyInfo = Console.ReadKey(true); // true表示不显示输入的字符
|
||
// 检查并处理所有监控的按键状态变化
|
||
foreach (var kvp in keyStates)
|
||
{
|
||
int vkey = kvp.Key;
|
||
bool wasPressed = kvp.Value;
|
||
|
||
// 检查当前按键的状态
|
||
short keyState = GetAsyncKeyState(vkey);
|
||
bool isKeyPressed = (keyState & 0x8000) != 0;
|
||
|
||
if (isKeyPressed && !wasPressed)
|
||
{
|
||
// 按下时触发
|
||
HandleKeyPress(vkey);
|
||
}
|
||
else if (!isKeyPressed && wasPressed)
|
||
{
|
||
// 松开时触发
|
||
HandleKeyRelease(vkey);
|
||
}
|
||
|
||
// 更新按键状态
|
||
keyStates[vkey] = isKeyPressed;
|
||
}
|
||
// 避免CPU占用过高
|
||
Thread.Sleep(50);
|
||
}
|
||
}
|
||
|
||
|
||
|
||
void HandleKeyPress(int vkey)
|
||
{
|
||
switch (vkey)
|
||
{
|
||
case VK_ESCAPE:
|
||
if (Program.IsWhile)
|
||
{
|
||
Program.IsWhile = false;
|
||
Console.SetCursorPosition(60, 5);
|
||
Console.Write("暂停状态 再次按下ESC退出游戏/按回车键继续");
|
||
}
|
||
else
|
||
{
|
||
Console.Clear();
|
||
Environment.Exit(0);
|
||
}
|
||
// 处理ESC键被按下的逻辑
|
||
break;
|
||
case VK_ENTER:
|
||
if (!Program.IsWhile)
|
||
{
|
||
|
||
Program.IsWhile = true;
|
||
new Thread(PrintCharArray).Start();
|
||
}
|
||
// 处理Enter键被按下的逻辑
|
||
break;
|
||
case VK_D:
|
||
isDown[0] = true;
|
||
// 处理D键被按下的逻辑
|
||
if (Program.chars[8, 3].Char == 'D' || Program.chars[9, 3].Char == 'D')
|
||
{
|
||
score += 100;
|
||
}
|
||
break;
|
||
case VK_F:
|
||
isDown[1] = true;
|
||
// 处理F键被按下的逻辑
|
||
if (Program.chars[8, 10].Char == 'F' || Program.chars[9, 10].Char == 'F')
|
||
{
|
||
score += 100;
|
||
}
|
||
break;
|
||
case VK_G:
|
||
isDown[2] = true;
|
||
// 处理G键被按下的逻辑
|
||
if (Program.chars[8, 17].Char == 'G' || Program.chars[9, 17].Char == 'G')
|
||
{
|
||
score += 100;
|
||
}
|
||
break;
|
||
case VK_SPACE:
|
||
isDown[3] = true;
|
||
// 处理空格键被按下的逻辑
|
||
break;
|
||
case VK_J:
|
||
isDown[4] = true;
|
||
// 处理J键被按下的逻辑
|
||
if (Program.chars[8, 31].Char == 'J' || Program.chars[9, 31].Char == 'J')
|
||
{
|
||
score += 100;
|
||
}
|
||
break;
|
||
case VK_K:
|
||
isDown[5] = true;
|
||
// 处理K键被按下的逻辑
|
||
if (Program.chars[8, 38].Char == 'K' || Program.chars[9, 38].Char == 'K')
|
||
{
|
||
score += 100;
|
||
}
|
||
break;
|
||
case VK_L:
|
||
isDown[6] = true;
|
||
// 处理L键被按下的逻辑
|
||
if (Program.chars[8, 45].Char == 'L' || Program.chars[9, 45].Char == 'L')
|
||
{
|
||
score += 100;
|
||
}
|
||
break;
|
||
}
|
||
}
|
||
|
||
void HandleKeyRelease(int vkey)
|
||
{
|
||
switch (vkey)
|
||
{
|
||
case VK_D:
|
||
isDown[0] = false;
|
||
// 处理D键被释放的逻辑
|
||
break;
|
||
case VK_F:
|
||
isDown[1] = false;
|
||
// 处理F键被释放的逻辑
|
||
break;
|
||
case VK_G:
|
||
isDown[2] = false;
|
||
// 处理G键被释放的逻辑
|
||
break;
|
||
case VK_SPACE:
|
||
isDown[3] = false;
|
||
// 处理空格键被释放的逻辑
|
||
break;
|
||
case VK_J:
|
||
isDown[4] = false;
|
||
// 处理J键被释放的逻辑
|
||
break;
|
||
case VK_K:
|
||
isDown[5] = false;
|
||
// 处理K键被释放的逻辑
|
||
break;
|
||
case VK_L:
|
||
isDown[6] = false;
|
||
// 处理L键被释放的逻辑
|
||
break;
|
||
}
|
||
}
|
||
} |