对古董老游戏的复刻,使用SDL再合适不过了,废话不多说,新建工程然后开搞!
对于IDE,本人选择jetbrains系列的CLion:
游戏程序总框架:
根据上图编写main.c文件:
#define SDL_MAIN_HANDLED#include <stdio.h>
#include "core/texture/texture.h"
#include "core/timer/timer.h"
#include "stdbool.h"
#include "SDL2/SDL_image.h"//常量----屏幕大小及帧刷新率(暂定)
const int SCREEN_WIDTH = 800;
const int SCREEN_HEIGHT = 600;
const int SCREEN_FPS = 60;
const int SCREEN_TICKS_PER_FRAME = 1000 / SCREEN_FPS;//声明全局变量
SDL_Window* g_window = NULL;
SDL_Renderer* g_renderer = NULL;
SDL_bool g_game_quit = false;
int g_screen_width = SCREEN_WIDTH;
int g_screen_height = SCREEN_HEIGHT;
int g_screen_fps = SCREEN_FPS;
int g_screen_tpf = SCREEN_TICKS_PER_FRAME;//函数声明
void game_init();
void game_load();
void game_loop();
void game_render();
void game_update(float dt);
void game_close();struct Texture map;int main()
{game_init();game_load();game_loop();game_close();return 0;
}void game_init()
{// initialize SDLif (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_TIMER) < 0){printf("SDL could not initialize! SDL_Error: %s\n", SDL_GetError());}//set texture filtering to linearif( !SDL_SetHint( SDL_HINT_RENDER_SCALE_QUALITY, "1" ) ){printf( "Warning: Linear texture filtering not enabled!" );}// create windowg_window = SDL_CreateWindow("ccz",SDL_WINDOWPOS_UNDEFINED,SDL_WINDOWPOS_UNDEFINED,SCREEN_WIDTH,SCREEN_HEIGHT,SDL_WINDOW_SHOWN //全屏的话用SDL_WINDOW_FULLSCREEN_DESKTOP);if (g_window == NULL){printf("Window could not be created! SDL_Error: %s\n", SDL_GetError());}//create renderer for windowg_renderer = SDL_CreateRenderer( g_window, -1, SDL_RENDERER_ACCELERATED );if( g_renderer == NULL ){printf( "Renderer could not be created! SDL Error: %s\n", SDL_GetError() );}//initialize renderer colorSDL_SetRenderDrawColor( g_renderer, 0xFF, 0xFF, 0xFF, 0xFF );//initialize PNG loadingint imgFlags = IMG_INIT_PNG;if( !( IMG_Init( imgFlags ) & imgFlags ) ){printf( "SDL_image could not initialize! SDL_image Error: %s\n", IMG_GetError() );}
}void game_load()
{texture_load_fromfile(&map, "4-1.png");
}void game_loop()
{SDL_Event e;//The frames per second timerstruct Timer fps_timer;//The frames per second cap timerstruct Timer cap_timer;//Start counting frames per secondint counted_frames = 0;float dt = 0.0f;timer_start(&fps_timer);//loopwhile (!g_game_quit){timer_start(&cap_timer);while (SDL_PollEvent(&e) != 0){if (e.type == SDL_QUIT){//g_ptr_ffp->video_thread_exit = true;g_game_quit = true;}}//Calculate and correct fpsfloat avg_fps = (float )counted_frames / ( timer_get_ticks(&fps_timer) / 1000.f );if( avg_fps > 2000000 ){avg_fps = 0;}//Clear screenSDL_SetRenderDrawColor( g_renderer, 0x00, 0x00, 0x00, 0xFF );SDL_RenderClear( g_renderer );game_render();//Update screenSDL_RenderPresent( g_renderer );int frame_ticks = timer_get_ticks(&cap_timer);++counted_frames;//If frame finished earlyif( frame_ticks < g_screen_tpf ){//Wait remaining timeSDL_Delay( g_screen_tpf - frame_ticks );}dt = (float)frame_ticks / 1000.f;game_update(dt);}
}void game_render()
{texture_render(&map, 0, 0, NULL, 0.0, NULL, SDL_FLIP_NONE);
}void game_update(float dt)
{}void game_close()
{//TO DO//Free global font
/* TTF_CloseFont( g_font );g_font = NULL;*///Destroy windowSDL_DestroyRenderer( g_renderer );SDL_DestroyWindow( g_window );g_window = NULL;g_renderer = NULL;//Quit SDL subsystems//TTF_Quit();IMG_Quit();SDL_Quit();
}
只要用sdl制作游戏,以上main.c代码大同小异,无非增增减减各种多媒体字体等的操作。
首要目标是能创建游戏窗口并显示图片:
这是一张战斗地图。
其中最重要的是 Texture 对象和功能函数:
#ifndef SDL_CCZ_TEXTURE_H
#define SDL_CCZ_TEXTURE_H#include "SDL2/SDL.h"struct Texture
{int width;int height;SDL_Texture* sdl_texture;
};void texture_init(struct Texture* ptr_texture);void texture_clean(struct Texture* ptr_texture);void texture_free(struct Texture** ptr_texture);void texture_load_fromfile(struct Texture* ptr_texture, const char* file);void texture_render(struct Texture* ptr_texture,int x,int y,SDL_Rect* clip,double angle,SDL_Point* center,SDL_RendererFlip flip);#endif //SDL_CCZ_TEXTURE_H
函数 void texture_load_fromfile(struct Texture* ptr_texture, const char* file) 的第二个参数要求图片文件的绝对路径名,这样未免字符串过长,不方便。我们可以在CLion中设置工作目录,方法如下:
点击Debug旁边的三角箭头
下拉菜单选Debug Configurations,弹出对话框:
之后使用图片加载函数如:
texture_load_fromfile(&map, "4-1.png");
就显得简洁明了些。还有一个Timer定时器对象,因今后还会用到,等以后说明。
编译前记得编写cmakefile
一部分IDE会自动编写,SDL路径需要根据自己安装位置设定:
cmake_minimum_required(VERSION 3.17)
project(sdl_ccz C)set(CMAKE_C_STANDARD 99)# 声明一个变量SDL2_DIR为SDL2安装路径
set(SDL2_DIR "E:/Applications/mingw-w64/x86_64-8.1.0-win32-seh-rt_v6-rev0/mingw64")# 设置要包含的头文件的路径
include_directories(${SDL2_DIR}/include
)# 设置要关联的库的路径
link_directories(${SDL2_DIR}/lib
)add_executable(sdl_cczsrc/main.csrc/core/texture/texture.hsrc/core/texture/texture.csrc/core/timer/timer.hsrc/core/timer/timer.c
)target_link_libraries(sdl_cczmingw32SDL2SDL2mainSDL2_image
)
编译执行后如图:
因地图尺寸相较于窗口要大,所以只显示了一部分。
下一篇将使游戏窗口有更多的功能:全屏、最大化、拉伸等,然后在地图上显示英雄单位。