Last Updated 2024.02.28
攻撃時にCharacterControllerが干渉し、もう少し接近して欲しいのに距離が離れてしまってる問題を何とかします。このままだと肘が届いてません。
極論だと、CharacterControllerの大きさ(赤枠)をキャラクターモデルぎりぎりに設定すればよいのですが……
そうすると今度は密着時に足を踏んだり
急にいかがわしい絵面になったり
……ではなく、頭がめり込んだりします。
キャラの喰らい判定は見た目より少し大きめの方が、実際にプレイする場合ストレスが少ないという話を何かの制作話で目にした記憶があって、自分にも心当たりがあるのでそれは避けたいところです。
CharacterControllerの操作で解決を試みるも……
特定の攻撃時に、CharacterControllerの衝突判定をどうにかして「キャラの見た目上の距離をもう少し詰める」というのが今回のやりたい事になります。
まず単純に、攻撃モーションの任意のタイミングで
▼CharacterControllerの中心を後方に下げるとか
characterController.center = new Vector3(0.0f, 0.88f, -0.22f); //終わり際に初期設定に戻す
▼大きさを一定時間だけ小さくするアプローチを試みてみたのですが……
characterController.radius = 0.20f; //初期設定は0.33f
再びまみえたキャラクター貫通問題
今回のはなんとなくカラクリは推察できて、密着時にこれ以上侵入しないよう反発しあってたCharacterControllerが、攻撃側のスクリプト操作によって初期設定に戻ったら喰らってる側の範囲内に侵入してしまい、一回外に出るまで弾くことが出来なくなってるのだと思います。
center操作で判定の中心を一旦下げてから戻す動きだとこれが顕著で、CharacterControllerの操作でなんとかしようとする場合、radiusの値を操作する方がまだ不具合は起き難い……といった結果でした。
判定を小さくしてから元に戻す場合、喰らった側をノックバックさせればまず貫通は起こらないとは思います。実際、撮影時に再現しようとすると狙ってやるのは難しかったです。
ただ、やはり不都合が生じると認識した以上、別の方法で解決しようと模索します。
キャラモデルのTransformを操作する
キャラモデルは親のゲームオブジェクトの子要素に設定していて
CharacterControllerの操作が無理なら、見た目上……キャラモデルの位置を一瞬ズラせばいけるのでは?と思い立ち、今度はそっち方面でのアプローチで考えました。
▼アニメーション関係の制御用スクリプトに下記の内容を追加してみます。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
//アニメーション制御用のスクリプト
public class AnimationControl : MonoBehaviour
private Animator animator;
private float normalizedtime = 0;
//キャラモデルの位置制御用
private Transform characterModelTransform;
private bool moveCharacterModel = false;//キャラモデルを動かしたか否か
private bool positionInitialize = false;//キャラモデルの位置初期化フラグ
void Start()
{
animator = GetComponent<Animator>();
//キャラモデルのコンポーネントの習得
characterModelTransform =
gameObject.transform.GetChild(0).gameObject.GetComponent<Transform>();
}
void Update()
{
//ダッシュ攻撃(肘打ち)時のモデル位置制御
if (animator.GetCurrentAnimatorStateInfo(0).IsName("DashAttack"))
{
normalizedtime = animator.GetCurrentAnimatorStateInfo(0).normalizedTime;
if (normalizedtime >= 0.74 && moveCharacterModel)
{
moveCharacterModel = false;
positionInitialize = true;
return;
}
else if (normalizedtime >= 0.74 && !moveCharacterModel)
{
return;
}
else if (normalizedtime > 0 && !moveCharacterModel)
{
characterModelTransform.localPosition = new Vector3(0, 0, 0.18f);
moveCharacterModel = true;
}
}
//モデルの位置初期化
if (positionInitialize)
{
if (!animator.GetCurrentAnimatorStateInfo(0).IsName("DashAttack"))//ダッシュアタック中じゃないのにフラグが入ってたら
{
characterModelTransform.localPosition = new Vector3(0, 0, 0);//モデルの位置を初期化する
positionInitialize = false;
return;
}
if (characterModelTransform.localPosition.z == 0)//ズラした値が0になったら
{
positionInitialize = false;
return;
}
characterModelTransform.localPosition =
Vector3.MoveTowards(characterModelTransform.localPosition, new Vector3(0, 0, 0), Time.deltaTime);
}
}
ダッシュアタック時にキャラモデルを前進させ、モーションが一定の部分を過ぎたらモデルの位置初期化フラグを入れ、「Vector3.MoveTowards」で徐々に初期の値に戻るようにしています。
余談ですが、ここの部分を「Vector3.Lerp」でも試してみたんですが、ゆっくりすぎるか早すぎるか極端で、ほどよい塩梅に出来ませんでした。これはこれで反撃を喰らうor相打ち等でモーションが中断された際、位置を自然に初期化する手段として採用するかもしれません。
結果……
キャラ同士の隙間もちゃんと縮まっており、かなりヒット感が上がってる気がします。
「キャラモデルだけ」が前進してるので、色んな距離や角度、タイミングで動いても、キャラの貫通は起こらなくなりました。
最後に
見た目とか、内部処理的なプロセスでいえば本当に僅かな差なんですけど、たったこれだけのことでも実際に動かしてみると全然違うように感じるので、個人的にはそういった部分も大事にしながら進めてます。
格ゲーっぽいものを作ってると、腕を使った攻撃(掴みにいくモーションとかも)は「微妙に届いてない」ケースが結構あったので、多少の修正が出来るようになったのは有難いです。
ともあれ調整の甲斐あって、お気に入りの攻撃モーションに仕上がりました。
……仕上げのAnimator矢印調整の際、振ってるだけで1時間以上経過してたことには目を背けつつ。