Input.GetKeyDown doesn't work when I call it twice - c#

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.

Related

How to check if an object has a rotation in a range near the rotation of another object?

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)

How can I check whether a gameObject is contained in a list?

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

How to find out when one object is under another

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

I'm trying to reduce the Length of this Code

I wrote some code today. I can't figure out how to reduce the length of this code, although it seems repetitive, every part is different.
try {
totalVerts.Add(verts[i]);
if (verts[i].x > maxXvert)
{
maxXvert = verts[i].x;
}
if (verts[i].x < minXvert)
{
minXvert = verts[i].x;
}
if (verts[i].y > maxYvert)
{
maxYvert = verts[i].y;
}
if (verts[i].y < minYvert)
{
minYvert = verts[i].y;
}
if (verts[i].z > maxZvert)
{
maxZvert = verts[i].z;
}
if (verts[i].z < minZvert)
{
minZvert = verts[i].z;
}
}
In this code I am adding the Vector3 position vertices (x,y,z) to the totalVerts Array. I am also testing each x,y,z position whether it is the maximum or minimum of all vertices, if it is, I then set the variables maxXvert, maxYvert... etc to the value that is higher or lower.
If anyone can think of a way to reduce, that would be great. Thank you.
You could use Math.Min and Math.Max.
minXvert = Math.Min(verts[i].x, minXvert);
maxXvert = Math.Max(verts[i].x, maxXvert);
That would make your code more concise and readable, but won't make it any faster.
To make it somewhat faster, you could store x, y, z values in local variables, so they only have to be looked up once instead of 2-4 times. But, the compiler is probably doing this for you anyway. int x = verts[i].x; etc.
You could remove all of the brackets: (No refactoring, just less lines!)
try {
totalVerts.Add(verts[i]);
if (verts[i].x > maxXvert)
maxXvert = verts[i].x;
if (verts[i].x < minXvert)
minXvert = verts[i].x;
if (verts[i].y > maxYvert)
maxYvert = verts[i].y;
if (verts[i].y < minYvert)
minYvert = verts[i].y;
if (verts[i].z > maxZvert)
maxZvert = verts[i].z;
if (verts[i].z < minZvert)
minZvert = verts[i].z;
}
Performance wise, this is fine. The code just looks ugly.
unfortunately the Array.max() function in LINQ is only for .net 3.5 and unity is .net 2.0, so I cannot think of a better way.
If the LINQ where available (which it is not), you could do.
float minX=totalVerts.min(v => v.x);
Or similar which would be a lot neater (I would have to check performance)
It's hard to guess the context of this, but in my experience having different floats represent a vector is an unnecessary pain. If you create two Vetor3 instead of six float, you can still access the individual values (eg. myVector3.x += 1f;). And, by using the higher abstraction, you both make the code more readable and incorporate Vector3 functionalities, like Max and Min methods, that serve the very purpose of simplifying code:
Vector3 upperBound = Vector3.one * Mathf.NegativeInfinity,
lowerBound = Vector3.one * Mathf.Infinity;
foreach (Vector3 vert in verts) {
totalVerts.Add(vert);
upperBound = Vector3.Max(upperBound, vert);
lowerBound = Vector3.Min(lowerBound, vert);
}
As a side note, if you are doing procedural meshes and this is to calculate the bounds, be aware of the RecalculateBounds() method. Most of the times, when I need the bounds of a procedural mesh I read it from mesh.bounds after creating and recalculating the mesh, because I had to do that anyways and just reading if afterwards saves me the trouble.

Bounding Box Collision On Certain Sides

I have a player sprite and a spikes sprite. The spikes are facing down and about at head level with the player. I have set it so that if the right side of the player's rectangle goes into the spikes's rectangle, it stops moving. However, I want to set it up like this-
if (playerRect.Right == spikesRect.Left - 1)
{
speedRight = 0;
}
However, this does not work. The player can continue to go past it. The only way I can get it to work is if I do this-
if (playerRect.Right > spikesRect.Left)
{
speedRight = 0;
}
To clarify, the spikesRect.Left value is 350. I want it so that if playerRect.Right is equal to 349, to stop moving to the right. Thanks for any help, it's appreciated.
If you just want a basic collision, use:
if(playerRect.Intersects(spikesRect))
{
//handle collision
}
I recommend having a velocity and a direction variable instead of different variables for different direction's speeds, it means that you only have to change one variable if you want your character to change speed or direction.
The main problem is is that as your player is moving it is not always going to land on spot 349. as its moving it might move from 348 to 350. therefore it will never trigger when it's 349. What you could however do is.
int i = spikesRect.Left - playerRect.Right;
if ( i < 0 )
playerRect.X += i; //playerRect.X can be replaced by a position variable
When it reaches spot 351. 350 - 351 = -1 so since it is less than 0 it will be added to playerRect.X making playerRect.X moved back to where playerRect.Right is 350. That way it won't look as if your player is penetrating the spike.
I think that the issue is caused by some changes you make to speedRight or to playerRect somewhere in your game. So if you're using VisualStudio just set a breakpoint and check the speedRight and playerRect values.
Although there are a few changes you should make to your game. Firstly you should create a public field into the Player class of type Texture as for the Spike class, then create another field of type Vector2 which indicates the speed and the direction :
public class Player{
public Vector2 DirectionSpeed;
public Texture2D Texture;
//...
public Player(){
//initialize your fields
}
}
Then you can handle the collision by using the method Intersects():
if(player.Texture.Bounds.Intersects(spike.Bounds)){
player.DirectionSpeed = Vector.Zero;
}
If you are trying to handle the collisions with more than one object of type Spike, you have to create a List<Spike> and then iterate with a cicle the entire list:
foreach(Spike s in listSpikes){
if(player.Texture.Bounds.Intersects(s.Bounds)){
player.DirectionSpeed = Vector.Zero;
}
}
EDIT:
Moreover if speedRight doesn't equal 1 or a submultiple of spikesRect.Left - 1 it's obvious that by increasing the position with it playerRect.Right exceeds spikesRect.Left - 1. A solution could be:
if (playerRect.Right > spikesRect.Left - 1)
{
playerRect.Location = spikesRect.Left - playerRect.Width - 1;
speedRight = 0;
}

Categories