feat(engine): 重构游戏引擎核心逻辑
- 重新设计了引擎的初始化和运行流程 - 引入了实体组件系统(ECS)和物理系统 - 优化了渲染系统和输入系统 - 移除了不必要的资源管理系统 - 调整了日志系统的实现
This commit is contained in:
10
game_core/plantform/win_app/win_interface.h
Normal file
10
game_core/plantform/win_app/win_interface.h
Normal file
@@ -0,0 +1,10 @@
|
||||
#ifndef __WIN_INTERFACE_H__
|
||||
#define __WIN_INTERFACE_H__
|
||||
|
||||
#include <ge_common.h>
|
||||
|
||||
|
||||
void win_sleep_us(ge_u32_t us);
|
||||
ge_u32_t win_get_us(void);
|
||||
|
||||
#endif // __WIN_INTERFACE_H__
|
||||
293
game_core/plantform/win_app/win_main.c
Normal file
293
game_core/plantform/win_app/win_main.c
Normal file
@@ -0,0 +1,293 @@
|
||||
#include <windows.h>
|
||||
#include "win_interface.h"
|
||||
#include <ge_core.h>
|
||||
|
||||
|
||||
// 自定义渲染上下文结构体(包含双缓冲资源)
|
||||
typedef struct {
|
||||
HWND hwnd; // 窗口句柄
|
||||
HDC hdc_front; // 前台设备上下文
|
||||
HDC hdc_back; // 后台缓冲区设备上下文
|
||||
HBITMAP hbm_back; // 后台位图
|
||||
HBITMAP hbm_old; // 保存原始位图(用于恢复)
|
||||
RECT client_rect; // 窗口客户区大小
|
||||
} win_render_context_t;
|
||||
|
||||
// 双缓冲初始化函数
|
||||
static void win_render_init(ge_render_t* ctx, const ge_render_pos2_t* init_screen_size) {
|
||||
(void) init_screen_size;
|
||||
win_render_context_t* wctx = (win_render_context_t*)ctx->context;
|
||||
HDC hdc = GetDC(wctx->hwnd);
|
||||
|
||||
// 获取窗口尺寸
|
||||
GetClientRect(wctx->hwnd, &wctx->client_rect);
|
||||
int width = wctx->client_rect.right - wctx->client_rect.left;
|
||||
int height = wctx->client_rect.bottom - wctx->client_rect.top;
|
||||
|
||||
// 创建双缓冲资源
|
||||
wctx->hdc_front = hdc;
|
||||
wctx->hdc_back = CreateCompatibleDC(hdc);
|
||||
wctx->hbm_back = CreateCompatibleBitmap(hdc, width, height);
|
||||
wctx->hbm_old = (HBITMAP)SelectObject(wctx->hdc_back, wctx->hbm_back);
|
||||
|
||||
// 保存屏幕尺寸到渲染上下文
|
||||
ctx->screen_size.x = width;
|
||||
ctx->screen_size.y = height;
|
||||
}
|
||||
|
||||
// 清空后台缓冲区
|
||||
static void win_render_draw_rect(ge_render_t* ctx, const ge_render_rect_t* rect, ge_render_color_t color) {
|
||||
win_render_context_t* wctx = (win_render_context_t*)ctx->context;
|
||||
RECT win_rect = {
|
||||
.top = rect->pos.y,
|
||||
.bottom = rect->pos.y + rect->size.y,
|
||||
.left = rect->pos.x,
|
||||
.right = rect->pos.x + rect->size.x,
|
||||
};
|
||||
win_rect.bottom *= 4;
|
||||
win_rect.right *= 4;
|
||||
win_rect.left *= 4;
|
||||
win_rect.top *= 4;
|
||||
HBRUSH brush = CreateSolidBrush(color); // WHITE background
|
||||
|
||||
FillRect(wctx->hdc_back, &win_rect, brush);
|
||||
DeleteObject(brush);
|
||||
}
|
||||
|
||||
// 将后台缓冲区复制到屏幕(双缓冲交换)
|
||||
static void win_render_flush(ge_render_t* ctx) {
|
||||
win_render_context_t* wctx = (win_render_context_t*)ctx->context;
|
||||
BitBlt(wctx->hdc_front,
|
||||
0, 0,
|
||||
wctx->client_rect.right,
|
||||
wctx->client_rect.bottom,
|
||||
wctx->hdc_back,
|
||||
0, 0,
|
||||
SRCCOPY);
|
||||
}
|
||||
|
||||
static void win_render_draw_text(ge_render_t* ctx, const ge_render_pos2_t* pos, const char* text) {
|
||||
win_render_context_t* wctx = (win_render_context_t*)ctx->context;
|
||||
// 使用GDI函数在 wctx->hdc_back 上绘制
|
||||
TextOut(wctx->hdc_back, pos->x, pos->y, text, strlen(text));
|
||||
}
|
||||
|
||||
// 键盘事件处理函数(将按键转换为字符)
|
||||
static char win_key_to_char(WPARAM wParam, LPARAM lParam) {
|
||||
BYTE keyboardState[256] = {0};
|
||||
WORD charBuffer = 0;
|
||||
|
||||
// 获取当前键盘状态
|
||||
GetKeyboardState(keyboardState);
|
||||
|
||||
// 将虚拟键码转换为ASCII字符
|
||||
if (ToAscii((UINT)wParam, (UINT)((lParam >> 16) & 0xFF),
|
||||
keyboardState, &charBuffer, 0) > 0) {
|
||||
// // 只返回可打印字符(ASCII 32-126)
|
||||
// if (charBuffer >= 32 && charBuffer <= 126) {
|
||||
return (char)charBuffer;
|
||||
// }
|
||||
}
|
||||
return 0; // 不可打印字符或转换失败
|
||||
}
|
||||
|
||||
// 窗口过程函数
|
||||
LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
|
||||
ge_core_t* core = (ge_core_t*)GetWindowLongPtr(hwnd, GWLP_USERDATA);
|
||||
|
||||
switch (uMsg) {
|
||||
case WM_KEYDOWN:
|
||||
if (!core) {
|
||||
goto END;
|
||||
}
|
||||
|
||||
// 将按键转换为字符
|
||||
char ch = win_key_to_char(wParam, lParam);
|
||||
ge_input_event_t event;
|
||||
if (ch != 0) {
|
||||
// 将字符放入事件缓冲区
|
||||
event.num = ch;
|
||||
core->_input.func_send(&core->_input, event);
|
||||
}
|
||||
|
||||
return 0;
|
||||
case WM_DESTROY:
|
||||
PostQuitMessage(0);
|
||||
core->state = GE_ENGINE_STATE_EXIT;
|
||||
return 0;
|
||||
default:
|
||||
END:
|
||||
return DefWindowProc(hwnd, uMsg, wParam, lParam);
|
||||
}
|
||||
}
|
||||
|
||||
static void win_render_getsize(ge_render_t* ctx, ge_vector2i_t* size) {
|
||||
win_render_context_t* wctx = (win_render_context_t*)ctx->context;
|
||||
|
||||
GetClientRect(wctx->hwnd, &wctx->client_rect);
|
||||
ctx->screen_size.x = wctx->client_rect.right - wctx->client_rect.left;
|
||||
ctx->screen_size.y = wctx->client_rect.bottom - wctx->client_rect.top;
|
||||
|
||||
size->x = ctx->screen_size.x;
|
||||
size->x = ctx->screen_size.y;
|
||||
}
|
||||
|
||||
// Windows计时函数
|
||||
static ge_u32_t win_get_ms(void* ctx) {
|
||||
return GetTickCount();
|
||||
}
|
||||
|
||||
static void win_sleep_ms(void* ctx, ge_u32_t ms) {
|
||||
Sleep(ms);
|
||||
}
|
||||
|
||||
static void win_run_at_frame(ge_core_t* core) {
|
||||
static MSG msg;
|
||||
const win_render_context_t* xctx = (win_render_context_t*)core->_inner_context;
|
||||
|
||||
while (PeekMessage(&msg, xctx->hwnd, 0, 0, 0)) {
|
||||
GetMessage(&msg, NULL, 0, 0);
|
||||
TranslateMessage(&msg);
|
||||
DispatchMessage(&msg);
|
||||
}
|
||||
}
|
||||
|
||||
static void win_render_drawex(ge_render_t* ctx, ge_vector2i_t pos, const char* data, const void* propety) {
|
||||
|
||||
win_render_context_t* wctx = (win_render_context_t*)ctx->context;
|
||||
|
||||
// 将 data 转换为 HBITMAP (假设传入的是位图句柄)
|
||||
HBITMAP hBitmap = (HBITMAP)data;
|
||||
|
||||
// 创建兼容的内存设备上下文
|
||||
HDC hdcMem = CreateCompatibleDC(wctx->hdc_back);
|
||||
|
||||
// 将位图选入内存设备上下文
|
||||
HBITMAP hOldBitmap = (HBITMAP)SelectObject(hdcMem, hBitmap);
|
||||
|
||||
// 获取位图尺寸
|
||||
BITMAP bitmap;
|
||||
GetObject(hBitmap, sizeof(BITMAP), &bitmap);
|
||||
|
||||
// 绘制位图到后台缓冲区
|
||||
BitBlt(
|
||||
wctx->hdc_back, // 目标设备上下文
|
||||
pos.x, // 目标左上角X
|
||||
pos.y, // 目标左上角Y
|
||||
bitmap.bmWidth, // 位图宽度
|
||||
bitmap.bmHeight, // 位图高度
|
||||
hdcMem, // 源设备上下文
|
||||
0, // 源左上角X
|
||||
0, // 源左上角Y
|
||||
SRCCOPY // 光栅操作码
|
||||
);
|
||||
|
||||
// 清理资源
|
||||
SelectObject(hdcMem, hOldBitmap);
|
||||
DeleteDC(hdcMem);
|
||||
}
|
||||
|
||||
// 主游戏逻辑函数
|
||||
int ge_main(ge_core_t* core);
|
||||
DECLARE_GE_KFIFO(ge_input_fifo, ge_input_event_t, 16, ge_input_fifo_t);
|
||||
|
||||
static int ge_input_send (ge_input_t* ctx, ge_input_event_t event) {
|
||||
struct ge_input_fifo_t* fifo = (struct ge_input_fifo_t*)ctx->context;
|
||||
if (ge_kfifo_is_full(fifo)) {
|
||||
return -1;
|
||||
}
|
||||
ge_kfifo_put(fifo, event);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ge_input_peek (ge_input_t* ctx, ge_input_event_t* event) {
|
||||
struct ge_input_fifo_t* fifo = (struct ge_input_fifo_t*)ctx->context;
|
||||
if (ge_kfifo_is_empty(fifo)) {
|
||||
return -1;
|
||||
}
|
||||
ge_kfifo_peek(fifo, event);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ge_input_recv (ge_input_t* ctx, ge_input_event_t* event) {
|
||||
struct ge_input_fifo_t* fifo = (struct ge_input_fifo_t*)ctx->context;
|
||||
if (ge_kfifo_is_empty(fifo)) {
|
||||
return -1;
|
||||
}
|
||||
ge_kfifo_get(fifo, event);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Windows入口点
|
||||
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {
|
||||
(void) hPrevInstance;
|
||||
(void) lpCmdLine;
|
||||
// 创建窗口
|
||||
wchar_t CLASS_NAME[] = L"GameWindow";
|
||||
|
||||
WNDCLASS wc = {0};
|
||||
wc.lpfnWndProc = WindowProc;
|
||||
wc.hInstance = hInstance;
|
||||
wc.lpszClassName = CLASS_NAME;
|
||||
|
||||
RegisterClass(&wc);
|
||||
|
||||
HWND hwnd = CreateWindowEx(
|
||||
0,
|
||||
CLASS_NAME,
|
||||
"Game Engine",
|
||||
WS_OVERLAPPEDWINDOW,
|
||||
CW_USEDEFAULT, CW_USEDEFAULT, 128 * 4, 128 * 4,
|
||||
NULL, NULL, hInstance, NULL
|
||||
);
|
||||
|
||||
if (hwnd == NULL) return 0;
|
||||
|
||||
// 初始化引擎核心
|
||||
static ge_core_t core;
|
||||
ge_engine_init(&core);
|
||||
|
||||
// 创建双缓冲上下文
|
||||
win_render_context_t* wctx = (win_render_context_t*)malloc(sizeof(win_render_context_t));
|
||||
wctx->hwnd = hwnd;
|
||||
|
||||
// 配置渲染器
|
||||
core._render.context = wctx;
|
||||
core._render.init_func = (ge_render_init_func_t)win_render_init;
|
||||
core._render.func_flush = (ge_render_flush_func_t)win_render_flush;
|
||||
core._render.func_draw_text = (ge_render_draw_text_func_t)win_render_draw_text;
|
||||
core._render.func_draw_rect = (ge_render_draw_rect_func_t)win_render_draw_rect;
|
||||
|
||||
// // 初始化渲染器
|
||||
// if (core->render.init) core->render.init(&core->render);
|
||||
|
||||
// 配置计时器
|
||||
core._timer.func_getms = (ge_timer_getms_func_t)win_get_ms;
|
||||
core._timer.func_sleepms = (ge_timer_sleepms_func_t)win_sleep_ms;
|
||||
|
||||
core._inner_run = win_run_at_frame;
|
||||
core._inner_context = wctx;
|
||||
|
||||
INIT_GE_KFIFO(&ge_input_fifo);
|
||||
core._input.context = &ge_input_fifo;
|
||||
core._input.func_send = ge_input_send;
|
||||
core._input.func_peek = ge_input_peek;
|
||||
core._input.func_recv = ge_input_recv;
|
||||
|
||||
// 将core指针关联到窗口
|
||||
SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)&core);
|
||||
|
||||
ShowWindow(hwnd, nCmdShow);
|
||||
UpdateWindow(hwnd);
|
||||
// 运行主游戏逻辑
|
||||
ge_main(&core);
|
||||
|
||||
// 清理资源
|
||||
SelectObject(wctx->hdc_back, wctx->hbm_old);
|
||||
DeleteObject(wctx->hbm_back);
|
||||
DeleteDC(wctx->hdc_back);
|
||||
ReleaseDC(hwnd, wctx->hdc_front);
|
||||
free(wctx);
|
||||
|
||||
return 0;
|
||||
}
|
||||
31
game_core/plantform/win_app/win_timer.c
Normal file
31
game_core/plantform/win_app/win_timer.c
Normal file
@@ -0,0 +1,31 @@
|
||||
#include <windows.h>
|
||||
#include <ge_common.h>
|
||||
|
||||
// 获取当前时间(微秒)
|
||||
ge_u32_t win_get_us(void) {
|
||||
static LARGE_INTEGER frequency;
|
||||
static BOOL initialized = FALSE;
|
||||
|
||||
if (!initialized) {
|
||||
QueryPerformanceFrequency(&frequency);
|
||||
initialized = TRUE;
|
||||
}
|
||||
|
||||
LARGE_INTEGER counter;
|
||||
QueryPerformanceCounter(&counter);
|
||||
return (ge_u32_t)((counter.QuadPart * 1000000) / frequency.QuadPart);
|
||||
}
|
||||
|
||||
// 微秒级休眠
|
||||
void win_sleep_us(ge_u32_t us) {
|
||||
if (us < 1000) {
|
||||
// 短时间使用忙等待
|
||||
ge_u32_t start = win_get_us();
|
||||
while ((win_get_us() - start) < us) {
|
||||
// 空循环
|
||||
}
|
||||
} else {
|
||||
// 长时间使用Sleep
|
||||
Sleep(us / 1000);
|
||||
}
|
||||
}
|
||||
@@ -11,8 +11,8 @@ static inline void register_win_term(ge_core_t* core);
|
||||
void win_sleep_ms(uint32_t ms);
|
||||
uint32_t win_get_timer_ms();
|
||||
static inline void register_win_timer(ge_core_t* core) {
|
||||
core->timer.sleep_ms = (ge_sleep_ms_func_t)win_sleep_ms;
|
||||
core->timer.get_ms = (ge_get_ms_func_t)win_get_timer_ms;
|
||||
core->_timer.sleep_ms = (ge_sleep_ms_func_t)win_sleep_ms;
|
||||
core->_timer.get_ms = (ge_get_ms_func_t)win_get_timer_ms;
|
||||
}
|
||||
|
||||
static void win_render_draw(ge_render_t* ctx, ge_vector2i_t pos, const char* data) {
|
||||
@@ -44,7 +44,7 @@ static void win_render_draw(ge_render_t* ctx, ge_vector2i_t pos, const char* dat
|
||||
}
|
||||
|
||||
// 普通字符处理
|
||||
char char_str[2] = { *ptr, '\0' };
|
||||
char char_str[2] = { *ptr };
|
||||
terminal_print(term, current_x, current_y, char_str);
|
||||
|
||||
current_x++;
|
||||
@@ -61,14 +61,19 @@ static void win_render_getsize(ge_render_t* ctx, ge_vector2i_t* size) {
|
||||
size->x = terminal_get_width((win_term_t*)ctx->content);
|
||||
}
|
||||
|
||||
static void win_render_flush(ge_render_t* ctx) {
|
||||
terminal_flush((win_term_t*)ctx->content);
|
||||
}
|
||||
|
||||
static inline void register_win_term(ge_core_t* core) {
|
||||
win_term_t* ctx = terminal_init();
|
||||
Assert(ctx != NULL);
|
||||
core->render.content = ctx;
|
||||
core->render.init = NULL;
|
||||
core->render.draw = win_render_draw;
|
||||
core->render.clear = win_render_clear;
|
||||
core->render.getsize = win_render_getsize;
|
||||
core->_render.content = ctx;
|
||||
core->_render.init = NULL;
|
||||
core->_render.draw = win_render_draw;
|
||||
core->_render.clear = win_render_clear;
|
||||
core->_render.getsize = win_render_getsize;
|
||||
core->_render.flush = win_render_flush;
|
||||
}
|
||||
|
||||
#endif // __WIN_TERM_INTERFACE_H__
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <windows.h>
|
||||
#include <pynic_log/pynic_log.h>
|
||||
#include "win_term.h"
|
||||
|
||||
// 终端抽象结构体
|
||||
@@ -9,35 +10,108 @@ struct win_term {
|
||||
HANDLE hStdout;
|
||||
HANDLE hStdin;
|
||||
CONSOLE_SCREEN_BUFFER_INFO csbi;
|
||||
int width;
|
||||
int height;
|
||||
char buffer[120 * 30 + 120 * 30];
|
||||
};
|
||||
|
||||
#define ESC "\x1b"
|
||||
#define CSI "\x1b["
|
||||
|
||||
// 初始化终端
|
||||
win_term_t* terminal_init() {
|
||||
win_term_t* term = malloc(sizeof(win_term_t));
|
||||
Assert(term != NULL);
|
||||
|
||||
term->hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
|
||||
term->hStdin = GetStdHandle(STD_INPUT_HANDLE);
|
||||
|
||||
|
||||
// Using UTF-8
|
||||
SetConsoleOutputCP(65001);
|
||||
SetConsoleCP(65001);
|
||||
|
||||
// 保存初始控制台信息
|
||||
GetConsoleScreenBufferInfo(term->hStdout, &term->csbi);
|
||||
|
||||
// 设置输入模式(禁用行缓冲)
|
||||
DWORD mode = 0;
|
||||
GetConsoleMode(term->hStdin, &mode);
|
||||
SetConsoleMode(term->hStdin, mode & ~(ENABLE_LINE_INPUT | ENABLE_ECHO_INPUT));
|
||||
|
||||
// 关闭光标(游标)
|
||||
CONSOLE_CURSOR_INFO cursorInfo;
|
||||
GetConsoleCursorInfo(term->hStdout, &cursorInfo);
|
||||
cursorInfo.bVisible = FALSE; // 设置为 FALSE 隐藏光标
|
||||
SetConsoleCursorInfo(term->hStdout, &cursorInfo);
|
||||
// https://learn.microsoft.com/zh-cn/windows/console/console-virtual-terminal-sequences
|
||||
// Set output mode to handle virtual terminal sequences
|
||||
HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE);
|
||||
if (hOut == INVALID_HANDLE_VALUE) {
|
||||
return NULL;
|
||||
}
|
||||
HANDLE hIn = GetStdHandle(STD_INPUT_HANDLE);
|
||||
if (hIn == INVALID_HANDLE_VALUE) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
system("cls");
|
||||
DWORD dwOriginalOutMode = 0;
|
||||
DWORD dwOriginalInMode = 0;
|
||||
if (!GetConsoleMode(hOut, &dwOriginalOutMode)) {
|
||||
return NULL;
|
||||
}
|
||||
if (!GetConsoleMode(hIn, &dwOriginalInMode)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
DWORD dwRequestedOutModes = ENABLE_VIRTUAL_TERMINAL_PROCESSING | DISABLE_NEWLINE_AUTO_RETURN;
|
||||
DWORD dwRequestedInModes = ENABLE_VIRTUAL_TERMINAL_INPUT;
|
||||
|
||||
DWORD dwOutMode = dwOriginalOutMode | dwRequestedOutModes;
|
||||
if (!SetConsoleMode(hOut, dwOutMode)) {
|
||||
// we failed to set both modes, try to step down mode gracefully.
|
||||
dwRequestedOutModes = ENABLE_VIRTUAL_TERMINAL_PROCESSING;
|
||||
dwOutMode = dwOriginalOutMode | dwRequestedOutModes;
|
||||
if (!SetConsoleMode(hOut, dwOutMode)) {
|
||||
// Failed to set any VT mode, can't do anything here.
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
DWORD dwInMode = dwOriginalInMode | dwRequestedInModes;
|
||||
if (!SetConsoleMode(hIn, dwInMode)) {
|
||||
// Failed to set VT input mode, can't do anything here.
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// disable cursor
|
||||
printf(CSI"?25l");
|
||||
term->height = terminal_get_height(term);
|
||||
term->width = terminal_get_width(term);
|
||||
terminal_clean(term);
|
||||
terminal_flush(term);
|
||||
return term;
|
||||
}
|
||||
|
||||
void terminal_flush(win_term_t* term) {
|
||||
// ESC[nJ
|
||||
// printf(CSI"2J");
|
||||
// for (int i = 0; i < term->height; i++) {
|
||||
// // ESC[x;yH 设置光标位置 x 行 y 列
|
||||
// // WriteConsole(term->hStdout, term->buffer + ((term->width + 1) * i), term->width, NULL, NULL);
|
||||
// WriteFile(term->hStdout, term->buffer + ((term->width + 1) * i), term->width - 1, NULL, NULL);
|
||||
// }
|
||||
printf(CSI"0;0H%s", term->buffer);
|
||||
// fflush(stdout);
|
||||
}
|
||||
|
||||
int terminal_clean(win_term_t* term) {
|
||||
// printf(CSI"2J");
|
||||
memset(term->buffer, ' ', sizeof(term->buffer));
|
||||
for (int i = 1; i <= term->height; i++) {
|
||||
term->buffer[i * term->width] = '\n';
|
||||
}
|
||||
term->buffer[term->width * term->height] = '\0';
|
||||
return 0;
|
||||
}
|
||||
|
||||
// 打印文本(带位置和颜色)
|
||||
void terminal_print(win_term_t* term, int x, int y, const char* text) {
|
||||
// terminal_set_cursor(term, x, y);
|
||||
// printf(CSI"%d;%dH%s", y, x, text);
|
||||
while (*text) {
|
||||
*((term->buffer) + ((term->width + 1) * y) + x) = *text;
|
||||
x++;
|
||||
text++;
|
||||
}
|
||||
}
|
||||
|
||||
// 清理终端
|
||||
void terminal_cleanup(win_term_t* term) {
|
||||
// 恢复初始属性
|
||||
@@ -45,19 +119,6 @@ void terminal_cleanup(win_term_t* term) {
|
||||
free(term);
|
||||
}
|
||||
|
||||
// 设置光标位置
|
||||
static inline void terminal_set_cursor(win_term_t* term, int x, int y) {
|
||||
COORD coord = { x, y };
|
||||
SetConsoleCursorPosition(term->hStdout, coord);
|
||||
}
|
||||
|
||||
// 打印文本(带位置和颜色)
|
||||
void terminal_print(win_term_t* term, int x, int y, const char* text) {
|
||||
terminal_set_cursor(term, x, y);
|
||||
printf("%s", text);
|
||||
fflush(stdout);
|
||||
}
|
||||
|
||||
// 获取按键事件
|
||||
int terminal_get_key(win_term_t* term) {
|
||||
INPUT_RECORD ir;
|
||||
@@ -86,60 +147,6 @@ int terminal_get_height(win_term_t* term) {
|
||||
return term->csbi.srWindow.Bottom - term->csbi.srWindow.Top + 1;
|
||||
}
|
||||
|
||||
int terminal_clean(win_term_t* term) {
|
||||
// Write the sequence for clearing the display.
|
||||
DWORD written = 0;
|
||||
PCWSTR sequence = L"\x1b[2J";
|
||||
if (!WriteConsoleW(term->hStdout, sequence, (DWORD)wcslen(sequence), &written, NULL))
|
||||
{
|
||||
// If we fail, try to restore the mode on the way out.
|
||||
SetConsoleMode(term->hStdout, ENABLE_VIRTUAL_TERMINAL_PROCESSING);
|
||||
return GetLastError();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// int main() {
|
||||
// win_term_t* term = terminal_init();
|
||||
|
||||
// // 清屏
|
||||
// system("cls");
|
||||
|
||||
// // 打印彩色文本
|
||||
// terminal_print(term, 10, 5,
|
||||
// "按方向键移动, ESC退出");
|
||||
|
||||
// int x = 10, y = 10;
|
||||
// char* player = "@";
|
||||
|
||||
// while (1) {
|
||||
// // 绘制玩家
|
||||
// terminal_print(term, x, y,
|
||||
// player);
|
||||
|
||||
// // 获取按键
|
||||
// int key = terminal_get_key(term);
|
||||
|
||||
// // 擦除旧位置
|
||||
// terminal_print(term, x, y, " ");
|
||||
|
||||
// // 处理移动
|
||||
// switch (key) {
|
||||
// case VK_UP: y--; break;
|
||||
// case VK_DOWN: y++; break;
|
||||
// case VK_LEFT: x--; break;
|
||||
// case VK_RIGHT: x++; break;
|
||||
// case VK_ESCAPE:
|
||||
// terminal_cleanup(term);
|
||||
// return 0;
|
||||
// }
|
||||
|
||||
// // 边界检查
|
||||
// if (x < 0) x = 0;
|
||||
// if (y < 0) y = 0;
|
||||
// }
|
||||
// }
|
||||
|
||||
uint32_t win_get_timer_ms() {
|
||||
static LARGE_INTEGER freq = {0};
|
||||
static BOOL has_freq = FALSE;
|
||||
|
||||
@@ -10,5 +10,6 @@ int terminal_get_key(win_term_t* term);
|
||||
int terminal_get_width(win_term_t* term);
|
||||
int terminal_get_height(win_term_t* term);
|
||||
int terminal_clean(win_term_t* term);
|
||||
void terminal_flush(win_term_t* term);
|
||||
|
||||
#endif // __WIN_TERM_H__
|
||||
|
||||
Reference in New Issue
Block a user