Your code is starting a new coroutine every time spacebar is pressed. Even though you're technically waiting within each coroutine instance for 0.5 seconds, it does not prevent a new coroutine from starting. So, you're almost correct - coroutine restarts from the top - a new instance of it - not the same one. Also, the statement if (Time.time >= timeWaited) is always true after first few frames - it returns the total amount of seconds since the game started. (https://docs.unity3d.com/ScriptReference/Time-time.html)
Instead, let's use a standard approach to solve this problem - an accumulator value, that is incremented by Time.deltaTime each frame. (https://docs.unity3d.com/ScriptReference/Time-deltaTime.html)
Step 0: Define time to wait
You already have this in your code - it's called timeWaited. I will rename it here, for clarity. This value should be global to the script (in Unity terms) - this a class field in your MonoBehaviour-derived class:
float minimumTimeBetweenDogSpawns = 0.5f;
Step 1: Accumulator variable
You don't have this variable in your code, so I am introducing it here. This value should be global to the script (in Unity terms) - this a class field in your MonoBehaviour-derived class:
float elapsedTimeSinceSpacebarLastPressed = 0; // feel free to make the name shorter, lol!
Step 2: Accumulate Time.deltaTime on each frame
Now, the Unity Game Engine (in fact, all game engines) keeps track of time that elapsed between each frame. This is a very important concept in game development, as it allows smooth movements of objects regardless of a frame taking a little bit longer or little bit shorter to run - since we know the elapsed time since last frame, we can use it in calculating object positions, how much a unit should advance by, etc. In our case, we are just using this value to get to a desired point - 0.5 seconds in your case, expressed by the minimumTimeBetweenDogSpawns variable.
So, how and where do we accumulate the elapsed time? Simple - just add it in Update:
void Update()
{
elapsedTimeSinceSpacebarLastPressed += Time.deltaTime;
}
Step 3: Check if it's time to spawn a new dog!
So, what do we do with this elapsedTimeSinceSpacebarLastPressed? So far, it keeps growing... we need to check if it reached the value of interest - in our case, minimumTimeBetweenDogSpawns has been reached., but only if spacebar was pressed. Let's add an if statement in Update to do that. I'll expand on Update from Step 2:
void Update()
{
elapsedTimeSinceSpacebarLastPressed += Time.deltaTime;
if(Input.GetKeyDown(KeyCode.Space)
&& elapsedTimeSinceSpacebarLastPressed >= minimumTimeBetweenDogSpawns)
{
// Do stuff! Spawn a dog! Run a coroutine! Have a ball!
elapsedTimeSinceSpacebarLastPressed = 0; // ...but don't forget to reset the accumulator!
}
}
Did you catch that last line? Very important - reset the accumulator! This restarts the process, allowing us to spawn more dogs, but not before reaching the value specified by minimumTimeBetweenDogSpawns.
Notes
Technically the coroutine is not necessary, but can be useful - suppose that you wanted to do some time-consuming task - say, the dog spawns with an animation that takes approx. half a second, which would be a good reason for the delay in-between the spawns.
Contrary to some of the comments on the original post, the difference between machines in terms of speed does not matter for this approach! Time is time - all that might change between machines is how many frames run before the next spawn - but not the time elapsed! In a properly written game, we never care how many frames past - we rely on timing, which is why some version of deltaTime is provided by every game engine and framework out there.