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;
发布者:admin,转转请注明出处:http://www.yc00.com/questions/1745554693a4632747.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