ゲームを作りたい!

プログラミングをしているからには、いつかはゲームを作ってみたい。勉強したことを備忘録的に綴るBLOG。

SDL2でキーボード入力を検知する

今回はSDL2を使用してキーボード入力の検知をする。 キーボードからの入力ができるようになるとゲームっぽい何かが作れそうな気がしてくるよね。 では、早速キーボード入力の検知はどのようにすればできるの調べていこう。

キーイベントを検知する

-> ここ(キーボートイベントタイプ)-> ここ(キーコード)にイベントの種類が色々まとめてある。
また、イベントを検知するには-> この関数(SDL_PollEvent)を使用するようだ。 早速コードを書いてみた。

#include <stdio.h>
#include <SDL2/SDL.h>
#include <SDL2/SDL_image.h>

const int SCREEN_WIDTH = 640;
const int SCREEN_HEIGHT = 480;
const int IMAGE_WIDTH = 16;
const int IMAGE_HEIGHT = 16;
const int MAGNIFICATION = 4;

int main (int argc, char *argv[]) {
    SDL_Window* window = NULL;
    SDL_Renderer *renderer = NULL;
    SDL_Surface *image = NULL; 
    SDL_Texture *image_texture = NULL;
    
    //Initialize SDL
    if( SDL_Init( SDL_INIT_VIDEO ) < 0 ) {
        printf( "SDL could not initialize! SDL_Error: %s\n", SDL_GetError() );
        return 1;
    }
    
    window = SDL_CreateWindow( "KEY EVENT TEST", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, SCREEN_WIDTH, SCREEN_HEIGHT, SDL_WINDOW_SHOWN );
    if( window == NULL ) {
        printf( "Window could not be created! SDL_Error: %s\n", SDL_GetError() );
        return 1;
    } else {
        renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED);
    }

    
    // 画像の読み込み
    image = IMG_Load("walkcat.bmp");
    if(!image) {
        printf("IMG_Load: %s\n", IMG_GetError());
        return 1;
    }

    // 透過色の設定
    SDL_SetColorKey( image, SDL_TRUE, SDL_MapRGB(image->format, 255, 0, 255));
    image_texture = SDL_CreateTextureFromSurface(renderer, image);


    SDL_SetRenderDrawColor(renderer, 200, 200, 200, 255);

    int iw,ih;     
    SDL_QueryTexture(image_texture, NULL, NULL, &iw, &ih);


    int animecycle = 60;
    int frame = 0;

    int mx = 0;
    int my = 0;
    // main loop
    while (1) {

        int x = ((frame / animecycle) % 4) * 16;
        SDL_Rect imageRect=(SDL_Rect){x,0,IMAGE_WIDTH,IMAGE_HEIGHT};
        SDL_Rect drawRect=(SDL_Rect){mx,my,IMAGE_WIDTH*MAGNIFICATION,IMAGE_HEIGHT*MAGNIFICATION};

        SDL_RenderClear(renderer);
        SDL_RenderCopy(renderer, image_texture, &imageRect, &drawRect);
        SDL_RenderPresent(renderer);

        if (frame <= animecycle * 4) {
            frame += 1;
        } else{
            frame = 0;
        }

        // event handling
        SDL_Event e;
        if ( SDL_PollEvent(&e) ) {
            if (e.type == SDL_QUIT){
                break;
            } else if (e.type == SDL_KEYDOWN && e.key.keysym.sym == SDLK_ESCAPE){
                break;
            } else if (e.type == SDL_KEYDOWN && e.key.keysym.sym == SDLK_RIGHT){
                mx = mx + IMAGE_WIDTH*MAGNIFICATION;
            } else if (e.type == SDL_KEYDOWN && e.key.keysym.sym == SDLK_LEFT){
                mx = mx - IMAGE_WIDTH*MAGNIFICATION;
            } else if (e.type == SDL_KEYDOWN && e.key.keysym.sym == SDLK_UP){
                my = my - IMAGE_WIDTH*MAGNIFICATION;
            } else if (e.type == SDL_KEYDOWN && e.key.keysym.sym == SDLK_DOWN){
                my = my + IMAGE_WIDTH*MAGNIFICATION;
            }
        }
    }

    IMG_Quit();
    SDL_FreeSurface(image);
    SDL_DestroyTexture(image_texture);
    SDL_DestroyRenderer(renderer);
    SDL_DestroyWindow(window);

    SDL_Quit();

    return 0;

}

前回のアニメーションのコード(-> ここを参照)に キーイベントを加えてキャラクターの位置を変えられるようにしてみた。前回のコードとの違いは以下になる。

    int animecycle = 60;
    int frame = 0;

    int mx = 0;
    int my = 0;
    // main loop
    while (1) {

        int x = ((frame / animecycle) % 4) * 16;    
        SDL_Rect imageRect=(SDL_Rect){x,0,IMAGE_WIDTH,IMAGE_HEIGHT};      
        SDL_Rect drawRect=(SDL_Rect){mx,my,IMAGE_WIDTH*MAGNIFICATION,IMAGE_HEIGHT*MAGNIFICATION};

        SDL_RenderClear(renderer);
        SDL_RenderCopy(renderer, image_texture, &imageRect, &drawRect);
        SDL_RenderPresent(renderer);

        if (frame <= animecycle * 4) {
            frame += 1;
        } else{
            frame = 0;
        }

        // event handling
        SDL_Event e;
        if ( SDL_PollEvent(&e) ) {
            if (e.type == SDL_QUIT){
                break;
            } else if (e.type == SDL_KEYDOWN && e.key.keysym.sym == SDLK_ESCAPE){
                break;
            } else if (e.type == SDL_KEYDOWN && e.key.keysym.sym == SDLK_RIGHT){
                mx = mx + IMAGE_WIDTH*MAGNIFICATION;
            } else if (e.type == SDL_KEYDOWN && e.key.keysym.sym == SDLK_LEFT){
                mx = mx - IMAGE_WIDTH*MAGNIFICATION;
            } else if (e.type == SDL_KEYDOWN && e.key.keysym.sym == SDLK_UP){
                my = my - IMAGE_WIDTH*MAGNIFICATION;
            } else if (e.type == SDL_KEYDOWN && e.key.keysym.sym == SDLK_DOWN){
                my = my + IMAGE_WIDTH*MAGNIFICATION;
            }
        }
    }

目新しくなったのは、whileループでアニメーションを表示しキーイベントを受け付けるようにしたところである。
今回追加したコードだとEscキーで処理を終了し矢印ボタンで表示されているキャラクターの位置が変化するようになっている。
キャラクターの位置を変えるのは単純に画像の大きさ分、x座標とy座標の位置を足したり引いたりしているだけ。
特に範囲を限定しているわけではないのでウィンドウ外にもキャラクターは移動できてしまうけど、
やりたかったのはキーボードからの検知だから、まぁOKってことにしよう。

実行結果

こんな感じでキャラクターの位置がキー入力に合わせて変化する。 f:id:K38:20181108234557g:plain

終わりに

SDL2を使うことで結構簡単にキーイベント入力の検知ができた。
次回はマウスからの入力を検知してみようかな。
そこまでできれば、とりあえずゲームを作っていく最低限は調べた感じになるかなぁ。