SDLで入力制御
今回はマウスとキーボードを使ったサンプルプルグラムです。
キーを入力すると画面に描画する色を変更、
左のマウスボタンをクリックすると、画面に矩形を描画します。
イベントが発生したときのみ処理を実行するようにしています。SDLでのマウスを押した時のイベントは、SDL_MOUSEBUTTONDOWN。キーボードを押した時のイベントは、SDL_KEYDOWNになります。
ただしSDL_KEYDOWNに関しては、デフォルトの設定だと
キーリピートが有効ではありません。
キーボードを押したときに走るイベントが、
「キーを押す」→「キーを離す」の一連動作で実行されるため、SDLのプログラムを実行中にキーを押しっぱなしにした状態で、連続したキーボードイベントを発生させる場合、
SDL_EnableKeyRepeat (SDL_DEFAULT_REPEAT_DELAY,SDL_DEFAULT_REPEAT_INTERVAL); |
を予め実行しておく必要があります。
今回は画面を更新する際に、画面に描画された箇所のみ更新するようにしています。
前回のプログラムでは描画した箇所に関わらず、全画面を更新していました。
つまり更新する必要の無いところまで更新していたのです。
その為、今回は複数の画面上の更新箇所を保存できるように、リストを使ってます。
ちょっとややこしいので、難しいと思ったら軽く眺めておいてください。
rectnode.h
#ifndef RECTNODE_H #define RECTNODE_H #include <SDL/SDL.h> typedef struct RectHandle { void (*add)(SDL_Rect *rect); void (*update)(SDL_Surface *screen); void (*free)(void); }RectHandle; void initRectHandle(RectHandle *rHnadle); #endif |
rectnode.c
#include "rectnode.h" #include <stdlib.h> //--矩形リスト構造体 typedef struct RECT_NODE { SDL_Rect rect; struct RECT_NODE *next; } RectNode; static RectNode *nodeTop = NULL; static Uint16 numRect = 0; //--関数宣言 static void add(SDL_Rect *rect); static void update(SDL_Surface *screen); static void freeList(void); //--関数ポインタ等の初期化 void initRectHandle(RectHandle *rHandle) { rHandle->add = add; rHandle->free = freeList; rHandle->update = update; } //--矩形情報の追加 static void add(SDL_Rect *rect) { RectNode **tmp; RectNode *node = (RectNode*)malloc(sizeof(RectNode)); if(node == NULL) { return; } node->rect = (*rect); node->next = NULL; tmp = &nodeTop; while( *tmp != NULL ) { tmp = &(*tmp)->next; } *tmp = node; //--矩形情報の追加 numRect++; } //--画面の更新 static void update(SDL_Surface *screen) { int idx; RectNode **tmp; SDL_Rect *rects = (SDL_Rect*)malloc(sizeof(SDL_Rect)*numRect); if(nodeTop == NULL) { return; } idx = 0; tmp = &nodeTop; while( *tmp != NULL ) { rects[idx].h = (*tmp)->rect.h; rects[idx].w = (*tmp)->rect.w; rects[idx].x = (*tmp)->rect.x; rects[idx].y = (*tmp)->rect.y; idx++; tmp = &(*tmp)->next; } SDL_UpdateRects(screen, numRect, rects); free(rects); } //--矩形情報の削除 static void freeList(void) { RectNode **tmp,*next; tmp = &nodeTop; while(*tmp != NULL) { next = (*tmp)->next; //リストを退避 free(*tmp); //要素を解放 *tmp = next; //次のリスト } numRect = 0; } |
今回のメインとなるソースです。
キーリピートは予め有効にしてあります。
キーボードを押しっぱなしにしていると、左上に表示される色が刻々と変化します。
キーリピートのインターバルはデフォルト値で設定されています。
ミリ秒単位からの調節が可能ですので、興味のある方はソースをいじってみてください。
main.cpp
#include <SDL/SDL.h> #include <stdio.h> #include "rectnode.h" #pragma comment(lib,"SDL.lib") #pragma comment(lib,"SDLmain.lib") #define WIDTH 320 //横幅 #define HEIGHT 256 //高さ #define BPP 32 //1ピクセルのビット数 #define SCREEN_BLOCK 32 #define FLG_INIT (SDL_INIT_VIDEO) #define KEY_REPEAT 1 //キーリピートフラグ static SDL_Surface *screen; //ビデオポインタ static RectHandle handle; //SDLコントロール変数 static Uint32 color; bool init(void); //初期化 void run(void); //メイン処理 void quit(void); //終了処理 void mouseAction(void); //マウス釦押下イベント //キーボードイベント void keyboardAction(SDL_keysym *keysym); int main(int argc, char *argv[]) { if( init() )run(); quit(); return 0; } void mouseAction(void) { int x,y; Uint8 flg; flg = SDL_GetMouseState( &x, &y ); if( flg & SDL_BUTTON(1) ) { SDL_Rect rect = { (x / SCREEN_BLOCK)*SCREEN_BLOCK, (y / SCREEN_BLOCK)*SCREEN_BLOCK, SCREEN_BLOCK, SCREEN_BLOCK }; SDL_FillRect( screen, &rect, color ); handle.add( &rect ); //矩形の追加 } } void keyboardAction(SDL_keysym *keysym) { Sint16 r,g,b; Uint16 random; int keyCode; r = (color>>16)&255; g = (color>>8)&255; b = color&255; keyCode = keysym->sym; random = (Uint16)rand(); switch( random%3 ){ case 0: r = (~keyCode + random | 128) & 255; break; case 1: g = (~keyCode + random | 128) & 255; break; case 2: b = (~keyCode + random | 128) & 255; break; default: break; } color = (r<<16)+(g<<8)+b; } bool init(void) { // ライブラリを初期化する if(SDL_Init(FLG_INIT) < 0) { printf("初期化に失敗"); return false; } // ビデオモードを設定する screen = SDL_SetVideoMode(WIDTH,HEIGHT, BPP, SDL_SWSURFACE ); if( screen == NULL) { printf("VideoInitialize Error"); return false; } initRectHandle( &handle ); #if KEY_REPEAT != 0 SDL_EnableKeyRepeat (SDL_DEFAULT_REPEAT_DELAY, SDL_DEFAULT_REPEAT_INTERVAL); #endif return true; } void run(void) { SDL_Event ev; bool flg; flg = false; // 次のイベントが来るまで無限に待機 while( SDL_WaitEvent(&ev) ) { switch(ev.type){ case SDL_QUIT: //ウィンドウの×ボタン printf("QUIT\n"); return; case SDL_KEYDOWN: //キーダウン printf("KeyDonw\n"); keyboardAction( &(ev.key.keysym) ); flg = true; break; case SDL_MOUSEBUTTONDOWN://マウスダウン printf("MouseDown\n"); mouseAction(); flg = true; break; default:break; //それ以外のイベントは無視する } if( flg ) { SDL_Rect rect = { 0,0,SCREEN_BLOCK, SCREEN_BLOCK }; SDL_FillRect(screen, &rect, color); handle.add( &rect ); //矩形の追加 //画面の更新 handle.update(screen); handle.free(); flg = false; } } } void quit(void) { if(screen != NULL) { SDL_FreeSurface( screen ); } SDL_Quit(); } |