I have two objects and one above the other, I want to use the condition to check whether one object is under the other, but for some reason nothing works.
I think this is because the interval between object movements is too large and the code simply does not have time to work on time
[image]1
if (this.transform.position.x == CarPlayer.transform.position.x)
{
print("isPosition");
}
Create a Tolerance Rectangle.
Like
const int tolerance = 3;
var r = new Rectangle(transform.Position.X-tolerance, transform.Position.Y-tolerance, 2*tolerance, 2*tolerance);
if (r.Contains(CarPlayer.transform.position.x))
{
print("isPosition");
}
You can adapt tolerance to your needs.
I'd just use the Vector3.Distance() method which returns a float value of the distance between the two GameObject's transforms. If they are on top of one another, the returned value should be 0.
This way you can easily establish the maximum distance to trigger the "isPosition" condition.
float maxDistance = 0.1f;
if (Vector3.Distance(objA.transform.position, objB.transform.position) <= maxDistance)
{
print("isPosition");
}
if ((int) this.transform.position.x == (int)CarPlayer.transform.position.x)
{
print("isPosition");
RandomPref = rndPref.Next(0, 2);
Instantiate(PrefabsOil[RandomPref], PositionOilDisgarge.position, PositionOilDisgarge.rotation);
}
Related
I'm not very experienced in unity C# so this may be something that is very easy that I'm over complicating.
what I'm trying to achieve is to get a variable to set to something depending on if 2 objects have similar rotations, but its outputting bullet1 every time.
if(hand1.transform.rotation.y > (hand2.transform.rotation.y + 90)
&& hand1.transform.rotation.y < (hand2.transform.rotation.y - 90))
{
bulletresult = bullet1;
}
else
{
bulletresult = bullet2;
}
You need to use hand1.tranfsform.rotation.eulerAngles.y instead of hand1.tranfsform.rotation.y. Same of course for hand2
You can you the function float Angle(Quaternion a, Quaternion b) to find out the angle between to rotation.
And please check your condition again. It will never be true. (Tell me if I am wrong)
Transform.rotation is a Quaternion (see also Wikipedia - Quaternion)!
Except you know exactly what you are doing - which you don't, no offense ;) - NEVER directly get or set the individual components of a Quaternion!
So in case you didn't know: A Quaternion has not 3 but 4 components x, y, z and w. All of them move in the range -1 to 1.
Your condition can never be true.
You could check using Quaternion.Angle
if(Quaternion.Angle(hand1.transform.rotation, hand2.transform.rotation) <= 90)
but be aware that this returns the rotation delta on any axis.
Alternatively for getting the delta only on the global Y-Axis you could rather use vectors and flatten the individual right (local X) or forward (local Z) vectors onto the XZ plane and use Vector3.Angle
// get the local right vectors in global space
var right1 = hand1.transform.right;
var right2 = hand2.transform.right;
// flatten the vectors so we don't have any difference in the global Y axis
right1.y = 0;
right2.y = 0;
// Now get the angle between these
if(Vector3.Angle(right1, right2) < 90)
Since the Dissolve effect process finish when the variable value is 1.08 I want at this value to change the object position. but this comparison I did is never true.
IEnumerator Teleport(float from, float to, float duration)
{
alreadyFading = true;
var timePassed = 0f;
while (timePassed < duration)
{
timePassed += Time.deltaTime;
var factor = timePassed / duration;
var value = Mathf.Lerp(from, to, factor);
foreach (var m in materials)
{
m.SetFloat("_DissolveAmount", value);
if (value == 1.08f)
{
transform.position = teleporters[1].transform.position;
}
}
yield return null;
}
Not all floating point numbers are exactly representable. When you add/subtract you may be adding a little bit more (or less) then you think you are. The value you compare against may not be representable either.
You need to compare to an approximation of that value. Typically this is done by selecting an epsilon value representing a tolerance that is "close enough" and checking that the absolute difference between the actual value and the target value is less than that tolerance. For example:
const float tolerance = 0.00001f;
if (Mathf.Abs(1.08f - value) < tolerance)
{
transform.position = teleporters[1].transform.position;
}
Alternatively you can make use of Unity's Mathf.Approximately
if (Mathf.Approximately(1.08f, value))
{
transform.position = teleporters[1].transform.position;
}
Approximately tests whether the value is within a tolerance of Mathf.Epsilon which is the smallest difference between two floating point numbers. Sometimes this value maybe too small. I suggest defining an epsilon yourself such as the first example.
Floating-point values are imprecise. You should check if the value is within a certain margin of error from 1.08f instead.
You can define an EPS (epsilon) float value and subtract the two floating-point values, get the absolute value of the subtraction and see if it is smaller than EPS. Epsilon is the acceptable tolerance value.
I don't know, though I'd try converting value to temporarily become a rounded-off double, then check if your now double value is == to 1.08, as a double.
keep it simple and try:
if (value >= 1.08f)
{
transform.position = teleporters[1].transform.position;
}
As floating numbers are really hard to compare, use in-build functions like this:
if (Mathf.Approximately(1.08f,value))
{
print("The values are approximately the same");
}
I need to check weather a hole is full or empty, by comparing the transform position of both Cylinders and Holes. Note that I can't simply do else if (cylpos != holpos) as I need it to be that way. It also seems that if (!fullHoles.Contains(hole)) doesn't work as I want it to.
foreach (GameObject hole in Holes)
{
holpos = hole.transform.position;
foreach (GameObject cylinder in Cylinders)
{
cylpos = cylinder.transform.position;
if (cylpos == holpos)
{
fullHoles.Add(hole);
}
}
if (!fullHoles.Contains(hole))
{
emptyHoles.Add(hole);
Debug.Log(hole);
}
}
Thanks for your help!
I don't see why fullHoles.Contains should not do the trick here.
But note that the Vector3 == operator uses a precision of 0.00001 for equality meaning it does the same as
if(Vector3.Distance(cylpos, holpos) < 0.00001f)
I don't know how exactly you move the according objects but it is very unlikely that a moved GameObject will exactly match a position with that precision on runtime.
So I can only guess that the objects where not added to fullholes the way you expected.
You should probably rather use
[SerializeField] private float threshold = 0.1f;
...
if(Vector3.Distance(cylpos, holpos) < threshold)
and adjust the threshold via the Inspector according to your needs
Issue
In unity, I have to calculate the angle of a spawning particle system according to the location where a different object hit it.
During this calculation I identify if the hit occurs on the bottom half of the impacted entity.
This evaluation fails, and produces a different result.
I debugged this (using VS2017 and latest Unity 2018 release) and found that when I perform a 'watch' on the relevant expression, it evaluates to true while when running the code itself it is evaluated to false.
How I Tried to Resolve it
Initially when facing the issue, I managed to work-around it by altering the expression inside of the condition, but now it doesn't change it.
I have tried to pull out the expression to it's own value, but it displays inconsistency regarding the result.
In the debugger it would, on rare occasions, evaluate correctly, while all other times (including not using the debugger) evaluate incorrectly.
The Relevant Code
SpriteRenderer Renderer = GetComponent<SpriteRenderer>();
Bounds Bounds = Renderer.bounds;
Vector3 Center = Bounds.center;
Vector3 HalfSize = Bounds.extents;
if (HitPosition.y != int.MinValue)
{
if (HitPosition.y < Center.y + HalfSize.y && HitPosition.y > Center.y - HalfSize.y)
{
HitPosition.y = Center.y + (HalfSize.y * (Center.y < 0 ? 1 : -1));
}
}
else
{
HitPosition.y = Random.Range(Center.y - (HalfSize.y * 0.2f), Center.y + (HalfSize.y * 0.9f));
HitPosition.x += (HitPosition.x < Center.x ? -1 : 1) * HitPosition.x / 100;
}
bool HitOnRight = HitPosition.x >= Center.x + HalfSize.x;
bool HitOnLeft = HitPosition.x <= Center.x - HalfSize.x;
float Angle = 0f;
if (Center.y - HalfSize.y - HitPosition.y >= 0) // <--- Issue
{
Angle = HitOnLeft ? 135f : (HitOnRight ? -135f : 180f);
}
else
{
Angle = HitOnLeft ? 90f : (HitOnRight ? -90f : 0f);
}
Result Expectations
Since this is a sort-of generic method, that is used accord multiple entities in the scene I expect it to evaluate differently across various
In the cases in which the evaluation issue occurs, I expect it to evaluate to true, in all other occurrences it should (and does) evaluates to false.
Following #McAden and another fellow who removed his answer (or had it removed), the issue was indeed the calculation itself.
I'll explain the reason for the issue, in the case that anyone in the future will come upon this.
Unity, when printing output using the Debug.LogXXX functions, will round all values to 2 decimal points.
I tried to find offical documentation, but as it appears it is a part of C# itself.
float (for those who come from a Java background) is identified as a Single type object, and when printed are printed using the ToString() method which narrows the result to 2 decimal places.
This can cause confusion when performing a standard Debug.LogFormat print, because it will display 2 decimal places, and in cases such as mine, the difference will be so small that the result will be rounded to 0.
After deeper debugging and further diving into the actual value of the difference, I arrived to the point where the values I got were:
Center Y Value: 5.114532
Half Y Value: 0.64
Hit Y Value: 4.474533
Difference Result: -0.0000001192
This is a less than perfect example, because you can see that it will result in -0.000001 difference there were many instances until now that resulted in what appeared to be an absolute 0.
In order to perform a proper comparison, we need to follow C# official documentation, which dictates:
In cases where a loss of precision is likely to affect the result of a comparison, you can use the following techniques instead of calling the Equals or CompareTo method:
Call the Math.Round method to ensure that both values have the same precision. The following example modifies a previous example to use this approach so that two fractional values are equivalent.
using System;
public class Example
{
public static void Main()
{
float value1 = .3333333f;
float value2 = 1.0f/3;
int precision = 7;
value1 = (float) Math.Round(value1, precision);
value2 = (float) Math.Round(value2, precision);
Console.WriteLine("{0:R} = {1:R}: {2}", value1, value2, value1.Equals(value2));
}
}
// The example displays the following output:
// 0.3333333 = 0.3333333: True
Another approach is to implement an IsApproximatelyEqual;
Test for approximate equality instead of equality. This technique requires that you define either an absolute amount by which the two values can differ but still be equal, or that you define a relative amount by which the smaller value can diverge from the larger value.
Eventually, the root cause of this issue was that I had ignored the deeper precision values represented by the variables and thus found myself not understanding why the comparison is incorrect.
Thank you for your help, hope no one runs into this type of silly issue :)
Operator precedence. Try some parentheses.
if ((Center.y - HalfSize.y - HitPosition.y) >= 0) // <--- Issue
{
Angle = HitOnLeft ? 135f : (HitOnRight ? -135f : 180f);
}
else
{
Angle = HitOnLeft ? 90f : (HitOnRight ? -90f : 0f);
}
I'm trying to let a cube drop in unity when i call Input.GetKeyDown("space"), and when a cube is dropped, the second cube is generated and drop again when the space is pressed, however, when I press it again it doesn't work, here is my code
void Update ()
{
if (Input.GetKeyDown("space"))
{
if (!ss)
{
shabi.useGravity = true;
shabi.AddForce(0, 0, -100);
ss = true;
}
}
if (cube1.transform.position.y == y)
{
if (!singleExecution)
{
Rigidbody newCube = spawn();
if (Input.GetKeyDown("space")) //THE PART THAT DOESN'T WORK
{
Debug.Log("sb");
newCube.useGravity = true;
newCube.AddForce(0, 0, -100);
}
y++;
//cubeY += 2;
singleExecution = true;
}
}
}
The function spawn() is used for generate another cube, and the second Input.GetKeyDown doesn't work, thank you for answering my question
I think the problem actually already lies in the line before:
if(cube1.transform.position.y == y)
Since your first object uses gravity, what are the odds that the position in one frame matches exactly y? Additionally comparing two float values might never match even if the value should be the same, see Math.Approximately for more information on that.
This will almost never be true so your code doesn't even reach the Input part.
Now you could ofcourse use
if(Math.Approximately(cube1.transform.position.y, y)
trying to still match an exact y value but the odds that this matches on a free falling object are still very small!
Instead you should use a qualitative comparison like <=. You can either use a wider approximation using the difference between the two values (in this example it matches while the object is less then +-10cm appart from the expected y):
if(cube1.transform.position.y - y <= 0.1f)
but for fast moving objects (which is usually the case for free falling ones) it might be better to simply check if it is smaller than the desired height:
if(cube1.transform.position.y <= y)
This depends obviously on what exactly your purpose is here.