admin管理员组文章数量:1429969
I'm making a turn based RPG in Unity and I have a slider that pops up when the player attacks. A runs down the slider and the closer the player gets the slider to the center and presses Z, the more damage it deals. However, for some reason, instead of it being a simple input, you either have to smash Z or it won't take the input at all.
Here's the code:
void DamageGauge(int target, float power, bool special, string status, string name)
{
int t = target;
float p = power;
bool s = special;
string st = status;
string n = name;
meterOpen = true;
slashSlider.gameObject.SetActive(true);
slashSlider.value = 0;
StartCoroutine(DamageSliderTick(t, p, s, st, n));
}
// ReSharper disable Unity.PerformanceAnalysis
public IEnumerator DamageSliderTick(int target, float power, bool special, string status, string name)
{
bool press = false;
int t = target;
float p = power;
bool s = special;
string st = status;
string n = name;
BattleChar sTarget = activeBattlers[t];
for (int i = 0; i < 51; i++)
{
yield return new WaitForSeconds(.01f);
slashSlider.value += 4;
if (Input.GetKeyDown(KeyCode.Z) || i == 50)
{
float v = slashSlider.value;
if(i != 50)
{
switch (v)
{
case < 20:
DealDamage(t, p, .5f, s, st, n);
break;
case < 50:
DealDamage(t, p, .8f, s, st, n);
break;
case < 85:
DealDamage(t, p, 1, s, st, n);
break;
case < 97:
DealDamage(t, p, 1.4f, s, st, n);
break;
case < 132:
DealDamage(t, p, 1, s, st, n);
break;
case < 170:
DealDamage(t, p, .8f, s, st, n);
break;
case < 200:
DealDamage(t, p, .5f, s, st, n);
break;
}
} else
{
DealDamage(t, p, .5f, s, st, n);
}
slashSlider.gameObject.SetActive(false);
slashSlider.value = 0;
if (activeBattlers[t].currentHP <= 0)
{
RewardDialog.instance.xpPool += sTarget.xpWorth;
RewardDialog.instance.moneyPool += sTarget.dollarWorth;
if (sTarget.itemDrop[0] != null)
{
RewardDialog.instance.ShuffleItems(sTarget.itemDrop);
}
}
UpdateStatus(t);
NextTurn();
break;
}
}
}
I'm making a turn based RPG in Unity and I have a slider that pops up when the player attacks. A runs down the slider and the closer the player gets the slider to the center and presses Z, the more damage it deals. However, for some reason, instead of it being a simple input, you either have to smash Z or it won't take the input at all.
Here's the code:
void DamageGauge(int target, float power, bool special, string status, string name)
{
int t = target;
float p = power;
bool s = special;
string st = status;
string n = name;
meterOpen = true;
slashSlider.gameObject.SetActive(true);
slashSlider.value = 0;
StartCoroutine(DamageSliderTick(t, p, s, st, n));
}
// ReSharper disable Unity.PerformanceAnalysis
public IEnumerator DamageSliderTick(int target, float power, bool special, string status, string name)
{
bool press = false;
int t = target;
float p = power;
bool s = special;
string st = status;
string n = name;
BattleChar sTarget = activeBattlers[t];
for (int i = 0; i < 51; i++)
{
yield return new WaitForSeconds(.01f);
slashSlider.value += 4;
if (Input.GetKeyDown(KeyCode.Z) || i == 50)
{
float v = slashSlider.value;
if(i != 50)
{
switch (v)
{
case < 20:
DealDamage(t, p, .5f, s, st, n);
break;
case < 50:
DealDamage(t, p, .8f, s, st, n);
break;
case < 85:
DealDamage(t, p, 1, s, st, n);
break;
case < 97:
DealDamage(t, p, 1.4f, s, st, n);
break;
case < 132:
DealDamage(t, p, 1, s, st, n);
break;
case < 170:
DealDamage(t, p, .8f, s, st, n);
break;
case < 200:
DealDamage(t, p, .5f, s, st, n);
break;
}
} else
{
DealDamage(t, p, .5f, s, st, n);
}
slashSlider.gameObject.SetActive(false);
slashSlider.value = 0;
if (activeBattlers[t].currentHP <= 0)
{
RewardDialog.instance.xpPool += sTarget.xpWorth;
RewardDialog.instance.moneyPool += sTarget.dollarWorth;
if (sTarget.itemDrop[0] != null)
{
RewardDialog.instance.ShuffleItems(sTarget.itemDrop);
}
}
UpdateStatus(t);
NextTurn();
break;
}
}
}
Share
Improve this question
asked Nov 19, 2024 at 14:27
Mike the ScripterMike the Scripter
176 bronze badges
2
|
2 Answers
Reset to default 1Input.GetKeyDown
will return true only if you press the key during that frame. Because you called it after WaitForSeconds
, there is no guarantee that you just press the key at that frame.
Normally, you can call Input.GetKeyDown
in the Update
event method to record the time the key is pressed, and then compare the difference between the current time and the pressed time in the coroutine. If it is less than a certain threshold, it is considered that the player presses the key during this period.
// Update
void Update()
{
if (Input.GetKeyDown(KeyCode.Z))
zPressedTime = Time.time;
}
// DamageSliderTick
if ((Time.time - zPressedTime < threshold) || i == 50)
{
...
}
You could also wait directly in the Coroutine, just instead of using WaitForSeconds
have a more manual wait loop like e.g.
for(var time = 0f; time < 0.01f; time += Time.deltaTime)
{
if(Input.GetKeyDown(KeyCode.Z))
{
break;
}
yield return null;
}
This allows to track input every frame without missing one and directly interrupts the wait and continues with the rest when Z is pressed.
Despite that, a waiting of 0.01
seconds barely makes sense. For 60
FPS one frame takes about 1/60 = 0.017
seconds. So you could as well just use a
yield return null;
so it waits exactly one frame. Then instead of increasing the slider by a hard value per frame you could go by per second and do
slashSlider.value += 4 * Time.deltaTime;
本文标签: cIEnumerator Not Taking Input ValueStack Overflow
版权声明:本文标题:c# - IEnumerator Not Taking Input Value - Stack Overflow 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/web/1745554693a2663113.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
DealDamage
in multiple places, all basically with the same parameters except one, rather store this one parameter according to your cases and then callDealDamage
in one single place right beforeslashSlider.gameObject.SetActive(false)
– derHugo Commented Nov 19, 2024 at 15:31