もしも、あるいはそれ以外のこと

Unityを使ったゲーム作りや、ゲームについて考えたりしています。

VOICEROID実況をはじめてから。投稿者側になって考えたこと①

こちらのブログではお久しぶりです。
一年前から環境が変わり、ゲーム作りもそのままになってました……。
近ごろになって少し落ち着いてきたため、また新しいことをはじめてみてました。
 

◆動画投稿はじめました

f:id:blazwel:20191226100157j:plain

スマブラシリーズのサムネイル

 

 
というわけで動画投稿をはじめてみました。
現在では上記の2シリーズを1~2週間間隔で投稿を続けていて、現在では他の解説動画も含めて12本です。自分の中では割とハイペースに投稿を続けられました。
動画編集の経験はなかったのですが、演出系のことを考えるきっかけにしたいということで。
 
◆VOICEROID実況動画を選んだキッカケについて
 
選んだジャンルはゲーム実況、それにVOICEROIDを使った実況動画です。
 
ちなみに私、普通の実況動画と呼ばれるものをほとんど観ることがないです。その理由は生声を聴くのが苦手なところから来ています。
他人の怒声とか、不意に来る感情の露出がスゴく苦手なんですよね……。
 
そんなこともあり、長らく字幕プレイや、ゆっくり実況などを主に観ていました。が、ここ数年でVOICEROIDという音声読み上げソフトの実況を観る機会が増えてきました。
 
VOICEROIDは音声読み上げソフトですが、人の声をベースにしているため聞きやすかったんですね。
あと単純にかわいい女の子が話しているという雰囲気そのものだと安心できますね。
(いわゆる生声実況ですと、急に入る叫び声や怒声を聴くことがあって、ずっと身構える状態がストレスでした)
ということで、普通の実況よりも馴染みの存在ではありました。
 
また、世の中にゲーム実況動画が増えてきて、ひとつの市場として成り立っている点、配信者と呼ばれる人が多くなっている点、配信側の心理などゲーム実況のジャンル自体に興味がある点がいくつかありました。
ゲームを観る側が存在するということは以前なら考えられなかったですね……。私自身は自分のやったゲームしか観る気は起きない性格です。
ゲームが好きな人も年齢層が幅広くなり、受け取り方も発信する側も形態が変わってきてるのだろうな、と思っています。
 
実況という文化については、文化的にも心理的な面でも深く調べてみたいですね。
 
◆VOICEROIDの知名度とプラットフォームによる受け皿
 
ですが、そもそもVOICEROIDの知名度はいくらばかりのものなのか。よく勘違いしそうになりますが、自分の知っている世界を相手が知っているとは限らないです。
知人にVOICEROIDの存在を訊いたときは、
「なにそれ?」
「ニコニコ? YouTubeで観るから知らないなぁ」
と、ほとんど知らない場合が多かったです。
 
これらは動画配信サイトの傾向性によるものが大きいのか、VOICEROID関係の動画はニコニコが圧倒的に多かったです。
私が投稿した動画は、YouTubeとニコニコの双方に投稿を続けていたのですが、やはりニコニコ動画の方が反響があります。反応が10倍くらい違ってきました。
 
これらはコンテンツを受け入れる土壌があること、作り手と視聴者の距離感の違いによるものが関係しているように感じました。
 
例えば、ニコニコ動画では専用のタグが作られていたり、ゲーム実況を観ればほぼ必ずVOICEROID実況動画が上げられている身近な存在です。
専用の立ち絵や効果音、画像素材は有志の方が無料で公開しており、またその方々も視聴者のひとりです。
私はいつも、立ち絵をお借りしている方にご紹介頂いています……(ありがとうございます)。
このように、ニコニコでは相互的にコンテンツが作られている雰囲気がありました。
 
続いてYouTubeでは、まずVOICEROID実況を見かけることが滅多にありません。
また、ただ動画を視聴する側についてとっては、ニコニコのコメントは動画のノイズに映ってしまい、あえて観る必要もなく感じます。
実際、投稿した動画の再生数は30以下がほとんどです。プラットフォームによる客層の違いを数字で感じましたね。
 
ただし、YouTubeで上げられているものも例外があります。誰か影響力のある人によって知られることで再生数がぐんと伸びたことが一度ありました。
 

f:id:blazwel:20191226093518j:image

 
この跳ね上がり方です。
反してニコニコでは投稿後は安定した再生数を推移します。こういうところからYouTubeのほうが潜在ユーザーは多いのだろうな、と思ったりします。
 
ただ、基本的には(VOICEROID実況に限って)ニコニコのほうが受け入れられやすい土壌ができている、という感じですね。
 
次回はVOICEROIDという「後付け」実況の特徴を踏まえて、キャラクター性や、投稿側の捉え方の面を書いていきます。
 
 

Unreal Engine練習中①

いろいろあって現在Unityを使わなくなってUnreal Engineの習得を始めているのですが、以前に買ったのにぜんぜん進めていなかった定番の書籍

www.borndigital.co.jp

これにまた最初から手を出すことになったんですが、せっかくの休暇ということで手を出したのはいいものの途中で詰まる……_(:3」∠)_

18.3章部分ですね。

f:id:blazwel:20180909142618p:plain

解説の図なんですけどこれができないんですよ…。
デリゲートとデリゲート(参照渡し)と互換性がない、といわれて繋がらないまま。

( ゚Д゚)ウァアアアアッ!!

どうなってるんだろうとネットを検索していると解決策がありました。

satcreative.hatenablog.com

 

こ!れ!!
そしてこの手段の通りにやると解決しました。


いままでUnreal Engineに魅力を感じたことがあまりなくて、Unityばかりだったんですがそうもいってられず。早く慣れないとなぁ。

そんなわけでして、UnityとCorgi Engineを使った記事はちょっと続くかが微妙です。
作ってみたいことは終えてしまったので……ちゃんと一本のゲームを作る、となると最初から企画しないとモチベーションが続かないみたいです。
このへん、機能を作ってみたい、と思えるプログラマーと決定的に違いますねぇ。

なにかまた、やりたいことが見つかったりしたらこのブログは活用したいと思います。

Corgi EngineVer5.0のアップデートのメモ

私情でバタバタしており更新が滞ってました……。

そんななかCorgi Engineが5.0にバージョンアップしてました。

 
今回はいつものゲームづくりメモをお休みして、アップデートのチェックを行います。更新しても大丈夫かな?
その中でも(個人的に)影響のありそうなアップデートをチェックしてきます。
ざっと並べるとこんな感じでした。
  • エネミーのAIのアクションやシステムの追加
  • ボスの行動決定
  • 新しい武器システムの追加
  • 『非常に簡単にコンボベースの武器を作成する可能性を追加』(!!??
  • キャラクターの能力を追加(泳ぐ、飛ぶ、グライド?)
  • 武器の所有者がヒットした時に攻撃中断オプション
  • 武器を称している間、水平動作(反転)を防ぐオプション追加
  • ほか、バグや調整、画面フラッシュイベントの追加など
 

コンボベースの武器!?

 (注:このブログはコンボアクションゲームを作りたいという動機のもとに書かれています)

あれ、じゃあこのブログの存在意義がなくなるのでは……?
  
と、とりあえずチェックしましょうか……。
日本語翻訳をかけているので原文は公式のリリースノートを参照してください。
 

■エネミーのAI

  - 独自の使いやすいステートマシンを備えた新しい高度なAIシステムを追加しました。
複雑な行動、パターンを作成し、意思決定と行動を組み合わせて独自の敵を創造する。
 - 健康(注 Health:体力設定などのスクリプトかな?)、
ヒット、レイキャストターゲット検出、ワイドキャストターゲット検出、
エリアターゲット検出、距離ベースの決定、時間、接地の新しいAI決定を追加
- パトロール、エリア内のパトロール、ターゲットへの移動、
ジャンプ、撃墜、待機、飛行、武器の変更
 
サンプルとしてDemosのRetroから新しく増えたエネミーをチェックしてみます。

スライムベースの敵には円形の索敵範囲を持っており、そこに入ったプレイヤーを狙って撃ってきます。
また、やられた際にはその場にやられモーションを残して存在し続けるようです。
 
従来までのCorgi EngineはエネミーのAI関係は(アップデートで消されたためか)ドキュメントに存在するような高度なシステムが存在せず、基本的には歩いて、正面方向にレイキャストを飛ばし、ぶつかった敵に対して近づく、または射撃する、程度のものしか存在しませんでした。
制御はAI Brainスクリプト側から設定できるようです。

状態名と付随するアクションのスクリプトを設定して、設定したアクションから真になれば別の状態に遷移する、といったシンプルな設定ですね。
(GUI上で設定できない、またはカスタムして細かく設定しようとすると苦労するかも……)
索敵範囲などはスクリプト上で調整可能です。
 
それにしてもザコ敵なのに狙いが正確過ぎません?
 
ほかにもこのシステムを利用したAIがいくつか追加されました。
◆レトロゴースト

……どっかで見たことある挙動ですね?
 
◆レトロソードマン

届いてないよ……。
 
 

■ボスのAI

 
- Corgiエンジンで複雑なボスの動作の最初の例であるRetroRabbitのボスを追加します。
複数の破壊的な武器、フェイズ、ムーブメントを完成させる。

 

 
こちらはボスにした場合の活用例ですかね?

なにこの絶対殺すムーヴ。
 
興味深いのは各武器ごとにAIを設定して、同一キャラクターとして成立できることですね。
また、武器が破壊されると動きも変わるようです。

ジャンプしたり体当たりベースの攻撃に移ったりと破壊状態によって変化を付けられるなどの細かい挙動の設定も可能なようです。
これは面白い動きができそうですねー。
AI Brainの設定は以下のようになって複雑化してます。

そして各武器ごとをエネミー化して、並行して動作させている仕組みです(左手武器)。

■コンボ武器

自分の苦労は何だったんですか!!
と言いたい気持ちを抑えつつ、チェックしていきます。

わかりにくいですが、三連攻撃をしています。二回目はアニメーション反転しています。
コンボ武器を作成するにはAnimator側に専用のBool値を入れ(画像ではSword1~3)、ステートを追加します。
ComboWeaponプレハブを作るには、
  • ComboWeapon
    • MeleeWeapon
    • MeleeWeapon
    • MeleeWeapon
というふうに追加予定の攻撃武器をコンポーネントとして追加します。
各WeaponスクリプトのAnimation Parameters Names のStart Animation Parameterに攻撃用のBoolパラメータ名を入れ、Animatorと連動させれば使用できます。
……たしかにコンボ攻撃ですね。
 
まぁしかし、どのみち攻撃状態に合わせて武器を付け替えるシステムがないと空中攻撃と通常攻撃などを分けたりはできないので、現在進めている方針で問題ない気はします。
ComboWeaponスクリプトの仕組み自体はカスタムして使用したほうがスリムになりそうですね。
 
 ◇◆
 
ほか、追加されたキャラクターのアビリティ関係に関しては割愛します。
今回のアップデートでは今まで歩くだけや撃つだけだったエネミー関係に手を入れられており、かつ、組み込みも簡単そうなのでこれから活用できそうですね。
 
自分でも敵関係にもチャレンジする機会があったら、今回のアップデートの内容を反映させて記事を書こうと思います。
 
それではまた次回。

Unity&Corgi Engineを使用したアクションゲームづくり ~近接武器で殴りたい①~

少しバタバタとしてました更新ができてませんでした。
ゲームづくり自体は続けてますよ(`・ω・´)
Anima2Dを使ってキャラクターのスケルタルアニメーション関連とかを勉強中です。

前回はアニメーション関連をいじってました。当たり判定の追従やらを行いましたが、いかんせん近接武器で殴りたいのに銃撃用の無駄なパラメーターが多いので見通しが悪いです。
これから改造することも考えて、また内部の構造を知るためにスクリプトを組み替えましょう。
(本来はパラメーターの調整などを行う前にやるべきですが、先に仕組みを知りたいのでこうなりました)
前回はこちらです。
blue-mist.hatenablog.jp

■武器の構成
Corgi Engineで使われている武器の構成は以下のような構造になっています。

  • CharacterHandleWeapon
    • 所持する武器
    • 入力受付
    • 状態管理
  • Weapon
    • 攻撃時間
    • アニメーション
    • 攻撃範囲、威力クラス
    • 攻撃状態管理
    • 弾の管理など
  • MeleeWeapon
    • 攻撃範囲の生成/消滅

CharacterHandleWeaponが入力を受け付け、所持している武器に対して攻撃開始の指示を出します。
対応する武器(MeleeWeapon)が攻撃範囲を生成します。
武器の状態は
攻撃開始⇒攻撃前⇒攻撃中⇒攻撃終了待機⇒攻撃終了
という状態を遷移していきますが、こちらはMeleeWeaponのもとのクラス、Weaponクラスが握っています。
終了後、MeleeWeaponは攻撃範囲をオフにして、CharacterHandleWeaponに管理を戻します。

ということで修正するべきスクリプトは先に挙げた三点ですね。
先に改造後のスクリプト名称を決めておきます(何のひねりもないですが)。
ちなみに少し手間がかかってももとのスクリプトを残したまま、継承などを使い組み直したほうがいいと思います。Corgi Engineでは関数をoverrideするだけで使えるように構成されていることも多いです。

  • CharacterHandleWeapon
    • ->CharacterHandleWeaponController
  • Weapon
    • ->SwordWeapon
  • MeleeWeapon
    • ->MeleeAttackWeapon

では元のCharacterHandleWeaponのスクリプトを改造、もしくはコピーして新たにスクリプトを作ります。
HandleInput()も銃関連が混じっているのでごくシンプルになります。

   protected override void HandleInput ()
    {           

        if ((_inputManager.ShootButton.State.CurrentState == MMInput.ButtonStates.ButtonDown) || 
(ContinuousPress && (CurrentWeapon.TriggerMode == Weapon.TriggerModes.Auto) && 
(_inputManager.ShootButton.State.CurrentState == MMInput.ButtonStates.ButtonPressed)))
        {
            ShootStart();
        }
    }

Animator関連のパラメータ項目の修正は、

   /// <summary>
    /// 必要なアニメータパラメータが存在する場合、アニメータパラメータリストに追加します。
    /// </summary>
    protected override void InitializeAnimatorParameters() {
        if (CurrentWeapon == null) { return; }

        RegisterAnimatorParameter(CurrentWeapon.IdleAnimationParameter,
 AnimatorControllerParameterType.Bool);
        RegisterAnimatorParameter(CurrentWeapon.StartAnimationParameter,
 AnimatorControllerParameterType.Bool);
        RegisterAnimatorParameter(CurrentWeapon.DelayBeforeUseAnimationParameter,
 AnimatorControllerParameterType.Bool);
        RegisterAnimatorParameter(CurrentWeapon.DelayBetweenUsesAnimationParameter,
 AnimatorControllerParameterType.Bool);
        RegisterAnimatorParameter(CurrentWeapon.StopAnimationParameter,
 AnimatorControllerParameterType.Bool);
        RegisterAnimatorParameter(CurrentWeapon.SingleUseAnimationParameter,
 AnimatorControllerParameterType.Bool);
        RegisterAnimatorParameter(CurrentWeapon.UseAnimationParameter,
 AnimatorControllerParameterType.Bool);
    }

    /// <summary>
    ///これをオーバーライドして、キャラクターのアニメーターにパラメーターを送信します。
    ///これは、キャラクターによってサイクルごとに1回呼び出されます
    /// class、Early、normal、Late processの後)。
    /// </summary>
    public override void UpdateAnimator() {
        if (CurrentWeapon == null) { return; }

        MMAnimator.UpdateAnimatorBool(_animator, CurrentWeapon.IdleAnimationParameter, 
(CurrentWeapon.WeaponStates.CurrentState == SwordWeapon.SwordWeaponStates.WeaponIdle),
 _character._animatorParameters);
        MMAnimator.UpdateAnimatorBool(_animator, CurrentWeapon.StartAnimationParameter,
 (CurrentWeapon.WeaponStates.CurrentState == SwordWeapon.SwordWeaponStates.WeaponStart),
 _character._animatorParameters);
        MMAnimator.UpdateAnimatorBool(_animator, CurrentWeapon.DelayBeforeUseAnimationParameter,
 (CurrentWeapon.WeaponStates.CurrentState == SwordWeapon.SwordWeaponStates.WeaponDelayBeforeUse),
 _character._animatorParameters);

        MMAnimator.UpdateAnimatorBool(_animator, CurrentWeapon.UseAnimationParameter, 
(CurrentWeapon.WeaponStates.CurrentState == SwordWeapon.SwordWeaponStates.WeaponDelayBeforeUse || 
CurrentWeapon.WeaponStates.CurrentState == SwordWeapon.SwordWeaponStates.WeaponUse || 
CurrentWeapon.WeaponStates.CurrentState == SwordWeapon.SwordWeaponStates.WeaponDelayBetweenUses),
 _character._animatorParameters);

        MMAnimator.UpdateAnimatorBool(_animator, CurrentWeapon.SingleUseAnimationParameter,
 (CurrentWeapon.WeaponStates.CurrentState == SwordWeapon.SwordWeaponStates.WeaponUse),
 _character._animatorParameters);
        MMAnimator.UpdateAnimatorBool(_animator, CurrentWeapon.DelayBetweenUsesAnimationParameter,
 (CurrentWeapon.WeaponStates.CurrentState == SwordWeapon.SwordWeaponStates.WeaponDelayBetweenUses),
 _character._animatorParameters);
        MMAnimator.UpdateAnimatorBool(_animator, CurrentWeapon.StopAnimationParameter,
 (CurrentWeapon.WeaponStates.CurrentState == SwordWeapon.SwordWeaponStates.WeaponStop),
 _character._animatorParameters);
    }

ほとんどが消しただけです。
ChangeWeapon関数部分がWeaponをキャストしている部分があるので、これを近接武器専用クラス、仮にSwordWeaponという基底クラスを作って組み替えます。

元のWeaponクラスはReload、Ammo、Magazineなどの銃に関連した用語部分を消していく形です。
Animatorのパラメータ部分はCharacterHandleWeaponの項目と連動していますのでそちらに合わせるようにします。
また、Weapon States項目を近接武器用に、そちらも余計な項目を消して、enumとして新しく定義します。

       // Weapon State
        public enum SwordWeaponStates {WeaponIdle, WeaponStart, WeaponDelayBeforeUse,
 WeaponUse, WeaponDelayBetweenUses, WeaponStop }

        [Header("Use")]
        // the delay before use, that will be applied for every shot
        public float DelayBeforeUse = 0f;
        // the time (in seconds) between two shots     
        public float TimeBetweenUses = 0f;

        [Header("Position")]
        /// an offset that will be applied to the weapon once attached to 
        /// the center of the WeaponAttachment transform.
        public Vector3 WeaponAttachmentOffset = Vector3.zero;
        /// キャラクターが反転した時に同じく反転する必要があるか?
        public bool FlipWeaponOnCharacterFlip = true;
        /// FlipValue は、フリップ上でモデルの transform's localscale を乗算するために使用されます。
        /// 通常は-1, 1, 1, しかし、あなたのモデルの仕様に合わせてそれを変更することをお気軽に 
        public Vector3 FlipValue = new Vector3(-1, 1, 1);

        [Header("Hands Position")]
        /// キャラクターの左手につけるべき変換
        public Transform LeftHandHandle;
        /// キャラクターの右手につけるべき変換
        public Transform RightHandHandle;

        [Header("Effects")]
        /// 武器を使用した際に発生させるエフェクト
        public List<ParticleSystem> ParticleEffects;

        [Header("Movement")]
        /// これがtrueなら、武器がactiveな間、乗数は動きに適用されるでしょう
        public bool ModifyMovementWhileAttacking = false;
        /// 攻撃中の動きに対する乗数
        public float MovementMultiplier = 0f;

        [Header("Animation Parameter Names")]
        /// Idle:これは、武器が使用されている場合を除き、すべての時間を true になります
        public string IdleAnimationParameter;
        /// Start:武器が使用され始めているフレームにTrue
        public string StartAnimationParameter;
        /// DelayBeforeUse:武器がアクティブになっているが、まだ使用されていない場合は true
        public string DelayBeforeUseAnimationParameter;
        /// SingleUse:Shotがtrueの後、次のいずれかまたは武器の停止の前に
        public string SingleUseAnimationParameter;
        /// Use:武器が発射を開始したが、まだ停止していない各フレームで true
        public string UseAnimationParameter;
        /// DelayBetweenUses:武器が使用中の場合はTrue
        public string DelayBetweenUsesAnimationParameter;
        /// DelayBetweenUses:武器が使用中の場合はTrue
        public string DelayBetweenUsesAnimationIntegerParameter;
        /// Stop:武器が使用された後の次のいずれかの武器の使用前にTrue
        public string StopAnimationParameter;

        [Header("Sounds")]
        /// the sound to play when the weapon starts being used
        public AudioClip WeaponStartSfx;
        /// the sound to play while the weapon is in use
        public AudioClip WeaponUsedSfx;
        /// the sound to play when the weapon stops being used
        public AudioClip WeaponStopSfx;
        /// the sound to play when the weapon gets reloaded
        public AudioClip WeaponReloadSfx;
        /// the sound to play when the weapon gets reloaded
        public AudioClip WeaponReloadNeededSfx;

        /// the name of the inventory item corresponding to this weapon.
        /// Automatically set (if needed) by InventoryEngineWeapon
        public string WeaponID { get; set; }
        /// the weapon's owner
        public Character Owner { get; protected set; }
        /// the weapon's owner's CharacterHandleWeapon component
        public CharacterHandleWeapon CharacterHandleWeapon { get; set; }
        /// if true, the weapon is flipped
        public bool Flipped { get; protected set; }
        /// the WeaponAmmo component optionnally associated to this weapon
        //public WeaponAmmo WeaponAmmo { get; protected set; }

        /// 武器のステートマシン
        public MMStateMachine<SwordWeaponStates> WeaponStates;
        public HandleWeaponCategory WeaponCategory;
        protected SpriteRenderer _spriteRenderer;
        protected CharacterGravity _characterGravity;
        protected CharacterHorizontalMovement _characterHorizontalMovement;
        protected float _movementMultiplierStorage = 1f;
        protected bool _triggerReleased = false;

        protected Vector3 _weaponOffset;
        protected Vector3 _weaponAttachmentOffset;
        
        /// 武器の使用前などを測るためのカウンタ
        protected float _delayBeforeUseCounter = 0f;
        protected float _delayBetweenUsesCounter = 0f;

武器はProcessWeaponState()で状態管理がなされています。ここから少し組みなおさないといけなくなります。
銃の場合はShootRequest関数で

  • 次の弾が入っているか?
  • 弾が装填されて発射可能か?

といった状態を見て武器を使用状態に変更し攻撃を開始させます。
この辺りは近接武器なので必要ない項目になっていきますので削除していきます。

       /// <summary>
        /// Called every lastUpdate, processes the weapon's state machine
        /// </summary>
        protected virtual void ProcessWeaponState() {
~~~~
            case SwordWeaponStates.WeaponUse:
                WeaponUse();
                _delayBetweenUsesCounter = TimeBetweenUses; 
                WeaponStates.ChangeState(SwordWeaponStates.WeaponDelayBetweenUses);
                break;

            case SwordWeaponStates.WeaponDelayBetweenUses:
                _delayBetweenUsesCounter -= Time.deltaTime;
                if (_delayBetweenUsesCounter <= 0) {
                    TurnWeaponOff();
                }
                break;

            case SwordWeaponStates.WeaponStop:
                WeaponStates.ChangeState(SwordWeaponStates.WeaponIdle);
                break;
            }

        }
        /// <summary>
        /// 武器が発射できるかどうかを判断する
        /// </summary>
        protected virtual void ShootRequest() {
            // そのままWeponUseに切り替え
            WeaponStates.ChangeState(SwordWeaponStates.WeaponUse);
        }

        /// <summary>
        /// 武器を使用しているときの状態
        /// </summary>
        protected virtual void WeaponUse() {
            SetParticleEffects(true);
            SfxPlayWeaponUsedSound();
        }

        /// <summary>
        /// 武器を使用不可に
        /// </summary>
        public virtual void TurnWeaponOff() {
            _triggerReleased = true;
            SfxPlayWeaponStopSound();
            WeaponStates.ChangeState(SwordWeaponStates.WeaponStop);
            ResetMovementMultiplier();
        }

微調整はいりますがおおむねこんな感じになります。
作成したスクリプトを継承して、SwordWeaponクラスを継承した近接武器クラスMeleeAttackWeaponを新規作成します。
こちらはほぼもとのMeleeWeaponと変更は大差ないので割愛します。

このスクリプトを作成した後、キャラクターにCharacterHandleWeaponControllerを直接アタッチして使用できるようにします。

このとき、前回までのMeleeWeaponやCorgi SwordなどのWeaponを継承して作成したプレハブは使用できなくなりますので、MeleeWeaponも新しく作成し、CharacterHandleWeaponControllerのInitialWeaponに付け直すことを忘れずに行います。
f:id:blazwel:20180712212040p:plain
動きが特に変わらず、攻撃判定が行われていれば成功です。

◆今後のカスタム
上述の通り、これで最低構成の形態を引き継ぐことができるようになります。
ですが、最初に考案した通り、今後コマンドやコンボ攻撃などを実装する際にはいろいろと不都合が生じます。
Corgi Engineでは一つの武器に対して

  • 攻撃の威力
  • 攻撃のノックバック値
  • 攻撃時間、待機時間、攻撃硬直時間
  • 攻撃範囲

などが紐づいて管理されています。ですから現時点では

  • 攻撃の威力が固定のため、コンボ攻撃のメリットが少ない、攻撃の種類を増やすメリットがない
  • ノックバック値が固定のため、攻撃①(ノックバック弱)⇒攻撃②(ノックバック強)という使い分け方ができない
  • 敵を打ち上げたりといった処理(ノックバック値をY方向に)が行えない

といった不都合が生じます。
これを改善するには一つの攻撃に対して一つの武器として管理し、攻撃ごとに武器を変更する、という処理が一番構成を崩さず管理ができそうに思えます。
つまり、4種類のパラメータを武器ごとに調整して、攻撃を管理する方式ですね。
とりあえず思いつく限りはこんな感じになります。
f:id:blazwel:20180712212046p:plain
攻撃は5種類ですが、コンボ攻撃の1~2段目といった共通化できそうな部分は共通武器を使います。
最後の攻撃だけノックバックと攻撃の威力を強めたり、といった微調整ができるようにします。

こうすることで攻撃アニメーションを追加しても後に武器パラメータを変更した違う武器を用意して対応することができます。

理想としては今回追加したMeleeAttackWeaponに図にあるような攻撃カテゴリを用意し、複数の武器を用意します。
そして現在では一種類しか所持することができないCharacterHandleWeaponControllerに武器種類を最初に定義し、アニメーションごとに武器を交換します。

といった流れになりますね。
次回はこれらの実装を行うことを目標にします。

今回の記事はおもにブログでソースコードを書くには、って感じの自分用の記事になりました('ω') ソースコードの埋め込み大きさでブログ全体のサイズ変わっちゃうのなんとかならないかなぁ……。

Unity&Corgi Engineを使ったアクションゲーム作り ~アニメーションと当たり判定②~

前回はキャラクターのセットアップを行ってキャラクターを実際にCorgi Engineで使えるところまでやりました。
ちなみに前回マテリアルのシェーダー項目を変更したんですが描画順序がおかしくなることにあとで気が付きまして訂正しました……。 
そんな前回はこちら。 

blue-mist.hatenablog.jp

 
では今回は当たり判定周りを調整していきましょう。
とりあえず実際に動かしたらどうなるか、というテストをしてみます。
 

 
……なんでキャラクターが唐突に死亡したんですかね。最初は( ゚д゚)フェッ?って状態になりました。
とりあえず原因を探ります。
 
MeleeWeaponコンポーネントのDamageAreaで当たり判定のMaskを変更する箇所がありますが、ここのTarget Layer Maskが当たり判定を握っています。
ここにPlayerレイヤーが指定されており、Player自身の攻撃が当たる、という設定になっているようです。

これはもともと対人ゲームとかを想定した作りになっているせいですね。シューティングメインのエンジンですし。今回は一人用の想定なのでこのPlayerレイヤーから外して自殺判定をなくします。
初期設定からいろいろいじる予定なのでコピーして使っていきましょう。
Character Handle WeaponのInitial Weaponの項目をコピーしたものに変更して使っていきます。
ちなみにWeapon Attachmentを設定しておくと、攻撃範囲が設定した位置に合わせて動くので「剣を振った位置に攻撃判定を出す」想定なのでつけておきます。

この辺りがちょうど追従して動いてくれそうなので、設定します。

コピーしたWeaponプレハブのMeleeSampleをつけました。
 
当たり判定を視覚化するとこんなかんじになります

当たり判定はWeapon Attachmentの下に生成される「Weaponプレハブ名(Clone)DamageArea」という部分のBox Collider部分です。

 
攻撃アニメーションを1.5倍速にしていますので、発生時間的にはちょうどいいかんじかもしれませんね。
当たり判定をもうすこし調整しましょう。調整点は以下のような感じです。
 
  • Use
    • Delay Before Use…使用前の遅延
    • Time Between Use…使用時間
  • Position
    • Weapon Attachment Offset…実際の装着している部分のオフセット
  • Damage Area
    • Damage Area Shape…当たり判定の形状
    • Area Size…当たり判定の大きさ
    • Area Offset…当たり判定のオフセット値
  • Damage Area Timing
    • Initial Delay…判定が出るまでの遅延時間
    • Active Duration…攻撃判定の時間
  • Damage Caused
    • Target Layer Mask…当たり判定を持つレイヤー属性の設定
    • Damage Caused…ダメージ量
    • Knockback…ノックバックのセットの仕方
    • Knockback Force…ノックバックの力
    • Invincibility Duration…無敵時間
 
このあたりを攻撃判定の出現の時間や形状の大きさなど、一時停止させたりしながら見て調整します(もっといい方法がありそうですが……)。
とりあえず、私はこんなかんじに。

f:id:blazwel:20180704141312p:plain

Flip Weapon On Character Flipのチェックを外さないと逆側の判定がおかしくなります。

実際にどうなるか見てみます。

こんな感じです。
あとでエフェクトを付けたりすることを考えると、すこし大きめに判定を出しておいたほうが爽快感が出るような気がします。
 
◆Animationパラメータの設定
 
Animatorの遷移条件などに使用されるパラメータですが、現在はMeleeStartしか設定していないので遷移の設定をしづらくなってます。
ついでにやっておきましょう。
持たせた武器(MeleeSample)のAnimation Parameters Names欄にAnimatorに影響する部分があります。
ここにAnimator側で使用するパラメータのブール値を入力します。

同様にAnimator側でもパラメータを用意します。

こう設定しておくと
  1. MeleeIdle…武器の入力待機状態
  2. MeleeStart…武器の入力開始
  3. MeleeUse…武器の攻撃アニメーション中
  4. MeleeStop…武器の攻撃終了
というふうに遷移条件を組むことができます。
 
ところでReload~などの近接武器では使用しないパラメータとか項目が気になり始めますね?
今後改造していくことも考えるとそろそろ無駄な項目を排除して、シンプルにまとめることも必要かもしれません。
次回はスクリプト部分も改造してシンプルにまとめつつ、今後の拡張性も考えて組み立てる予定です。

季節感を出そうとするとワンテンポ遅れる ~小説投稿~

今日は小説の宣伝です。実は書いたりもしてます。

kakuyomu.jp

梅雨が明け始めて、この夏に踏み込みそうな時期に雨をモチーフにした小説を上げました!
……いつも季節感を出そうとするとワンテンポ遅くなるんです( 一一)

これを書いたのはスマートフォンが普及しはじめた頃になります。ずいぶんと前ですが、今やネットがあればだれとでも繋がれる世の中になりました。

今の世のひととの繋がりって、不特定多数に向けた発言が誰かに聞こえるような環境だと思うんですね。

私たちはいったい誰に向けて声を発しているのだろう?

そんな疑問を抱くことがあります。

私は雨の日に傘を差すのが好きなんですよね。路面に当たる雨音を聞きながら、切り離されたような感覚を覚えて落ち着くんですよね。
密に張り巡らされたコミュニケーションからすこし離れられて、一息つけるような。

今やみんな、まるで宝石箱を眺めるように、誰もが目の前の端末の中の世界に夢中です。それが身の回りで起こっていることに無関心になりはじめてしまっているような気がして。

現代は、誰かがすぐそばにいるような感覚の中で私たちは過ごしているんじゃないだろうか。
それは、幽霊に取り憑かれたような状態なのではないだろうか。

そう思ったことが書き始めた発端ですね。

久しぶりな投稿になりますが、最後までお読みくださると幸いです。

 

カクヨム 近況ノートより。

Unity&Corgi Engineを使ったアクションゲーム作り ~プレイヤーキャラクターのセットアップ~

Animator関連を触っていたんですが、Corgi Engineでキャラクターを動かすのにセットアップ作業が必要になります。今回は実際に動くところまで。
セットアップ作業自体は同じなので、違うキャラクターを使って試してみたいと思います。(自分が覚えているのかのチェックも兼ねて)
 前回はこちら。
ちなみに今回はプレイヤーキャラクターとしての操作できるまで、ここまでを目指します。
 

 
 
◆キャラクターのセットアップ
 
セットアップに使うシーンは最小構成とされているシーンを使います。
\Assets\CorgiEngine\Demos\Minimal\
MinimalLevelシーン
基本的にテストに使うシーンはここのシーンをコピーして使います。
キャラクターは何キャラかいるんですが、セットアップ用に今回こちらのキャラクターを使います。 

 まずはこのキャラクターをシーンにインポート。選択して、Animatorの設定をもともとのサンプルであったコーギー君の設定に倣います。
 
Corgi Engineのセットアップ初期設定では右向きに各種の設定がされますので(変えられますが、視認上こちらのほうが都合がいい)、ので先に設定を変えておきます。
  • Scale Xを2⇒-2にする
  • Animatorの
    • Apply Root Motionを切る(Animator準拠で座標移動などをさせる設定?だったような)
    • Culling Mode ⇒ Always Animate
に設定変更です。

 Characterコンポーネントを追加します。
そのなかのAuto Build Player Characterをクリックすると一通りのセットアップが終わります。
また、あとで気が付いたんですが、Modelを設定しておかないとFlip On Direction Changeによるキャラクターが反転処理が働きませんので、ここで設定しておきます。
 

するとこんな感じにコンポーネントのたぐいがいろいろくっついてきます。
スクリプトの詳細が開かれている場所が歩く速度などの調整が必要な部分です。
基本的にデフォルトで不自然な動きではないと思ったので、現状私はほぼそのままにしてます。
 

とりあえず、Character Jumpの俗にいう多段ジャンプの項目があり、デフォルトで3回は自由度が高いな、と感じたのでこれだけ二回に直します。
Number Of Jumps⇒2
Jump Heightなどの設定はお好みで。

 
そして使わないスクリプトなどは今のうちに外しておきましょう。

  • Character Crouch しゃがみ
  • Character Dangling ぶら下がり
  • Character Jetpack ジェットパック
  • Character Wall Clinging 壁につかまる
  • Character Walljump 壁ジャンプ
このあたりをアニメーション側がなかったりするので外します。必要に応じて追加というかんじで。
 
 
◆Animatorの設定見直し
 
キャラクターのAnimator設定を変更して歩かせるようにします。
パラメータの設定はコーギー君の設定を参考にします。
\Assets\CorgiEngine\Demos\Corgi2D\Prefabs\PlayableCharacters
ここのプレハブ内のAnimatorのパラメータ設定ですね
 
初期設定から

 
遷移条件を各種Bool値をtrueでつなげてこんなかんじにしました。
 

 
動きを確認してみます。今更ですがキャラクターを出現させるにはシーン内に存在する、LevelManagerのここを変更します。

 
プレハブ化しないとキャラクターが二体生成されますが、現状、画面を見ながら調整しますのでゲームがはじまったら片方をOFFにするかんじでやります。
 

 
んー……? なんか動きがつっかえてますね。それに空中に浮いてますね。
それに影になっているのか、キャラクターが暗いです。
一度コーギー君の設定とアニメーションを確認しなおしましょう。
 

 
コーギー君はちゃんと歩いている感じがしますが、AnyStateから何度も最初から遷移してるのがわかりますね。
どうやらデフォルトの設定に合わせると普通にアニメーションさせる分にはすこし不都合がある様子。
ですので遷移条件とAnimatorの設定を再度見直します。企画屋さんらしくちゃんと状態遷移を書きましょう!
 

 
AnyStateはボタンが押された判定などを使う際にそのまま使えそうなので、ダメージを受けたときや死んだとき、攻撃、などの条件につなげます。
こういう遷移図を書くのにGoogleドライブのプラグイン、draw.ioが便利です。
 
また、空中に浮いたように見えるのは当たり判定が設定されていないのが原因です(でした)。ズレてますね……。

本体よりすこし小さく判定をとって、こんなかんじに。

 
また、キャラクターが暗く見えるのはライティングの影響を受けているからです。
マテリアルのシェーダーをSpriteに変更すると直せます。
既存のマテリアルをコピーしてShader項目だけ変更しました。

※ 追記
こちらで進めるとキャラクターのパーツの描画順がおかしくなるので、StandardでEmissionを使って自己発光させるほうがいいです

f:id:blazwel:20180704084103p:plain

 

 Animatorの各種Stateのアニメーションは足りなければ現状は代わりのもので代用しましょう。
JumpAndFall、DashはRunモーションで、DamageやDeadはないので、今のところは諦めます。

f:id:blazwel:20180701120655p:plain

とりあえず代用。
ここまで来たら確認してみましょう!

f:id:blazwel:20180701115722g:plain

一通り動いてますね!(はず)
次回からはまた、アニメーションや当たり判定を作っていって攻撃系のものを作っていきます。