iPhone/iPadでゲームを開発しよう - その2

さて、OpenGL ES2の性能テストをすることにしたわけですが、まずテスト用のモデルを用意しないといけません。ここでは、あまり深く考えずに「ジーラ君」を採用しました:)

ジーラ君」とはこんなモデルですhttp://lwpinball.wordpress.com/2010/12/08/iphone/

さて「ジーラ君」はLightWave3Dで作ったモデルなので、このデータをOpenGL ES2でレンダリングできるデータに変換しないといけません。ここではBlenderを使いました。BlenderプラグインPythonで書く事ができる素敵仕様だからです :D

まずBlenderプラグインの中からWavefront .obj fileへの出力を行うものを探して、これを少し書き換えてCのstaticデータを書き出すようにします。

次にXcodeに用意されているOpenGL ES Applicationテンプレートを使ってアプリを作り、これを書き換えて「ジーラ君」がiPhoneの画面に出るようにします。この時点では色も質感も無い石膏像のような表示でしたが、かかった時間は1日ちょっと。まずは快調な滑り出しです ;^)

でも、この調子が続いていたのなら12月8日の私の写真があんな小汚くならなかったんだよな〜 :(

つづく

iPhone/iPadでゲームを開発しよう - その1

Pinball Tristanの開発過程を思い出しながらiOSのゲーム開発について少し書いてみようと思います。

まず最初に行ったのがOpenGL ES2の性能テストです。ピンボールゲームの場合は60FPSの維持が最優先ですので、そのために3Dモデルの最適化が必要になるのですが、それにはドロップフレーム無しでデバイスが描画できるポリゴンやテクスチャの量を知りたくなるのです。最初は簡単に済むと思っていたのですが・・・これが思ったより大変でした・・・開始早々いきなり想定外 :p

つづく

Pinball TristanをiOSにリリースしましました

ここ半年ほど本業のピンボールゲームのiOS版を作っておりました。これは20年ほど前に開発したピンボールゲームを全面的に書き直したものです。

当時のコードもちゃんとありましたよ ;^)
といっても使えそうなものは一行もないわけなのですが・・・これだけ時間が経ってから自分の書いたコードを見るというのは面白いものですね :p。新しいTristanはiOSということでObjective-Cを使って書くのですが、20年前のコードを見ながら(仕様をリバースエンジニアリングするため)「当時すでにObjective-CNextStepがあったんだよな〜、継続は力なりってのはこのことか :D」などと考えておりました。
iOSObjective-CGCが使えないので書くのが少々面倒です。でもゲームの場合はGCでいきなり止まられるよりは遥かにいいです :) 一般アプリの場合にはRuby+Cocoa Touch+C(LLVM)とかあるとすごい楽になりそうだなと思いました(もしかして、もうあります?)

開発ツールはXcode4, LightWave3D, Ypsilon, Photoshop, Illustratorを使っています。YpsilonはLightWave3Dのオブジェクトファイルを読み込み、iPhoneGPUとOpenGLES2に最適化したレンダリングデータとコードを自動生成するために使いました。
ハードウエアとしてはMacと実機はもちろんですが、こんなものが必要でした・・・

これは印刷用フィルムの網点を見るためのルーペです。これを使わないとiPhone4のピクセルが見えないんです・・・
Retinaディスプレイ恐るべし :O

Pinball Tristan App Store 日本語ページ
Pinball Tristan App Store 英語ページ

MAD DAEDALUS Released!

MAD DAEDALUSリリース開始しました。

どんなゲームなのかは、下記のURLでみられますよ :)
http://www.littlewingpinball.com/doc/ja/special/index.html

ちなみにMAD DAEDALUSはC++で35,000行ほどです :D

とりあえずはご案内まで!

Recent conditions

ここしばらく本体となるピンボールゲームの開発に忙しくイプシロン関連の更新が滞っております :(
新タイトル「MAD DAEDALUS(仮称)」が完成しましたら、その成果をイプシロンにフィードバックいたします、どうぞしばらくお待ち下さい m(_ _)m

JelloBench - A practical garbage collection benchmark program

Shibuya Lisp TT#2の発表の時に使った"JelloBench"です :)
テクスチャマッピングされたポリゴンをSDL/OpenGLで描画しています。
プログラムはすべてSchemeで書かれていますが、Intel Core2 2.4GHzのLinuxで3500フレーム/秒以上の表示が可能です。

D

JelloBenchの実行には開発版のイプシロン(http://code.google.com/p/ypsilon/)とSDL, SDL_image, SDL_mixerが必要です。MacOSXでは最初にSDL.framework, SDL_image.framework, SDL_mixer.frameworkをインストールしておいてください。インプシロンのビルド時にSDL初期化用のdylibが作成され/usr/local/lib/ypsilon/に自動的にインストールされます。

JelloBenchは'example'にカレントディレクトリを移動してから'ypsilon jello.scm'で実行してください。

今回追加したMacOSXSDLサポートにはid:kazuya_aさんがypsilon+SDL+Mac OSX!に紹介された方法を使っています。これによりSDL専用のイプシロンをビルドする必要がなくなりました。感謝です!:)

(6/13追記:動画を再エンコードしました)

YpsilonがPS3で動くようになりました

野田 開さんのご厚意によりPS3SSH経由で提供して頂きました m(_ _)m
32bit/64bit対応でFFIもサポート済みですよ。 :)

libspe2を使ったテストプログラムを作ってみました。
svn trunkのイプシロンPS3に入れると動きます^^b

#!/usr/bin/env ypsilon
#!r6rs

;; ps3-cell-demo.scm
;; tested on PS3 Linux

(import (rnrs)
        (only (core) system format iota)
        (ypsilon ffi)
        (ypsilon concurrent)
        (ypsilon cell libspe2))

(define spe-code
  "
  #include <stdio.h>
  int main(unsigned long long spe_id, unsigned long long pdata) {
    printf(\"SPE:0x%llx sleep for 2 second\\n\", spe_id);
    sleep(2);
    printf(\"SPE:0x%llx exit\\n\", spe_id);
    return 0;
  }\n")

(define NULL 0)
(define source-file "spe_example.c")
(define object-file "spe_example")

(define make-spe-program
  (lambda ()
    (when (file-exists? source-file) (delete-file source-file))
    (call-with-port
      (open-output-file source-file)
      (lambda (port)
        (put-string port spe-code)))
    (unless (= (system (format "spu-gcc ~a -o ~a" source-file object-file)) 0)
      (error 'make-spe-program "unexpected error"))))

(make-spe-program)
(newline)

;; sequential

(let ((image (spe_image_open object-file)))
  (when (= image NULL) (error 'spe_image_open "unexpected error"))
  (for-each (lambda (n)
              (let ((context (spe_context_create (+ SPE_EVENTS_ENABLE SPE_MAP_PS) NULL)))
                (when (= context NULL) (error 'spe_context_create "unexpected error"))
                (spe_program_load context image)
                (let ((entry (make-c-int SPE_DEFAULT_ENTRY)))
                  (format #t "-- kick sequential run ~a/6\n" n)
                  (when (< (spe_context_run context entry 0 0 NULL NULL) 0)
                    (error 'spe_context_run "unexpected error"))
                  (spe_context_destroy context))))
            (iota 6))
  (spe_image_close image))

(newline)
(newline)

;; parallel

(let ((image (spe_image_open object-file)))
  (when (= image NULL) (error 'spe_image_open "unexpected error"))
  (let ((threads
         (map (lambda (n)
                (format #t "-- kick parallel run ~a/6\n" n)
                (future
                 (let ((context (spe_context_create (+ SPE_EVENTS_ENABLE SPE_MAP_PS) NULL)))
                   (when (= context NULL) (error 'spe_context_create "unexpected error"))
                   (spe_program_load context image)
                   (let ((entry (make-c-int SPE_DEFAULT_ENTRY)))
                     (when (< (spe_context_run context entry 0 0 NULL NULL) 0)
                       (error 'spe_context_run "unexpected error"))
                     (spe_context_destroy context)))))
              (iota 6))))
    (format #t "== wait for all SPE exit\n")
    (for-each (lambda (x) (x)) threads))
  (spe_image_close image))

このプログラムは、最初に一つのSPEで順次実行し、次に6個のSPEで並列実行します。

$ ypsilon example/ps3-cell-demo.scm 

-- kick sequential run 0/6
SPE:0x101b4340 sleep for 2 second
SPE:0x101b4340 exit
-- kick sequential run 1/6
SPE:0x101b4340 sleep for 2 second
SPE:0x101b4340 exit
-- kick sequential run 2/6
SPE:0x101b4340 sleep for 2 second
SPE:0x101b4340 exit
-- kick sequential run 3/6
SPE:0x101b4340 sleep for 2 second
SPE:0x101b4340 exit
-- kick sequential run 4/6
SPE:0x101b4340 sleep for 2 second
SPE:0x101b4340 exit
-- kick sequential run 5/6
SPE:0x101b4340 sleep for 2 second
SPE:0x101b4340 exit

-- kick parallel run 0/6
-- kick parallel run 1/6
-- kick parallel run 2/6
-- kick parallel run 3/6
SPE:0x101b5230 sleep for 2 second
SPE:0x101b5170 sleep for 2 second
SPE:0x101b52f0 sleep for 2 second
SPE:0x1020c248 sleep for 2 second
-- kick parallel run 4/6
-- kick parallel run 5/6
== wait for all SPE exit
SPE:0x10223910 sleep for 2 second
SPE:0x10237e48 sleep for 2 second
SPE:0x101b5230 exit
SPE:0x101b52f0 exit
SPE:0x101b5170 exit
SPE:0x1020c248 exit
SPE:0x10223910 exit
SPE:0x10237e48 exit

うまく動いているようです :D

ところでpowerpcはわたしの好きなCPUの一つなのですが、やはりあのニーモニックは微妙・・・思い出せばなんでもないことなんですけどね :p

SSH経由なのでエディタはemacsを使いました。どこでも同じものが動くというのは素晴らしいことです!でも・・・あいかわらず・・・普段はほとんど使っていません(笑