スポンサーサイト

上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。

DXRubyでノベルエンジン作ってみた(AC用記事)

〈完成!>

こんにちは、みれいゆですー
今回の記事はDXRubyのアドベントカレンダー に向けて作られた記事となっています。
http://www.adventar.org/calendars/345
今回の私は12月23日を担当しました!!もうクリスマスも近い!!

前回は 役に立ちそうで役に立たない少し役に立つかも知れないDXRubyローグライクのノウハウ hoshi_sano さんでした!!
ローグライクは私もかなりはまってたゲーム種別ですね!!ちゃんとYAMLで内容をユーザーが変更できるのもうれしいところ
これまでのAC記事の集大成のような記事でした!!

さて、当の私はこれまでの自身の成長?の集大成(にはならなかったかもしれない)なものを作ろうと思って、考えたところ、
様々なゲームジャンルを探っていくとどうもフリーゲームで一人専用だと
「ノベルADV] これは非常に人気で数が多い事がわかりました!!

私にはノベルを書くような文学才能はありませんが型なら作れるぞ!!と思って今記事にとりかかった次第です。では、どうぞー




[DXRubyノベルエンジン作ってみた]

目標:ファイルの簡単な一部をユーザーが加えることで簡単にノベルを編集できる!!

用意する(した)もの(ソース)
以下の適当なファイルを用意しておく。
・背景画像 ・背景じゃない前に置くような画像、
・キャラクターの顔を含めない画像 ・キャラクターの顔の画像
<それぞれ拡張子は png !!>
・効果音に使うWAVファイル
・音楽に使うMP3ファイル

をそれぞれ1つ以上あるといいです!

今回作るソース・ファイルは以下の3つになります。

・main.rb ・・・メインですね。ここにノベルクラスを動かす為の記述を入れます。
・page.rb・・・Sceneクラス。これは汎用sceneモジュール
(http://dxruby.sourceforge.jp/cgi-bin/hiki.cgi?%C8%C6%CD%D1scene%A5%AF%A5%E9%A5%B9)
を改造させていただきました!(パブリックドメイン)
・class.b・・・今回最も重要な、Classを管理しているファイルになります。




①:では、まずはpage.rb のソースだけちゃっと載せましょう!!

http://pastebin.com/7fMhfrET

#メインの定常処理はrun->render->update->exitとなる。
step.times do
break if page.Next_page
page.__send__ :__run
end

page.render

step.times do
break if page.Next_page
page.__send__ :__update
page.__send__ :__exit
end



ここが重要でして、フレームで動かすdefの順番を run->render->update->exit (描写前の処理、描写処理、描写後処理、終了用処理)としています。




②:class.rbを作ろう!!

さて、今回はユーザーが比較的に?簡単にコードを編集して音楽も画像も、もちろんノベルの文章も追加できるようにと考えていきました。そこで音楽、画像の導入には、”全てを配列に突っ込み、番号で処理できる”ようにしました。
つまりこうです。

@body , @face= [],[]
@body << @sample_body1 = Image.load('sample_pass/body_sample1.png')



画像をファイルパスからロードした画像を適当な変数で定義し、そのまま@body配列に突っ込みます。
この要領で音楽等もやっていきました。
次に文章はクラスに引数を設定する事で、非常に可変的に作ります。
ボタンですが(ここでは文字をボタンとした)、ボタンのサイズを得るためにこのようなコードを書きました。

button_size = [x..x + font.getWidth(sentence) , y..y + font.size]


として、

if button_size[0].include?($xpoint) && button_size[1].include?($ypoint)


これは、文字の大きさをrangeクラスで取り、マウスカーソルがその範囲に入ったかを意味しています!

なるべく抽象化する事で、立ち絵、背景等画像、音楽、文章、ボタンを下のようなクラスに纏めてどれも引数で処理ができるようになりました!!

http://pastebin.com/vfTRHa9S

本当に、抽象化を覚えてよかったと思いました!!

ここの引数は後に作る、ノベルを構成するクラスで全て設定ができるようになります・・・





本番のノベルを構成するクラスに入る前にここで息抜き?のクラス、
固定データの変更に用いる。Param_edit_class を作っていきます。
なぜ必要になったかはノベルクラスの際に紹介します・・・
結果は20行でできました。

http://pastebin.com/EZe9aCXt
ここのところ、 演算子を変数化できればもっと短く出来たところです!!(やり方があったらお願いします!!)




さて、本番のクラスです。ノベルクラスを紹介します。
ノベルに必要な事柄はなにか?と考えていったところ、必要な事柄をまとめました(あくまで個人の結果なので、もうちょっといいまとめ方があったらお願いします!)

・イベント開始条件 ・・・開始条件によって複数のイベントを分岐させる
・イベント結果分岐 ・・・正答度の概念によってイベント全体の結果を変える
・分岐判断待ちタイム ・・・これはボタンのタイムに同期させない理由は、瞬間的に出てくる分岐とかも作りたかった
・サウンドエフェクトタイム ・・・サウンドノベルはいつでも音を鳴らせるようにしたい!
・画像描写 ・・・画像、音楽も条件分岐によって滑らかに変えたい
・文章描写 ・・・大量の文章を構造化して編集がし易いように
・分岐ボタン描写 ・・・大量の条件分岐を構造化して編集がし易いように


にまとめ上げました。




class.rb の完成形がこちらになります!!

http://pastebin.com/fj0D15uQ

ここで最初んっと思ったところがあって、それは、
"一つの変数に対し、each メソッド上の変数を使ってeachした値は、基の一つ変数と関連性が無くなる"
という事です。つまりこのような事です。
sample_ary = [[2,"up",[[$sample_data[0],3],[$sample_data[1],-4]],-1],[2,"down",[[$sample_data[1],3],[$sample_data[2],-4]],-1]]
という配列があって、

sample_ary.each do |p|
p[2].each{|d| d[0] += d[1]}
end


このやり方では、$sample_dataのどの値も変化しないようですね!
何かというと、一回目のeachの時点で本来$sample_data各種であったはずの変数はp[2]配下のp[2][0]に姿を替えてしまったために、関連性が無くなってしまったのだと思います。

そのため上のような事をする為に息抜き?でやっていたparam_edit_classを呼び出して引数で直接変更させる変数を設定するようにしました。

今回はeachメソッドを使う機会が非常に多かったので、この仕様を見つけることができて感慨深いです。




③:main.rbで戻り値を使った総管理

最後にmain.rbと題して、上のClass_novel内の操作をどういった方法で使用するのかを決めます。
Class_novelの def initialize と def reinit 以外はこれからいかなる編集をする上では全く操作する必要が無いと入っていいでしょう!

http://pastebin.com/ABvHwWtK

Class_novel内のdefの使用順番は、
ifs->draw->effects->sentence->result->(ifs)->time->mind->reinit
となります。

main.rbのユーザーが手を加える時は、ゲームオーバー条件を定める必要がある場合です。
もしゲームオーバーが存在しないように作るならばこれも編集の必要がありません。




④:まとめ

今回のノベルエンジンコードでできる事は
・タイムワークで文章や効果音を流せる
・ボタンを押すことで物語の分岐を作る
・複数の開始条件と結果を作れる。(ゲームオーバーも用意できる)

やろうと思えば拡張はどんどんできます!!拡張しても負担がそれほどかからないのが抽象化されたクラスの特長ですね!!


最後に、このノベルエンジンを作る事は、DXRuby、Ruby言語で作る方法が非常に簡単でした!!まずほかの言語ではGUIを出すところから、(できれば高機能にできるかもしれないが)難しいところがあり、それをコマ送りのように動かすことはとても準備がいる作業でした。
DXRuby(Ruby)のイイトコロはぱっと思いついた構想をぱっと実現できるところだと思いました!!特にDXRubyはGUIアプリケーションを作る時にはかなり使いやすいですよ!!
最後に、ゲームのジャンルはノベルやシューティング、ローグライク以外にももっと様々あります。想像すればいつでも実現がしやすいDXRubyで、グラフィカルに再現してみませんか??

コードソースリンクがあちらこちらにあったので、完成形をここにまとめます。

・page.rb
http://pastebin.com/7fMhfrET

・class.rb
http://pastebin.com/fj0D15uQ

・main.rb
http://pastebin.com/ABvHwWtK




さて、次回は土屋つかささん t_tutiya さんです!!またDXRubyに纏わる短編物語を書いてくださるのでしょうか??
それとも・・・


ご閲覧ありがとうございました!!

製作経過(育成ADV?)

こんにちはーみれいゆーです。
ずいぶんと更新が止まっていたので申し訳ございません。

さて、育成?ADVの製作は現在ノベルの型はできあがって今4イベントは作ったのですが、作業が
物量 物量 物量 なのでなかなかつらいものですw

ちゃっと終わらせて公開するなら9年分(ゲーム時間で)の15程度のイベントにしようか
作りこむなら36季節分で50程度イベントにするかですが、これまでの経験では

公開後からやりこみの要素を追加していくのはやる気が出ない

という事で、まず形になったものを公開するよりもどうせなら完成版として二度と手を加えないぞの気持ちで行こうと思っています。ですので1年コマの9年分イベントで、短編で終わらせるよう調整しようかな・・・

ということで次回の記事は、このノベルの型について、技術的説明を加えながら公開説明しようかと思います!お楽しみにー

新ゲームのジャンル、内容について と妖かし憑狐の進行

さあ、年末も迫ってきた所で、鍋がおいしいですねー


第三作目のジャンルが決まりました!!
「育成ADV」です!!

今度の作品はゲーム日数制限ありで、一人の少女を主人公視点で、育てていくのが基本のADVとしていきます。

ADVで重要になってくる絵は、キャラ立ち絵は描きました! 挿絵は描けるかしりません!!w

今回も背景はぐったりにゃんこさんを全力頼ってます!曲は M-ART様を全力で!

ベータリリースは年明けになりそうなので、まあゆっくり待っていてくださいねー




妖かし憑狐の開発ですが
残り新たに開発するべき所が「新聞」と「おはなし」 そして絵の改善増量しかありません!!
ですのでこれらはもう、プレイしてくださってる皆さんの要望で増やしていこうと考えています。

また気が向いた時に大幅アップも来るかもしれないのでその時は期待していてくださいね!!

みれいゆーの絵(2014/12/10)

フリゲが人気になるにはダメでも絵を描かなければならない、特にRPGやノベルでは。
ということで書いてみた二枚です。

noteuall_a.png
kanonall_a.png

上は私の(脳内)彼女、ノティ・メイプリリュ略してのてうー

下はかのんの信仰集めで簡単にかかれてたご本人、望月神狐です。(神狐をかのんと読むセンス)

二枚合わせて製作時間は1時間半でした。

これから妄想を広げていきたいですねーーー
(ヽ´ω`)

DXRubyで成長曲線と父母遺伝の再現、描写

こんにちはーれゆーですーっ



(まちがったみれいゆーだ)


今日は DXRuby Advent Calender 2014 の10日目という事で、私が担当します!!

前回は、Vivit_jc さんの 「〜ゲーム制作者だってテストがしたい!〜DXRubyユーザー向けRspec入門」でした!!
まだ記事は続きがあるようで・・・楽しみですね!!
さて、今回は、DXRubyで成長曲線と父母遺伝の再現、描写
となっておりますっ。これは私が遺伝子計算を勉強した中で得た計算式の詳細や、その曲線を描写する為の処理、他様々に加え、父と母のグラフを定義して合成するといった内容を行います!
(あまりDXRubyに関係が無いかもしれませんがご了承くださいすいません><)


使用するパロメータを定義する
今回成長曲線を描く上で必要になってくる要素を遺伝子生物学から考えていきましょう。
まず、人間にも、いかなる生物にもそうですが、思春期ありますよねー。この思春期の時には体、そして心も急成長します。これを第二次性徴期といいます。今回はこの第二次性徴期を再現しようと思います。最も成長する歳を名づけて成長頂点歳、変数は
peakage
としましょう。
只、性徴期が訪れた時、人によってその成長の進み具合、言い換えれば傾斜が違うと思います。人間同士ならわかりにくいですが特にネズミとゾウを比べるとはっきりわかります。この時必要となってくる要素を、私は成長幅と名付けます。
今回変数表すとこれは
peakrange
となります。
でも、人間もそうですが、皆さん寿命が存在します。この定められた寿命を超える、体力が衰え、もう体を成長させようにも出来ないことになります。これを決定づける値、ここでは変数で
activeage
とします。
最後に、皆さん体を成長させるとき、それには二つの方法が存在すると思います。それは、体が自然に成長していく「自然成長」と、ジムなどによって人為的に鍛えて成長させる「訓練成長」です。
これも今回は再現しようと思います。変数はそれぞれ、
naturalpower
trainpower
としましょう。
尚、上記二つの成長力を総合して
totalpower
とします。




成長曲線グラフを考える

さてグラフの時間となりました!
まず、今回の成長曲線を描くにおいての必要な動きの四大要素を掲示します!!
A:成長頂点歳に向けて指数関数的に成長力が上昇する事
B:成長幅の広さに応じてその成長力の傾斜をゆるめ、成長力最大値を可変する。
C:成長頂点歳を過ぎた場合一定の成長力に収まる
D:寿命を超えると成長力が0に進む。。


これらを叶える為に必要な計算式を順々に取り出して行きましょう!

A:成長頂点歳に向けて指数関数的に成長力が上昇する事
まずこれは、成長頂点歳の時には成長力が最大になるということの再現を行います。

Rubyでは指数関数を扱うモジュール/メソッドとして Mathモジュールの expメソッドがあります!
(組み込みライブラリ)

よって単純に表したい場合こうなります。

grow = Math.exp(time)


timeは0..60 つまり現在の年齢を指定します。 grow に出力されます。
これが成長頂点歳の場合、

peakgrow = Math.exp(peakage)


となります。

B:成長幅の広さに応じてその成長力の傾斜をゆるめ、成長力最大値を可変する。
これを表現する為に、二箇所の計算式を加える必要が出てきます。
まずは成長力の傾斜をゆるめこれに着目します。
確かに最大の値はA:で述べた成長頂点歳式peakgrowに達したいけどそこまでの傾斜を決めたい場合、必要なメソッドは、そう、 Math.sinです。
この三角関数Sin(正弦関数)の持つ値は、角度にして0..180と言われており、そのグラフは、
○の上半円を切り取ったようなものとなります。
角度ではなくラジアンで表現した場合、その単位はπとなりますが、πをrubyではMath::PIで取得する事ができます。
そして、以上の三角関数式に影響したい値は、ここまでの流れから当然、成長幅、peakrangeとなります。
以上を纏めると入る式は、

Math.sin(peakrange * Math::PI/ 180.0)



次に、成長力最大値を可変するに着目します。
成長力の最大値を決めるにあたって、必ず「成長頂点歳と成長幅によって"大きく"総合成長力を変えない」という事を前提に置きます。
ここの"大きく"と表現した理由は、人間誰しもが同じ成長力を持ってそれが早熟であれ晩成であれ同じだとすると、特に晩成は「報われない」からです。今回はこの事も視野に入れた式を作ります。
こうして作りたい式は、
「成長歳が遅ければ晩成として成長力の総合が大きい」
「成長幅が成長歳と釣り合っていればさらに成長力の総合が大きい」

これを再現する為、得た式はこうなります。

((totalpower / peakage ) / peakrange) / (1.0 + peakage * Math.exp(-1.0 * (Math.sin(peakrange * Math::PI/ 180.0)) * time))


最早自分でも意味の分からない式となりました。

C:成長頂点歳を過ぎた場合一定の成長力に収まる
前述の式は成長頂点歳に向かうまでの再現をとりました。次は成長頂点歳を過ぎた場合の式を作ります。
マイナスの方向に進む式の為、まず、最大成長力から引く式を立てます。

peakgrow - 式



さて、次に考えるのは、最大成長力からの「減衰力」です。
すなわち、成長頂点歳を境にマイナス式を大きくするという考えで行くので、加える式は

式 * (time - peakage )


さあこれで再現しよう!という時に問題が一つあります。それは、
「減衰が無い。」
この状況を回避する為に「成長頂点歳を過ぎたら約半分程の成長力を残そう」
という考えです。これを考慮して完成した2式がこちらです。

grow = ((totalpower / peakage ) / peakrange) / (1.0 + peakage * Math.exp(-1.0 * (Math.sin(peakrange * Math::PI/ 180.0)) * time)) if time <= peakage and time <= activeage
peakgrow = ((totalpower / peakage ) / peakrange) / (1.0 + peakage * Math.exp(-1.0 * (Math.sin(peakrange * Math::PI/ 180.0)) * peakage))
grow = peakgrow - (((totalpower / peakage ) / peakrange) / (1.0 + peakage * Math.exp(-1.0 * (Math.sin(peakrange * Math::PI/ 180.0)) * (time - peakage )))) / 2.0 if time > peakage and time <= activeage



型崩れが激しいです。申し訳ございません。この上記にある条件式は双方とも、「寿命を超えていない」事を書いております。さて、超えるとどうなるのか・・・・

D:寿命を超えると成長力が0に進む。。
先ほどに書いた式の減衰に、小幅な修正を加えます。すなわち、先ほどは値を"2"としたことで減衰したら残りの成長力は成長頂点歳に比べ"1/2"で安定しました。ならば、値が2より大きく、そして∞に向かうなら・・・

/ (2.0 * (activeage / time) ** 4.0)


尚、** は累乗を意味します。

こうして成長曲線を描く3式が出来上がりました。列挙すると、


for time in 0..60
grow = ((totalpower / peakage ) / peakrange) / (1.0 + peakage * Math.exp(-1.0 * (Math.sin(peakrange * Math::PI/ 180.0)) * time)) if time <= peakage and time <= activeage
peakgrow = ((totalpower / peakage ) / peakrange) / (1.0 + peakage * Math.exp(-1.0 * (Math.sin(peakrange * Math::PI/ 180.0)) * peakage))
grow = peakgrow - (((totalpower / peakage ) / peakrange) / (1.0 + peakage * Math.exp(-1.0 * (Math.sin(peakrange * Math::PI/ 180.0)) * (time - peakage )))) / 2.0 if time > peakage and time <= activeage
grow = peakgrow - ((totalpower / peakage ) / peakrange) / (1.0 + peakage * Math.exp(-1.0 * (Math.sin(peakrange * Math::PI/ 180.0)) * (time - peakage ))) / (2.0 * (activeage / time) ** 4.0) if time > activeage
grow = 0.0 if grow <= 0.0
totalgrow += grow
end



後ほど完成されたコードは pastebinにあるのでご心配なく!!




成長曲線グラフを描写する。

Window.draw_font(10 + time * 10 , (-1 * grow* 100) + 440 , "●" , font,hash={color: [255,66,66]})


これを前述のFOR文に加えます。
ここで、-1 が入ってる理由は、Windowのy座標は大きければ↓に向かうからです。今回は上に山なりとするため、440をベースに-1 * としました。
年齢が1進むことでx座標は10進みます。

こうして、完成されたグラフはこう映ります。

grarh4.png

赤が自然成長力のみ、水色が訓練成長力のみ、黄色が総合成長力です。
また後の話にはなりますが、分かりやすいように左上に各重要値の配列を表示しています。
ここでは左から順に、
自然成長力、訓練成長力、成長頂点歳、成長幅、成長寿命、生命寿命。
成長寿命の事を今までは単純に寿命と言ってきました。実際の遺伝ゲームとなると生命寿命を別に設け、その歳に死亡するようにします。




おまけ?父母遺伝を書く。

この項は最早おまけです。
一つ言うならば、父と母で引き継ぐ"比率"が重要という事ですね。
あとは、新しい子を人間の配列に pushします。




こうして、すべてのコードを導入した完成品をpastebinに貼ったのでどうぞ!!!

http://pastebin.com/CdVGVjzt




grarh1.png
grarh2.png
grarh3.png

最後までご視聴ありがとうございました!!
さて、次回は、unohanaTさんの記事です。お楽しみにーーー
上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。