我正在尝试创建一个计时器,例如,在EG 15秒期间每3秒钟都会执行操作。
我尝试使用gameTime.elapsedgametime.totalseconds and Loop,但不幸的是它不起作用。
我具有攻击功能,可以在敌人攻击时降低玩家统计。我希望在一个特定敌人的情况下,在指定时间段内的此功能将减去玩家的HP,例如每3秒钟每3秒钟。我想不幸的是,我不知道该怎么做。
public override Stats Attack()
{
attack = true;
return new Stats(0, -stats.Damage, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
}
public override void Update(GameTime gameTime)
{
spriteDirection = Vector2.Zero; // reset input
Move(Direction); // gets the state of my keyborad
float deltaTime = (float)gameTime.ElapsedGameTime.TotalSeconds; // make movement framerate independant
spriteDirection *= Speed; // add hero's speed to movement
position += (spriteDirection * deltaTime); // adding deltaTime to stabilize movement
totalPosition = new Vector2((int)((BottomBoundingBox.Center.X) / 32.0f), (int)((BottomBoundingBox.Center.Y) / 32.0f));
base.Update(gameTime);
}
我将变得简单,因此您需要修改我的代码以实现您的需求结果。
我最好的猜测是,当您的怪物击中玩家时,您想产生特殊效果。
首先,您需要检查怪物是否真的击中了玩家(如果检测到碰撞(:
if (collision)//if it's true
{
// Apply your special effect if it is better than
// the one currently affecting the target :
if (player.PoisonModifier <= poisonModifier) {
player.PoisonModifier = poisonModifier;
player.ModifierDuration = modifierDuration;
}
//player.setColor(Color.Blue);//change color to blue
player.hitPoints -= Poision.Damage;//or enemy.PoisonDamage or whatever you define here
hit.Expire();//this can be for the arrow or bullet from your enemy or simply just a normal hit
}
在您的Player
类中,您需要:
public float ModifierDuration {
get {
return modifierDuration;
}
set {
modifierDuration = value;
modiferCurrentTime = 0;
}
}
然后在 Update
Player
类中:
// If the modifier has finished,
if (modiferCurrentTime > modifierDuration) {
// reset the modifier.
//stop losing HP code is here
modiferCurrentTime = 0;//set the time to zero
setColor(Color.White);//set back the color of your player
}
count += gameTime.ElapsedGameTime.TotalSeconds;//timer for actions every 3s
if (posionModifier != 0 && modiferCurrentTime <= modifierDuration) {
// Modify the hp of the enemy.
player.setHP(player.getCurrentHP() - posionDamage);
//Or change it to every 3s
//if (count > 3) {
// count = 0;
//DoSubtractHP(player);
//}
// Update the modifier timer.
modiferCurrentTime += (float) gameTime.ElapsedGameTime.TotalSeconds;
setColor(Color.Blue);//change the color to match the special effect
}
希望这会有所帮助!
您需要存储开始时间,或者最后一次执行操作的时间。然后,在每个更新期间,将经过的时间与存储时间进行比较。如果三秒钟通过,请执行操作,请存储当前时间并重复该过程。
我不知道单体,但是如果我在我的一个c#应用程序中这样做,我会使用一个计时器,并传递任何计时器需要修改的任何东西。p>这里有很好的信息https://learn.microsoft.com/en-us/dotnet/api/system.timers.timer.timer?view=netframework-4.8,我从这里偷了一些代码,并将其修改为一个例子来证明我的想法。我扩展了系统。Timer允许其运行持续时间并停止自身。您可以设置频率和持续时间,而忘记它。假设您能够从计时器更新此信息。
class Program
{
private static FixedDurationTimer aTimer;
static void Main(string[] args)
{
// Create a timer and set a two second interval.
aTimer = new FixedDurationTimer();
aTimer.Interval = 2000;
// Hook up the Elapsed event for the timer.
aTimer.Elapsed += OnTimedEvent;
// Start the timer
aTimer.StartWithDuration(TimeSpan.FromSeconds(15));
Console.WriteLine("Press the Enter key to exit the program at any time... ");
Console.ReadLine();
}
private static void OnTimedEvent(Object source, System.Timers.ElapsedEventArgs e)
{
FixedDurationTimer timer = source as FixedDurationTimer;
if (timer.Enabled)
{
Console.WriteLine("The Elapsed event was raised at {0}", e.SignalTime);
}
}
public class FixedDurationTimer : System.Timers.Timer
{
public TimeSpan Duration { get; set; }
private Stopwatch _stopwatch;
public void StartWithDuration(TimeSpan duration)
{
Duration = duration;
_stopwatch = new Stopwatch();
Start();
_stopwatch.Start();
}
public FixedDurationTimer()
{
Elapsed += StopWhenDurationIsReached;
}
private void StopWhenDurationIsReached(object sender, ElapsedEventArgs e)
{
if (_stopwatch != null && Duration != null)
{
if (_stopwatch.Elapsed > Duration)
{
Console.WriteLine("Duration has been met, stopping");
Stop();
}
}
}
}
}
您可以看到如何将对象传递到计时器的示例(@jaredpar的示例(如何将对象传递到计时器事件?
string theString = ...;
timer.Elapsed += (sender, e) => MyElapsedMethod(sender, e, theString);
static void MyElapsedMethod(object sender, ElapsedEventArgs e, string theString) {
...
}
做到这一点的一种方法是使用Coroutines。单组没有像其他游戏引擎那样对它们的内置支持,但是它们并不是太复杂而无法实施自己。您需要有关yield
关键字和枚举者的知识来理解它们,但是一旦抽象就可以使您的游戏代码更容易编写和理解。
这是您的游戏玩法逻辑使用Coroutine系统的外观的一个示例,如下所述:
public void Attack(Enemy enemyAttacking)
{
if (enemyAttacking.Type == "OneParticularEnemy")
{
StartCoroutine(RunDamageOverTimeAttack());
}
}
// This coroutine starts a second coroutine that applies damage over time, it
// then waits 15 seconds before terminating the second coroutine.
public IEnumerator RunDamageOverTimeAttack()
{
var cr = StartCoroutine(ApplyDamageOverTime());
yield return 15000; // in milleseconds (ms), i.e. 15000 ms is 15 seconds
cr.IsFinished = true;
}
// This coroutine applies the damage every 3 seconds until the coroutine is finished
public IEnumerator ApplyDamageOverTime()
{
while (true)
{
ApplyDamageToPlayer();
yield return 3000;
}
}
代码读取非常接近您描述要解决的实际问题的方式。现在用于Coroutine系统...
StartCouroutine方法创建了一个Coroutine类实例并将其存储。在游戏循环的更新步骤中,您会遍历coroutines并更新它们,并提供gameTime来计算方法的下一步应运行。每个步骤在例程中执行代码,直到找到收率或方法自然结束为止。Coroutine完成后,您将它们清除。这种逻辑看起来像这样:
private List<Coroutine> coroutines = new List<Coroutine>();
public Coroutine StartCoroutine(IEnumerator routine)
{
var cr = new Coroutine(routine);
couroutines.Add(cr);
return cr;
}
public void UpdateCoroutines(GameTime gameTime)
{
// copied in case list is modified during coroutine updates
var coroutinesToUpdate = coroutines.ToArray();
foreach (coroutine in coroutinesToUpdate)
coroutine.Update(gameTime);
coroutines.RemoveAll(c => c.IsFinished);
}
public void Update(GameTime gameTime)
{
// normal update logic that would invoke Attack(), then...
UpdateCoroutines(gameTime);
}
Coroutine类负责跟踪例程步骤之间的剩余时间,并在例程完成时跟踪。看起来像这样:
public class Coroutine
{
private IEnumerator routine;
private double? wait;
public Coroutine(IEnumerator routine)
{
this.routine = routine;
}
public bool IsFinished { get; set; }
public void Update(GameTime gameTime)
{
if (IsFinished) return;
if (wait.HasValue)
{
var timeRemaining = wait.Value - gameTime.ElapsedGameTime.TotalMilliseconds;
wait = timeRemaining < 0 ? null : timeRemaining;
// If wait has a value we still have time to burn before the
// the next increment, so we return here.
if (wait.HasValue) return;
}
if (!routine.MoveNext())
{
IsFinished= true;
}
else
{
wait = routine.Current as double?;
}
}
}
这似乎比此处提供的其他解决方案更为复杂,并且可能是过分的解决方案,但是Coroutines允许您放弃在跟踪变量中跟踪一堆状态,从而使复杂的场景更易于遵循和清洁更加清洁。ld37/gameObjects/burstarrowspawnbehavior.cs
如果您想更多的社会证明,则可以看一下团结。Unity是最受欢迎的游戏引擎之一,它具有Coroutine的支持。他们描述了一个方案,其中它在其文档中很有用:https://docs.unity3d.com/manual/coroutines.html。
我将其用于游戏:
Public Async Function DelayTask(Time As Double) As Threading.Tasks.Task
Await Threading.Tasks.Task.Delay(TimeSpan.FromSeconds(Time))
End Function
转换为C#:
public async System.Threading.Tasks.Task DelayTask(double Time)
{
await System.Threading.Tasks.Task.Delay(TimeSpan.FromSeconds(Time));
}
您会在异步函数中使用它:
Await DelayTask(1.5);
数字在几秒钟内,您可以通过更改timespan.thateverformat。
来更改此操作。考虑到您将拥有各种影响您统计数据的事物,也许您会在统计课上的更新子例程中检查一下,该类别将检查计划在某个时间点后计划更新的效果列表。这对性能比依靠自己的线程更好。