質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

Unity3D

Unity3Dは、ゲームや対話式の3Dアプリケーション、トレーニングシュミレーション、そして医学的・建築学的な技術を可視化する、商業用の開発プラットフォームです。

Unity

Unityは、Unity Technologiesが開発・販売している、IDEを内蔵するゲームエンジンです。主にC#を用いたプログラミングでコンテンツの開発が可能です。

Q&A

解決済

3回答

5047閲覧

HPがちゃんと満タンにならない【(int)Mathf.Lerp】の加算問題

jum6948

総合スコア20

C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

Unity3D

Unity3Dは、ゲームや対話式の3Dアプリケーション、トレーニングシュミレーション、そして医学的・建築学的な技術を可視化する、商業用の開発プラットフォームです。

Unity

Unityは、Unity Technologiesが開発・販売している、IDEを内蔵するゲームエンジンです。主にC#を用いたプログラミングでコンテンツの開発が可能です。

0グッド

0クリップ

投稿2017/08/23 06:02

###前提・実現したいこと
下記のコードの動作を維持しながら、表示がちゃんと表示されるようになって欲しい。

###発生している問題・エラーメッセージ
キャラクターがダメージを受けてHPが減る分には問題ないのですが、回復アイテムを導入した所
表示されていない数字(DebugLog等でHitPointを表示)は満タンになっているものの、実際に画面に表示されているHPは9足りなくなります。

HP:800/900
↓【回復アイテム取得 (回復量:100)】
HP:891/900

この時の【HitPoint】は900ですが、【displayHitPoint】は891です。

###該当のソースコード
void Update()
{
//【HP関係】
//現在の体力が表示用の体力と重なっていれば、現在の体力になるまで加減算する
if (displayHitPoint != HitPoint)
displayHitPoint = (int)Mathf.Lerp(displayHitPoint, HitPoint, 0.1f);

//最大体力と体力をUI Textにお表示する HpText.text = string.Format("{0:000}/{1:000}", displayHitPoint, HitPointMax, 0.1f); //HPがゼロの以下の時、表示がマイナスにならないようにする、及び死亡時処理 if (HitPoint < 0) { HitPoint = 0; isDead = true; GameDirector.Pdead = true; } //ゲージの長さを体力の割合に合わせて伸縮させる HPgaugeImage.transform.localScale = new Vector3(percentageArmorpoint, 1, 1);

}

###試したこと
本来floatで使うものを、【(int)Mathf.Lerp】このように使っているからだと思います。
displayHitPoint = (int)Mathf.Lerp(displayHitPoint, HitPoint, 【0.1f】);
この【0.1f】部分の数値が大きくなればなるほど、HPの誤差は小さくなりますが、その分HPゲージの伸縮のスピードが早くなりすぎてアニメーションしているのを感じられなくなります。【1f】にすると、アニメーションはしませんが、表示はちゃんとします。また、LeapをClampにしても動作はしますがアニメーションは指定内容に見えます。

###補足情報(言語/FW/ツール等のバージョンなど)
【環境】
Unity5.6.1f1 personal
win10
MicrosoftVisualStudio

int型をfloat型に変換して、1f=最大HPみたいな事をすれば良いのでしょうか?
知識不足すぎてナニをどうすればわかりません。
ご存じの方何卒よろしくお願いいたします。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

ozwk

2017/08/23 08:21

質問文のコードだと最初は急に増えて、だんだん増え方がゆっくりになっていきますが、 それは意図通りですか?
jum6948

2017/08/23 12:20

意図通りです。(のはず)動的にHPゲージを動かす方法がこれしか知らないので、こうなっております。
guest

回答3

0

ベストアンサー

Update内でやるならそもそもMathf.Lerp要らないのでは?
Time.DeltaTimeは「1フレームの時間」を示します。60fpsだと大体0.016です。
これに速度調整用の値を掛け算しつつ増減してやれば目的は果たせるかと。
(IShikawanさんのやり方と考え方は一緒なんですが、fpsが変わるとアニメーション速度が変わるのでTime.DeltaTimeの使用が必要です)

C#

1//前提条件:displayHitPointはfloatにしておきます。 2private float animeSpeedFactor = 1.0; //速度調整用。値を大きくすると早く増減する 3 4void Update() 5{ 6 //【HP関係】 7 //現在の体力が表示用の体力と重なっていれば、現在の体力になるまで加減算する 8 if (HitPoint > displayHitPoint) { 9 displayHitPoint += Time.DeltaTime * animeSpeedFactor; 10 } else if (HitPoint < displayHitPoint) { 11 displayHitPoint -= Time.DeltaTime * animeSpeedFactor; 12 } 13 14 if (Mathf.Abs(HitPoint - displayHitPoint) < 1.0f) { //差の絶対値が1未満の場合は同値とみなす 15 displayHitPoint = (float)HitPoint; 16 } 17 18//最大体力と体力をUI Textにお表示する 19HpText.text = string.Format("{0:000}/{1:000}", (int)displayHitPoint, HitPointMax, 0.1f); 20 21//HPがゼロの以下の時、表示がマイナスにならないようにする、及び死亡時処理 22if (HitPoint < 0) 23{ 24HitPoint = 0; 25isDead = true; 26GameDirector.Pdead = true; 27} 28//ゲージの長さを体力の割合に合わせて伸縮させる 29HPgaugeImage.transform.localScale = new Vector3(percentageArmorpoint, 1, 1); 30}

質問へのコメント見てませんでした。

上記コードだと等速で増減します。
「急に増えて、だんだん増え方がゆっくりになっていく」ような処理が必要なら、
Time.DeltaTime * animeSpeedFactor * Mathf.Abs(HitPoint - displayHitPoint)
とでもしてください。
(2値の差の絶対値を掛け算する=差が大きい程変動値が大きく、差が小さい程変動値が小さくなる=だんだんゆっくり動く)

投稿2017/08/24 01:22

編集2017/08/24 01:40
sakura_hana

総合スコア11427

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

jum6948

2017/08/24 04:21

しゅげぇええ! 求めていたのはコレですよ! 等速アニメと緩急アニメ両方できるようになってるし、速度調整がかなり細かくできるなんて素晴らしいとしか言いようがないです! 実はコレ以外にスタミナも合ったんですけど、ソレは表示を%にしてごまかしていたんですがこれならスタミナも数値化出来るようになるじゃないですか! 「Update内でやるならそもそもMathf.Lerp要らないのでは?」 やり方を一つしか知らなかったので、この一言は衝撃でした。やはり「知っている」と言う事はそれだけ視野が広くなるってことで、自分の関数やらメソッドの不勉強を痛感しました。 本当に有難うございます!感謝感動です!
sakura_hana

2017/08/25 01:48

解決して何よりですが一応備考として。 「差の絶対値が1未満の場合は〜」と決め打ちしちゃってますが、速度設定(animeSpeedFactor)によっては永遠に同値とならない場合があります。 その場合は値を適宜調整してください。 また、負荷対策してないのでそちらも必要に応じて対応していただければと。 (例えばHpText.textを常に書き換えていますが、本来は「値が変わった時だけ」にすべきです。ゲージ伸縮も同様) 1つのやりたいことに対して複数のアプローチがあるので、「これで最適か?」を常に考えるといいかもしれません。 今回は元ソースを生かす為にUpdateを使いましたが、今思えば確かにコルーチンとMathf.Lerpを使ったやり方の方がスマートで負荷軽減になったかもしれません。よかったら調べてみてください。
guest

0

Mathf.Lerpの使い方がちょっとおかしいですね。
A - B 間を時間で補完する関数です。
https://docs.unity3d.com/jp/530/ScriptReference/Mathf.Lerp.html

バッファになる変数を定義してそこを基準に計算しHPに反映するといいと思います。
1ずつ足して反映していますが、実際はもう少し大きい数値の方がいいかもしれません。
今回の件と関係ないですがTransformはキャッシュした方がいいので例を記載しました。
今回の件と関係ないですがUpdate内でnewしなくていいようにキャッシュするといいと思います。

※下記コードにはADD_ONECE_LIFEが1以上の時の処理を記載していません。
※下記コードはfpsを考慮しておりません。fpsを考慮した実装はsakura_hanaさんの実装をごらんください。

C#

1 //1回あたり追加するライフの量 2 static readonly int ADD_ONECE_LIFE = 1; 3 int hitPointBuffer = 0; 4 5 Transform HPgaugeImageT; 6 7 void Start() 8 { 9 HPgaugeImageT = HPgaugeImage.transform; 10 } 11 12 //外部からはこういう感じの関数を呼ぶ 13 public void addLifeCharactor(int addLifePoint) 14 { 15 hitPointBuffer += addLifePoint; 16 } 17 18 private void Update() 19 { 20 if (hitPointBuffer != 0) 21 { 22 int addPoint = hitPointBuffer >= 0 ? ADD_ONECE_LIFE : -ADD_ONECE_LIFE; 23 24 HitPoint += addPoint; 25 hitPointBuffer += addPoint; 26 27 //DEAD 28 if (HitPoint <= 0) 29 { 30 HitPoint = 0; 31 isDead = true; 32 GameDirector.Pdead = true; 33 hitPointBuffer = 0; 34 } 35 //MAX LIFE 36 else if (HitPoint >= HitPointMax) 37 { 38 HitPoint = HitPointMax; 39 hitPointBuffer = 0; 40 } 41 42 HpText.text = string.Format("{0:000}/{1:000}", HitPoint, HitPointMax); 43 44 //※ percentageArmorpointこの値を取る箇所が記入されていませんがこのif文内で完結できるようにするといいです。 45 HPgaugeImageT.localScale = new Vector3(percentageArmorpoint, 1, 1); 46 } 47 }

投稿2017/08/23 07:53

編集2017/08/24 02:31
IShix

総合スコア1724

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

sakura_hana

2017/08/24 01:23

「1回あたり追加するライフの量」を固定値にすると、fpsが変わった場合にアニメーション速度が変わります。 (常に同じfpsで動作するとは限らない為、見栄えに影響する可能性があります) Time.DeltaTimeの使用が必要です。
IShix

2017/08/24 02:32

ご指摘ありがとうございます。コードに注意事項を追記しました。
jum6948

2017/08/24 03:21

返答に時間がかかり申し訳ないです。 キャッシュとかわからなくて、調べておりました。 今年C#初めたばかりで、全然使ったことがない表記方法が多くて、非常に勉強になります。 他でも、使えるかもしれないので週末に動作を試してどう動くか勉強させていただきます。
IShix

2017/08/24 06:16

わかりづらい言い方をしてすみません。キャッシュとは変数に代入しておくという意味です。 GameObject.transformは内部でInternalGetTransform()というinternal mono runtime メソッドを呼びTransformを取得しています。変数にキャッシュすることでこのメソッドの実行が1度だけで済むので処理が少し軽くなるということです。本来であればそんなに気にすることはないですが、Update内は別です。1秒間に数十回の処理が走るのでできる限り無駄を省く設計を心がけておくと吉です。あとは、動く必要が無い場合は処理が走らないようにちゃんと止めておくのも重要です。 C#楽しいですよね!表記で分からないものがあればまた聞いてください。
guest

0

なぜそうなるか。

Mathf.leap(a,b,t)は
a*(1-t) + b*tを返します。

displayHitPoint = 891,
HitPoint = 900のとき、
(int)Mathf.Lerp(displayHitPoint, HitPoint, 0.1f)
= (int)(891.00.9 + 900.00.1)
= (int)891.9
= 891
となり、displayHitPointが変化しません。

ではどうするかですが、
例えば
displayHitPointをfloatで持ちます。(またはこの処理のためにfloatの値を別で持つ)
表示するときはintにキャストします。

ただしこれだと899になってから900になるまで長いか永久に来ないので、

abs(displayHitPoint-HitPoint)が充分小さくなったら
displayHitPoint=HitPointとします。

投稿2017/08/23 06:40

ozwk

総合スコア13528

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

jum6948

2017/08/23 12:26

【abs】っていうのが自分の知識にないので未だに修正できておりませんが、何故そうなるのかの部分がわかりやすく助かりました。 if (displayHitPoint != HitPoint) { displayHitPoint = (int)Mathf.Lerp(displayHitPoint, HitPoint, 0.3f); if (displayHitPoint - HitPoint < 0.1f) { displayHitPoint = HitPoint; } } とりあえずこれで、数字はちゃんと表示されるようになりました。 アニメーション全くしないけど・・・ もしお時間がございましたら、その【abs】の使い方を教えていただけると幸いです。
ozwk

2017/08/23 23:35 編集

絶対値です 今回の例だと displayHitPoint - HitPoint<0なのに その条件文入れるの疑問に思わなかったんですか?
jum6948

2017/08/24 03:09

わからなかったんで、疑問に思いませんでした、ごめんなさい! まだ、C#というものを全然理解していなくて、こうかな?ああかな?と、いつも入力しております。 今回は、学の足りない自分にご教授いただき誠にありがとうございます。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問