微分積分学(初等の解析学)やるときに大事っぽい式

ポストモダン解析学を読んでいたら、イプシロンデルタ論法の性質で単独でまとめられてもいんじゃねって思ったのがいくつかできたので書きます。多分、微分積分の教科書の行間埋めに役立つんじゃないかと。「かつ」は楔(くさび)の記号\wedgeで表わしてます。あと、PとかQとかは、括弧のなかの文字の関係について述べる*1命題をさします。

2つのイプシロンデルタの式を結びつける

\left(\left(\exists N; \forall n \ge N; P(n)\right) \wedge \left(\exists M; \forall m \ge M; Q(m)\right)\right) \Rightarrow \exists L; \forall l \ge L ; \left(P(l) \wedge Q(l)\right)
lをnとmとのうち、大きいほうをとれば満たされる。2つ以上のイプシロンデルタの命題を結びつけてひとつにしたいときに使う。たとえば、実数列\{a_n\}\lim_{n\rightarrow \infty} a_n = aと収束するとき、
\lim_{n\rightarrow \infty} \frac{a_1 + a_2 + \cdots + a_n}{n}=aを示せ、みたいなときにつかえるはず。

「小さい」のイメージ

fは常に0以上として、P(\epsilon) \Leftrightarrow \exists N; \forall n\ge N; f(n) \le \epsilonとすると、0\le a\le b \wedge P(a) \Rightarrow P(b)がなりたつ。

よく教科書とかにしれっと書いてある、「εは十分小さいので、\epsilon < 1としてよい」みたいなやつの根拠になる。そこで示せたなら、このことによりそれより大きいところは自動的に証明されたことになる。

イプシロンを加工してよい

\left(\forall \epsilon; P\left(\epsilon\right)\right) \Rightarrow \left(\forall \epsilon; P\left(f(\epsilon)\right)\right)
例えばなりゆきで2\epsilonとかで最後の評価をしてしまったときとかに使える。さっきのと組合せて。

訂正

\left(\lim_{n\rightarrow\infty}b_n=0 \wedge \exists N; \forall n\ge N |a_n-a| \le b_n\right)\Rightarrow \forall \epsilon \exists N \forall n\ge N |a_n-a|\le \epsilon
特に、
\left(k\ge 0 \wedge \forall \epsilon \exists N; \forall n\ge N |a_n-a| \le k\epsilon\right)\Rightarrow \forall \epsilon \exists N \forall n\ge N |a_n-a|\le \epsilon

要するにいくらでも縮むもので差を抑えられれば、εで直接に抑えなくてもいいという話。なりゆきで2\epsilonで抑えちゃったときとかの合法化に使える。あと、εで抑えるところでは<\leかを気にしなくてよい、ということも保証する。

全称と存在の交換

\left(\exists a; \forall b; P(a,b)\right) \Rightarrow \forall b; \exists a; P(a,b)
一様連続性から普通の連続性まで情報を落して使うときに。

*1:使わない文字があってもよいが、他の変数には依存しない

変数スコープに関する初歩的なミスで詰んでた

なんか書いてるjsのコードでの問題が切り離せたので備忘録に。

    var array = [];
    
    for(var i=0; i < 3; i++){
      console.log("i=", i);
      array.push(function(){
        console.log("in function ", i);
      });
      array[i]()
    }

    console.log(array.length);
    for(var j=0; j < array.length; j++){
      console.log("run function no.", j);
      array[j]();
    }

こういうコードで、最後の配列に入った関数を実行するときに、

run function no. 0
in function 0
run function no. 1
in function 1
run function no. 2
in function 2

となることを期待していたというのが本質のバグ作ってた。このコードの最後は実際は、

run function no. 0
in function 3
run function no. 1
in function 3
run function no. 2
in function 3

と実行される。「なんで"i<3"なのにi=3になってるんだよ!」という類のことで悩んでいたのだが、カウンタが生きているならば、forが終ったあとはその制約の一個次になるんだったなあと高校のBASICの授業を思いだす。

DIM I

FOR I = 0 TO 3
  PRINT I
NEXT
PRINT I

みたいに書くと(正確な文法忘れた)

0
1
2
3
4

となるはず

追記

"JavaScript: The Good Parts"のクロージャの章に全く同じの載ってました。結局こう直します。

    var array = [];

    for(var i=0; i < 3; i++){
      array.push(function(j){
        return function(){
          console.log("in function (revised): ", j);
        };
      }(i));
    }

    for(var j=0; j < array.length; j++){
      console.log("run function no.", j);
      array[j]();
    }

すごいH本のチェスの演習問題書いた

「すごいHaskellたのしく学ぼう!」の308ページの、3手で到達できるときその途中経路を出力する演習問題を書いてみた

import Control.Monad

type Route = [(Int, Int)]

routeStart :: (Int, Int) -> Route
routeStart x = [x]

inBoard :: Route -> Bool 
inBoard (x:xs) = x `elem` [(a,b) | a <- [1..8], b <- [1..8]]

possibleRoute :: Route -> [Route]
possibleRoute all@((x,y):xs) = do
  (dx,dy) <- [(2,1), (-2,1), (2,-1), (-2,-1), (1,2), (1,-2), (-1,2), (-1,-2)]
  let p = (x+dx, y+dy)
      r = p:all
  guard $ inBoard r
  return r

canReachIn3 :: (Int, Int) -> (Int, Int) -> [Route]
canReachIn3 s g = filter (\x -> head x == g)
                  (return (routeStart s) >>= possibleRoute >>= possibleRoute
                  >>= possibleRoute)

数学は若いころしか出来ない系語録(適当に更新)

いろいろためていってSAN値を下げていこう。随時募集中。

「若いころしか出来ないから急いだほうがいい、例外はあるけど」

うろおぼえ。「怠け数学者の記 (岩波現代文庫)」だったと思う。あと、小平邦彦が言ったわけではなくて、小平さんがプリンストンにいたときに一級の数学者の誰かに言われた言葉だったと思う。

「若くて一番頭のいい時期に数学をやり、少し悪くなったところで哲学をやり、それも出来なくなって歴史をやった。」

ラッセルらしい。

Amazon,ある数学者の生涯と弁明


ここのレビューから。

「かつてはあったがもう二度と帰って来ない創造的能に対する熱烈な嘆き」

Wikipedia,ある数学者の生涯と弁明

カナダ式キーボードでバックスラッシュを打つ

フランス語でTeXやろうとしたらバックスラッシュをどう打つかわからなかったのでメモ。

アクサンの入力

カナダキーボードでは本来はAltGr(AltCar)キーとナンバーキー(?、#キー。)を打てばよいのだが、日本語キーボードではそれぞれ右Altと半角全角キーに対応しているので、右Altを押しながら半角全角を押せばよい。が、うちには右AltがなかったのでKeySwapを使ってひらがなキーを右Altにした。

ギュメ(引用符)の入力

スクリーンキーボードには出ているが対応するキーがよくわからなかったのでEmacs上で何とかしようと思います。キーボードマクロでなんとかしましたが、できあがったものはとにかくこれです。

.emacsのなかに

(load-file "~/french.macs")

homeのfrench.macsに

;; -*-coding:iso-8859-1-*-

(fset 'insert-guillemet
[?« ?» ?\C-b])

としました。ファイル分割しないと文字コードが面倒なのです…


Emacs上でのエンコーディング

%% -*-mode: yatex; coding:iso-8859-1-*-

をつけて保存しました。

TeXでLatin-1を使う

とりあえずこのへん(http://www.tuteurs.ens.fr/logiciels/latex/manuel.html)を参考にいろいろくっつけて、

\usepackage[latin1]{inputenc}
\usepackage[francais]{babel}
\usepackage[cyr]{aeguill}
\usepackage[T1]{fontenc}

とした。何が何かは後で調べよう。

TeXにかます

pLaTeXがsjisにしか対応しないらしくあれなのでLaTeXにやったらうまくいった。

画面遷移構造雑考(一応完結)

Bonjour!前回の更新からもう200日近くたっているようです。あれまあ。最近はC#+XNAでいそいそゲーム開発駆け出しをしていて、今はライブラリ整備をしているのですが、遷移構造のところで霧中になってしまったので、書いて整理をしたいと思います。

定義

「画面遷移」という言葉は割りとポピュラーなようですが一応自分の確認のためにも定義を確認してみます。ゲームにおいては、大きく画面の見た目と機能が変わることがあります。たとえば、タイトル画面で"Press Any Key"と出ているときに何らかのキーを押せばたぶんメインメニュー画面に飛ぶでしょう。タイトル画面においては画面上で何か動かす処理やら、キーに反応してメインメニュー画面に飛ぶ処理やらが要求されますし、メインメニュー画面においては矢印キーで項目を選択したり、項目を表示する機能が要求されるでしょう。このように、タイトル画面の処理とメインメニュー画面の機能には明らかに関連が薄いので、これらの処理を一箇所にまとめて書くのはコードの可読性からして問題だと思われます。そこで、画面の状態で明らかに違うように分けたとき、それらの画面を互いに(何らかの規則にしたがって)移り変わる構造のことをこの記事の中では「画面遷移」と呼ぶことにします。

なぜこれのことで悩む必要があるのか。いい加減に作ればいいのではないか。

確かにいい加減に作って問題が出てから直せばいい、悩んだって徒に時間を消費するだけだというのはそんな気もするし、今のモットーとして「できるだけ小柄に」を採用しているのではっきり言って真理なのですが、ここであえてじっくり悩んだほうが良いと考える理由は次のとおりです。

画面遷移構造はどんなゲームにも出てくる

ミニゲームにしてもタイトル画面、ゲーム画面、リザルト画面の3つは出てきますし、何を作るにしても画面遷移から目を背けている間ずっと苦しむことになります。

可読性にたぶん効いてくる

「困難は分割せよ」は理系の基本ですが、画面遷移を上手に作れば画面ごとに分けてプログラムを書くことをプログラマに推奨することが出来る、というわけで眠いときにプログラムを書いてもそこそこ可読性の高いものを書くことが出来る、はず。

pygame時代の反省

pygame時代に安直に組んだら(あれはあれでそこそこ使えたのですが)もっと複雑なものを作ろうとすると面倒なことになるということが当時わかったのですがその問題点については後述。

考えてみる

ざっくり考えてみる

まず前提として、ゲームは主に描画をつかさどるDrawメソッドとロジックをつかさどるUpdateメソッドとから成っています。というわけで、SceneクラスにDrawメソッドとUpdateメソッドを持たせて、メインのところにSceneの変数CurrentSceneを持たせ、そのSceneを次々取り替えていき、メインのDrawとUpdateからCurrentSceneのDrawとUpdateを呼び出せば作れそうです。

どう実現するか

いきなり閑話休題なのですが、これをXNAでどう実現するかが不安なので少し考えてみます。いまいちXNAのフィロソフィー*1がよくわからないのですが、基本的にゲームで扱うもの全般はGameComponentというものらしく、それをGame.Components(ComponentsはGameComponentのCollection)にAddすると有効になるみたいな雰囲気みたいです。DrawableGameComponentというGameComponentを継承したクラスはUpdateとDrawを持っていて、Addしておくと自動的に呼んでくれます。というわけで登場人物的なものはGameComponentを主軸に書いていくことを考えています。もっといい方法(というかXNA開発者の意図した方法)を知っている人がいたら教えて下しあ><。問題はGame.Componentsがデフォルトでは1個しかなく、これに階層構造を持たせる方法も見たらないので、これをどう扱っていくかというところになりそうです。(そしてこの基本方針が一番怪しい。

そういうわけで、各SceneにIsDeadみたいなメソッドを持たせて、メインのUpdateからそのIsDeadを呼び出し、そのSceneがすでに終了したことがわかったらそのSceneに所属するGameComponentをSceneから取得してそれらをGame.Componentsから削除し、またそのSceneから次のSceneを受け取ってそれをメインのCurrentSceneに代入して作ればよさげです。*2

遷移エフェクトについて考えてみる

ところでこのまま実装するとたぶん画面が一瞬で切り替わってしまいますが、普通画面が切り替わるときは画面がゆっくり暗転するなりの画面の移り変わりのエフェクトがかかるものです。パワーポイントをご存知の方は「ワイプアウト」などを想像していただければそれです。というわけでそれを組み込むことを考えてみます。画面遷移時に遷移前のSceneと遷移後のSceneの両方にアクセスすることが考えられるので、先ほどあったCurrentSceneのほかにPreviousSceneも必要になりそうです。またSceneは、今自分が遷移中でCurrentSceneであるのか遷移が終わってCurrentSceneであるのかPreviousSceneであるのかを区別する方法が必要になります。うち、PreviousSceneであるかどうかは、そのSceneを終わらせるかの裁量はそのSceneにあるわけで、それを示すのがIsDeadでしたから明らかですが、遷移中でCurrentSceneであるのか遷移が終わってCurrentSceneであるのかの情報は遷移をつかさどるものに裁量があるはずです。というわけで、いったんこの「遷移をつかさどるもの」をどのように作るべきかを考えるのがよさそうです。

と、一瞬思ったのですが

CurrentSceneだけでなんとかなる気がしてきました。つまり、Scene甲がその役目を終えたときに、そのScene甲を次のScene乙に渡してしまい、CurrentSceneをScene乙にして、遷移エフェクトはScene乙に担わせればそれでいいような気がしてきました。そして、Scene乙は遷移が終了したときにScene甲を破棄します。このほうがすっきりしていますし、「ざっくり考えてみる」で考えたところからたいした変更なしに実現できそうです。一応、Scene甲はScene乙を生み出して参照せずにメインに渡しますし、Scene乙はScene甲を参照するだけなので、相互参照にはなっていないはずですが、破棄タイミングは不安です。そういうわけで、SceneがPreviousSceneを持つことになりそうです。

どう実現するか

二つの画面を扱うということは、それぞれのSceneについて、その画面を直接にスクリーンにアウトプットするわけには行きません。具体的に考えればすぐにわかる話で、たとえば簡単そうなワイプアウト、つまりScene甲の画面が徐々に左に押し出されていき、Scene乙の画面が右からScene甲を押し出すように入ってくるような遷移エフェクトを考えれば、直接にScene甲やScene乙の画面がスクリーンに直接アウトプットされると、そのアウトプット位置が制御できないためにワイプアウトは実現できなくなってしまうことがわかると思います。というわけで、少なくとも画面遷移中はScene甲や乙の画面は画像としてアウトプットされ、その画像を配置するという風にしないと実現しえません。画像の出力先を2DテクスチャであるTexture2Dにするためには、
http://stackoverflow.com/questions/8425922/draw-a-string-to-texture-in-xna
この辺のことを使えばいいと思うのですが、この辺で煮詰まったのでまた後で。

一度Componentsについて考えてみる(そして昨日煮詰まった原因)

なんかComponentsのなれない仕様に惑わされている気がするので、一度Componentsについてまとめなおしてみます。Game.ComponentsはGameComponentCollectionであって、MSDNhttp://msdn.microsoft.com/ja-jp/library/microsoft.xna.framework.game.components%28v=xnagamestudio.40%29.aspxによれば、

ゲームに対してゲーム コンポーネントを登録するには、対象のコンポーネントを Game.Components.Add に渡します。登録されたコンポーネントは、Game.Initialize、Game.Update、および Game.Draw メソッドから呼び出される描画、更新、および初期化メソッドを持ちます。

とのことなので、描画、更新のするされないはComponentsに含まれているいないで決まるわけです。(本当はGameComponentのVisibleをfalseにしてしまうととまるのですが、使わないものがコレクションに居座っているのも気持ちが悪いので、これに関しては心の片隅に止めつつなかったものとして考えて見ます。)このことを意識しておくと、(抽象的な言葉遣いになってしまうのですが)Sceneは基本的にはGameComponentを包むものであって、SceneがComponentsへSceneの保有するGameComponentを出し入れするという使い方が基本になりそうです。

おそらく(自分のことなんですけどね)昨日煮詰まった原因はここにあります。CurrentSceneがPreviousSceneSceneを保有する形にしてしまうと、CurrentSceneがアクティブなわけですからCurrentSceneのGameComponentはComponentsに登録されているわけですが、その内部でPreviousSceneを生かしておくからにはCurrentScene.PreviousSceneのGameComponentもComponentsに登録されてしまっていて、2画面を描き分けることが出来なくなってしまいます。つまり、機能考えた「と、一瞬思ったのですが」の「どう実現するか」は結構気持ち悪いということがわかりました。

で、どうするか

Game.Componentsの仕組みから言って、どう考えても1フレームには1Sceneにつき1回しかDrawやUpdateしか呼べないことになりますから、割と振り出しに戻った観はありますがComponentsをSceneにも持たせるということになりそうです。なんかすごい回り道でしたが(ここまでで約4500文字)、まあこれしかないという証明が出来てよかった…

とりあえず遷移なしのSceneの再構成

SceneはGameComponentを継承したクラスで、Scene.Componentsを持つ。Scene.DrawではScene.Componentsのすべてに対してDrawが呼ばれ、Scene.UpdateではScene.Componentsのすべてに対してUpdateが呼ばれ、Scene.InitializeではScene.Componentsのすべてに対してInitializeがよばれる。Sceneがアクティブなとき、そのSceneはメインの(つまりGameの)CurrentSceneに入っていて、またGame.Componentsにも入っている。基本的にGame.Componentsの中は1つのSceneだけが入っていることになる。デバッグ用とかで2つ以上にはなるかも

画面遷移ありのSceneの構成

やっぱり遷移のコードとSceneのコードは切り分けておいたほうが良い気がするのでそういう方針で作る。遷移もある意味Scene的な要素を持っているので、むしろ遷移もSceneの一種として捉えたほうがいいような気がしてきた。つまり、Sceneはゲーム中の画面を担うGameSceneクラスと遷移を担うTransSceneクラスに派生し(インターフェースでもいい、というかSceneはインターフェースのほうがいいような気が…)、TransSceneクラスは2つのGameSceneである、遷移前のGameScene甲と遷移後のGameScene乙をとる。遷移中はメインのCurrentSceneはTransSceneになる。TransScene.DrawメソッドでGameScene甲や乙のDrawを呼び出してその画面をTextureに振り向け、適当に処理して描画するということになる。遷移が終わったらTransSceneにもIsDeadがあって、GameScene同様Scene切り替えの手続きでメインのCurrentSceneをScene乙に切り替える。

各GameSceneはやはり遷移中でアクティブであるのか遷移が終わってアクティブであるのかすでに役目を終えたのかの3状態を持つことになる。遷移中かどうかはメインから(あるいはTransSceneから)与えら得る情報なので、その窓口としてStartMainPhaseみたいな遷移が終わったときに呼ばれるvoidのメソッドが必要になる。

SceneはIsDeadとGetNextSceneを持つことになる。メインはUpdateでCurrentScene.IsDeadを呼んで、trueならGetNextSceneで次のSceneを取得しCurrentSceneとする。

だんだん文章がひどいことに…

Sceneは階層構造を持つかもしれない

いままでは2状態の遷移だけを考え、遷移したら遷移した前のことはさっぱり忘れてしまっていたのですが、それだけではすまないかもしれません。たとえば、シューティングゲームでのポーズ画面は一種の状態かもしれません。(最初の定義の「明らかに違う状態」かどうかは怪しいですが。)そのとき、ポーズ中のSceneはゲーム画面にオーバーラップして表示されることになるでしょう。つまり、ゲームのSceneにアクセスできないと困るわけです。

どう実現するか

すると、SceneがSceneを持つことになるかもしれませんが、これを実現するためにいままでの構造を変更する必要はなさそうです。
f:id:sle:20120919234005p:plain
たとえば上のような状態を考えてみたいと思います。TitleからGameってなんやねんという気がするのですが、間にMenuを挟んでもあまり本質的ではないので省きました。鍵は右二つのMainMenuとSystemMenuで、想定としてはゲーム中にEscか何かを押すとSystemMenuに入ってゲームの中断(Titleへ戻る)ができ、さらに左右キーでItemMenuとSystemMenuを行き来できるというところです。二つのMenuはGame画面にオーバーラップして描かれるわけですからGameへのアクセス権が必要です。

今までと主に違うのはGameからSystemMenuへの遷移ですが、これは遷移時にSystemMenuがGameを要求するようにしておけばいいのではないでしょうか。そして、CurrentSceneはSystemMenuのSceneになります。また、ItemMenuに移るときもやはりGameが要求され、これはSystemMenuから渡されます。


なんか満足したのでこの辺で。そのうち推敲するかも。

*1:不安になってぐぐってみたのですが、"Philosophy of Programming Languages"という用法があったので良かった。「その言語はどう使われることを意図しているか」ぐらいの意味のつもりです。

*2:相互参照でどうこうする方法もあるとは思うのですが、一応避けられる場面なら避けておこうかなーと。

「Star Guard」やってみた

「250 Indie Games You Must Play」に載っていたインディーズゲーム「Star Guard」をやってみた。スクショとればよかったんだけど忘れてた。今度からつける。ご意見歓迎。

どのぐらいやったの?

ノーマルモードクリア。ミスあり。

入手法

「250 Indie Games You Must Play」に載っている入手先は404。新しいのはhttp://vacuumflowers.com/star_guard/index.html。WindowsとMacに対応。しかし、Flashゲームなんだから工夫すればLinux系でもいけるのではないか。

ゲーム概要

アクションシューティングゲーム。主人公の緑の人を操作して、ステージ(重力あり)を駆け巡り、モンスターを倒したりやりすごしたりしつつ、悪い魔法使いの撃破を目指す。

システム

全9面の面クリア型。セーブ不可。主人公は、ジャンプ(zキー)とレーザーガン(xキー)で戦う。緑色の味方もいて一緒に戦ってくれるがあまり頼りにはならない。敵はレーザーガンで何度か撃つと倒せる。踏んでも倒せない。一部の敵は倒れた後死体のようになるのだが、しばらくすると復活して白い敵になる。それで倒すと完全に撃破となるが、白い敵は倒しても点が入らないので、できるならさっさと逃げるが吉。最初から倒れたようになっているが、ある地点まで到達すると突然動き出したりする敵がいるのに少し理不尽さを感じた。しかし、割とこまめにステージ中チェックポイントが設置されており、死んでもさくさくやり直すことが出来るので、そのあたりで理不尽さを中和しているように感じる。また、死んでも一度倒した敵が復活したりはしないので、死ねば死ぬほど楽になるということになる。ノーミスクリアは至難かと。死んだ復活直後は無敵状態で、しかもその間に敵に触れると倒せるのでそれで多少楽できる。ステージ中にはダイヤモンドみたいなアイテムが設置されており、取るとボーナス点になる。ギミックとしては、崩れる床やら固定砲台やら、定番どころは押さえているが、組み合わせ方使い方がうまく感心した。ラスボスは3形態ぐらいあって、結構歯ごたえがあった。第1形態はパターンを見抜けばなんとかなる。第2形態もやることはすぐに気づくはず。第3形態はそろそろ疲れてきていて、しかも先述のセーブポイントがあったので、ショット連打で終わらせてしまった。ストーリーは背景として、文字情報で与えられるのはゲームの邪魔をせず好感が持てたのだが、当然英語だし妙に難しいし、ゆっくり読んでいるとやられてしまうので全然読めなかった。ネイティブなら余裕だと思う。

グラフィック

非常にシンプル。黒い背景で、主人公は緑、敵および触れると死ぬものは赤、破壊できないものは白い囲いと、うまくシステム的な情報をグラフィックに自然に乗せられている。このため、説明書がなくてもすぐに細かいルールが飲み込めるようになっている。敵にショットがヒットしたときに破片みたいなものが出るあたり細かい。敵の外形とその動きがよくマッチしていて、個性がよくついていると思う。

ただ、主人公の移動速度や、死んだときのセーブポイントまでの視点移動が速いせいか、2Dゲームにもかかわらず画面酔いしてしまった。画面サイズを縮められるので、それで多少は改善されたが、それと先に進めないストレスが重なってしまってクリア時にはぐったりだった。単にアクションゲームをプレイするのが久々だったからかもしれない。だとしたら作者に申し訳ないことをした。

サウンド

BGMはなし。これでほとんど同じ見た目の9面の間行くのは精神的に疲れた。音楽によって面の特徴づけをすることの重要性を再認識。

技術

Flash Playerが同梱されていて、それでプレイするのでFlashゲームと思われる。破片が飛び散るなどは細かいなあと思ったが、Flashならそういう挙動は得意分野だろうし実はたいしたことはないのかもしれない。ジャンプは長押しすると高く飛べる方式。敵の制御は丁寧なつくりなのではないか(あまり比較対象を知らない)。

こまごまと

どうもSF小説に影響を受けて作ったゲームらしい。そういう作り方もあるのね。

総括

とにかく酔った。それのせいでいろいろものがゆがんで見えてしまっている気もする。本の売り文句が"Presents 250 influential and fun indie video games"となっていたし、Independent Games Festival 2010でデザイン賞を受賞しているしで、かなり期待して望んだのだが、ちょっと過度の期待をしすぎたかなあと。製作面で学ぶことは結構あったように思える。