按键操作

按键操作

先来讲点题外话,为啥我会喜欢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;
}

下面我要解释的不多,主要就是夸夸我本人:

  1. 重点按键操作,这个看了应该是不难的,但是是不是看见这份代码开始有点慌了,显得好臃肿,很想重构他?没错,模块化编程在我现在看来模块的不仅是功能函数模块化,还应该是多文件书写代码。明明不同类别模块的东西,非得挤在一个文件里面,很想多文件分开;同时,明明功能接近但是却重复造*的代码,如bool loadMedia()函数,就应该重构统一为一个函数,这是我的一个编程思想,需要改进结构的话肯定得下死手。
  2. 对于C语言和c++在书写方式上是很多不同的,目前我只会一点点c++的语法,但是我很想只用C语言写完这个教程,因为C语言是最好的编程语言!!!因此,我会对接下来大佬开源的代码进行C语言化,尽量不影响其原汁原味的特性
  3. 对于struct_type.h文件,暂时不加说明,到后面会统一公布,会在本教程书写完毕后,再在开头补充如何使用他。说白了其中就是一点宏定义以及枚举定义之类的。为了增加代码的兼容性,同时为了方便以后代码的使用,才单独进行封装。

似乎离翻译汉化的道路越来越远,算了算了,写成个人学习汉化教程吧,因为我英语虽然不好,但意会这些外国文献倒是够了,翻译太耗时间了,而且确实没有必要处处都看,我给你们只挑选重点,你好我也好。

上一篇:Google Earth Engine——美国国家环境预测中心(NCEP)的气候预测系统再分析(CFSR)是作为一个全球性的、高分辨率的、大气-海洋-陆地表面-海冰耦合系统设计和执行的数据集


下一篇:Google Earth Engine(GEE)——MODIS影像StateQA波段bit去云