So I’m trying to do something relatively simple. I have 2 soldiers. Soldier A walks up to Soldier B. Soldier B turns towards soldier A and they attack each other. They each have 50HP, each has a 1 second reload and each does 10 damage. In theory, both soldiers should die as they are equally powerful.
However, because I’m waiting for Soldier B to turn, the coroutines are not starting at the same time, so 1 soldier dies before the other.
Is there a way to start 2 coroutines at the exact same time? How would you accomplish something like this?
Well, if there weren’t any misses or any other factors… whomever struck first would win (logically speaking).
Unless you imagine they’re hitting each other at exactly the same time in each ‘strike’…
You can’t run 2 at the same time. Things run one after another (without going outside this convo).
Several things come to mind… like … the soldier is mortally wounded but alive long enough for a final fatal blow to the other…etc… a soldier fires an arrow, but is hit by one after its fired , and so on.
Hard to say how your game works…
even in your example, if soldier one is turning but knows he’s turning to attack, can he be in attack mode, already? maybe he hits first? I have no idea.
Sorry, I wasn’t descriptive enough. That’s the greatest sin you can commit when posting a question
Even worse, I was busy all day today so I replied very late
Basically, in my game I want soldiers of equal strength to kill each other since they’re equal. So when Soldier A is waiting for Soldier B to turn, A is not attacking yet. Only when B turns around do they both attack each other. So I want them to start attacking each other at the same time so they’ll both die.
In theory, I could just issue 1 more blow after death to ensure the enemy is dead, but this would be awkward with longer reload times. For example: Let’s say I had 2 equal catapults attacking each other, each having a 30 second reload. They both fire at the same time (appearing to the player), but Catapult B dies because it killed A before it could fire. 30 seconds later, Catapult B destroys Catapult A while B is dead. This is a situation I want to avoid, so simply reloading once more after death isn’t an option
Is there any way to make things happen at the same time in C#, or at least give the impression that they are?
Hopefully I was more descriptive this time. When I get off my laptop and back to my PC I can post a video of how it looks.
Still not understanding the full problem. So when B attacks A can you not just have the part that takes damage in A counter attack when it takes damage? You could even have conditions to make sure that B was in range or counter attack would fail.
I’m just spitballing here, but could you build some sort of basic queuing system (for lack of a better description) and have the attacks play out all together in one coroutine?
Your catapult description made sense to me except that in your explanation you gave catapult B exactly zero time to respond… but anyways, games are sometimes like that.
If that’s really want you want - that two equal combatants always kill each other, I guess you could delay the “impact” a frame (or even use LateUpdate maybe?).
if the fighting groups are small enough, you could have some “exchange damage” logic that considers all parties and their attacks/defenses … sums that all up and then deals the consequences.
Like you said, there could “allow 1 more attack” (not sure how you foresee a 30 second problem here if they are equal).
As I was writing, queuing was suggested as well as auto-counter attack.
From from all this & that… surely you have some options/ideas… to cobble something ;)?
@cstooch I was thinking the same thing. Have like a combat controller that did the combat. So B would report it was attacking A and the combat controller would play the fight out and kill what needed to be killed and such. Also a solid idea and way to approach it.
Well if I’d Debug.Log everything, here’s the sequence of events:
Soldier 1: Waiting for Soldier 2 to turn
Soldier 2: Finished turning, now attacking Soldier 1
Soldier 1: I have 10HP, dealt 5 damage to Soldier 2
Soldier 2: I have 5HP, dealt 5 damage to Soldier 1
Soldier 1: Killed soldier 2. I have 5HP left
So as @Phorsaken (love that username) pointed out, the problem is that both scripts aren’t taking each other into account properly.
Perhaps I could just take Health * Damage per second when they start attacking each other, and if they are the same then when 1 dies, the other one dies too?
That’s a great idea, but how would that fix the problem of 1 thing happening after another?
My issue is that 1 soldier dies before the other (as I explained in the Debug.Log example above). So the soldier that got attacked 1 line before the other soldier got attacked will die, because any sort of combat controller will realize that 1 soldier died 1st.
Even if you cut out the whole “Soldier B turning thing” and just have them attack each other head on, 1 will still get hit before the other. Even if I put them in 1 function like this:
UNLESS!! I have them both take damage, and then check if HP is less than 0 after they’ve been damaged! As I was writing this reply, I think I’ve got the solution:
First, determine if they’re equal power. This can be done by calculating damage per second, then doing (HP * DPS). Wait for both of them to attack each other. Only after both have attacked each other, check the HP. That way, both of them can have HP of 0 or less.
I had no idea something so simple could become so hard, then find the solution myself while replying to someone else
Yeah, I was going to add that you may want to break it down into combat states – Attack and/or Damage state, and resolution state that runs afterwards to kill off anything that should die.
Also a handy way to deal with nearby exploding barrels, etc.
There are two ways to do approach this, depending on your game type.
For an action/fps type game you can just give projectiles an ‘in flight’ time. That means if two entities fire at each other at the same time, the projectile will continue to exist and do damage even if the entity firing the projectile dies.
For a strategy game, I would implement it with a custom update loop or ‘tick’. At the beginning of a tick all entities do damage. At the end of a tick all entities check for death.
The tick approach is kind of essential for strategy games in general, so its worth learning.
I need to read up on the tick approach. By tick approach, do you mean creating 1 script that manages all the different soldiers fighting each other? I’m not sure how I’d go about making a script that would dynamically keep track of the HP, damage and reloads of hundreds of soldiers. I thought I’d just have a HP/DMG script on each soldier, but that’s turning out to be harder than I expected. I’m having some difficulty figuring out how I’d go about implementing my solution above.
Perhaps there’s something I can read and learn about making strategy games? I feel like I’m re-inventing the wheel here with terrible results.
At the beginning of the round, you run through all entities, and each ones gets a chance to add a command to a queue. Use some ICommand interface which lets you create specific commands (direct strike, AOE damage, etc.).
After looping through all entities, it’s time to start processing the commands.
If the command is a direct entity-entity attack, and the target has a special counterattack, then a new command gets pushed to the end of the queue.
If the command is some AOE splash damage that causes nearby barrels to explode (same idea as counterattacks), you can create a new AOE command to add to the end of the queue.
If the command is a DOT, just update it, process accordingly (i.e. command stays in the queue until x turns or time passed).
The command could even be some slowly expanding AOE. Whatever, it’s up to you to decide how to implement the command.
In the end, you have these states:
Loop through entities to check for new commands to add to the queue
Loop through commands, processing each one until the end of queue is reached
Loop through entities to kill off dead entities (i.e. begin playing death animations, etc.). You might want to consider moving these entities to some “dead entities” list that can no longer generate commands if that simplifies things for you.
Thanks for the ideas!! I’ll pour over them for the next week (I’ve got almost no free time this week) and see what I can come up with. I’ll make sure to post what works for me once I’m done