Unexpected behaviour from if statement - c#

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;
}
}

Related

Unity Crashes Because of For Statement

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;
}

Following other object with delay in Unity

I'm making a 2D game in Unity, and attempting to have one character move after another in order to attack them. In order to make this movement look natural, I want to add a delay, i.e. character follows the exact path other character took, but 0.5 seconds behind.
Since I'm utilizing the State Pattern for my characters behaviour, the movement logic is in a scriptable object. This means I don't directly have access to Update() or IEnumerator, but I work around this by passing in a reference to a MonoBehaviour script attached to the characterGameObject (not sure if this part is relevant, but included just in case there was some weird side effect that I didn't know about).
I first tried to use IEnumerator, with every Execute() call of the scriptable object (which occurs once every game tick) starting a couroutine which first waited for a set amount of time, and then moved the object.
void Execute(StateController stateController){
Vector3 movementVector =
Vector3.MoveTowards(actor.transform.position,targetWithOffset,
Time.deltaTime);
stateController.StartCoroutine(stateController.MoveTorwards(movementVector,
delay));
}
public IEnumerator MoveTorwards(Vector3 movementVector, float delay)
{
yield return new WaitForSeconds(delay);
gameObject.transform.position = movementVector;
}
However, this resulted in an extremely weird glitchy movement, where the character constantly teleported around itself as it moved torwards the target.
Does anyone have insight into this? Am I missing a fundamentally simple implementation, or was my method correct and the glitchy movement has come from a side effect (doubtful, because the code works perfectly without the IEnumerator, and the glitch still occurs when the delay var is set to zero.
character follows the exact path other character took, but 0.5 seconds
behind.
Step 1: Define what the "exact path" is.
Implement a "consumable" point-to-point path structure (ie Queue<Vector3>), and keep recording the path of the first character to it by recording it's current position on an update loop (ie Update(), directly or indirectly).
Step 2: Try to "consume" the path from oldest node to newest.
For now, ignore the idea of a delay; just make sure that the path system to work, and that the movement looks right.
On each update (Update() or indirect) of the follower entity, move towards the next node in the path until it's reached; when it is, "consume" that node (remove from "path", ie .Dequeue()), and any next nodes that are so close as to be considered "reached"; this, obviously, will make the entity start walking towards next node, if there is any "unreached" node left.
Step 3: Delay the following of the path at start and after the path is empty (and/or based on events & triggers if you need more than that).
When the path goes from a length/count of <=1 nodes to >1 nodes, before you start following the first (or next) segment, do the delay; this will create the effect you're looking for.
If the path's length ever gets <=1 again, it means it's being consumed immediately upon creation, which means the "follower" entity has reached the "followed" entity. In this case, from your description, the "follower" entity attacks the "followed" entity; meaning the game is not instantly ended; in that case, to allow the "followed" to distance itself again (as is implied should be the case) after it starts moving, the delay is applied again before the "follower" starts following. --- This approach to the implementation of delay makes the behavior happen automagically to this case, as it's the same check as is done at "start" (actually a loop); no need for secondary checks.

Performance Issue using Vector3.Distance

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...

c# Xna turned off FixedTimeStep but still update calls max. 60 times

Hi guys i just made a small Algorithm to display the fps to my screen.
frames_temp++;
frames_Time += (int)gameTime.ElapsedGameTime.TotalMilliseconds;
if (frames_Time >= 1000)
{
frames = frames_temp;
frames_temp = 0; frames_Time = 0;
}
this code snipped is located in the Update-method. The frame variable stores the actual value drawn to the screen(just posting that code, to make sure there is no fault, eventhough i checked it already).
Now the problem is that i can't turn off the IsFixedTimeStep. I set it to false inside the constructor, initialize and even the update-method but still the programm limits my fps to ~60. I either put in a for() query into my update-method running many million loops without frame-drops to make sure its not my cpu beeing too slow .Another thing i already tried is to use my own timeSpan and the systemtime to get the elapsed time between the calls of Update(), wich gives me kinda the same output. Now it is 99% sure that update only runs 60 times a second.
So why can't i call the Update-Method as often as possible as it should be when IsFixedTimeStep is false
Ty for replies
I believe that you problem is Vertical Syncing, this function of the graphics device is locking the frame rate to your monitor refresh rate. To solve this problem you need to turn off VSync (SynchronizeWithVerticalRetrace) in the GraphicsDeviceManager:
graphicsDeviceManager.SynchronizeWithVerticalRetrace = false;
graphicsDeviceManager.ApplyChanges();
graphicsDeviceManager is your game's GraphicsDeviceManager
If I recall correct fixed timestep = false results in the update being called before the draw method, not calling it as often as possible. Therefore you should check wheter Vsync or something else is limiting your application to 60fps.

Changing variables outside of Scope C#

I'm a beginner C# programmer, and to improve my skills I decided to give Project Euler a try. The first problem on the site asks you to find the sum of all the multiples of 3 and 5 under 1000. Since I'm essentially doing the same thing twice, I made a method to multiply a base number incrementally, and add the sum of all the answers togethor.
public static int SumOfMultiplication(int Base, int limit)
{
bool Escape = false;
for (int mult = 1; Escape == true; mult++)
{
int Number = 0;
int iSum = 0;
Number = Base * mult;
if (Number > limit)
return iSum;
else
iSum = iSum + Number;
}
regardless of what I put in for both parameters, it ALWAYS returns zero. I'm 99% sure it has something to do with the scope of the variables, but I have no clue how to fix it. All help is appreciated.
Thanks in advance,
Sam
Your loop never actually executes:
bool Escape = false;
for (int mult = 1; Escape == true; mult++)
Escape is set to false initially, so the first test fails (Escape == true returns false) and the body of the loop is skipped.
The compiler would have told you if you were trying to access variables outside of their defined scope, so that's not the problem. You are also missing a return statement, but that is probably a typo.
I would also note that your code never checks if the number to be added to the sum is actually a multiple of 3 or 5. There are other issues as well (for example, iSum is declared inside of the loop and initialized to 0 after each iteration), but I'll let you work that one out since this is practice. The debugger is your friend in cases like these :)
EDIT: If you need help with the actual logic I'll be happy to help, but I figure you want to work it out on your own if possible.
As others have pointed out, the problem is that the control flow does not do what you think it does. This is a common beginner problem.
My suggestion to you is learn how to use your debugger. Beginners often have this strange idea that they're not allowed to use tools to solve their coding problems; that rather, they have to reason out the defect in the program by simply reading it. Once the programs become more than a page long, that becomes impossible for humans. The debugger is your best friend, so get to know its features really well.
In this case if you'd stepped through the code in the debugger you'd see that the loop condition was being evaluated and then the loop was being skipped. At that point you wouldn't be asking "why does this return zero?", you'd be asking "why is the loop body always skipped?" Clearly that is a much more productive question to ask since that is actually the problem here.
Don't write any code without stepping through it in the debugger. Watch every variable, watch how it changes value (the debugger highlights variables in the watch windows right after they change value, by the way) and make sure that the control flow and the variable changes are exactly as you'd expect. Pay attention to quiet doubts; if anything seems out of the ordinary, track it down, and either learn why it is correct, or fix it until it is.
Regarding the actual problem: remember that 15, 30, 45, 60... are all multiples of both three and five, but you only want to add them to the sum once. My advice when solving Project Euler problems is to write code that is as like what you are trying to solve as is possible. Try writing the problem out in "pseudocode" first. I'd pseudocode this as:
sum = 0
for each positive number under 1000:
if number is multiple of three or five then:
add number to sum
Once you have that pseudocode you can notice its subtleties. Like, is 1000 included? Does the problem say "under 1000" or "up to 1000"? Make sure your loop condition considers that. And so on.
The closer the program reads like the problem actually being solved, the more likely it is to be correct.
It does not enter for loop because for condition is false.
Escape == true
returns false
Advice:
Using for loop is much simpler if you use condition as limit for breaking loop
for (int mult = 1; something < limit; mult++)
This way in most cases you do not need to check condition in loop
Most programming languages have have operator modulo division.
http://en.wikipedia.org/wiki/Modulo_operation
It might come handy whit this problem.
There are several problems with this code. The first, and most important, is that you are using the Escape variable only once. It is never set to false within your for loop, so it serves no purpose whatsoever. It should be removed. Second, isum is declared within your for loop, which means it will keep being re-initialized to 0 every time the loop executes. This means you will only get the last multiple, not the addition of all multiples. Here is a corrected code sample:
int iSum = 0;
for(int mult = 1; true; mult++)
{
int Number = Base * mult;
if(Number > limit)
return iSum;
else
iSum += Number;
}

Categories

Resources