- Papyrusスクリプトの記憶を記録に残すシリーズその4 -
魔法でキャベツを作り出したいと思ったことはありませんか?
インベントリからお皿を捨てた瞬間、スイートロールにすり替えたいと思ったことは?
大丈夫。スクリプトで解決できますよ。今回は PlaceAtMe のお話です。
目次
1. 新しく魔法を作成する
1-1. 魔法の構造
キャベツ魔法を作りたいなら、スクリプトを書く前に新しく魔法を作らないといけません。細かいことは省いて、最低限必要なことだけやります。
魔法の内部構造は結構複雑で、Spell(覚える魔法)> Magic Effect(魔法効果)> Projectile や ImpactData など(Effect に使う各種設定)というようにいくつもの設定があります。
今回はキャベツを作り出したいだけなので、自己にかける回復魔法をコピーし、回復効果だけを取り除いて使います。
1-2. Magic Effect(魔法効果)の複製
まずは Object Window の Magic > Magic Effect から、RestoreHealthConcSelf を探して右クリックし、Duplicate(複製)します。
複製品を開き、ID と Name を変更します。ここでは「CreateCabbageEffect」にしました。
回復効果を無効にするため、Assoc. Item 1 を「None」にします。
Magic item description が魔法の説明になるので、とりあえず「Create a cabbage.」にしておきました。
1-3. Spell(魔法)の複製
Object Window の Magic > Spell から HealingLeftHand を Duplicate します。
複製品を開き、ID と Name を変更します。Name が魔法の名前になります。
右枠内に設定されている既存の項目を右クリックして Delete します。
そのままもう一度右クリックして New を選択し、先ほど作成した CreateCabbageEffect を指定します。
CreateCabbageEffect の Magnitude や Duration は 0 のままでOKです。
これで魔法は作成できました。見た目は回復魔法そのままですがご容赦を。
2. 魔法でアイテムを作り出す
2-1. 魔法効果に設定するスクリプト
魔法を唱えると手から光が出て、いざ発動!というときにキャベツを出します。
このスクリプトは Magic Effect ダイアログの Papyrus Scripts: に付けます。今回の場合は CreateCabbageEffect ですね。その記述が以下です。
Scriptname CreateCabbageScript extends ActiveMagicEffect Potion Property potCabbage Auto ; キャベツ Event OnEffectFinish(Actor akTarget, Actor akCaster) Game.GetPlayer().PlaceAtMe(potCabbage, 1) EndEvent
Event OnEffectFinish
が、魔法を唱え終わったときに発動するイベントです。ほとんどの魔法ではこのイベントでいけるでしょう。
スクリプトを保存したら、potCabbage プロパティに「FoodCabbage」を指定します。プロパティの指定については オブジェクトを表示したり消したりする を参照してください。キャベツなどの食べ物は、回復効果があるので Potion タイプに分類されています。
2-2. 物を作り出す「PlaceAtMe
」
単に物を作り出すだけなら Game.GetPlayer().PlaceAtMe(~, 1)
だけのお手軽コードです。
「1」の部分が出てくる個数ですので、変更すれば2個でも3個でも出せます。
出てくる場所はプレイヤーの足元、というか足の裏です。プレイヤーが立っている座標です。
出現した瞬間に Havok が働きますので、出てくる物によってはポーンと飛んでいってしまったり、プレイヤーがカクカクしたりします。
出現位置の調整は最後にしっかりまとめてありますので、今はこのまま進めましょう。
2-3. 魔法の習得
作成した魔法を使えるようにしましょう。どこかにアクティベーターを設置して、以下のようなコードを追記します。
Spell Property speCabbage Auto ; キャベツ魔法 Event OnActivate(ObjectReference akActionRef) If akActionRef != Game.GetPlayer() Return EndIf akActionRef.AddSpell(speCabbage) EndEvent
AddSpell
で簡単に魔法を覚えることができます。speCabbage プロパティに、先ほど作成した魔法「CreateCabbage」を指定すればOKです。
お時間のある方はここでレッツテストプレイ! 魔法を唱えるたびにキャベツが出てくるだけですが、それなりに楽しめましたよ。ゲルダさんのお掃除の邪魔にはなります。
3. アイテムを捨てたときに別の物にすり替える
3-1. インベントリから捨てた瞬間に発動するイベント
今度は、お皿をインベントリから捨てた瞬間にスイートロールとすり替えるスクリプトを書いてみます。以下のコードを Items > MiscItem > SilverPlate01(皿)に付けます。
Potion Property potSweet Auto ; スイートロール Event OnContainerChanged(ObjectReference akNewContainer, ObjectReference akOldContainer) If akNewContainer != None Return EndIf Game.GetPlayer().PlaceAtMe(potSweet, 1) Self.Disable() Self.Delete() EndEvent
potSweet
プロパティには「FoodSweetroll(スイートロール)」を指定します。
Event OnContainerChanged
は、そのアイテムの収納場所が変更されたときのイベントです。
収納場所とは、樽や宝箱、インベントリなどです。
このイベントでは変更する前後の収納場所を取得することができ、akNewContainer
は変更後の新しい収納場所を指します。アイテムを捨てたときは akNewContainer == None
として判定できます。
上記のスクリプトでは、None
でない場合に Return
ですぐ終了するようになっています。例えばインベントリから宝箱に仕舞うときには実行されません。捨てたときにだけ PlaceAtMe
でスイートロールが出現します。
3-2.「Self
」について
上記スクリプトで Self
が出てきました。これは、その名の通り自己を指します。スクリプトを付けた対象であり、この場合は皿です。
Self.Disable()
とすることで、皿が非表示になります。そのままでは存在はしていますから、Self.Delete()
として消去しています。
Self
はプロパティや変数のように宣言しておく必要がありません。いつでも自己を指すコードとして使えます。
3-3. アイテムすり替えの用途
すり替えの使い道としては、インベントリに入っているアイテムを捨てた瞬間に、見た目が同様のアクティベーターにすり替える例があります。
アクティベーターというのはインベントリに取得させることができませんので、インベントリ専用のアイテムと設置用のアクティベーターを分けて管理するんですね。アクティベーター側に取得用のスクリプトを付ければ、取得したり設置したりできる1つのアイテムに見えるわけです。
今はわかりやすいように皿をスイートロールに替える方法としてご説明しました。
このスクリプトを皿に付けたいという方はいないと思いますが、実際にやると同じ皿すべてに影響しますのでご注意ください。盗まれても安心なスカイリムにしたいなら別ですが。
4. アイテムの出現位置を変更する
4-1. 変数の作成と格納
Game.GetPlayer().PlaceAtMe
でアイテムを出現させると、そのままではプレイヤーの足元に出現します。この出現位置を任意の場所に変更しましょう。
実は PlaceAtMe
には引数が4つあります。その4番目に「true」を指定すると、Disable(非表示)の状態で出現させることができます。
「非表示で出現?」という方は、CKで既存オブジェクトを非表示にする方法 が参考になると思います。
この Disable 出現を使って、皿を捨てた位置(目の前)にスイートロールを出しましょう。皿のスクリプトを次のように修正します。
Potion Property potSweet Auto ; スイートロール Event OnContainerChanged(ObjectReference akNewContainer, ObjectReference akOldContainer) If akNewContainer != None Return EndIf ObjectReference objSweet ; 配置するスイートロール objSweet = Game.GetPlayer().PlaceAtMe(potSweet, 1, false, true) objSweet.SetPosition(Self.GetPositionX(), Self.GetPositionY(), Self.GetPositionZ()) objSweet.SetAngle(Self.GetAngleX(), Self.GetAngleY(), Self.GetAngleZ()) Self.Disable() objSweet.Enable() Self.Delete() objSweet = None EndEvent
ObjectReference objSweet
で、変数を定義しています。変数の型はプロパティのタイプと同様のものが使えます。上記の例では、ObjectReference
という型で、objSweet
という名前の変数を定義したことになります。
ObjectReference
は配置されたオブジェクト全般を格納できますので、次の行で出現させたスイートロールを格納し、それ以降の行で扱えるようにしています。
変数の定義と同時に値を格納することも可能で、上の2行を次のようにまとめてしまうこともできます。
ObjectReference objSweet = Game.GetPlayer().PlaceAtMe(potSweet, 1, false, true)
変数はこのスクリプトの中でだけ使うもので、プロパティのように esm/esp ファイルと関連付けたりしません。プロパティはゲームデータとスクリプトを事前に紐付ける役割が大きいのに対し、変数はスクリプト内で値を格納して使うものになります。
今回出現させたスイートロールのように、事前に指定しておくことができず、一時的に扱って値を保持しておく必要のないものは、変数に格納します。これをプロパティに格納することもできてしまいますが、プロパティの使い方としては好きではないです。
4-2. アイテムの位置と角度の指定
objSweet
にスイートロールを格納したら、位置と角度を指定します。
objSweet.SetPosition(x, y, z)
… xyzの座標を指定objSweet.SetAngle(x, y, z)
… xyz軸に対する角度を指定
Self.GetPositionX()
で皿のx座標が取得できますので、それをスイートロールのx座標に指定しています。他の座標、角度も皿から取得してスイートロールに指定しています。皿とまったく同じ位置に、同じ角度でスイートロールを置いたことになります。
4-3. 皿とスイートロールとのすり替え
スイートロールはまだ非表示状態でしたので、皿とすり替えます。
Self.Disable()
と objSweet.Enable()
で、皿を非表示にしてスイートロールを表示しています。このすり替えは一瞬で起こりますので、ゲーム内ではインベントリから捨てた皿がスイートロールにパッと切り替わるように見えます。
スクリプトの最後に objSweet = None
として、使った変数をクリアして片付けておきます。
そのままでもプレイに支障はありませんが、「変数は必ず初期値を確認し、使ったらクリアする」というのが、エラーを起こさないための個人的な決め事です。
4-4. 位置と角度指定の応用
もし出現位置を少し前の足元に指定したい場合は、次のように変更すると上手くいきます。
Potion Property potSweet Auto ; スイートロール Event OnContainerChanged(ObjectReference akNewContainer, ObjectReference akOldContainer) If akNewContainer != None Return EndIf Actor actPlayer ; プレイヤー Float fltAngle ; プレイヤーの角度 Float fltX ; 配置するx座標 Float fltY ; 配置するy座標 Float fltZ ; 配置するz座標 ObjectReference objSweet ; 配置するスイートロール actPlayer = Game.GetPlayer() fltAngle = actPlayer.GetAngleZ() fltX = actPlayer.GetPositionX() + Math.Sin(fltAngle) * 50 fltY = actPlayer.GetPositionY() + Math.Cos(fltAngle) * 50 fltZ = actPlayer.GetPositionZ() objSweet = actPlayer.PlaceAtMe(potSweet, 1, false, true) objSweet.SetPosition(fltX, fltY, fltZ) objSweet.SetAngle(0, 0, fltAngle) Self.Disable() objSweet.Enable() Self.Delete() actPlayer = None objSweet = None EndEvent
変数を追加で定義しています。Actor
は人や動物の型で、プレイヤーを格納しました。Float
は小数を含む数値を扱います。
プレイヤーの位置と角度からスイートロールのxyz座標を決めるために、Math.Sin
や Math.Cos
などの三角関数を用います。
三角関数の説明はしませんが、プレイヤーの位置と角度から目の前にオブジェクトを置くときは、いつでもこの方法の応用で書けます。「50」の数値を大きくすれば、より離れた所に置かれます。
それから、スイートロールの角度を指定している所は、xyを「0」と指定することで水平に設置しています。床に置く場合には非常に有効です。
以上の座標と角度の指定方法は、最初に作成したキャベツ魔法のときにも同様に使えます。
補足:私はスクリプトを書くのは好きですが、専門家ではありません。内容は creationkit.com の情報と個人的な経験を基にして書いています。どうかご参考程度にご覧ください。
0 件のコメント:
コメントを投稿
注: コメントを投稿できるのは、このブログのメンバーだけです。