mieki256's diary



2013/12/01() [n年前の日記]

#1 [anime][prog][neta] 声優さんの演技と3回繰り返しとemacsのdmacro

物語シリーズを見ていたら、カイキ?なるおじさんが、鏡の前で自問自答するシーンがありまして。 「〜はどうだ?」「ノーだ」「〜はどうだ?」「ノーだ」…コレを延々繰り返す、というシーンだったのですけど。

おそらく脚本には、 「ノーだ」「ノーだ」としか書いてないと思うんですけど。声優さんの演じるソレは、同じ 「ノーだ」なのに微妙にバリエーションがついていて。たぶん即興で、次々に引き出しを開けていくんだろうなと。声優さんってスゲーと感心してしまったのでした。

いや、もしかすると、どれも同じ 「ノーだ」で聞こえるように演技してたのかもしれないけど。だったらゴメンナサイ。

さておき。そのシーンを見ていて、「おや?」と思った部分があって。1回目と2回目は、似た感じの 「ノーだ」だったのですが、3回目からちょっと演技が変わってきて。…たしかそうだったと思うけど。

なるほど、これは「3回繰り返しの技」だなと。1回目と2回目は似たようなソレで、3回目から飛躍するアレ。こういうところでも使えるのかと…。

そこでふと唐突に。「この、3回繰り返しって、プログラミングにも利用できないのかなー」と思ってしまったり。でもまあ、「お前何言ってんだ。バカじゃねえのか」と言われそうな話ですわな。全然ジャンルが違うだろ。何考えてんだ俺。

が、そこで、「アレ? もしかして?」と思い出した。emacs の dmacro って、ソレじゃないのかと。

1回目では、そのキー操作を人間が繰り返したいと思っているのか、emacs側では判断しようがない。しかし2回目なら、そこでキー操作が繰り返されていると判断できる。なので、3回目からは、dmacroのショートカットキーを叩くだけで、今まで繰り返してたキー操作が再生される。

なるほど、それで3回繰り返すのかと、なんとなく分かったようなな気分になってきたのでした。dmacroの処理内容と同じことを、娯楽コンテンツを見ているときの人間の脳も行っているのだろうと。2回目で、繰り返しが認知されるから、3回目で変化があれば面白く感じる…。そういう仕組みかー。

「それがなんなの?」「今頃そんなことに気付いたの? バカじゃないの?」と言われそうですね。スイマセン。自分、バカなんで…。今頃気がつきました…。

しかしコレ、ゲーム仕様にも利用できたりもするのかしら。二段ジャンプより三段ジャンプのほうが感覚的に気持ちいいとか。パンチを、ビシバシ、ビシバシ、より、ビシバシパーンのほうが気持ちいいとか。爆発音が、ボンボーン、より、ボンボンボーンのほうが気持ちいいとか。

いやー、ソレ、どうなんだろ。短い時間で行われるソレは、繰り返しが行われてると認知しにくいから、少し違ってくるのかな。もしかすると、同じ「魔力を持った数字」でも、7とか12のほうが効果があったりするのかしら。ボボボ、ボボボ、ボーン、とか。…いやいや。短い時間内に行われるソレは、どちらかというと音楽的なリズムのほうが絡んできそうな予感。

ちなみにdmacroってのは。 :

dmacro ってのは、キー操作の繰り返しを動的に行える拡張機能…という説明でいいのかどうか…。

_Dynamic Macro

コンピュータ上で動く各種入力システムに関して次々に成果を上げている Toshiyuki Masui 氏が作ったシステム、という説明でいいのかしらん。

本家は、emacs用の拡張として公開されてますが。自分は、連番にも対応した、 _ndmacro.l を、xyzzy 上で使わせてもらっていたり。ちなみに、emacs 用にも、 _ndmacro.el があります。

一応ざっくりと「売り」を説明。

一般的なエディタ上で、キー操作を繰り返したい場合は、えてして「キーボードマクロ機能」を使うのですが。
  1. 「キーボードマクロ記録開始」のショートカットキーを押す。
  2. 繰り返したいキー操作をする。
  3. 「キーボードマクロ記録終了」のショートカットキーを押す。
  4. 「キーボードマクロ再生」のショートカットキーを押す。記録した操作が再生される。

でも、人間って、頭が悪いわけですよ。「さあ、これから、このキー操作を何度も繰り返すぞー」と、あらかじめ気づけない時がある。カタカタ打ち込んでる最中に、「アレ? なんか俺、さっきから同じキー操作を繰り返してるぞ?」と、繰り返しのキー操作を始めちゃってから、ようやく気付く時が多い。

そんな時でも、dmacro なら大丈夫。dmacro を割り当てたショートカットキーを押すだけで、自分がソレとは知らずにやっていたキー操作の繰り返しを再生してくれるわけです。

さらに。「キーボードマクロ機能」は、3つのショートカットキーを使い分けないといけませんが、dmacro なら、覚えておくべきショートカットキーは、たったの1つ。それだけで、全く同じことができちゃう。

この dmacro に慣れてしまうと、一般的なキーボードマクロ機能は、ツラくてツラくて…。 *1

他のエディタも、dmacro 相当を実装すればいいのに…。

*1: まあ、一般的なキーボードマクロ機能は、マクロをファイルとして保存して、後で使いまわすことができるというメリットもあるんですけど。フツー、そこまでしなきゃいけない場面ってあまり無いので。

#2 [anime] 聖闘士星矢Ωの次回予告にシビレタ

次回は兄さんが頑張る回らしいのだけど。次回予告が…。

「闘争こそ本性! 煉獄こそ故郷(ふるさと)!」
「紅蓮の炎で体を冷やし、不死鳥は歩む…修羅の道を!」

ですよ。炎で体を冷やしちゃうあたりで、シビレました…。これぞ少年漫画ノリ。カッコよすぎて、逆に笑えてきたぐらい。いいぞ、もっとやれ!

こういうの、誰が書いてるんだろう。よくまあ、こんな文章、思いつくものだなあ…。

2013/12/02(月) [n年前の日記]

#1 [xyzzy] xyzzy の設定ファイル内を整理

~/.xyzzy から、site-lisp/siteinit.l にコピペして、~/.xyzzy を少なめに。そうすることで、起動をちょっと早くしたいなと。

siteinit.l のバイトコンパイルができなくて悩んだり。どうも一部の関数がエラーを出すようで。~/.xyyzy に書いておくと通るのに、siteinit.l に書くと通らない。なんでや…。仕方ないので ~/.xyzzy に残したり。ワケワカラン…。

emacs系の設定ファイルを弄ってると、どんどん時間が経ってしまいますな…。奥が深いぜ…。いや、奥が深いとか言ってちゃダメなんだけど。ソレ、トラップなんだけど。

2013/12/03(火) [n年前の日記]

#1 [game][anime][neta] 「ホビット」について少し調べてたり

小人がウロウロするゲームを作れないかなと妄想してしまったのだけど、タイトルで悩んだり。

小人と言えば「ホビット」だよなと。しかし「ホビットなんとか」ではそのまんまだなと。

ググってみたら、「ホビット」は指輪物語で登場した名称だそうで、そのまま使うと訴えられてしまうから、様々な作品が独自名称を作ってどうにかしてるらしい。ならば自分も、多少もじって、もうちょっと違うタイトルを捻り出さないといかんのだろうか、みたいなことをもやもやと。

「トロール」が「トトロ」になったソレを応用すれば、「ホビット」は「ホホビ」になるけど、その名称はアリだろうか。…ナシだろうな。発音しにくいから。

「トロール」が「トトロ」になるなら、「エルフ」は「エエル」になるし、「ドラゴン」は「ドドラ」になってしまうのだろうな。…む。「ドドラ」はアリな気がする。「ドドラスレイヤー」「ドドラクエスト」「燃えよドドラ」。アリじゃないかな。まあ、ググってみたら、既にあちこちで使われてるようではあるけど。

「エエル」も「エルル」ならアリになるかも。「エルルを狩るモノたち」。アリかもしれない。…なんかそういう名前のキャラが居たような気もするけど、何の作品に出てきたキャラなのか、自分は知らなかったり。

「ホビット」に話を戻して。

少しもじって「チョビット」とか。…CLAMP作品でそういうタイトルがあったような気も。ググってみたら「ちょびっツ」だった。微妙に違ってた。それはともかく、「チョビット」はさすがにあちこちで使われてるっぽい。

小人なんだから「コビット」とか。これもたくさんあるみたい。Google画像検索したらソレらしいのが山のように。

「ドビット」「モビット」「ノビット」等でググってみたが、ズラズラ出てきた。なかなか「コレだ」という名前が思いつかないなあ。

見た目の問題も。 :

自分の頭の中では、とんがり帽子のメモルみたいなキャラがウロウロしているイメージなのだけど。考えてみたら、あの、とんがり帽子ってスゴイなと。アレを被ってるだけで、そういう種族だと視覚的に分かる。おそらく元になった作品があるのだろうけど。

メモルは、ホビットという分類とは少し違う気がする。アレは何の種族扱いが妥当なんだろう…。本編中では宇宙人ってことになってるけど、地球上では妖精あたりに分類されるのだろうか?

とんがり帽子に相当するアイテムって何か無いものか。ソレをつければ小人だか妖精だかに即座に思ってもらえる、てな便利アイテム。何か無いか…。

メガネとか。って、それだと「メガネブ」か「境界の彼方」になっちゃうか。そもそも、つけてるのかつけてないのか、ちょっと分かりづらいな。ドット絵になったら、ますます分からない。

ちょんまげとか。…皆「サムライ」に見えちゃうな。

そのへん考えていくと、アリエッティの洗濯バサミは上手いなと思えてきたり。アクセントにもなってるし、一目でスケール感も分かる。思いついた方は天才じゃないのかと…。その後、あまり有効活用されてないのが残念だけど。まあ、そのうちジブリがTVアニメも手掛けるスタジオに変貌していった際には、アリエッティのTVシリーズだって出てくるかもしれないから、その時は色々活用されるんだろう…。いや、今でも、あの企画だけ別スタジオに渡してTVアニメにしちゃうのもアリじゃないかと思えたりもするけど。日本アニメーションとかトムスとかテレコムとかそのへんに。「企画原案 宮崎駿」の文字は、今ならまだ、売りになるんじゃないのかと…。いや、「企画協力」のほうがいいのかな。原作がある作品でもあるし。

それはともかく、便利アイテム、何かないか。

頭にコン○ームを被ってる妖精種族とか。ダメか…。スケール感は一発で分かりそうだけど。頭のてっぺんで、ぴょこっと飛び出したアレも、アクセントになりそうだけど。ダメだよな…。

#2 [zatta][neta] 国旗掲揚とか国歌斉唱とかを強制するアレ

急にふと思いついたのでメモ。ある種のバカ妄想だと思いますけど。

今になって考えたみたら、「愛国心」云々って、左翼を分類してブラックリストに入れるための「釣り針」「踏絵」でしかなくて、ソレを言ってる人達も本気でそういう効果があるとは考えてなかったんじゃないか、と思えてきたり。

そういうアレを強要することで、3つの種族が明らかになるわけで。 タイプAは、ほっておいていい。こちら側から何も言わなくても勝手にそういうことを始めかねない人達だし。

タイプBも、ほっておいていい。「周りがやってるから俺もやらないとな」「長いものには巻かれろ」派だから、体制側から何か理不尽な話を強要されてもそのまま受け入れる。奴隷体質だから、気にしなくていい。

タイプCが、面倒臭い。体制側のアレコレにいつも反発する。こういうのは、日本社会には要らない。あぶり出して、ブラックリストに載せておきたい。

あぶり出すための策としては…。何かを強要してみて、その反応を見ればいい。あまり変なことを強要するとこちらの見識が疑われるから、国際的には特に問題になってないアクションがいい。せっかくだから、実施理由の中にも、彼等がより大きく反応するキーワードを混ぜておこうか。「愛国心」なんて適切じゃないか。きっと、蜂の巣をつついたように騒ぎ始めるだろう…。

てなことを考えて、そういうアレをしたのかなと、今頃になって思えてきたり。

だって、あんなアクションで「愛国心」が育つとか、多少なりとも頭の中でロジック組んで考えることができる人間なら、非論理的で理由として成立しないと分かりそうなものだし。一応上の方に居るはずの人達が、そこまで頭が回らない人達とも思いたくないので、つまり、最初からその理由はフェイクだったんじゃないかと。全然別の部分で、効果が得られることを期待してたんじゃないか。

大人達のそういう思惑で、集会のたびにソレを強要される子供達の姿を想像して、日本ってやっぱり変な国だなと思えてきたけれど、まあ、そういう国に生まれちゃったんだから仕方ないよな…。能力がある人は、さっさと国外に脱出している現状もあるわけだから、「こんな国は嫌だ」と思ったら、語学等を勉強して脱出してほしいなと思えてきたり。

や。コレ、自分の勝手な邪推に過ぎないので、実際はどうなのかさっぱり分かりませんけど。…本気で「愛国心が育つ」と上のほうが思ってたら、それもそれで、もっと絶望的な気分になってくるので、まだそういう理由で、だったら、多少はマシなほうだったりするのかな、どうかな、みたいな。

#3 [zatta][neta] 怒鳴り声を上げるデモは本質的な部分でテロに似ているという話

なんか与党の某政治家さんがそういうことをblogで書いてプチ炎上、みたいなニュースを見かけて。

自分も、「たしかにそうだなあ。それは妥当な見方だなあ」と思ってしまったり。

デモをするところまでは問題無いけど、ていうかソレは民主的な活動だと思うけど。怒鳴り声を上げるのは違うよなと。怒鳴り声を浴びせて、相手に恐怖心を抱かせて、その恐怖心で相手の選択を変えようとしてるのであれば、それは、相手に恐怖心を抱かせて、その恐怖心で自分達の思った通りの状況に持っていこうとする、テロ行為が持つ本質と、たしかに似てるよなと。まるっきり同じとは言わないけど、似てるとは言えそう、な気が。

なので、「世間様から見たら言い方はかなりマズいのだろうけど、たしかにその通りかも」と、自分は思ってしまったのでした。

とはいえ、怒鳴りたくなる気持ちも、なんとなく分かってしまうあたりも、なんだかややこしくて。

例えば、自分達の意見・主張を提出できる場が用意されていて、かつ、その意見を吟味・検討して、体制側の方針を若干でも修正してもらえるシステムがある ―― そういう希望があるならまだしも、実際にはその可能性はほとんどないわけだし。一応、自身で立候補して政治家になるとか、選挙で民意を反映させるとか、手管はちゃんとありますよ、という建前にはなっているけど。庶民レベルで、ソレを実現できる可能性は低いのが実状だし。そりゃ、デモの最中に怒鳴りたくもなるよなと。要するに、そこに“希望が無い”から、怒鳴ってしまうのかなと。

テロだって同じなのだろうと。自分達の主張が通る見込みがないから、超法規的手段・暴力的手段を使ってどうにかしよう、もうこのぐらいしか手は残ってない、と追い込まれていって、テロに走るのだろうし。

ということで、怒鳴り声を聞きたくなかったら、怒鳴らなくても意見が通る部分だってこのとおりありますよ、そっちを活用してみてくださいよ、と嘯くぐらいの努力は見せておかないと、てな気にもなってきたり。もっとも、体制側には、苦労して政治家や官僚になったという自負もあるだろうから、「意見を通したかったらお前達も俺のように努力したらええんや」「なんで努力もしてない人間の意見なんぞ聞いてやらにゃいかんのや」という気持ちが根底に…てなところもありそうな気もしてきたり。

まあ、色々と難しいですな。人間社会って難しい。ていうか面倒臭い。

2013/12/04(水) [n年前の日記]

#1 [ruby] Rubyをアップデート

アップデートなのかアップグレードなのか分からないけど。

最近 Ruby を全然使ってないなと。ちょっと触ってみようかなと。しかしその前に、使ってる Ruby その他が古くなってたりしないかなと気になってきて。今まで Ruby 1.9.3 p429 を入れてたけれど、p484 が公開されてたので、この際最新版に、みたいな。

でも、どうやってアップデートしたらいいのやら。

Rubyのインストール方法はあちらこちらで丁寧に説明されてるけど。アップデート方法は、ググっても情報が出てこない。実は初心者泣かせな部分だったりしないのかなコレ。ていうか自分、何年間、初心者レベルのままなんだか。まあ、時々思い出したように触ってるレベルなので…。

ちなみに環境は Windows7 x64。 _RubyInstaller for Windows を使っていたり。

よく分からないけど、とりあえず、rubyinstaller-1.9.3-p484.exe を実行して上書きインストールをしてみたり。

一応、ruby -v で表示されるバージョンは最新版になったように見える。コレで問題は起きないのだろうか…。どうなんだろ…。

ついでに、Ruby 2.0.0 もインストールしてみたり。rubyinstaller-2.0.0-p353.exe をDLして実行。

DevKit も入れなきゃいけないけど、コレは Ruby 1.9.x 以下と 2.0.x 以上で、別のモノを入れないといけないらしい。
Ruby の複数バージョンの切り替えには、pik を使用。以下の記事が参考になりそう。

_Rubyアソシエーション: 複数のRuby環境の構築

#2 [ruby] Ruby 2.0.0 + Rubygems で色々インストールしていったけど色々問題が

環境は、Windows7 x64。

unable to convert って何だろ。 :

gem install 〜 で色々インストールしてみたけど。unable to convert なるメッセージがズラズラ出てきて。コレ、どうすればいいんだろう…。Windows環境だからこうなるのかな? *.so をどうこうする際に出ているようでもあり。
chcp 65001 でDOS窓をUTF-8にすると改善するという話も見かけたけど、試してみても効果無し。うーん。

ライブラリがまだ揃ってないみたい。 :

wxRuby や Ruby/SDL 等、Ruby 2.0用の .gem が無くて、どうしようかなと。

なんだか、Ruby も Python と同じ状況になってるような。あちらも、各ライブラリが Python 3.x に対応してくれない問題があって…。

Ruby の解説ページでは、「安定版は、2.0.0」「これから使うなら、2.0.0」という話になってるみたいだけど。ライブラリが追従してこないのではな…。自分はよく知らないんだけど、おそらく Rails なるソレさえ対応してれば他はイラネ、てな人が多いから、そういう話になっちゃうのかなと想像したり。

いや、考えてみたら、仮に現状では使い物にならないとしても、「安定版は2.0.0」と言っておかないと、各ライブラリの作者さんも対応しようという気にならないのか…。そのあたりの扇動(?)って、なんだか大変だなあ。

昔書いたスクリプトソースが、現行版ではライブラリが無いから動かない、とか、ちょっと悲しい…。でも、互換性ばかり気にして言語の改善が停滞しちゃったらソレもソレでアレだし。そのあたりの舵取りって、色々と難しそう。頭が下がります。

Ruby/SDLのインストール作業を試してみたけどやっぱりダメだった。 :

Ruby 2.0.0 上で gem install rubysdl-mswin32-1.9 を試してみたら、スルスル入ったように見えたので期待してしまったり。

途中で「install_rubysdl.bat を実行してdllをコピーせよ」と言ってくる。install_rubysdl.bat は、Ruby 2.0.0 インストールフォルダ\bin\ 以下にコピーされてるので、そのまま実行できるはず…。と思いきや、実行するとエラーが出て。

仕方ないので、Ruby 2.0.0インストールフォルダ\lib\ruby\gems\2.0.0\gems\rubysdl-mswin32-1.9-2.1.1.1\ をカレントフォルダにして、ruby install_rubysdl.rb を実行。dll が、あちこちにコピーされた。

これで Ruby/SDL が使えるようになったかなと思ったけれど、既存のスクリプトを実行しようとすると「モジュールが見つかりません」と怒られた。やっぱり、Ruby 1.9 用のソレを Ruby 2.0 に入れるなんて無茶でしたか…。

もしかして gem instal rubysdl で行けちゃったりしないかな? …ダメだった。エラーが出る。

結論。Ruby 2.0.0 上で、Ruby/SDL は使えません。 :

現行版の Ruby では Ruby/SDL は使えないみたいです。

Windows + Ruby 2.0.0 上で Ruby/SDL が動かないということは…。SDLを使ってるらしい、 _MyGame、Miyako、StarRuby等、Rubyで使える2Dゲームライブラリもほぼ全滅 じゃないかな…。 *1

つまり現時点では、Windows上で Ruby 2.0.0 を使って2Dゲームを作ろうとしたら DXRuby 一択、ですね。

しかし、DXRuby は DirectX を使うライブラリなので、Windows上でしか動かない。ということは、Mac や *NIX では、Ruby 2.0.0 を使って2Dゲームは作れない、ということに。

かと思いきや。Mac + Ruby 2.0.0 なら Ruby/SDL が動いてるみたいで。えー。なんでー。Windows だけ置いてけぼりかよ…。まあ、あっちは BSD文化圏、かつ、SDL か OpenGL しか頼れるモノがないから、対応せざるを得ないのかしら。

何にせよ、Ruby 2.0.0 は色々と厳しいなと思いました。当面、Ruby 1.9.3 を使おうかなと。

Ruby 2.0.0 は、初心者が使うバージョンではない、ということですかね…。「このライブラリ、なんだか面白そう」と興味を持った際、Ruby 2.0.0 だと無駄にハマるから、使わない方がヨサゲ。初心者なら、「これからは 2.0.0 がオススメ」なんて言葉に耳を傾けちゃいけない。勉強用には枯れてるバージョンを使いましょう。と、言ってしまっていいのかもしれないなと。

もしかして、こういう話を、DXRuby Advent Calendar とやらで書けばネタになったのだろうか…。でも、DXRuby とは微妙にずれた話かな…。

*1: StarRuby は独自にSDLを使ってる・Ruby/SDLのラッパーではなかったと思うけど。どのみち更新は止まってるし。

#3 [prog] NetBeans IDE 7.4 をインストールしたのだけれど

プラグインを更新したら、メニュー等が英語表記になってしまった…。どうすれば日本語化できるのだろう…。

Pythonに対応させるプラグインをインストールした際に、他のプラグインもごっそり更新してしまったのが原因っぽい。Python のソレだけをインストールした後で、Python 用のURLを無効にしておけば大丈夫っぽい。NetBeansの日本語環境用プラグインは、日本語環境用のURLを見て更新があるかどうか調べるようで、そこに Python のソレを追加しちゃったから、英語環境用のURLを見ちゃったのではないか、と想像。

一応インストール手順についてメモ。 :

環境は、Windows7 x64。

_Welcome to NetBeans から辿って、 _NetBeans IDE ダウンロード に。今回は「すべて」の版を選択。netbeans-7.4-windows.exe をDLした。

netbeans-7.4-windows.exe を実行すると、何をインストールして何をインストールしないかが選べる。「カスタマイズ」ボタンを押して…自分の場合は、「Java EE」「Java ME」「Java Card〜」「C/C++」は使いそうにないので、そこはチェックを外した。他は試用してみたくなるかもしれないから入れておく。

Ruby用のプラグインをインストール。 :

公式では既にサポートされてないけど、一応今もメンテナンス?されてるらしい。ありがたや。

以下のページで解説されてたので、参考にして作業。

_NetBeans 7.4にRuby on Railsプラグインをインストールする手順 - Rails 雑感 - Ruby on Rails with OIAX
_NetBeans 7.3にRuby on Railsプラグインをインストールする手順 - Rails 雑感 - Ruby on Rails with OIAX

_Ruby and Rails - NetBeans Plugin detail から、NetBeans 7.4 を選んで、Download。今回は 1385326848_archive.zip というファイルがDLできた。コレを解凍しておく。

NetBeans 7.4 上で、ツール → プラグイン → ダウンロード済み → プラグインの追加 → 先ほど解凍したファイル内の updates\ 以下の *.nbm と *.jar を全部追加、してインストール。NetBeans の再起動が求められるので再起動。

新規プロジェクトを作る際に「Ruby」という項目が選べるようになるはず。

使用するRubyは、ツール → Ruby Platforms で設定できる。標準では JRuby しか入ってないので、自分の環境に入っている ruby.exe を追加していく。

デバッガに、Fast Debugger (ruby-debug-ide) てのを選べるとナイスなのだけど…。Rub 1.8.7 は ruby-debug-ide が、Ruby 1.9.3 は ruby-debug-ide19 があるので、gem だか Rubygems だかでインストールできるのだけど。Ruby 2.0.0 は、あるのだかないのだか分からなくて。困った。まあ、 Ruby 1.9.3 を使い続ければいいのですけど…。

ちなみに、Ruby 1.9.3 で ruby-debug* をインストールする際は、一部の gem をローカルにDLして、ソレをインストールしないとハマる用で…。以下のページが参考になりそうです。

_Windows7でRails3 + NetBeans + デバッガー が動かない - 同じにやっても動かない
_Aptana StudioでRubyをデバッグ | もっとクールにプログラミング

Python用のプラグインをインストール。 :

Pythonプラグインも、現在の NetBeans では公式サポートから除外されてるらしいのですが。以下のページを参考にして作業。ありがたや。

_おべんきょーぶろぐ: Netbeans7.3でpythonの環境を整えてみる
_Python in NetBeans IDE 7.3 (Geertjan's Blog)

NetBeans 上で、ツール → プラグイン → 設定 → 追加、で、
http://deadlock.netbeans.org/hudson/job/nbms-and-javadoc/lastStableBuild/artifact/nbbuild/nbms/updates.xml.gz
を登録すると、使用可能なプラグインの中に python という項目が出てくるのでソレだけにチェックをしてインストール。必要とするプラグインも2つ3つ出てくるけど、ソレもインストール。

この作業をすると、更新可能なプラグインも大量にリストアップされるけど、それらをインストールすると NetBeans がおかしくなるので入れない。おかしくなるというか、英語版の NetBeans になってしまうみたいで。

Python用のプラグインだけインストールできたら、すぐに、上記のURLを無効にしておく。

新規プロジェクトを作る際に、python の項目が増えているはず。

デフォルトエンコーディングをUTF-8にしておいた。 :

_NetBeansの文字コードをUTF-8に設定する | 初心者に優しいWPカスタマイズ を参考に、 etc\netbeans.conf をエディタで開いて、netbeans_default_options に、-J-Dfile.encoding=UTF-8 を追加しておいた。

Google Chrome上にも拡張をインストール。 :

_"Web開発ツールを使いこなせ!"クリエイターの道具箱 (5) NetBeans 7.3を使ったWeb開発 | マイナビニュース という記事によると、NetBeans と Google Chrome を連携することができるらしくて。NetBeans Connector なる拡張を Google Chrome にインストールしておくといいらしい。もしかすると、Adobe Brackets みたいなことができるのかな…?

とりあえず、htmlファイルを保存するたびに Google chrome 上での表示が更新されることは確認できた。

NetBeans 上でのHTMLタグ入力も、イイ感じなのかもしれない。補完が効くし…。いや、操作の仕方はよく分からないんだけど。候補が出てきたらTABキーを押していけばいいのだろうか。何回か押さないといけないように見えるあたり、よく分かってなかったり。

#4 [dxruby][game] DXRubyでインチキ多関節を試してみる

DXRuby Advent Calendar という企画の話を聞いて、自分が書けそうなネタなんてあるのかなと悩んでしまったわけですが。Ruby や DXRuby については初心者なので書けないとしても、アクションゲームのソレなら書けるのかな…と思えてきたり。

とりあえず、DXRuby Advent Calendar 云々とは全然関係なく、そういうのをちょこちょこ書いて、その手の記事を書く練習をしてみようかなと。

ということで。ふと思いついたネタとして、インチキ多関節とかどうだろうと。見た目は多関節キャラっぽいけど、内部処理は多関節なの? なんか違うんじゃないの? でも、見た目がソレっぽいから別にコレでもいいか、みたいなソレ。

もちろん、使用言語・使用ライブラリは、Ruby + DXRuby を使います。

まず、根っこから先っぽまで、複数のスプライトを使って、一直線に繋ぐことを試してみましょうかね…。
# インチキ多関節その1
# 根元と先っぽを等間隔で繋いでみる

require 'dxruby'

img = Image.load("ufo.png")

Window.loop do
  break if Input.keyPush?(K_ESCAPE)

  # 根元
  bx = 0
  by = Window.height / 2

  # 先っぽ。マウスカーソル座標を取得
  tx = Input.mousePosX
  ty = Input.mousePosY

  nmax = 32    # 32個のスプライトで繋ぐ
  dw = tx - bx
  dh = ty - by
  nmax.times do |i|
    x = bx + (dw * i / nmax) - img.width / 2
    y = by + (dh * i / nmax) - img.height / 2
    Window.draw(x, y, img)
  end
end
一直線にただ繋いでみた


このままだと見た目がつまんないですよね。各関節?のy座標に、sin値を足して、少し形を変えてみましょうか。
# インチキ多関節その2
# 各関節のy座標に、sin値を足してみる

require 'dxruby'

img = Image.load("ufo.png")

Window.loop do
  break if Input.keyPush?(K_ESCAPE)

  # 根元
  bx = 0
  by = Window.height / 2

  # 先っぽ
  tx = Input.mousePosX
  ty = Input.mousePosY

  nmax = 32
  dw = tx - bx
  dh = ty - by
  deg = 0
  
  # sin値に掛ける値。sin値は -1.0〜1.0 の値なのでそのままだと小さ過ぎる
  h = 100
  
  nmax.times do |i|
    x = bx + (dw * i / nmax) - img.width / 2
    y = by + (dh * i / nmax) - img.height / 2
    y += h * Math.sin(deg * Math::PI / 180.0) # sin値を足してる
    Window.draw(x, y, img)
    deg += 30
  end
end
sin値をy座標に足してみた


全然動かないのもつまんないですわな…。根元に与えるsin値の角度をずらしてみましょう。1フレーム毎に、10度ずつ足してみることにします。
# インチキ多関節その3
# 根元に加えるsin値の角度を毎フレームずらしてみる

require 'dxruby'

img = Image.load("ufo.png")

# 根元に加えるsin値の角度
startdeg = 0

Window.loop do
  break if Input.keyPush?(K_ESCAPE)

  # 根元
  bx = 0
  by = Window.height / 2

  # 先っぽ
  tx = Input.mousePosX
  ty = Input.mousePosY

  nmax = 32
  dw = tx - bx
  dh = ty - by
  deg = startdeg
  h = 100
  nmax.times do |i|
    x = bx + (dw * i / nmax) - img.width / 2
    y = by + (dh * i / nmax) - img.height / 2
    y += h * Math.sin(deg * Math::PI / 180.0)
    Window.draw(x, y, img)
    deg += 15
  end

  startdeg += 10   # 根元の角度を毎フレーム増やす
end
根元のsin値の角度を毎フレーム変えてみる


イイ感じの動きになってきましたけど…根元がグングンと上下に動いちゃうのが気に入らない…。根元から、先っぽまで、少しずつsin値の幅を変化させていくことにしましょうか。
# インチキ多関節その4
# 各関節に加えるsin値の幅を変えてみる

require 'dxruby'

img = Image.load("ufo.png")
startdeg = 0

Window.loop do
  break if Input.keyPush?(K_ESCAPE)

  # 根元
  bx = 0
  by = Window.height / 2

  # 先っぽ
  tx = Input.mousePosX
  ty = Input.mousePosY

  nmax = 32
  dw = tx - bx
  dh = ty - by
  deg = startdeg
  h = 100
  nmax.times do |i|
    x = bx + (dw * i / nmax) - img.width / 2
    y = by + (dh * i / nmax) - img.height / 2
    hh = h * i / nmax  # 幅を少しずつ大きくしていく
    y += hh * Math.sin(deg * Math::PI / 180.0)
    Window.draw(x, y, img)
    deg += 15
  end

  startdeg += 10
end
根元は動かないようにしてみる


うむ。なんとなく、コイツをムチで倒してやりたい気分になってきたぞ。後はムチ男を作るだけ。なんちてぽっくん。

とまあ、こんな感じに、たったコレだけのスクリプトソースを書くだけで、サクサクと動きを試せてしまうところが、DXRuby のいいところじゃないかなと自分は思っているのでした。気軽に実験できるあたりが、実にイイ感じです。

ソースと画像は、ここに置いときますね。Public Domainってことで。

_inchiki_takansetsu.zip

明日も何か書いてみよう…。練習練習…。

2013/12/05(木) [n年前の日記]

#1 [nitijyou][pc] 自転車で買い物に

親父さんの電動自転車を以下略。コンビニとダイソーとリオンドール、一旦帰って夕飯の支度をしてから、ホーマックとSeriaとサンドラッグに行ってきたり。

リオンドールで夕飯のおかずを、ホーマックでマウスパッドと枕を購入。

マウスパッドについてメモ。 :

購入したマウスパッドは、 _サンワサプライ MPD-T1GY (グレー色) 。298円、だったかな…。小さいマウスパッドだけど、パッケージに「コレで充分!!」とデカデカと書いてある。

昔のボール式マウスは、精度が低かったり、動かす際に引っ掛かったり等色々あったから、マウスパッドも大きいのが必要だったけど。今時のマウスは、光学センサやレーザーセンサで精度がそこそこ高いし。たしかにコレで充分、な気がする。グワングワンと腕全体を動かしてマウスを動かす時代じゃなくて、手首から先でチョチョイと動かす時代だよなと。

枕について。 :

低反発枕を買ってきた。1,280円、だったかな。

ここ数ヶ月、昔「ためしてガッテン」で紹介されてた、座布団+バスタオルを枕代わりにして試していたけど。高さはたしかに調整可能でイイ感じなのだけど、座布団の余った部分が、邪魔で邪魔で…。やっぱり枕が必要だなと。そのうち使って様子を見てみるつもり。

#2 [pc] ダイソーで小物を色々購入

色々買って試してみたり。

ボタンやキーボードに貼るシールを購入。 :

マウスの拡張ボタンに、ポッチをつけたいなと思ったので、ガラケーのボタン、あるいは、PCのキーボードに貼り付けられるシールの類を探したのだけど。さすがにスマホ全盛な時代だけあって、全然売ってなくてガックリ。それでも、かろうじて、シールを2つほど買ってきたり。

一つは、シールの厚みが薄すぎて、貼っても意味が無かった。たぶん、ボタンに色付けをするためだけのシールなのだろう…。もう一つは、ラインで貼っていくタイプのシールだったので、カッターで一粒だけ切り出して使ってみたり。こちらはまだ、それなりの厚みがあったので、目的は果たせたような気がしたり。

スマホスタンドを購入。 :

手持ちのガラケー、N905i をデジカメ代わりに使う時があるのだけれど、手持ち撮影だからぶれてしまう時があって。三脚に固定する何かが欲しいなとずっと思っていたわけで。

たまたま、ダイソーで目にしたスマートフォンスタンド、携帯電話グッズNo.715 が、両側からバネで挟んで固定しながら三脚っぽい何かで立たせるタイプだったので、これを流用できるのではないかと試しに買ってみたり。

帰宅後試してみたけれど。N905i の本体が細すぎてダメだった…。約53〜65mm の幅のスマホには使える、と書いてあったけど、ガラケーはそこまで太くないのだなと。

仕方ないので、裏面に両面テープがついたスポンジを貼って、挟める幅を狭くして試してみたけど。
  • 件のスタンドは、ガジェットを上向きにして固定するグッズなので、カメラ撮影時のように横向きにはならない。
  • N905iの側面はボタンだらけなので、固定できる場所が極めて限られる。
てな理由で、こりゃダメだと。

扉を開けたら光るLEDセンサーライトを購入。 :

扉を開けると磁石が離れてスイッチが入るLEDライト、LEDライト No.11 が売られていたので購入。コレを使えば、親父さんやお袋さんが、夜中トイレに行こうとした際に、ドアを開けただけでライトが光って便利だろうと思ったわけで。

帰宅後、開封して弄っているうちに、問題点に気がついた。親父さんやお袋さんが使う部屋のドアは、昼間は開けっ放し。その間、このLEDライトは、ずっと点いたままになるはず。あっという間に、電池切れになるな…。ダメだこりゃ。

何かしら使い道は無いかなあ…。思いつかない…。引き出しその他に設置すると言っても、暗すぎて困りそうな引き出しは、日常生活の中で基本的には使わない扱いになるわけだから、ココに付ければ、という場所が全然思いつかない。うーん。

おにぎりを作る容器を購入。 :

御飯を詰めてギューッと押し込むとおにぎりが作れるソレ。

一応、昔、そういうグッズを購入して、今も時々使ってるのだけど。御飯がベタベタとついてしまうのがなんだかアレで。

昨今は、しゃもじの表面を凸凹させて、御飯がつきにくい状態にしてあるわけだけど、ソレをこの手の容器にも使えばいいのに、と常々思っていたわけで。ところが、今日、たまたま店頭でそのものズバリを見かけて。やはり皆、考えることは同じか、コレは一つ試してみないと、てな気分で購入。

まあ、たぶん、表面の凸凹は、何も考えてない凸凹で、やっぱり御飯ついちゃうじゃん、というオチになりそうだなと思ってますけど。

電池残量を測定する何かを購入。 :

電池の両端を挟むとメーターが動くソレを Seria で購入。

自分、一応これでも工業高校電子科卒なので、実習の時間にテスターを作らされて、ずっとそのテスターを使ってる・電池残量を測る時もソレを使っているのだけど。一々引っ張り出すのが面倒臭いし、あの細い棒で電池の両端を挟むのも結構至難の業だし、手軽に測れる何かが欲しいなーと。てなわけで、これなら十分イケそうだなと購入。

帰宅後、手持ちの電池で測定してみたけど。どのあたりが1.5Vなのか、よく分からず…。

また、説明書に、「3秒以上測ると電池が無くなるよ」と書いてあることにも気付いたり。たしかに、目盛り上の針がグングン動いていく…。なんだかコレ、電池をわざと使いきるという目的でも使えそうな。

ちなみに、充電池の類には使えないらしい。

100円ショップでいくつか買ってきただけなのに。 :

100円ショップでいくつか買ってきただけなのに、こんだけズラズラと、どうでもいいことを書けるあたり、なんだか自分はお得というか…。何を使っても「ふむふむ、なるほど」と遊べる人間じゃないのかと思えてきたり。安上がりな人間…。

#3 [dxruby][game] DXRubyで二足歩行する敵っぽい動きを作ってみる

今日も DXRuby を使って何かしら書いてみます。

今回も多関節ネタということで、二足歩行する敵っぽい動きを試してみようかなと。

なんで二足歩行なのかというと…。個人的に、ちょっと思い入れがありまして…。

昔、先輩から、「このゲームの、この中ボスは、こうやって動かしてるんだよ」と説明してもらったことがありまして。「うわー、面白そう。自分もそういうのやってみたい」と思ったものの、その後、そんな機会には恵まれず。

当時は、その手のゲームを作るとなるとアセンブラで書くのが当たり前だったので、なかなか気軽に試すわけにもいかなくて。また、CGツールも無かった時代ですので、絵描きさんに「こういうの描いてくれませんか?」とお願いする必要もあって。 *1 なので、お遊びでチョチョイッと、てなわけにはいかなかったのです。 *2

だけど今なら、気軽に試せる DXRuby がある。CGツールだって、好きなだけ使える。ということで、当時、指をくわえて眺めていたあの動きを、自分もちょっと試しに書いてみようかな、と。

とりあえず、こんな感じになりました。

二足歩行その1
# 二足歩行する敵モドキ

require 'dxruby'

$angadd = 2

# 足先の座標を求めるクラス
class Foot
  def initialize(start_ang)
    @ang = start_ang
    @x = 0
    @y = 0
    self.update
  end

  attr_accessor :x, :y

  def update
    # 円運動をさせてみる。
    # 本当は放物線運動のほうがいいと思う…けど
    # 面倒臭いから今回は安直に円運動
    
    ang = @ang * Math::PI / 180.0
    @x = -128 * Math.cos(ang)
    @y = 96 * Math.sin(ang)
    @y = 0 if @y >= 0
    @ang += $angadd
  end
end

# 棒状の部分を複数のスプライトを使って描く
def draw_foot_sub(bx, by, tx, ty, img)
  count = 10
  count.times do |i|
    x = bx + ((tx - bx) * i / (count - 1)) - img.width / 2
    y = by + ((ty - by) * i / (count - 1)) - img.height / 2
    Window.draw(x, y, img)
  end
end

# 足を一本分描画する
def draw_foot(bx, by, tx, ty, img, flen)
  dw = tx - bx
  dh = ty - by

  # 腰から足の先までの長さ、の半分を求める
  # 三平方の定理(ピタゴラスの定理)を使ってる
  l = Math.sqrt(dw * dw + dh * dh) / 2

  # 膝までの距離を求める。これも、三平方の定理を使ってる
  nl = flen * flen - l * l
  n = (nl <= 0)? 0 : Math.sqrt(nl)

  # 腰と足先の中間点を求める
  cx = (bx + tx) / 2
  cy = (by + ty) / 2

  # 膝があるはずの方向(角度)を求める
  # 腰と足先の座標から角度を求めて、それに90度足せばいい
  ang = Math.atan2(dh, dw) + Math::PI / 2
  
  # 膝の場所を求める
  lx = cx + n * Math.cos(ang)
  ly = cy + n * Math.sin(ang)

  # 腰から膝までと、膝から足先までを描く
  draw_foot_sub(bx, by, lx, ly, img)
  draw_foot_sub(lx, ly, tx, ty, img)

  # 分かりやすくするために線を引いてみる
  Window.drawLine(cx, cy, lx, ly, [255, 0, 0])
end

img = Image.load("ufo.png")

by = 150 # 腰の高さ
gy = 420 # 地面の高さ

# 足半分の長さ
flen = (gy - by) / 2 + 20

footl = Foot.new(0)
footr = Foot.new(180)

# メインループ
Window.loop do
  break if Input.keyPush?(K_ESCAPE)

  # マウスカーソルのy座標で足先の移動速度を変えてみる
  $angadd = 20.0 * Input.mousePosY / Window.height - 10.0
    
  bx = Input.mousePosX

  # 右足の根元と先っぽの座標を求める
  n = 24
  frbx = bx - n
  frby = by
  frtx = bx + footr.x - n
  frty = footr.y + gy

  # 左足の根元と先っぽの座標を求める
  flbx = bx + n
  flby = by
  fltx = bx + footl.x + n
  flty = footl.y + gy

  # 右足を描く
  draw_foot(frbx, frby, frtx, frty, img, flen)
  
  # 腰を描く
  Window.drawScale(bx - img.width / 2, by - 80 , img, 2, 2)

  # 左足を描く
  draw_foot(flbx, flby, fltx, flty, img, flen)

  # 足先の座標を更新
  footl.update
  footr.update

  # 分かりやすくするために線を引いてみる
  Window.drawLine(frbx, frby, frtx, frty, [0, 255, 255])
  Window.drawLine(flbx, flby, fltx, flty, [0, 255, 255])
end
ちょっとソースが長くなってしまいましたが…。もうちょっと短く書けないのかな、コレ…。

ざっくりと解説を。

一般的に、2Dゲームの多関節処理というと、各関節毎に角度を管理・制御して動きをつけていくのですけど。このプログラムでは、少し違うことをしています。

このプログラムでは、各関節の角度ではなく、根元と先っぽ(足先)の座標だけを管理・制御しています。そして、膝だか肘だかの座標は、計算して求めます。

この仕組みを作ってしまえば、根元と先っぽだけを制御すればいいので、比較的自由に動きをつけていけますし、時々、プログラマーが意図してなかったポーズになったりもして、見た目が面白い場面も出てきたり…するかもしれません。

MMD(MikuMikuDance)や3DCGソフトを触ったことがある人なら、ピンときたのではないでしょうか。「それって、IK(インバースキネマティクス)じゃね?」。そうです。これ“も”、IKです。

MMDや3DCGソフトのIKは、以下のような状態ですが…。 このプログラムでは、以下のような状態です。 制限だらけですね…。とはいえ、さすがに、これだけ制限があれば、昔の非力なCPUでもIKが実現できたわけです。実際、スーパーファミコンやメガドライブの某タイトルでは、こういう仕組みでボス敵が動いてました。…スーパーファミコンのCPUはとにかく遅くてプログラマー泣かせだったらしいですけど、プログラマーの工夫次第で、こういうこともできたわけですね。

さて、実際の処理内容ですが…。 ここまで分かれば、中間点の座標、sin、cos、膝があるはずの角度、膝までの距離、を使って膝座標が得られますね。

ちょっと分かりづらいかな…?。余裕があったら説明図も後で描いときます。

(※ 2013/12/06追記。説明図を追加してみました。ちょっとだけ…分かりやすくなった…のかどうか…)

説明図

ところで。

DXRuby は、スプライトの回転拡大縮小半透明描画ができますので…。何もわざわざ、複数のスプライトを数珠繋ぎにして、足を描かなくてもいいような気がしてきました。

ということで、足を丸々画像にして、回転させて描画してみましょうか。blender でレンダリングした画像を使ってみました。
足を画像にしてみた例
# 二足歩行する敵モドキ。足を画像にしてみた版

require 'dxruby'

$angadd = 2

# 足先の座標を求めるクラス
class Foot
  def initialize(start_ang)
    @ang = start_ang
    @x = 0
    @y = 0
    self.update
  end

  attr_accessor :x, :y

  def update
    # 円運動をさせてみる。
    # 本当は放物線運動のほうがいいと思う…けど
    # 面倒臭いから今回は安直に円運動
    
    ang = @ang * Math::PI / 180.0
    @x = -128 * Math.cos(ang)
    @y = 96 * Math.sin(ang)
    @y = 0 if @y >= 0
    @ang += $angadd
  end
end

# 棒状の部分を1枚のスプライトを回転させて描く
def draw_foot_sub(bx, by, tx, ty, img)
  cx = (tx + bx) / 2 - img.width / 2
  cy = (ty + by) / 2 - img.height / 2
  dw = tx - bx
  dh = ty - by
  ang = Math.atan2(dh, dw) * 180.0 / Math::PI
  Window.drawRot(cx, cy, img, ang)
end

# 足を一本分描画する
def draw_foot(bx, by, tx, ty, img, flen)
  dw = tx - bx
  dh = ty - by

  # 腰から足の先までの長さ、の半分を求める
  # 三平方の定理(ピタゴラスの定理)を使ってる
  l = Math.sqrt(dw * dw + dh * dh) / 2

  # 膝までの距離を求める。これも、三平方の定理を使ってる
  nl = flen * flen - l * l
  n = (nl <= 0)? 0 : Math.sqrt(nl)

  # 腰と足先の中間点を求める
  cx = (bx + tx) / 2
  cy = (by + ty) / 2

  # 膝があるはずの方向(角度)を求める
  # 腰と足先の座標から角度を求めて、それに90度足せばいい
  ang = Math.atan2(dh, dw) + Math::PI / 2
  
  # 膝の場所を求める
  lx = cx + n * Math.cos(ang)
  ly = cy + n * Math.sin(ang)

  # 腰から膝までと、膝から足先までを描く
  draw_foot_sub(bx, by, lx, ly, img)
  draw_foot_sub(lx, ly, tx, ty, img)

  # 分かりやすくするために線を引いてみる
  # Window.drawLine(cx, cy, lx, ly, [255, 0, 0])
end

img = Image.load("foot.png")
bodyimg = Image.load("body.png")

by = 150 # 腰の高さ
gy = 420 # 地面の高さ

# 足半分の長さ
flen = (gy - by) / 2 + 20

footl = Foot.new(0)
footr = Foot.new(180)

# メインループ
Window.loop do
  break if Input.keyPush?(K_ESCAPE)

  # マウスカーソルのy座標で足先の移動速度を変えてみる
  $angadd = 20.0 * Input.mousePosY / Window.height - 10.0
    
  bx = Input.mousePosX

  # 右足の根元と先っぽの座標を求める
  n = 24
  frbx = bx - n
  frby = by
  frtx = bx + footr.x - n
  frty = footr.y + gy

  # 左足の根元と先っぽの座標を求める
  flbx = bx + n
  flby = by
  fltx = bx + footl.x + n
  flty = footl.y + gy

  # 右足を描く
  draw_foot(frbx, frby, frtx, frty, img, flen)
  
  # 腰を描く
  Window.draw(bx - 150, by - 100, bodyimg)

  # 左足を描く
  draw_foot(flbx, flby, fltx, flty, img, flen)

  # 足先の座標を更新
  footl.update
  footr.update

  # 分かりやすくするために線を引いてみる
  # Window.drawLine(frbx, frby, frtx, frty, [0, 255, 255])
  # Window.drawLine(flbx, flby, fltx, flty, [0, 255, 255])
end
うむ。実にそれらしくなりましたな。

ただ、見た目をリアルにしていくのは楽しい作業なのですが…。これはちょっと、落とし穴がありそうな気もしますね。

まあ、今回は、「昔憧れたあの動きを、DXRubyという便利ライブラリを使って気軽に実験」という話でやってますので、コレはコレでOKかなと。

ソースと画像も置いときますね。Public Domainってことで。

_walkenemy.zip

さて、明日も何か書いてみようかな…と思ったけれど、今日のコレで時間ギリギリだったので、二日に1回ぐらいのペースで書くかもしれないし書かないかもしれません。まあ、この手の記事を書く練習ってことで、気楽に、気楽に…。

余談。他のツールを検討すべき境界線。 :

DXRuby に限らず、2Dゲームライブラリを使ってアレコレ作っていく際に、見た目をリアルにしていくことにリソースを割いていくと…。

どこかの時点で、「ソレ、Unity使ったほうがよくね?」となりそうな気がするのです。つまり、そこに落とし穴というか、「ここから先は別のツールを使ったほうが…」と判断できる境界線が、どこかにあるんじゃないのかな、と思えるのですね。

Unity の場合…。
  • 3Dで描画するから、見た目からしてリアル。
  • 多関節キャラを扱うのは当たり前。そもそも、人体モデルが多関節キャラですから…。
  • 多関節キャラの動きを、3DCGソフトを使って確認しながら作り込める。トライ&エラーが簡単。
  • モーションの合成も、基本機能として持っている。
  • IKも、基本機能として持っている…。
てな感じの、大変便利なツールですので…。何も今から、Unityと同じことをしなくてもいいんじゃないか、車輪の再発明をしなくても、ということになりそうですよね。

ただ、Unityも、習得に要する時間というものがあるわけで…。

習得時間に関しては、DXRuby 等、2Dゲームライブラリは、比較的短いので…。やはり、「ちょっと試してみる」「この手のプログラムの書き方を勉強してみる」という点では、メリットがあるようにも思うのでした。

*1: 当時は、国民機 PC-9801 を使ってた時代ですから…。16色しか出ませんから…。TVゲーム機用の色を出すには、自社設計のハードウェアをPC-9801に追加して、とかやってた時代ですから…。プログラマーが、余技? 趣味? でCGツールも使わせてもらう、なんてことは、ちょっと難しかったのです。…いや、やる気ビンビンな先輩方は「俺にもCGツール使わせて!」とかやってましたけど。自分は引っ込み思案、かつ、プログラム書くだけで手一杯でそこまでは…。
*2: そもそも自分、当時はまともなPCを持ってなかった気がする。X1 turbo は部屋にあったかもしれないけど、電源すら入れてなかったような…。X68Kでも持ってたら違ったのかもしれないけど。

2013/12/06(金) [n年前の日記]

#1 [pc] ヘッドフォンにポッチがついてることに気がついた

今まで、ヘッドフォンを使う時は、根元に書いてあるRとLの文字を頼りにして耳に刺していたのだけど。

_次世代USBコネクタは表裏なし | スラッシュドット・ジャパン ハードウェア というページの中で「ヘッドフォンにもポッチをつけよ! 左右が分かりにくいんだよ!」という意見を目にして。ふと、自分が使ってたヘッドフォンを眺めたら…。

ポッチついてるやん! 「L」のほうに、ポッチついてるやん!

知らなかった、というか、気づかなかった…。自分は今まで一体何をしてたんだ…。audio-technica ATH-C500M、偉い。地味に素晴らしい。

他のヘッドフォンはどうなのだろうと思って眺めてみたら。SONYは…まあ、コレは、ケーブルの長さが左右で違うし、スピーカ部分とその根元の2ヶ所で、「R」「L」が書いてあるし。まだ気を使ってるほうなのかなと。さすがSONY、なのでしょうか。

Panasonic は…これもポッチがついてた。さすがPanasonic、なのかな。

とりあえず手持ちのヘッドフォンは、左右が分かりやすくなるように、ちょっとした工夫はしていた模様。これは勉強になった…。

マウスのボタンも、ポッチがついてたらよかったのに。

#2 [dxruby] DXRubyというタグを増やしました

ここ数日、DXRuby絡みの記事を書くことを意識してますが、タグが無いのもアレだなと思ったのでその手の記事にはつけておくことにしました。

#3 [windows][dxruby] デスクトップ画面をキャプチャしてGIFアニメにするツール

昨日、一昨日と、DXRubyのウインドウをキャプチャしてGIFアニメにして貼り付けているわけですが。キャプチャする際に、GifCam というソフトを使っておりまして。

_【レビュー】デスクトップを動画キャプチャーしてアニメーションGIFファイルにする「GifCam」 - 窓の杜

コレ、大変便利です。コレが無かったら、あの手のGIFアニメを作って載せるとか、ちょっと無理だったかもしれず。これで、録画開始と終了をホットキーで出来たら文句なしなのですが…。

ちなみに、他にも同種のソフトをHDDにインストールしてある状態でして。

_LICEcap - k本的に無料ソフト・フリーソフト
_【今日のお気に入り】GIFアニメ作成など多彩な機能を備える画面キャプチャーソフト「窓フォト」 - 窓の杜

どのソフトも、ウインドウ枠でキャプチャサイズを指定するタイプです。

LICEcap は、GifCam と同様、キャプチャ結果を即座に GIFアニメにしてくれるソフト。FPSを指定できる点はイイ感じ。ただ、GifCamのように、録画後、フレームを削除したりはできないようで。

窓フォトは、一旦、bmp、jpg、png等でHDDに連続でキャプチャ画像を保存した後、それら画像群を使ってGIFアニメ作成を行うタイプ。おそらく、キャプチャ画像はフルカラー相当でしょうから、それら画像群を元にして綺麗な動画を作る等の作業もできるのではないかと。また、マウスカーソルに赤い丸をつけて表示する機能もあるので、操作説明動画を作るには向いてるかもしれず。

自分は使用してないですが、 _Gyazo というツール+Webサービスも便利らしいですな。録画したソレを、即座にWebサーバに送るそうで、URLを相手に知らせれば、すぐにキャプチャ結果を共有できるのが売り、らしいです。

ただ、興味は湧いたものの、キャプチャ結果を一般公開できるのかどうかがよく分からなくて…。一般公開もできるのであれば、自分の手持ちのサーバ容量や回線の転送量を圧迫しないで済みそうだなと。いや、件のWebサービス提供側がその分負担してるだけだから、ホントにソレっていいのかなという気もしますが。

#4 [dxruby][game] DXRubyで等速度運動と加減速運動を試してみる

今回も、DXRubyを使って、そっち関係の記事を…。いや、もう DXRuby は関係なくて、ただの昔話ばかり書いてる気もしますが…。それはさておき。

昨日の記事で時間ギリギリだったので、今日は少し軽い話にしとこうかなと。…や、昨日のソレは、ソースは1時間ぐらいで書けたのですけど、blenderでモデル作るだけで半日かかっちゃって…。あんなヘボ画像でも、ボディ部分のモデルは3回作り直してたり…。ホントは超兄貴みたいな画像にしたかったんですけど、これが全然そんなレベルにはならず…。モデリングを仕事にしてる人達、絵描きさん達はやっぱりスゴイと再認識ですよ…。

さて本題。自分、何かしらを動かす時に、好きな動きというか、好きな書き方があるのです。そのあたりを紹介してみようかなと。

例えば。メニュー画面で十字キーを押すと、各項目に向かってカーソルが動いていく、といった処理を書かなきゃいけない場合。さて、カーソルに、どういう動きをさせますかね?

真っ先に思いつくのは、等速度運動ですかね。等速度、つまり、速度が一定の動きです。こんな感じの動きかなと。
等速度運動
# 動きのテスト。等速度運動

require 'dxruby'

font = Font.new(24)
img = Image.load("ufo.png")
CNTMAX = 60
cnt = 0
x = 0 # 現在座標
y = 0
tx = 0 # 目標座標
ty = 0
dx = 0 # 速度
dy = 0

Window.loop do
  break if Input.keyPush?(K_ESCAPE)

  if cnt % CNTMAX == 0
    # 1秒ごとに現在座標と目標座礁を初期化
    x = 0
    y = 0
    tx = Window.width
    ty = Window.height
    dx = (tx - x).to_f / CNTMAX
    dy = (ty - y).to_f / CNTMAX
  end

  # 等速度運動
  x += dx
  y += dy
  
  # 目標座標に到達したらメッセージを描画
  if x == tx and y == ty
    Window.drawFont(32, 32, "到達", font)
  end
  
  Window.draw(x - img.width / 2, y - img.height / 2, img)

  cnt += 1
end

たしかにコレでも仕様は満たせますが。自分はどうも、物足りなさを感じてしまって…。

そこで、加減速運動(?)をさせることが多いのです。
加減速運動
# 動きのテスト。加減速

require 'dxruby'

font = Font.new(24)
img = Image.load("ufo.png")
CNTMAX = 60
cnt = 0
x = 0 # 現在座標
y = 0
tx = 0 # 目標座標
ty = 0

Window.loop do
  break if Input.keyPush?(K_ESCAPE)

  if cnt % CNTMAX == 0
    # 1秒ごとに現在座標と目標座礁を初期化
    x = 0
    y = 0
    tx = Window.width
    ty = Window.height
  end

  # 加減速運動
  x += (tx - x) * 0.2
  y += (ty - y) * 0.2
  
    # 目標座標に到達したらメッセージを描画
  if x == tx and y == ty
    Window.drawFont(32, 32, "到達", font)
  end
  
  Window.draw(x - img.width / 2, y - img.height / 2, img)

  cnt += 1
end
現在座標と目標座標の差を1/nにして、現在座標に足すという処理です。等速度運動より、なんかちょっぴりカッコイイ感じがしませんか? 自分だけかな? また、ソースを見れば分かりますけど、速度を管理しなくて済むあたりも、ちょっとだけ美味しくて。

ちなみに。以前、DXRuby を使って _Anime PV Easy Maker ZERO てのを書いたんですけど。メニューがヒュンヒュンと動くあたりは、全部こういう書き方をしています。お気に入りなんです。この動き。

ただ、この書き方、ちょっと問題があって。

コレ、いつまで経っても、目標座標に到達してくれないのですよ…。なんだかちょっと、 _「アキレスと亀」 みたいな状態ですから。いや、この場合、亀は止まってますけど。

なので、「一定距離まで近づいたら、強制的に、現在座標を目標座標で上書きする」という処理が必要になりまして。
加減速運動、ちゃんと目標座標に到達する版
# 動きのテスト。加減速。目標座標に近づいたら現在座標を設定する版

require 'dxruby'

font = Font.new(24)
img = Image.load("ufo.png")
CNTMAX = 60
cnt = 0
x = 0 # 現在座標
y = 0
tx = 0 # 目標座標
ty = 0

Window.loop do
  break if Input.keyPush?(K_ESCAPE)

  if cnt % CNTMAX == 0
    # 1秒ごとに現在座標と目標座礁を初期化
    x = 0
    y = 0
    tx = Window.width
    ty = Window.height
  end

  # 加減速運動
  x += (tx - x) * 0.2
  y += (ty - y) * 0.2

  # 目標座標に近づいたら現在座標を設定する
  x = tx if (tx - x).abs < 0.5
  y = ty if (ty - y).abs < 0.5

  # 目標座標に到達したらメッセージを描画
  if x == tx and y == ty
    Window.drawFont(32, 32, "到達", font)
  end
  
  Window.draw(x - img.width / 2, y - img.height / 2, img)

  cnt += 1
end
現在座標を変更した直後に、ちょっと条件判定してますよね。こうしないと、目標座標に到達してくれない。このへんが、ちょっともにゃもにゃした気分に…。

まあ、こういう動きが自分は好きでよく使ってます。てなだけの話でした。

一応ソースと画像も置いときます。Public Domainってことで。

_movetest.zip

ちなみに、こういう書き方って、今はあまり主流じゃないのだろうな、とも思うのですけど。

#5 [game][prog] 今は数式で動かすのが主流、なのかな

昔のTVゲーム機上で動いてたプログラムって、上に書いたソースのように、毎フレーム、現在座標に速度を足したり、速度に加速度を足したり、という書き方をしてたんですけど。

今は、座標移動は数式で行う場合が多いのかな、という気がしています。

例えば、JavaScript のライブラリで、Tween.js てのがあるらしいですけど。動きの一覧を見ると、どう見てもフレーム毎にどうこうしてる動きじゃないなと。たぶん、座標値を求めるための数式が、ライブラリ中にそのまま書かれているんじゃないのかなと。あくまで想像ですけど。

_Tween.js / graphs

Unity あたりも似たような感じで。「前回のフレームから今回のフレームまで何ミリ秒かかった、という値が取得できるから、それを速度に掛けて座標に足せ」みたいな書き方が基本としてあるわけですよ。

このあたり、昔のことを思い出すのです…。

子供の頃、ベーマガという雑誌を買って読んでたんです。ベーマガ=マイコンBASICマガジンの略なんですけど。

その雑誌の中に、「あのゲームの敵の動きは、こうやって実現している!」てな記事がありまして。そこではBASICを使って、座標移動が数式で書かれてたんですね。子供だった自分は、「そうかー。こういう動きって、数式で書くものなんだー」と素直に信じていたのです。

ところが、その手の業界に入ってみたら、そんな書き方してる人は誰も居ない。皆、毎フレーム、速度や加速度をひたすら足して、動きを作っていて。「うわあ。これは騙された。ベーマガに騙されちゃった」てな気分になった記憶があります。

ところが…どうも昨今、座標移動は数式で、という書き方が主流になってる気がするのです。

考えてみたら、数学の教科書その他に載っているのも、数式ですから…。数学をちゃんと勉強してきた人なら、たぶんそういう書き方のほうが分かりやすい。では、どうして、昔はそういう素直(?)な書き方をしなかったのかなと。

このあたり、ハードウェアが関係していたのだろうと思うのですよね。 そんな事情があったので、毎フレーム、速度・加速度を“足す”“引く”という書き方だったのだろうなと。

しかし、3Dゲームが普及して、状況が変わってくるわけです。

3Dゲームは、描画処理が重いので、フレームレートが一定にならない。フレームレートが一定であることを期待したプログラムを書くと、ハマってしまう。おそらくは、まだ、数式を素直に書くべく志向したほうが、ハマりにくいのだろうなと。

さらに、CPUの性能も向上した。おそらくは掛け算・割り算はもちろんのこと、浮動小数点演算まで当たり前のようにできるようになってきた。昔のTVゲーム機に使われてたCPUは、整数演算しかできませんでしたから…。固定小数点演算が関の山で…。

そんなわけで、昔、「ベーマガに騙された」と思ったソレが、ゲームの見た目が変わって、CPUが性能向上して、着々と主流になっているような気がして、なんだか不思議な気分になったりするのでした。

ちなみに昔の書き方も、全然間違ってないのですけど。むしろ、速度や加速度というものが理解できてるから、そのように書けていたわけで。

速度とは何でしょうか? この時間で、どの程度の距離を進むのか。それが速度ですから。1時間で進む距離は「時速」と呼ばれてるし、1秒で進む距離は「秒速」と呼ばれてる。ゲームの場合は、1フレームで進む距離ですから…「フレーム速」とでも呼べばいいのでしょうかね?

ただ、3Dゲーム全盛時代は、可変フレームレートが当たり前なので…。いくつかのゲーム用ライブラリを眺めていた際、速度の単位が全て「秒速」で統一されてたりして、「昔とは違うんだなあ」と感じた記憶もあります。

まあ、何の役にも立たない昔話でした。

待てよ? ふと思ったけど、このあたり、もしかすると、PC文化とTVゲーム機文化の違いでしかなかったりするのかな…?

#6 [dxruby][pc] Anime PV Easy Maker ZEROの苦労話その1

今頃になって、 _Anime PV Easy Maker ZERO の苦労話、というか悩んだ点について、書けなくもなかったかな…と思えてきてしまったり。途中途中で悩んだ点があったことを少し思い出してきたというか。せっかくだから忘れないうちにメモしておきます。

フラットデザインを意識。 :

件のアプリのメニュー画面を作る際、「今回はフラットデザインで行くぞ」と意識して作業しました。なんだか流行ってるようだし、このビッグウェーブに、俺も乗らねば!

嘘です…。乗りたくて乗ったわけでは…。

実を言うと、最初の頃はもっとリッチな感じの画面でした。でも、メニュー画面を何枚も作ってるうちに、かなり面倒臭くなってきて。例えば、ボタンの形が複雑になれば、マウスカーソル座標との判定処理も複雑になるわけですよ。

こんなのやってられねー、なんとかインチキできんのか? てなわけで、シンプルな形のボタンに作り替えてるうちに、「お? コレ、今流行りの『フラットデザイン』てのにすれば誤魔化せるんじゃね?」と気付いて、舵を切り直したという…。自分、ダメ過ぎですね。

ちなみに、配色に関しては、 _Flat UI Colors というサイトを参考にしました。更に、このサイトで紹介されてる配色を、GIMP、Inkscape で使えるパレットファイル(.gpl)にして配布してくれてる方もいまして。コレを、Inkscape と GIMP に入れて作業しました。

_Rok Fajfar : Flat UI Color Palette for Inkscape / Gimp
_rfajfar/gplflat - GitHub

件の配色だけを使うよう心掛けてる限りは、パッと見でそれっぽくなるのでオススメ…かどうかは知りませんけど、デザインについてはド素人の自分でもソレっぽくなったので助かりました。ありがたや。

画像は事前に用意。 :

DXRuby には、画像を生成する機能もありますので、件のアプリのようなシンプルな画面・シンプルなボタン画像なら、大半はスクリプト上でその都度生成できるはず、なのですが。

その方法では、いくつか問題点があることに気付きまして。故に、画像生成は極力せず、事前に画像を作っておいてソレを表示する方針にしました。配布時のバイナリ容量が大きくなるというデメリットはありますけど、今回は画像で持っておいたほうがいいかなと。

以下、問題になるなと思えた点をメモしておきます。

レイアウトを考える際の問題。 :

DXRubyを使って画像生成をするとなると、フォント描画その他の、描画位置調整作業は、以下のようになるわけですが。
  1. エディタでスクリプトを修正して数値を調整。
  2. スクリプト実行。
  3. 位置を確認。
  4. 1. に戻る。
こんな作業、やってらんねーです。面倒臭いです。

そんなわけで、レイアウトを決める作業は、Inkscape を使ってやりました。WYSIWYGとまではいかないまでも、GUIでレイアウトを決めて、決まったらその数値をエディタで打ち込むほうが、まだ楽かなと。その関係で、ボタン等も丸々画像で持った方が楽だろうなと。

まあ、本来、Inkscape で作ったSVGファイルをロード・parseして描画する何かを書いたほうが楽だったんじゃないか、という気もしていますが…。

今になって気付きましたが、エディタ上で数値を調整して位置決めする作業って、デバッガを使って作業すれば早く終わったような気も…。もっとも、当時、emacs でスクリプトを書いてたので、デバッガを使うスタイルに気付きませんでした…。Ruby 対応のグッドなIDEが無いのがいかんのや…。

フォント絡みの問題点その1。 :

DXRuby は、フォントを描画する際、状況によってアンチエイリアスの有無が違ってくると知りまして。 _DXRuby 1.4.0 リファレンスマニュアル 4.13 フォント描画 で解説されてますが。

当時、試してみたところ、なんだかその時々で描画結果がバラバラだなと首を傾げまして。このあたりハマりそうだったので、最初から別途画像を持っておいて、DXRuby は画像描画に専念させよう、と思った、ような気がします。

たしか、DXRuby 1.5.? dev版では、フォント描画周りでアンチエイリアスの有効無効のオプションが追加された記憶がありますので、DXRuby 1.6.x 等が正式公開された際には、このあたりの状況が変わってくるだろうなと期待していますが。

ただ、Webページのデザインもそうでしょうけど、何としてもこの見た目を寸分違わず提供したいと思った時は、迷わず全部画像にしちゃう、というのはアリじゃないかなと。

フォント絡みの問題点その2。 :

DXRubyを使って、自分の好みのフォントデザインでフォント描画をするためには、そのフォントファイルが必要になる ―― スクリプトと一緒に、フォントファイルを同梱しておく必要がありますが。その、フォントファイルの使用条件・ライセンスがどれもなかなか厳しくて、同梱させるのは無理だ、できる限り画像化するしかないなと諦めたのでした。フォント絡みでは、こちらの問題のほうがはるかに大きかったです。

考えてみたら、SVGをparseして、というやり方では、このフォントライセンス問題をクリアできない可能性があるので、あまり意味が無いですね…。描画に使うべきフォントがそれほど選べないのでは…。

このあたり、愚痴り(?)始めると長くなるので、別記事にしておきます。

他にも何かあったような。 :

まあ、思い出したらその都度メモするということで…。

#7 [game][dxruby] フリーゲーム制作時におけるフォントのライセンス問題

上の記事でちょっと書いたあたりを補足というか。もっとも、フリーのゲーム、同人ゲームを作ってる人なら、えてしてフォントのライセンス問題は知ってると思いますけど…。念のため、自分も軽く(?)書いておこうかなと。

世の中、「フリーで使えるフォント」なるものがたくさん紹介されていますが。各フォントには、使用条件・ライセンスがついていて、「フリー」だからといって「自由」ではないのが実状で。また、ゲームの場合、画面内でメッセージを表示しなければいけない場面も時々あるわけですけど。そのためにはフォントファイルを、アプリと一緒に同梱しておく必要がありまして。

しかし、この、「アプリと同梱」を禁止してるフォントが多いので、色々と困ってしまうわけでして。

企業が提供するフォントの場合。 :

まず、企業から販売されているフォントは ―― まあ、そもそもフリーのフォントではないわけですけど、それらのフォントはライセンスがが圧倒的に厳しく、たとえCD-ROM等を正規に買った場合であっても、フリーソフトの類では利用できませんで。「同梱禁止」は当たり前としても、更に、「ボタン等に画像化してゲーム画面に出すのも禁止」だったりします。「ゲームや映像作品に、そのフォントを使う場合は、別途契約して使用料を払ってください」というフォントばかり。

以前調べた範囲では、「Webページに画像として表示するのも禁止」てなフォントもありました。じゃあ、一体何に使えるんだよ? …たぶん、年賀状にしか使っちゃダメ、と言ってるのだと思いますけど。

中小企業が配るチラシとかもダメですね。「商業が絡む印刷物への利用は禁止」等が書いてありましたから。

こんな状態ですので、フリーソフトを作る際には、企業が提供してるフォントは絶対に触れないのが賢いだろうと思うのです。こっちは無料で自作ソフトを公開してるのに、後になって「使用料を払え」なんて訴えられたら、大赤字になっちゃいますし。

フリーの日本語フォントの場合。 :

ならば、「フリーで使えるフォント」と紹介されてるフォントなら大丈夫かというと、これも厳しい状態で。

とりあえず、日本語フォントは、99%ダメな印象です…。

まず、「同梱禁止」を明示してあるフォントがゴロゴロあります。まあ、これは、ちゃんと書いてあるだけ、ありがたいほうでして…。

危ないのが、「宗教、アダルト、商業利用禁止」が書いてあるフォント。…アレは何なんでしょうかね? 誰かがテキトーに作った意味不明の独自ライセンスを、何も考えずにコピペして使い回してるとしか思えませんが。

「宗教、アダルト禁止」は避けたほうが無難です。何故なら、こちらの思う「宗教、アダルト」の境界線と、フォント作者様の「宗教、アダルト」の境界線は、大きく異なってる可能性があるからでして。

例えば、フォント作者様が、「Rubyを使ってるヤツは宗教野郎だ。DXRubyを使ってるヤツは、もっと宗教野郎だ」「だから、お前が公開してるDXRubyアプリはライセンス違反している。お前は宗教活動にこのフォントを使ってるのだ」「よって、アプリの公開を即刻停止せよ!」と叫んでも、こちらは文句を言えない。

つまり、フォント作者様の胸三寸で、フォントの使用条件が、後からいくらでも実質的に変更できてしまうのです。せっかく苦労して作ったアプリの生殺与奪を、ソフト制作者ではなく、フォント作者様が、ずっと持ち続けている状態になってしまう。

「宗教、アダルト禁止」という条項は、そんな危険性を内包している一文なのです。

「そんなバカなことを言い出すヤツは居ないよ」と笑いますかね? …でも、日本には、「お前の作った歌詞は、私の漫画から盗んだモノだ! 訴えてやる!」と本当に訴えちゃったおじいちゃんだって居るわけですよ。そのぐらい、モノを作る人ってのは、えてして人間としてどこかおかしいのが常。それでもまだ、「ありえないよ」と笑えますか? そのフォント作者様が、そういうアレな人物ではないと、何故思えるのですか?

わざわざ御丁寧に、フォント作者様が、一時停止の標識を掲げているのだから、こっちはちゃんとブレーキを踏まないと。そのフォントはスルーした方が賢いと思いますが…どうでしょうかね。

このあたり、日本人の民族性があるのでしょうね。何かしらの決まり事を作る際、日本人は、とにかくやたらとグレーゾーンを広げておこうと画策するのだろうと。

例えば、今現在、国会で問題になってる秘密保護法案もそうですし。以前問題になっていた児ポ法もそうですよね。グレーゾーンをとにかく広げておいて、後で問題が出た際には、そのグレーゾーンに引っ掛けて対応できるようにしておこう、と企むという…。

閑話休題。

そんなわけで、日本語フォントで自由に使えるフォントとなると、
  • M+フォント
  • *NIX文化圏から出てきたフォント
  • もしかするとIPAフォント
ぐらいしか選択肢が無いのが実状でして。つまり、デザイン面での自由度が制限されるわけです。いや、M+フォントのデザインは、自分好きなんですけど。それでも選択肢はどうしても絞られちゃうよね、という話です。

ちなみに、M+フォントから派生したフォントも油断できません。時々、独自ライセンスに変わってしまってるフォントを見かけますし。他のフォントが混在したことで制限が増えたフォントもありますから。

まあ、どのフォントも、使う時はライセンスをよく読まないとマズい、というだけの話ですが…。

英語圏のフリーフォントの場合。 :

その点、英語圏のフリーフォントは、随分と状況が違っている印象があります。

まず、独自ライセンスではなく、よく知られているライセンスを選ぶ傾向があります。GPL、BSDライセンス、MITライセンス、CC(Creative Commons)、OFL(SIL Open Font License)、等々…。

英語圏のライセンスは、許可される範囲、禁止される範囲が、比較的明確なので、安心して使えます。

そもそもあちらでは、「宗教」がどうとか奇妙なことを言い出さない印象もありますね。例えばアメリカなどは多民族国家ですから、宗教禁止などと言い出したら無駄に余計なトラブルが発生するわけで。故に、そこらへんは誰も口を挟まないことにするのが、大人の知恵、賢い対応、なのだろうなと想像しますが。

その点日本は、何かおかしいですな…。日常生活のあらゆる場面で宗教が絡んでるわりに、自身が絶えず宗教と接してることにはとことん無自覚で、それでいて突然、合理的理由も無く「宗教禁止」を言い出すのですから…。一体何を考えてるのか、というか、たぶん何も考えてないのでしょうけど。

何にせよ、フリーソフトを作る際、画面のほとんどを英語メッセージにすれば、同梱できるフォントファイルの選択肢はグンと広がると、思っておいてもいいのではないかと。

画像化するなら話は別。 :

ここまでの話は、「フォントファイルをアプリに同梱するなら」という前提の話でしたが。フォントファイルを同梱せず、ボタン画像等、画像化する方向なら話は違ってきます。その場合、独自ライセンスであっても、制限が緩くなる可能性がある…。

そんなわけで。自分が Anime PV Easy Maker ZERO を作った際は、各フォントのライセンスを調べた上で、極力、ボタン等を画像化する方向で作業したのでした。英語フォントは基本的にOFLを、日本語フォントは、同梱はできなくても画像化して使う分にはOK、というフォントだけ選んで使って…いたはずです。たしかそのはず…。

フォント関係は、実に面倒臭いですね。

まあ、見た目に拘ると面倒臭くなるという話ですが。例えば、Windowsに標準でインストールされてるフォントをそのまま使ってしまう分には、全然面倒臭くないのですけど。少し欲を出して、「もうちょっとパッと見を」なんて思い始めると…。

それでも、自身でフォントを作り始める光景を想像すると、現状でもありがたいぐらいで…。M+フォントには、いつもお世話になっております。ありがたや…。

2013/12/07() [n年前の日記]

#1 [anime] 「ログホライズン」、面白いな

NHK教育、というかETVで放映されてるアニメ、「ログホライズン」。今のところ一応どうにか毎週ぼんやり眺めてるのですが。結構面白いなと。

台詞の中に、 「適正価格」なんて単語が出てきて「おおぅ」と。見た目だけならフツーのファンタジーモノなのに、そんな単語がポーンと出てくるアニメなんて、これは珍しいなと。昔放送されてた「夢色パティシエール」の二期で、ちょっとソレに近いノリがあったな、ぐらいなもんで。

まあ、「夢色パティシエール」は途中で打ち切りっぽくなってしまいましたが…。あのノリを「もしドラ」にも期待してたんだけどな…。「もしドラ」は途中でケータイ小説みたいになっちゃって、個人的にはガックリでした…。最初のあたりで期待し過ぎちゃった…。 *1

さておき、ログホライズン。ラストのあたりで、主人公が、「ギルマス…ギルドマスター…ギルドのリーダー…」と口にするあたりに感心したり。主人公がギルマスという言葉の意味を噛みしめるシーンだと思うのですけど。おそらくは、NHK教育でアニメを見ているちびっ子達に、「ギルマスってのは、ギルドマスターの略なんだよ。ギルドマスターってのは、ギルドのリーダーという意味なんだ」と丁寧に説明している台詞でもあるのだろうと。さりげない気配りを忘れないアニメだなあ、と。

また、NPCについて語るシーンでは、上から見下ろした形のレイアウトで、八頭身の見た目はちゃんとしたキャラ達が、上下左右にのみ動くという画になっていて。これは昔のRPG画面を再現することで、そこに居るのがNPCであると示したカットなのだろうなと。お遊びで入れてるようでもありながら、映像による説明も込められてる気がして、面白い見せ方をするなあ、と。

けして派手ではなく、むしろ地味な作品だけど、あちこちで丁寧な作りをしてるよなあ、と感心する時があって。NHK教育で放送するに相応しい作品かもしれん、と、自分の中では好印象なのでした。
*1: まあ、よほど頭のいい作家さんじゃないと、ビジネス論(?)とドラマ性の融合なんてできないのでしょうし、仕方ないよなとも。あの組み合わせを思いついただけでも「一本!」なので、アレはアレで、とも思ってますが…。

#2 [anime] ルパン三世VS名探偵コナンを視聴

映画版の公開に合わせて、昨日放送されたようで。途中で放送に気づき、中盤以降はリアルタイムで見てましたが、今日は、HDDレコーダに録画していたソレを、最初から視聴したのでした。

やっぱり、面白いなあ…。結構カットされてたという話も見かけたけれど、それでも面白い…。キャラが登場するだけで、「キター!」と思える作品って珍しいよなと。

脚本も、各キャラの見せどころで苦労しながらもちゃんと上手いことまとめてる印象で。「さすがだ…素晴らしい…」と唸ってしまったシーンが多々。ツッコミどころと、なるほどと思わせる箇所の、量のバランスも取れてるような気が。

監督さんが、コナン、ルパンTVSPの両方に関わったことがある方、というのも上手く働いたのかなと。この監督さん、基本的にファミリー向けの作風が強過ぎて、個人的にはピンとこない監督さんだったのだけど。この作品に限っては、その作風がドンピシャで一致して実力を存分に発揮できてるような気がして、かなり好印象だったり。

神谷明氏が演じてるのであろう、 ルパンが変装した小五郎の演技も絶妙で。前回見た際もスゴイなと思ったけど、やっぱり何度見てもスゴイ…。

こういう作品を見ると、他にもコラボできないかなと妄想してしまうのだけど。基本的に一話完結モノ、時間が進まないタイプの作品じゃないと、この手のコラボはしにくいだろうと思えて、候補がさっぱり思い浮かばなかったり。一般的なコンテンツは、大きな話の流れがあるタイプばかりだし…。

キャラデザ・絵柄に関しては、この作品を通じて、セル画風になってしまえば意外と気にならなくなる、ということは分かったけれど。さすがに、キン肉マンと北斗の拳をコラボする、みたいなのは無理だろうし。比較的ジャンルが近い作品じゃないと厳しいのだろうなと。また、両方の知名度が無いと、コラボの効果も弱いだろうし。例えば「ゲゲゲ物語」等では、片方の知名度が圧倒的に足りないわけで…。

てなことを考えると、ルパンVSコナンという企画が生み出せたのは、まるで奇跡のようだなと。コラボの条件がここまで一致する両作品って、他にはちょっと思いつかない…。

再放送とは言え、イイもの見せていただきました。ありがたや。いやー、面白かった。この作品は素晴らしい。

#3 [zatta][pc][neta] モノを作る人はえてして人間としてどこかおかしいのが常、という話

昨日、「モノを作る人ってのは、えてして人間としてどこかおかしいのが常」という一文を書いちゃったのですけど。キーボードを叩きながら、「これは問題発言かもしれんなあ。怒る人が出てくるかもしれんよなあ。…でも、事実だし。書いちゃえ書いちゃえ」とやってしまいまして。

や、ホント、自分の中では、そういう印象なのです。モノを作る人ってのは、ちょっとおかしいです。人によって、どこがおかしいか、何がおかしいかは全然違ってくるので、分かりやすくおかしい人、分かりにくくおかしい人が居るとは思いますけど。

いくつか例を挙げれば分かるかなと…。

参考事例。 :

例えば、宮崎駿監督。世間一般では素晴らしい人物として認知されてる節もありますが、とんでもない誤解だよなと…。何せあの方、震災直後、まだ余震が続いてる状態でありながら、スタッフに対して「何が何でも会社に出てこい!」と怒鳴りつけた人ですから。あの緊急時にそういうことを言うのだから、まともじゃないです…。そりゃ奥さんが、息子のゴロー監督に、「アニメ業界には入らないで。私がどれだけお父さんに泣かされてきたことか」と涙ながらに訴えるわけですよ。…宮崎駿監督のそのあたりって、富野監督が言うところの、意識と身体が分離してしまった状態の一種、なのかなと思えてきたりもして。理念は分かるけど、こっちは身体とか命を持ってるんやで、みたいな。

その富野監督だって、ファミレスだか喫茶店だかで、キャラデザの方に対してオ○ンコ発言を叫んでしまったり。これもそこだけ見ると、おかしい人ですよ。もちろんそれだけ、自身の仕事に対して意識が集中してることの証明で、実に職人らしいエピソード、のような気もしますが。

故・手塚治虫先生だって、色んなエピソードがありますよね。〆切に追われて、トイレに行くと言ったまま逃亡したりとか。真夜中にチョコレート食べたいとごね始めて担当編集者が…、とか。それらエピソードだけで、漫画が描けちゃうぐらいに…。

また、コンピュータの世界では、 _リチャード・ストールマン という有名人がおりまして。GNUの提唱者、emacsを作った方、という認識でいいのでしょうかね…。この方も、何かあるたびに問題発言ばかり繰り返す方で。いや、ぶれてない故の発言なので、その内容は納得できるものばかりですけど。

発明王エジソンも、なんだか危ない。子供の頃、先生に「Why?」ばかり言い過ぎちゃって、学校に来るなと言われてしまって学校に通えなかった男、ですから…。いや、これは伝記で読んだソレなので、話を作ってんじゃないのと思わないでもないですが。まあ、エジソン関係のエピソードを探すとゴロゴロその手の話が出てくるので、やっぱりおかしい人だったのではないのかなと。

ということで。 :

他にも事例は多々あると思いますが。このように、モノづくりで何かに秀でた人というのは ―― いや、「表現者」という人種は、どこかしら、何かしら、おかしいのですよ。常識の枠を飛び越えた言動を時々見せてくれる傾向があるよなと。 *1

「モノづくり」「表現者」は、常識に囚われないからこそ、凡人では思いもつかないものを作り上げてみせる、てな面があるわけです。ある意味、「常識人」属性と「表現者」属性は、トレードオフではないのかなと。 *2

そんなわけで、何かを作ってみせた方は、基本的に、「どこかおかしい可能性が非常に高い人」として、最初から疑って見ておいたほうが無難だろうと。表現者の持つ常識と、こちら側の凡人が持つ常識は、結構大きくずれてる可能性がある。そのことで、後にトラブルが発生する可能性はある、と。

まあ、このあたり、漫画・アニメ・ゲーム・音楽・映画等々、娯楽コンテンツを楽しんでる方なら、「そういう面はあるよね」「天才って、別のところで、人として何かおかしいよね」と納得してくれそうな気もしているのですが。

人格者としても表現者としても優秀、なんて人はそうそう居ませんよね…。人間は神様じゃないんだから…。

故に日本語フリーフォントは時々危険。 :

ということで、昨日の記事内容を繰り返しますが。フリーフォント制作者様が、「宗教、アダルトで使うのは禁止」と言ってるときは、こっちは身構えておくべき、という話になるのでした。

何せ、フォントを一セット作るって、とんでもなく大変な作業なわけで…。とても凡人が出来る作業じゃない。しかし、仕事でやってるわけでもないのに、その作業を見事にやり遂げてみせて、しかも無償で使っていいよと公開してるわけで。これは良い意味で、おかしい方ですよ。<褒めてます。

その、何かおかしい方 ―― 凡人側の常識が通じない方が、「宗教、アダルト」と言ってるわけですから…。この定義は得体がしれない、正体不明の定義だぞ、後からどんな難癖つけられるか分からん、予測不能だ、と。「どう考えてもコレは宗教・アダルトじゃないだろう」と、こっち側が常識レベルで思っていても、あちらにはライセンス違反に見えてるかもしれないぞ、と。こちらの常識は通用しない。通用しないからこそ、目の前で、完成フォントが公開されているのです。

大体にして、インターネット黎明期の昔ならともかく、メジャーなライセンスが多々存在してる現在において、あえて独自ライセンスを掲げ続けているなんて、もうソレだけでトラップ臭が…。まともな人なら、今の時流に合わせて、メジャーなライセンスにさっさと切り替えてるはずなのです。しかし、変更しないということは、その独自ライセンスに、こちらが気付いてない何かが潜んでるんですよ…。おそらく、作者様の妙なこだわりの念が…。そこにうっかり触れたら爆発するんです…。

なので、そういうフリーフォントは使うのを避けておいた方が無難、と自分は思っているのでした。まあ、フォントに限った話ではないのですけど。フリーソフト等も、時々そういうトラップ臭が…。

まあ、「作者様に見つからなければ、問題にはならないし」てなノリでガンガン使っちゃうのもアリかもですけど。怒られたら「ゴメンテヘペロ」で済むかもしれないし。いや、済まないかもしれないけど。

*1: もちろん、表現者として優秀であっても、対人トラブルを全然起こさない方だってたくさん居ますけど。ただ、それは、人前で仮面を被るのが上手いからであって…。中身はやっぱり、どこかおかしいはずなんです。
*2: だからといって、ひたすら非常識な人間なら、必ず表現者として成功するわけではないあたりが、なんだか悲しいですけど。それはさておき。

#4 [dxruby][game] DXRubyで例の多関節を実験

今日もDXRubyを使って、動きを作ってみます。

今回のネタは、昔懐かしの、あの多関節を試してみようかなと。学生時代、ファミコン版でプレイしていて、必ずこの敵で何機か失ったことを思い出します。やられグセがつくと、なかなか抜け出せなくて…。

自分、この処理は、書いたことがないんですよね…。昔、隣で先輩が書いてるソレを見て、「スゴーイ。まさしくアレだー」と子供のように喜んでしまった記憶があります。さて、自分は上手く書けるだろうか…。少し不安。

とりあえず、できた…かな…と思います。こんな感じの動きで合ってますかね? 微妙に何か違う気もするけど…。
グルグル回る例のアレ
# ぐるぐる回る、あの多関節のテスト

require 'dxruby'

# ボディ部分のスプライト
class BodySpr < Sprite
  
  # 初期化処理
  def initialize(sx, sy, dist, ang, img)
    super
    @px, @py = sx, sy # 自身の座標格納用
    @cx, @cy = sx, sy # 円運動の中心座標
    @dist = dist # 円運動の半径
    @ang = ang # 円運動の角度
    self.image = img # 画像
    
    self.scale_x = 1.6 # 拡大縮小率
    self.scale_y = 1.6
  end

  attr_accessor :px, :py
  
  # 毎フレーム呼ばれる処理
  def update
    # 円運動をさせる
    rad = @ang * Math::PI / 180.0
    @px = @cx + @dist * Math.cos(rad)
    @py = @cy + @dist * Math.sin(rad)
    
    # 描画位置を設定
    self.x = @px - self.image.width / 2
    self.y = @py - self.image.height / 2
    
    @ang += 0.7
  end
end

# 腕関節一つ分のスプライト
class Arm < Sprite
  
  # 初期化処理
  def initialize(sx, sy, dist, ang, img, parent)
    super
    @px, @py = sx, sy
    @cx, @cy = sx, sy
    @parent = parent # 親を記録
    @dist = dist # 親からの距離
    @ang = ang # 自分の角度
    @angt = ang # 親と自分の角度を加算した角度
    self.image = img
    self.center_x = img.width # 回転描画の中心位置をずらす
  end

  attr_accessor :angt, :px, :py

  # 毎フレーム呼ばれる処理
  def update
    if @parent.instance_of?(BodySpr)
      # 親がボディ部分だった場合
      @ang += 1
      @angt = @ang
      self.angle = @angt
      bx = @parent.px
      by = @parent.py
    else
      # 親が腕部分だった場合
      @angt = @parent.angt + @ang # 親の角度+自分の角度を得る
      self.angle = @angt
      bx = @parent.px
      by = @parent.py
      
      @ang += 0.3 # 自分の角度を少しずつ増やしてく
      @ang = -60 if @ang > 60
    end
    
    # 自身の座標を算出
    rad = @angt * Math::PI / 180.0
    @px = bx + @dist * Math.cos(rad)
    @py = by + @dist * Math.sin(rad)
    
    # 描画位置を算出
    self.x = @px - self.image.width
    self.y = @py - self.image.height / 2
  end
end

# 画像読み込み
img = Image.load("arm.png")
imgbody = Image.load("ufo.png")

# ボディ部分の発生
cx = Window.width / 2
cy = Window.height / 2
body = BodySpr.new(cx, cy, 80, 0, imgbody)

# 腕の初期化処理
sprs = []
armmax = 4 # 腕の本数
jointmax = 12 # 関節数
dist = 22 # 関節の長さ

# 何本か腕を延ばす
armmax.times do |i|
  parent = nil
  
  # 腕一つにつき、n個スプライトを使う
  jointmax.times do |j|
    if j == 0
      # 腕の根元
      s = Arm.new(cx, cy, 32, i * (360 / armmax), img, body)
    else
      # 腕
      s = Arm.new(cx, cy, dist, 0, img, parent)
    end
    sprs.push(s) # リストに登録
    parent = s # 次の親として扱う
  end
end

# メインループ
Window.loop do
  break if Input.keyPush?(K_ESCAPE)

  body.update # ボディを移動
  Sprite.update(sprs) # 腕を移動
  
  Sprite.draw(sprs) # 腕を描画
  body.draw # ボディを描画
end
これまた長くなってしまいました。もっと短く、スッキリ書けないものか…。

一応ざっくりと説明を。

今回は、DXRubyの Spriteクラスを使ってみました。Spriteクラスを継承して、ボディ部分を担当するクラスと、腕関節一つ分を担当するクラスを作ったわけです。自分は、Rubyについては初心者なので、こういう書き方でいいのかよく分かってませんが。

腕関節には、誰が親なのか、覚えさせておきます。@parent がソレです。また、親からの距離、親の角度+自分の角度を使って、自分の位置も求めます。

図で描いたほうが分かりやすいですかね…。一応描いてみましたが…。
説明図
この、親、子、孫…という状態が、10個前後ほど、ずっと続いているわけです。

子は、親からの距離、親の角度+自分の持ってる角度で、自分の位置を決めます。図で言えば、小さい四角い点がソレですね。また、スプライト描画の回転中心位置を、この小さい四角の位置にしておけば、各関節が滑らかに繋がっているように見えるはずです。

ひょっとして、位置の求め方が分からない方が居たりするのかもしれないか…。距離と角度があれば、sin関数、cos関数を使って、位置を求めることができますよ。
x座標 = 距離 * cos(角度) + 親の位置 x
y座標 = 距離 * sin(角度) + 親の位置 y
ソース中では、 rad = @angt * Math::PI / 180.0 なんて行もありますけど。これは、度からラジアンへの変換をしています。というのも、プログラムを書く際の sin関数、cos関数は、えてして、度ではなくてラジアンを与えないといけないので…。

それにしても、Ruby って、度とラジアンの変換関数は無いのでしょうかね…? ググってみても、見つかりませんが。

さておき。

もしも、子供達全員が持っている角度が、0度だったら。この仕組みだと、どんな見た目になるでしょうか。…皆でピーンと、一直線になりますね。

子供達が持っている角度が、例えば10度だったら…。下の方に曲がっていく線になるはずです。逆に、全員が、-10度を持ってたら、上の方に曲がっていく線になるでしょう。

そして、子供達全員が持っている角度が、毎フレーム、少しずつ増えていったら…。線の曲がり具合が、時間と共に、グングン変わっていくはずです。

とまあ、こんな仕組みで、あのグルグルはできていたのではないかなあ、と思いますが、本当にコレで正解なのかどうか…。まあ、それらしく動いてるから、コレはコレでOKかなと。

長年、例のアレって、どうやって動いてたのかビミョーに気になっていたのですが。今回もどうにか実証(?)できたので、ちょっぴり嬉しいです。こんなにもお手軽に、実験を可能にしてくれる、DXRubyよ、ありがとう…。

とりあえず、画像とソースも置いときますね。Public Domain ってことで一つ。

_rolltaka.zip

おっと。書き忘れてた。一昨日の記事で、二足歩行の動きを試した際に、IKがどうとか書きましたが。今回のソレは、各関節が角度を持っていて、根元からの角度で位置決めをしていくわけですから…。概念としてはFKに近いのではないかと思います。もちろん、3Dでグリグリ動いちゃう今時のアレコレと比べると、原始的なものですが…。

#5 [pc][neta] Z80のXOR A

ここ数日、DXRubyを使って多関節がどうこうとか書いてますけど。

巷のゲームの画面の中では、3Dでグリグリとモデルが動くのが当たり前の、こんなゴイスな時代に…。こんなの書いてみて何の意味があるんだろうと不安になっていたりもするのです。けして、ドヤ顔で書いてたりはしないです…。

こういうのって、「Z80のXOR A」に近いかもと、チラッと思ってしまったりもするのです。

「Z80のXOR A」ってのは…。昔々、Z80という8bit CPU上で、アセンブラを使ってプログラムを書く際に、「AレジスタをクリアするならXOR Aがベスト」というノウハウがあったのですよ。Aレジスタをクリアする命令は色々あるけど、XOR Aは、命令実行クロック数が一番少ないので一番早く処理が終わる上に、1バイトで済む命令だから容量も食わないのです。以下のページが参考に…なりそうかな…。

_Ticalc Japan :: Z80アセンブラの小技

当時は役に立つノウハウだったけど、今ではさっぱり役に立たないノウハウですよね。コンピュータの世界って、そういう話がゴロゴロしてるわけですけど。

なので、ファミコンその他で動いてたプログラムの仕組みを解説するのって、実は「Z80のXOR A」を説明してるようなものではないか、と不安になるという。いや、たぶん、その不安は、かなり当たってる気がしますけど。

ただ、それでも、多関節のソレなどは、まだ応用が効くほうなのかなとも思えていて。

2Dで動かしてるモノを眺めてる分には、「こんな古いものを…父さん…酸素欠乏症にかかって…」てな感想にしかならないでしょうけど。 等々。

とまあ、そんな感じで、不安になりながらも、そういう理論武装(?)を頭に浮かべながら、その手の話を書いてたりするのでした。

同じモノを眺めていても、スルーしちゃう人と、何かを学び取ってしまう人って居るわけですし。もっとも、自分は前者なので、どんな情報に価値があるのか判断がつかないのですけど…。だったら、とにかくアウトプットしてみたほうがいいのかなと。

2013/12/08() [n年前の日記]

#1 [dxruby][game] DXRubyを使って星を飛ばしてみる

今日も DXRuby を使って何か書いてみますよ。そろそろ自分の中でネタ切れ感がありますけど…。

今回は、星をたくさん飛ばしてみようかと。今風のソレでカッコよく言うと、パーティクル処理…ってこのレベルでそんな呼び方をしたら、なんだか怒られそうな気もしますが…。

まずは単純に、等速度運動で飛ばしてみました。

等速度運動で飛んでいく星達
# 星を飛ばす。単純な等速度運動

require 'dxruby'

# 星一つ分のSprite
class Star < Sprite
  attr_accessor :dx, :dy, :rx, :ry, :cx, :cy

  # 初期化処理
  def initialize(cx, cy, img)
    super
    self.cx = cx
    self.cy = cy
    self.image = img
    self.init
  end

  # 座標初期化処理
  def init
    self.rx = self.cx # 発生位置を設定
    self.ry = self.cy
    
    rad = rand(360) * Math::PI / 180.0 # 乱数で角度を得る
    speed = rand(6) + 2 # 乱数で速度を得る
    
    self.dx = speed * Math.cos(rad) # sin と cos を使って、速度x,yを求める
    self.dy = speed * Math.sin(rad)
  end

  # 毎フレーム呼ばれる処理
  def update
    # 速度を加算
    self.rx += self.dx
    self.ry += self.dy

    # 描画座標を設定。画像の中心を基準位置にしてる
    self.x = self.rx - self.image.width / 2
    self.y = self.ry - self.image.height / 2

    if self.rx < 0 or self.rx > Window.width or self.ry < 0 or self.ry > Window.height
      # 画面外に飛び出したら座標や速度を再初期化
      self.init
    end
  end
end


img = Image.load("star.png")

# 発生位置。画面の右上のほうに設定
cx = Window.width * 0.75
cy = Window.height * 0.25

sprs = []
64.times do
  sprs.push(Star.new(cx, cy, img)) # 星を発生させて配列に登録
end

# メインループ
Window.loop do
  break if Input.keyPush?(K_ESCAPE)

  Sprite.update(sprs)
  Sprite.draw(sprs)
end
また長くなった…。もっとシンプルに書けないのかな…。

やってることは、星一つ分を表示するクラスを作って、大量に発生させてるだけです。 これを延々繰り返してるだけですね。

2Dゲームなら、この動きでも十分と言えば十分、ではあるのですけど…。例えば…。 そのような調整を加えるだけで、結構見た目が変わりますし。

でも、ちょっと欲が出てきました。もう少し、一工夫してみようかなと。

とりあえず、座標計算だけは3Dにしてみたりして。

座標計算だけ3Dになってる星達
# 星を飛ばす。座標だけ3D計算

require 'dxruby'

# 星一つ分のSprite
class Star < Sprite
  attr_accessor :rx, :ry, :rz, :cx, :cy

  @@scrz = 200 # 画面までの距離
  @@dz = -2.5 # z座標の速度
  @@w = 256 # 星の発生範囲

  # 初期化処理
  def initialize(cx, cy, img)
    super
    self.cx = cx
    self.cy = cy
    self.image = img
    self.init
  end

  # 座標初期化処理
  def init
    self.rx = rand(@@w) - (@@w / 2) # 発生位置を設定
    self.ry = rand(@@w) - (@@w / 2)
    self.rz = rand(256) + 10
  end

  # 毎フレーム呼ばれる処理
  def update
    # 速度を加算
    self.rz += @@dz
    
    # 画面のこちら側に飛び出してたら座標を初期化
    self.init if self.rz <= 0.0
    
    # 描画座標を算出
    px = self.rx * @@scrz / self.rz
    py = self.ry * @@scrz / self.rz
    self.x = self.cx + px - self.image.width / 2
    self.y = self.cy + py - self.image.height / 2

    if self.x < 0 or self.x > Window.width or
        self.y < 0 or self.y > Window.height
      # 画面外に飛び出したら座標や初期化
      self.init
    end
  end
end


img = Image.load("star.png")

# 発生位置。画面の右上のほうに設定
cx = Window.width * 0.75
cy = Window.height * 0.25

sprs = []
64.times do
  sprs.push(Star.new(cx, cy, img)) # 星を発生させて配列に登録
end

# メインループ
Window.loop do
  break if Input.keyPush?(K_ESCAPE)

  Sprite.update(sprs)
  Sprite.draw(sprs)
end
うーん。GIFアニメのフレームレートが低くて、パッと見では、違いが分かりづらいかなあ…。16FPSでは、こうなっちゃうか…。実際に、DXRubyのウインドウ上で、60FPSで眺めると、印象が随分違うのですけど…。まあ、いいや。

ちなみに、DXRuby のサンプルスクリプト中にも、3D計算をしていて、もっと見た目がカッコイイ、flight.rb というサンプルがありますので、そちらのほうが参考になりそうな気もします。

flight.rb って、一目見ただけで、「アレが…作れそう!」と思うサンプルですよね…。眺めてるだけで、夢がひろがりんぐ。

さておき。「3D計算ってどうやればいいの?」と疑問を持つ方も居るかもしれないので、一応念のために説明図も置いときます。真横から見たらこうなるよ、という図になってます。…3D計算というか、透視投影? 透視変換? ですね。
3D計算
3D空間上のx,y,z座標値と、カメラ位置から画面までの距離を使って、画面上のx,y座標を求めたい ―― 図で言えば sy を求めたいわけですけど、こんな感じで求められますよ、と。

「カメラ位置から画面までの距離って、どんな値を決めておけばいいの?」と思われる方も居るのかな…。どうせ2Dゲームで使う予定ですし、見た目がそれっぽくなればOKなので、テキトーな値でいいです。

や、広角だの望遠だの焦点距離だのを意識して、真面目に各値を算出するのもアリなんですけど。所詮はゲームなので、見た目が大事じゃないのかなと。アレコレ正確な値よりも、見た時にイケてるかどうかが大事、と自分は思ってまして。…アニメの作画と似たノリがあるような気もします。それでカッコよくなるならインチキ上等! みたいな。

ところで、この星達。遠くの星も、近くの星も、描画画像の大きさが同じなので、なんだか今一つですね…。

一応、z座標値に基づいて、大きさを変えてみましょうかね。
距離に応じて星の大きさを変えてみる
# 星を飛ばす。座標だけ3D計算

require 'dxruby'

# 星一つ分のSprite
class Star < Sprite
  attr_accessor :rx, :ry, :rz, :cx, :cy

  @@scrz = 200 # 画面までの距離
  @@dz = -2.5 # z座標の速度
  @@w = 256 # 星の発生範囲

  # 初期化処理
  def initialize(cx, cy, img)
    super
    self.cx = cx
    self.cy = cy
    self.image = img
    self.init
  end

  # 座標初期化処理
  def init
    self.rx = rand(@@w) - (@@w / 2) # 発生位置を設定
    self.ry = rand(@@w) - (@@w / 2)
    self.rz = rand(256) + 10
  end

  # 毎フレーム呼ばれる処理
  def update
    # 速度を加算
    self.rz += @@dz
    
    # 画面のこちら側に飛び出してたら座標を初期化
    self.init if self.rz <= 0.0
    
    # 描画座標を算出
    px = self.rx * @@scrz / self.rz
    py = self.ry * @@scrz / self.rz
    self.x = self.cx + px - self.image.width / 2
    self.y = self.cy + py - self.image.height / 2

    # 大きさを変えてみる
    scale = @@scrz / self.rz
    self.scale_x = scale
    self.scale_y = scale

    if self.x < 0 or self.x > Window.width or
        self.y < 0 or self.y > Window.height
      # 画面外に飛び出したら座標や初期化
      self.init
    end
  end
end


img = Image.load("star.png")

# 発生位置。画面の右上のほうに設定
cx = Window.width * 0.75
cy = Window.height * 0.25

sprs = []
64.times do
  sprs.push(Star.new(cx, cy, img)) # 星を発生させて配列に登録
end

# メインループ
Window.loop do
  break if Input.keyPush?(K_ESCAPE)

  Sprite.update(sprs)
  Sprite.draw(sprs)
end
うむ。ド派手になった。

や。もっとさりげなく変わるかなーと思って処理を追加したけど、予想外の結果に。こんなはずでは…。まあ、これはこれで、派手だから良し。カッコよければ、なんでもOK。

updateメソッドの中で、「scale = @@scrz / self.rz」という行がありますが、ここでスケールを変えてます。変数 scale に、0.5 とか 0.25 とか掛けてあげれば、もっとさりげない見た目になるはずです。

ということで、今回は星をたくさん飛ばしてみました。一応、画像とソースを置いときますね。Public Domain ってことで。

_movestar.zip

ちなみに。

Unity には標準でパーティクルシステムがついていて、プログラムをわざわざ書かなくても、GUIで各パラメータを調整していけるのでした…。しかも、当然3Dで動くし…。ギャフン。

_Unity - パーティクル アニメータ(旧パーティクルシステム)
_Unity - パーティクルシステム(Shuriken)

でも、見るからに、操作方法を習得するのが大変そうですな…。もちろん、習得すれば、複雑なパーティクルを出せるのでしょうけど。

アプリ配布時の容量や、メモリ消費量で特に問題が無いなら、この手のソレを画像で丸々持ってしまって済ませちゃうのもアリかもですね。パーティクルを使って画像生成するソフトを紹介しておきます。

_Prominence
_発色弾
_Detonation
_パーティクリン

これらソフトで画像を作って、その画像を今回のような方法で描画するのも全然アリです。ますますド派手な画面が作れるのではないかなと。

#2 [pc][neta] Advent Calendarへの雑感

あくまで、自分の勝手な印象論です。ただの思考メモです。

ここ数日、 _DXRuby Advent Calendar 2013 を眺めて、「凄いなあ。勉強になるなあ」と毎日感心しているのですけど。

しかし…。眺めてるうちに、「こりゃ参加しなくてよかった。レベル高過ぎ。この調子だと、自分、来年も参加できそうにないなあ…」という気分に。

なんというか、自分がうっかり参加しちゃってたら…。パーティ会場で、スーツ姿の方々が談笑してる中、ジャージ姿で片手にけん玉持ってる男の子が泣きそうな顔でポツンと立ってる、てな状態になってただろうなと。「けん玉大会かと思って来てみたら、なんか全然違う…どうしよう…」みたいな。またKYになるところだった。危ない危ない。

まあ、わざわざ正月に髑髏を掲げて街中を練り歩いた一休さんの意識レベルまで到達すれば、あえてジャージ姿で、いや、どうせならハードゲイのような格好をして、パーティ会場に乗り込んで「フォーッ!」と叫んじゃうスタイルもアリかもしれないけど。そこまでの度胸も、深い考えも持ってないし。

DXRubyの内部解析だの、ラッパーライブラリを作って紹介するだの、そんなレベルに自分は行けないなと。ライブラリを作る側じゃなくて、使わせてもらう側で、「動いた動いた、面白ーい」とやってるレベルですから。

それにしても。

なんだか年々、各言語の Advent Calendar のレベルって、高くなってる気がしていて。RSSで流れてくる様々な記事を眺めていると、こりゃ凄いことになってるなー、と。

誰かが、「インターネットは、毎日毎日、天下一武道会が開かれてるようなもの」と喩えてたけど。Advent Calendar は、その天下一武道会で勝ち進んできた強者が、さらにそれぞれ対戦を始めちゃってる、そんな印象だったり。

自分が最初にその手のイベントを知ったのは、たしか Perl関係でしたけど。その頃は、本当にさりげないちょっとしたtipsも、まだポツポツと紹介されてた記憶があって。

ところが今は、言語の内部に掘り進んでみた感じの、ゴイスな記事が多々。年に一度の文化祭で研究結果を発表します、いよいよ来たぜ! 俺達の晴れ舞台! みたいなノリで。コレ、凡人では観客側にしか回れないよなと。

もしかするとこのあたり、男性の性なのかなと。仮に些細な分野であっても、いつの間にか、ついつい競争を始めてしまう、男の習性。

女性のように、「○○に砂糖を使うと美味しくなるのよ」「あらそうなの? 今度試してみるわ」てな、なごやかな雰囲気にはならなくて。「アイツには負けていられない。俺はもっと上を行かねば」みたいな気持ちになって、やることのレベルがグングン上がっていく、みたいな。

さらに、プログラマーは、肉体的優位性で勝負をする人種ではなく、知識量で勝負をしている節もあり。それに加えて、自身の発表内容や、所属しているコミュニティの属性が、就職先や転職先まで左右する可能性も否定できなくて。

そんな状態だから、「これは手を抜けない…」とプレッシャーを感じて、それがそのコミュニティのレベルを押し上げてるところもあるのかなあ、と。

もちろん、どれもためになる記事ばかりなので、観客側としてはとてもありがたいわけですけど。「君も参加してみない?」と誘われても、「いやいやいや! 無理無理無理! 絶対無理!」という状態になってきてる、ような気もしているのでした。

自分はヤムチャだから瞬殺されること間違いなしッスよ…。

2013/12/09(月) [n年前の日記]

#1 [anime] 境界の彼方、白の世界を視聴

なるほど…そういうことだったのか…。

誰かが、「点が線になっていく」と言ってたけど。たしかに、まさしく、その通りだなと。「このヒロイン、なんでそんな言動を…」と疑問に思った部分が、全部綺麗に一直線に繋がっていく。これは見ていて気持ちいいなと。そして、気持ち良さを感じた分、グングンと切ない気持ちにさせられて、作品への印象がガラリと変わってくる。いやー、これは上手いわ…。

おそらく、この作品、1回目の視聴と2回目の視聴では、印象が随分変わりそうな気がしたり。

1回目と2回目の視聴で印象が変わる作品と言えば、「まどかマギカ」や、映画「シックスセンス」が思い浮かぶのだけど。それら作品は、最初から終わりまで、シリアス一辺倒だったわけで。

しかし、この作品、それらとはちょっと違いがあって。1回目の視聴時は、おそらくほとんどの人は笑って見ていたはず。なので、2回目の視聴時は、その分、かなり強烈な感覚を味わえそうだなと。何故なら、笑えた各シーンが、見ていてボロ泣き(?)するシーンに、まるっと転換されるはずだから…。2回目からは、終始、胸を締め付けられるような切ない感覚を味わえる、そんな作品に変化しそうな予感。

まあ、まだ最終回は放送されてないので、どうなるのかは分からないのですけど。それでも、既に現時点で、作りからしてかなり稀有な作品になってるのではないかと思えてきたり。

花田脚本+京アニの本気を見せてもらったような気がします。や、「俺達いつも本気だよ?」と怒られちゃうかな…。何にせよ、素晴らしい。

OP・ED曲の歌詞。 :

なんだか少し、OP曲やED曲の歌詞が気になってきたり。作品内容を、一応そこそこ反映してたりするのかなあ…。

もっとも、世の中には、「少年漫画が原作のアニメのOP曲を作れと言われたけど自分は少年漫画なんか読んだことないから『キャンディキャンディ』を思い浮かべながら作ってみました」てな「お前ちょっとここに座れ」と言いたくなるアニメのOP曲もあったりするので、この作品のOP・ED曲も、そういうテキトーなノリで作られてるのかもしれんなあ、あるいは作品とは全然関係ない楽曲を「このグループを売り出したいから」と捻じ込まれたりしてる可能性もあるのだろうな、と邪推したりもするのですけど。

しかし、もし、万が一、ちゃんと作品内容を真面目に反映させた歌詞になってるとしたら…。例えば、こんな感じの映像で、こんな感じのタイミングで、曲を流し始めたら…。うわヤベエ、こりゃかなりクルぞ、号泣間違いなしだぞコレ、てな妄想をしてしまったり。

あー。いかんいかん。この流れはマズい。またしても勝手に脳内で理想の最終回を作り始めてしまった…。リセットリセット。忘れろ忘れろ。作品を美味しくいただきたいなら、脳内で理想映像を作っちゃいけない。

「ソレ」に期待しちゃいけない。希望を持っちゃいけない。不必要に、思い入れを持ってしまってはいけない。勝手に期待して、当たり前のように裏切られて、それでツラい思いをするのはこっちなんだから。距離を取ろう。心を氷にしよう。どうせ「ソレ」は、自分にとって、きっとろくなもんじゃないんだ。そうに違いない。…そう思いながら、「ソレ」に接しないと。

てなことを書いてるうちに、なんだかヒロインの気持ちがますます理解できてしまったような、そんな気分にもなってきたり。あのヒロインの頭をなでなでしてやりたくなってきました。

なんとなくだけど。日本アニメ史の中でも五本の指に軽く入りそうな薄幸メガネ美少女設定やなー、と思えてきましたよ。「太陽の王子ホルス」のヒルダにメガネつけてみたレベルだったりしないかコレ。って方向性が全然違いますね…。

#2 [dxruby][game] DXRubyでファイル選択ダイアログやフォルダ選択ダイアログを開く

今日も DXRuby を使って何か書きますよ。

今回は、ちょっとゲームとは違う部分でも、DXRuby って使えたりもしますよ、みたいな話を。…まあ、この話、前にもこの日記でメモしてた記憶もあるんですけど。せっかくだから、この際もう一度紹介を、と。

Windows + Ruby で何か処理をする際、ユーザさんに、任意のファイル、もしくは、任意のフォルダを指定してもらいたい場面があるわけですが。

一般的には CUI で、
ruby hoge.rb 指定ファイル
と指定する方法がメジャー、ですかね?

でも、プログラマーさんにお願いするならともかく、一般的なユーザさんに、「DOS窓開いて、こういう文字列を打ち込め」なんて、ちょっとお願いしにくいじゃないですか…。できれば、GUIで ―― ファイル選択ダイアログや、フォルダ選択ダイアログを開いて、ファイルやフォルダの指定をさせてあげたい…。

そんな時、DXRuby が役に立つかもしれません。

DXRuby の Windowクラスには、ファイル選択ダイアログを開くメソッドが用意されてまして。
# DXRubyでファイル選択ダイアログを開く

require 'dxruby'

filters = [
           ["画像ファイル(*.jpg;*.bmp;*.png)", "*.jpg;*.bmp;*.png"],
           ["テキストファイル(*.txt)", "*.txt"],
           ["すべてのファイル(*.*)", "*.*"]
          ]

filepath = Window.openFilename(filters, "ファイルを選んでください")

if filepath
  puts filepath + " を選択しました"
else
  puts "キャンセルしました"
end
ファイル選択ダイアログ
>ruby fileselect.rb

C:\home\prg\ruby\test_dxruby\fileselect_sample\えっちなのはいけないと思います!.png を選択しました
ね、簡単でしょ? (ボブの口調で)

さらに、DXRuby 1.5.3 dev 版以降に限定した話ですが、フォルダ選択ダイアログを開くこともできるのです。
# DXRubyでフォルダ選択ダイアログを開く
# ※ DXRuby 1.5.* dev 版が必要

require 'dxruby'

folderpath = Window.folder_dialog("フォルダを選択してください")

if folderpath
  puts folderpath + " を選択しました"
else
  puts "キャンセルしました"
end
フォルダ選択ダイアログ
> ruby folderselect.rb

C:\home\prg\ruby\test_dxruby\fileselect_sample\不死鳥はもはや籠の中の小鳥よ!フォルダ を選択しました
ね、簡単でしょ? (ボブの口調で)

そんなわけで、「Windows + Ruby + GUI で、ファイルやフォルダを選択させたいなあ。それも、サクッと、簡単に」と思った時は、DXRuby を使っちゃう手もありますよ、という話でした。DXRubyの作者様、ありがとう…。この機能、ちょっとした場面で、地味に便利に使えてます…。

他にも色々方法はありますが。 :

む。「汝、 _Win32OLE を使え…」という電波が届いたような。たしかにソレも全然アリでございます。

Windows + Ruby で、ファイル/フォルダ選択ダイアログを開く手段は、他にも色々ありまして。例えば、以下のページが大変参考になるかと。ありがたや。勉強になります…。

_ruby 覚え書き

ただ、眺めてみると分かりますけど、自分のようなRuby初心者には、記述がちょっと難しくて…。「こっちはファイル選択したいだけなのに…」みたいな。もちろん、記述が難しい分、他にも色々なことができてしまうメリットはあるのですけど。

また、VisualuRuby のように、Ruby 1.8 までしか正式対応してないライブラリもあったりするので、「Ruby 2.0.0 が安定版」と宣伝されてる現在では、使えないやり方もチラホラ…。 *1

その点、DXRuby のソレは…。
  • やれることが決まってる分、記述は簡単。
  • DXRuby 開発版なら、Ruby 2.0.0 にも対応してるので、しばらくは安心して使える。
といったメリットがあるんじゃないかなと。まあ、複数ファイルを指定できない等のデメリットもあった気もしますが、高機能と簡便さはトレードオフじゃないのかなと。

*1: Rubyの配布パッケージによっては、Ruby 1.9上でも vruby が同梱されてたものもあったような…。でも、ググってみても見当たらず…。自分の偽記憶だったのかな…。何にせよ、Ruby 2.0.0 以降で vruby を動かせてる事例は全く見た記憶が無いので、どのみち、これからは使える見込みがないライブラリ、と思っておいた方がいいんじゃないかなあ…。Python と比べると、Ruby用のGUIライブラリって、何故かそういう展開が多く…ゲフゲフゴフン。

2013/12/10(火) [n年前の日記]

#1 [web][neta] AmazonからのDMを眺めてたら

AmazonからのDMを眺めてたら、おむつがオススメされていて。

何故…趣味がバレたのだ…。

嘘です。そういう趣味は全然ないです。なんとなく思い出したことがあるとすれば、お腹の調子がとてもとても悪い時に、「大人用おむつを使えば、こういう時も安心なのかなあ」と思ったぐらいで。そんな状態になってる時に、Amazonで、大人用おむつの値段を調べてみたことがあったのかしら。かもしれん。

おむつと言えば。若かりし頃、レモンピープルというその手の漫画雑誌上で、何かと言うとおむつを描き始める漫画家さんの作品を毎号見かけたのですけど。「この趣味はよくわからん…」と思った記憶もありまして。や、考えてみれば、それらの作品は、おしゃぶり、よだれかけも描かれてたっけ。つまりは、赤ん坊を連想させるためのアイテムとして活用されてたのだろうけど。そういうコスプレをすることで、何を引き起こそうとしていたのだろう…。赤ん坊そのものへの反応なのか、普段はしていない服装をすることへの反応なのか。もしかすると単に後者だったりするのかな。だとすれば、もっと異なるバリエーションも通用しそう…。ゴミ袋被ってるだけとか、ダンボール被って「GUNDAM」と書いてあるだけでも、それらの層は反応しそうな気もする。社会的に認められている服装ではなく、反社会的服装をすることで、とかそのへんが…。

まあ、Amazonのソレを見て、そんなどうでもいいことを思い出しました、てなだけの話なんですけど。

#2 [anime][neta] 刑事コロンボと魔法少女アニメ

「境界の彼方」の感想を書いてるうちに、ふと思い出したことがあるのでメモ。思考メモです。結論は無いです。結論は無いです。大事なことなので二回言いました。

刑事コロンボの異質さ。 :

昔、平成ライダーシリーズのプロデューサーさんが、blogを書いてた時期がありまして。そのblogの中で、刑事コロンボの異質さについて述べていたのです。たしか、こんな話で…。

「一般的な刑事ドラマは、犯人がラスト直前まで分からない」「しかし、刑事コロンボは、いきなり冒頭で、誰が犯人なのか説明してしまう」「それでいて、ドラマとして、ちゃんと面白い」「刑事コロンボ、パねえ。アレ、ヤバイ」みたいな話で。

その記事を読んだ時に、「ああ! ライダー555って、そういう構成だったのか!」と、ようやく気づくことができまして。一般的な特撮ヒーロー番組は、そのほとんどがコロンボ方式なのだなと。どうして主人公が変身できるのか、大体は第1話で説明しちゃう。仮面ライダーシリーズも、その構成をえてして踏襲してる。でも、ライダー555は、ちょっと違う。あえて、非・コロンボ方式で構成してみた作品だったのだなと。「ライダーシリーズを使いながら、そんなところでも大冒険してたのか…。チャレンジャーだなあ」と自分は感心させてもらったのでした。

で。それから幾年が過ぎて。

魔法少女アニメを見て悩んでしまった話。 :

ついこないだまで、とある魔法少女アニメ? 変身ヒロインアニメ? が放送されてたのです。これが、既存作品をつまみ食いしたようなアニメで。タロットカードがどうとか、心の闇を持った少女達が怨念のようなものと戦うとか、「CCさくら」+「まどかマギカ」なのかなと。や、ただの邪推ですけど。

そのアニメの中で、最終回ちょっと前に、主人公に対して「実はあなたの出自は…」「ガーン」みたいなやり取りがありまして。

それを見て、自分はかなり白けちゃったのです。

最終回ちょっと前に、「重大な秘密が、今、明かされる!」てのは全然OKで。「まどかマギカ」だってそうだし、先日見た「境界の彼方」もそうだし。やっぱりラスト前は盛り上げないといかんよなと。

でも、主人公の出自がどうとか、そんなの別に重大な秘密でも何でもないよなー、と。例えば、「青の祓魔師」なんか1話目でさっさとバラしてるわけで。「仮面ライダー」だって1話目でさっさとバラしてる。それどころか、毎回OPで「本郷猛は改造人間である!」とナレーション使って自己紹介までしちゃってる。

そういった作品群を思い返すと、このアニメは何をやっとるのかなあ、と。OPで毎回自己紹介したっていいぐらいの設定を、1クールの終わり頃まで後生大事に隠しておく意味あったのかなと。このスタッフ、「コレはスゴイ秘密だぞ! きっと視聴者もビックリだあ!」と思いながら構成してたのかなと。

薄いわ…。何もかも薄いわ…。頭の中身ペラッペラだわ…。ジャンル中では後発だから、何か勝算を見出しつつ取り組んでるのかなと期待しつつ眺めてたけど。実は何も武器持ってないじゃねえか。最後に出してきた秘密兵器がコレか。なんだこの企画。いやー、コレは薄いわあ。「まどかマギカ」という、ジャンル中では「ガンダム」クラスの後だから、せめて「ダグラム」「ボトムズ」を出してくるのかなと思ってたら「ガンガル」出てきちゃったヨ。みたいな。

しかし、そんな失礼極まりない不遜な感想を持った直後に、考え込んじゃいまして。ソレって、ライダー555と同じ構成じゃないのかと。要は、非・コロンボ方式だよなと。じゃあ、同じ方式をやってみせたライダー555はつまんなかったのか。とんでもない。結構面白かった記憶があるわけですよ。

同じレベルの設定を、似たようなタイミングで明かしたのに、片方は面白くて、片方はつまんない。これってどういうことだろう。一体何が違うんだろうと。

ライダー555の井上脚本は、おそらく何かをちゃんと抑えつつ書かれていて、「実はこうでした」ってところまで見事に持っていった。件のアニメは、そこを抑えてない脚本を平気で書いてた。ということじゃないのかなと。さて、一体何が肝だったのか…。どこに勝利の鍵があるのか…。

そのあたり、なんだか考え込んでしまったのでした。

とりあえず違いをリストアップしてみる。 :

具体的に違いを洗い出してみないと見えてこない気もするので、思い出せる範囲でリストアップしようかなと。ただ、それぞれが、実際にポイントかどうかは、これはさっぱりわからないのですが。

まず、主人公自身が秘密を知ってたかどうか、てな面はあるのかなと。ライダー555は、主人公が秘密を知ってた。件のソレは知らなかった。このへん、地味に関係ありそうな気もしたり。

秘密を知っていて、しかもそれを隠し持ち続けていると、主人公は苦悩するわけで。
  • 秘密を周囲に知られないように振る舞うから、場合によっては、なかなか周囲に心を開けなかったりする。
  • それはつまり、周囲と打ち解け、信頼関係を築いていく流れも、少しずつ書けることに繋がる。
  • そうしてせっかく積み上げた信頼関係が、「止むに止まれぬ状況下で秘密がバレる」ことで、崩壊していく様子も描ける。
  • そこからまた関係を再生していく流れも描ける。
その流れは、視聴者を感動させる手管に成り得るのかなと。そして、そういう構成は、非・コロンボ方式のみならず、コロンボ方式上でも十分通用する。「青の祓魔師」なんて、まさにそのタイプで。

そういや「まどかマギカ」もそうだったなと。秘密を ―― 心に秘めた想いを押し殺しながら振る舞ってるキャラが居て、その秘密が明かされた時に、視聴者はそのキャラの言動の謎・心情が理解できて…。不可解に思っていた分が一気に氷解するから、そのキャラに対する、視聴者側の感情の反転が起きる。それが雪崩のように感情移入へと繋がり、心を揺さ振られてしまう。という構成だったような気がしてきたり。

しかしそもそも、キャラが自身の秘密を知らないと、そういう葛藤はゼロだなと。視聴者が秘密を知った瞬間が、主人公が秘密を知った瞬間になるのだから…。そこまでは、ソレについての葛藤が何一つ描けない。コレ、結構痛手な気もしたり。ストーリー面で、まるで手錠をかけられてる状態のような。「秘めた想い」とか「苦しみ」とか何も付随できない。地味に厳しい気がします。

秘密そのものには、実は大して価値はないのかもしれない。「この秘密を明かせばビックリだあ!」なんてレベルで止まってちゃいけない。その秘密が明かされることで、周囲のキャラがどんな変化を見せるのか、あるいは、そこに付随していた感情を視聴者が理解できることが大事、だったりするのかなあ…。

そういや…。そもそも、開示のタイミングも全然違ってた気も。ライダー555は、中盤前後で開示してたんじゃなかったかな…。

もしかすると、ライダーのスタッフ間では、「これは最後まで引っ張れるほどヘビーな設定じゃないだろ」という意識があったのかしら。たくさんヒーロー番組を作ってきた職人さん達だから、客観的に、あるいは感覚的に、その設定の重さを正確に判断できていたのかも。

そして、件のソレは、そこを読み違えてしまった…。いや、もしかすると、二期の制作も視野に入れてて、一期目の1クールの最後が全体の中盤と考えていたのかな…。それならまだ分からんでもないような…。

秘密の開示の仕方も違ったような。ライダー555は、映像を使って開示してたけど。件のソレは、先生役の台詞だけで開示しちゃってた。画を使って、バーン!ドギャーン!と説明されるのと、言葉で説明されるのでは、似たような内容でも印象がガラリと変わるよなあ…。

キャラの人間関係も、ライダー555は複雑だった気がしたり。ライダー側の仲間達と、そのまま対になる敵側の仲間達を用意して。見るからに「コレは考えたなあ」って感じで。しかも、「実はコレ、ライダー側が正義の味方ではなくて、敵側が正義の味方だったりしねえか?」と思わせる話も時々あったような。そのあたり、戦うトレンディドラマと称されたジェットマンを手掛けた井上脚本の手腕が遺憾なく発揮された面もあるのでしょうけど。要するに、「見ていて考えさせられる」シチュエーションが散りばめてあったなと。

件のソレは…別に複雑な人間関係ではなかったような…。昨今のアニメにありがちな、とにかく女の子ばかりたくさん出せや、みたいな安易さが漂うキャラ配置だったし…。善と悪の描き方も、別にコレと言って…。「ああ、よくある設定ですね」てな感じで。

そもそも、長さが違うか…。4クール近い作品と、1クール作品では、詰め込める量は最初から違うし。あらかじめ用意しておく設定の複雑さは違ってくるよな…。

考えてみたら、ライダー555は群像劇になってたけど。件のソレは、「魔法少女モノ」「変身ヒロインモノ」という分類以外の分類が、何も思いつかない…。結局、秘密の開示云々以前に、「コレは面白い」と思える部分が、あまり…。

うむ。わかりません。何を抑えてたら面白くなりそうなのか、さっぱり分からないや。せいぜい、どのキャラにどんな秘密を持たせておいて、どの程度までそのキャラに知らせておくのか。あるいは、どんな形で開示するのか。そこはよく考えておかないといかんのかもしれんなあ、ぐらいの漠然としたことしか…。

要するに、ライダー555は面白いのです。井上脚本はスゴイです。この記事にオチはないです。ゴメンナサイ。

#3 [dxruby][game][web] DXRubyとWeb記事

今日も DXRuby を使って何か書いてみますよ。と言いたいところなんですけど、ゴメンナサイ。とうとうネタ切れです。書けそうなネタが思いつかない…。

なので、今回はちょっと違う話というか、自分の勝手な印象論だけでも、この際書き残しておこうかなと。

ここ数日、DXRubyを使って、2Dゲームのアレコレを書いてはみたものの。「DXRubyってWeb記事が書きづらいなあ…」と毎回感じていまして。「記事」を書きづらいわけではなくて、「Web記事」が書きづらいという話ですが。

要するに、実行結果をWebブラウザ上で表示できないあたりが、インターネット全盛の現代では結構痛い気がするなと。もちろんそのあたりは、書籍等、紙に印刷された記事も、同じデメリットを抱えているのですけど。

例えば、以下の言語・環境を使えば、サンプルプログラムの実行結果を、Web記事と同時に閲覧してもらうことが可能になるわけです。 「Web記事をスクロールさせていくと、インタラクティブ性を持ち、それなりのフレームレートで動く実行結果が目の前に出現する」 ―― そんな見せ方ができるので、間違いなく訴求力があるだろうなと。「おお、スゲエ!」とか「なるほど、これはゲームで使えそう」と思ってもらえる。これぞ、マルチメディア(死語)、てな気分になれますな。

それらと比べてしまうと、DXRuby、あるいは、Ruby/SDL、PyGame、HSP等々、Webブラウザ上では動かせない言語や環境は、ちとWeb記事が書きづらい。閲覧者に、「なるほど、こういう動きかー」と瞬時に理解してもらうための手段を持ってないですから。 *1 せいぜいできることがあるとしても、実行結果をキャプチャして、GIFアニメにして記事に貼るのが関の山。しかし、実際の実行結果に近づけてみたくて、GIFアニメのフレームレートを高くしていくと、あっという間に数MByte超えの画像ファイルに。それでいて、容量が大きい割に、全くインタラクティブではないわけで。

ですので、昨今、プログラマーさんが書くblog等においても JavaScript 等が大流行なのは、分かる気もするのでした。Web記事を書く手軽さで、実行結果も見せられるのだから、そりゃ強いよなと。それに触れ続けるためのモチベーションも維持しやすいだろうと。

とは言え。

ローカルでしか動かせない言語・ライブラリは、パフォーマンスが確保しやすいというメリットがありますし。例えば、DXRuby などは、若干酷いソースの書き方、雑で無駄な描画の仕方をしていても、意外と60FPSでヌルヌル動いちゃう。こういう点は、強みだろうと。 ローカルで動かしてる分には、やる気も持続できそう、てなもんで。 *2

そんなわけで、こういったあたりもトレードオフなのだろうなと。Webブラウザ上で動きは披露できないけど、その分、ローカル上ではもうヌルンヌルンのグリングリンで、コレ、キンモチイイイイーッ、フォーーッ! みたいな。

しかし、ActionScript や WebGL もヌルヌル動きますし。Unity も2D機能を強化してきましたし。将来的には、2Dゲーム云々は、どれもそのあたりに集約されていくのかなと思う時もありますが。Haxe のように、最終的には ActionScript か JavaScript の形で出力する、そんな言語・環境が生き残ったりするのかなと。2Dのアーケードゲームも JavaScript で動いてますよ、てな状況が当たり前に、とか。

まあ、コンピュータ関係の未来なんて、どうなるのかさっぱり予想できないですよね…。
*1: HSP には、HSPLet という、Java Applet 化して公開する手段もあるのですが。Java そのものが排除される方向にあるので、ちょっと厳しいかなあ、という気がしています。Java Applet に関しては、Processing (Proce55ing)も 2.0 以降、Java Applet で書き出す機能をサポート外にして、JavaScript で書き出す方向になりましたから…。どうやらWeb上では、全体的に、Java Applet をあらゆる場所から排除していこう! という流れになってきた、そんな印象がありますね…。
*2: 例えばこれが、JavaScript を使ったゲームライブラリの enchant.js あたりだと、デフォルトフレームレートが30FPSですし。ちょっとガクガクしちゃうよなと。もっとも、60FPSも指定可能ですが、低スペックのPC・スマホにも対応させないといけないので、わざと遅くしてるそうで。世の中に非力なハードウェアがゴロゴロしてるのがいかんのや…。まあ、少し前なら、「JavaScriptでそんなことするなよ。無茶だよ」と笑われてたはずで、そう考えると、恐ろしい時代になってますけど。

2013/12/11(水) [n年前の日記]

#1 [prog] Processing 2.1をインストール

「たしか、今の Processing は Java Applet 書き出しをサポートしてなかったはず…だけど、ホントにそうだったかな?」と不安になって。

関連情報をググっていたら、Processing 2.1 が公開されてることに気がついて。手持ちのソレは 2.0.1 だったので、せっかくだからアップデート。そういや今気がついたけど、2.0.3も出てたのね…。

ちなみに、Java Applet の書き出しが無くなって、JavaScript の書き出しになってたのは、正解だった模様。

Windows7 x64 環境だけど、processing-2.1-windows32.zip (32bit版) をDLしてきた。解凍して、processing.exe を実行するだけで動いてくれた。相変わらず導入は実に簡単。

サンプル群が減っていた。 :

右上の「Java」をクリックして、「JavaScript」に切り替えると、ブラウザ上で実行結果が確認できる書き出し方法になるのだけど。File → Examples... を選択、もしくは、Ctrl + Shift + o を叩いて、サンプルソース群の一覧を覗いてみたら、以前眺めていたソレと随分違うことに気付いたり。昔は3D関係のサンプルもあった気がするんだけど。どこに行ったんだろう…。

色々弄ってたら、謎が分かった。右上の選択が「Java」の状態で、サンプル群一覧を表示すると、山ほどサンプル群が出てくるけれど。「JavaScript」の状態で表示すると、基本的なサンプル群しか出てこない。結構な数のサンプルが、リスト上から無くなってしまう。

なるほど…。JavaScript で書き出しすることを前提にして使うと、おそらく機能が減ってしまって、仕方ないからサンプル数も減らしたのだな…。まあ、点を打つとか、線を引くとか、四角を描くとか、そういう範囲なら JavaScript モード(?)でも充分だけど。Javaモード上でやれる範囲を一旦知ってしまうと、ちとガックリ、ではあるなと。

JavaScript も、WebGL を使えば色々できそうとは思うけど。ソレ用の .js も必要になって対応が大変なのかしら。さりとて今更、Java Applet の書き出しを復活させる予定も無いだろうし。

アート関係の学習用としては、Processing はなかなかヨサゲな環境ではないかと思っていたけど、この展開は厳しいというか、残念というか。

結局、JavaScript は、Java だの Java Applet だのを代替できるレベルにはなってない、ということでもあるのだろうか…。もちろん、JavaScript の各ライブラリを眺めていくと、随分高度なことができるようになってきているけれど。それぞれがバラバラで、まとまってないから、スポンと差し替えてハイ終わり、ということにはならない面もあるのかなと思えてきたけどそのへんよく分かりません。

#2 [prog] Processing 2.1 のバグに気付いた

エディタ内の、日本語文字列の表示がおかしい…。
Processing 2.1 ScreenShot

環境は Windows7 x64 + Processing 2.1 x86版。使用フォントは _Ricty 。MSゴシックも選んでみたけどやっぱり表示がおかしくなる。

たぶんコレ、2バイト文字の、文字幅計算がおかしい予感。2.1からは設定ダイアログで、好みのフォントを選択できるようになったのはありがたいけど、エンバグもしちゃったのかな?

気になって Processing 2.0.1上で確認してみた。こっちは正常。
Processing 2.0.1 ScreenShot
Processing 2.0.3 でも試してみたけど、2.0.1と結果は同じで、正常だった。

_Using Processing - Processing 2.0 Forum を眺めてみたけど、報告は上がってないような…。まあ、英語圏では、こういうバグに気付くはずないけど…。

_chinese text is overlapped in Processing 2.1 editor - Issue #2173 - processing/processing - GitHub で、中国の方が報告してくれていた。ただ、どうも話が通じてない雰囲気…。「2.1で中国語に対応させるために大修整をした」と言ってるので、やはり2.1でエンバグしちゃったのだろうけど。英語圏側は、フォント表示の問題と、IME動作の問題を一緒くたにして扱ってるみたいだから、今現在は何が問題なのか理解できてないのでは、という不安も。

外部エディタを使うことが前提のツールなら、このあたり問題にはならないのだろうけど、やはりエディタ込みで即座に動かせるところに重きを置いているのかしら。であれば、バグ修正してもらえないと困るな…。

#3 [prog] Processingと外部エディタ

Processing には、たしか外部エディタを使用するオプションもあったはず。しかし、確認しても見つからず。おかしいな。偽記憶かな。いやいや、そんなはずは…。

関連情報をググってみたら、1.5.x の頃は外部エディタの利用も視野に入れてたけど、2.0以降は外部エディタを利用することが難しくなったらしい。以下のページで現状が解説されてた。

_Processing を好きなエディタでコーディングしてコマンドラインから実行する - 雑念日記

その代わり、コマンドラインで実行できるようになったらしいけど。しかし、Javaモード限定…。JavaScript は…。

待てよ? どうせ JavaScript を使うなら、最初から processing.js を使ってしまえばいいのでは? なるほど。だから Javaモードしか対応してないのか。

であればと、processing.js について少し調べてみたけれど。どうやらパフォーマンスが圧倒的に低いライブラリのようで。もちろん、少ない記述量で色々なことができる点が売りのライブラリだから、これもまた、トレードオフなのだろうなと。

#4 [javascript] JavaScriptのパッケージ管理システムもしくはサービスってないのかな

Processing のソレを見て、「JavaScript はライブラリの管理・導入が面倒なのでは」という疑念が湧いたのだけど。本当にそうなのかなと。Perl のCPAN、Ruby の Rubygems のような仕組みが、本当にまだ存在してないのだろうか…?

やっぱり、既にあるらしい。Bower なるものがソレっぽい。

_「Flight試してみたい!」でWindowsにBowerをインストールする | Developers.IO
_Bower入門(基礎編) - from scratch

_Bower components を覗いてみたら、現時点では 6428個ほど登録されてるようで。試しに「three」と打ち込んだら、 _three.js もリストアップされた。素晴らしい。

すると、ライブラリを入手する術は、既にちゃんと用意されてるということなのかな…。では、どうして Processing は、そういうライブラリをガシガシ同梱等して、Javaモード時並みに JavaScriptモードを強化しないのだろう…。

単に、どんなライブラリがあるか把握できてないのかな。あるいは、各ライブラリに対応するのが大変過ぎるとか。そんな感じなのかなあ…。

とりあえず、JavaScript にもそういう仕組みがあると知り、勉強になりました。

WebGLスゴイ。 :

それにしても、 _three.js はスゴイなあ。いや、WebGL がスゴイのだろうけど。

WebGL の普及については絶対足を引っ張るだろうと思ってたIEすら、 _IE11で WebGL に対応 してくれたらしいし。少なくとも Webブラウザ上では、「描画速度が欲しい? WebGL 使え」で済みそうですね。スゴイ時代になってきたなあ。

後は、サウンドとジョイパッドに対応したら、ブラウザの標準機能のみでリアルタイムゲームすら動かせるのが当たり前になるだろうけど。まあ、そのあたりは、無視・軽視されちゃう予感も。

#5 [dxruby][game] DXRubyで安直な画面フラッシュを試してみる

今日もDXRubyを使って何か書きますよ。と言っても、ゲーム制作をしてる人なら誰でも知ってそうな話ですけど…。

例えば、シューティングゲームやアクションゲームを作る時、敵の爆発時に画面をビカッと光らせたいな、一瞬だけ真っ白にしたいな、と思う時がありまして。要するに、画面をフラッシュさせたい時があるわけですよ。

昔のTVゲーム機だったら、画面の色は、全てパレットで管理されてたので、パレット内容を書き換えれば画面を真っ白にすることができました。1パレット16色で、1色2バイト使ってるなら ―― たった32バイトを書き換えるだけで、そのパレットを使って表示してる全てが真っ白になったわけです。 *1

でも、今のゲーム機って、パレットで色を管理〜なんてケチ臭いことしてないし。ちょっと書き換えれば全部の色が変わる、なんて仕組みじゃない。

じゃあ、どうするのかというと…。

かなり安直な方法ですが、画面全体に、真っ白な画像や、真っ黒な画像を、べた書きしちゃえばええやん、みたいな。どうせ今時のハードウェアは、強力なハードウェア描画機能を持ってますから、そのくらいなら描画処理時間もさほど影響ないやろと。

てなわけで、一応自分もサンプルを書いてみました。
# 画面を白く、あるいは黒く(?)、フラッシュさせる。(安直版)

require 'dxruby'

Window.resize(320, 240)

bgimg = Image.load("bg.jpg")
whiteimg = Image.new(Window.width, Window.height, C_WHITE)
blackimg = Image.new(Window.width, Window.height, C_BLACK)

white_alpha = 0
black_alpha = 0

Window.loop do
  break if Input.keyPush?(K_ESCAPE)
  Window.draw(0, 0, bgimg)
  
  if Input.mousePush?(M_LBUTTON)
    # マウス左ボタンがクリックされた
    white_alpha = 255
  end

  if Input.mousePush?(M_RBUTTON)
    # マウス右ボタンがクリックされた
    black_alpha = 255
  end

  if white_alpha > 0
    # 画面全体に、真っ白な画像を、透明度を変えながら描画する
    Window.drawAlpha(0, 0, whiteimg, white_alpha)
    white_alpha -= 5
  end

  if black_alpha > 0
    # 画面全体に、真っ黒な画像を、透明度を変えながら描画する
    Window.drawAlpha(0, 0, blackimg, black_alpha)
    black_alpha -= 5
  end
end
画面フラッシュ

実に安直ですが、それらしく見えてるし、コレで済んじゃう場合もあるんじゃないかなと。どんな方法でも、60FPSが維持できていれば、それでOKじゃないかしらん。

しかし。この方法では、例えば敵に自機の弾が当たった時に、敵だけフラッシュさせるとかできないわけですよ。

じゃあ、どうするかというと。

スイマセン。思いつきません…。明日までに考えておきます…。というか、DXRubyのシューティングゲームサンプルで、そういう処理してましたよね…?

それはそれとして。この、安直な画面フラッシュ。他のライブラリでもフツーに使えるやり方なので、こうして書いてしまいましたが。DXRuby の場合は HLSL という機能があるわけで。DXRuby のサンプルにも、sample_flash.rb という、そのものズバリがありますし。そっちを勉強しといたほうが応用効くんじゃないのかな、と思えていたりもするのでした。

フラッシュのさせ方。 :

そのまま何も考えずに、画面全体を単に白くフラッシュさせても、最低限の仕様は満たせるのですけど。

ちょっと気の利いた人ならば、いや、アニメオタクなプログラマーさんなら、おそらく、たまには、「黒」→「白」とか、「白」→「黒」とかフラッシュさせたりしてますよ、と、念のために書いておきます。TVアニメで画面フラッシュするカットをコマ送りしてみれば、このあたり、とても勉強になりますのでオススメです。結構いろんなタイミングのつけ方がありますので。

だけど、日本全国のちびっ子達がポケモンのアニメを見ていてバタバタと倒れたあの日から、そういうカットには放送局側が機械的にフィルタをかけてしまう、そんな状況になったので…。昔のアニメじゃないと、その手の小技を学べないかもしれない、という不安もあるのですけど。

いや、待てよ。逆に、今現在放送されてるアニメで、画面フラッシュしてるのに、フィルタがかからないとしたら…? ただそれだけでも、アニメスタッフさんが、何かノウハウを駆使してる可能性が高そうですね。そういうシーンをたまたま見かけたら、ソイツはお宝映像。要チェックですな。そこには、更に洗練された秘術が存在する…かもしれませんな…。

*1: と言っても、昔のゲーム機はめっちゃ遅かったんで、その程度のバイト数の書き換えも結構もったいなくて。パレットデータはVRAM上にあって、かつ、VRAMへのアクセスは垂直帰線期間(区間?)内に済ませておかないといけないけれど。VRAM上の値を読んで計算してまた書き戻して、なんてやってたら間に合わない。メインRAM上にパレット内容を持っておいて、そこであらかじめ計算しといて、VSYNC割り込みが来たら「今だ! 急げー!」とばかりに、VRAMに対しては上書きオンリーでひたすらDMA転送、てな感じの処理をしてたような気もします。…違ったっけ? たしかそうだったような。

ですので、パレットをたくさん持てるハードウェアなら、フラッシュ専用のパレットを持っておいて、スプライト等のパレット番号を切り替えるだけでフラッシュさせてた、そんな記憶もありまして。

パレットが少ないハードウェアでは、誰かが使ってるパレットを、中身を気にせず無理矢理流用して別の色に変えてたり。…そんなことをしてたので、某ゲームは、赤と青が激しく点滅する、今では絶対販売禁止であろうポケモンフラッシュ画面になっていたのでした。

2013/12/12(木) [n年前の日記]

#1 [firefox] Firefox 26 にアップデートしたらJSActionsが動作しなくなってしまった

個人的に、これが使えないとかなり困ってしまう Firefox拡張、JSActions が、Firefox 26 にアップデートしたら動かなくなってしまった。右クリックして項目を選んでも、メニューが出てこない…。 等々に使っていたわけで…。それぞれ別個に、同等の機能を持った拡張も無くはないのだけど、アレコレを一つの拡張で実行できるところが助かってたわけで。コレは困った。

公式サイトもどこかに消えてしまっているようで、現状がどうなってるのかよく分からず。

仕方ないから、Firefox 25.0.1 にダウングレードするしかないか…。 _Firefoxをダウングレードする方法 知らなきゃ絶対損するPCマル秘ワザ を参考に、 _ftp://ftp.mozilla.org/pub/mozilla.org/firefox/releases/ から、Firefox Setup 25.0.1.exe をDLしてきたりして。

諦めきれずにググっていたら、なんとか現在の公式サイトや、関連情報に遭遇。

_index - + HideAway Firefox +
_Firefox - SkyDrive
_HideAway (HideAwayFx) - Twitter

SkyDrive から jsactions_3.0.10beta.20131130.xpi をDLして、Firefox にインストールしてみたところ、使えてるように見えました。ありがたや。助かりました…。

Download Statusbarが使えなくなってしまった。 :

Firefox 26 にアップデートしたら、Download Statusbar が使えなくなってしまった。Firefox のステータスバーに、今現在どのファイルをDLしてるか、ズラリと表示してくれる拡張で。要するに、Google Chrome でDLした時のような見た目にしてくれる拡張なのだけど。

何のファイルがDL完了していて、何のファイルがまだDL中なのか確認する際、わざわざマウスカーソルを、Firefoxのツールバー上のDLアイコンにポインティングせずとも、スッと視線を変えるだけで確認できるあたりが便利な拡張だったわけですけど。コレが使えないとなると、地味に困るなあ…。

Google Chrome に乗り換えるしかないのだろうか…。だけどあっちは、JSActions や RSS Checker みたいなこと、できるのかなあ…。

#2 [firefox][prog] マウスを左手に持ちかえてみるべき

Firefox 26上で Download Statusbar が使えなくなった問題を目にしてモヤモヤと考えてしまったり。ここ最近、Firefox は、拡張用のステータスバーを削除する云々の議論をしてた、という話もどこかで見かけたので。Download Statusbar が動作しなくなったのは、そのあたりが関係してたりするのかなと邪推したのだけど、実際はどうなんだろう。あまり関係ないのかな。

ただ、ファイルのダウンロード状態を示す、ツールバー上のアイコンを眺めてるうちに、なんだか疑念が湧いてきたり。Firefox の開発陣は、ユーザのポインティング作業にかかっている労力を、ちと軽く見過ぎているんじゃないのかな、と。

マウスを使ってるなら、トラックボールやタッチパッドに変えてみるべき。右利きの人が、右手でマウスを操作してるなら、左手でマウスを操作してみるべき。

ソレを試してみた時に、「ウガーッ。やってられるかこんなこと」と思ったなら、そのアプリのGUI設計は、どこかで間違いを犯しているのではないか ―― そのように自分は思うわけですよ。

などと書いてみたものの、自分も普段、そこまで検証しながらアプリ作ってないのですけど。ただ、そのGUI設計が上手くいってるかどうか、ざっくり確認するなら、コレってそこそこ有効じゃないのかなと。「まあまあこれでも使えなくもない」なら上手くいってるし、「ウガーッ」なら失敗してる。簡単に分かりそうだなと。

で。状況に応じて、そのアプリがバックグラウンドで今現在何をしているのか、その状態を表示してくれる機能 ―― それも、最低限の表示領域を使って表示してくれる機能って、「ポインティング操作」自体を要せずとも目的を果たせるわけですから、当然、便利・快適なわけでして。

であれば、それらの表示が可能になる機能ぐらいは、標準で用意して、存在し続けることを保証しておかないといかんのではないかと思えるのですが。どうなんですかねえ…。 そのあたり、比較的正解に近いことをやってくれる拡張が存在してたのに、それを殺してどうするんだろうと。標準で取り込んでもいいぐらいの仕様だと思うのですけど…。

さておき。Download Statusbar を使えるようにできないのかなと色々ググってたら、「browser.download.useToolkitUI自体が削除されたからどうしようもない」みたいな話を見かけて、ガックリなのでした。旧タイプのDLマネージャが無くなってしまったから、という話だったのかな…。何にしても困った…。

#3 [cg_tools][blender] blender を 2.69 にアップデート

blender 2.68 で作業してたら、Extra Objects の Gear を追加した際に、おかしな形状が出てきてしまって。

blender 2.69 が出ていたはずなので、変更点を確認したところ、どうも Gear という文字列が見えたので、もしかしたら修正されてるのかなと。気になったので、blender 2.69 をDLしてきてインストール。

今回は、 _GraphicAll.org から、Blender 2.69.4 - Fastest build: CUDA + OSL の zip をDLして入れてみたり。DLしたファイルは、
10680_blender-2.69---31871c7---unified-contrib-add-ons---fastest---cuda.7z
だった。

起動したところ、以前の設定をコピーするか否かの選択肢がスプラッシュ画面に表示されていたのでクリック。再起動したところ、設定は反映されているように見えた。

Gear も、正常に生成されるようになっていた。ありがたや。

#4 [anime][neta] ウルトラマンのカラータイマーとNASAのロボット

_【やじうまPC Watch】NASAが開発した二足歩行ロボット「ヴァルキリー」 - PC Watch という記事を読んでいて、ウルトラマンの胸のランプ ―― カラータイマーのことを思い出してしまったり。

件の記事のロボットの胸には、ランプがついていて。単に飾りとしてつけたのか、それともロボットの動作状態・ステータスを視覚で認知するためにつけたのか、そこは分からないのだけど。まあ、後者のような気もする。何せ、X-box のレッドリングを生み出した国だし。

仮に、ウルトラマンという種族・生命体が現実に存在していたとしたら、彼等の出自・進化の過程が気になるわけで。実は、ウルトラ一族は、件のロボットと同様に、何か上位の生命体が、各惑星で単なる作業人員を必要としていたから作ってみた、有機的なロボットなんじゃないか、みたいな。だから、カラータイマーがあるんじゃないのか。そのカラータイマーは、ウルトラ一族の上位の存在にとって、何か利便性があったに違いない。「こいつはもうエネルギー切れだから使えないな。しばらく充電させといて、別の個体を呼び出して作業をさせよう」みたいな。

自分達がウルトラマンシリーズを見るときは、ウルトラ一族は人間より上位の存在、ある種の神様と思い込んで見ているけれど。そのウルトラ一族にも、更に上位の何かが存在しているという設定は、ちょっと頭がクラクラしてきて面白いような気もする。

逆に、人間が下位の存在と思い込んでいるソレが、実は人間より上位の存在であった、あるいは、未来においては上位の存在になっていた、という設定も面白そう。…まあ、そっちは、「猿の惑星」がそのもののズバリだろうけど。

そんなくだらない妄想をモヤモヤと。

まあ、考えてみれば、神話の類はほとんどソレなのかなと思えてきたり。今はもう、神様なんて、人間の想像上の何かと思われちゃってるので、それらを読んでもほとんどの人は「ふーん」だろうけど。神は本当に居るのかもしれないと、結構マジに思えていた時代なら、神様の上にも神様が居るとか、神様にも階級があるとか、そういう話で頭がクラクラできて面白かったのかもしれないなと。

そのように、大衆が「これはこうだ」と思い込んでいる何かを、「実はそうではなかった」と錯覚させられる話・設定が捻り出せたら、それだけで商品に成り得る資格を持てるのかもしれないなと思えてきたりもして。自分達が、意識せずに、「これはこうだ」と思い込んでる、そんな何かの存在に容易に気付けて、そこをひっくり返すことができる人は、ヒットメーカーになれるのかもしれない。

てな感じの甘々な夢想をぼんやりもやもやと。

#5 [dxruby][game] DXRubyで敵キャラのフラッシュを試してみたり

今日もDXRubyを使って何か書いてみますよ。

昨日、「敵キャラ画像をフラッシュさせる方法がわからない…」みたいな結末で記事を書き終えたわけですけど。その後ググってみたら、色々やり方があるらしいと分かってきたので、そのあたりを自分なりにまとめてみることにしました。

同じ画像を加算合成で描画する方法。 :

最初に自分が思いついたのが、この方法。DXRuby は加算合成描画ができますので、敵キャラ画像をもう一度、加算合成で描画しちゃえば、少しは明るく見えるんじゃないのかなと。
# 敵キャラ画像をフラッシュさせる。
#
# 加算描画で、もう一枚上に重ねるやり方。
# 全てが完全に白にはならないけれど、一応光ってるようには見える。

require 'dxruby'

Window.resize(320, 240)
bgimg = Image.load("bg.png")
img = Image.load("boss1.png")

x, y = 64, 20
enemy_alpha = 0

Window.loop do
  break if Input.keyPush?(K_ESCAPE)

  # BG画像描画
  Window.draw(0, 0, bgimg)

  # マウスボタンが押されたらフラッシュ開始
  enemy_alpha = 255 if Input.mousePush?(M_LBUTTON)

  # 敵画像描画
  Window.draw(x, y, img)
  
  if enemy_alpha > 0
    # もう一枚加算描画
    Window.drawEx(x, y, img, :alpha => enemy_alpha, :blend => :add)
    enemy_alpha -= 10
  end
end
加算合成描画でフラッシュさせる方法

メリット・デメリットは、以下になりますかね。
  • 画像枚数は、1枚で済む。持つべきテクスチャ領域を節約できる。
  • 加算合成描画が使えるハードウェア/ライブラリなら使える。
  • 同じ画像を2枚描くので、非力なGPUでは描画時間がかかってしまって処理落ちするかもしれない。
  • 白部分をたくさん含む画像なら光ってるように見えるけど、黒部分が多い画像では全然光ってるように見えない。(GIFアニメの、肩(?)の丸いところに注目。黒に近いので、全然光ってるように見えません。)

あらかじめフラッシュした画像を作っておく方法。 :

事前に、フラッシュした画像を作っておいて、ソレを表示しちゃえば、そもそも容易にフラッシュ表示ができますな。プログラムで生成してもいいし、CGツールを使って事前に作業してもいいですが…。

DXRuby の、るびま記事用サンプルで、この方法を使っているようでして。プログラム内で、
  • 元画像と同サイズの新規画像を作成。
  • 元画像の透明ではない部分を、全部白いドットに置き換える。
といった処理をしているように見えました。
#!ruby -Ks
# -*- mode: ruby; encoding: sjis -*-
# 敵キャラ画像をフラッシュさせる。
#
# 事前に、フラッシュした画像を作成してしまうやり方。
# るびま記事のサンプルを参考にしました。

require 'dxruby'

# フラッシュ画像を作成するメソッド
def make_flush_image(img)
  w, h = img.width, img.height # 画像の縦横幅を取得
  newimg = Image.new(w, h) # 新規画像を作成

  # 縦横幅の値でループ
  h.times do |y|
    w.times do |x|
      # 透明度が128より大きかったら白にする
      newimg[x, y] = C_WHITE if img[x, y][0] > 128
    end
  end
  
  return newimg # 生成画像を返す
end

Window.resize(320, 240)
bgimg = Image.load("bg.png")
img = Image.load("boss1.png")
flushimg = make_flush_image(img)

x, y = 64, 20
enemy_alpha = 0

Window.loop do
  break if Input.keyPush?(K_ESCAPE)

  # BG画像描画
  Window.draw(0, 0, bgimg)

  # マウスボタンが押されたらフラッシュ開始
  enemy_alpha = 255 if Input.mousePush?(M_LBUTTON)

  # 敵画像描画
  if enemy_alpha <= 0
    # 通常描画
    Window.draw(x, y, img)
  else
    # フラッシュ画像を描画
    Window.draw(x, y, flushimg)
    enemy_alpha -= 10
  end
end
フラッシュ画像を生成しておく方法

  • あらかじめCGツールでフラッシュ画像を作っておけば、凝った表示も可能になる。
  • フラッシュ時に別画像を描画するだけなので、描画処理時間は通常時とほぼ同じで済む。
  • 持つべき画像枚数が2倍になる。テクスチャ領域を圧迫してしまう。
  • CGツール上で作業する時間が増える。絵描きさんに負担をかけてしまう。
  • プログラムで生成する場合は、事前に画像生成するために、初期化処理の時間が増えてしまう。

DXRubyのHLSL/Shader機能を使う方法。 :

DXRuby は、HLSL / Shader という、超極力な機能をサポートしてますので、ソレを使うのが DXRuby ライクな方法らしいです。

ググってみたら、そのものズバリの解説記事・サンプルを、DXRuby の作者様が公開してました…。ありがたや。

_DXRuby プロジェクトWiki - Shaderを使うためのチュートリアル02
_RGSSに近い色調整機能を持たせるSprite拡張 - mirichiの日記

自分の手元でも、解説記事のソレを丸々コピペして動作確認してみました。
#!ruby -Ks
# -*- mode: ruby; encoding: sjis -*-
# 敵キャラ画像をフラッシュさせる。
#
# HLSLを使用するやり方。
# 以下の解説記事を、ほぼ丸々コピペしてます…
#
# DXRuby プロジェクトWiki - Shaderを使うためのチュートリアル02
# http://dxruby.sourceforge.jp/cgi-bin/hiki.cgi?Shader%A4%F2%BB%C8%A4%A6%A4%BF%A4%E1%A4%CE%A5%C1%A5%E5%A1%BC%A5%C8%A5%EA%A5%A2%A5%EB02

require 'dxruby'

# HLSLを文字列で持っておく
hlsl = <<EOS
  texture tex0;

  sampler Samp0 = sampler_state
  {
   Texture =<tex0>;
  };

  float4 PS(float2 input : TEXCOORD0) : COLOR0
  {
    float4 output;

    output = tex2D( Samp0, input );
    output.rgb = 1.0;
    return output;
  }

  technique
  {
   pass
   {
    PixelShader = compile ps_2_0 PS();
   }
  }
EOS

# HLSLをSahderに渡す
core = Shader::Core.new(hlsl)
shader = Shader.new(core)

Window.resize(320, 240)
bgimg = Image.load("bg.png")
img = Image.load("boss1.png")

x, y = 64, 20
isFlush = 0

Window.loop do
  break if Input.keyPush?(K_ESCAPE)

  # BG画像描画
  Window.draw(0, 0, bgimg)

  # マウスボタンが押されたらフラッシュ開始
  isFlush = 255 if Input.mousePush?(M_LBUTTON)

  # 敵画像描画
  if isFlush <= 0
    # 通常描画
    Window.draw(x, y, img)
  else
    # Shaderを使って描画
    Window.drawShader(x, y, img, shader)
    isFlush -= 10
  end
end
HLSLでフラッシュさせる方法

  • 画像枚数は、1枚で済む。持つべきテクスチャ領域を節約できる。
  • GPUに仕事をさせているので、おそらくは処理時間も速い(と思われる)。
  • Shader機能相当があるライブラリじゃないと使えない。
  • HLSL / GLSL の知識が必要になるので、Ruby の書き方しか知らない場合は、若干ハードルが高い。(コピペで済ませてる分には問題無し)

他にも色々ありそう。 :

とりあえず、ググってみて知った方法を並べてみましたが、他にも色々な方法があるのだろうなーと想像しております。まあ、今後も、研究課題ということで一つ…。

ベンチマークを取ってみたらどうなるのかなとも思いましたが、さて、こういうソレって、どうやったら測定できるんですかね…。そのあたりも、自分にとっては、今後の課題・宿題ですな。

とりあえず、画像とソースも置いときます。後半2つは、既存サンプルの引用に近い気もするのでアレですけど。

_enemyflush.zip

2013/12/13(金) [n年前の日記]

#1 [zatta] 正岡子規の「再び歌よみに与ふる書」という文書が気になってきた

妹から、漫画「うた恋い。」4巻を借りて読んでいたら。その中に、「正岡子規が紀貫之をチョーdisってた」という話を見かけて。一体どういうdisりかたをしてたのだろうと興味が湧いてきたり。

ググってみたら、「再び歌よみに与ふる書」という文書がソレらしくて。昔の文書だから、青空文庫にも載ってました。ありがたや。

_正岡子規 再び歌よみに与ふる書 - 青空文庫

眺めてみたけど…。うむ。何が何だか分かりません。コレ、現代語訳とかないの?

現代語訳はないらしい。

_正岡子規の「歌詠みに与ふる書」の全文現代語訳のサイトがあれば教えて下さい。 お... - Yahoo!知恵袋
サイトはないと思います。むしろあったらびっくりです。と言いますのは、『歌詠みに与ふる書』を読もうと思うような人にとって、これは現代文と変わらないものだからです。

正岡子規の「歌詠みに与ふる書」の全文現代語訳のサイトがあれば教えて下さい。 お... - Yahoo!知恵袋 より

うへえ。マジすか…。

自分なりに意訳を試みたい気分になってきた。 :

なんか、「正岡子規はそんなこと言ってない」とツッコまれそうだけど…。いくらなんでもアレをそのまま読めと言われるより、勝手な意訳のほうがまだマシかもしれんと思えてきたので、一つ挑戦。

貫之は下手な歌よみにて古今集はくだらぬ集に有之候。其貫之や古今集を崇拝するは誠に気の知れぬことなどと申すものゝ実は斯く申す生も数年前迄は古今集崇拝の一人にて候ひしかば今日世人が古今集を崇拝する気味合は能く存申候。

正岡子規 再び歌よみに与ふる書 より

紀貫之って歌人が居ますけど。なんかファンが多いですけど。
あの人、歌人としてはヘッタクソですよね…。
「古今和歌集」って和歌を集めたソレを作った人でもあるけれど。
その「古今和歌集」も、中身はマジにくっだらねえっつーか。

あんなもんのファンやってますとか、お前正気か?って感じスよ。

なんてこと言ってみちゃったけどー。
実は自分も数年前まで大ファンでして。テヘペロ。
なもんで、未だにファンがゴロゴロ居る理由も分かるんですわ。
俺はね、ソレ、分かっちゃうんですよ(ニヤリ。

崇拝して居る間は誠に歌といふものは優美にて古今集は殊に其粋を抜きたる者とのみ存候ひしも三年の恋一朝にさめて見ればあんな意気地の無い女に今迄ばかされて居つた事かとくやしくも腹立たしく相成候。

正岡子規 再び歌よみに与ふる書 より

ファンになってた間は、
「和歌ってもんは、美しいのう」
「古今和歌集なんてサイコー! チョーイケてる!
  コッキーン! こ、こーっ、コキイーッ!! コキーッ!!」
って思ってたんスけど。

アレは、一時の熱情で頭がおかしくなってたんでしょうなあ。
目が覚めてみたら、なんつーか…。
コレってもしかして、ナメクジみたいなキモ女に
ずっと馬鹿にされ続けてた俺、
みたいな状況じゃねえかと思えてきてムカついちゃって。
意味分かんないか。俺も分からん。
とにかくムカつくんだよ! 紀貫之も古今和歌集もムカつく!

先づ古今集といふ書を取りて第一枚を開くと直に「去年(こぞ)とやいはん今年とやいはん」といふ歌が出て来る実に呆れ返つた無趣味の歌に有之候。日本人と外国人との合の子を日本人とや申さん外国人とや申さんとしやれたると同じ事にてしやれにもならぬつまらぬ歌に候。

正岡子規 再び歌よみに与ふる書 より

大体にしてね。古今和歌集の1ページ目を開いてみると。

「去年(こぞ)とやいはん今年とやいはん」

とか書いてあるわけですよ。
ハァ? ナニソレ? アホか。センスねえにもほどがあるだろ。
ソレ、ハーフの人を

スイマセン。ここで挫折しました。元の文章が、何を言いたいのか分からない…。ハーフの人を、日本人扱いするか外国人扱いするか、みたいなことが書いてあるのですかね? それがどうして悪口になるのか…。当時はそのあたりの物言いが、何か流行ってたのかなあ?

此外の歌とても大同小異にて佗(ママ)洒落か理窟ッぽい者のみに有之候。それでも強ひて古今集をほめて言はゞつまらぬ歌ながら万葉以外に一風を成したる処は取餌(ママ)にて如何なる者にても始めての者は珍らしく覚え申候。

正岡子規 再び歌よみに与ふる書 より

どの歌も、大体がそんな感じっスよ。
ぜーんぶ、おんなじ。オヤジギャグかよ。ヘリクツかよと。

これでもまだ、古今和歌集のファン続けてるヤツラって

また挫折。万葉ってのは、万葉集のことなのかな…? それがどう話に絡んでくるんだ? 分からんわ…。

只之を真似るをのみ芸とする後世の奴こそ気の知れぬ奴には候なれ。それも十年か二十年の事なら兎も角も二百年たつても三百年たつても其糟粕を嘗(な)めて居る不見識には驚き入候。何代集の彼ン代集のと申しても皆古今の糟粕の糟粕の糟粕の糟粕ばかりに御座候。

正岡子規 再び歌よみに与ふる書 より

しかもソレを延々コピーしてるだけのくせして
「これこそが真の芸である(キリッ」
とか言っちゃって。アイツラ、理解不能ッスよ。

でもまあ、そういうのが
十年〜二十年程度はウケてるとかなら分からんでもないスけど。
二百年も三百年も、こんなカスコンテンツを絶賛してるとか…ねえ…。
見てるこっちはビックリだよ。オマエラ、一体どんだけ見る目がないのかと。

また挫折。何代集って、何だ? うーん。どうにか、この、「カス! カス! カス! カスばっか!」のあたりまでは行きたかったのですけど…。

ということで、これは自分如きでは歯が立たないなあ、と思いました。無謀でした。

とりあえず、ここまでの範囲では、「お前等、センスない」を、別の言い方で、延々と繰り返してるだけというか、「古今和歌集、でーべそ!」程度の中身空っぽのdisりだなーと思えたけれど。これで紀貫之への世間の評価がガラリと変わった、という話も見かけたので、ますますよく分からん…。後半が理解できれば、印象が変わるのだろうか?

_歌よみに与ふる書 - Wikipedia によると、1898年頃に発表されたものらしく。

たった100年とちょっとで、こんなにも、理解できない文章になるのか…。日本語って恐ろしいなあ。

それはともかく。「ホアーッ」の正しいフレーズについて確認したくて「ホアーッ」でググってみたら、ホリエモンのヌードグラビア画像が出てきて大変困惑しました。「ホ」しか合ってないじゃん。Google、どうなってんの。

と思ったら、画像載せてる記事のタイトルに「ホアーッ」が入ってたようで。ほほう…ぐうぐるは、まっこと働き者じゃのう…(まんが日本昔ばなしの、あの声で)。

#2 [dxruby][game] 敵に弾が当たったら敵をフラッシュさせるソレ

昨日一昨日と、画面をフラッシュさせる云々の記事を書き残してみたものの。書いてる最中、ずっともやもやしてたのです。

と言うのも。たしか以前、Web上の何かの記事で、「敵に弾が当たったら敵をフラッシュ、なんてやってる時代じゃねえだろ(プゲラ」みたいな主張を読んだ記憶もあるんですよ…。いや、自分の偽記憶かもしれないけど。

その主張にも一理あるよな、と、自分は思っていて。 てな感じの話が書いてあったような気がするんですよね…。違ったかなあ…。

もしかすると、このあたり、正岡子規が言ってたらしい、「テメエラ、紀貫之や古今和歌集をいつまでも崇拝してんじゃねえよ。和歌はもっと写実的であるべき!」みたいな話と似てるのかもしれませんが。それはそれとして。

どうして敵をフラッシュさせるかと言えば、「YOUの撃った弾はちゃんと敵にダメージ与えてるから、安心してプレイせえや」と、遊んでる人に知らせたいからやってるわけで。「敵に弾がちゃんと当たってる」「ダメージを与えてる」ことを伝えるのが目的であって、ただ真っ白にフラッシュさせることが目的じゃない。フラッシュは、数ある手段の中の一つでしかない。目的が果たせるなら、どんな手段を選んでもいいわけで。

例えば、たしかパロディウスあたりは、ボスキャラに弾が当たると目玉が飛び出て仰天する絵になるわけで。昔だって、そういう伝え方はしてたよなと。

とは言うものの。

TVゲームの歴史って、他と比べたら圧倒的に短いけれど、一応それなりに何十年も続いてるわけで。そこを無視してええのかな、とも。
ということで、「この手のフラッシュ云々なんて、書いてみて意味あるのかな? 読んだ人は笑うんじゃないの? いやー、でも、どういうゲームを作りたいかによるよなあ…」などと結構もやもやしつつ、それでも一応は書いてみたのでした。

まあ、「コイツ今頃何やっとんじゃい。今のハードならこういう見せ方するのがベターやろ」と憤慨された方がおられましたら、せっかくだからそのあたりを、blogとか _Qiita とかで、チラッと紹介してくれれば勉強になる人も多いはずなので、そん時はそういう方向でどうかよろしくお願いいたします。みたいな。

「今ならこうだよ」的な話って、別にプログラマーじゃなくても、ゲームをたくさん遊んできた人なら書けそうな予感も。「このゲームではこういう表現してたよ」と、記憶を辿ってリストアップする作業に近いだろうし。

もっとも、このあたりの表現を絶えず意識しながら、ゲーム映像を見てる人は少ないんじゃないか、という気もしてますが…。こういうのって、上手く行ってれば行ってるほど、ソレをやってることに気付かれなくなっていくものですし。

#3 [game] 地形アタリの処理でもやもや考え始めてしまったり

_2Dアクションゲームの簡易衝突判定入門 - 土屋つかさのテクノロジーは今か無しか という記事を読んで、「そういや自分はどうやって実装してたかな…」と記憶を辿り始めてしまったり。

今もメリットはあるような気がする。 :

件の記事中にあるように、2Dゲームの地形アタリ判定は…。
  • ファミコン時代によくやってたように、タイル? チップ? セル? で構成された、BGマップ上のコードを取得して地形アタリを取る方法。
  • 複数のポリゴンを地形の形に配置して、地形アタリを取る方法。
この2つがあるのだろうなと自分も思っていて。

一見すると、今時は後者がクールなようにも思えるのだけど。前者も前者で、おそらくメリットがあって。地形アタリにかかる処理時間が、比較的安定してるというか。

プレイヤーキャラぐらいしか地形アタリを取らない、という状態なら、別にどっちでやっても処理時間なんてたいした違いはないだろうと思うのだけど。

しかし、例えば、画面内に雑魚敵がワラワラと出てきて、それら全てが、各々勝手に、地形アタリを取らなきゃいけない、なんて時は…。

そんな時は、マップのコードを見てアタリを取る方法のほうが、最悪の場合でも処理時間がこのぐらいで済む、と見通せる状態になるような気がしていて。たぶんこのあたり、ソートアルゴリズムの、「最悪計算時間」「平均計算時間」みたいなものが、地形アタリ処理にもあるんじゃないかと。地形アタリを取る敵の数が増えれば増えるほど、処理時間のグラフが急角度になる、そういう処理もありそうで。その点、マップのコードを見ていくやり方は、最悪でも比例グラフになりそうかなと。

てなわけで、自分もこのへん、もう一度処理を書いてみて、復習?しておかないといかんなあ、と思えてきたのでした。

実験用マップを作成中。 :

処理を書くためには、実験用マップが必要になるので、EDGE2 でBGアタリ画像を描いて、Tiled で配置。コレを使って、処理を書いて実験しようかと。

BGアタリ実験用マップの全景


作業してるうちに、少しずつ思い出してきた。たしか、昔やったソレは、床、壁、天井、ジャンプで乗れる足場、ぶら下がる棒、その他モロモロに、それぞれ別コードを割り当てていたような気がする。

たしか、自分が上手く実装できなくて悩んでたら、絵描きさんのほうから、「以前やった企画では、こういうBGアタリにして解決してたから、言ってくれれば、その作業をやるよ?」と助け舟を出してもらえて。そのお言葉に甘えさせてもらった上に、こっちはますます調子に乗って、アタリのコード種類をやたらと増やしちゃった…そんな記憶も。

たしか、壁登りを始めるとか、壁登りと天井ぶら下がりを切り替えるとか、そういう判別のために、床・壁・天井の境界のところに小さい三角を入れて、その三角にも、それぞれ異なる別コードを割り当てていたような…。

当時のハードは非力だった上に、バンバン敵を出して、ガンガン弾を撃って、バカスカやっつけるゲームにすることを前提にしてたから、1クロックでも稼ぎたくて、やたらと特殊処理用のコードをマップに入れてもらってた…ような気がするけどどうだったかなあ。

だけど今のハードなら、プログラム側で、その周辺の複数のコードを見て、そこにある地形アタリは本来どういう属性なのか、判別することができそうだなと。地形アタリのコード種類も、最低限で済みそうな気がする。

あるいは、事前にマップを走査して、元から持っている地形コードを、ゲーム中の処理に適したコードに変換して上書きする、なんてこともできそうな気もしたり。

余談。ポリゴンで地形アタリをとる方法について。 :

ググってたら、とても丁寧に解説してくれてる記事と遭遇。

_2D当たり判定超入門 (PDF)
_すべての講演資料 - 全日本学生ゲーム開発者連合(全ゲ連)資料置き場

素晴らしい…。そのうち、この資料を元にして、自分もこの方式の地形アタリ処理を試してみたい気分になってきたり。ありがたや。

#4 [dxruby][game] DXRubyで画面を揺らすソレ(偽りあり)

今日もDXRubyで何か書いて

と思ったんですけど、もう時間がなくてソースを書けませんで。とりあえず文章だけで説明をば。

今回は、画面を揺らすソレについて。ボスキャラの爆発時に画面フラッシュが云々、と書いてしまったので…。であれば当然、画面も揺らさなきゃいかんだろ、と思えてきたので、一応念のために書き残しておきます。

重いモノが地面に落ちた時、巨大ロボットがズーンズーンと歩いてる時、ボスキャラの爆発時など。そんな時は、画面を揺らすと迫力がちょっとだけ増してグーですよ。お試しあれ。

揺らし方にも色々あります。縦にだけ揺らしたり、横にだけ揺らしたり。上下左右に等しい量で揺らしたり、ランダムな量で揺らしたり。拡大縮小が使えるハード/ライブラリなら、前後に揺らすのもアリですよね。

ランダムに揺らすのがベスト、と言うわけでもありませんで。例えば、某ゲームでは、開発当初、思いつく揺らし方は全部書いて一通り試してみましたが、結局、上下のみ、かつ、上下とも同じ量で綺麗に揺らしたものが一番迫力があった(「チョー揺れてる! コレチョー揺れてるよー!」感が分かりやすかった)ので、その処理だけを残して他は捨てちゃいました。ゲームやシーンに応じて、しっくり来る揺らし方を選びましょう。ケースバイケースです。「この揺らし方じゃないとダメ!」なんて法律はありませんよ。

やはりこのあたり、アニメの映像がとても参考になりますので、そういうシーンを見かけたら、(たまには)コマ送りしてみてください。色々な発見があると思います。

注意点が二つほど。

画面を揺らすためには、背景・BGマップの上下左右に余裕が必要です。画面の大きさギリギリでBGマップ等を作っちゃうと、揺らしたときに見えてはいけないものがチラチラ見えて興醒めですので、上下左右に「これなら映っちゃってもOK」と思える領域を用意しておきましょう。

シビアなプレイヤー操作を要求される場面で画面を揺らしてしまうと、敵弾を避けられない、足場の位置が分からない等、たちまちクソゲーになっちゃいますので、影響が無さそうなところで使いましょう。

そんな感じですかねえ…。

昔は、この小技に気付いてないゲームプログラマーさんが時々居て、せっかくの見せどころなのに迫力が全然無い、寂しい画面をたまに見かけたのですけど。今はさすがに、その手の2Dゲームライブラリにも最初から機能として入ってたりするようで。「誰もが知ってて当然」の小技になってるのではないかなと想像しています。

_ActionScript入門Wiki - Flixel - 画面を揺らす

まあ、DXRuby には、そんな機能は入ってないんですけどね…。もっとも、前述のとおり、色んな揺らし方があって、ゲームやシーンによって選ぶべき揺らし方が変わってくるでしょうから、そこは各プログラマーさんが実装する時に、楽しめる・遊べる部分じゃないのかな、と思うのでした。

2013/12/14() [n年前の日記]

#1 [nitijyou] 雪がうっすら積もった

朝になったら積もってた。もう、自転車では走れない時期だなあ。

#2 [anime] 漫画だけができる話の終わらせ方

「俺の脳内選択肢が〜」の、おそらくは最終回?を視聴して、「なんだか『うる星やつら』を思い出すなあ…こういうドタバタは好きだわ…」と思ったのだけど。

「うる星やつら」アニメ版をぼんやり思い出しながら、「そもそもこういうドタバタした感じの終わらせ方って、アニメでは難しいよな。漫画ならともかく」と思えてきたり。

「うる星やつら」の原作漫画は、えてして毎回、最後のコマが、ページの1/2〜1/3ぐらいを占めていて。たくさんのキャラがギッチリ描き込まれて ―― ウォーリーを探せみたいな状態で。それぞれが混乱したやり取りをして、ドタバタして終わる、という形が一つの様式美になっていたのだけど。

それを、小説、もしくはアニメで、そっくりそのまま再現しようとすると、これはもうほとんど無理で。各人のやり取りを、一つ一つ時分割して、順に並べて、読者・視聴者に見せていくしかなく。もし、それらやり取りを、漫画と同様に1カットで同時に収めようとすると、ゴチャゴチャドタバタしてることだけは伝わるけれど、そこで何が起きてるのか視聴者側が理解することは不可能で。

漫画は、そこで起きてることを、並列で見せることができるけど、小説やアニメは、直列でしか見せられないというか。

画とテキストを併存させて、時間制御を読者に任せて、読者自身は一つ一つシーケンシャルに情報を理解していくけれど、全体としてはソレが同時に起きていると認知できてしまう ―― そんな見せ方は、漫画じゃないとできないなと。

そんなわけで、「こういう終わり方は懐かしいなあ」と思いながらも、「漫画にしかできない見せ方ってあったんだな」とも思えてきたのでした。

逆に考えると、漫画ではできないけれど、アニメならできる見せ方ってのもありそうだなと。いや、間違いなくたくさんあるだろうけど。たぶんこっちは、そういう特徴に気付かないまま、ぼんやりと見ちゃってるんだろうな…。

アニメでもそういう見せ方できないかな。 :

漫画のソレを読む時も、一つ一つのやり取りを、読者は一つ一つ追いかけて読んでるわけで。それが一つのコマに収まってるから、「コレは同時に起きてることだ」と認知するわけで…。

そう考えたら、アニメでもできるんじゃないのかと思えてきたり。一つのコマに収めるという漫画のソレを、別の何かで代替すれば済む予感。

うむ…。なんだか、そういう見せ方をしてるアニメのシーンがいくつか思い浮かんできましたよ。漫画のああいう感じは、そっくりそのままできないとしても、かなり似たようなことはできるなと。

「こんなの○○で表現できねえよ」とか迂闊に思い込んだらいかんですな。「なんとかできねえかソレ」とジタバタすれば、何かしら出てくるけど。「できるわけねえよ」と思い込んでたら永遠に出てこないなと。そんなことを思ったり。

#3 [anime] まどかマギカ、ほむほむの回を視聴

BS11で放送されてるソレを見たけど。やっぱり何度見ても、クるわ…。

ほむほむの能力に制限をつけた・当面はたった一つだけ願いを叶えたことで、魔法少女らしからぬ行動を次々にとらざるを得なくなっていくあたりに感心。魔法少女という設定はどう考えても非現実的なのに、妙に現実的な展開が加えられていくことで、一見すると笑えてしまうのだけど。しかし、笑った後に、それを実行してるのが年端もいかない少女であったことを思い出して、次第に怖くなってくる。その、怖い行為を、どうして実行してるのかと言えば、そこには当人の強い想い・決心・周囲を信用できない絶望感があるが故で。…やっぱり上手い脚本だよなあ、と思えたり。

#4 [zatta] 未来の日記を書いてたり

なんやかんやで、 _DXRuby Advent Calendar 2013 に参加することになりまして、12/19に公開する予定の記事を書いていたり。要するに、未来の日記を書いているわけですけど。

スクリプトソースは3日前に書き終えていて、解説文をようやく書き始めたけど。分量が多くなって、どうしたもんかと。初心者向けの解説部分をバッサリ削ろうか…。でも、そこを削ると、その後に出てくるスクリプトの必要性が分からなくなるし。どうしようかなあ。

参加云々。 :

参加云々は、ちと悩んじゃったところもあって。どの記事もレベルが高いのに、自分が参加してもええのかな、とか。 DXRuby作者様からのお誘いは断ってしまった後で、イベント主催様からのお誘いは受けてしまってええのかな、とか。だけど当時(?)は、
  • 公開記事が少なくて、イベントのイメージが掴めなかった。
  • 自分自身、そういった記事を書いたことが全く無かったので、完全に自信がなかった。
という状態で。そこから、
  • 公開記事が増えてきて、どんなイベントなのか、ぼんやり分かってきた。
  • それっぽい記事を自分でいくつか書いてみたら、ちょっとだけ変な自信もついてきた。
と状態が変わってきて。それに加えて、
  • 主催様から、「ここ数日の日記に書いてるレベルでいいスよ」と言ってもらえた。
ので、「自分の日記を眺めた上で『これでもOK』と思うのであれば…」と。

とは言え、自分が書く予定の記事は、他の記事と比べたら絶対に頓珍漢な内容になるだろう、という妙な自信もあるのですけど。まあ、「枯れ木も山の賑わい」と申しますし…。DXRubyという山が大きくなればなあ、と願う気持ちは皆様と同じであらう、ということで御海容いただければと。

このあたり、もし来年も開催するのであれば、少し楽になりそうだな、とも。「去年はこんな感じでした」と提示すれば、イベントのイメージを掴んでもらうこともできるだろうと。なんでもそうだろうけど、前例の有無は大きいですな。

未来の日記云々。 :

考えてみたら、「未来の日記」を書くなんて、この日記ページを書き始めて以来、初めての体験だなと気付いたり。

日記を書くのを忘れていて、後になって数日前のことを思い出しながら無理矢理書き留める、なんて場面は数え切れないほどあったけど。過去は書いても、未来の事なんて、書いたことはないよなと…。

ここに来て、何かの禁を破ろうとしてる、そんな気分にもなってきたり。

そもそも自分、Web日記とblogは、性質が違うような気がしていて。
  • その日あったこと、その日見たこと、その日考えたことを、だらだら書き残すのが日記。
  • 数日〜数ヶ月かけて、内容をじっくりと煮詰め、ジャーナリストや研究者にでもなったつもりで、ドカーンと発表するのがblog。
そんな勝手な定義の違いが、自分の中にありまして。

なもんで、
「日記の中に、blog記事を書いていいのだろうか…? もしかすると、Wikiとか、単なるhtmlとか、 _Qiita とか、そういうところに書き残したほうがスッキリしないか?」
「そこまでカッチリ考えることでもないやろ。たまにはこーゆーのもいいんじゃね?」
てな間で悶々と。自分、めんどくさい人間だなあ…。

Qiitaが出てきた頃、「こういうサービスって意味あるのかな。プログラマーさんはえてして自分のblogで書いちゃうんじゃないか」と思ってしまったのですけど。自身のblogに載せるのはちょっと、と躊躇してしまう属性の記事も、Qiitaなら書けるという需要はあったのだろうなと…。未来の日記を書き始めたことで、今頃気付いた次第。

2013/12/15() [n年前の日記]

#1 [prog] Qiitaのアカウントを取ってみたり

実際何かを投稿するかどうかはわからないけど、とりあえず取ってみたり。そのうち使い始めるかも。

github や twitter のアカウントと連携して、というあたりが、ちょっとよく分からず。github のほうをクリックしたら、英文ページが…。何をどうすればいいのやら。

#2 [anime] 聖闘士星矢Ω、「なぜ脱ぐ!?」の回

紫龍親子が活躍する回を視聴。個人的には、敵の人の「なぜ脱ぐ!?」の台詞だけで「よしっ!」という感じでした。何が「よしっ!」なんだかよく分かんないけど。

考えてみたら、結構深いのかもしれない。自分達は現実世界のあちこちで、何かを取り繕いながら生きてるわけですけど。そこで、ここぞというタイミングで、「パンツを脱ぐ」「ぶっちゃける」「裸になる」ってのは、やっぱり何か強いんじゃないかと。脱いじゃえば、もう、後はないわけですよ。脱いでしまった分、恥も外聞も無く、何かの一点に自分の持っているリソースを集中して突進するしかない。それで通ればそれで良し。通らなくても、「ここまでやってダメだったのだから、こりゃもうどうしようもねえや」と清々しい気持ちで諦めもつくだろうと。…てなことを考えてしまいました。まあ、それを、「背水の陣」と呼ぶのでしょうけど。…なんかコレ、前にも書いたような? 気のせいかな。

それはそれとして。 を目にして、今回の演出家さんは、星矢の漫画原作を意識しながらコンテに挑んでくれてるなあ、と、見ていて嬉しくなりました。それでいて、息子さんが軽く吹っ飛ぶところに件のレイアウトを挿入して、しかし勝負の決着がつくシーンではアニメノリのコンテになってたので、さすがだなあ、と。

星矢の最初のアニメ版は、漫画の中では軽く流されてる部分を、丁寧に、律儀に、アニメスタッフならではの解釈で映像化していく点も売りだったと思うわけで。原作では、見開きページをドーンと見せるだけで終わらせていても、具体的にはそこでどんなバトルが繰り広げられていたのか、肉付けをしていくのがアニメ版だっただろうと。

そんなわけで、決定的シーンに漫画原作のソレを挿入してしまうのではなく、その前のちょっとしたシーンに挿入したあたり、「わかってらっしゃる」と感心させてもらったのでありました。

最初の聖闘士星矢アニメ版の映像表現の方向性。 :

これ、前にも書いたかもしれないけど。自分が未だに覚えてるのは、ペガサス流星拳の表現で。

漫画原作では、音速だか光速だかを超えるパンチ、と説明されてるらしいですが。アニメの演出家さんは、「音速を超えるパンチって、どんなパンチなんだろう?」と真面目に考え始めたそうで。音速は秒速nメートルだけど、そんな速度で映像を見せたら何やってるか分からない。ここは逆に考えて、1秒間当たり何発パンチを繰り出せるのかで考えようと。計算してみたら、1コマあたり何発パンチを描き込めば、理論上は音速を超えるパンチになっているはずだ…。

てなわけで、ボコボコボコとパンチが生まれて打ち込まれる、今まで誰も見たことが無い、妙に説得力のあるパンチ映像が誕生したという。もちろん、もはや人間技じゃないのだけど。その分、聖闘士と呼ばれる連中の超人性を見事に表現できていた。

そのように、漫画家さんが、おそらくは単なるハッタリでさらっと書いた部分も、「これを映像にするとどうなるんだろう」と真面目にやってみる ―― そんな作業を律儀に繰り返していたのが、聖闘士星矢の最初のアニメ版だったのではないか、と思うわけですよ。結果、日本全国、いや、世界中の子供達が、「カッケー!」と喜ぶ、熱い映像になっていったのだろうと。

このあたり、漫画原作のコマのレイアウトをそのまま模写すれば忠実なアニメ化なんだ、と考えちゃう昨今のソレとは、取り組む姿勢からして違うのだろうなと。

でもまあ、聖闘士星矢Ωは、別に漫画原作があるわけでもないので、そのへんちょっと難しいだろうなと思うのですけど。まあ、そういうノリにも、時々挑戦してくれたら嬉しいなあ、なんてことを思ってるのでした。超人らしさの表現を、存分に追求できる機会なんて、滅多にあるもんでもないだろうし。

と思ったけど、昨今の東映アニメって、ワンピースもプリキュアも、超人ばっかりだな…。実は東映アニメのお仕事って、超人表現にチャレンジし放題だったのか…。

そもそも原作に書いてあったらしい。 :

上に書いたソレって本当にそうだったのかなと不安になってググってみたら、そもそも原作で、そういう説明をしていたらしいと知り。

_聖闘士星矢のペガサス流星拳 - Yahoo!知恵袋

作中で、どうして音速を超えるのか、1秒間に何発打ってるのかを、しっかり解説してたという話が。なるほど、理屈を捻り出したのは、演出家さんじゃなくて原作者だったのか…。するとアニメ版は、それを真面目に受け取って映像化してみた ―― アニメは秒間24コマだから、1コマあたり何発描けば1秒で100発になるはず、てなノリでホントに試してみた、ということになるのかな。

こういうのって、妄想していくと面白そうですな。ソニックブームとやらが発生したりするんだろうか。SF考証してるぐらいに物知りな方々に、聖闘士の各必殺技について相談してみたら、一風変わった表現が生まれるのかもしれない…。

その場合、肩書はどうなるんだろう? SF考証じゃなくて、必殺技考証、みたいな名称になるのかしら。

#3 [dxruby][game] DXRubyでペガサス流星拳

聖闘士星矢Ωの感想記事を書いているうちに、「その、ペガサス流星拳の表現って、DXRubyで試せないのかな?」と思えてきまして。

1秒間に100発打てるということは、アニメは1秒間24コマだから、100/24 = 4.166...。1コマにつき、約4発、パンチを描けばいいのですかね?

# ペガサス流星拳

require 'dxruby'

bodyimg0 = Image.load("body1.png")
bodyimg1 = Image.load("body2.png")
punchimg = Image.load("punch.png")

# パンチを出す中心位置
punch_bx, punch_by = 210, 300

cnt = 0
framerate = 24
Window.fps = framerate # 24FPSに設定

Window.loop do
  break if Input.keyPush?(K_ESCAPE)

  if cnt < framerate
    Window.draw(0, 0, bodyimg0)
  else
    Window.draw(0, 0, bodyimg1)
    
    # 1秒間で100発ということは、
    # 1/24秒なら、約4発
    4.times do |i|
      c = (cnt - framerate + 8.0).to_f / framerate.to_f
      x = punch_bx + (rand(400) - 200) * c - punchimg.width / 2
      y = punch_by + (rand(200) - 100) * c - punchimg.height / 2
      scale = 1.0 + (1.5 * (cnt - framerate).to_f / framerate.to_f) * rand()
      angle = rand(45) - 22.5
      Window.drawEx(x, y, punchimg,
                    :angle => angle,
                    :scalex => scale, :scaley => scale)
    end
  end
  
  cnt += 1
  cnt = 0 if cnt > framerate * 2
end
ペガサス流星拳
GIFアニメにした段階でフレームレートが怪しいことになってますけど。こんな感じだった…のかな…。うーん。記憶の中にあったソレより、全然ショボイ…。どうやら、かなり脳内美化をしちゃってたような気がしてきました。

まあ、ちゃんとした絵で描かれてたら、カッコよく見えるのかもしれないか。それと、今ならCGが使えるから、例えば流星みたいなパーティクルも一緒に飛ばして、とかやれたりするのかも。もしかしたら、自分がぼんやり見ていて気づかなかっただけで、星矢Ωの中でも、既にそういう工夫を施したカットがあったのかもしれませんな…。

とりあえず、画像とソースを置いときます。Public Domain ってことで。

_ryuuseiken.zip

妙なことを思いついたら、すぐに試せるあたりが、DXRuby のいいところですな。もちろん、こういうのは、Ruby/SDL でも PyGame でも HSP でも Processing でも、何使ってもいいんですけど。Windows上で動かしたときに爆速描画な点と、使い方が簡単な点が、DXRuby のいいところ、とも思います。

2013/12/16(月) [n年前の日記]

#1 [anime] 境界の彼方、黒の世界、を視聴

最後のあたり、良かった…。 曲・歌詞の使い方が、イイ…。グッときました…。もうねえ…コレ、理想形ですわ。まるでお手本のようですわ。素晴らしい。これは素晴らしい。

「キャンディキャンディをイメージしながら作りました」みたいなソレじゃなくて、ホントに良かったなあ…。そういうアレだったら、こうはできない…。

この 、幸せ者だなあ…。仲間外れにされなかった。本編と一緒にスゴイ勢いで飛んで行けた。監督さんに 音楽の力を信じてもらえた。いやー、良かったなあ。こういう使い方を見ると、嬉しくなるなあ。素晴らしい。とにかく素晴らしい。

#2 [dxruby][ruby] DXRuby開発版がRuby2.0.0以降にのみ対応する方針と知ってちょっと困ったり

DXRuby 1.5.8dev版が公開されたようなので、試してみようと DXRuby Wiki を開いてみたら、Ruby 1.9.x 用が無くて「あうっ」てな状態に。改めて作者様のblogを追いかけていくと、DXRuby は今後 Ruby 2.0.0 のみ対応していく方針らしくて。

うーむ。困った。個人的には、困った。

自分は時々、NetBeans 使って、Ruby + DXRuby スクリプトのデバッグをすることがありまして。妙な動作になる原因がどうしても分からん時、ブレークポイント設定して、そこで止めて、変数覗いて、みたいな作業をするのです。

しかし、NetBeans 上で Ruby のデバッガを使おうとすると、これが Ruby 1.9.3 までしか対応してませんで…。 *1 NetBeans 上で、Ruby 2.0.0 を選んでしまうと、もはやデバッガを動かせないわけですよ。かといって、この時代に、CUIでデバッガ使うとか、printfデバッグとか、そんなの勘弁願いたいし。

てなわけで、さあ、困ったぞ、と。

以前もこういうことがあったなと。 :

昔、Ruby 1.8 が主流で、Ruby 1.9 がじわじわ普及し始めた頃、やっぱり Ruby 1.9 ではデバッガが動かなくて困ってしまって。

ただ、当時の DXRuby は、Ruby 1.8 にも 1.9 にも対応していたので…。
  • デバッグ時は、デバッガが使える Ruby 1.8 上で動かす。
  • 最終的な実行は、処理速度が劇的に改善された Ruby 1.9 上で動かす。
そういう形で、どうにかしのいでいたのです。

現行世代のほうが性能は上がってるけど、一世代前のほうが開発環境はえてして整ってる・使える武器が多いわけで。それを考えると、現行世代と一世代前の二つに対応してるライブラリは、ある種、いいとこどりができる部分もあるよなあ、と。

デバッガの規格って無いのかな。 :

NetBeans のソレは、Ruby 1.8 時代の仕組みしか考えてない設計なのが問題だったりするのだろうけど。

このあたりって、規格を決められないのかしら。その規格に沿ったやり取りをすることにしておけば、言語・環境のバージョンが変わっても問題になりにくいのでは、という気もするけれど。言語の内部仕様に食い込むような部分もあって、なかなか決められないところもあるのかしら。

*1: Fast Debugger だか ruby-debug-ide19 だかを導入しないといかんのですが、それらは Ruby 2.0.0 以降は対応してない。 Fast Debugger ではなく、 Classic Debugger なるものを使えば動くかと思いきや、例外が発生してフリーズしちゃう…。

#3 [ruby] Ruby2.0.0+IDEでデバッガは使えないのかな

そろそろ Ruby 2.0.0 以降でも使えるデバッガ+IDEを見つけないといけない、ということなのだろうなと思えてきたので、この際、ちゃんと探してみようかなと。

Aptana Studio 3 を試してみたり。 :

NetBeans なんぞ使ってるからあかんのや、他のIDEを使うべし、という状況なのかもしれないか…。では、Aptana Studio はどうだろう。ググってみたけど、解説されてるソレは、Ruby 1.9.x 時代の情報ばかり。うーん。コレもダメなんじゃないか? まあ、試しにインストールしてみるか…。

結論を先に書いておくと、Aptana Studio は NetBeans より酷くて、Ruby 1.8.7 でしかデバッガが使えなかったです。うーん。

とりあえず、導入手順をメモ。以下の記事を参考にインストール。

_フリーの高機能HTMLエディタ「Aptana Studio3」の日本語化と「Zen-Coding」のインストール方法 | 便利なツール
_Aptana Studioを使ったRuby/RoR開発

スタンドアローン版の、Aptana_Studio_3_Setup_3.4.2.exe をDLしてインストールしてみたり。

日本語化は、以下から pleiades.zip (1.4.x) をDLして、中に入っている features、plugins フォルダを、Aptana Studio インストールフォルダに上書きコピー。

_Pleiades - Eclipse プラグイン日本語化プラグイン | MergeDoc Project

Aptana Studio をインストールしただけではダメで、Ruby開発ツールもインストールしないといかんらしい。

_Ruby開発ツールのインストール - Aptana Studioを使ったRuby/RoR開発

インタプリタの指定を Ruby 2.0.0 にして、Rubyプロジェクトを作り。簡単なスクリプトを書いて、ブレークポイントを設定して、デバッグを実行してみた。…うむ。「ruby-debug が必要じゃい」と言われた。だからさあ、ソイツは Ruby 2.0.0 で動かんのだってば。

設定を眺めてたら、Ruby → デバッグ → エンジン、の項目で、デバッグエンジンを指定できるらしく。ここがデフォルトでは、「高速 Ruby デバッガー(ruby-debug)」になっていた。「Ruby組み込みデバッガー」もあるので、そちらに変更。

よく分からないエラーが大量に出た。ダメっぽいな…。

デフォルトの Ruby インタープリタを、Ruby 2.0.0 から 1.9.3 に切り替えてみた。これもダメ。組み込みデバッガではエラーが出るし、高速デバッガでも「ruby-debug が必要じゃ」と言われる。変だな。巷の解説記事では、ruby-debug19 が入ってれば動くと書いてあるのに…。

もしかして…。 Ruby 1.8.7 に切り替えてみた。うむ。これはブレークポイントで止まるな…。組み込みデバッガも、高速デバッガも使える。

すると、Aptana Studio 上でデバッガを使おうとすると、Ruby 1.8.7 までしか対応してない、ってことになるのかな。

_Eclipse Community Forums: Dynamic Languages Toolkit (DLTK) ≫ Debugging Ruby on Eclipse を眺めると、「Ruby 1.9 でデバッガ使えないよう」「この拡張の中身を見たけど、ハードコーティングされてるぞ。なんじゃこりゃ」云々のやり取りが。ダメっぽいな…。

Ruby 2.0.0対応のデバッガ情報 :

ググった範囲でメモ。

_Ruby 2.0 向けのデバッガー byebugについて - Qiita [キータ]
_[ruby-list:49324] Re: 1.9 から 2.0 への移行にあたって 困ったこととかありました?
_cldwalker/debugger
_2013/08/02/ruby2.0時代のデバッガはこれだ - ヽ(´・肉・`)ノログ

どうにも情報が少なくて。困った。

Ruby 2.0.0 上では、debugger、byebug というデバッガが使えるらしいので、一応どちらも入れてみたのだけど、ただ、どっちも、CUI なわけで。えー。21世紀にもなってそりゃねえよ、どんな拷問だよ、という気もするんですけど…。どうにかならんのかな。

emacs+デバッガの組み合わせもあるらしいけど。 :

Rubyのデバッガと、emacsを連携して、ということもできるらしいので調べてみたけど。それら解説記事も、ruby-debug の文字が書いてあったので、おそらく状況は、NetBeans や Aptana Studio と同じなんじゃないかと予想したり。

_EmacsをつかったRubyのデバッグ | アルミナ解析室 を眺めると、CUIのデバッガを呼び出して、ということができるらしいのだけど。ていうか、自分の ~/.emacs にも設定が書いてあって目が点になったのだけど。何時頃書いたんだろう。完全に忘れてる。

さておき、NTEmacs上で使ったら、CUIのデバッガらしきものは出てきたものの、操作方法が分からず。DOS窓上で使った時のように、nを押せば次に進む、というわけでもないような。うーん。もしかして、*NIX や Mac なら、スンナリ動くのかしら。

eclipseを試した。 :

もしかすると eclipse + Aptana Studio の組み合わせなら使えたりしないかなと思えてきたので試してみたり。

インストール済みだった eclipse 4.2 を久しぶりに起動。更新の確認をしていったら、Android 関係の SDK も更新しないといかんと言われたので、この際それも更新。

気づいたら、eclipse 4.3 が公開されてたようで。せっかくだからそっちもインストール。 _日本語化 Eclipse 4.3 Kepler ケプラー | MergeDoc Project から、32bit版 Ultimate をDL。パスの短いフォルダに移動させて、展開先フォルダ名も短い名前にして解凍。そうしないと、パスが長過ぎて解凍できないファイルが出てくるので、ここは要注意ですぞ。

以下をインストール。
  • Aptana Studio 3
  • RDT(Ruby用の拡張)
  • ADT(Android SDK用の拡張)
  • ETEE
他に入れてた拡張はあったかな…。まあいいや。とりあえずここまでで試すことに。

Ruby 1.9.3 で、高速デバッガを指定したけど、これはダメ。組み込みデバッガを指定したら…。お? ブレークポイントで止まった。

Ruby 2.0.0 にしてみた。組み込みデバッガを指定。…おお。ブレークポイントで止まってくれた。

全変数の中身が覗けないのが気になるけど、監視ウインドウを出して変数名を登録してみたら、登録した分だけは一応覗けた、ように見える。…でも書き換えができないな。うーん。

ステップ実行するとエラーが発生するのも気になる。どうも監視ウインドウの中に空行があるとエラーが出るらしい。

それでも、Ruby 2.0.0 を使っていて、GUIでデバッガを使えそうなのはありがたい。CUIでどうにかするしかないのかなと、かなり暗い気持ちになってたわけで。それと比べたら、はるかにマシ。

ということで、スタンドアローンの Aptana Studio はよろしくないけど、eclipse + Aptana Studio + RDT なら、もしかすると Ruby 2.0.0 でもデバッガが使えるのかもしれず。

_Bug 345976 - Debugger is looking for ruby-debug gem when it should look for ruby-debug19 を眺めると、Ruby 1.9.3 でも Ruby 2.0.0 でも debugger との組み合わせで動いてるという報告らしきものがあるのだけど。それが本当なら、ruby-debug-ide19 を要求してくるNetBeans を使うのを諦めて、eclipse に移行したほうがいいのだろうか。うーん。

NetBeans上でも変数の値を書き換え出来なかった。 :

NetBeans 上で動作を確認してみたら、そちらも、値を見れるだけ、だったのですね…。もしかして、値を書き換えるのは、また別のツールなのだろうか。

大昔、MC68000使用のハード上で、ガンガン値を書き換えながら動作確認してた気もするんだけど、あの時使ってたツールは、一体何だったんだろう。アレをデバッガと呼ぶものと思い込んでたんだけどな…。

それはともかく、Ruby 1.9.3 上でも debugger その他をインストールしておかしくなってしまったので、gem uninstall 〜 で、ごっそりアンインストール後、ruby-debug-base19等をインストールし直し。以下のページが参考になりました。ありがたや。

_Ruby1.9.3の実行環境とデバッグ環境の整備 | Dear プログラマー
_Windows7でRails3 + NetBeans + デバッガー が動かない - 同じにやっても動かない
_exabugsの雑記帳 Eclipse(Aptana3) で Ruby1.9.3 をデバッグする

lib/ruby/gems/1.9.1/gems/ruby-debug-ide19-0.4.12/lib/ruby-debug/xml_printer.rb の修正を忘れて、変数ウインドウを表示すると途端に落ちるという不具合に見舞われ、首を傾げてました。
class String
  def is_binary_data?
    ( self.count( "^ -~", "^\r\n" ).fdiv(self.size) > 0.3 || self.index( "\x00" ) ) unless empty?
  end
end
を追加する修正をしておかないといかんのですな…。

それにしても、NetBeans 上のソレって、やたらフリーズするなあ…。ruby-debug*19 は、もうメンテナンスされてないという話も見かけたし。どうしたもんか。

この記事へのツッコミ

Re: Ruby2.0.0+IDEでデバッガは使えないのかな by monsieur_murah    2014/09/26 14:57
Ruby開発環境としてRDEを愛用してましたが、Ruby2.0ではデバッグできないので、乗り換えようと模索しておりましたが、なかなかまとまった情報がなく、
非常に参考にさせていただきました。
Eclipse + Ruby2.0.0 + RDT + 内蔵デバッガはうまくいきましたが、
唯一、メソッドのキーワード引数を認識してくれず、アウトライン機能がうまくいかなかったので諦めました。どうもRDTは最近の更新が止まっているようで、
使い続けるのは少々ためらいを感じました。
NetBeans(8.0.1) + Ruby2.0.0 + Ruby and Rails Pluginは、デバッガとしてインストールするgemを
ruby-debug-ide-0.4.22.gem(お尻に19とか書かれていないやつ)
debase-0.0.9.gem(2.0用らしいです。ruby-debug-ide-0.4.22/lib/ruby-debug-ide.rbの8行目でご指名されてます。)
とすれば、ブレークポイントで止まって変数の中身を見る事ができています。
(xml_printer.rbの追記は相変わらず必要みたいですが。)
私のような迷える子羊さん達の参考になれば、と投稿させていただきました。

#4 [dxruby] Ruby 1.9対応版の DXRuby が欲しいな…

開発版はともかくとしても、せめて、DXRuby 1.5開発版をバックポート(?)した DXRuby 1.4.1 は、Ruby 1.9対応版も欲しい…と思えてきたり。もちろん、技術的に難しいとか、対応がめっちゃ大変、という話なら、仕方ないのですけど。
*1

DXRuby 1.4.0 には、フルスクリーン表示がおかしくなるバグが ―― ゲームアプリ制作においては、結構クリティカルなバグがあった記憶が。 *2 そんなバグ持ちバージョンを、Ruby 1.9 対応の最後のバージョンにされてしまうと、ちと自分は困るので。「DXRubyオススメ」と言えなくなる。もにゃもにゃしてきちゃう。

「Windowsオンリーと言う制限はあるものの、誰でも手軽に使えるのが DXRuby の売り」と自分は思っているのですけど。もし、「Ruby 2.0.0以降のみ対応」という方針になると…。興味を持った方が導入してる Ruby のバージョンによっては、いきなり門前払い食らわせることになるよなと。DXRubyが持っていた、「誰でも手軽に」が無くなっちゃう。

かといって、「Ruby 1.9上で使いたい人は DXRuby 1.4.0 を使って」と言われてしまうと、それはバグ持ちバージョンであることが自分は分かってるから、オススメだの宣伝だのはしにくくなるし。

初心者向けも考慮したい、あるいは、お試しから本格利用まで間口を広げておきたいなら…。Ruby 1.8 はサポート終了してるからともかくとしても、Ruby 1.9 までは、まだ、今のうちは、あくまで当面は、対応しといたほうがいいのでは、と思うのですけど。せめて、バグを取った正式版は、二世代分に対応していただけないものかと。

とは言え現行版にのみ対応するメリットもありそうで。 :

  • Ruby はバージョンが上がるたびに処理速度が改善されてる。リアルタイムゲームを作るなら処理速度が速いほうが望ましい。現時点で最速の環境にのみ対応、という考え方も、ライブラリの性質からしてアリなのかも。
  • 今後 DXRuby が、Ruby 2.0.0 以降で追加された機能を積極的に活用するつもりなら、Ruby 1.9.x に対応し続けるのは技術的に難しい。
  • Ruby 1.9.x を導入してある環境でも、pik を使えば Ruby 2.0.0 がインストールできるので、「お試しインストール」も不可能ではない。そもそも、スターターキットだってある。
  • DXRuby は将来的に OpenGL もサポートする、という話もあり…。すると、Windows 限定ではなくマルチプラットフォーム対応のライブラリに変貌していくのかなと。他ライブラリが放置状態の中、DXRuby だけが、最新Rubyに対応済みの2Dゲーム制作ライブラリになり、存在意義が変わってくる可能性も。古いRubyを切り捨てて失うユーザ数より、マルチプラットフォーム対応にリソースを集中して新規獲得できるユーザ数のほうが多い、という展開もありえる。
前世代を切り捨てる理由を、自分もスラスラ思いついちゃうあたりが、なんというか。うーん。

余談。 :

このあたり考えていくと、 _Shoes_Processing 、 あるいは _HSP のように、「そこで一旦全てを閉じてしまう」方針も、なんだか理解できちゃいますな…。

根幹技術がアップグレードした際に、自分達まで右往左往する状況を回避したい、となると、根幹技術のバージョンを固定して同梱したり、開発に必要なエディタを同梱して強制したり…。そういった手段は有効なのかなと。その代り、開発環境を丸ごと提供し続ける形になるので、開発リソースが分散して、全体の作り込みは今一つになりそうですが。

Processing のエディタの表示バグを眺めてると、「そこはもう、本来 Processingが担当する領域じゃないけど、こういうパッケージングしてるからには、そこにもリソース割かないといかんよな…」と思えてきて、なんとも難しいなと。

*1: DXRuby 1.6.0 が出てくる頃には、Ruby 2.0.0 を取り巻く環境も変わっているでしょうから、DXRuby 1.6.0 からは Ruby 2.0.0 以降で、という方針は構わないのですけど。
*2: そのバグがあると分かってたら、アプリ側で、フルスクリーン表示可にする仕様を入れるわけにはいかない・入れてあっても削る選択肢しかないので…。アプリ側で努力して解決できる問題ならクリティカルじゃないけれど。ライブラリを差し替えないと直せない症状はクリティカルな部類じゃないかと。

2013/12/17(火) [n年前の日記]

#1 [unity][game] 「ユニティちゃん」いいなあ

_ユニティ・テクノロジーズ・ジャパン、無償利用可能なキャラクター「ユニティちゃん」を発表:CodeZine
_UNITY-CHAN!

少し前に Unity を触っていて、勉強用として使えるモデルデータが見当たらなくて、モブ子さんやMakeHumanモデルを変換して表示して、とかやってたんですけど。公式で、こういうモデルデータが用意されるなら素晴らしいなと。「とりあえずはユニティちゃんを表示して勉強しよう」となるだろうから、モチベーションの維持にも繋がりそう。

もしかすると、こういうソレは、他のライブラリも参考にしたほうがいいのかもしれないと思えてきたり。 HSPなんて、同梱のサンプル画像が、大昔の洋ゲーに出てきそうなオヤジの生首画像、ですからね…。生首画像が画面一杯に飛び散るサンプルを目にして困惑した記憶が。

考えてみたら、enchant.js はそのあたり上手いよなと。「とりあえずクマ出しとけ。クマを出せば、プログラム書き始められる」みたいな。あのクマ画像は小さいドット絵だけど。しかし、彼がそこに居る意味は、かなり大きい…気がしてきました。

#2 [tv] ロボットバトル番組を視聴

民放で放送されてた番組を録画してあったので消化。2m以下のサイズでロボットを作ってバトルさせる、という企画のようで。

移動途中でバタンと倒れて壊れてしまうロボット。足が制御できなくなって前に倒れてバラバラになるロボット。制御を司るPCにパンチされて動けなくなるロボット。エンジンが止まって動かなくなるロボット。

漫画やアニメのソレがどれほど夢物語なのかを痛感してしまう展開ばかりで…。あれだけ苦労して作ったのに…。二足歩行とかしてないのに…。

爆発した原発に入って作業するロボットが実現するのはまだまだ先なのだろうなと思えてきたり。そういう場所では、途中で止まっても助けに行けないもんな…。必ず帰ってくるレベルにまで高めるのは大変そう。

む。行って帰ってくるだけのロボットで、何か話作れないかな。ってソレは、はやぶさの映画かな…。

#3 [anime] サムライフラメンコ、敵基地の回まで視聴

途中で急に面白くなくなったと思ったら…。そこまで含めて 敵の作戦って…考えたなあ…。のんびりとした呑気なやり取りと、 拷問・改造シーンのコントラストが凄い…。

毎回(ではないけど、ほぼ毎回)感心してるのが、ちょっとした台詞でクスリと笑えてしまうあたり。脚本家は誰だろうと思ってスタッフロールを見ると、これが全部、倉田脚本で。こういうところが強み、だったりするのでしょうか。自分、倉田脚本作品はほとんど見れてないので、傾向は分からないのですけど。

そういや昔、「今、そこにいる僕」を見て、「この脚本家さん、酷いなあ。悪魔のようだなあ」と思ったことがあったっけ。考えてみれば、そのあたりのノリが、この作品でも 拷問シーンのあたりで滲み出ている気がしてきたり。

#4 [nitijyou] 自転車で買い物に

雪は完全に溶けた上に雨や雪も降ってなかったので、ヨークベニマルまで行って夕飯の食材を。元グリーンモールの場所にヨークベニマルができて、距離的には助かるなと。

いつ行っても駐車場は一杯だし、店内も結構客が来ているように見えるのだけど。経営側としては、それでも集客は今一つ、ということになってる、てな話も耳にしたわけで。おかしな話だなあ…。何か、計画段階で計算ミスでもしていたのでは…。この駐車場数ではそもそもこのくらいしか入らんはず、なのに多く見積もってた、とか。

2013/12/18(水) [n年前の日記]

#1 [neta] 車の中の妖精さん

寝ていたら、車のダッシュボード? グローブボックス?の中ですやすや寝ている小人の女の子、が出てくる四コマ漫画、を読んでいる夢、を見たのだけど。そういう漫画ってどこかにあるのかな…?

こんな感じの夢で…。

主人公、新車を買って、乗り込んで、中を色々弄ってる。
ダッシュボードを開けたら、寝息を立ててる小さい女の子が居て、目が点に。

女の子「むにゃむにゃ…。ハッ! すいません。今、西暦何年ですか?」
主人公「…2013年だけど」
女の子「ああー! なんてこったー! ここで30年も寝続けてたー!」
主人公「いや、これ新車なんだけど」
女の子「あっ」

なんでこんな夢見たんだろ。わからん…。

艦船のメンタルモデルなる設定があるのだから。 :

「蒼き鋼のアルペジオ」には、戦艦のメンタルモデルと称して女の子が出てくるのだから…。

車やバイクにも、そういうのがあってもいいのかもしれないなと。

む。考えてみたら、それって「ナイトライダー」の「K.I.T.T」かもしれないか…。

日本製アニメで「ナイトライダー」をリメイクしたら、「K.I.T.T.」は女の子になるのかな、と妄想。いや、ドライバーを美女 or 美少女にして、「K.I.T.T.」はイケメン男性にするのもアリかな…。

まあ、日本は、Windowsや電車が美少女になるぐらいだから、車やバイクでそういうソレの漫画やアニメも既にたくさんありそうですかね。

#2 [pc][neta] 「MZ700 Advent Calendar」とか「X1 Advent Calendar」とか無いのかな

別に、 等々、何でもいいんですけど。完全に、オッサンホイホイコンテンツですな。

今の時代にソレを書いてみてどうするのだ…という気もしますけど。

#3 [nitijyou] 明日の分の日記も一部アップしてみたり

今のうちに出しとけば色々楽かなと思ったのでアップロードしておきます。

#4 [dxruby][game] とりあえずBGマップを表示するべく作業中

先日、Tiled で実験用BGマップを作ったものの。画面に表示してみないと実験もへったくれもないので、そのあたりを勉強中。

もしかすると、そのうち DXRuby Advent Calendar で紹介されるのでは、という予感もあるけど…。Ruby には、Tiled の保存フォーマットを読み込める _tmx というライブラリがあるので、今回はソレを使わせてもらおうかと。

ちなみに、以前触った際には、nokogiri、oj が必要だったのだけど。現在の版は、nokogiri、multi_json を要するように変わったらしい。

今時の2Dゲームの適切なタイルサイズってどのくらいなんだろう。 :

昔のTVゲーム機は、QVGA = 320x240前後の画面サイズで、タイルサイズは8x8ドットが最小だったのだけど。

今時のPCゲームは、いくらなんでもVGA = 640x480より小さくなることはないだろうから…。画面ドット数が縦横2倍になってるのだから、タイルサイズも、最小で16x16ドットになるのかなと。

でも、本当にそれでいいのかしら。例えば…。
  • GPU、もしくは、使用ライブラリが、小さいテクスチャを大量に出すより、大きいテクスチャを少量出すほうが速いのであれば、タイルサイズを32x32や64x64にしたほうが安心できそう。
  • 「今時 640x480 の画面サイズのゲームなんてないよ?」「800x600もないよ?」「1280x720 とか 1920x1080 でもいいぐらいだよ」ということなら、タイルサイズも大きいほうがヨサゲ。
ずっとPC向けゲームを作ってきた人なら、このあたり感覚的に分かるのかもしれないけど。どこかに参考記事・解説記事がないものか…。

表示はできた。 :

表示もできたし、当たってるかどうかの判定までは、どうにか動いたような。
BGアタリ判定
後は補正処理 ―― 補正後の座標を返す処理を書かないと、かな…。

先日作ったテスト用マップは、最低限のBGアタリ番号だけでマップを作れないかと思って作業してたけど。プログラムを書いてる最中、やっぱり、属性で分けて、別のアタリ番号にしたほうが良さそうだなと思えてきたので、そのようにマップを作り直したり。ぶら下がり棒や、空中に浮いてる床=ジャンプして飛び乗れる床は、別のアタリ番号に、みたいな。
変更後のテスト用BGマップ

Tiled でマップ作成する際にも、見た目からして、「ここは空中に浮いてる床」「ここはぶら下がり棒」と分かるほうが、バグを入れずに済みそうだし。

もし、最低限のBGアタリ番号でどうにかしようとすると、
  • 平らな床は、上下2マス分、床タイルを置くこと。
  • ぶら下がり棒は、上下2つの斜め床の組み合わせ、及び、空中に浮いてる一マス分の床で配置すること。
  • 空中床は、床タイルの下に、高さ半分の床を配置すること。
といった具合に、どうしてソレが必要なのか、プログラマー以外はピンとこない、奇妙なBGマップ作成ルールを強要することになりそうで。

それよりは、それぞれ別のアタリ番号を用意して、配置してもらうほうが分かりやすいだろうなと。

各タイルのアタリ判定用データについて。 :

昔、このあたりの処理を書いた時は…。アタリ番号一つ一つに対して、「当たってるか、当たってないか」の判定処理を、わざわざプログラムで書いてたのですが。
プログラムで判定する例
当時は、テーブルで持ったらROM容量を圧迫してしまうのではないかと不安だったので…。タイル種類が増えるたびに、その形に合わせて、毎回コツコツと書いていくという、ちとアホみたいな作業をやっていて。

だけど今では、RAMは比較的余裕があるだろうし、テーブルで持ってしまっていいよなと。そのほうが処理もシンプルになるし、どのタイルでも実行時間が一定になるし。
テーブルで判定する例
場合によっては、当たってるか当たってないかの判別用に、0/1で、タイルサイズ分の二次元配列 or ビットデータ列を持ってしまってもいいぐらい、かもしれない。 *1

さておき。今はテーブルを用意して処理するとしても、テーブル作成が面倒臭い。ので、プログラム側に画像を渡して、各タイル内のドットの有無をスキャンして、配列に入れる形にしてみたり。与える画像さえ修正してしまえば、即座にテーブルに反映される上に、画像上で凝った形状を作っても、ちゃんと反映されるので、作業は楽になるかもしれないなと。

待てよ? どうせ画像を渡すなら、当たってるかどうかの判定も、画像中のドットを見て、やっちゃっても良さそうな。いや、どのみち補正用の座標を得るためにテーブルが必要になるのだから、それを使って判定してもいいか…。

このあたりの処理って、どのくらいの個数のオブジェクトが、地形アタリを取るのかで違ってくるから…。やたらと呼ばれるなら速くしないといけないけれど、たいして呼ばれないなら、処理を速くしてみたところで、さほど意味は無いし。動かしてみて重くなったら、その時に最適化を、てなノリでも良さそうな。

*1: 今になって考えてみたら、上下方向用に2つのy座標、左右方向用に2つのx座標を持てば済んだのだから、当時もテーブルで持ってしまったほうが良かったのではと思えてきたり。当時は1タイル32x32ドットで処理してたけど、座標1つにつき5bit、いや、ヌケ部分も考えると6bitで済んだのだから、1タイルにつき、192bit x 4方向 = 96byte、かける、タイル種類分で済んだよな…と思ったけど、それはそれで結構容量を食いそうな。3KByte…当時としてはどうだったんだろう…。上下左右の反転もあるから、もうちょっと少なくできるかな…。

#5 [ruby] Ruby 1.9.3上でirbを使うとフリーズしちゃう

環境は Windows7 x64 + Ruby 1.9.3 mingw32版。irbを使ってちょっと動作確認しようとすると、何かの拍子にフリーズしてしまう…。上書きインストールで更新してしまったせいだろうか…。

Ruby 2.0.0 の irb なら問題は…。いや、こちらも時々反応が返ってこないな…。何か補完関係で処理時間がかかってるんだろうか。よくわからんなあ…。

Windows/DOS窓だから、なのかな…。*NIX や Macなら、もしかするとスンナリ動くのかしら。

それとも、何か変な設定ファイルが、自分の環境に残ってしまってるのだろうか…。~/.irbrc は消してみたんだけどな…。うーん。

2013/12/19(木) [n年前の日記]

#1 [dxruby][game] DXRubyと疑似乱数

_DXRuby Advent Calendar 2013 の 19日目です。

17日、18日目の記事は、GameKazuさんの、 _DXRubyでRPGを作る_DXRubyでRPGを作る(2) でした。自分、RPGは作ったことが無いので、大変勉強になりました…。

今回は、「DXRubyと疑似乱数」というお題で書かせていただきます。個人的に、前から少し気になってた部分なので、せっかくだからこの機会を利用して検証させてもらおうかなと。

「疑似乱数? DXRubyと関係ないじゃん」と思われる方もおられましょうが。 という流れで、全く関係ない話ではないよね? と。そんなわけで、大目に見てもらえればと。

とりあえず。 この流れで話を進めていこうかと。中級者以上の方は、「あーハイハイ。知ってる知ってる」と、全部読み飛ばしてしまってOKですよ。

最初に謝っておきます。やたらと長い記事になってしまってゴメンナサイ…。

それでは、初心者向けの解説から。

Q. 疑似乱数って何? :

A. 要するに、サイコロです。どんな数が出てくるのか予測できない数。でたらめな数。それを乱数と言います。「乱れた数」と書きますが、つまり、そこに、ルールだの法則だのが無いように見える数、ということですね。

ただ、コンピュータ上の乱数は、パッと見では乱数に見えますが、真の乱数ではありませんので、疑似乱数と呼ばれています。

ふと思いましたが、「乱れた数」があるなら、「みだらな数」「淫数」もあるのでしょうか? 例えば、隠しコマンドを入れると残機数が「69機」になるとか…。うむ。これは「淫数」な気がする。…どうでもいいか。

Q. 疑似乱数ってゲームのどこで使われてるの? :

A. 思いつくのは…。以下のような場面で使われたりします。
  • 敵の動きや、発生位置を、乱数を使って決めてたり。
  • 爆発等のエフェクト種類や、初期位置、速度を、乱数を使って決めてたり。
  • サイコロを振る時に使ったり。
  • じゃんけんする時に使ったり。
  • カードやマージャン牌を、かき混ぜる時に使ったり。(でも、実は…ちゃんとかき混ぜてないんですけどね…)
まあ、ゲームによって、色々です。

Q. ゲームに使う疑似乱数って、何を使ってもいいの? :

A. 個人的な印象ですけど、疑似乱数をゲームに使う場合、以下の3つの条件は満たしてないとダメかなあ、と思ってます。まあ、作るゲームにもよりますけど。
  • 処理時間が短いこと。
  • 再現性があること。(疑似乱数の種が初期化できること)
  • 妙な周期性がないこと。

処理時間は…。乱数一つゲットするのに、何フレームもかかってたら、ゲームになりませんよね。ですので、とにかく一瞬で得られること。この条件は、絶対に外せません。

再現性は…。「初期化してから使えば、毎回、同じ並びの乱数が得られるか?」ということですね。プログラミング言語によっては、疑似乱数の初期化メソッドがそもそも存在しないものもありまして。その場合、当然再現性なんか期待できませんから、乱数生成器を自作することになります。

周期性は…。「似たような乱数の並びが繰り返し出てきちゃったりしないか?」ということです。

Q. 疑似乱数の再現性って、大事なの? :

A. ゲームの仕様によりますが、ほとんどの場合は、大事だと思います。

例えば。昔風の2Dゲームにおいて、乱数の再現性は、リプレイ機能、デモプレイ画面を作る時に、とても重要です。敵が、再現性のない乱数を使って動いていたら、その画面に入るたびに、全然違う動きになるわけで…。
  • 誰も居ない虚無の空間を、気でも触れたかのごとく、執拗に撃ち続けるプレイヤーキャラ。
  • そんな異常状態をスルーして、プレイヤーキャラを容赦なく殺害する、一介の雑魚敵達。
  • あっという間に残機ゼロ。わずか数秒で、デモプレイ画面終了。
  • 「…アレ? 今、一瞬、デモプレイ画面っぽいものが映ったような…気のせい?」
乱数の再現性が無いばかりに、画面の中は、そりゃもう大惨事さ! …まあ、昔のゲーセンでは、そんな大惨事のデモプレイ画面を、たまーに目にしましたが。見ていて胸が痛んだものです。 *1 *2

難易度調整や、バグチェックをする際にも、乱数の再現性が無いと苦労します。
  • プレイするたびに難易度がガラリと変わってしまう。(そこまで乱数に頼った作りをしちゃってる時点で大問題、という話も…)
  • プレイヤーキャラのワーク(変数)をいくら整えても、敵が同じ動きをしてくれなくて、最悪、何度やってもバグが再現できない。
これは地獄です…。今日も泊まり込み…。椅子寝かな…。体が臭い…。風呂入りたい…。

つまり、風呂に入れる生活をしたいなら、乱数の再現性は重要なのですね。…や、コレ、冗談めかして書いてるけど、結構マジで死活問題で。

まあ、別に乱数に限った話でもなくて。「動かすたびに全然違う結果が出てくるプログラム」では、えてして大惨事になりますので、コンピュータの世界では、再現性は重要なのですが。

Q. 疑似乱数の周期性って、あったらマズイの? :

A. ゲームによっては、致命的ですね…。製品回収にすらなってしまう場合も。以下の記事が参考になるかと。

_「カルドセプトサーガ」にダイス目が偶数と奇数を繰り返すバグ | スラッシュドット・ジャパン
_カルドセプトサーガの乱数問題 | ψ(プサイ)の興味関心空間

サイコロの目が、偶数→奇数→偶数→奇数と出てくる周期性が ―― つまり、乱数の最下位ビットが、必ず 0→1→0→1 を繰り返す、という話で…。次に出てくるサイコロの目が、そこそこ予想できちゃうのは、ちょっと厳しいですね。

もっともこのあたり、サイコロを使うゲームだから問題になったのであって、シューティングゲームやアクションゲームでは、あまり関係ないんじゃないか、という気もしますけど。でも、どうせなら、妙な周期性がないほうが、安心して使えますよね。

Q. DXRuby で使える疑似乱数って、何があるの? :

A. DXRuby は Ruby のライブラリですから…。Ruby が標準で持ってる疑似乱数を使うのが一般的でしょう。

調べてみたら、以下の2つの書き方があると知りました。
srand(整数) # 疑似乱数を初期化する(種を設定する)

rand(整数) # 0〜(整数-1)の範囲で、疑似乱数を得る。


※ 以下は、Ruby 1.8.7 では使えない。

r = Random.new(整数) # 疑似乱数を初期化する(種を設定する)

r.rand(整数) # 0〜(整数-1)の範囲で、疑似乱数を得る。
  • 整数を指定する場合は、rand() も Random#rand() も同じ処理をするらしいです。
  • 浮動小数点数(float)を指定する場合もありますが、今回はゲームに使えるかどうかで考えてますので、とりあえず整数の乱数が得られれば、なんとかなるかなと。
  • Random クラスは、Ruby 1.8.7 では使えません。ただ、Ruby 1.8.7 は、2013/06末でサポートが打ち切られましたので、これから使う人は居ないでしょうし、気にしなくていいかも?
自分は Ruby 初心者なので、このあたり自信ありませんで。間違ってたらツッコミ入れといてくださいです。

Q. じゃあ、Rubyの rand() を使えばいいんだね? :

A. さて、どうなんでしょうね…。自分が気になっていたのは、このあたりで。

上にも書きましたが。
  • 処理時間が短いこと。
  • 再現性があること。(疑似乱数の種が初期化できること)
  • 妙な周期性がないこと。
この条件を満たしていれば、安心して使える疑似乱数だろうと思います。加えて、
  • Rubyのバージョンによって、違う乱数が出てこないか。
  • rand() と Random#rand() で、処理時間が大きく違ったりしないか。
このあたりも、気になるところ。作ったゲームを Ruby 1.9.3 上で動かす分には遊べるのに、Ruby 2.0.0 になったら乱数の並びが変わっちゃって難易度ハネ上がった、なんて展開は困ります。

実はそのあたり、Rubyのドキュメントに、答えは掲載されているのですが…。

_class Random

でも、ホント? ホントにそうなの? ここがもし間違ってると、後で泣くのはこっちだぜ?

そんなわけで、一応自分の手元でも検証してみることにしたのでした。

再現性についての検証。 :

まずは再現性について、ざっくり検証してみます。

検証に使ったスクリプトソースとその結果は、随分と長くなってしまったので、この記事の一番最後に載せておきますね。

また、使った環境は、以下の通りです。
  • CPU : Intel Core i5 2500 (3.3GHz)
  • Windows7 x64
  • Ruby 1.8.7 mswin32版
  • Ruby 1.8.7 mingw32版
  • Ruby 1.9.3 mingw32版
  • Ruby 2.0.0 mingw32版

さて、検証結果ですが。
  • 再現性はある。
  • 少なくとも、Ruby 1.8.7、Ruby 1.9.3、Ruby 2.0.0 は、同じ乱数が得られる。
  • rand(整数) と Random#rand(整数) は、同じ乱数が得られる。
  • rand(整数) と Random#rand(整数) の実行時間は、どちらもほとんど同じ。
  • 処理時間も…まあ、おそらく、大丈夫そう。乱数を得る際に、めっちゃ時間がかかってるようには見えません。
良かった良かった。ここまでは、一安心。

余談ですが、ついでに以下のことも分かりました。
  • Ruby はバージョンが上がると、グングン処理速度が速くなってる。
  • mswin32版より、mingw32版のほうが、処理速度は速い。かもしれない。(Ruby 1.8.7しか検証してないので、Ruby 1.9以降は、違ってるかも?)

周期性について検証。 :

周期性も確認しておきましょう。

とりあえず、某ゲームの乱数と同様に、乱数の最下位ビットが、0→1→0→1 を繰り返してないか、画像にして眺めてみましょうか。ついでに、乱数の種も変えてみて、同じ状態が続かないか確認してしまいましょう。

ちなみに、画像生成には、DXRuby を使ってます。
# 乱数の最下位ビットを画面に描画してみる

require 'dxruby'

Window.resize(160,120)

# 画像を新規作成
img = Image.new(Window.width, Window.height)

# 乱数初期化の種
lst = [
       [0, 4, 8, 12, 1, 5, 9, 13, 2, 6, 10, 14, 3, 7, 11, 15],
       [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]
      ]

# 乱数初期化の種を変えながら、画像に、乱数の最下位ビットを点として打つ
y = 0
lst.each do |dt|
  dt.each do |i|
    srand(i) # 乱数初期化
    puts "srand(#{i})"
    Window.width.times do |k|
      img[k, y] = ((rand(65536) & 0x01) == 0)? C_BLACK : C_WHITE
    end
    y += 1
  end
  y += 16
end

# 画像をファイル保存
img.save("rand_result.png", FORMAT_PNG)

Window.loop do
  break if Input.keyPush?(K_ESCAPE)
  Window.draw(0, 0, img) # 画面に描画
end

結果画像は以下になりました。見づらいので4倍に拡大してあります。
最下位ビットの検証画像

0→1→0→1 の周期性があれば、綺麗な市松模様が出てくるはずですが…そうは見えませんね。どうやら、最下位ビットが妙な周期性を持ってるわけではなさそうです。

だけど、まだ不安なので、乱数を使ってひたすらドットを打ってみます。

「そんな検証をして意味あるの?」と言われそうですが、意味がある時もあったりします。と言うのも、以前、自分で乱数生成器を作った際、こういった感じの検証をしたら、整然と並んだ綺麗な模様が出現しまして。それってつまり、妙な周期性があるということで…。

まあ、その時は、ビットシフトして下位ビットを捨ててみたら、乱数っぽい状態になってくれたので、それでお茶濁ししてしまったのですけど。疑似乱数を作るアルゴリズムによっては、下位ビットが妙な周期性を持つ場合も多く、そんな時は、ビットシフトして下位ビットを捨ててしまう手も使われるのだそうです。もちろん、上位ビット分にも周期性がないか、検証する作業が必要になりますが。
# 乱数でドットを打ってみる

require 'dxruby'

# 画像を新規作成
img = Image.new(Window.width, Window.height, C_BLACK)

srand(1)
Window.height.times do |y|
	Window.width.times do |x|
		c = rand(256)
		img[x, y] = [c, c, c]
	end
end

# 画像をファイル保存
img.save("rand_result2.png", FORMAT_PNG)

Window.loop do
  break if Input.keyPush?(K_ESCAPE)
  Window.draw(0, 0, img) # 画面に描画
end
ランダムにドットを打ってみた画像

整然と並んだ綺麗な模様は、別に出てきていませんよね…。どうやら大丈夫そうかな…。たぶん…。

Q. 結論としてどうなの? Ruby の乱数はゲーム制作に使えるの? :

A. 少なくとも、現時点では、安心して使えそうです。ただし、各シーンの、キリのいいタイミングで ―― 例えばステージ開始時の初期化処理中に、疑似乱数の種を初期化する、等をしてから使うことを忘れずに。

もっとも、コレ、ドキュメントに書いてある通りになっただけ、なんですけど…。まあ、自分で検証してその通りになりましたから、「よしっ! バッチグー!」ということで。

Ruby のバージョンが変わったら、また検証してみたほうがいいのかもしれません。もっとも、Ruby 1.8、1.9、2.0 と、結果は同じでしたから、今後も再現性は保証されるのではないかと予想しますけど。

そもそもゲームに乱数なんか使わないよ、という話。 :

ここまで、「ゲームに乱数を使う」という前提で話をしましたが。

実は、「ゲーム制作に乱数を使うべきではない」という主張もあります。以下の記事を読んでいただければ分かるかと。

_ゲーム作るのにまだ乱数使ってるの? - 2010-02-05 - ABAの日誌

要するに、「完璧なゲームデザインができているなら、乱数が入り込む隙など無いはずだ」という主張ですね。それはたしかに、そうかもしれない。自分も少し心当たりがあります。アクションゲームの類でも、敵の動きや、発生テーブルを作り込んでいくと、乱数を使う箇所がどんどん減っていく気がしますね…。 *3

とは言え。件の記事でも言及されていますが…。
  • プロトタイプをサクッと作ってる時に、なんとなく敵がそれっぽく動いてるようにしたいとか。
  • プレイヤーの必勝パターンができてしまうのを軽く防止したいとか。
等々、乱数使用が有効な場面もありますので、「絶対に乱数を使わないぞ!」と意固地になる必要もないだろうと自分は思います…。

DXRubyはゲーム制作以外にも使えますよ、という話。 :

上の方で、DXRubyを使って、検証結果を画像化したのですが。

DXRubyを使って、こういうことができるという点も、実は大事じゃないかと個人的には思っているのです。

「ゲーム制作ライブラリ」と銘打たれていると、「ゲーム制作? 俺には関係ないや」とスルーする方も多いと想像するのですが。それはおそらく早計で。

「ゲーム制作に使えるぐらいだから、こういうことだって軽くできちゃうはずだよな?」と思い直すことができれば、意外なところで、ソレを使って楽ができる…。そんな場面もあるだろうなと。

そして、それは、おそらく逆も成り立つのだろうと。「ゲーム制作には関係ないや」と思い込んでた、プログラミング言語やライブラリが、ゲーム制作を楽にしてくれる時だってあるはずだと。

そもそも、Rubyの作者様だって、Rubyを使って、グリグリ動くリアルタイムゲームが作れるなんて、夢にも思ってなかったはずですから…。DXRubyの存在自体が、「その発想は無かったわ」的事例の一つ、かもしれませんよね。

つまるところ、この記事は、検証作業に DXRuby を軽く使ってみることで、

「○○用と謳われていても、○○にしか使えないというわけじゃない」
「目の前の道具を、柔軟性を持って捉えることも、プログラマーには必要」
「そんな姿勢を心掛けていれば、いつかどこかで、その道具が自分に楽をさせてくれる、かもしれない」

―― そんな考え方を示すための、簡素な事例の一つとして書いてみたつもり、でもあるのでした。まあ、「立っている者は親でも使え」という話に過ぎませんが。

それでは、明日は、あおたくさんの _ゲーム作りました をお楽しみくださいませ。

関連資料。 :

疑似乱数、あるいは、Rubyで扱える乱数についての、解説ページも紹介しておきます。

_良い乱数・悪い乱数
_Ruby の標準乱数生成器とその改善案
_Rubyにおけるrand(乱数)の挙動について - yayuguのにっき

特に、乱数生成器を自分で実装する際には、 _良い乱数・悪い乱数 は必読ではないかなと個人的には思います。ありがたや。

再現性の検証に使ったソースと結果。 :

# 乱数の再現性を確認する

require 'benchmark'

n = 1024 * 1024 * 4 # 乱数を発生させる回数

lst_rand1 = Array.new(n)
lst_rand2 = Array.new(n)
lst_random1 = Array.new(n)
lst_random2 = Array.new(n)

# ベンチマークを取る
Benchmark.bm(14) do |x|

  unless /^1.8/ =~ RUBY_VERSION
    # Ruby 1.8.7 は Random クラスを持たないので
    # 処理をスキップする
    
    # 2回乱数を作ってみて、後で比較する
    r = Random.new(0) # 乱数を初期化
    n.times do |i|
      lst_random1[i] = r.rand(0x7fffffff)
    end
    
    r = Random.new(0) # 乱数を初期化
    n.times do |i|
      lst_random2[i] = r.rand(0x7fffffff)
    end

    tmp = 0
    x.report("random:") {
      n.times { tmp = rand(0x7fffffff) }
    }
    
    x.report("random:") {
      n.times { tmp = rand(0x7fffffff) }
    }
  end
  
  # 2回乱数を作ってみて、後で比較する
  srand(0) # 乱数を初期化
  n.times do |i|
    lst_rand1[i] = rand(0x7fffffff)
  end
  
  srand(0) # 乱数を初期化
  n.times do |i|
    lst_rand2[i] = rand(0x7fffffff)
  end

  tmp = 0
  x.report("rand:") {
    n.times { tmp = rand(0x7fffffff) }
  }

  x.report("rand:") {
    n.times { tmp = rand(0x7fffffff) }
  }

end

# 乱数を記録した配列の並びを比較してみる

if lst_rand1 == lst_rand2
  puts "rand は同じ並びです"
else
  puts "rand の並びは異なります"
end

unless /^1.8/ =~ RUBY_VERSION
  if lst_random1 == lst_random2
    puts "random は同じ並びです"
  else
    puts "random の並びは異なります"
  end

  if lst_rand1 == lst_random1
    puts "rand と random は同じ並びです"
  else
    puts "rand と random の並びは異なります"
  end
end

# バイナリファイルとして出力してみる

fn1 = "result_rand_" + RUBY_VERSION + ".bin"
File.open(fn1, 'w+b') do |file|
  file.write(lst_rand1.pack("N*"))
end

unless /^1.8/ =~ RUBY_VERSION
  fn2 = "result_random_" + RUBY_VERSION + ".bin"
  File.open(fn2, 'w+b') do |file|
    file.write(lst_random1.pack("N*"))
  end
end

結果はこうなりました。
> pik list
  187: ruby 1.8.7 (2010-12-23 patchlevel 330) [i386-mswin32]
  187: ruby 1.8.7 (2012-10-12 patchlevel 371) [i386-mingw32]
  192: ruby 1.9.2p290 (2011-07-09) [i386-mingw32]
* 193: ruby 1.9.3p484 (2013-11-22) [i386-mingw32]
  200: ruby 2.0.0p353 (2013-11-22) [i386-mingw32]

# ----------------------------------------
# Ruby 1.8.7 mswin32版とmingw32版を比較
#
# ※ Ruby 1.8.7 は、2013/06/30にサポート対象外になっている

> pik 187
Select which Ruby you want:
1. 187: ruby 1.8.7 (2012-10-12 patchlevel 371) [i386-mingw32]
2. 187: ruby 1.8.7 (2010-12-23 patchlevel 330) [i386-mswin32]
?  2

> ruby rand1.rb
                    user     system      total        real
rand:           4.305000   0.000000   4.305000 (  4.308247)
rand:           3.838000   0.000000   3.838000 (  3.845220)
rand は同じ並びです

> pik 187
Select which Ruby you want:
1. 187: ruby 1.8.7 (2012-10-12 patchlevel 371) [i386-mingw32]
2. 187: ruby 1.8.7 (2010-12-23 patchlevel 330) [i386-mswin32]
?  1

> ruby rand1.rb
                    user     system      total        real
rand:           3.915000   0.000000   3.915000 (  3.915224)
rand:           3.557000   0.000000   3.557000 (  3.558204)
rand は同じ並びです

# mswin32版よりmingw32版のほうが処理速度は速い

# ----------------------------------------
# Ruby 1.9.7 mingw32版で検証

> pik 193
> ruby rand1.rb
                     user     system      total        real
random:          2.356000   0.000000   2.356000 (  2.353134)
random:          2.356000   0.000000   2.356000 (  2.356135)
rand:            2.465000   0.000000   2.465000 (  2.451140)
rand:            2.449000   0.000000   2.449000 (  2.449140)
rand は同じ並びです
random は同じ並びです
rand と random は同じ並びです

# Ruby 1.8.7 より Ruby 1.9.3 のほうが2倍近く速い

# ----------------------------------------
# Ruby 2.0.0 mingw32版で検証

> pik 200
> ruby rand1.rb
                     user     system      total        real
random:          2.121000   0.000000   2.121000 (  2.114121)
random:          2.122000   0.000000   2.122000 (  2.123121)
rand:            2.246000   0.000000   2.246000 (  2.247129)
rand:            2.278000   0.000000   2.278000 (  2.266129)
rand は同じ並びです
random は同じ並びです
rand と random は同じ並びです

# Ruby 1.9.3 より Ruby 2.0.0 のほうが僅かに速い

# ----------------------------------------
# ファイル保存した乱数列を比較

> fc /b result_rand_1.8.7.bin result_rand_1.9.3.bin
ファイル result_rand_1.8.7.bin と RESULT_RAND_1.9.3.BIN を比較しています
FC: 相違点は検出されませんでした

> fc /b result_rand_1.8.7.bin result_rand_2.0.0.bin
ファイル result_rand_1.8.7.bin と RESULT_RAND_2.0.0.BIN を比較しています
FC: 相違点は検出されませんでした

> fc /b result_rand_1.8.7.bin result_random_1.9.3.bin
ファイル result_rand_1.8.7.bin と RESULT_RANDOM_1.9.3.BIN を比較しています
FC: 相違点は検出されませんでした

> fc /b result_rand_1.8.7.bin result_random_2.0.0.bin
ファイル result_rand_1.8.7.bin と RESULT_RANDOM_2.0.0.BIN を比較しています
FC: 相違点は検出されませんでした

# Ruby 1.8.7、Ruby 1.9.3、Ruby 2.0.0 の結果は同じ
# Kernel.#rand(整数) と Random#rand(整数) の結果は同じ

*1: もっとも、太古のTVゲームは、CPUのリフレッシュカウンタ等を読んで ―― ハードウェアで乱数を作っていたそうで。それでは再現性が得られなかったから、大惨事な画面も、仕方なかったのかもしれません。
*2: これは、60FPSで動作することが保障されてる、昔ながらの2Dゲームの場合の話でして。3Dゲームになると、可変フレームレートになるので、事情が変わってくるはずです。フレーム毎の、プレイヤーのコントローラ操作を再現しても、毎回フレームレートが同じではないため、ゲーム展開にずれが出てきます。ですから、おそらく、座標値や状態を記録して、リプレイやデモプレイを実現している場合が多いのではないかと想像していますが…。
*3: 例えばですが、プレイヤーとの間合い、プレイヤーの位置、プレイヤーの状態をチェックして、自分の動作を決定していく、そういう敵の動かし方もあるわけです。たしか、「ワンダと巨像」は、地面に、巨像の動きを決定するための判定マップを設定して動作を決定してた、という記事を読んだ記憶が…。そういう動かし方なら、乱数が入ってくる箇所も少なくなりそうですよね…。

#2 [game] プレイヤーキャラを斜め床で走らせる時のポーズ問題

最近ちょっと、モヤモヤ考えてしまう問題がありまして。ゲームのプレイヤーキャラを、斜め床の上で走らせる際のポーズって、どういうポーズが適切なのかなあ、と。

昔のTVゲーム機における、「ソニック」「ストライダー飛竜」等は、斜め床の上を走る時に、体が斜めになった…記憶があるのですけど。当時はソレを見て、不自然とは思わなかったのですが。

随分前に、Xbox 360で「ストライダー飛竜」の新作が出るぞー、てな話を見かけまして、興味津々でプレイデモ映像を見たのです。3DCGになった「ストライダー飛竜」、チョーカッコええなと。パーティクル飛ばしまくりやなと。見ていてシビレたのですが。

しかし、そこでも、プレイヤーキャラは、斜め床の上で体が斜めになっていて。「うーむ、不自然だ…」と思ってしまったのです。

件のソレは、3DCGになったから、パッと見はチョーリアルになってるわけですけど。斜め床の上では、見た目をそれほどリアルにできなかった、2Dゲーム時代の文法を踏襲してる。そこに自分はギャップを感じてしまったのでは、と思うのですけど。

さりとて、斜め床の上で、垂直(?)にして走らせるわけにもいかない。件のゲームは、斜め床の上を高速で走っていくシーンもあるわけですよ。そういう場面では、身体が斜めになってるほうが、どう考えてもカッコイイ。そういうシーンを成立させるためには、普段から、「斜め床の上では体が斜めになる」というルールを適用しておかないといかんよなと。

でも、パッと見、やっぱりなんだか不自然で。

たぶんこのあたり、 その違いも絡んでそうな気もしますけど。日本のソレって、歌舞伎みたいなところがあるよなと。リアルであることより、抽象化・デフォルメしたほうがカッコイイ、みたいな。

何にせよ、そんな流れで、「斜め床の上を走らせる時って、どういうポーズがいいんだろう?」と、たまに思い出したようにモヤモヤ考えてしまうのでした。

ちなみに、新作「ストライダー飛竜」は、そんな細かいところがどうでもよくなるぐらいに、全編が超絶カッコイイと思います。ちゃんと売れてほしいなあ…。自分、横スクロールアクションというジャンルが好きなので。

「カリ城」はお手本になりそう。 :

このあたりモヤモヤ考えてると、「ルパン三世 カリオストロの城」の、屋根の上をルパンが走るシーンを思い出すのです。…ここから先は、どなたかが話してたソレの受け売りのような気もしますけど。

あの一連のシーンには、キャラが斜め床の上を走る際の、ありえるポーズの全てが凝縮されてるよなと。それでいて、不自然な映像とは感じない。…いや、もちろん、その後の展開は「ありえねえだろ…」な漫画的展開ですけど。走ってる最中は、不自然ではないよなと。

なので、おそらく「カリ城」に何かヒントがある、ような気がするのです。

とは言っても。ゲームのソレはキャラのポーズが全て連続しているけれど。映画はモンタージュで解決してるところもあるから、そう単純ではないのかな。でも、ちょっとした「ヒント」ぐらいは、混じってる気もするなあ。

速度と絵柄。 :

「カリ城」を思い返すと、問題解決に使えそうな2つの要素がありそうだと思えてきたり。
  • ルパンは、速度に応じて、ポーズが変わってる。ゲームのソレも、速度で各ポーズを繋いでいけないか。
  • 「カリ城」はアニメ。アレが実写だったら、不自然で見ていられない、かもしれない。であれば、ゲームのソレも、リアル方向ではなく、アニメ方向の見た目・絵柄にすれば、印象が変わらないか。
ただ、この2つとも、問題がありそうで。
  • 体を斜めにすべき速度を判定するのって、結構難しそう。速度と体の角度を比例させれば済む、というわけでもないよなと。結局、「ここは斜めに立たせるべき」「ここは垂直に立たせるべき」の判定って、速度程度じゃ足りないだろうと。
  • せっかく3DCG使ってリアルに見せられる時代になったのに、昔の2Dゲームの絵柄に戻してどうするんだと。お客さんの食いつきが悪くならないか。
やってみたら、「あら、これでイケるわ」となるかもしれないけど、「やっぱりコレじゃアレだな」ともなりそうな。

まあ、このあたり、そのうち「カリ城」が再放送されたら、件のシーンをじっくり見直して考えてみよう、と…。これも、自分にとっての宿題・今後の課題ってことで。

#3 [game] 斜め床の上で立ち止まってる時のプレイヤーキャラの足の角度

上の記事を書いたついでに、このあたりの自分の記憶を整理するために、覚えてることを今のうちにとりとめなくメモ。

ファミコン版の「悪魔城ドラキュラ」は、斜め床がそもそも存在せず、階段しかなくて。しかし、階段を昇り降りする時は、一歩一歩踏みしめて、じわじわ動いていくので…。階段の上で立ち止まってる時も、階段の地形にピタリと一致した足の角度で。ファミコン版のくせして(?)、地味にそういうところで、見た目がリアル。

この文法は、PS1版のドラキュラXで破棄されます。斜め床の上をスッタカスッタカと滑るように走る仕様になり、階段も全部、斜め床の扱いになった。そして、斜め床の上でも、ソレ専用のグラフィックは用意してなかった…ような気がします。勘違いしてるかもしれないけど。 *1

「ストライダー飛竜」は、斜め床の上で立ち止まると、床の角度に合わせた足の角度になります。つまり、地形に合わせたソレ専用のグラフィックが、わざわざ用意されていて。…まあ、斜め床の上を歩くと体が斜めになる時点で、「地形に合わせたポーズでなきゃダメなんだ!」てなこだわりが感じられますが。昔のハードで体を斜めにするってことは、体が斜めになってるグラフィックをわざわざ持たなきゃいかんはずで。元がアーケードとは言え、そこまでやるか…。

「魂斗羅」MD版以降も、(ディレクターさんが「ストライダー飛竜」大好き人間だったので)斜め床の上で立ち止まると、ちゃんと斜め床に合わせたグラフィックになります。…SFC版はどうだったか自分の記憶は怪しいのですが、MD版とPS2版はそうだったはず。PS2版を見て、「おお…相変わらず、こだわってる…」と思った記憶が。

「ソニック1」は…斜め床の上で立ち止まっても、普段と同じ立ちポーズだったような? どうでしたっけか。足をピシッと閉じたポーズだから、どんな地形の上でも不自然にならなかった、そんな記憶がありますけど。最初のソレは容量が4Mbitだったから、そういうところでも地味に容量節約してたのかなと想像してみたり。

「マリオ」は…ファミコン版のマリオって、斜め床ありましたっけか? どうだったかな。たしか無かったですよね?

そんな感じで、2D横スクロールアクションゲームにおいて、「斜め床の有無」や「斜め床の上でプレイヤーキャラがどんなグラフィックになってるか」は、ゲームによって色々違っていて。そのあたり、自分の中では、どれが適切なのか、悩んじゃうのでした。

例えば、 _Flixel という2Dゲームライブラリは、地形管理クラスに、斜め床が無いんですけど。おそらく、マリオをイメージしながら作った2Dゲームライブラリは、そうなるんだろうなと。

でも、自分は、横スクロールアクションというと、「ストライダー飛竜」あたりを連想しちゃうので…。「この仕様で足りるの?」とか思っちゃって。でも、「そもそも斜め床って必要なのだろうか?」という疑問も湧いたりもして。

「2Dゲームにおける斜め床とはなんぞや?」てなあたりを、誰か考察してくれないものかしら。「斜め床は必要なのか否か?」「あると、ゲームの何が違ってくるのか?」みたいな。

スマホゲーム全盛のこの時代にそんなの考えてみてもな、というところもありますかね…。
*1: PS1版ドラキュラのメインスタッフは、PCE版ドラキュラのメインスタッフでもありますから、階段をじわじわ昇るソレが実装できないはずはなく。PCE版で既にやってますから、やろうと思えばできたはずで。なので、「このタイトルは斜め床があったほうが面白い」とか「今時、階段をじわじわ昇るのはいかがなものか」とか「マップがとにかく広いから、作業量やプレイ時間を考えたら階段じわじわはキツイ」等の判断をして、あえて文法を破棄したんじゃないのかな、と想像してますけど。

#4 [ruby] Ruby 1.9.3 を再インストールした

irb や pry の動作が怪しいあたりが気になったので、Ruby 1.9.3 p484 を再インストールした。環境は Windows7 x64。

既に入ってる版をアンインストール。 :

コントロールパネルから、アンインストール。以前のインストールフォルダはリネームしてバックアップ。

RubyInstallerをインストール。 :

_RubyInstaller for Windows から、rubyinstaller-1.9.3-p484.exe と DevKit-tdm-32-4.5.2-20111229-1559-sfx.exe をDL。

rubyinstaller-1.9.3-p484.exe を実行してインストール。今回は、C:\ruby193mingw にインストールした。

pik に登録。 :

一旦以前の版をリストから削除して、その後、インストールした版を登録。
pik remove 193
pik add C:\ruby193mingw\bin

pik は、Windows上でRubyの複数のバージョンを使うことができるツール。

DevKitをインストール。 :

  1. DevKit-tdm-32-4.5.2-20111229-1559-sfx.exe を実行して任意のフォルダに解凍。
  2. フォルダに入って、ruby dk.rb init を実行。
  3. config.yml を編集。インストールしたい Ruby の版だけ残して他はコメントアウト。
  4. ruby dk.rb install を実行。

gemをアップデート。 :

gem install rubygems-update
update_rubygems

ruby-debug-base19をインストール。 :

NetBeans 上でデバッガを使えるようにするためにインストール。
  • gem install linecache19
  • ruby-debug-base19-0.11.26.gem をDLしてくる。
  • gem install ruby-debug-base19-0.11.26.gem -- --with-ruby-include=C:\ruby193mingw\include\ruby-1.9.1\ruby-1.9.3-p484
  • gem install ruby-debug-ide19
  • gem install ruby-debug19
C:\ruby193mingw\lib\ruby\gems\1.9.1\gems\ruby-debug-ide19-0.4.12\lib\ruby-debug\xml_printer.rb に以下を追加。
class String
  def is_binary_data?
    ( self.count( "^ -~", "^\r\n" ).fdiv(self.size) > 0.3 || self.index( "\x00" ) ) unless empty?
  end
end

その他のライブラリをインストール。 :

gem install hoge で。

結局 irb や pry はどうなったかというと。 :

やっぱり固まる。なんでや。

Ubuntu Linux 上で試してみた。 :

VMware Player + Ubuntu 13.10 で、Ruby 関係のアレコレを色々インストールして、その上で irb や pry を使ったのだけど。これだと、固まらない。うーん。

ActiveScriptRuby 2.0.0をインストールしてみた。 :

こっちだと irb がするする動く。うむむ。mingw32版が問題なのか、自分がインストールした gem が問題なのか…。

ActiveScriptRuby 2.0.0 上では、pry はインストールしても動かなかった。win32console が無いよと言われる…。gem install win32console をしたら、エラーがたくさん出てきた。

ActiveScriptRuby 1.8.7 もインストールしてある環境なので、そちらでも irb を動かしてみた。コレもするする動く。むむむ。どういうことだろう。

とりあえず、普段 irb を使う場合は、ActiveScriptRuby 版を使うことにしようかな…。

#5 [dxruby] ActiveScriptRuby版は同梱のDXRubyじゃないと動かないのかな

ActiveScriptRuby 2.0.0 版に入ってる DXRuby のバージョンを確認したら ―― irb 上で require 'dxruby' 後に DXRuby::VERSION と打ったら 1.3.7dev と出てきた。結構古い…。

先日公開された、DXRuby 1.5.8dev版をインストールしようとしたら、「msvcrt-ruby200.dll が無いからプログラムを動かせないよ」とエラーダイアログが表示された。

なら、DXRuby 1.4.0 Ruby 2.0対応版はどうだろう。これも、インストールしようとしたら、同じエラーが出た。

どうやら、件の Ruby は、同梱されてる DXRuby じゃないと動かないらしい…。というか、おそらく DXRuby 公式サイトで配布されてるバイナリは、mingw32版でしか動かないのかもしれない。

なんだか環境を色々壊してしまったような気がしてきたので、とりあえず ActiveScriptRuby 2.0.0 版をアンインストールして、また再インストール。

#6 [ruby] Ruby/SDLとruby-openglをインストール

Ruby 1.9.3 p484 mingw32 版上にインストールしようと試みたのだけど、チラチラ問題が。

Rubyforge.orgに繋がらないのですが。 :

Ruby/SDL の Windows用バイナリをDLしようと思ったら、Rubyforge.org に繋がらず。困った。

「Windowsへのインストールは、バイナリを利用するのが楽」と公式サイトのドキュメントには書いてあるけど、そのバイナリが入手できないのでは…。

gem でインストール。 :

gem install rubysdl-mswin32-1.9 でインストールしても、手元のスクリプトが動いてくれず。

あ。「install_rubysdl.bat を実行せよ」とメッセージが表示されてることに、今気がつきました。

実行したら、エラーが出た。
> install_rubysdl.bat

C:/ruby193mingw/lib/ruby/gems/1.9.1/gems/rubysdl-mswin32-1.9-2.1.1.1/dll/install_rubysdl:7:in `<top (required)>': uninitialized
constant Gem::GemPathSearcher (NameError)
        from C:/ruby193mingw/bin/install_rubysdl:23:in `load'
        from C:/ruby193mingw/bin/install_rubysdl:23:in `<main>'
困ったな。

C:\ruby193mingw\lib\ruby\gems\1.9.1\gems\rubysdl-mswin32-1.9-2.1.1.1\ をDOS窓で開いて、ruby install_rubysdl.rb を実行してみたり。インストールできたっぽい。

ただ、このままだと、ruby-opengl と競合するはずだから…。 _2013/05/08の日記 を参考にして、opengl.so をリネームしたり等。

gem install opengl 後、gem install ruby-opengl を実行したら、ruby-opengl (0.61.0) が入ってくれた。

Ruby/SDL も ruby-opengl も動いてるように見える。これで大丈夫そうかな…。

まあ、Ruby/SDL は、Ruby 1.8〜1.9 上でしか動かないんだけど。

Ruby/SDLのドキュメントがグチャグチャ。 :

_File: README ・ Documentation for rubysdl (2.1.3) を眺めたら、ほとんどの文字が「???」になっていて。どういうことだろう…。

#7 [python] PyGameって開発終了してたのか…

_Pygameの後継らしいPySDL2をインストール - ばぐばぐわーるど を見て、PyGame が開発終了してたことを今頃知ったわけで。

_PySDL2 ってのが後継なのか…。入れてみるか…。

む。Python 2.7 か Python 3.2 以降じゃないと動かん、と書いてあるような。自分の環境は、gimp-python を動かす関係で、Python 2.6 がデフォルトなわけで。困った。

_#84 複数バージョンのPythonをインストールする << Python << a wandering wolf によると、バッチファイルを作成することで、複数のPythonを使い分けることもできなくもないらしい。であれば、試せるかな…。

PySDL2 のドキュメントを読むと、PyPy なるものも必要、というか、PyPyでも動かせる、と書いてあるように見える。名前だけは見かけてたけど、それもインストールしてみるか…。

PyPyをインストール。 :

PyPy というのは… Python が爆速になったもの、らしい。よく分からないけど。

とりあえずインストール。環境は Windows7 x64。

_PyPy - Download and install から、pypy-2.2.1-win32.zip をDLしてきた。解凍して、任意のフォルダにおいておく。

環境変数PATHが通ってるフォルダの中に、pypy.bat というバッチファイルを作ることにした。中身は以下のような感じ。
@echo off
C:\pypy\pypy.exe %1 %2 %3 %4 %5 %6 %7 %8 %9
とりあえず、DOS窓で、pypy と打ってみた。…なんだか python.exe を実行した時と同じ画面になった。exit() で終了。

_PyPyを試してみた @ Project Euler Problem 92 - matsulibの日記 で紹介されてるスクリプトを実行してみた。

うわ。Python 2.6 だとめちゃくちゃ待たされるのに、PyPy だとあっという間に処理が終わった。これはたしかにスゴイ…。

さておき、次は何をすれば…?

setuptools と pip をインストール。 :

なんだかよく分からないけど、setuptools と pip なるものが必要らしい。

_WindowsにPythonのツール: setuptools(easy_install), pipをインストールする | ユニキャストラボ を参考に作業。 _setuptools 2.0.1 : Python Package Index から、ez_setup.py なるファイルをDLして、
python ez_setup.py
を実行。なんか色々入った。これが setuptools だか easy_install だかなのだろうか。

easy_install pip
を実行。またなんか色々入った。これで pip がインストールされたのかな?

Python 2.6 でやったこの流れを、Python 2.7, 3.2 でも実行。環境変数PATHを書き換えて、その都度行ってみたり。

Python 2.7 と 3.2 をアップデートしたら面倒なことに。 :

Python 2.7 と 3.2 の新しい版があったので、ついでにアップデート。

やっかいなことになった。各Python をインストールしてたフォルダは、シンボリックリンクを使って、Cドライブにあるように見えながら実体はDドライブに置いていたのだけど。インストーラが、フォルダを削除、再作成をしたようで、CとDの両方に Python がある状態に。もうグチャグチャだー。

面倒臭くなったので、全部アンインストールして、もう一度再インストールすることに。モジュールの再インストール作業を考えると、気が重い。

ez_setup.pyがエラーを出す。 :

_Issue 9291: mimetypes initialization fails on Windows because of non-Latin characters in registry - Python tracker に書いてある症状と同じ。

_2013/12/19 Python-2.7.6がWindows環境でmimetypes.init()に失敗する場合がありsetuptoolsがインストールできない話 - 清水川Web に書いてあった状態になってた。レジストリの HKEY_CLASES_ROOT 以下に、日本語文字列のキーが…。
Windows Registry Editor Version 5.00

[HKEY_CLASSES_ROOT\カート]
@="カート"

[HKEY_CLASSES_ROOT\カート\DefaultIcon]
@="C:\\Program Files (x86)\\FUJIFILM\\MyFinePix Studio\\MyFinePixStudio.exe,0"

[HKEY_CLASSES_ROOT\カート\shell]

[HKEY_CLASSES_ROOT\カート\shell\open]

[HKEY_CLASSES_ROOT\カート\shell\open\command]
@="C:\\Program Files (x86)\\FUJIFILM\\MyFinePix Studio\\MyFinePixStudio.exe \"%1\""

Windows Registry Editor Version 5.00

[HKEY_CLASSES_ROOT\フォトブックファイル]
@="フォトブックファイル"

[HKEY_CLASSES_ROOT\フォトブックファイル\DefaultIcon]
@="C:\\Program Files (x86)\\FUJIFILM\\MyFinePix Studio\\MyFinePixStudio.exe,0"

[HKEY_CLASSES_ROOT\フォトブックファイル\shell]

[HKEY_CLASSES_ROOT\フォトブックファイル\shell\open]

[HKEY_CLASSES_ROOT\フォトブックファイル\shell\open\command]
@="C:\\Program Files (x86)\\FUJIFILM\\MyFinePix Studio\\MyFinePixStudio.exe \"%1\""

FUJIFILM製デジカメに付属してきたソフトをインストールしたときに作られてしまったものと思われます。

が、しかし、該当キーをバックアップ後削除してみても、やっぱりエラーが出る。うーん。

python-2.7.5.msi を _Python 2.7.5 Release からDLして上書きインストールしてみた。これならエラーが出ない、けど、動作が怪しくなりそうな。モジュールも含めて全てアンインストールして、Python 2.7.5 を再インストールすることに。助けて。

とりあえず PySDL2 をインストール。 :

PySDL2 も、 _Pygameの後継らしいPySDL2をインストール - ばぐばぐわーるど を参考に、インストールしてみた。

_Installing PySDL2 ・ PySDL2 0.7.0 documentation によると、SDL2 の他に、SDL2_image、SDL2_mixer、SDL2_ttf、SDL2_gfx もインストールしないといけないらしい。しかし、SDL2_gfx だけは、ソースのみの公開で。Windows用のバイナリは無いのかな…。ググってみても、「この SDL gfx ってバイナリがないぞ…」みたいな話しか出てこなくて。

とりあえず、SDL2_gfx 以外は全部入れてみた。 _Integrating PySDL2 ・ PySDL2 0.7.0 documentation に従って、環境変数 PYSDL2_DLL_PATH に、SDL2 関係の .dll が入ったフォルダを設定しておく。

おお。たしかにサンプルが動いた。と思ったけれど、DOS窓に、「今、ソフトウェアでレンダリングしてるよ」とメッセージが表示されてる。

ソフトウェアでレンダリングするのでは、PyGame と変わらず、描画が遅いのではあるまいか…。設定でどうにかできるのかもしれないけど、デフォルトでソフトウェア描画されてしまう仕様では、他の環境に持っていって動かしたときに、一々設定してもらう羽目になりそう。とは言え、最初からハードウェアを使って描画する設定だと、環境によってはそもそも起動しないとか、OSが落ちるとかありそうだし。

PySDL2 になったことで、ソースの書き方も、全然 Python らしくないノリになってるし。サンプルソースを見て萎えた人の気持ちも分かる。

現段階では、ちょっとビミョーなライブラリだなと思えてきたり。でも、もちろん、今後に期待。

GIMP 2.6 がおかしい。 :

Python 2.6.6 をインストールしたはずなので、GIMP 2.6 上で Pythonスクリプトが動くはず、と思ったのだけど、これが動かない。うーん。

2013/12/20(金) [n年前の日記]

#1 [windows] CubePDF Utilityが便利

_CubePDF Utility - 窓の杜ライブラリ

pdf を回転させる作業が必要になったのだけど、このソフトを使わせてもらって解決。助かりました。ありがたや。昔は pdf なんてほとんど変更・修正できなかったのに。イイ時代になった…。

だけどコレ、複数ファイルを一気に回転、等はできないのだな…。そういうソフトもどこかにあるんだろうか。

_PDFを回転させて保存するには|単なる会社だけの人生で終わらせないためのフジロッカーなリーマンのブログ 経由で、 _RotPDF というソフトがあることを知った。複数ファイルをD&Dすれば、一括して回転してくれるらしい。ありがたや。

#2 [cg_tools] GIMPを再インストール

昨日 Python 関係をごっそり再インストールした際に、GIMP 2.6.x の Pyhon-fu が動かなくなってしまったので、GIMP を再インストール。環境は Windows7 x64。

GIMP 2.6.12 と GIMP 2.8.10 を共存させたいのだけど、GIMP 2.6 インストール後に GIMP 2.8 をインストールすると、前バージョンが強制的にアンインストールされてしまう、という仕様だったはずなので…。今回は、GIMP 2.6.12 は通常のセットアップ版を使い、GIMP 2.8.10 は Portable 版を使うことにしてみたり。

GIMP 2.6.12 Windows版は、 _Index of /pub/graphics/gimp/v2.6/windows からDL…したと思う。

GIMP Portable 2.8.10 は、 _GIMP Portable | PortableApps.com からDL。

GIMP Portable 2.8.10 の設定。 :

GIMP 2.8.10 Portable 版は、そのままだと英語表記になってしまうので、 _GIMP質問掲示板 GIMP2.8.10 中で紹介されてる手順で日本語表示に設定。
GIMPPortable2.8.10がリリースされました。
http://portableapps.com/apps/graphics_pictures/gimp_portable
相変わらずシステム言語が効かず英語表示になります。
起動してメニューから言語を変更して下さい。
Edit > Preferences > 左の項目からInterface
> 右のLanguageの項目をSystem LanguageからJapanese[ja]に変更 > OK
GIMP再起動

GIMP質問掲示板 より


メニュー表示フォントの見た目がなんだかおかしいので、gtkrc ファイルを編集して変更。
インストールフォルダ\App\gimp\share\gimp\2.0\themes\Default\gtkrc
インストールフォルダ\App\gimp\share\gimp\2.0\themes\Small\gtkrc
インストールフォルダ\Data\.gimp\gtkrc
のあたりをエディタで開いて、
style "gimp-default-style"
{
  font_name = "Meiryo UI 9"
style "gimp-display-style" = "gimp-default-style"
{
  font_name = "Meiryo UI 9"
といった感じに、font_name = "Meiryo UI 9" を挿入。もちろん、好きなフォント種類、フォントサイズを指定すればいいのですが。

以前は pango.aliases なるファイルも設定してたらしいのだけど…。これはどこに置けばいいんだろう? とりあえず、
インストールフォルダ\App\gimp\etc\pango\pango.aliases
に置いてみたけど…。反映されてるのかどうか、よく分からず。

ブラシやパレット等は、GIMP 2.6 のものを流用したいので、環境設定のフォルダ設定で、GIMP 2.6 のソレを追加設定。

GAPもインストール。 :

GAP は、GIMP でアニメーションが作れるようになるプラグイン集。

_GAP-2.6 for Gimp 2.6-Windows by photocomix-resources on deviantART の右上のDownloadをクリックして、GAP_2_6_for_Gimp_2_6_Windows_by_photocomix_resources.zip をDL、解凍。

Gimp-GAP-2.6.0-Setup2.exe を実行すれば、GIMP 2.6 にインストールできる。

解凍フォルダには、スクリプトも入ってるので…。ただ、これは、GAPが無いと動かないかもしれないので、別フォルダにまとめて入れといて、GIMPの設定でフォルダを追加したほうがいいかもしれない。

#3 [windows][emacs] NTEmacsを23.4から24.3に変更してみたり

_NTEmacsでshell、eshellの標準入力は出来ない? - kumar8600の日記 という記事を目にして、もしかすると先日 NTEmacs 上で Ruby デバッガが動いてくれなかったのはコレかなと思えてきて。別の NTEmacs でも同じ状態になるのかどうかが気になってきたので、常用してるソレを変えてみようかと。

今まで使っていたのは、NTEmacs 23.4。

_OOTA's page
_GNU emacs windows(x64)バイナリパッケージ : Vector

差し替えるのは、NTEmacs 24.3。

_NTEmacs

環境変数 HOME を指定してある環境なので、~/.emacs を読んでくれたのだけど。色々エラーが出るようで。

とりあえず、~/.emacs 内では、こんな感じに条件分岐を。
(defvar run-unix (or (equal system-type 'gnu/linux) (equal system-type 'usg-unix-v)))
(defvar run-w32 (and (null run-unix) (or (equal system-type 'windows-nt) (equal system-type 'ms-dos))))
(defvar run-ntemacs (equal system-type 'windows-nt))
(defvar run-emacs20 (and (equal emacs-major-version 20) (null (featurep 'xemacs))))
(defvar run-emacs21 (and (equal emacs-major-version 21) (null (featurep 'xemacs))))
(defvar run-emacs22 (and (equal emacs-major-version 22) (null (featurep 'xemacs))))
(defvar run-emacs23 (and (equal emacs-major-version 23) (null (featurep 'xemacs))))
(defvar run-emacs24 (and (equal emacs-major-version 24) (null (featurep 'xemacs))))
(defvar run-meadow (featurep 'meadow))
(defvar run-meadow1 (and run-meadow run-emacs20))
(defvar run-meadow2 (and run-meadow run-emacs21))
(defvar run-meadow3 (and run-meadow run-emacs22))
(defvar run-ntemacs22 (and run-ntemacs run-emacs22))
(defvar run-ntemacs23 (and run-ntemacs run-emacs23))
(defvar run-ntemacs24 (and run-ntemacs run-emacs24))
(defvar run-xemacs (featurep 'xemacs))
(defvar run-xemacs-no-mule (and run-xemacs (not (featurep 'mule))))
(cond
 (run-ntemacs24 (load "~/.ntemacs24"))
 (run-ntemacs23 (load "~/.ntemacs23"))
 (run-ntemacs22 (load "~/.ntemacs22"))
 (run-meadow3 (load "~/.meadow"))
 (run-emacs23 (load "~/.emacs23"))
 (run-emacs22 (load "~/.emacs22"))
 (run-emacs21 (load "~/.emacs21"))
 )

よく分かってないけど、環境変数もちょっと変更。
GNUCLIENTW=-F
GNUDOITW=-F
RUNEMACS=C:\Program Files\GNU\Emacs23\bin\runemacs.exe
RUNEMACS に、使いたい runemacs.exe のパスを指定。おそらく自分の環境は、 _gnuserv を入れてるらしい。たぶん。Meadow を使ってた頃に入れたのではないかと。一般的には emacsclientw.exe を使うのかなと思うのだけどどうなんだろう。

Windows7 のタスクバーに、アイコンが2つ表示されてしまう。 :

runemacs.exe と emacs.exe が別扱いされてしまうのでそうなるらしい。

_NINE GENERATIONS: Emacs (NTEmacs) 23.1 をWindows 7上で少し快適に使う - Part.2
_でらうま倶楽部 : Windows7 (x64) 痒いところに手を届けるカスタマイズ

AppID なるものを弄れば解決できるそうで。

_win7appid - Windows 7 Shortcut Application Id Tool - Google Project Hosting から、Win7AppId1.1.exe をDLさせてもらって、runemacs.exe のショートカットファイル(.lnk)を作成して。DOS窓で、
Win7AppId1.1.exe hoge.lnk GNU.Emacs
を実行。そのショートカットファイルを、タスクバーに表示すればいいらしい。

migemoが働かない。 :

emacs は C-s を叩いて検索する時に日本語入力ができないので、migemoとやらを使ってローマ字入力するだけで検索できるように、と思ったのだけど。これがさっぱり動作せず。

2時間ぐらいアレコレ試して、ようやく動くように…なったかもしれないので今のうちにメモ。

C/Migemo は、 _C/Migemo - KaoriYa から、cmigemo-default-win32-20110227.zip をDLさせてもらったり。解凍して、cmigemo.exe、migemo.dll を、emacs.exe と同じフォルダにコピー。dictフォルダを、~/.emacs.d/ 以下にコピー。

DOS窓上で、cmigemo.exe が動作するか確認する。ヘルプを表示すると、辞書ファイルは -d オプションで指定する、とあるので…。
C:\Prog\emacs24_3\bin>cmigemo.exe --help
cmigemo - C/Migemo Library 1.3 Driver

USAGE: cmigemo.exe [OPTIONS]

OPTIONS:
  -d --dict <dict>      Use a file <dict> for dictionary.
  -s --subdict <dict>   Sub dictionary files. (MAX 8 times)
  -q --quiet            Show no message except results.
  -v --vim              Use vim style regexp.
  -e --emacs            Use emacs style regexp.
  -n --nonewline        Don't use newline match.
  -w --word <word>      Expand a <word> and soon exit.
  -h --help             Show this message.

とりあえず cp932 のほうの辞書を渡してみる。最後が必ず migemo-dict になるはず。フォルダを指定するものかと思い込んで、ずっとハマってた。migemo-dict というファイルを指定しないといかんのね…。
C:\Prog\emacs24_3\bin>cmigemo.exe -d C:\home\mieki256\.emacs.d\dict\cp932\migemo-dict
migemo_open("C:\home\mieki256\.emacs.d\dict\cp932\migemo-dict")=00507B38
clock()=0.101000
QUERY: migi
PATTERN: ([砌汀頻⇒』】)右→>」]|ミギ|ミギ|水際|身綺麗|御教書|みぎ|migi|migi)
QUERY:
^C
とりあえず「migi」と打ち込んで Enter を叩いたら、それらしい文字列が表示されたので、C-c を叩いて強制終了させる。

migemo.el を入手しないといけない。MELPA とやらに登録されてるらしいので、M-x list-packages で一覧を表示。C-s migemo と打てば、migemo が見つかるはず…。「migemo」の上で Enter を押して、「install」を選んだらインストールできたっぽい。

~/.emacs、というか ~/.ntemacs24 に、以下を記述。
;; ----------------------------------------
;; MIGEMO
(when (and (executable-find "cmigemo")
           (require 'migemo nil t))
  (setq migemo-command "cmigemo")
  (setq migemo-options '("-q" "--emacs" "-i" "\g"))
  ;; (setq migemo-options '("-q" "--emacs" "-i" "\a"))
  ;; (setq migemo-options '("-q" "--emacs"))

  ;; migemo-dict のパスを指定
  ;; (setq migemo-dictionary "C~/.emacs.d/migemo-dict/utf-8")
  (setq migemo-dictionary (expand-file-name "~/.emacs.d/dict/utf-8/migemo-dict"))
  (setq migemo-user-dictionary nil)
  (setq migemo-regex-dictionary nil)
  
  ;; 辞書の文字コードを指定.
  (setq migemo-coding-system 'utf-8-unix)
  ;; (setq migemo-coding-system 'euc-jp-unix)
  
  ;; キャッシュ機能を利用する
  (setq migemo-use-pattern-alist t)
  (setq migemo-use-frequent-pattern-alist t)
  (setq migemo-pattern-alist-length 1024)

  (load-library "migemo")
  
  ;; 起動時に初期化も行う
  (migemo-init)

  ;; emacs 24.3 で C-s を働かせるための設定
  (setq search-whitespace-regexp nil)
  
  ;; (eval-after-load "migemo"
  ;;   '(defadvice isearch-search (around migemo-search-ad activate)
  ;; 	 "adviced by migemo."
  ;; 	 (let ((saved-isearch-lax-whitespace isearch-lax-whitespace))
  ;; 	   (when migemo-isearch-enable-p
  ;; 		 (setq migemo-do-isearch t)
  ;; 		 (setq isearch-lax-whitespace nil))
  ;; 	   (unwind-protect
  ;; 		   ad-do-it
  ;; 		 (setq migemo-do-isearch nil)
  ;; 		 (setq isearch-lax-whitespace saved-isearch-lax-whitespace))))
  ;;   )
  
  ;; 起動時に off にする
  ;; (setq migemo-isearch-enable-p nil)
)
  • (executable-find "cmigemo") の部分で、cmigemo.exe が見つかったら設定有効になるようにしてるらしい。
  • (setq migemo-command "cmigemo") で、cmigemo.exe を指定してる。
  • (setq migemo-options '("-q" "--emacs" "-i" "\g")) は、migemo.el の中に記述されてたソレをそのまま真似た。
  • (setq migemo-dictionary (expand-file-name "~/.emacs.d/dict/utf-8/migemo-dict")) で、辞書ファイル migemo-dict の場所を指定。今回は utf-8 の辞書を指定、してるのだと思う。
  • (setq migemo-coding-system 'utf-8-unix) で、文字コードを指定するらしい。

万が一のために、ミニバッファ上で日本語入力できるように設定もしておく。
;; ----------------------------------------
;; ミニバッファで日本語入力可にする
;; NTEmacs 23.3.92以降で有効、らしい

(defun w32-isearch-update ()
  (interactive)
  (isearch-update))
(define-key isearch-mode-map [compend] 'w32-isearch-update)
(define-key isearch-mode-map [kanji] 'isearch-toggle-input-method)

(add-hook 'isearch-mode-hook
          (lambda () (setq w32-ime-composition-window (minibuffer-window))))
(add-hook 'isearch-mode-end-hook
          (lambda () (setq w32-ime-composition-window nil)))

rubydbはやっぱり動かず。 :

M-x rubydb が動くかどうか確認してみたけど、やっぱり入力ができなくて。

M-x eshell も、M-x shell も、動いてるように見えるのだけど…。いや、標準入力とやらが正常に動いてるかどうかの確認方法が思いつかないので、動いてるように見えても一部色々と動いてないのかもしれないけど。

2013/12/21() [n年前の日記]

#1 [ruby] YARDを使ってみた

YARDてのは、Rubyのスクリプトソースの中に、ある決まったフォーマットでコメントを書いておくと、そこからドキュメントを作ってくれるツール、という認識でいいのかしら。
yardoc hoge.rb
てな形で実行すると、doc/ フォルダを作ってその中にhtmlでドキュメントを生成してくれる模様。

それらしいドキュメントを出力してくれた。ありがたや。しかし、一部書き方が分からないところが。 ググってみても、そのあたりを解説してあるページには辿り着けず。

#2 [dxruby][game] 地形アタリの実験中

DXRuby + tmx で地形アタリ処理の実験中。

タイル毎の補正値を得るところまではできたのだけど、問題発生。上から下までずっと床タイルが並んでる場所で床補正をしていくと、無限ループに陥ってしまう…。上に補正する → そこにも床タイルがある → 上に補正する → 床タイルがある、を繰り返すから当たり前なんだけど。補正する回数制限をつけとかないとあかんなと。

数年前に、ドラキュラシリーズでそういうバグ映像を見かけたことを思い出したり。
  1. プレイヤーキャラがボス敵の上に乗れる仕様が入ってた。
  2. 動いてるボス敵の上に乗り続けてると、天井の中にプレイヤーキャラが押し込まれた状態になる。
  3. ジャンプボタン等を押して、ボス敵から離れた瞬間、おそらくは床補正が働いて…。
  4. BGマップの天井、壁、床の中を凄い勢いで飛び回り、まったく関係ない場所に出現しちゃう。
みたいなバグで。ソレを利用して、あえて爆速クリア、とかやる人まで出てきちゃって。

件のバグは、壁の中を高速移動していくプレイヤーキャラの映像が見えた気がするので、おそらく回数制限を設けて床補正、ぐらいはしてたのではないかと想像。そうじゃないと、無限ループに入ってフリーズするはずだし。

そういう場合、どう対処すればいいんだろう…。

2013/12/22() [n年前の日記]

#1 [ruby] YARDってreadme.mdをindex.htmlに反映してくれるのか…

.rbファイルと一緒に readme.md を書いて置いといたら、yardoc 実行時、index.html が readme.md の内容を取り込んだ状態になって、一瞬困惑しつつも感動したり。気が利くなあ…。

ただ、readme.md から doc/ 以下にリンクを張ろうとしていたので困ったりもして。doc/ 以下に置かれること前提で書いといたほうがいいのかな。しかしソレだと、readme.md を単体で読もうとしたときに、よく分からない状態に。どうしよう。

yardoc のコマンドラインオプションに、-r、--readme、--main FILE というのがあるあたりも気になる。--no-readme とか無いのかな。

#2 [dxruby][game] DXRubyでtmxファイルを使ってBG表示

_Tiled Map Editor の .tmxファイルを、tmx ライブラリを使って読み込んで、DXRuby で表示、かつ、地形アタリ処理をしてみるソレが、そこそこなんとか動くようになってきた…ような気がするのでアップロード。

動作してる様子

以下のソースで動いてます。(メイン処理のみ)

mapdisp.rb
#= Tiledの .tmx を読んで、表示と地形アタリ判定をするサンプル
#
# * カーソルキーでカーソル移動
# * WASDキーでスクロール
# * Bキーで、BGアタリレイヤーを表示/非表示
# * Hキーで、ぶら下がり棒とアタリをとるか否かを切替
# * ESCキーで終了

require 'dxruby'
require 'tmx'
require_relative 'dxrbtmx'
require_relative 'bgatari'

font = Font.new(14)
Window.frameskip = false

# 画面サイズ(ドット数)を取得
scrw = Window.width
scrh = Window.height

# BG描画に使うタイル画像を読み込む
bgimg = Image.loadTiles("bg_attari.png", 256/16, 256/16)

# BGマップファイル(.tmx)を読み込む
tmx = DxrbTmx.new("./bg_atari_test.tmx", scrw, scrh)

# レイヤー名を指定して、DXRubyの描画用マップデータ(二次元配列)を取得
atari_layer = tmx.get_layer("bg_atari")
bg_layer0 = tmx.get_layer("layer0")
bg_layer1 = tmx.get_layer("layer1")
bg_layer2 = tmx.get_layer("layer2")
bg_layer3 = tmx.get_layer("layer3")

# 画面を占めるタイル個数を取得
bgtw = tmx.screenwidth
bgth = tmx.screenheight

# BGアタリ判定用テーブルを作成
#
# 以下の引数を渡す
#
# 1. アタリ判定用の画像配列(Image.loadTiles() で読み込んだ画像)
# 2. BGアタリマップデータ(二次元配列)
# 3. 画面横幅ドット数
# 4. 画面縦幅ドット数
# 5. 抜けアタリ番号 (省略時は 0番を抜けとして扱う)
# 6. 非床アタリ開始番号 (省略可能)
# 7. 非床アタリ終了番号 (省略可能)
#
bgatari = BgAtari.new(bgimg, atari_layer, scrw, scrh, 0, 22, 30)

bx, by = 0, 0 # スクロール位置初期化
px, py = scrw / 2, scrh / 2 # カーソル位置初期化
atari_disp = true # BGアタリを描画するかどうかのフラグ
floor = true # ぶら下がり棒のアタリは無視するか否かのフラグ

# カーソル描画用メソッド
def draw_cursor(x, y, col)
  w = 2
  Window.drawLine(x - w, y, x + w, y, col)
  Window.drawLine(x, y - w, x, y + (w + 1), col)
end

# メインループ
Window.loop do
  break if Input.keyPush?(K_ESCAPE) # ESCキー押しで終了

  # Bキーで、BGアタリを描画するかしないかを切り替える
  atari_disp = !atari_disp if Input.keyPush?(K_B)

  # Hキーで、ぶら下がり棒アタリを無視するかしないかを切り替える
  floor = !floor if Input.keyPush?(K_H)

  # WASDキーでスクロール
  spd = 4.0
  bx -= spd if Input.keyDown?(K_A)
  bx += spd if Input.keyDown?(K_D)
  by -= spd if Input.keyDown?(K_W)
  by += spd if Input.keyDown?(K_S)
  
  # カーソルキーでカーソル移動
  spd = 1.0
  px += Input.x * spd
  py += Input.y * spd

  # BG描画
  if atari_disp
    # BGアタリのみ描画
    Window.drawTile(0, 0, atari_layer, bgimg, bx, by, bgtw, bgth)
  else
    # 通常BGのみ描画
    Window.drawTile(0, 0, bg_layer3, bgimg, bx / 8, by / 8, bgtw, bgth)
    Window.drawTile(0, 0, bg_layer2, bgimg, bx / 4, by / 4, bgtw, bgth)
    Window.drawTile(0, 0, bg_layer1, bgimg, bx / 2, by / 2, bgtw, bgth)
    Window.drawTile(0, 0, bg_layer0, bgimg, bx, by, bgtw, bgth)
  end

  # カーソル座標のBGアタリ番号を取得
  x = bx + px
  y = by + py
  bg_code = bgatari.get_bg_code(x, y)

  # カーソル座標がBGと当たってるかチェック
  chk_hit = bgatari.check_bg_hit(x, y, BgAtari::ADJUST_NONE, floor)
  col = (chk_hit)? [192, 255, 0, 0] : [192, 0, 128, 255]

  # カーソル座標描画
  draw_cursor(px, py, col)

  # 床補正座標を得る
  nx, ny = bgatari.adjust_bg_hit(x, y, BgAtari::ADJUST_UP, floor)
  hosei_code = bgatari.bg_code
  draw_cursor(nx - bx, ny - by, C_CYAN) if nx

  # 天井補正の座標を得る
  nx, ny = bgatari.adjust_bg_hit(x, y, BgAtari::ADJUST_DOWN, floor)
  draw_cursor(nx - bx, ny - by, C_CYAN) if nx

  # 壁補正の座標を得る
  nx, ny = bgatari.adjust_bg_hit(x, y, BgAtari::ADJUST_LEFT, floor)
  draw_cursor(nx - bx, ny - by, C_YELLOW) if nx
  
  nx, ny = bgatari.adjust_bg_hit(x, y, BgAtari::ADJUST_RIGHT, floor)
  draw_cursor(nx - bx, ny - by, C_YELLOW) if nx

  # BGアタリ番号その他の情報を描画
  yh = 16
  Window.drawFont(16, yh * 0, "FPS: #{Window.real_fps}", font)
  Window.drawFont(16, yh * 1, "input CURSOR、WASD,B,H key", font)
  Window.drawFont(16, yh * 2, "#{bg_code} : BG code", font)
  Window.drawFont(16, yh * 3, "#{hosei_code} : BG code (Floor adjust)", font)

end
一見すると長いのですが、見栄えを良くするために行数が増えちゃってるだけで…。処理の実体は、
.tmx の読み込みと変換
tmx = DxrbTmx.new( tmxファイル名, 画面横幅, 画面縦幅 )
レイヤー名を指定してBGマップデータ(二次元配列)を取得
atari_layer = tmx.get_layer(レイヤー名)
BGアタリ処理用のテーブル作成
bgatari = BgAtari.new(BGアタリ用画像配列, BGアタリに使うマップデータ, 画面横幅, 画面縦幅, 抜けアタリ番号, 床として扱わないアタリ開始番号, 床として扱わないアタリ終了番号)
BGアタリ番号を取得
bg_code = bgatari.get_bg_code(x, y)
BGと当たってるかチェック
chk_hit = bgatari.check_bg_hit(x, y, BgAtari::ADJUST_NONE, 床のみチェックするかをtrue/falseで)
BGアタリを元に座標補正(床補正)
nx, ny = bgatari.adjust_bg_hit(x, y, BgAtari::ADJUST_UP, 床のみチェックするかをtrue/falseで)
このあたりです。

使い回しができるように、別クラスにしてみました。
.tmxファイル、画像ファイル、スクリプト、各クラスのドキュメントを、zip にして Dropbox に置いておきます。Public Domain ってことで。

_dxruby_map_disp_20131222.zip

tmxライブラリについて。 :

_tmxライブラリ は、
gem install tmx
でインストールできます。 _multi_json_nokogiri も一緒にインストールされる模様。

tmx、nokogiri、multi_json、どれも MIT License のようですね。

アタリ判定用画像について。 :

アタリ判定用画像は、以下の画像(1タイル = 16x16ドット)を使ってます。

アタリ判定用画像

一番左上から、右に向かって、
  1. 抜けアタリ
  2. 進めない床
  3. フツーの床
  4. 斜め床…
と続いて…。青いところが、ぶら下がり棒用のアタリ。0〜31番までをアタリ判別用として使ってる状態です。

bgatari.rb の中で、この0〜31番を、1個ずつ、16x16ドットを全スキャンして、アルファ値が128以上ならその座標はアタリ有り、として扱ってます。

結局、やってることは、画像を読んで、ドットを見て、
[ [ [y最小値, y最大値] x 横ドット数 ], [ [x最小値, x最大値] x 縦ドット数 ] ]
という配列を作ってるだけなので、事前にそういう配列を用意して渡すように修正すれば、DXRuby 以外のライブラリでも bgatari.rb が使えるようになるのではと。…そういう作りにしといたほうがいいのかな。

先日アップした画像が参考になるかもしれないので再掲。

y最小値とy最大値があればアタリ判定できる

テーブルで持ってしまう

アタリ判定用データの扱いについて。 :

今回は、画像をスキャンして、アタリ判定用データを作ってるわけですが。

このあたり、以下のような作りでもいいんですけど、というか昔の自分は、そういうやり方してたんですけど。
  • あらかじめ、BGマップを作る前に、アタリ種類を決めておく。
  • アタリ種類毎に、数式だの条件分岐だので、必要な値を求める処理を書いておく。(一般的には switch 〜 case、Ruby なら case 〜 when になると思う)
  • BGアタリ番号と、アタリ種類の対応表を作っておく。

しかし…。
  • マップエディタやドットエディタで作業してるうちに、「もうちょっとアタリ種類を増やしたいな…」と考えてしまいがち。
  • アタリ種類を増やすの、メンドクサイ。数式や条件分岐を一々書くのは、メンドクサイ。
  • BGアタリ番号と、アタリ種類の対応表を作るのって、地味にメンドクサイ。
  • BGマップ側で使うアタリ種類の並びが変わっただけでも、対応表を作り直すので、メンドクサイ。
  • 曲線的なアタリの形に対応するのが、メンドクサイ。
とにかくメンドクサイ。

その点、今回のように、画像をスキャンして判別用データを作る方法なら…。
  • アタリ種類を増やしたり、並びを変える作業が、CGツール上で完結する。
  • 人間様が対応表を作らなくて済む。
  • 曲線的なアタリにも対応できる。
メンドクサくない。

その代り、
  • 画像の読み込み、かつ、ドットをチェックできるライブラリが必要。どこでも使い回せるソースにならない。
  • 毎回ゲームを動かすたびに、判別用データと対応表を作り直してるので、その処理時間が、ガチで無駄。
  • アタリ種類分のテクスチャ領域を、無駄遣いしてる。
というデメリットはありますが。

とりあえず、プロトタイプをサクッと、てな段階では、今回のやり方も有効なのかもしれないなと。このあたり、判別用データを別途出力するスクリプトを書くだけでも作業は楽になると思うのですが、そのスクリプトを動かす操作すら、プロトタイプ作成段階ではメンドクサイよなと…。

アプリとして完成間近で、実行バイナリに、無駄な処理も無駄なデータも入れたくない、という状態なら…。ツールを作って、判別用データを出力して、それをソース内に列挙、あるいは、別ファイルとして同梱して読み込む、という流れがベターではないかと。

でも、LL使ってゲーム作ってる時点で…。どうせ富豪的プログラミングをしてるわけですし…。このあたりのデータを毎回作り直しちゃってもいいよな、という気もするのでした。ンMbitのROMに収めて、ンMHzのCPUで動かすわけでもないし。

2017/03/19追記。 :

Dropboxのpublicフォルダが死んだのでファイルの置き場所を変更。

#3 [game] ドンキーコングと斜め床

先日、 _ファミコンリミックスなるゲームの宣伝映像? を眺めてたら、「あっ!」と気付いたことがあって。

最初の頃のマリオには斜め床は無いと思ってたけど、そもそもマリオが初登場した _ドンキーコング で、1面からいきなり斜め床だったのですな…。すっかり忘れてましたよ…。

ドンキーコングは、「樽が転がってくるからジャンプして避けるべし」というゲームだったけど。「樽が転がってくるんだよ」ということを、見ただけで間違いなく伝えるためには、斜め床は必須だよなと思えてきたり。あの床が平らだったら、樽がどっちに転がってくるのか分からないので、ビミョーにクソゲーになりそうな予感も。

_MZ-700のドンキーゴリラ はどうだったかな…。うむ…平らだ…。なかなか厳しい…のかなと思ったけど、意外とそうでもないような。樽は一方向にしか転がらないので、全体の流れはまだ分かるなと。樽より、火の玉の動きのほうが、よほどヤバイ。どう動くか分からん。

ターザンのゲームも思い出した。 :

_ジャングルキング というタイトルだったらしい。タイトー製。小学生の頃、駄菓子屋でコレをプレイしたのが、TVゲーム初体験、だったかなあ…。自分に限らず、近所の子供達が皆でコレに夢中になったものだから、学校+PTAで問題になった、と、後になってから聞いたっけ。

記憶の中では、左→右へと進んでたと思ってたけど。右→左、つまり一般的な横スクロールゲームとは逆方向だったのだな。記憶って、容易に改竄されてしまうのだなと、なんだか怖くなってきた。

それはともかく。3面目で斜め床が出てくる。コレも、「岩が転がってくるから避けるべし」という、ドンキーコングと同じ遊びで。何かが転がってくるぞとプレイヤーに分からせる際、斜め床は視覚的に大変有効、なのかもしれないと思えてきたり。

さておき、1面目で、多関節のロープが動いてるあたりが気になる…。当時からこんなスゴイことやってたのか…。しかし、気にはなるんだけど、なんだか各ロープにつかまった時に、プレイヤーキャラの座標移動のフレームレートが変わってるような気もする。もしかして、ロープの動きは全部テーブルで持ってて、アニメの再生速度を変えてるだけ、だったのでは。どうなんだろう。まあ、それでも、どうやって実装すればいいのか考え始めると、ちょっと軽く悩んじゃうのだけど。

マリオ3が気になる。 :

_「マリオ1には斜め床は無いが、マリオ3には斜め床がある」 という話を知って、興味が湧いてきたり。自分、マリオ1しか遊んでないので、2とか3とか全然知らなくて。どういうゲームだったんだろう…。

ググって辿り着いた、 _マリオ3小ネタ集 - YouTube_スーパーマリオ3  ファミコン スーパープレイ 最短攻略 TAS - YouTube を眺めて、「あわわわ…」てな気分になってきたり。地形アタリ絡みのバグは…精神衛生上よくないなと…。いや、バグじゃなくて、こういう仕様なのかもしれないか。

画面を見ていて、「なんだか _ギミック! みたいだな」と思ったけれど。発売日を調べてみたら、ギミックより何年も前だったらしい。ていうかソニックよりも前なので、どうもソニックの回転技は、マリオ3の回転技からのインスパイアだったのかなと思えてきたけど、そのへんどうなんでしょうか。

ギミックは、斜め床に立つとつるつる滑り落ちる仕様だったけど。マリオ3もそれっぽい動きをしてる時があるように見えるので、「斜め床=滑り落ちるので操作が大変」という遊びを入れるのが常、だったりするのかなとも思えてきたり。

SFC版魂斗羅も思い出してきた。 :

1面目の、爆撃機が近づいてくるシーンで ―― 爆撃機なのに何故かヘリコプターの「バタバタバタ」という音を出してるあたりが魂斗羅らしさだと思うのだけど ―― あのシーンで、斜め床の上に立って両手に銃を構える例のポーズを取っていたことを今頃思い出したり。あの時、足は、ちゃんと斜め床と一致した角度になってた気がする。

_魂斗羅スピリッツ (Contra 3 : The Alien Wars) 1/3 - YouTube の1:50〜や5:30〜あたりを見て、やっぱりそうだったなと。なるほど、その流れで、ガンスターヒーローズも斜め床用のポーズを持ってたのかしら。

アーケード版の魂斗羅はどうだったかなと思って動画を探してみたけど、無印は斜め床が無くて、Superで斜め床アリになったようで。ただ、斜め床の上で止まってるシーンが見つからず。まあ、平らな床の上でも足を閉じて銃を撃ってるから、斜め床でも足を閉じて撃ってそうかなと…。だとすれば、SFC版以降から斜め床用のポーズをちゃんと用意するようになった、ということになるのかしらん。

お行儀よく足を閉じて撃ってるポーズより、足をガバッと開いて踏ん張って撃ってるほうが、見た目カッコイイなと。例えばロックマンも、足を閉じて撃ってたら、それはなんかちょっと…。

ただ、斜め床用のポーズを作るのって、地味に面倒で。

斜め床に対応させるとパターン数がグングン増える。 :

一般的に2Dゲームって、キャラが右向きから左向きになる時、グラフィックを左右反転すればいいのだけど。 *1 斜め床用のポーズを作ってある場合は、そう単純にはいかなくて。右上がりの坂+右向きで立ってる状態から、十字ボタンを押して左向きにした際、ただ左右反転だけしちゃうと足がとんでもない状態に。

加えて、走りアニメも、伏せをする時も、床の角度に対応させようとか考え始めると…。「床の角度に合わせた足の角度にする」だけで、パターン数がグングン増えていって、頭が少しこんがらがってくる…。

しかも、銃を八方向に撃てる、なんて仕様だと…。今まで書いてきたことの、更に8倍のパターン数に。いや、右を向いている時は左には撃てない、とかなら、パターン数が8→5に減って、まだちょっとアレだけど。右向きに走ってるけど左にも撃てるよ、みたいな仕様だったら、もう何が何やら。上半身と下半身を分割して管理したほうがいいのかな…。PS1の某3Dゲームも、ちょっとそんな感じがしたなあ…。上半身と下半身が別々に動いてる感じで…。

そんなわけで、銃を撃つタイプの2Dゲームは、昔のロックマンみたいに、右向きなら右にしか、左向きなら左にしか撃てない仕様だと、随分楽になりそうだなと思えてきたり。そういう仕様なら、斜め床も対応できそうな気がしてくる…。更に、走りながらは撃てない、撃つ時は必ず止まる、てな仕様だともっと楽に。ってそこまで楽しちゃうとアレですね。

*1: もちろん、右向き左向きでちゃんとグラフィックを変更する、こだわって作ってあるタイトルも多々あるけれど。

2013/12/23(月) [n年前の日記]

#1 [cg_tools] ディザでグラデーションを作りたい

タイリングというか、市松模様というか、ディザというか、そういう模様でグラデーションを作りたいなと。

そもそも、現代において、少ない色数でグラデーションを作ってみてどうするんだ、という気もしますが。ただ、いかにもな昔風の2Dゲーム画面を、なんてことを考えてると、こういうこともやりたくなるわけで。1タイル16色で描けば、たぶんそれっぽくなる予感。ソレって一体どんなプレイなんですか。

EDGE2には該当機能無し。 :

日頃、ドットエディタとして、EDGE2 を愛用しているのだけど。EDGE2 には、そういったグラデーションを自動で作る機能は無くて。

一応、ディザの段階を選べる機能はあるのもの、ディザを選択 → 塗る → ディザを選択 → 塗る、なんてやってられないよなと。他のツールを探さねば…。

ちなみに、この認識は完全に間違いだったのですが。このまま話を進めます。

GIMPのインデックスカラー化ではビミョー。 :

GIMP でフルカラー画像のグラデーションを作成してから、インデックスカラー化することで実現できないかと思ったけれど。試してみたら、なんだか妙な感じのディザになってしまって。

GIMPでインデックスカラーにした画像

4倍に拡大してありますが。なんだかあちこちに、変な点が入ってしまう…。

D-Pixedをインストール。 :

ググってみたら、D-Pixed という256色のみ対応のCGツールに、グラデーション作成機能があると知ったので、試しにインストールしてみたり。

_D-Pixed : Vector
_D-Pixed Add-In tool

単体ではできなくて、アドインが必要らしい。おそらく、ペンアドインセット dppenadd.lzh の中にある、「グラデーション」、gradat.dll がソレ。コレを、D-Pixed のインストールフォルダにコピーする。

使い方を、画像で説明してみたりして。

D-Pixed + グラデーションの使い方


少し使ってみたけど、D-Pixed 自体がガンガンフリーズするな…。Windows7 上で動かしてるから、だろうか。ちょっと常用はできない感じ。

D-Pixed 上で画像を作ったらコピーして、EDGE2 で、編集 → 新しいウインドウに貼り付け、をして、後の作業は EDGE2 を使ったほうがヨサゲ。

ImageMagcikで作れないかな。 :

ImageMagick でグラデーション画像を作って減色すれば同じことができそうな気がしてきたり。以下を参考にして作業すれば、おそらくは…。

_Canvas Creation -- IM v6 Examples
_Quantization -- IM v6 Examples

convert -size 16x160 gradient:black _tmp1.png
convert _tmp1.png -ordered-dither o4x4 _tmp2.png

ImageMagickで作ったグラデーション画像

うむ。これでもイケそう。

と思ったけど、単なる白黒画像ならともかく、フルカラー画像を減色させると、奇妙な結果が出てくるなあ。
convert test_grad1.png -ordered-dither o4x4 test_grad1_dither.png
ImageMagickでグラデショーン画像を減色

ImageMagick のバージョンは 6.8.5-7 2013-05-19 Q8 だけど。 _ある時期の ImageMagick は減色関係でバグ持ち 、という話もあるし、最新版にしてみたほうがいいのかも。

ImageMagickを最新版に更新。 :

前のバージョンをアンインストール後、ImageMagick-6.8.7-10-Q16-x86-dll.exe をDLしてきてインストールしてみたり。ImageMagick には、Q8 と Q16、static版とdll版があるけど。今回は Q16、dll版をインストール。

結果は微妙に違ってきた、が、やはり前述のソレと同様、ちょっと奇妙な結果に。

オプションの与え方で、結果が違ってきた。「o4x4」→「o4x4,4」にしてみたら、イイ感じに。
convert test_grad1.png -ordered-dither o4x4,4 test_grad1_dither.png
ImageMagickでグラデーション画像を減色(オプション変更)

そもそもEDGE2にグラデーション塗り潰し機能があった。 :

作成画像をEDGE2で眺めたり弄ったりしてるうちに、「…アレ?」と。塗りつぶしツール利用時、オプションに「グラデーション」という項目が…。

なんてこったー。グラデ塗り機能が、ちゃんとあったのか…。

この機能、かなり充実していて。
  • ディザで塗ることができる。(「トーンを使う」にチェックが入ってれば使える。)
  • 利用する色を、パレットから複数選んで、順番を並び替えることができる。
  • グラデの角度はもちろん、位置を変えることもできる。
EDG2のグラデーション塗り機能

自分にとっては完璧。これは素晴らしい。

それにしても、この機能の存在に気付いてたら…。自分は今まで何をしてたのか…。アホ過ぎる…。でもまあ、EDGE2 さえあれば大体のことはできると分かったので、これはこれでOK、ということにしておきたいです…。

#2 [dxruby][game] DXRubyで地形アタリを取りながらプレイヤーキャラの移動

昨日アップロードしたクラスを使って、プレイヤーキャラの移動をやってみようかなと。

とりあえず、横移動と、足元に床が無かったら落下する、だけの処理を書いてみました。

playermove1.rb
# プレイヤーキャラを動かしてみるサンプルその1
# 横移動、床補正、落下処理だけの版

require 'dxruby'
require 'tmx'
require_relative 'dxrbtmx'
require_relative 'bgatari'

# 画像読み込み
pimg = Image.loadTiles("player.png", 640/80, 640/80)
bgimg = Image.loadTiles("bg_attari.png", 256/16, 256/16)

# tmx読み込み
scrw, scrh = Window.width, Window.height
tmx = DxrbTmx.new("./bg_atari_test.tmx", scrw, scrh)

# Bgレイヤーマップデータ取得
atari_layer = tmx.get_layer("bg_atari")
bg_layer0 = tmx.get_layer("layer0")
bg_layer1 = tmx.get_layer("layer1")
bg_layer2 = tmx.get_layer("layer2")
bg_layer3 = tmx.get_layer("layer3")

bgtw, bgth = tmx.screenwidth, tmx.screenheight

# BGアタリテーブル作成
bgatari = BgAtari.new(bgimg, atari_layer, scrw, scrh, 0, 22, 30)

# カーソル描画用メソッド
def draw_cursor(x, y, col)
  w = 2
  Window.drawLine(x - w, y, x + w, y, col)
  Window.drawLine(x, y - w, x, y + (w + 1), col)
end

bx, by = 0, 0
px, py = scrw / 2, scrh / 2
dx, dy = 0, 0
gravity = 0.45
pimgnum = 16

# メインループ
Window.loop do
  break if Input.keyPush?(K_ESCAPE)

  # プレイヤー移動処理

  # 左右キーで横移動
  # x速度に、キー入力に応じて加速度を加算
  dx += Input.x * 0.2

  # 横方向の最大速度を超えないようにする
  spdmax = 6.0
  dx = spdmax if dx >= spdmax
  dx = -spdmax if dx < -spdmax

  # 左右キーを押してなければ、速度を減らしていく
  dx *= 0.95 if Input.x == 0

  # 速度を加算
  px += dx
  py += dy

  # 床アタリで補正する
  if pimgnum == 16
    # 落下中
    yadd = 0
  else
    # 床の上に居る
    # 足元よりちょっと下の座標でアタリを取る
    yadd = 16
  end
  nx, ny = bgatari.adjust_bg_hit(px, py + yadd, BgAtari::ADJUST_UP)

  if nx == nil
    # 足元に床が無い
    dy += gravity # 重力加速度を、速度に加算
    pimgnum = 16 # 落下ポーズに変更
  else
    # 足元に床がある
    py = ny
    dy = 0 # y速度を0にする
    pimgnum = 0 # 床の上に居るポーズに変更
  end

  # プレイヤー移動処理ここまで

  # プレイヤーの位置から、BGスクロール座標を決定
  bx += ((px.to_i - (scrw / 2) - bx) * 0.2).to_i
  by += ((py.to_i - (scrh / 2) - by) * 0.2).to_i

  # BG描画
  Window.drawTile(0, 0, bg_layer3, bgimg, bx / 8, by / 8, bgtw, bgth)
  Window.drawTile(0, 0, bg_layer2, bgimg, bx / 4, by / 4, bgtw, bgth)
  Window.drawTile(0, 0, bg_layer1, bgimg, bx / 2, by / 2, bgtw, bgth)
  Window.drawTile(0, 0, bg_layer0, bgimg, bx, by, bgtw, bgth)

  # プレイヤー描画
  x = px - bx
  y = py - by
  img = pimg[pimgnum]
  Window.draw(x - 40, y - 68, img)

  # プレイヤー座標にカーソルを描画
  draw_cursor(x, y, C_RED)
end
_playermove1.rb.txt

プレイヤーキャラの移動の様子その1

BGアタリ(地形アタリ)で座標補正してるから、ちゃんと床の上をするすると動いているように見えますな。

しかし…。GIFアニメの後半、どんどん怪しい動作に…。

結局、床で座標補正しかしてない状態だと、一度壁の中にめり込んだが最後、こんなことになるわけですね。市販ゲームでもこういうバグを、(稀だろうとは思いますが) 目撃してしまった人も居るのではないかと。

ということで、こんなヒドイことにならないように、明日は、壁で補正する処理も入れてみたいと思います。

実験用に、プレイヤーキャラ用画像も置いときますね。Public Domain ってことで。

プレイヤーキャラ画像
画像サイズは640x640ドット、1パターン80x80ドット、8x8個のパターン入り、です。ってパターン入ってない隙間がたくさんあるけど。

GPU側の都合としては、256x256、512x512、1024x1024といった、キリのいい画像サイズ(テクスチャサイズ)のほうが良いのでしょうな…。

2013/12/24追記。 :

実験用のプレイヤーキャラ画像を、画像サイズ512x256ドット、1パターン64x64ドットに描き直してみたので置いときます。Public Domain ってことで。
プレイヤーキャラ画像、64x64ドット版

2013/12/24(火) [n年前の日記]

#1 [emacs] ndmacro.elが動かなくなってたけど最新版にしたら解決

emacs上で、キー操作を繰り返した場合にその操作を再生してくれる、ndmacro.el という拡張(?)があるのだけど。気付いたら動かなくなっていて。NTEmacs を 23.4 → 24.3 にしたせいだろうか。それとも自分、その前から動いてなかったけど、気付かなかったのだろうか…。

_snj14/ndmacro.el

github で入手できる最新版と交換したら、バッチリ動くようになりました。ありがたや。この機能、本当に助かります…。

#2 [cg_tools] Inkscapeでビットマップを扱ったら望んだ結果が得られず

ビットマップを含んだsvgを、pngエクスポートすると、ビットマップ部分がぼやけてしまう…。何か設定等で、ぼやけないようにできないのだろうか…。

む。もしかして、コレかな。

_ビットマップのインポート | Inkscape@JP
ビットマップをインポートすると、画像のサイズによって次のようにボケてしまうことがあります。

ビットマップの配置がドキュメント中のピクセルと合っていない場合に、自動的にアンチエイリアスがかかってこのようなボケた表示になります。ドキュメントのピクセルに配置を合わせるにはビットマップを選択してから、「エクステンション(N) > パスの変形 > ピクセルスナップ」を実行します。

手軽に合わせるには、選択ツールのツールボックスバーでX座標とY座標の小数点以下をそれぞれ0に変更します。つまり、XY座標がいずれも整数となるように変更します。

ピクセルスナップエクステンションでは、上記の作業を選択したすべてのオブジェクトに対して実行します。

ビットマップのインポート | Inkscape@JP より

試してみないと…。

#3 [dxruby][game] DXRubyで地形アタリを取りながらプレイヤーキャラの移動その2

今日も、DXRuby を使って、地形の上でプレイヤーキャラを動かす実験をしてみますよ。

以下のソースを動かすには、 _DXRubyでtmxファイルを使ってBG表示 で公開してる、 _dxruby_map_disp_20131222.zip と、 _player_512x256_64x64.png が必要です。

昨日のソースの補足。 :

_昨日のソース について、言及することを忘れてた部分があるので、念のために補足しておきます。

床とアタリチェックする時、ちょっと妙なことをしていまして。
  if pimgnum == 16
    # 落下中
    yadd = 0
  else
    # 床の上に居る
    # 足元よりちょっと下の座標でアタリを取る
    yadd = 16
  end
  nx, ny = bgatari.adjust_bg_hit(px, py + yadd, BgAtari::ADJUST_UP)
図で描くと、下のような感じです。
床アタリを見てる位置

「なんでそんな珍妙なことするの? 足元のBGアタリだけ見ればいいじゃん?」と思う方も居るかもしれませんね。ですので、あえて、足元しか見ないソースを書いて動かしてみました。
  # 足元しか見ないとどうなるかな…?
  yadd = 1
  nx, ny = bgatari.adjust_bg_hit(px, py + yadd, BgAtari::ADJUST_UP)
_playermove1_bug1.rb.txt
足元だけ見て動かしてる版の動作結果

斜め床を登っていく時はいいのですけど、下る時に「あわわわわ!」みたいな状態になりますな。

要は、以下のようなことが起きてしまうわけです。
足元だけ見てると斜め床を下る時にヤバイ
昔のゲームでも、こういうの、たまーに見かけましたけどね…。

なので、足元からちょっと下のあたりをチェックしてるわけです。
足元からちょっと下を見ればヤバくない

ですが、ジャンプ中や落下中も、同じように足元からちょっと下を見てるままだと、よろしくない状態になります。
着地してないのに着地したことになってしまう

ですので、「床の上に立っている時」と「ジャンプ中・落下中」で、BGアタリを見る位置を変えてみたのでした。

このあたり、もっと上手い方法があるんじゃないかと思うのですけど…。これもこれで、地形によっては何か問題が出そうな気もするんですよね…。まあ、今後の課題ってことで。

壁補正をしてみたり。 :

さておき。 _昨日のソース は、壁の中に入ってしまうと大惨事になったので、壁補正を入れてみました。

_playermove2_bug.rb.txt
# プレイヤーキャラを動かしてみるサンプルその2
#
# 横移動、落下処理、床補正に加えて、壁補正もするが…

require 'dxruby'
require 'tmx'
require_relative 'dxrbtmx'
require_relative 'bgatari'

# 画像読み込み
pimg = Image.loadTiles("player_512x256_64x64.png", 512 / 64, 256 / 64)
bgimg = Image.loadTiles("bg_attari.png", 256 / 16, 256 / 16)

# tmx読み込み
scrw, scrh = Window.width, Window.height
tmx = DxrbTmx.new("./bg_atari_test.tmx", scrw, scrh)

# Bgレイヤーマップデータ取得
atari_layer = tmx.get_layer("bg_atari")
bg_layer0 = tmx.get_layer("layer0")
bg_layer1 = tmx.get_layer("layer1")
bg_layer2 = tmx.get_layer("layer2")
bg_layer3 = tmx.get_layer("layer3")

bgtw, bgth = tmx.screenwidth, tmx.screenheight

# BGアタリテーブル作成
bgatari = BgAtari.new(bgimg, atari_layer, scrw, scrh, 0, 22, 30)

# カーソル描画用メソッド
def draw_cursor(x, y, col)
  w = 2
  Window.drawLine(x - w, y, x + w, y, col)
  Window.drawLine(x, y - w, x, y + (w + 1), col)
end

# プレイヤーのアニメパターンを定義
ppat = { "walk" => 0, "jump" => 16}
pimgnum = ppat["jump"]

bx, by = 0, 0
px, py = scrw / 2, scrh / 2
dx, dy = 0, 0
gravity = 0.45
bgatari_disp = false

# メインループ
Window.loop do
  break if Input.keyPush?(K_ESCAPE)

  # Bキーを押したらBGアタリ表示と切替
  bgatari_disp = !bgatari_disp if Input.keyPush?(K_B)

  # プレイヤー移動処理

  # 左右キーで横移動
  # x速度に、キー入力に応じて加速度を加算
  dx += Input.x * 0.2

  # 横方向の最大速度を超えないようにする
  spdmax = 6.0
  dx = spdmax if dx >= spdmax
  dx = -spdmax if dx < -spdmax

  # 左右キーを押してなければ、速度を減らしていく
  dx *= 0.95 if Input.x == 0

  # 速度を加算
  px += dx
  py += dy

  # ----------------------------------------
  # 壁アタリで補正する ← new!

  # 右側にBGアタリがあるかチェック
  xadd, yadd = 32, -32
  nx, ny = bgatari.adjust_bg_hit(px + xadd, py + yadd, BgAtari::ADJUST_LEFT)
  if nx
    # 右方向にアタリがある
    px = nx - xadd # 座標を補正
    dx = 0 # x速度を0に
  end

  # 左側にBGアタリがあるかチェック
  xadd, yadd = -32, -32
  nx, ny = bgatari.adjust_bg_hit(px + xadd, py + yadd, BgAtari::ADJUST_RIGHT)
  if nx
    # 左方向にアタリがある
    px = nx -xadd # 座標を補正
    dx = 0 # x速度を0に
  end

  # 壁アタリ補正ここまで
  # ----------------------------------------

  # 床アタリで補正する

  # 床の上に居る時だけ、足元よりちょっと下の座標でアタリを取る
  yadd = (pimgnum == ppat["jump"])? 0 : 12
  nx, ny = bgatari.adjust_bg_hit(px, py + yadd, BgAtari::ADJUST_UP)

  if nx == nil
    # 足元に床が無い
    dy += gravity # 重力加速度を、速度に加算
    pimgnum = ppat["jump"] # 落下ポーズに変更
  else
    # 足元に床がある
    py = ny
    dy = 0 # y速度を0にする
    pimgnum = ppat["walk"] # 床の上に居るポーズに変更
  end

  # プレイヤー移動処理ここまで

  # プレイヤーの位置から、BGスクロール座標を決定
  bx += ((px.to_i - (scrw / 2) - bx) * 0.2).to_i
  by += ((py.to_i - (scrh / 2) - by) * 0.2).to_i

  # BG描画
  if bgatari_disp
    Window.drawTile(0, 0, atari_layer, bgimg, bx, by, bgtw, bgth)
  else
    Window.drawTile(0, 0, bg_layer3, bgimg, bx / 8, by / 8, bgtw, bgth)
    Window.drawTile(0, 0, bg_layer2, bgimg, bx / 4, by / 4, bgtw, bgth)
    Window.drawTile(0, 0, bg_layer1, bgimg, bx / 2, by / 2, bgtw, bgth)
    Window.drawTile(0, 0, bg_layer0, bgimg, bx, by, bgtw, bgth)
  end

  # プレイヤー描画
  x = px - bx
  y = py - by
  img = pimg[pimgnum]
  Window.draw(x - 32, y - 57, img)

  # プレイヤー座標にカーソルを描画
  draw_cursor(x, y, C_RED)
  draw_cursor(x + 32, y - 32, C_RED)
  draw_cursor(x - 32, y - 32, C_RED)
end
床補正をする直前に、壁補正を入れてみました。

さて、結果は。
壁アタリ処理を追加したが…

Oops! 左右に進めません…。なんでや…。

こういう状態になってるわけですな。


さて、どうやって解決しよう…。

考えてみたら、壁として扱うべきBGアタリは、今のところ四角いブロックだけですので…。横方向にBGアタリがあった際、ソレが四角いブロック(壁相当)だった時だけ、壁補正をすることにしてみましょうか。
壁は四角いブロックだけ

_playermove2.rb.txt

  # 右側にBGアタリがあるかチェック
  xadd, yadd = 32, -32
  nx, ny = bgatari.adjust_bg_hit(px + xadd, py + yadd, BgAtari::ADJUST_LEFT)
  if nx and (1..2).member?(bgatari.bg_code)
    # 右方向に「壁」アタリがある
    px = nx - xadd # 座標を補正
    dx = 0 # x速度を0に
  end
(1..2).member?(bgatari.bg_code) で、BGアタリ番号が 1〜2 の時だけ、壁補正をする、という処理になってます。

…Ruby って、「その範囲の中に入ってるか?」を、こういう風に書けるのですな。今まで知りませんでした…。(ググってみて知りました…。) Ruby、便利だなあ。

壁補正もしている版

うむ。これで大丈夫そうです。

しかし、コレ、穴に落ちたら脱出できませんな…。明日は、ジャンプ処理を追加して、もっとあちこちに動けるようにしましょうかね。

壁補正についての余談。 :

ところで。上記の解決方法 ―― 壁相当とだけ壁補正をするというやり方も、ちと問題がありまして。下のような地形では、マズイことになるのです。
バグが発生する事例その1

どうやって解決するかは…。さて、どうすればいいのでしょう?

自分が今思いつくのは、2つぐらい、かなあ…。

一つは、壁相当とだけ壁補正するのはやっぱりやめて、BGアタリがあったらとにかく「壁」扱いしちゃう方法。最初の実装に戻しちゃうというか。その代わり、斜め床まで壁になったりしない程度に、壁をチェックする距離を短くする、とか。
壁アタリを見る位置を変える方法

もう一つは、壁アタリをチェックする位置を、もっと増やす方法。
壁アタリを複数チェックする方法
ただし、メインの壁補正 → 床補正 → サブの壁補正、といった具合に、チェックする順番に工夫が必要かもしれません。そうしないと、下図のようなバグが発生しそうだなと。
どこまでも続く「床」を、どこまでも続く「壁」として扱って、どこまでも補正され続けるバグ
あるいは、「どうも壁っぽいものがありそうなんだけど…普段見ている位置のBGアタリ番号だけでは確定できないなあ。念のために他の位置もあちこち見て判断するか」てな対処でもいいのかしら。

まあ、手っ取り早い解決策として、「おかしなことになる地形は作らない」という手も…。最悪、解決策がさっぱり思いつかないなら、そういうルールでマップを用意するのもアリですね。

2017/03/19追記。 :

Dropboxのpublicフォルダが死んだのでファイルの置き場所を変更。

#4 [zatta] ソース書いてる時間より説明図作ってる時間のほうが長いな

説明図をサクサク作れるツールとかないものか。

手描きでメモ用紙にサラサラ描いて、スキャンしてアップしちゃってもいいんだろうけど。むしろそのほうが、手作り感・趣味っぽい感じが出て良かったりして…?

2013/12/25(水) [n年前の日記]

#1 [cg_tools][dxruby] EDGEとEDGE2ってファイルの互換性は無かったのね

_あおたくノート - [Ruby][DXRuby] AnimeSpriteを使おう を参考にしながら、EDGE2で保存したアニメファイル(.anm)を読み込んでDXRubyで表示、という実験をしようとしたら、エラーが出てしまって。

EDGE2で保存した anmファイルをエディタで開いてみたら、どう見てもバイナリファイル。テキストファイルの形になってるはずでは…? はてな? どういうこと?

_EDGE2 Ver.0.90 beta006 アップ|TAKABO SOFT に、「EDGEとEDGE2は、ファイル互換性無いっス」と書かれていた。ガーン。

仕方ないので、EDGE をインストールして anmファイルを作ってみたけど。うむ。EDGE2に比べると、EDGE は地味に操作がツラい。 EDGE はフリーソフトだけど、EDGE2 はシェアウェアなので、細かいところで使い勝手が改善されているのだなと再認識。

さておき。EDGE で出力した anm は、たしかにテキストファイルだった。なるほどこれなら簡単に利用できそう。

それにしても、どうして EDGE2 で、わざわざバイナリにしちゃったんだろう…。テキストファイルにしておけば、他のツールとの連携がやりやすくなっただろうに。 _マップエディタの Platinum もそうだったけど、独自データをバイナリ保存しちゃうツールって、どうしても世界が閉じてしまう…。 *1 ファイルを開いて、「あ、テキストファイルだ。これならなんとかなる」と思う場面って、結構多い印象もあるのだけど。

まあ、EDGE2 は EDGE2 で、アニメーションデータを xml でエクスポート/インポートできるので、それでどうにかしなさい、ということなのだろうな…。

でも、これだと、EDGE と EDGE2 が混在してる環境では困りそう。と思ったけど、ビットマップデータを格納しているedgファイル自体は、EDGE → EDGE2 も、EDGE2 → EDGE もOKだった。すると、anmファイルだけは別、という状態なのか…。

EDGEでアニメ作成について。 :

解説ページを参考にしながら作業すればよかったのだなと今頃気付いたり。

_ドット絵描こうZ : アニメーションの作り方
_かんたんGIFアニメアイコン制作講座
_大学生の悩み ロボ太の日記

そういや、Adobe も「Adobe Edge」というツールを出してきちゃったから、ドットエディタのEDGEのほうで検索する時、ちょっと困りますな…。

*1: Platinum は CSV出力できるから、それで助かった記憶もあるけれど。

#2 [xyzzy] xyzzy + complete+.l を動かそうとして四苦八苦

_complete+.l を使ってみようとしたら、C-x C-f を押すだけで、「complete+::*virtual-file-mode* がねえよ」みたいなエラーダイアログが表示される状態に。

netinstaller で virtual-file* を全部と、ffap を入れて、ダンプファイル作り直したら動いてくれた、ような気がする。

でも、complete+ を有効にしておくと、時々 xyzzy が一瞬固まる時があるような。なんでだろ。とりあえず、やっぱり無効にしておいたり。

#3 [dxruby][game] DXRubyで地形アタリを取りながらプレイヤーキャラの移動その3ひとまず完結編

今日も、DXRubyを使って、プレイヤーキャラを動かしてみますよ。

_昨日の時点 では、壁にめり込まなくなったものの、穴に落ちるとそこから脱出できなくなったので、今日はジャンプ処理を追加してみようかと。

下のようなソースになりました。

playermove3.rb
# プレイヤーキャラを動かしてみるサンプルその3
#
# 横移動、落下処理、床補正、壁補正、
# ジャンプ、天井補正をする。

require 'dxruby'
require 'tmx'
require_relative 'dxrbtmx'
require_relative 'bgatari'

font = Font.new(12)

# 画像読み込み
pimg = Image.loadTiles("player_512x256_64x64.png", 512 / 64, 256 / 64)
bgimg = Image.loadTiles("bg_attari.png", 256 / 16, 256 / 16)

# tmx読み込み
scrw, scrh = Window.width, Window.height
tmx = DxrbTmx.new("./bg_atari_test.tmx", scrw, scrh)

# Bgレイヤーマップデータ取得
atari_layer = tmx.get_layer("bg_atari")
bg_layer0 = tmx.get_layer("layer0")
bg_layer1 = tmx.get_layer("layer1")
bg_layer2 = tmx.get_layer("layer2")
bg_layer3 = tmx.get_layer("layer3")

bgtw, bgth = tmx.screenwidth, tmx.screenheight

# BGアタリテーブル作成
bgatari = BgAtari.new(bgimg, atari_layer, scrw, scrh, 0, 22, 30)

# 空中床
float_floor = 21

# カーソル描画用メソッド
def draw_cursor(x, y, col)
  w = 2
  Window.drawLine(x - w, y, x + w, y, col)
  Window.drawLine(x, y - w, x, y + (w + 1), col)
end

# プレイヤーのアニメパターンを定義
ppat = { "walk" => 0, "jump" => 16}
pimgnum = ppat["jump"]

bx, by = 0, 0
px, py = scrw / 2, scrh / 2
dx, dy = 0, 0
gravity = 0.45
bgatari_disp = false

wall_dist = 16 # 壁アタリをチェックする距離
ceiling_dist = 54 # 天井アタリをチェックする距離

# スクロール座標の範囲
scrl_spc = 16
bx_min = scrl_spc
by_min = scrl_spc
bx_max = tmx.map_width - Window.width - scrl_spc
by_max = tmx.map_height - Window.height - scrl_spc

# メインループ
Window.loop do
  break if Input.keyPush?(K_ESCAPE)

  # Bキーを押したらBGアタリ表示と切替
  bgatari_disp = !bgatari_disp if Input.keyPush?(K_B)

  # プレイヤー移動処理

  # 左右キーで横移動
  # x速度に、キー入力に応じて加速度を加算
  dx += Input.x * 0.2

  # 横方向の最大速度を超えないようにする
  spdmax = 6.0
  dx = spdmax if dx >= spdmax
  dx = -spdmax if dx < -spdmax

  # 左右キーを押してなければ、速度を減らしていく
  dx *= 0.95 if Input.x == 0

  # ジャンプボタン(Zキー/ゲームパッドのボタン0)が押されていたら、ジャンプする
  # …このままだと空中でもジャンプできちゃうけど、なんだか面白いから残しとく

  # if Input.padPush?(P_BUTTON0)
  if Input.padDown?(P_BUTTON0)
    # dy = -16 # y速度を上向きに設定
    dy = -10 # y速度を上向きに設定
    pimgnum = ppat["jump"] # ジャンプポーズにする
  end

  # 速度を加算
  px += dx
  py += dy

  # 天井アタリで補正する
  if dy < 0
    # y速度が上向きの時だけ天井アタリを見る
    xadd, yadd = 0, -ceiling_dist
    nx, ny = bgatari.adjust_bg_hit(px + xadd, py + yadd, BgAtari::ADJUST_DOWN)
    if nx and bgatari.bg_code != float_floor
      # 天井側に、空中床以外のBGアタリがある
      py = ny - yadd # 座標を補正
      dy = 0 # y速度を0にする
    end
  end

  # 壁アタリで補正する

  # 右側にBGアタリがあるかチェック
  # xadd, yadd = 32, -32
  xadd, yadd = wall_dist, -32
  nx, ny = bgatari.adjust_bg_hit(px + xadd, py + yadd, BgAtari::ADJUST_LEFT)
  if nx and bgatari.bg_code != float_floor
    # 右方向に、空中床以外のアタリがある
    px = nx - xadd # 座標を補正
    dx = 0 # x速度を0に
  end

  # 左側にBGアタリがあるかチェック
  # xadd, yadd = -32, -32
  xadd, yadd = -wall_dist, -32
  nx, ny = bgatari.adjust_bg_hit(px + xadd, py + yadd, BgAtari::ADJUST_RIGHT)
  if nx and bgatari.bg_code != float_floor
    # 左方向に、空中床以外のアタリがある
    px = nx - xadd # 座標を補正
    dx = 0 # x速度を0に
  end

  # 床アタリで補正する
  if dy < 0
    # 上向きに飛んでいる
    dy += gravity # 重力加速度を、速度に加算
  else
    # 下向きに飛んでいる、もしくは、床の上に居る

    # 床の上に居る時だけ、足元よりちょっと下の座標でアタリを取る
    yadd = (pimgnum == ppat["jump"])? 0 : 12
    nx, ny = bgatari.adjust_bg_hit(px, py + yadd, BgAtari::ADJUST_UP)

    if nx == nil
      # 足元に床が無い
      dy += gravity # 重力加速度を、速度に加算
      pimgnum = ppat["jump"] # 落下ポーズに変更
    else
      # 足元に床がある
      py = ny # 座標補正
      dy = 0 # y速度を0にする
      pimgnum = ppat["walk"] # 床の上に居るポーズに変更
    end
  end

  # プレイヤー移動処理ここまで

  # プレイヤーの位置から、BGスクロール座標を決定
  bx += ((px.to_i - (scrw / 2) - bx) * 0.25).to_i
  by += ((py.to_i - (scrh / 2) - by) * 0.25).to_i
  if true
    # スクロール範囲を制限する場合
    bx = bx_min if bx < bx_min
    by = by_min if by < by_min
    bx = bx_max if bx > bx_max
    by = by_max if by > by_max
  end

  # BG描画
  if bgatari_disp
    Window.drawTile(0, 0, atari_layer, bgimg, bx, by, bgtw, bgth)
  else
    Window.drawTile(0, 0, bg_layer3, bgimg, bx / 8, by / 8, bgtw, bgth)
    Window.drawTile(0, 0, bg_layer2, bgimg, bx / 4, by / 4, bgtw, bgth)
    Window.drawTile(0, 0, bg_layer1, bgimg, bx / 2, by / 2, bgtw, bgth)
    Window.drawTile(0, 0, bg_layer0, bgimg, bx, by, bgtw, bgth)
  end

  # プレイヤー描画
  x = px - bx
  y = py - by
  Window.draw(x - 32, y - 57, pimg[pimgnum])

  # プレイヤー座標にカーソルを描画
  draw_cursor(x, y, C_RED)
  draw_cursor(x + wall_dist, y - 32, C_RED)
  draw_cursor(x - wall_dist, y - 32, C_RED)
  draw_cursor(x, y - ceiling_dist, C_RED)

  Window.drawFont(8, 8, "Move: ← → / Jump: Z / BG atari: B", font)
end
これで、穴に落ちても脱出できるかなと。

動作画面
ホントは、床の上に居る時だけジャンプ可能にすべきかもしれませんが。なんだかこのほうが面白かったので、そのままにしておきました。…きっと、彼の背中には翼がついてて、ジャンプボタンを押してる間は翼がバタバタ動いてるんです。心の目で見ればそう見える。ということにしておこう。

途中で、空中床(?)にも飛び乗れてますが…。どうやっているのかと言うと…。 たったこれだけです。BGアタリの種類を色々用意していけば、こんな風に、できることが増えていくのかなと。…でも、アタリ種類がどんどん増えていくので、これもこれでどうなんだろうという気もしますけど。もっとスマートなやり方はないのかな。まあ、そこは今後の課題ってことで。

ちなみに、マップの一番右のほうに、怪しいことが起きそうな地形を、いくつか置いておきました。個人的には、小さい段差で「ガクッ」と補正されるあたりが、気になりますなあ…。

とりあえず、ここまでのソースも画像も、zipファイルにまとめて、Dropboxに置いときますね。exeファイル以外は Public Domain ってことで。(exeファイルだけは、MIT License の tmxライブラリを含んでるので、ライセンスがよく分からず…。再配布するぐらいなら問題ないと思ってるんですが、どうなんだろう?)

_dxruby_map_disp_20131225.zip
他にも実装したい部分はありますが…。 まあ、ここまでやってきたことを参考にすれば、作り込みはできると思いますので…。

今回は、というか今年の DXRuby関係の記事は、これで最後にしたいと思います。どうにか、「一人DXRuby Advent Calendar 201」 も、そこそこやり遂げられたような気もしますし…! *1

課題のヒント。 :

床の上に立っている時だけジャンプさせたい。
床の上に立っている時だけ、ジャンプボタンが押されたかチェック。
空中床から真下に飛び降りたい。
飛び降り始めてから一定距離は、床アタリを無視。ただし、空中床の上に居ると分かってる時だけ、飛び降り操作を受け付ける。
崖(?)のギリギリ端っこにも立ちたい。
床補正時に見る位置を、足元の一点だけではなく、両脇にも増やす。
崖から落ちるときにガクッと動くのが気になる。
崖のギリギリ端っこに立てるようになれば、気にならないかも。
天井にぶら下がりたい。
床アタリに対してやってることを、上下逆にして、頭のあたりの座標を使って行う。
壁をよじ登りたい。
床アタリに対してやってることを(以下略
ぶら下がり棒に、ぶら下がりたい。
床アタリに対してやってることを、頭のあたりの座標を使って行う。ただし、ぶら下がり棒のBGアタリ番号以外は無視。
壁を蹴って三角飛びしたい。
ジャンプ中、かつ、壁補正された時に、ジャンプボタンを受け付ける。
斜め床の上では移動速度を変えたい。平らな床と同じ速度で動くのは気になる。
BGアタリ種類と、速度もしくは角度の対応表を作っておく。足元のBGアタリ番号を見て速度を決定。
小さい段差の上に乗るとガクッと動くのが気になる。
これ、どうやればいいんでしょうね? たぶん、対処を入れると、斜め床絡みでバグが出そうな予感…。「こういう地形は作らない」というルール適用が一番安直だけど…。
動く足場を作りたい。
動く足場のアタリ範囲と当たったら、床補正時と同じノリでプレイヤー座標を補正。ただし、動く足場の移動量をプレイヤー座標にも加える。足場側が自分の移動量を保持していて、プレイヤー側がソレをゲットして座標変更するか、あるいは、プレイヤー側が、乗ってる足場に、「お前に乗ってるよ」と知らせてあげて、足場側でプレイヤー座標を変更、等の処理になるのかなと。

参考になりそうなページ。 :

_地形判定させてみる の、真ん中あたりにある説明図が、今回のソースの問題点をズバリ示してる、ように思います。

また、前にも書きましたが、 _2D当たり判定超入門(pdf) は、大変参考になりそうです。件のpdfは図形で地形判定してますが、タイルで地形判定する場合と共通する問題点にも触れていますので…。

2017/03/19追記。 :

Dropboxのpublicフォルダが死んだのでファイルの置き場所を変更。

*1: や。「一人DXRuby Advent Calendar 2013」なんてする気はなかったですけど…。そもそも、ほとんどの記事は、DXRubyと関係ないですよね…。HSP、PyGame、pyglet、Processing、等々何を使ってもいいような話ばかりでしたし。

#4 [anime][game][neta] 牛男が気になる

昔目にしていた牛男のゲームのタイトルが気になり始めて検索。

「Wild West Cowboy of Moo Mesa」というタイトルだったらしい。 _Chibi Resena Wild West Cowboy of Moo Mesa - YouTube を眺めた感じでは…アニメ版はカッコイイな…。ゲーム版はちょっと頭身を縮め過ぎてしまった気もする。でも、アチラから「キャラを大きく表示しろ」と要求されつつも、ゲームとして成立させるために、このバランスになったのかなと想像したり。

_wild west cowboys konami - YouTube を眺めた感じでは、結構人気があったのかしら。「俺のお気に入りだぜ!」なんてコメントもあるような。

とは言え。例えばPCE版と○メモチームの画面に、代わりにコレが映ってたら、あのチームはあそこまで踏ん張れなかったんじゃないかという気がして。やっぱり画面の中に可愛い女の子が出てるか否かって、地味に効いてくるような気がしたり。

自分も、起動直後の「(ピピン!) おはようございます! 今日も一日〜」で、もう色々とグッタリ状態だったのに、「…よし…頑張らねば…この娘のためにも…な…」てな気分になった記憶もあって。

つまり、赤い矩形や、青い矩形じゃ、ソース単体で事足りるとは言え、「勉強してみようかな」てな気分にならないよなと。そんなわけで、自分、その手の実験をする時すら、まずはドットエディタを起動しちゃうのでした。でも、 _ワイデス40 モドキが関の山という…。

む。なんとなく思ったけど、Ruby のソース内に画像バイナリを記述して、ソースのみをblogに張ってるのに、コピペして動かすと可愛い画像が、みたいなことはできないのかしら。…考えてみたら、ARGB値を並べておけばいいだけ、なのかな。いやいや、それだと圧縮が効かないか。

Rubyで、テキスト化されたバイナリ圧縮データを解凍するのって、どんな形式がメジャーなんだろう…。

2013/12/26(木) [n年前の日記]

#1 [anime] 恋物語のOP、凄いなあ

見ていて感心。 今風の絵柄と昔の絵柄が交錯するあたりも含めて、見ていてクラクラする…。

撮影時のガタツキとか、 _髪が風でなびく時に一瞬つるっぱげになる ところまで再現してたら凄いなと思ったのだけど、さすがにそこまでは…と見えたけど、実はそのへんもちゃんとやってたらどうしよう。

#2 [dxruby][ruby] Rubyスクリプトの中に画像を仕込むソレ

昨日、「Rubyスクリプトの中に画像を入れておくことってできないのかな?」と疑問を持ったのだけど。どうやら簡単に(?)できるらしいと分かったのでメモ。

テキストの中にバイナリデータを入れておく方法としては、一般的には base64なるものが使えるらしくて。ソレを使って実験。ちなみに、画像の表示には DXRuby を使っております。

_imgdisp.rb
# base64をバイナリに変換してImage作成、かつ表示

require 'dxruby'

# ファイル最後のbase64文字列を読み込む
base64_text = ""
DATA.each {|l| base64_text += l.chomp}

# base64 からバイナリ化
bin_data = base64_text.unpack('m')[0]

# Image生成
img = Image.loadFromFileInMemory(bin_data).sliceTiles(2, 1)

Window.minFilter = Window.magFilter = TEXF_POINT # 拡大縮小の補間方法を「無し」に設定
Window.bgcolor = [0, 140, 255] # 背景色設定
Window.resize(320, 240) # ウインドウサイズ変更

cnt = 0
Window.loop do
  break if Input.keyPush?(K_ESCAPE)
  i = (cnt >> 3) & 0x01
  Window.drawScale(64, 64, img[i], 3, 3) # 拡大して描画
  cnt += 1
end

__END__
iVBORw0KGgoAAAANSUhEUgAAAEAAAAAgBAMAAABQs2O3AAAAKlBMVEVzAAD/
////ra1CISH/rXO9vb2MUhD/3q2t75xCzhAQ70IA/1IAjP8AAAAa/EhrAAAA
DXRSTlP///////////////8APegihgAAAWhJREFUOE+FkrFqwzAQQDUEumTR
kK1Lpq4B/4IglGYJQVvmTJ2K4ZYs3Tx0T+X0A0qzFlqqDIU0Q0B7fqenOyk+
ecmBBXf3nnyWpcKVUHFprwCnbVMWpcCAb5qXrlYIEXBb770gCoGAHQLfHVEI
BHhfEIWAwKn1iWg0A1IQgG+0vg19QQDPugRYQMDRO2Nbj5ahLxDQfrzrS78n
EOBiNrJ2yTMWAgGxbxdKDRMgBQReKZsMjFIJyEI0VDjOKTNTMLyFEFQE7Jwy
OMM5REAIQywgYG1V10DALwJSIOBoFxPscyECQuAhw2FyA093yBDQExhQU4AM
9AT6skoNDMbDPgNCoCuHZ8fHn7aQAl2YDcTT196vqd8JsKbf7aCO2dj7LwI2
kIV6loD7HRuftAGAScKeL4wztKWmAubGuCRkwNEVGPuftzSCEGjIS+QZhUDn
8GfyQlEIBBxWj2lJYWb8dMAqLSkqhCsW/gGJgHQo0efUBgAAAABJRU5ErkJg
gg==
bse64からバイナリに変換して表示


画像はコレ。Public Domain ってことで。

player.png
player.png


画像ファイルからbase64への変換は、以下のスクリプトを使ったり。なんだかワンライナーでもイケそうだけど。

_imgconv.rb
# 画像ファイルを読み込んで、base64にして出力する

fn = ARGV[0]
bin_data = File.binread(fn)
base64_text = [bin_data].pack('m')
puts base64_text

実行すると、こうなる。
> ruby imgconv.rb player.png
iVBORw0KGgoAAAANSUhEUgAAAEAAAAAgBAMAAABQs2O3AAAAKlBMVEVzAAD/
////ra1CISH/rXO9vb2MUhD/3q2t75xCzhAQ70IA/1IAjP8AAAAa/EhrAAAA
DXRSTlP///////////////8APegihgAAAWhJREFUOE+FkrFqwzAQQDUEumTR
kK1Lpq4B/4IglGYJQVvmTJ2K4ZYs3Tx0T+X0A0qzFlqqDIU0Q0B7fqenOyk+
ecmBBXf3nnyWpcKVUHFprwCnbVMWpcCAb5qXrlYIEXBb770gCoGAHQLfHVEI
BHhfEIWAwKn1iWg0A1IQgG+0vg19QQDPugRYQMDRO2Nbj5ahLxDQfrzrS78n
EOBiNrJ2yTMWAgGxbxdKDRMgBQReKZsMjFIJyEI0VDjOKTNTMLyFEFQE7Jwy
OMM5REAIQywgYG1V10DALwJSIOBoFxPscyECQuAhw2FyA093yBDQExhQU4AM
9AT6skoNDMbDPgNCoCuHZ8fHn7aQAl2YDcTT196vqd8JsKbf7aCO2dj7LwI2
kIV6loD7HRuftAGAScKeL4wztKWmAubGuCRkwNEVGPuftzSCEGjIS+QZhUDn
8GfyQlEIBBxWj2lJYWb8dMAqLSkqhCsW/gGJgHQo0efUBgAAAABJRU5ErkJg
gg==

この文字列を、前述のスクリプト imgdisp.rb の __END__ 以降に貼り付けてもいいし。

あるいは、imgdisp.rb の __END__ 以降を事前に削除してから、以下を実行して imgdisp.rb のお尻に追加しちゃってもいいし。
ruby imgconv.rb player.png >> imgdisp.rb

ちなみに、WindowsのDOS窓(cmd.exe)上で、Ruby スクリプトを使ってリダイレクト?( > とか >> ってやつ) を使う場合は、hoge.rb を実行したのではダメで、ruby hoge.rb を実行しないといけないようで。そのへんちょっとハマったりして。

何にせよ、base64 てのを使えば、テキストだけで書かれてるように見えてもバイナリを含めることができると知り、勉強になりました…。や、「今頃そんなこと知ったのかよ」と笑われたり呆れられたりしそうではありますが。

こういう使い方って意味あるのかな。 :

ソースにバイナリを仕込めたものの。サンプルソースの中に、こんな謎文字列が並んでたら、ソレってどうなのという気もしたり。

もしかして DXRuby などは、実験用に使えるメソッドとかあったら便利なのだろうか。
k_img = Image.makeBear() # テスト用のクマさん画像を作成
m_img = Image.makeMiku() # テスト用の初音ミク画像を作成
みたいな。学習用ライブラリとして強化するなら、そういうのも有効かもしれない?

まあ、そのへんは、enchant.js に任せるべきなのかな…。あっちのクマさん画像は、子供達に訴求力ありそう。

Scratch も、その手の画像があらかじめ入ってるけど。あの絵柄で喜ぶのはアメリカンな子供達だけだろうな…。

参考になった記事をメモ。 :


2013/12/27(金) [n年前の日記]

#1 [game][prog] 吉里吉里/KAGを試用中

Ruby で xp3 ファイルのデコードを ―― 吉里吉里/KAGのパッキングしたファイルをデコードすることってできないのかなと疑問が湧いて。サンプルになる xp3 があればいいのだろうけど、そんなものは見つからず。仕方ないから xp3 を作るかと。ググった感じでは、吉里吉里/KAGのSDKとやらに同梱されてる Releaser なるツールを使って data.xp3 というファイルを作る流れが主流らしい。

しかしそもそも、吉里吉里/KAGを触ったことが無いので、何が何やらさっぱりで。ひとまず添付されてるドキュメントを見ながら、ざっくり使い方を勉強してる次第。

ドキュメントによると、 これで動いてしまうらしい。後は、 このあたりを弄っていけば、たちまち紙芝居ゲームっぽくなってきて。コレ、小説を書いたことがある人なら、すぐに紙芝居ゲームが作れちゃうなと。素晴らしい。その手のジャンルに特化して作り込まれてきただけのことはあるなあ、と感心。

とはいえ、今時このスタイルってどうなの、てな根本的な部分でもやもやしたりもするのだけど。でも、そのあたりと、ツールの完成度は、また別の話だし。よくまあここまで作ったなあ、と。

入力作業が面倒臭い。 :

動作を指定するタグとやらの入力が面倒だなと。Markdown 等と比べてしまうと、「今時こんな入力作業、やってられん…拷問だ…」と思えてきたり。HTMLタグをメモ帳で書いてる気分。簡易記法や、入力を楽にする関連ツールがありそうな予感。

ググってみたら、専用エディタ、IDE、プラグイン等があるらしい。

_KKEF | PORING SOFT .NET
_KKDE | PORING SOFT .NET
_赤恐竜のブログ vimで吉里吉里の開発をする

Vim用のプラグイン?があるとは恐れ入りました。すると emacs や xyzzy 用もあるのかな、と思ったけどコチラは見つからず。どうやら、吉里吉里/KAGと、emacs文化圏は、断絶してるっぽい。まあ、こういうツールを使う人が、日頃、emacs系エディタで、バシバシ書いてるわけないし…。

とりあえず、KKDEを試用してみたり。なるほど、HTMLタグエディタと同程度の快適さになった気がする。

でもやっぱり、もうちょっと改善のしようがありそうな。ほとんどの場面で、Markdown 程度の簡素な記述にできそうだけど…。まあ、そういう記法や変換ツールも既にありそうだけど。

そもそもxp3を使わない方がいいのかもしれない。 :

元々、DXRuby と組み合わせて使うパッキングの仕組みとしてどうか、と考えていたのだけど。どうも昨今は zlibライブラリを使って云々、という流れになってるらしいので、だったら別に xp3 じゃなくても良さそうだよなと思えてきたり。パッキングするためだけに、一式を導入するのもなんかアレだし。

でもまあ、吉里吉里/KAGを触ってみて、この手のツールの大まかな印象は掴めたような気もするので、これはこれで。

#2 [dxruby][game] 昔のPCは色んな文字があったなと

大昔の、8bitパソコンって、各メーカが勝手に色んな文字をツッコんでたなと思い返したり。

_SHARP MZシリーズ には、「大」みたいな、人を表す文字があって、あらゆるゲームで大活躍してた。90度ずつ回転した4パターンがあったから、倒れてる人を示したり、頭から落ちていく人を示したり、やられた時はグルグル回って表現したり。他にヘビみたいなマークもあって、コレはえてして敵キャラだった記憶も。

_ NEC PC-8001 は、トランプのマークが活躍してた気がする。ハートを取ると得点ゲット。クラブは、木。ダイヤは、触ったらアウトの壁。必然的にスペードは自機を担当、みたいな。

_ナショナル(今の Panasonic) JR-100 は、ちょっと違ってて。ユーザが自分の好きな文字デザインを登録することができた。ベーマガ(マイコンBASICマガジン)の、JR-100のページだけ、見るからに楽しそうな画面になってて。「JR-100、いいなあ…」と羨ましかったっけ。

てなことを思い返しているうちに。今の各種ゲームライブラリでも、フォントを使ってドット絵っぽいのを作れたりしないかな、とバカ妄想を。

結局、スクリプトソース内にちょこっと記述を増やすだけでそれらしいドット画像をバーンと表示できないかな、という話なんですけど。

フォントで画像モドキを作ってみたり。 :

フォントを重なっていったらそれっぽい画像にならないかなと。Ruby + DXRuby で実験。

_makedotimg.rb
# フォントで画像を作ってみる

require 'dxruby'

w, h = 80, 80
font = Font.new(72, "Courier New")

srand(0)
Window.bgcolor = [00, 64, 255]

init_fg = true
imgs = []

Window.loop do
  break if Input.keyPush?(K_ESCAPE)

  init_fg = true if Input.keyPush?(K_SPACE)

  if init_fg
    # 画像作成
    imgs = []
    32.times do |i|
      img = Image.new(w, h)
      strs = []
      xw = w / 2
      6.times do |j|
        c = (rand(126-32) + 33).chr
        x = rand(xw)
        y = rand(xw)
        img.drawFont(x, y, c, font)
        strs.push([x, y, c])
      end
      imgs.push(img)
      # p strs
    end
    init_fg = false
  end

  # 描画
  x, y = 0, 0
  imgs.each do |img|
    Window.draw(x, y, img)
    x += w + 8
    if x + img.width > 640
      x = 0
      y += w + 8
    end
  end
end
実行結果
  • スペースキーで再作成。

うーん。ビミョー。いや、ビミョーどころじゃなく、厳しい。

もっとも、文字の選択と位置調整を手作業で指定していければ、それらしい組み合わせが作れそうな気もしたり。以下のような事例もあることだし…。

_ドラえもんの特殊顔文字はどういうしくみでできているか|Colorless Green Ideas

ただ、それでスクリプト中に記述するデータ量が少なくなるかと言うと、そこはちょっと読めないなと…。

JR-100方式。 :

ビットパターンで画像を作るだけでもそれっぽくなるのではと思えてきたので実験。

_makebitpat.rb
# ビットパターンを作成、あるいは描画
#
# ビットパターンデータをダンプ
# ruby makebitpat.rb hoge.png
#
# ビットパターンを描画
# ruby makebitpat.rb
#

require 'dxruby'

if ARGV[0]
  # ビットパターンをダンプ
  fn = ARGV[0]
  img = Image.load(fn)
  w, h = img.width, img.height
  dt = []
  h.times do |y|
    d = 0
    w.times {|x| d |= (1 << x) if img[x, y][0] > 128}
    dt.push(d)
  end
  p dt
  exit
end

# 与えられたデータから画像を作成する
def make_image_from_bitpat(dt)
  w = h = dt.length
  img = Image.new(w, h)
  h.times do |y|
    w.times {|x| img[x, y] = C_WHITE if ((dt[y] >> x) & 0x01) != 0}
  end
  return img
end

# ビットパターンデータ
data = [
  [2016, 2064, 2640, 6744, 6168, 2064, 2064, 2016, 2064, 6168, 10260, 18450, 20466, 1632, 576, 7224],
  [0, 2016, 2064, 2640, 23130, 22554, 18450, 18450, 10212, 6168, 2064, 2064, 4080, 1632, 576, 7224]
]

# 画像を作成
imgs = []
data.each {|d| imgs.push(make_image_from_bitpat(d))}

Window.minFilter = Window.magFilter = TEXF_POINT
Window.resize(320, 240)

cnt = 0
Window.loop do
  break if Input.keyPush?(K_ESCAPE)
  Window.drawScale(32, 32, imgs[(cnt >> 4) & 0x01], 4, 4)
  cnt += 1
end
ビットパターンで画像作成

DXRuby は色配列を渡すことで画像作成もできるのだけど、それだと配列の個数が多くなりそうで…。白黒のビットバターンだけにすれば、記述するデータ量も減らせそうだなと。 _JR-100の画面を見てると、それでも結構イケそうな気もしてくるし。

データをダンプするには以下のような感じで。
> ruby makebitpat.rb bitpat0.png
[2016, 2064, 2640, 6744, 6168, 2064, 2064, 2016, 2064, 6168, 10260, 18450, 20466, 1632, 576, 7224]

文字列をコピーして、上記のソースに貼り付けて、以下を実行すれば表示できる。
ruby makebitpat.rb

2013/12/28() [n年前の日記]

#1 [windows] Windowsの現在のホットキー一覧を確認できるツールは無いのだろうか

ここ最近、 _Screenpresso という画面キャプチャツールを時々使わせてもらっているのだけど。ホットキーの割り当てを確認したら、「別アプリがそのホットキーを使ってるから登録できねえよ」と表示されて。Shift + Ctrl + Printscreen なんだけど。

試しに押してみたら、どうも Evernote のキャプチャ機能に、そのホットキーが使われていたようで。

上記のソレを調べてる最中、「どのアプリが、どのホットキーを使用済みなのか、一覧表示してくれるツールがあったらなあ…」と思えてきて。この事例では、どうせキャプチャするツールが使ってるだろうから、と押してみたけど。迂闊に押せないホットキーだってあるよなと。そういう時、困るよなと。

ググってみたけど、これが全然見当たらず。

.lnk ファイルに割り当てられたショートカットキーを検索・一覧表示できるツールはあるらしいのだけど。現在実行中のアプリが、それぞれどんなホットキーを奪っているのか、分からんよなと。

技術的にできないことではないだろう、とも思うのだけど。何故なら、Screenpresso が、「そのホットキーは別アプリで使ってるようだよ」と言ってきたからで。もっとも、何のアプリが使っているのかまでは表示してないわけだから、使われてることは分かっても、使ってるアプリ自体は判別できないのかもしれない。

せめて、今現在空いているホットキーを一覧表示できれば、それだけでも助かりそうだけどなあ…。

#2 [pc] ネットに繋がらないと相談が

親父さんが、「PCがネットに繋がらない」と言ってきて。

自分のメインPC上では繋がってるので、ルータがコケてるとか、プロバイダが死んでるとか、そういうわけではナサゲ。親父さんPCだけの問題だろうと。

無線LAN子機は繋がっているか、と尋ねたら…。なんでも夜中にPCの前を通ったら、USBポートに刺さってる、ソレのLEDがずっと点灯してたので、気になってきて引っこ抜いてみた、という話で。その後、差し込み直したら、“しっかり”点灯しなくなったので、「これでよし」とそのままに…。

それじゃ繋がるわけないよな…。別のポートに差し込み直して、LEDが点灯したらネットに繋がるようになるはず、と伝えてみたり。

自分、そのあたり、説明してなかったのかな…。いや、説明しても忘れそうだよな。ネットなんて、繋がって当たり前、てな感覚だろうし。となれば、何を使ってネットに接続してるのか、なんてことも忘れてしまいそう。

M/Bに最初から無線LANのソレがついていれば、こういう問題は起きないのかもしれない。と思ったけど、そういったM/Bはアンテナが必要になるから、似たような問題は起きるのかもしれないか。メーカー製のPCなどは、そのへんどうやって解決してるんだろう。アンテナが出てるPCって、あまり見かけ…ないわけでもないな…。伸びてるやつは伸びてたような。

まあ、ノートPCを使ってもらえばいいのかもしれないけど。そっちなら全部入りだし。

2013/12/29() [n年前の日記]

#1 [anime][neta] マスコットキャラがラスボスてな設定はどうだろう

某アニメを見ていたら、幼女キャラの言動がなんだか怪しくて、「もしかしてこのキャラがラスボスなのでは…」「いや、このキャラは現実に存在してなくて、主人公が孤独に耐えきれず謎の力で作ってしまった存在なのでは…」てなバカ妄想を始めてしまったのだけど。

考えてみたら、マスコットキャラ的ポジションのキャラがラスボスだったりする設定ってどのくらいあるのかなと。意外と多いのか、少ないのか…。

プリキュアの主人公たちにくっついてるマスコットキャラがラスボスだったら…。いや、その設定も、既にいくつかあったような気もしてきたり。UMA自体がラスボスではないとしても、 赤ん坊とか鳥とかがラスボス、てな作品はあったような。…あ。考えてみたら、 まどかマギカが、そのまんまだったのか。まあ、ラスボスかというと、それはちょっと微妙だけど。

「その発想はなかったわ」的ラスボス設定って、何かあるだろうか…。

マクロスとかヤマトがラスボス、とか?

#2 [ruby] Rubyでzipファイルにアクセスする実験をしてみたり

rubyzipなるライブラリを使うと zip ファイルにアクセスできるらしいと知ったので、手元でも実験してみたり。 実験用スクリプトとzipをまとめたファイルも置いときます。→ _zip_extract.zip

_zip_open_rubyzip.rb
# zipファイルを開いて中にある画像ファイルを表示する。
# rubyzip使用版。
#
# rubyzip, dxruby, Ayame/Ruby が必要

require 'zip'
require 'dxruby'
require_relative 'ayame'

# zipファイルを開いて、中にあるファイルを読み取る
bindata = {}
Zip::File.open("res.zip") do |zipfile|
  zipfile.each do |f|
    name = f.name # ファイル名取得
    size = f.size # ファイルサイズ取得
    next if name =~ /\/$/ # ディレクトリは除外
    # puts "#{name} , #{size}"
    
    # bindata[name] = f.get_input_stream.read
    bindata[name] = zipfile.read(f.name)
  end
end

# 画像作成、サウンドデータの記録を行う
imgs = []
bgms = []
bindata.each_key do |fn|
  if fn =~ /\.png$/
    # 画像作成
    imgs.push(Image.loadFromFileInMemory(bindata[fn]))
  elsif fn =~ /\.ogg$/
    # サウンドデータを記録
    bgms.push(bindata[fn])
  end
end

# サウンドを再生
bgm = Ayame.load_from_memory(bgms[0])
bgm.play(0)

# メインループ
Window.loop do
  break if Input.keyPush?(K_ESCAPE)

  # 読み込んだ画像を全て表示
  x, y = 0, 0
  imgs.each do |img|
    Window.draw(x, y, img)
    y += img.height
  end
end
画像ファイルも表示できたし、oggの再生もできた。

処理速度は速いのか遅いのかよく分からないけど、とりあえず、一つにまとめたzipファイルから、画像やサウンドデータを取り出すことはできそうだなと…。

ただ、パスワードをかけたzipにアクセスする方法が分からず。rubyzip ではなくて、zipruby なるライブラリなら、パスワードつきzipにもアクセスできるみたいだけど…。そっちは Ruby 1.9 までの対応のようで…。

ziprubyも試してみたり。 :

一応は試してみるかなと。

_ziprubyをRuby1.9.3ではインストール出来ない → 出来た(インストール方法は最後に追記) - 趣味プログラマがまれになんかしたことの記録 を参考に、Ruby 1.9.3 上にインストール。
gem install zipruby1.9 --platform mswin32

パスワードを設定した zip を扱ってみたのだけど…。

_zip_open_zipruby.rb
# zipファイルを開いて中にある画像ファイルを表示する。
# zipruby使用版。パスワードつきzipファイルを対象にする。
#
# ただし問題有り。
# 一度パスワードを解除してしまうと、
# その後、別ツールでも平気で開ける zip になってしまう…。
#
# zipruby, dxruby, Ayame/Ruby が必要

require 'zipruby'
require 'dxruby'
require_relative 'ayame'

res_zip = "res_encrypt.zip"

# zipの解凍パスワード
passwd = "hogefugapiyo"

bindata = {}

# zipのパスワードを設定
# Zip::Archive.encrypt(res_zip, passwd)

# zipのパスワードを解除
Zip::Archive.decrypt(res_zip, passwd)

# zipファイルを開いて、中にあるファイルを読み取る
Zip::Archive.open(res_zip) do |ar|

  # ar.decrypt(passwd) # パスワードを解除
  n = ar.num_files # ファイル数を取得(ディレクトリも含む)

  # ファイル数分、繰り返す
  n.times do |i|
    entry_name = ar.get_name(i)
    ar.fopen(entry_name) do |f|
      name = f.name # ファイル名取得
      size = f.size # ファイルサイズ取得(展開後)
      comp_size = f.comp_size # ファイルサイズ取得(圧縮時)

      # puts "#{name} , #{size} , #{comp_size}"

      # ディレクトリの場合はサイズが0になる
      # サイズが0ではないなら、何らかのファイル
      if size > 0
        bindata[name] = f.read
      end
    end
  end
end

# 画像作成、サウンドデータの記録を行う
imgs = []
bgms = []
bindata.each_key do |fn|
  if fn =~ /\.png$/
    # 画像作成
    imgs.push(Image.loadFromFileInMemory(bindata[fn]))
  elsif fn =~ /\.ogg$/
    # サウンドデータを記録
    bgms.push(bindata[fn])
  end
end

# サウンドを再生
bgm = Ayame.load_from_memory(bgms[0])
bgm.play(0)

# メインループ
Window.loop do
  break if Input.keyPush?(K_ESCAPE)

  # 読み込んだ画像を全て表示
  x, y = 0, 0
  imgs.each do |img|
    Window.draw(x, y, img)
    y += img.height
  end
end
アクセスはできたのだけど、一度パスワードを解除してしまうと、その後は他のツールでもアクセス可能な、フツーの zip になってしまう…。

さりとて、一度アクセスした後で再度Rubyスクリプト中からパスワードを設定し直してみても、その次からはアクセスできない謎のzipになってしまって。うーん。

さらに、Ruby 2.0 では zipruby が使えないようで。
  • gem install zipruby してもエラーが出るし。
  • gem install zipruby --platform mswin32 をして、一見インストールできたように見えても、スクリプトを実行すると「zipruby.so がねえよ」と怒られる。
なかなか厳しい。

参考ページ。 :

#3 [pc] 親父さんPC上でTVが見れず

PT1機に接続しても映像がガクガクして見れなくて。

PT1機の調子がおかしくなってるのかなと思ったけど。そういや昨日、親父さんPC上で、USB接続の無線LAN子機を差し込み直したとか言ってたっけ…。無線LANの接続状態を見たら、電波が弱くて。

子機を隣のUSBポートに差し込み直したら、急に受信状態が良くなって、映像がなめらかに。たった数cm、場所を変えただけなのに…。いや、ポートの状態がアレなのかもしれないけど。

とりあえず、無線LAN子機の速度が出ない時は色んなポートに差し込んで確認してみるのもアリなのかなと。

#4 [anime] 境界の彼方、最終回を視聴

HDDレコーダに録画してあったソレをようやく消化。

作画凄いな…。それと、「パキン…」は、なんだかいいなと。ヴァルヴレイヴの「パキーン」「パキーン」もグッときた記憶があるけど。「パキン」とか「パキーン」とかその手の音って、何かの効果がありそうな気もしてきたり。…まあ、心が折れるとかそういうアレも、おそらくは「ポキン」「パキン」だろうし。これが「ボキッ」じゃダメだと思う。「パキン」「パキーン」じゃないと。…何書いてんだかわからんですな。でも、聞いた瞬間に切なくなる効果音ってあるんじゃないかと。

ラストのあたりに納得できず。もちろん、こういうラストにしておかないと、見てる側にとってはショボーンだろうから、これはこれでと思うのだけど。しかし、これでは…。さりとて、どうすればよかったのか、素人なりの案すら浮かばなくて。「まあ、しょーがねえよなあ」てな気持ちと、「いやー、でも、もうちょっとどうにかならんかったかな」てな気持ちの両方がモヤモヤと。

えてして、この手の娯楽コンテンツは、所詮は御都合主義、ではあるのだけど。そのように強く感じてしまうものと、それなりに納得できるものの差は、一体どこにあるのだろうと考え込んでしまったり。できれば後者の方がいいよなと。

何か伏線があれば違ったのだろうか。秘密が分かる回までは、アレコレちゃんと伏線を入れてあったのに、どうしてラストだけ、そういう手管が急に消滅してしまったのだろう…。シリーズ構成・脚本では、あのラストシーンは存在しなかったけど、監督がどうしても気に入らなくて、コンテ段階でで追加した、とか。まあ、ちゃんと伏線は入ってるけど、自分が未だに気付いてないだけの可能性もあるのだけど。わざわざ主人公にアイテム持たせているのだから、そこに設定がありそうだよなとも。

2013/12/30(月) [n年前の日記]

#1 [anime] アニメミライ作品を視聴

BSフジで放送されてたアニメミライ作品を視聴。「リトル ウィッチ アカデミア」「わすれなぐも」「デスビリヤード」「アルヴ・レズル」「万能野菜 ニンニンマン」を一挙放送、だったかな…。たしかそのはず。

個人的には、「リトル ウィッチ アカデミア」「わすれなぐも」「デスビリヤード」が、かなり面白かったなと。

「リトル〜」は、魔女を育成する学校を舞台に、てな話。TRIGGER作品なだけあって、元気一杯な感じで。Kickstarterで続編制作?資金が集まったらしいけど、なんだか納得。たしかにコレは、続きを見てみたくなるよなあ…。

「デスビリヤード」は、よくわからないバーに連れてこられた二人が命をかけたビリヤードをさせられる、てな話。視聴者の想像にお任せします的なソレが仕込んであって、そのあたりが面白いなと。さらに、若者役を担当してた声優さんの迫真の演技もグー。マクロスFや氷菓の主人公役をやってた方らしいけど、心の底から叫ぶ、みたいな演技が、めちゃくちゃ上手いなと…。

「わすれなぐも」は、古書の中にとある○○が、てな話。この作品、個人的に、かなりお気に入り。おそらく30分前後の作品だろうに、たったそれだけの時間で、自分も完全に絡めとられてしまった気がしてきたり。あのキャラ、可愛い。その分、恐ろしい。なんだか「観用少女(プランツドール)」を思い出したりもして。ああいう作品は好きなのです。「わすれなぐも」も「観用少女」も、小説・漫画・アニメじゃないと成立しない作品だよなと。こういうのは実写ではちと成立しにくい。「カリ城」の「クラリス」とか、「うさぎドロップ」の「りん」とか、そういう可愛さって実写じゃ難しいだろうと。「わすれなぐも」は、ああいうソレを出してくる作品だよなと。

「アルヴ」と「ニンニンマン」はノーコメント。若手育成云々と言うアニメミライの目的が達成できていれば、それでOKなのではないかと。

とにかく、「わすれなぐも」を見れただけでも良かった、と思えたり。この作品は、素晴らしい。や、単に自分にとってチョー好みなだけ、なのですけど。

全然関係ないけど、「わすれなぐも」を見た後で、「『境界の彼方』もこういう方向なら、納得できるラストになったんじゃないか」と思えてきたり。…いや。それ、どうなんだろ。自分はそういうの好きだけど、たぶんフツーの人は見ていて怒るんじゃないか。うーん。

#2 [ruby][python] 画像を難読化してみる

画像に変な難読化をかけてみる実験。

とりあえず、Python 2.6.6 + PIL(Pillow)を使って、読み込んだ画像を難読化。

_imgcrypt.py
#!/usr/bin/env python
# -*- coding: utf-8 -*-
u"""
画像に変な暗号化をかけてみるPythonスクリプト

PIL(Pillow)を使用。

Usage:
    python imgcrypt.py IN_IMAGE OUT_IMAGE

"""

import sys
import os
from PIL import Image

next = 1

def rand():
    u"""乱数生成器(C言語のソレ)"""
    global next
    next = (next * 1103515245 + 12345) & 0xffffffff
    return int((next / 65536) % 32768)

def srand(seed):
    u"""乱数初期化。種を渡す。"""
    global next
    next = seed

def encrypt_image(img):
    u"""画像を難読化。Imageを渡す。"""
    outimg = img.copy()
    w, h = img.size
    srand(0)
    for y in range(h):
        rx = rand()
        for x in range(w):
            c = img.getpixel(((x + rx) % w, y))
            outimg.putpixel((x, y), c)
    return outimg

def decrypt_image(img):
    u"""画像の難読化の解除。Imageを渡す。"""
    outimg = img.copy()
    w, h = img.size
    srand(0)
    for y in range(h):
        rx = rand()
        for x in range(w):
            c = img.getpixel(((x - rx) % w, y))
            outimg.putpixel((x, y), c)
    return outimg

def main():
    if len(sys.argv) < 3:
        print "Usage: python %s IN_IMAGE OUT_IMAGE" % \
            os.path.basename( __file__ )
        sys.exit()

    inimgfn = sys.argv[1]
    if not os.path.isfile(inimgfn):
        print "Not Found %s" % inimgfn
        sys.exit()

    outimgfn = sys.argv[2]
    img = Image.open(inimgfn, "r")

    outimg = encrypt_image(img)

    if True:
        # 画像を保存
        outimg.save(outimgfn)
        print "Output %s" % outimgfn
    else:
        # 画像を表示して確認
        outimg.show()
        decrypt_image(outimg).show()

if __name__ == '__main__':
    main()
python imgcrypt.py image0.png image0_out.png
python imgcrypt.py image1.png image1_out.png
画像の難読化も Ruby でやらなかったのは、Ruby でアルファチャンネルつきのpngが出力できるかどうか不明だったので…。Python + PIL(Pillow)ならできることは知ってたので、そちらを使ってみた次第。

以下のような画像になった。とりあえず、コレを見てどんな画像か理解できる人は、まず居ないだろうと。

image0_out.png
image0_out.png

image1_out.png
image1_out.png


これを Ruby + DXRuby で読み込んで元に戻して表示する。

_imgdecrypt.rb
# 画像の難読化を解除して表示するRubyスクリプト
#
# DXRuby を使用

require 'dxruby'

$next = 1

# 乱数生成器(C言語のソレを再現)
def c_rand
  $next = ($next * 1103515245 + 12345) & 0xffffffff
  return (($next / 65536) % 32768).to_i
end

# 乱数初期化。種を渡す
def c_srand(seed)
  $next = seed
end

# 画像の難読化を解除
def decrypt_image(img)
  w, h = img.width, img.height
  outimg = Image.new(w, h)
  c_srand(0)
  h.times do |y|
    rx = c_rand()
    w.times do |x|
      outimg[x, y] = img[(x - rx) % w, y]
    end
  end
  return outimg
end

img0 = Image.load("image0_out.png")
img1 = Image.load("image1_out.png")
img0 = decrypt_image(img0)
img1 = decrypt_image(img1)

Window.loop do
  break if Input.keyPush?(K_ESCAPE)

  Window.draw(0,0, img1)
  Window.draw(0,0, img0)
end
ruby imgdecrypt.rb

以下のような結果に。

imgdecrypt.rbの実行結果


ちゃんと元の画像に戻せましたな。アルファチャンネルも有効になってる。(ポスト画像がアルファチャンネルを使用。)

もっとも、LLのソースを眺めることができる=どんな難読化をしてるのか容易に分かってしまうので、この手のソレをする意味なんてどの程度あるのか、という気もしますが。まあ、非プログラマーの方に御褒美画像をそのまま見せない、ということぐらいなら、使えるのかもと。

参考ページ。 :

乱数生成器(線形合同法)は、以下の記事をそのまま使わせてもらいました。

_Algorithms with Python / 乱数

周期性がある疑似乱数らしいけど、とりあえず Python と Ruby で同じ結果が出てくる簡素な疑似乱数が欲しかったので…。もっとも、Python の乱数(Random)もMT法らしいので、書き方次第で前述のソース内の乱数生成器部分は丸々削除できるかもしれませんが。

2013/12/31(火) [n年前の日記]

#1 [dxruby] DXRubyのSpriteを勉強中

Spriteクラスの衝突判定について簡単なサンプルを書きながら勉強中。とりあえず、Sprite.check(攻撃側Spriteの配列、守備側Spriteの配列) を呼べば、Spriteを継承したクラスの、shot()、hit() が呼ばれるらしいと分かったり。その中に、当たった時の処理を書けばどうにかなるらしい。

スプライトの基準座標が左上座標に固定されてるあたりがしっくりこなかったのだけど。DXRuby開発版なら、self.offset_sync = true を設定してやることで、画像の拡大縮小回転の中心位置を基準座標として扱えることを今頃知ったり。コレ、正式公開版に反映されたら嬉しいのだけど…。とりあえず、DXRuby 1.4.0 に該当機能は無いので、手元のサンプルでは基準座標+オフセット値を表示座標としてわざわざ設定したり。…そういや、開発版のソレって、アタリ範囲はどうなるんだろう。

さらにDXRuby開発版には、Sprite#flush(色配列) で、フラッシュ画像を生成できるメソッドも追加されていて。先日、自前でフラッシュさせようとしてたソレを、メソッド一発でできるようになるのはありがたいなと。コレも、正式公開版に反映されたら以下略。

とりあえず以下のような感じに。

_sprite_test2.rb
# スプライトの衝突判定動作テスト

require 'dxruby'

font = Font.new(12)

# 画像読み込み
base64_text = ""
DATA.each {|l| base64_text += l.chomp}
bin_data = base64_text.unpack('m')[0]
$imgs = Image.loadFromFileInMemory(bin_data).sliceTiles(8, 1)

# enemyshotimgs = [$imgs[3], $imgs[4], $imgs[5]]

# 度→ラジアン変換
def deg2rad(deg)
  return deg * Math::PI / 180.0
end

# ----------------------------------------
# プレイヤーキャラ
class Player < Sprite
  attr_accessor :bx, :by, :shottimer, :hit_timer, :flush_image

  # 初期化処理
  def initialize(x, y)
    super
    self.bx = x
    self.by = y
    self.image = $imgs[1]
    self.flush_image = $imgs[7]
    self.shottimer = 0
    self.collision = [16, 16, 4] # アタリ範囲を設定
    self.hit_timer = 0

    # self.offset_sync = true # DXRuby開発版でのみ使えるプロパティ
  end

  def update
    w, h = self.image.width, self.image.height

    # マウスカーソル座標を自機座標にする
    self.bx = Input.mousePosX
    self.by = Input.mousePosY

    xmin, ymin = 0, 0
    xmax, ymax = Window.width, Window.height
    self.bx = xmin if self.bx < xmin
    self.by = ymin if self.by < ymin
    self.bx = xmax if self.bx > xmax
    self.by = ymax if self.by > ymax

    if self.shottimer % 10 == 0
      # 自機ショットを発射
      [270, 30, 150].each do |i|
        spr = Shot.new(self.bx, self.by, 16, i + self.bx / 4)
        $shots.push(spr)
      end
    end

    self.shottimer += 1
    self.angle += 8

    if self.hit_timer > 0
      self.hit_timer -= 1
      self.hit_timer = 0 if self.hit_timer <= 0
    else
      self.hit_timer = 0
    end

    # 基準座標+オフセット値を表示座標とする。
    # DXRuby開発版なら、self.offset_sync = true で済んでしまうのだけど、
    # 開発版は Ruby 1.8 や 1.9 に対応してないので…
    self.x = self.bx - w / 2
    self.y = self.by - h / 2
  end

  # 雑魚敵と当たった時に呼ばれる処理
  def hit(o)
    self.hit_timer = 4
  end

  def draw
    super
    if self.hit_timer > 0
      Window.drawScale(self.x, self.y, self.flush_image, 3, 3)
    end
  end
end

# ----------------------------------------
# プレイヤーの弾
class Shot < Sprite
  attr_accessor :bx, :by, :dx, :dy

  def initialize(x, y, spd, angle)
    self.bx = x
    self.by = y
    self.image = $imgs[0]
    self.dx = spd * Math.cos(deg2rad(angle))
    self.dy = spd * Math.sin(deg2rad(angle))
    self.angle = angle
    self.collision = [0, 13, 31, 18]
    self.collision_enable = true
    self.collision_sync = true
  end

  def update
    w, h = self.image.width, self.image.height
    self.bx += self.dx
    self.by += self.dy

    # 画面外に出たら自分を消滅させる
    xmin = - w / 2
    ymin = - h / 2
    xmax = Window.width + w / 2
    ymax = Window.height + h / 2
    if self.x < xmin or self.x > xmax or self.y < ymin or self.y > ymax
      self.vanish
    end

    self.x = self.bx - w / 2
    self.y = self.by - h / 2
  end

  # 敵に当たった場合に呼ばれるメソッド
  def shot(d)
    self.vanish # 自分を消滅させる
  end
end

# ----------------------------------------
# 雑魚敵
class Enemy < Sprite
  attr_accessor :bx, :by, :dir, :dx, :dy
  attr_accessor :hit_timer, :spd, :org_image, :flush_image

  def initialize(spd)
    self.org_image = $imgs[2]
    self.image = self.org_image
    self.flush_image =  $imgs[3]

    # DXRuby開発版でのみ利用可能。フラッシュ画像を作れる
    # self.flush_image = self.org_image.flush(C_WHITE)

    self.spd = spd
    self.collision = [0, 0, 31, 31]
    self.init
  end

  # 発生時の初期化処理
  def init
    self.bx = rand(Window.width)
    self.by = rand(Window.height)
    self.collision_enable = false
    self.collision_sync = false
    self.hit_timer = 0
    self.alpha = 0
  end

  # 更新処理
  def update
    w, h = self.image.width, self.image.height

    if self.alpha < 255
      # 出現中
      self.collision_enable = false
      self.alpha += 5
      if self.alpha >= 255
        self.alpha = 255

        # プレイヤーを狙った速度を決める
        ply = $players[0]
        self.dir = Math.atan2(ply.by - self.by, ply.bx - self.bx)
        self.dx = spd * Math.cos(self.dir)
        self.dy = spd * Math.sin(self.dir)
      end
    else
      # 移動中

      if self.hit_timer > 0
        # 弾が当たっているなら一定時間フラッシュさせる
        self.hit_timer -= 1
        self.collision_enable = false

        # フラッシュ時間が終わったら再発生
        self.init if self.hit_timer <= 0
      else
        # 弾は当たってない
        self.hit_timer = 0
        self.collision_enable = true

        # 移動
        self.bx += self.dx
        self.by += self.dy

        # 画面外に出たら再発生
        xmin = - w / 2
        ymin = - h / 2
        xmax = Window.width + w / 2
        ymax = Window.height + h / 2
        if self.x < xmin or self.x > xmax or self.y < ymin or self.y > ymax
          self.init
        end
      end
    end

    self.image = (self.hit_timer <= 0)? self.org_image : self.flush_image

    self.x = self.bx - w / 2
    self.y = self.by - h / 2
  end

  # プレイヤーの弾と当たった時に呼ばれるメソッド
  def hit(o)
    self.hit_timer = 4
  end

  # プレイヤーと当たった時に呼ばれるメソッド
  def shot(d)
  end
end

# ----------------------------------------
# メイン

# Input.mouseEnable = false # マウスカーソル非表示

srand(0)
$players = []
$shots = []
$enemys = []
$players.push(Player.new(0, 0))
8.times {|i| $enemys.push(Enemy.new(2))}

in_pause = false

Window.loop do
  break if Input.keyPush?(K_ESCAPE)

  update_enable = false
  if in_pause
    # ポーズ中

    # Nキー押しで1フレーム進める
    update_enable = true if Input.keyPush?(K_N)

    # Pキーを押したらポーズ解除
    in_pause = false if Input.keyPush?(K_P)
  else
    # 通常処理
    in_pause = true if Input.keyPush?(K_P) # Pキーを押したらポーズ
    update_enable = true unless in_pause
  end

  if update_enable
    # プレイヤーの弾と雑魚敵の衝突判定
    Sprite.check($shots, $enemys)

    # 雑魚敵とプレイヤーの衝突判定
    Sprite.check($enemys, $players)

    Sprite.update($players)
    Sprite.update($shots)
    Sprite.update($enemys)

    Sprite.clean($shots)
    Sprite.clean($enemys)
  end

  Sprite.draw($enemys)
  Sprite.draw($players)
  Sprite.draw($shots)

  l = $players.length + $shots.length + $enemys.length
  Window.drawFont(0, 0, "Sprs: " + ('■' * l), font)
  Window.drawFont(0, 16, "PAUSE", font) if in_pause == 0
end

__END__
iVBORw0KGgoAAAANSUhEUgAAAQAAAAAgCAMAAADKd1bWAAAAwFBMVEV/AACg
AADAAADgAAD/HBz/cHD/qKj/xMT/4OAAwAAMdwBN/03/////Ziv/hk3/p3D/
x5OROADaLAAwMDBgYGCUlJSwsLDg4ODExMT///+goKSyAKwAAAAAAAAAAAAA
AAD/////ior/KyubAAD/////u4n/mSuacwDLy8vvdi7EUgCJBgD/Kyv/biv/
dCv/uSsAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAACCWjOjAAAAHHRSTlP/////////////////////////////////
//8AF7Li1wAAA0tJREFUeJzlmd2SokAMhbVquNhdB91tcKW4USj1wkLe/+02
P40ESDN2iyNbnuJiTKYczjdJaLoXuYfSdAdK005wJ6UEMinMDwLfpsJKxhY+
X2ASIJAmRsa20q4xg0CW9QwPAt8ksv4J6jLwAoAIuvbB7zZtRQC6gZkAYPcV
iRnYhBcArQXArzE6AIjPBQDZv8anGHSKr4SAM4+3AADYOQDs5gIA/V/jeL0+
gtbrGBA0BN6iBfDfD/aPG/64OQICLAL88HAL5InpKukEBoZf478C+zIECCom
8HAL5H/FyG/UhmYAAOu/558IcBdMMQOaajdmScKfXC0wTgCnc1m6bwBn+OXi
zteg87kX1Pw3BCYEQPY/UIwgAECzTnEhqKxc+dqqm6f5N/APBGgSegGA/say
Towk0AJYfkQoQhACoCgOh8MIgaqC/AiBuob8kAAVgPb7XAIeAND/T1CXgAVA
/rOsT8ADAPrfjxBA//sRAuh/rxBwFIAtga8BpIYvQ/5/gIgAGMzpagFE6IcJ
BAGA+99bAioAm3cCsPkeACqAjeZsQyWgA9iw8PbShC8Q+P8FQgKgNKdrawc/
FUCnBFj3AoAC2KNcJQAFwHlHCUABcL5XAkVRndQOgB44VQoAXC+B2D/c344W
dLjWI/+rFRHAj4auvAVgW6AD4O7HYCErQAfQVoAOoK0ACQDWAGoHYA/AWmDx
m/QHhG9KnzGJCPAdwtCjCwQAViAEQMOQLv6u2wgUAOTfGvVuAYgZoAIQM0AF
IGbAqwFEYQBuTwHwrwG4PQUqJV/X7VOgLj0A9KPeLWAXgbAGuPnPIgSgbYi4
KZSFkGLwUgkp+XMt9AgAks8QbAA0BKABomUD4P4h+DQAvkOwr/sfgx+s0HVA
Oeof8qP+Ia/6D3wMqvpqIcQEoP55MewNoBT+NYOl8K/mhf8JF0I9AmNLYUYQ
LZdhS+GSEZS6P8o39l35xv5zlsJ3vAw1CnsZKm/S/3xYfsKXIX0/QO5/tK/D
YRsiY/aC809+HX6rDRHHrrDcAhSbIQEbIs/RdFtib78p6toWn/25wFTb4q6D
kdmfC0x1MPK/tkA+1dGY2gLdU4FBYCYApjkcVQ9Gev4HgYHd1/hHacfj/wAC
/D82nEMmSwAAAABJRU5ErkJggg==

実行結果。
実行結果


オブジェクトについて、画面外に消えるたびに破棄したり、一定時間毎に生成してるあたりが、ちょっと気になる…。オブジェクトの生成と破棄って時間がかかるらしいから、最初に使う分を確保して、それを使い回したほうがいいのかなと…。

このあたり、双方向リストで管理すれば、実行するオブジェクトと、実行せずに溜めておく空きオブジェクトを、即座に登録・解除できるのだけど…。実は DXRuby の内部でソレに近いことをやってたりしないのかな、という疑問も。タスクマネージャでプロセスを見ていても、メモリ使用量が増えているようには見えないし…。

この記事へのツッコミ

Re: DXRubyのSpriteを勉強中 by takaranotou    2017/07/10 17:17
getyerdrgkhuykhim;

以上、31 日分です。

過去ログ表示

Prev - 2013/12 - Next
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30 31

カテゴリで表示

検索機能は Namazu for hns で提供されています。(詳細指定/ヘルプ


注意: 現在使用の日記自動生成システムは Version 2.19.6 です。
公開されている日記自動生成システムは Version 2.19.5 です。

Powered by hns-2.19.6, HyperNikkiSystem Project