After I added this one for statement, Unity crashes, I've reopened and reran it several times, but it still crashes. Here is the for statement:
for (i = 0; i < 20; i++)
{
player.transform.position += Vector3.right * -1;
i = 0;
}
Your code results in an infinite loop. If you want to have a repeating function with a delay, you can use Coroutine. The YieldInstruction (yield return new WaitForSeconds(waitTime) in the unity document example) determine the amount of time you wish to wait. The sample code in the document prints infinitely with a 2 second delay; however, rewriting the condition of the while loop is one of the ways that helps you determine when a coroutine ends.
Another way to acheive it is using async/await. However, the instructions you can use for await are not as rich as yield instructions. Moreover, the last time I checked, a while true code with a print statment, keeps printing even when unity is not in play mode anymore.
Your loop is running infinitely. On each iteration you set your counter variable back to 0, hence it never stops and keeps decrementing your player position. Have you tried forcing the loop to quit at one point to see if your program still crashes?
Well, of course you program crashes, you have an infinite loop due to always resetting
i = 0;
which basically makes it equivalent to
while(true)
{
// move
}
since you never exit this loop you never allow Unity to move on in its execution -> The app and the entire Unity editor which runs in the same single Unity main thread completely freezes.
Since you say you want this to happen infinitely anyway, what you rather want is move this into Update which is called once every frame and then use Tim.deltaTime to convert your fixed value per frame into a value per second
// Speed in Units per second
// adjust this via the Inspector
[SerializeField] private float speed = 1;
private void Update()
{
player.transform.position += Vector3.left * speed * Time.deltaTime;
}
Related
I'm making an Asteroid Destroyer game in which you get score as time passes by (the game becomes progressively more difficult), but also when you hit an asteroid. I have written a method inside the Game1 class to calculate the amount of score that should be added by the end of the Update method.
The code is as follows:
private float CountScore(GameTime gameTime, List<Asteroid> asteroids)
{
float addScore = 0;
foreach (Asteroid asteroid in asteroids)
{
if (asteroid.Killed)
{
addScore += 100;
}
}
if (spaceship1.Alive)
{
addScore += 80 * (float)gameTime.ElapsedGameTime.TotalSeconds;
}
return addScore;
}
The method is called like this in the Update method:
score += CountScore(gameTime, asteroids);
The part of the code that adds score as time passes works fine. The problem is that when I destroy an asteroid, instead of getting 100 more score points, sometimes I get 200, sometimes I get 2000 and sometimes I get 5000. I don't understand what is happening, since only asteroids that are killed by the player get the property Killed = true;, so I don't really think it is adding 100 per asteroid on screen.
Does anybody know what could cause this? If it's needed I can post more code, but I didn't want to write too much here for the sake of readability.
Edit:
Adding asteroid.Killed = false; just after adding the score worked. However I still don't understand what was the issue, since it looks like it was looping through the same asteroid more than once.
I would recommend that the logic for adding to the score when an asteroid is killed, is done at the same time as the logic for killing an asteroid.
It is likely that you are iterating through the list of asteroids already when processing the hit detection, and thus it would improve performance if the logic was done at the same time, instead of having another foreach loop, as demonstrated in your code.
Further more your addScore += 80 * (float)gameTime.ElapsedGameTime.TotalSeconds; is unreliable, a player with a higher FPS will have an unfair advantage. I recommend using the deltaTime when adding to the total score during the games progression.
My main problem is, I'm coding a movement simulaltor for a game,
What I want to do is, to check if the character got stuck and its position is not changing.
So What I thought is something like this:
If Me.Location3D is the same for X Amount of time -> Me.SetLocation(Location3D.X = Location3D.X +1, Location3D.Y = Location3D.Y +1)
public void Pulse(float dt)
{
Skandia.Update();
Me = Skandia.Me;
if (Me == null)
{
return;
}
//This void repeats every frame of the game
//functions should take place below
}
If anyone got an idea how to check the elapsed time, that'd be great.
Sadly I havent found such a specific thing on stackoverflow yet, just saying cause the topic sound pretty general.
greetings
If you are working a game, you should use a main loop.
The solution is pretty simple.
Each time you get Inside this method, check the time elapsed between your actions.
You should read this link: https://msdn.microsoft.com/en-us/library/bb203873.aspx
Variable-Step Game Loops
A variable-step game calls its Update and Draw methods in a continuous loop without regard to the TargetElapsedTime. Setting Game.IsFixedTimeStep to false causes a Game to use a variable-step game loop.
Animation and Timing
For operations that require precise timing, such as animation, the type of game loop your game uses (fixed-step or variable-step) is important.
Using a fixed step allows game logic to use the TargetElapsedTime as its basic unit of time and assume that Update will be called at that interval. Using a variable step requires the game logic and animation code to be based on ElapsedGameTime to ensure smooth gameplay. Because the Update method is called immediately after the previous frame is drawn, the time between calls to Update can vary. Without taking the time between calls into account, the game would seem to speed up and slow down. The time elapsed between calls to the Update method is available in the Update method's gameTime parameter. You can reset the elapsed times by calling ResetElapsedTime.
When using a variable-step game loop, you should express rates—such as the distance a sprite moves—in game units per millisecond (ms). The amount a sprite moves in any given update can then be calculated as the rate of the sprite times the elapsed time. Using this approach to calculate the distance the sprite moved ensures that the sprite will move consistently if the speed of the game or computer varies.
I would usually comment with a short answer like this but I'm short 3 reputation.
My solution is just track it with a variable and reset when needed, in your case when character moves.
Double elapsedTimeInMS = 0;
private void YourTimer(object sender, EventArgs e)
{
//Every 10 ms
elapsedTimeInMS += 10;
}
private void btnClick(object sender, EventArgs e)
{
//In your case the character moves
MessageBox.Show(elapsedTimeInMS + "");
elapsedTimeInMS = 0;
}
After edit
You would need to implement a check in your timer to see if elapsed time isn't getting too high.
I have a simple if statement as follows:
if (!state.wasGroundedLastFrame && _speed.y > 0){
_newPosition.y += _speed.y * Time.deltaTime;
}
But as you can see in the image below that it’s entering the block even when _speed.y is less than 0.
What could I be doing wrong?
I using MonoDevelop with Unity in C#
EDIT:
To further clarify, _speed is a private Vector3 variable. In the screenshots below you can see that the value doesn’t change at the time of evaluating the condition, and in the block. The value is calculated before this statement is called.
Another odd thing I just noticed is that when there is no user input this value should be constant (-3.33); it represents the current speed of the character. When I create a breakpoint, in the first frame the value is usually between 0, and -1. However in all the subsequent frames, when I continue execution without removing the breakpoint, the value is -3.33, the “correct” constant value.
There are 2 things I can think of that may be causing this issue:
Your code and compiled version are out of sync. Not sure how to build on MonoDevelop with Unity, but my guess is that it is similar to other IDEs. So do a 'Clean' and a 'Rebuild All' and re-run to see if you encounter the same problem.
You have multiple threads accessing and changing the value for _speed.y. In order to solve that problem, put a lock() around the entire if statement as shown below. You will also need to put the same lock around any code that changes the value for _speed
private object SpeedLock = new object();
...
lock(SpeedLock){
if (!state.wasGroundedLastFrame && _speed.y > 0){
_newPosition.y += _speed.y * Time.deltaTime;
}
}
I have made some collision if statements, but they didn't work.
birdbox3.X += 5;
birdbox3.Y -= 5;
if (birdbox3.Intersects(Banner1)) {
birdbox3.Y += 10;
}
else if (birdbox3.Intersects(Banner2)) {
birdbox3.Y = -birdbox3.Y; }
So if we take the first statement, the box is initially on the left down corner. According to my code, it would ideally be going right+up in my game, once it hits the banner on the extreme top, it should go down+right, thus both the X and the Y positions will increase. But what happens is that is starts bouncing really fast, after debugging I realised it was forever stuck in the first if, it's almost as if it collides 2 times, reverting Y to its initial movement, colliding a 3rd time, and doing the process over and over.
Which brings us to the question, how can I make the Update code run a tad bit slower, or after half a second or such passes, so when it runs, it doesn't misinterpret collisions? Thanks a lot!
If you look at your Update method definition (If you have a regular GameComponent or DrawableGameComponent) , you'll notice you have access to the GameTime:
public override void Update(GameTime gameTime).
You can use that variable to trigger the collision only after a set amount of time. To do that, surround everything by a big if which checks the time elapsed:
private int elapsedTime = 0; //Declared at class level
public override void Update(GameTime gameTime)
{
// We add the time spent since the last time Update was run
elapsedTime += gameTime.ElapsedGameTime.TotalMilliseconds;
if (elapsedTime > 500) // If last time is more than 500ms ago
{
elapsedTime = 0;
birdbox3.X += 5;
birdbox3.Y -= 5;
if (birdbox3.Intersects(Banner1))
{
birdbox3.Y += 10;
}
else if (birdbox3.Intersects(Banner2))
{
birdbox3.Y = -birdbox3.Y;
}
}
}
In that case, the collision code is run only once every 500 milliseconds.
We need to add the elapsed time each time Update is run. Then, when we exceed the threshold, we run the collision bit and reset the timer to 0.
We need the local variable because ElapsedGameTime only knows how much time was spent since the last Update. To carry that number on multiple updates, we need to store it somewhere.
I also encourage you to take a look at MSDN's Starter Kit: Platformer. You can find the download links at the bottom. There a lot of info that can be take from that, like effective screen/input management or a basic physics engine. In my opinion, it's the best thing from the official documentation.
I am working on a system, which is distributing Commands from a HashSet to a Player. I want to distribute a Command to the Player, who is closest to the Command.
void AssignCommand(Player player, HashSet<Command> commandList) {
//Player assigned;
float min = float.MaxValue;
float dist;
foreach(Command command in commandList) {
dist = Vector3.Distance(command.Position, player.Position);
if(dist < min) {
//check if command already assigned to another player
assigned = command.assigned;
if(assigned != null) {
//reassign when distance is smaller
if(dist < command.Distance(assigned)) {
//mark previously assigned command as unassigned
if(player.activeCommand != null) player.activeCommand.assigned = null;
player.activeCommand = command;
command.assigned = player;
min = dist;
assigned.activeCommand = null;
AssignCommand(assigned, commandList);
}
}
else {
if(player.activeCommand != null) player.activeCommand.assigned = null;
player.activeCommand = command;
command.assigned = player;
min = dist;
}
}
}
}
My problem with this code is that if there are a lot of commands in the HashSet it takes quite a while and the framerate drops from ~60 to about ~30 fps on my machine. This is no surprise, because the Vector3.Distance method is just called for (every player) * (every command), which is way too much. I am looking now for a way to reduce the number of calls somehow to improve the performance. Any ideas here?
I also tried running this code in a different Thread, but I gave up, because this is changing and using too many Thread Unsafe values. My latest try brought me to the check if assigned != null throwing an error for comparing.
I would be very grateful for any hints either improving the overall speed of this code or how to run this in a ThreadPool. If required I can also post my JobClass I created for the Thread attempt.
All the threading solutions and optimizations are fine, but the biggest thing you want to keep in mind (for this and for the future) is: Do not use Vector3.Distance or Vector3.magnitude for this, ever. They are inefficient.
Instead, use Vector3.sqrMagnitude, which is the same thing (for distance comparison), without the sqrt (the most expensive part).
Another optimization is to write your own (square) distance calculation, throwing out the y value if you know you don't care about vertical distances. My distance comparison code was slow, so I tested this pretty carefully and found this is the fastest way (especially if you don't care about vertical positions): (EDIT: this was fastest in 2015. Test yourself for the fastest code on modern Unity.)
tempPosition = enemy.transform.position; // declared outside the loop, but AFAIK that shouldn't make any difference
float xD = targetPosition.x - tempPosition.x;
float yD = targetPosition.y - tempPosition.y; // optional
float zD = targetPosition.z - tempPosition.z;
float dist2 = xD*xD + yD*yD + zD*zD; // or xD*xD + zD*zD
Edit: Another optimization (that you're likely already doing) is to only recalculate when a player has moved. I like this one because it doesn't compromise the data at all.
I wrote my own version of System.Threading.Tasks for unity and added something like this for ordering workload based on distance from the camera.
Essentially whenever a task (or in your case command) was needed it passed off a position and the task to a TaskManager that would then each frame sort the items it had and run through them.
You could probably do the same / similar but instead of passing the command to some sort of CommmandManager like I did with a TaskManager do a lookup on creation and pass the command to the player closest to the point in question.
Most people these days are pulling their scene graphs in to something like a quad tree which should make finding the right player fairly fast then each player would be responsible for executing its own commands.
Okay after hours working on the issue I finally found a solution to improve the performance on the one hand and make it threadable on the other hand. I had problems with the threading, because player is a Unity object.. Instead of using the player object within the task I only get its position in the Start() method. Thus I managed to make it threadable, although it seemed strange to me, that I represented the players by its positions using Vector3 now.
Improving the performance did happen by adding another Dictionary storing the already calculated distances for each player. So when reassigning a player the distance did not need to be recalculated again... I am not sure how much of performance this brought, because I tested it together with the Thread, but at least I got rid of some calls of Distance and am back at stabel 60 fps!
Furthermore I messed something up with the recursions, so that I got up to 100.000 recursions for each player.. This should NOT happen o.O. The fix was easy enough. Simply added a minCommand command, which I set during the foreach and only assign commands and touch the Sets AFTER the foreach.. I bet the code would now run like sugar even without threading...