ゲームを作りたい!

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

SDL2で画像を表示する

前回はウィンドウ上に文字を表示する方法を調べた。
今回はウィンドウ上に画像を表示する方法を調べていこうと思う。

表示する画像の用意

今回表示に使う画像は以下である。
f:id:K38:20181019005500j:plain
この画像は、KonaLinuxに標準で入っていたAzPainterを使用して作成した。
WEBで探した猫を真似してドット絵打ってみたけど下手くそなのはご愛嬌。これから頑張っていこうと思う。
AzPainterはLinuxでフリー使用できるペイントソフトで、私が使用している古いノートPC(どれくらい古いかは環境設定の項目参照)でもサクサク動く軽さが魅力的である。詳細は-> ここを確認されたし。
AzPainterを使用してドット絵を書くために調べたことは、後日別記事にまとめようと思う。
オリジナルを打てるように頑張っていきたい。
これを、表示するためにひとまずテストコードと同じ階層に置いておく。階層はこんな感じ

sdl2_test/
  |--sdl2_img.c
  |--cat.bmp

ちなみに、画像の背景色はRGB(255, 0, 255)になっている。
これは、SDL2の関数を用いて背景色を透過するためにドット絵に使用しない色を指定している。

画像の表示

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


const int SCREEN_WIDTH = 640;
const int SCREEN_HEIGHT = 480;

int main( int argc, char* args[] ) {
    SDL_Window* window = NULL;
    SDL_Renderer *renderer = NULL;
    SDL_Surface *image = NULL;
    SDL_Texture *image_texture = NULL;

    // 今回は使用していないがJPGとPNG形式の画像を読み込めるようにするには以下を設定する
    int flags=IMG_INIT_JPG|IMG_INIT_PNG;
    int initted=IMG_Init(flags);

    if(initted&flags != flags) {
        printf("IMG_Init: JPGとPNGの読み込みの初期化に失敗した!\n");
        printf("IMG_Init: %s\n", IMG_GetError());
    }

    //Initialize SDL
    if( SDL_Init( SDL_INIT_VIDEO ) < 0 ) {
        printf( "SDL could not initialize! SDL_Error: %s\n", SDL_GetError() );
    } else {
        //Create window
        window = SDL_CreateWindow( "DRAW IMAGE 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() );
        } else {

            renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED);

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

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

            image_texture = SDL_CreateTextureFromSurface(renderer, image);

            int iw,ih;
            SDL_QueryTexture(image_texture, NULL, NULL, &iw, &ih);
            SDL_Rect imageRect=(SDL_Rect){0,0,iw,ih};
            SDL_Rect drawRect=(SDL_Rect){300,220,iw,ih};

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

            SDL_Delay( 3000 );
        }
    }

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

    SDL_Quit();

    return 0;
}

新規に使用した関数は以下。メモっておく。
-> IMG_Init
-> IMG_Load
-> SDL_SetColorKey
-> SDL_SetRenderDrawColor
-> IMG_Quit

コンパイル

gcc -g -o sdl2_img sdl2_img.c `sdl2-config --cflags --libs` -lSDL2_image

このような形でコンパイルを行う。前回、文字を表示した時は-lSDL2_ttfを追加したが、画像の場合は-lSDL2_imageを追加する必要がある。

実行結果

./sdl2_imgで実行する。
f:id:K38:20181019011002p:plain:w300
無事に画像を背景色透過で表示させることができた。

終わりに

文字、画像、と来たので次回は音を鳴らす方法を調べようと思う。今回はこれで以上!

SDL2で文字を表示する

先日は、C言語+SDL2でプログラムをするための環境を整えてウィンドウを表示するコードを書いた。
今回はそのウィンドウ上に文字を表示してみようと思う。
ちなみに、SDL2の日本語リファレンスは-> ここを参照。 使用する関数はリファレンスを確認しながら使おう思う。

フォントの用意

まずは、文字を表示するためにフォントを用意する。
ゲームっぽいフォントを探していたら以下のフォントが見つかった。
-> PixelMplus 8bitビットマップふうフリーフォント - itouhiroはてなブログ
これを、ダウンロードして展開しテストコードと同じ階層に置いておく。階層はこんな感じ。

sdl2_test/
  |--sdl2_ttf.c
  |--PixelMplus12-Regular.ttf

文字の表示

文字を表示するために以下のテストコードを作成した。
基本的には前回ウィンドウを表示するために作成したコードに文字表示分を追加した形になっている。

#include <SDL2/SDL.h>
#include <SDL2/SDL_ttf.h>

#define FONT_PATH "PixelMplus12-Regular.ttf"

const int SCREEN_WIDTH = 640;
const int SCREEN_HEIGHT = 480;

int main( int argc, char* args[] ) {

    SDL_Window* window = NULL;
    SDL_Renderer* renderer = NULL;

    SDL_Surface *surface;
    SDL_Texture *texture;
    SDL_Event ev;

    TTF_Font *font;

    //Initialize SDL
    if( SDL_Init( SDL_INIT_VIDEO ) < 0 )
    {
        printf( "SDL could not initialize! SDL_Error: %s\n", SDL_GetError() );
    } else {

        window = SDL_CreateWindow("Draw Text Test", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, SCREEN_WIDTH, SCREEN_HEIGHT, SDL_WINDOW_SHOWN );
        renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED);

        if( window == NULL ) {
            printf( "Window could not be created! SDL_Error: %s\n", SDL_GetError() );
        } else {

            //Initialize TTF
            if ( TTF_Init() < 0 ) {
                printf("TTFcould not initialize! TTF_Error: %s\n", TTF_GetError());
            } else {

                font = TTF_OpenFont(FONT_PATH, 40);

                if (!font) {
                    printf("TTF_OpenFont: %s\n", TTF_GetError());
                }else {
                    //TTF_SetFontOutline(font, 1);//枠抜きで描写するとき
                    surface = TTF_RenderUTF8_Blended(font, "HelloWorld!", (SDL_Color){255,255,255,255});

                    //surfaceからTextureを作る    
                    texture = SDL_CreateTextureFromSurface(renderer, surface);

                    SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255);
                    SDL_RenderClear(renderer);

                    //文字を描写したTextureのサイズを取得する      
                    int iw,ih;
                    SDL_QueryTexture(texture, NULL, NULL, &iw, &ih);

                    SDL_Rect txtRect=(SDL_Rect){0,0,iw,ih};
                    SDL_Rect pasteRect=(SDL_Rect){200,200,iw,ih};

                    //Textureを描写する      
                    //描写元の描写する部分,描写先の描写する部分)      
                    //サイズが違うと勝手にTextureを伸展してくれる      
                    SDL_RenderCopy(renderer, texture, &txtRect, &pasteRect);
                    //windowにレンダリングする      
                    SDL_RenderPresent(renderer);

                    SDL_Delay(3000);
                }

            }
        }
    }

    SDL_FreeSurface(surface);
    SDL_DestroyTexture(texture);
    SDL_DestroyRenderer(renderer);
    SDL_DestroyWindow(window);
    SDL_Quit();

    TTF_CloseFont(font);
    TTF_Quit();

    return 0;

}

使用した関数についてメモっておく。使用方法は、リンク先に書いてある。
-> TTF_Init
-> TTF_OpenFont
-> TTF_RenderUTF8_Blended
-> SDL_CreateTextureFromSurface
-> SDL_QueryTexture
-> SDL_RenderCopy
-> SDL_SetRenderDrawColor -> SDL_FreeSurface
-> SDL_DestroyTexture
-> TTF_CloseFont
-> TTF_Quit

コンパイル

gcc -g -o sdl2_ttf sdl2_ttf.c `sdl2-config --cflags --libs` -lSDL2_ttf

このような形でコンパイルを行う。
SDL2_ttfを使用するためには、前回ウィンドウを表示したコードをコンパイルした引数に加え、-lSDL2_ttfを追加する必要がある。

実行結果

./sdl2_ttfで実行する。
f:id:K38:20181012060723p:plain:w300
このように、ウィンドウにHelloWorldを表示することができた。

終わりに

今回は、SDL2で文字を扱う方法を調べた。次回は、画像の扱い方を調べようかなと思う。

ゲームを作るための環境設定

SDL2のインストール

特に理由はないが、C言語+SDL2を使ってゲームを作っていこうと思った。 趣味で作るものなのであまり深く考えず使いたい言語で行こうと思う。
私は現在、Debian系のkonalinuxを使用している。調べたところ、SDL2は以下のコマンドで簡単にインストールできるようだ。

sudo apt-get install libsdl2-dev

さらに、.bmp以外の画像ファイルを扱うときはsdl2_image、フォントを扱うときはsdl2_ttfなどが必要なようだ。 音楽を扱う場合はsdl2_mixer、ネットワークを扱う場合はsdl2_netがあるといいらしいので追加でインストールする。
ちなみに、インストールしなくても自力でコーディングすれば画像だろうがフォントだろうが扱えるっぽいが使えるものは使っていこうと思う。
インストールコマンドは以下。

apt-get install libsdl2-image-dev libsdl2-mixer-dev libsdl2-net-dev libsdl2-ttf-dev

Debian系ではない場合は、yumからのインストールもしくはソースからのMakeが可能なようだ。他の環境に入れる時があれば追記しようと思う。

動作確認

簡単なコードを書いて動作確認を行う。 SDL2に初めて触ったので、使用する関数等が妥当かはわからないが、とりあえず以下のコードで画面を出力できた。

  • コード
#include <SDL2/SDL.h>
#include <stdio.h>

const int SCREEN_WIDTH = 640;
const int SCREEN_HEIGHT = 480;

int main( int argc, char* args[] ) {

    SDL_Window* window = NULL;
    SDL_Renderer *renderer = NULL;

    //Initialize SDL
    if( SDL_Init( SDL_INIT_VIDEO ) < 0 ) {
        printf( "SDL could not initialize! SDL_Error: %s\n", SDL_GetError() );
    } else {
        //Create window
        window = SDL_CreateWindow( "Hello SDL", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, SCREEN_WIDTH, SCREEN_HEIGHT);
        if( window == NULL ) {
            printf( "Window could not be created! SDL_Error: %s\n", SDL_GetError() );
        } else {

            renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED);

            SDL_RenderClear(renderer);
            SDL_RenderPresent(renderer);

            SDL_Delay(3000);
        }
    }

    SDL_DestroyRenderer(renderer);
    SDL_DestroyWindow(window);

    SDL_Quit();

    return 0;
}
gcc -g -o hello_sdl hello_sdl.c `sdl2-config --cflags --libs`

使用した関数は以下。メモっておく。
-> SDL_Init
-> SDL_CreateWindow
-> SDL_CreateRenderer
-> SDL_RenderClear
-> SDL_RenderPresent
-> SDL_Delay
-> SDL_DestroyRenderer
-> SDL_DestroyWindow
-> SDL_Quit

環境設定終了

とりあえずこれでSDL2が使用できるようになった。次からは、この環境でゲーム作りに必要なことを勉強していこうと思う。

Blog記事をVim+Markdownで書きたいと思った

私は普段何かを書くとき(プログラムなり文章なり)大抵Vimを使用している。 そんなこともあって、Blog記事もできれば書き慣れてるVimで書きたいと思った。 Hatenaブログの設定を見ると記事をMarkdown記法で書けるそうな。

記事はVim+Markdownで書こうと決めた。

ここからが、本題。

書こうと決めたは良いが、書くためには環境設定が必要だ。 Vimは、普段使っているがMarkdownを書く設定は入れてない。 今回は、VimMarkdownを書くための設定方法をまとめようと思う。

使用環境

DISTRIB_ID=Debian  
#DISTRIB_RELEASE=8.0  
DISTRIB_CODENAME=jessie  
DISTRIB_DESCRIPTION="Kona Linux 3.0"  

ちなみに、私が使っているマシンは15年も前に買った、NECのノートPC。 ぶっちゃけ、ウェブブラウジングもしんどいレベルのスペックの低さである。 しかしながら、長く使っているからかタイピングはこのマシンが一番しっくりくる。

dein.vim

githubにある(https://github.com/Shougo/dein.vim )説明文によると

Dein.vim is a dark powered Vim/Neovim plugin manager.

ということらしい

設定

早速、説明を見ながら設定していく

1. 必要要件としてはVimの8.0以上が必要なようだ
vim --version

で、確認したところ8.1が入っていた。要件は問題なし。

2. インストール用のディレクトリを用意する
mkdir ~/.cache/dein
3. インストール用のスクリプトを作る
cd ~/.cache/dein
curl https://raw.githubusercontent.com/Shougo/dein.vim/master/bin/installer.sh > installer.sh

ちなみに、インストール用のスクリプトを作るには、gitcurlがインストールされている必要がある
私の端末にはインストールされていなかったのでインストールを行った

sudo apt-get install git
sudo apt-get install curl
4. スクリプトを実行する
sh installer.sh ~/.cache/dein

スクリプトを実行すると、最後に以下のような設定が表示される。それを、.vimrcに設定する必要がある

""dein Scripts-----------------------------
if &compatible
  set nocompatible               " Be iMproved
endif

" Required:
set runtimepath+=/home/K38/.cache/dein/./repos/github.com/Shougo/dein.vim

" Required:
if dein#load_state('/home/K38/.cache/dein/.')
  call dein#begin('/home/K38/.cache/dein/.')

  " Let dein manage dein
  " Required:
  call dein#add('/home/K38/.cache/dein/./repos/github.com/Shougo/dein.vim')

  " Add or remove your plugins here:
  call dein#add('Shougo/neosnippet.vim')
  call dein#add('Shougo/neosnippet-snippets')

  " You can specify revision/branch/tag.
  call dein#add('Shougo/deol.nvim', { 'rev': '01203d4c9' })

  " Required:
  call dein#end()
  call dein#save_state()
endif

" Required:
filetype plugin indent on
syntax enable

" If you want to install not installed plugins on startup.
" if dein#check_install()
"   call dein#install()
" endif

""End dein Scripts-------------------------
5. deinで管理するプラグインを追加する

先ほど、.vimrcに追加した記述の中の

" Add or remove your plugins here:
call dein#add('Shougo/neosnippet.vim')
call dein#add('Shougo/neosnippet-snippets')

の下に、以下の3つを追加する

call dein#add('plasticboy/vim-markdown')
call dein#add('kannokanno/previm')
call dein#add('tyru/open-browser.vim')

これら、3つを入れることでMarkdown記法がVimでも容易にできるようになる。とのこと。

加えて、拡張子の設定を.vimrcにを入れる

autocmd BufNewFile,BufRead *.{md,mdwn,mkd,mkdn,mark*} set filetype=markdown

最後に、プラグインがインストールされているかチェックを行うために下3行のコメントを外す

" If you want to install not installed plugins on startup.
if dein#check_install()
  call dein#install()
endif

最終的に、今回.vimrcの中身は以下のようになった。

autocmd BufNewFile,BufRead *.{md,mdwn,mkd,mkdn,mark*} set filetype=markdown

""dein Scripts-----------------------------
if &compatible
  set nocompatible               " Be iMproved
endif

" Required:
set runtimepath+=/home/K38/.cache/dein/./repos/github.com/Shougo/dein.vim

" Required:
if dein#load_state('/home/K38/.cache/dein/.')
  call dein#begin('/home/K38/.cache/dein/.')

  " Let dein manage dein
  " Required:
  call dein#add('/home/K38/.cache/dein/./repos/github.com/Shougo/dein.vim')

  " Add or remove your plugins here:
  call dein#add('Shougo/neosnippet.vim')
  call dein#add('Shougo/neosnippet-snippets')

  call dein#add('plasticboy/vim-markdown')
  call dein#add('kannokanno/previm')
  call dein#add('tyru/open-browser.vim')

  " You can specify revision/branch/tag.
  call dein#add('Shougo/deol.nvim', { 'rev': '01203d4c9' })

  " Required:
  call dein#end()
  call dein#save_state()
endif

" Required:
filetype plugin indent on
syntax enable

" If you want to install not installed plugins on startup.
if dein#check_install()
  call dein#install()
endif
""End dein Scripts-------------------------
6. プラグインのインストール

最後に、設定に加えたプラグインをインストールして終了
vimを起動して以下のコマンドを打つ

:call dein#install()

2018/10/08(月) 追記
Vimで書いたMarkdownの記事をプレビューするためのコマンドは以下

:PrevimOpen

設定終了!

長々と書いてきたが、これで設定終了。Vim+Markdownの環境ができた。
今回のこの記事も早速設定した環境で書いているが中々快適に使えている。
この記事のように今後も勉強したこと(調べたこと)をまとめていければ良いなと思う。