PythonとC#でSDL2やってみた

C#の勉強をかねてSDL2をつかったちょっとしたデモを作ってみた

# できたもの

https://gitlab.com/mkiuchi/sdl2samples

# 概要

## SDL2とは？

ゲームやマルチメディアアプリケーションで使うようなライブラリで、高速に描画したり、3D、音声などを扱うことができる。マルチプラットフォームが売りで、Linux, Windows, Mac, iOS, Androidなどに対応している。SDL2自体はCで書かれているが、有志による多数の言語バインディングがある。SDL2ではハードウェアアクセラレーションに対応していて、GPUを使った処理を行うことができる。

・・・とここまでが[公式の説明](https://www.libsdl.org/)。

多くの言語バインディングがあることは事実なのだが、こういうもののあるあるとして、他の言語バインディングではドキュメントがpoorだったり、独自の拡張が施されていたりなど、それぞれのバインディング自体に差があることは否めない。過去Gtk2のPerlバインディングでアプリを作ったこともあったが、その時もいろいろ苦労した記憶がある。Rootの言語以外で使おうとしたときはそういうこともあるということは頭に入れておいたほうがストレスが軽減されていいと思う。

## Pythonバインディング(python3-sdl2)

公式ページ: https://pysdl2.readthedocs.io/

- 割とドキュメントがしっかりしている。解説付きサンプルもあり、最初のアプリを動かすまでに戸惑うことはあまりない
- [sdl2.ext パッケージ](https://pysdl2.readthedocs.io/en/0.9.13/modules/sdl2ext.html)で独自の拡張が行われていて利便性が向上している
- 処理速度はイマイチ。これはSDL2の問題というよりはPythonそのものの問題かもしれない

## C#バインディング(SDL2-CS)

公式ページ: https://github.com/flibitijibibo/SDL2-CS

- 独自のドキュメントはまったくなく、公式のドキュメントを使ってねというスタイル
- 独自の拡張はない
- 処理速度はPythonと比べれば断然速い

# 開発をはじめるための初期設定

今回いずれも Ubuntu 23.04 Desktop を使ってサンプルを作成した。

## Python: python3-sdl2

```shell
sudo apt install python3-sdl2
```

helloworldはこんな感じ

```python:hellosdl2.py
import sdl2
import sdl2.ext

sdl2.ext.init()
window = sdl2.ext.Window(
                    "Hello SDL2",
                    size=(640, 480),
                    flags=(sdl2.SDL_WINDOW_SHOWN))
loop = True
while loop:
   for e in sdl2.ext.get_events():
      if e.type == sdl2.SDL_QUIT:
         loop = False

```


## C#: SDL2-CS

```shell
sudo apt install dotnet-sdk-7.0 libsdl2 libsdl2-image
mkdir <projectdir>; cd <projectdir>
dotnet new console  # .NETコンソールアプリのボイラープレートを生成
dotnet add package SDL2-CS.NetCore
cd csharp/bin/Debug/net7.0; ln -s /usr/lib/x86_64-linux-gnu/libSDL2-2.0.so.0 ./SDL2.dll.so
cd csharp/bin/Debug/net7.0; ln -s /usr/lib/x86_64-linux-gnu/libSDL2_image-2.0.so.0 ./SDL2_image.dll.so
```
↑この方法だとUbuntu由来のバイナリが含まれるのでいわゆる[ライセンス感染](https://ja.wikipedia.org/wiki/%E3%83%A9%E3%82%A4%E3%82%BB%E3%83%B3%E3%82%B9%E6%84%9F%E6%9F%93)の可能性がある。配布用には[公式のライブラリ](https://github.com/libsdl-org/SDL/releases/latest)を使ったほうがいい

helloworldはこんな感じ

```c#:hellosdl2.cs
using SDL2;

_ = SDL.SDL_Init(SDL.SDL_INIT_EVERYTHING);
window = SDL.SDL_CreateWindow(
                "Hello SDL2",
                SDL.SDL_WINDOWPOS_UNDEFINED, SDL.SDL_WINDOWPOS_UNDEFINED,
                640, 480,
                SDL.SDL_WindowFlags.SDL_WINDOW_SHOWN);
var loop = true;
while (loop)
{
   while (SDL.SDL_PollEvent(out SDL.SDL_Event e) != 0)
   {
      switch (e.type)
      {
         case SDL.SDL_EventType.SDL_QUIT:
            loop = false;
            break;
      }
   }
}
SDL.SDL_Quit();
```

# サンプルコード

実際に動くサンプルコードを一通り作ってみたので参考にしてみてください

https://gitlab.com/mkiuchi/sdl2samples

# 一通り作ったあとのお気持ち

- Python
    - 取っ掛かりも手っ取り早くコード量もコンパクト
    - サンプルも多く情報もあるので、困ったらぐぐれば前には進める
    - オブジェクト数が増えてくると重くなってきてイマイチ。本気アプリ作るときにはPythonの高速化に時間を使うよりはC#なりで書き直してしまったほうがいいのかもしれない
- C#
    - マジで情報がない。Ubuntuで.NETで開発している人世界でオレ1人なんじゃないかってくらい情報がない。特に .NET (Core?) 6以降くらいで大きく中が変わったようで、最初はSDL2のパッケージを入れるのにも苦労した。サンプルコードもほとんど見つからないので「どうすりゃいいんだこれ・・・」と悩む時間が多い
    - Microsoft公式.NETリファレンスはわけがわからない。日本語明瞭意味不明瞭。ブログ記事は参考になりました
    - 日本人でSDL2+C#でアプリ作ってる人ほとんどいないような気がする。唯一見つけたのが[みにおんさん](https://mini09memo.blog.fc2.com/blog-entry-12.html)という方。記事読ませていただきました。
    - そもそもライブラリが本家Cのラッパーなので、ほとんどの関数の返り値がポインタになっていて、プロパティがほしいときにはいちいちオブジェクトに変換してあげないといけないのが手間
    - アプリの実行速度はとても速い。Pythonでの苦労はなんだったんだというくらいバカっ速い。サンプルコードでボールの数を40000個とかにすると一目瞭然
    - 別の記事だとVisual Studioでしかステップ実行などができないというのを見かけたがそんなことないUbuntu+VSCodeだけでステップ実行や変数のウォッチなどのデバッグ実行はできる

# さいごに

正直C#覚えたら、UnityなりGodotなりのリッチなフレームワークを使ったほうがいいと思います・・・。SDL2は薄くていいかもしれないけど正直しんどい。

一応参考にしたサイト

- https://jsayers.dev/tutorials/
- https://www.freepascal-meets-sdl.net/chapter-4-imagestextures/
- https://devblogs.microsoft.com/dotnet/net-core-image-processing/
- https://devblogs.microsoft.com/dotnet/hardware-intrinsics-in-net-core/