按键操作
先来讲点题外话,为啥我会喜欢SDL呢?我之前从事的编程是嵌入式开发,我喜欢嵌入式,但是人生苦短,学学其他东西也是好的。我讨厌Python,因此没有过于学习pyqt库,不知道为啥,就是觉得啥东西都不是自己写的,代码量一写大一点,就觉得不是自己的东西,格外不踏实。在者这门语言执行效率太低下了,一边有C语言的影子,还有c++的影子,却又是脚本语言。我是新手菜鸡,或许我的感觉是很不对的,但是没人纠正我之前我就这样认为吧。
好,回归主题,SDL的开发其实和嵌入式开发很像,更多类似于对库进行开发。事件类似于嵌入式的信号输入,刷新渲染层类似于像电机发送处理好的命令,窗口运行的视觉效果就像嵌入式代码烧进板子里产品运行效果,无现象就失败了,有现象也不一定成功了,或许一个极端条件直接就无了。
这种感觉很强烈,说不清楚。应该没有哪个闲人会像我一样做着嵌入式跑来学SDL吧!好了,如果看不懂这段直接飘过,进入下面正题。
用户按键很重要,特别是游戏,我的小miku还等着按键交互呢
还是先看代码,看代码是最快的学习方式,前提是你能看懂的话,看不懂还是好好学语法,学基础,多抱着基础书籍啃啃,总会好起来的。
也别慌,我会使用中文注释对代码进行讲解,以中文注释的方式呈现(非中文注释的地方要么简单,要么已经讲过),并在文末附上我对这份代码的划重点“欸欸欸~~~敲黑板了,必考的喔”(还是想念高三的时光啊!)
/*This source code copyrighted by Lazy Foo' Productions (2004-2020)
and may not be redistributed without written permission.*/
//注意,此份代码只是用C语言,因此做出过修改,不会影响大局
//Using SDL, standard IO, and strings
#include <SDL.h>
#include <stdio.h>
#include <string.h>
//为了C语言和c++部分数据类型命名的统一,自己书写的一个头文件
#include "struct_type.h"
//Screen dimension constants
const int SCREEN_WIDTH = 640;
const int SCREEN_HEIGHT = 480;
//将事件封装为一个枚举类型,命名很重要
enum KeyPressSurfaces
{
KEY_PRESS_SURFACE_DEFAULT,
KEY_PRESS_SURFACE_UP,
KEY_PRESS_SURFACE_DOWN,
KEY_PRESS_SURFACE_LEFT,
KEY_PRESS_SURFACE_RIGHT,
KEY_PRESS_SURFACE_TOTAL
};
//Starts up SDL and creates window
bool init();
//Loads media
bool loadMedia();
//Frees media and shuts down SDL
void close();
//将图片的装载处理为一个单独模块,模块化的编程很重要
SDL_Surface* loadSurface(char path[]);
//The window we'll be rendering to
SDL_Window* gWindow = NULL;
//The surface contained by the window
SDL_Surface* gScreenSurface = NULL;
//不同按键对应的图片资源
SDL_Surface* gKeyPressSurfaces[KEY_PRESS_SURFACE_TOTAL];
//Current displayed image
SDL_Surface* gCurrentSurface = NULL;
bool init()
{
//Initialization flag
bool success = true;
//Initialize SDL
if (SDL_Init(SDL_INIT_VIDEO) < 0)
{
printf("SDL could not initialize! SDL Error: %s\n", SDL_GetError());
success = false;
}
else
{
//Create window
gWindow = SDL_CreateWindow("SDL Tutorial", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, SCREEN_WIDTH, SCREEN_HEIGHT, SDL_WINDOW_SHOWN);
if (gWindow == NULL)
{
printf("Window could not be created! SDL Error: %s\n", SDL_GetError());
success = false;
}
else
{
//Get window surface
gScreenSurface = SDL_GetWindowSurface(gWindow);
}
}
return success;
}
bool loadMedia()
{
//Loading success flag
bool success = true;
//Load default surface
gKeyPressSurfaces[KEY_PRESS_SURFACE_DEFAULT] = loadSurface("C:\\Users\\Lixin\\Desktop\\down.bmp");
if (gKeyPressSurfaces[KEY_PRESS_SURFACE_DEFAULT] == NULL)
{
printf("Failed to load default image!\n");
success = false;
}
//Load up surface
gKeyPressSurfaces[KEY_PRESS_SURFACE_UP] = loadSurface("C:\\Users\\Lixin\\Desktop\\down.bmp");
if (gKeyPressSurfaces[KEY_PRESS_SURFACE_UP] == NULL)
{
printf("Failed to load up image!\n");
success = false;
}
//Load down surface
gKeyPressSurfaces[KEY_PRESS_SURFACE_DOWN] = loadSurface("C:\\Users\\Lixin\\Desktop\\down.bmp");
if (gKeyPressSurfaces[KEY_PRESS_SURFACE_DOWN] == NULL)
{
printf("Failed to load down image!\n");
success = false;
}
//Load left surface
gKeyPressSurfaces[KEY_PRESS_SURFACE_LEFT] = loadSurface("C:\\Users\\Lixin\\Desktop\\left.bmp");
if (gKeyPressSurfaces[KEY_PRESS_SURFACE_LEFT] == NULL)
{
printf("Failed to load left image!\n");
success = false;
}
//Load right surface
gKeyPressSurfaces[KEY_PRESS_SURFACE_RIGHT] = loadSurface("C:\\Users\\Lixin\\Desktop\\down.bmp");
if (gKeyPressSurfaces[KEY_PRESS_SURFACE_RIGHT] == NULL)
{
printf("Failed to load right image!\n");
success = false;
}
return success;
}
void close()
{
//Deallocate surfaces
for (int i = 0; i < KEY_PRESS_SURFACE_TOTAL; ++i)
{
SDL_FreeSurface(gKeyPressSurfaces[i]);
gKeyPressSurfaces[i] = NULL;
}
//Destroy window
SDL_DestroyWindow(gWindow);
gWindow = NULL;
//Quit SDL subsystems
SDL_Quit();
}
SDL_Surface* loadSurface(char path[])
{
//Load image at specified path
SDL_Surface* loadedSurface = SDL_LoadBMP(path);
if (loadedSurface == NULL)
{
printf("Unable to load image %s! SDL Error: %s\n", path, SDL_GetError());
}
return loadedSurface;
}
int main(int argc, char* args[])
{
//Start up SDL and create window
if (!init())
{
printf("Failed to initialize!\n");
}
else
{
//Load media
if (!loadMedia())
{
printf("Failed to load media!\n");
}
else
{
//Main loop flag
bool quit = false;
//Event handler
SDL_Event e;
//Set default current surface
gCurrentSurface = gKeyPressSurfaces[KEY_PRESS_SURFACE_DEFAULT];
//While application is running
while (!quit)
{
//Handle events on queue
while (SDL_PollEvent(&e) != 0)
{
//User requests quit
if (e.type == SDL_QUIT)
{
quit = true;
}
//用户按键事件处理,本节课学习的重点,其他的可以不理解,但是它不行
//类似于SDL_KEYDOWN,SDLK_UP,全是已经定义好了的宏定义或者枚举类型,直接F12查看即可,注意这里为枚举的一个函数
else if (e.type == SDL_KEYDOWN)
{
//Select surfaces based on key press
switch (e.key.keysym.sym)
{
case SDLK_UP:
gCurrentSurface = gKeyPressSurfaces[KEY_PRESS_SURFACE_UP];
break;
case SDLK_DOWN:
gCurrentSurface = gKeyPressSurfaces[KEY_PRESS_SURFACE_DOWN];
break;
case SDLK_LEFT:
gCurrentSurface = gKeyPressSurfaces[KEY_PRESS_SURFACE_LEFT];
break;
case SDLK_RIGHT:
gCurrentSurface = gKeyPressSurfaces[KEY_PRESS_SURFACE_RIGHT];
break;
default:
gCurrentSurface = gKeyPressSurfaces[KEY_PRESS_SURFACE_DEFAULT];
break;
}
}
}
//Apply the current image
SDL_BlitSurface(gCurrentSurface, NULL, gScreenSurface, NULL);
//Update the surface
SDL_UpdateWindowSurface(gWindow);
}
}
}
//Free resources and close SDL
close();
return 0;
}
下面我要解释的不多,主要就是夸夸我本人:
- 重点按键操作,这个看了应该是不难的,但是是不是看见这份代码开始有点慌了,显得好臃肿,很想重构他?没错,模块化编程在我现在看来模块的不仅是功能函数模块化,还应该是多文件书写代码。明明不同类别模块的东西,非得挤在一个文件里面,很想多文件分开;同时,明明功能接近但是却重复造*的代码,如bool loadMedia()函数,就应该重构统一为一个函数,这是我的一个编程思想,需要改进结构的话肯定得下死手。
- 对于C语言和c++在书写方式上是很多不同的,目前我只会一点点c++的语法,但是我很想只用C语言写完这个教程,因为C语言是最好的编程语言!!!因此,我会对接下来大佬开源的代码进行C语言化,尽量不影响其原汁原味的特性
- 对于struct_type.h文件,暂时不加说明,到后面会统一公布,会在本教程书写完毕后,再在开头补充如何使用他。说白了其中就是一点宏定义以及枚举定义之类的。为了增加代码的兼容性,同时为了方便以后代码的使用,才单独进行封装。
似乎离翻译汉化的道路越来越远,算了算了,写成个人学习汉化教程吧,因为我英语虽然不好,但意会这些外国文献倒是够了,翻译太耗时间了,而且确实没有必要处处都看,我给你们只挑选重点,你好我也好。