feat(game_core): 重构游戏引擎并添加新功能
- 重构了游戏引擎的核心逻辑和架构 - 添加了新的实体组件系统(ECS) - 实现了简单的碰撞检测和响应 - 新增了地图和子弹功能 - 优化了输入处理和渲染逻辑 - 调整了游戏控制方式
This commit is contained in:
38
game_core/plantform/win_app/win_input.c
Normal file
38
game_core/plantform/win_app/win_input.c
Normal file
@@ -0,0 +1,38 @@
|
||||
#include "win_interface.h"
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
void win_init_input(ge_core_t* core) {
|
||||
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;
|
||||
}
|
||||
@@ -1,10 +1,25 @@
|
||||
#ifndef __WIN_INTERFACE_H__
|
||||
#define __WIN_INTERFACE_H__
|
||||
|
||||
#include <ge_common.h>
|
||||
#include <windows.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;
|
||||
|
||||
void win_sleep_us(ge_u32_t us);
|
||||
ge_u32_t win_get_us(void);
|
||||
#define WIN_HEIGHT 128
|
||||
#define WIN_WIDTH 128
|
||||
#define WIN_SCARE 4
|
||||
|
||||
void win_init_input(ge_core_t* core);
|
||||
void win_init_timer(ge_core_t* core);
|
||||
void win_init_render(ge_core_t* core, win_render_context_t* wctx);
|
||||
|
||||
#endif // __WIN_INTERFACE_H__
|
||||
|
||||
@@ -1,76 +1,4 @@
|
||||
#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) {
|
||||
@@ -121,26 +49,6 @@ LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM 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;
|
||||
@@ -152,92 +60,42 @@ static void win_run_at_frame(ge_core_t* core) {
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
wc.lpszClassName = TEXT("GameWindow");
|
||||
|
||||
RegisterClass(&wc);
|
||||
|
||||
// 计算正确的窗口尺寸 =====================================
|
||||
RECT clientRect = {0};
|
||||
clientRect.right = WIN_WIDTH * WIN_SCARE; // 期望的客户区宽度
|
||||
clientRect.bottom = WIN_HEIGHT * WIN_SCARE; // 期望的客户区高度
|
||||
|
||||
// 使用 AdjustWindowRectEx 计算窗口尺寸(遵循微软建议)
|
||||
DWORD dwExStyle = 0; // 无扩展样式
|
||||
DWORD dwStyle = WS_OVERLAPPEDWINDOW;
|
||||
AdjustWindowRectEx(&clientRect, dwStyle, FALSE, dwExStyle);
|
||||
|
||||
int windowWidth = clientRect.right - clientRect.left;
|
||||
int windowHeight = clientRect.bottom - clientRect.top;
|
||||
// ======================================================
|
||||
|
||||
HWND hwnd = CreateWindowEx(
|
||||
0,
|
||||
CLASS_NAME,
|
||||
"Game Engine",
|
||||
WS_OVERLAPPEDWINDOW,
|
||||
CW_USEDEFAULT, CW_USEDEFAULT, 128 * 4, 128 * 4,
|
||||
dwExStyle, // 使用计算时的扩展样式
|
||||
wc.lpszClassName,
|
||||
TEXT("Game Engine"),
|
||||
dwStyle,
|
||||
CW_USEDEFAULT, CW_USEDEFAULT,
|
||||
windowWidth, windowHeight, // 使用计算出的窗口尺寸
|
||||
NULL, NULL, hInstance, NULL
|
||||
);
|
||||
|
||||
@@ -250,33 +108,15 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine
|
||||
// 创建双缓冲上下文
|
||||
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;
|
||||
win_init_render(&core, wctx);
|
||||
win_init_timer(&core);
|
||||
win_init_input(&core);
|
||||
|
||||
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._inner_context = (void*)wctx;
|
||||
|
||||
// 将core指针关联到窗口
|
||||
SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)&core);
|
||||
|
||||
ShowWindow(hwnd, nCmdShow);
|
||||
UpdateWindow(hwnd);
|
||||
// 运行主游戏逻辑
|
||||
|
||||
126
game_core/plantform/win_app/win_render.c
Normal file
126
game_core/plantform/win_app/win_render.c
Normal file
@@ -0,0 +1,126 @@
|
||||
#include "win_interface.h"
|
||||
|
||||
// 双缓冲初始化函数
|
||||
static int 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;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// 清空后台缓冲区
|
||||
static int 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 *= WIN_SCARE;
|
||||
win_rect.right *= WIN_SCARE;
|
||||
win_rect.left *= WIN_SCARE;
|
||||
win_rect.top *= WIN_SCARE;
|
||||
HBRUSH brush = CreateSolidBrush(color); // WHITE background
|
||||
|
||||
FillRect(wctx->hdc_back, &win_rect, brush);
|
||||
DeleteObject(brush);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// 将后台缓冲区复制到屏幕(双缓冲交换)
|
||||
static int 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);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int win_render_draw_text (
|
||||
ge_render_t* ctx,
|
||||
const ge_render_pos2_t* pos,
|
||||
ge_render_unit_t font_size,
|
||||
ge_render_color_t font_color,
|
||||
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));
|
||||
return 0;
|
||||
}
|
||||
|
||||
void win_init_render(ge_core_t* core, win_render_context_t* wctx) {
|
||||
core->_render.context = wctx;
|
||||
core->_render.init_func = win_render_init;
|
||||
core->_render.func_flush = win_render_flush;
|
||||
core->_render.func_draw_text = win_render_draw_text;
|
||||
core->_render.func_draw_rect = win_render_draw_rect;
|
||||
}
|
||||
|
||||
__attribute__ ((__unused__))
|
||||
static void win_render_drawex(ge_render_t* ctx, ge_vector2i_t pos, const char* data, const void* propety) {
|
||||
(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);
|
||||
}
|
||||
|
||||
__attribute__ ((__unused__))
|
||||
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;
|
||||
}
|
||||
@@ -1,5 +1,15 @@
|
||||
#include <windows.h>
|
||||
#include <ge_common.h>
|
||||
#include "win_interface.h"
|
||||
// Windows计时函数
|
||||
#include <stdint.h>
|
||||
static ge_time_t win_get_ms(ge_timer_t* ctx) {
|
||||
(void) ctx;
|
||||
return GetTickCount();
|
||||
}
|
||||
|
||||
static void win_sleep_ms(const ge_timer_t* ctx, ge_time_t ms) {
|
||||
(void) ctx;
|
||||
Sleep(ms);
|
||||
}
|
||||
|
||||
// 获取当前时间(微秒)
|
||||
ge_u32_t win_get_us(void) {
|
||||
@@ -28,4 +38,13 @@ void win_sleep_us(ge_u32_t us) {
|
||||
// 长时间使用Sleep
|
||||
Sleep(us / 1000);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void win_init_timer(ge_core_t* core) {
|
||||
core->_timer.time = 0;
|
||||
core->_timer.func_sleepms = win_sleep_ms;
|
||||
core->_timer.func_getms = win_get_ms;
|
||||
core->_timer.func_sleepus = NULL;
|
||||
core->_timer.func_getus = NULL;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user