「Papyrus入門」の編集履歴(バックアップ)一覧はこちら

Papyrus入門 - (2015/08/19 (水) 22:34:14) の1つ前との変更点

追加された行は緑色になります。

削除された行は赤色になります。

#contents *概要 スクリプト作成の流れや構造をざっくり掴みます。 流れをつかみやすくするために平たく説明するので厳密に言うと違うこともあります。 実践編はCK Wikiの[[Papyrusチュートリアル>http://www.creationkit.com/Bethesda_Tutorial_Papyrus_Hello_World/ja]]をおすすめします。 *Papyrusって何? スカイリム専用のイベント駆動型オブジェクト指向スクリプト言語です。 いきなり難しい用語が出てきましたが、大事なことなのでざっくりと概念を掴みましょう。 **イベント駆動とは? イベント駆動型というのはイベントが発生する時にしかスクリプトが動きません。イベントを起点として動くということです。 イベントとは例えば座る時(OnSit)、攻撃を受ける時(OnHit)、死ぬ時(OnDeath)、ロード(OnLoad)時などに発生します。 [[イベント一覧>http://www.creationkit.com/Category:Events]] ゲームは基本的にイベント駆動型です。なぜイベント駆動型なんでしょうか? ゲーム画面には大量のオブジェクトが設置してあり、その一つ一つに対しての状態を0.1秒毎に監視して動くようにしたらどんなにハイスペックでもまず重くなってしまって動きません。 それに何がどこでどう動いているのかがわかりにくくなり複雑すぎます。 これをイベント駆動にすると見た・触った・動いた等のタイミングでスクリプトが動くだけなので、構造がずっとシンプルで動作は軽いです。 ゲームは大体、スイッチを踏んだらトラップが稼働するなど何かのアクション(イベント)に対して反応という仕組みでできています。 なのでゲームにはイベント駆動が向いています。 **オブジェクト指向 オブジェクト指向というのはオブジェクトを主体として考える手法です。 あなたが操作するプレイヤーはオブジェクトです。あなたが持っている武器もオブジェクトですし、NPCもオブジェクト、天気が晴れているならその晴れの状態もオブジェクトです。 見たまんまの実体としてオブジェクトで画面が構成されているからわかりやすいですね。 だからゲームには非常に相性が良いです。 でも、オブジェクト自体は&bold(){なんかしらの役割を持つもの}として覚えておいてください。必ずしもすべてがゲーム画面で実体を持っているわけではないです。 CK上のオブジェクト=フォーム(Form)です。そしてそのFormの種類がFormType。Formが被らないように管理番号を与えられているのがFormID。 実際に見たほうが早そうですね。 それではCKでSkyrim.esmを開いて、Object Windowを見てみます。 #ref(player.png) 左側のツリーに入ってるものはすべてオブジェクト(フォーム)です。 右側見ますとPlayerが一つのフォームでFormIDは00000007、FormTypeがNPC_。 UserっていうのはこのPlayerを参照にしているオブジェクトです。 Countは実際のゲーム世界(Cell)に設置してある数です。このUserとCountが実際に何に参照されていてどこに設置してあるかは対象を右クリックしてUseInfoで見れます。 オブジェクト同士が相互に作用しあってゲームが成り立っているのでこの&bold(){UseInfoは何と何がつながっているのか手がかりになるので極めて重要です。} もう一つ事例を見てみましょう。 #ref(basictankard.png) BasicTankard01を開いた状態にしてます。ただのジョッキです。 名称(Name)、Weight(インベントリでの重さ)、Value(価格)が設定されてますね。 画像にはないですがモデルデータの指定もここです。 これ、ゲーム画面での実体のあるモノではないんです。 ただの設定だけのオブジェクトですね。これを&bold(){ベースオブジェクト}と言います。 実際にゲーム画面に出てくるジョッキはセル内に設置してあります。 これが&bold(){リファレンスオブジェクト}です。 画像準備中。 なぜ、ベースとリファレンスで分けるのでしょうか?ややこしいですよね。 ではジョッキ一個の値段を10にしましょうか。 ベースとリファレンスを分けずに、リファレンス単体が価格の設定を持っていると仮定したら、セル上にある4179個設置されているのを一つ一つ価格を直さないといけません。途方も無いですよね。 これを回避するために設定=ベースと設置=リファレンスの役割を分けるんです。 役割を分けた上でリファレンスはベースの設定を持っています。(包含関係。リファレンス変更してもベースは変わらない。) この&bold(){役割でオブジェクトを分ける}というのがオブジェクト指向の肝だと思います。 魔法なら:威力の強さ、持続時間、魔法名を持つSpellと、効果の種類、耐性、エフェクトやサウンドなどを設定するMagicEffectで役割を分けてます。 鎧なら:防具の性能や種類を決めるArmorと、モデルデータと装備箇所と適用する種族のArmorAddonに分かれています。こうやって分けてあるから種族別で革の兜のモデルデータを変えたりできます。 要は&bold(){テンプレ化(ひな形を作る)}です。 基本となるテンプレ作っちゃえば後は組み合わせであとは無数のバリエーション作れます。 キャラクター例: |名前|種族|戦闘AI|装備|スケジュール| |山賊長|ノルド|ボスクラス|重装ボスセット|一日鍛冶してるスケジュール| |山賊|ブレトン|魔法使い|魔法使いセット|ダンジョン内巡回| |市民A|インペリアル|非戦闘|服セット|畑仕事| *Papyrusを言語として覚える 言語なので文法があります。ルールですね。 プレイヤーを取得する。をPapyrusに翻訳すると。 Game.GetPlayer() 後ろから分解してみて、GetPlayer()は&bold(){関数}です。 英語でFunction、直訳は&bold(){機能}。 関数の語尾には必ず&bold(){()}がつきます。これ付いてるものは人も機械も関数だってわかります。 GetPlayer()はそのまんま、プレイヤーを取得する機能(関数)ですね。 関数は自分で作ることもできますが、ゲーム側でまとまったリストを作ってます。 このリストの中の一つがGameで、このGameはゲーム全般に関わる関数リストです。 実際のこのリストの場所はData\Scripts\Source\Game.pscです。 ここからGetPlayer()を引っ張ってくるために先頭にGameを付けます。 つまりGameという関数リストの中からGetPlayer()を呼び出しただけなんです。 .は単に区切りです。、みたいなものです。 関数と関数リストは全部は把握できないので[[CK wikiのパピルスリファレンス>http://www.creationkit.com/Category:Papyrus ]]を見ながら、どんな関数や関数リストがあったけなーって何ができるかなーって探して使います。 たいてい使用例が書いてあるのでコピペで使えます。 次はアクター(キャラクター)の体力を取得したいと思います。 Actor.GetActorValue("Health") Actorの関数リストからGetActorValue()という関数を呼んでます。 さて、関数のカッコ内に"Health"とありますがこれを&bold(){引数(ひきすう)}と呼びます。 英語でParameter(argumentとも)、今じゃ英語のわかりやすい気がする、パラメータのことです。 GetActorValueはアクターに設定されている数値、体力、スタミナ、マジカ、錬金術のスキル値とかを取得します。 アクターの&bold(){何の数値を対象にするのか}指定しないと、ですね。ここでは"Health"です。対象がスタミナなら"Stamina"を指定します。 上のコードは実は動きません。対象が必要なんです。 一体誰のアクターの値を取得するんだ、と。 対象がプレイヤーの場合は Game.GetPlayer().GetActorValue("Health") 実はActorの部分、関数のリストだけではなくて&bold(){型}の役割を持ってます。 このGetActorValueの関数はActorの型にしか使えません。壷などがスタミナの値持ってませんしね。 型はデータの種類だと思っていいです。関数の使用できる範囲を区切る役割が型にはあります。 Game.GetPlayer()で取得したプレイヤーのデータはActorていう型に入れます。 これで対象のアクターをプレイヤーにすることができます。 型の概念は今は難しいかもしれないですが、 一つの構文パターン(SVとかSVOとか)だと思ったら全然構造は難しくないです。 ***対象があるパターンの構文 ~の.~を~する() 対象.実行() 型.関数(引数) 上全部意味は同じ。 Actor、ObjectReference、Form、Formlistなど ***対象の指定がないパターンの構文 関数リスト.~を~する() 例: Game.GetPlayer() プレイヤーをアクター型として取得する。 Utility.Wait(0.5) これの書かれた部分でこのスクリプトの処理を0.5秒待つ。 Debug.notification("Hello world.") 左上にHello worldと通知を出す。 Math.abs(-1.0) 引数の数値を絶対値として返す。つまり結果は1.0。 Utility、Debug、Math、Gameなど。 **変数、宣言、型 変数(variable)はデータを一時的に記録したり、そのデータを代入したりできます。 変数には型と名前をつけます。この型と名前を明確に定義することを&bold(){宣言}といいます。 型というのは格納するデータの種類です。 基本形が4つあるのでそれをまず覚えましょう。 基本の4型 |int|整数の型| |float|小数点も扱える数字型(浮動小数点数型)| |bool|true(真)かfalse(偽)かで返す型| |string|文字列の型。""で囲う必要がある| 名前は自由につけられますが、接頭辞に数字と記号(例外はアンダーバー→_)はダメです。 (ダメな理由を見たことないですが、文字のはじめが数字なら数字という時代の名残りっぽいです) ☓0IsWalking ○IsWalking 型 名前 float PlayerHealth *プロパティ *if *while 条件が&bold(){False(偽=不一致)}になるまでループします。 そのとおりに繰り返しの処理をする場合に使ったり、特定の条件を待機だとかにも使います。 条件が満たされない場合のタイムアウトのために(でないと永遠と回り続けてしまう)、処理の手前でカウントの変数を用意して、カウントまで達したら抜けるようにしておいたほうがいいです。 例: int count = 0 While self.Is3DLoaded == False || count < 10 Utility.wait(1.0) EndWhile *イベント *配列 Papyrusで難解なものの一つが配列なんですが、使いこなせれば強力です。 Papyrus上で基本となるのは一次元の配列で、これは平たく言って&bold(){変数の集合リスト}だと思ってください(厳密にはリストではない)。 変数は一時的にデータを記録したり、代入したりするものですから、例えたら&bold(){箱}と言えます。 この箱が連なってるのが配列です。箱には番号が振り当てられます。番地みたいなもんです。 その番号が&bold(){インデックス(添え字)}です。 #ref(arraybox.png) 上の画像をpapyrusで書くと int[] a = new int[4] a[0] = 12 です。 分解していきます。 intは整数型の指定ですが、配列の時は通常時と区別するため&bold(){[]}を付けます。 aは&bold(){変数名}です。ここまでは普通の変数の宣言とあまり変わりません。 newは新しく&bold(){配列の長さをセット}します。 [x]は&bold(){配列の長さ}です。例のように[4]なら0,1,2,3の4つの箱が作られます。 これが[2]なら0,1ですし、[5]なら0,1,2,3,4です。 &font(#600000){インデックスは0から始まるのが、ややこしく間違いやすい点です。([5]の長さで設定したなら[4]で終わる。一個ずれる)} 最初の行は配列の変数を宣言、そして配列の長さを新しく定義しました。 あとの行では箱の中身に数値を入れます。 例ではa[0]の箱に12を代入してます。 a[1] = 13 a[2] = 15 a[3] = 7 みたいに箱別に代入できます。 debug.notification(""+ a[0]) で表示されるのは12です。 例2: string[] myArray = new string[5] myArray[0] = "Hello" myArray[1] = "World" myArray[2] = "Hello" myArray[3] = "World" myArray[4] = "Again" Event OnInit() int i = 0 While i <= 5 debug.notification("" + myArray[i]) i += 1 EndWhile EndEvent で順番にHello,World,Hello,World,Againと左上に表示されていきます。 宣言の部分は前と同じです。 iというカウント用の変数作って0に設定します。 Whileでループして5以上になったら止めます。 myArrayの変数にiを代入します。 例3: Actor[] Property DeadActorList Auto プロパティにも配列使えます。プロパティのウィンドウで複数のプロパティを指定できます。 活用すると、まとめて変数を扱えるため冗長なコードになりにくくなり、またインデックスは自然数ですから足したり引いたりできて扱いやすいです。 (かなり応用例があるのですがそれはまた今度) 実例としてはCK wikiのComplete Example Scripts(テキスト検索で[]で調べる) http://www.creationkit.com/Complete_Example_Scripts またこちらの配列の解説も読んでおきましょう。 http://www.creationkit.com/Arrays_%28Papyrus%29/ja  

表示オプション

横に並べて表示:
変化行の前後のみ表示:
目安箱バナー