I want to know, how to get no collision inside an object.
I have a big circle and inside the circle is a smaller square. When the game starts, the circle is scaling down.
And what i want, is to check the collision, if circle is touching or is inside the square.
Can you please help me ? Thank you
As far as I know there is no built-in way of achieving this in Unity (There is also not a built-in way of detecting whether a collider is fully inside another collider or not).
If I understood you correctly your circle is going to shrink and when it reaches this point
you want to do something e.g. execute some code.
The way you could make it work for a circle and a square just based on maths would be this:
If the sides of your square are of length a and your circle has a decreasing radius of r, then at the moment you see in the image above the relation between the two of them is:
r = a / sqrt(2)
So you could check if (r <= a / Mathf.Sqrt(2)) in the Update function and based on that call some function. (Maybe add another boolean to ensure the function only gets called once.)
You can get your sprite widths using
width = GetComponent<SpriteRenderer>().bounds.size.x;
The radius of your circle would then obviously be half the width of the circle sprite.
You should probably also store the SpriteRenderer in a variable once instead of calling GetComponent on every frame.
For an equilateral triangle the equation would be
r = a / sqrt(3)
where a is the length of the triangle's side.
Related
I'm not really like to post questions about problems without doing the research, but I'm close to give up, so I thought I give it a shot and ask you about my problem.
I want to create a custom collision detection in Unity ( So please don't advice "use rigidbody and\or colliders" because I don't want to use them by purpose).
The main idea: I want to detect Basic Sphere and Basic Box collision. I already find AABB vs Sphere theme with the following solution:
bool intersect(sphere, box) {
var x = Math.max(box.minX, Math.min(sphere.x, box.maxX));
var y = Math.max(box.minY, Math.min(sphere.y, box.maxY));
var z = Math.max(box.minZ, Math.min(sphere.z, box.maxZ));
var distance = Math.sqrt((x - sphere.x) * (x - sphere.x) +
(y - sphere.y) * (y - sphere.y) +
(z - sphere.z) * (z - sphere.z));
return distance < sphere.radius;
}
And this code does the job, the box bounding and the sphere center point with radius works fine, I can detect the Sphere collision on Box.
The problem is, I want to Rotating the Cube in Runtime, so that will screw up everything, the bounding will split away and the collision will gone (or collide on random places). I've read about some comments where they said, bounding not works with rotation, but I'm not sure what else can I use to solve this problem.
Can you help me with this topic please? I'll take every advice I can get (except Colliders & Rigidbodies of course).
Thank you very much.
You might try using the separating axis theorem. Essentially, for a polyhedron, you use the normal of each face to create an axis. Project the two shapes you are comparing onto each axis and look for an intersection. If there is no intersection along any of the axes, there is no intersection of shapes. For a sphere, you will just need to project onto the polyhedron's axes. There is a great 2D intro to this from metanet.
Edit: hey, check it out-- a Unity implementation.
A good method to find if an AABB (axis aligned bounding box) and sphere are intersecting is to find the closest point on the box to the sphere's center and determine if that point is within the sphere's radius. If so, then they are intersecting, if not then not.
I believe you can do the same thing with this more complicated scenario. You can represent a rotated AABB with a geometrical shape called a parallelepiped. You would then find the closest point on the parallelepiped to the center of the sphere and again check if that point exists within the sphere's radius. If so, then they intersect. If not, then not.
The difficult part is finding the closest point on the parallelepiped. You can represent a parallelepiped in code with 4 3d vectors: center, extentRight, extentUp, and extentForward. This is similar to how you can represent an AABB with a 3d vector for center along with 3 floats: extentRight, extentUp, and extentForward. The difference is that for the parallelepiped those 3 extents are not 1 dimensional scalars, but are full vectors.
When finding the closest point on an AABB surface to a given point, you are basically taking that given point and clamping it to the AABB's volume. You would, for example, call Math.Clamp(point.x, AABB.Min.x, AABB.Max.x) and so on for Y and Z.
The resulting X,Y,Z would be the closest point on the AABB surface to the given point.
To do this for a parallelepiped you need to solve the "linear combination" (math keyword) of extentRight(ER), extentUp(EU), and extentForward(EF) to get the given point. In other words, what scalars do you have to multiply ER, EU, and EF by to get to the given point? When you find those scalars you need to clamp them between 0 and 1 and then multiply them again by ER, EU, and EF respectively to get that closest point on the surface of the parallelepiped. Be sure to offset the given point by the Parallelepiped's min position so that the whole calculation is done in its local space.
I didn't want to spend any extra time learning how to solve for a linear combination (it seems it involves things like using an "augmented matrix" and "gaussian elimination") otherwise I'd include that here too. This should get you or anyone else reading this off to the right track hopefully.
Edit:
Actually I think its a lot simpler and you don't need a parallelepiped. If you have access to the rotation (Vector3 or Quaternion) that rotated the cube you could get the inverse of that and use that inverse rotation to orbit the sphere around the cube so that the new scenario is just the normal axis aligned cube and the orbited sphere. Then you can do a normal AABB - sphere collision detection.
I am trying to draw a line animation outline various shapes as in the image below. I am very well aware that it's best practice that I mention what I've been able to achieve to get specific help, but I am not sure where to begin, just that I know that using a Line Renderer could be a good approach to achieving this. That said, how can I achieve this?
UPDATE
I think I didn't explain a few things clearly enough. I am interested in animating the outline of objects without arrows, just a line traced round the outline like the image below:
I would do the following: (pseudocode, untested)
For every prefab or gameobject, store a List of edges that define your outline.
I wouldn't recommend using the mesh's edges, it's probably better to have a specific predefined list of edges per shape to avoid the inner edges of the object. Every entry in the list is defined by two Vector3's which are the two vertices.
List<Vector3[]> outline = new List<Vector3[]>();
Now, you have many ways to actually draw the arrows, like having them as individual gameobjects (probably not a good idea), particle system, or just drawn automatically from the parent objects update function. I would recommend the latter.
Now you would store a bunch of floats that define where your arrows are
public List<float> arrow_locations = new List<float>();
//adding one arrow
arrow_locations.Add(0.0);
//now in the update function of your parent object, update the arrow locations
private float cycle = 0.0f;
void Update()
{
float segment_size = 360.0f/outline.Count;
for(int i=0; i < arrow_locations.Count; i++)
{
arrow_locations[i] += 0.05f; //speed of spinning
if( arrow_locations[i] >= 360.0f ) arrow_locations[i] = 0;
//now to get the actual location of the arrow
int which_edge = Mathf.Floor((arrow_locations[i]/360.0f)*outline.Count);
//this will give us a number 0..1 telling us where along the edge the arrow is
float weight_within_edge=(arrow_locations[i] - segment_size*which_edge)/segment_size;
//here we lerp between the two vertices of the edge
Vector3 new_loc = outline[which_edge][0]*(1.0-weight_within_edge) + outline[which_edge][1]*(weight_within_edge);
//now that we have the location of the arrow, draw it
//note, you can get more efficient if using instancing for all arrows
//You can also use line drawing, but i wouldn't recommend that.
DrawMesh(arrow_mesh, new_loc, Quaternion.identity);
}
}
Please note, that when you have the positions of the arrows, you can opt to draw them in 2D in the UI by projecting them onto the camera plane. The lines aside from the arrows are themselves static, so you can draw them as part of the mesh very easily. Also note, I make no mention of the objects position, all values should probably be defined in local space, then transformed with the object. You can transform the drawn stuff in the the DrawMesh function by supplying a a transform matrix.
I think a shader with a parameterized radial mask would be the best way to do this. I have never done one myself, so I only have a general idea of how it's done, but here is how it would work AFAIK:
Create some kind of cell shader that can draw the edges of objects.
Create a filter/mask that has an angle shape extruding radially from the center to the edges; you can control the shape/angle using a parameter. Unity already has something similar to this in the Tanks! tutorial - Tank Health lesson.
Note: The tutorial might even be exactly this idea, but I don't remember with enough details to confirm; I'll update the answer after I take a look again.
The tutorial has the same idea, but it applies it using unity's builtin UI stuff.
Using this mask, only the masked area of the shape's edge will be drawn the screen.
By increasing the angle parameter of the mask over time, you can create the effect of the edge of the object getting revealed radially over time. Which seems to be exactly what you want.
To help visualize, a very professional diagram made in paint:
light blue = mask.
dark blue = "revealed" part of the mask (angle parameter). Plus how it would behave if the angle is increased (arrow).
green = object.
black = outline being drawn to the screen.
I have been working on and off of a certain game I'm making (trying to get it finished!) and a problem that has been unsolved for a while in it is the collision detection between a ball and a square.
Basically what I want to happen eventually is depending on the angle/way the rectangle is facing, I want the ball to bounce of it accordingly (I know I could just inverse the ball direction before/as it hit the square).
At the moment though, my current problem is trying to inverse the correct X and Y components depending on the side/face that the ball collides with the square, e.g. if the ball hits the right side of the square, then I need to inverse the ball's X component.
This doesn't seem to work and I was wondering if I could somehow label each side of the rectangle, in terms of for the top of it label that 'face 1' or something, then for the right side of it 'face 2' or 'side 2', etc...
I have provided some code below (this is the code I'm using now):
//(collision with right side of square)
if (theBall.GetRectangle.Left <= thePaddle.GetRectangle.Right)
{
theBall.pVelocity.X = -theBall.pVelocity.X;
}
//(collision with bottom of square)
if (theBall.GetRectangle.Top <= thePaddle.GetRectangle.Bottom)
{
theBall.pVelocity.Y = -theBall.pVelocity.Y;
}
I have written the code for the other 2 sides of the rectangle but they are just the opposite of the two above, i.e. for collision with top of rectangle = opposite of bottom, etc.
EDIT: the object I am checking against if the ball has collided with DOES NOT move, I mean it only rotates... so I don't know if this is important (it probably is, therefore I apologise for missing this info out at the start).
EDIT # 23:36: ok, I have tried something.... and it hasn't worked... :(
public Vector2 DistBetweenBallAndBlock(Paddle thePaddle, Ball theBall)
{
Vector2 centreOfBall = new Vector2(theBall.Texture.Width / 2, theBall.Texture.Height / 2);
float distX = thePaddle.Position.X - centreOfBall.X;
float distY = thePaddle.Position.Y - centreOfBall.Y;
if (distX < 0)
{
distX = -distX;
}
if (distY < 0)
{
distY = -distY;
}
return new Vector2(distX, distY);
}
I have then tried to just print the result just to get an idea of what's going on and what sort of values are being output:
Vector2 a = ball.DistBetweenBallAndBlock(paddle1, ball);
angleOfPaddle = Math.Atan2(a.Y, a.X);
I then just print this value to screen, however I am getting the same result of 0.63...
To detect a collision between Rectangles you could use Rectangle.Intersect method, instead of checking the objects' sides.
And to detect which side of the rectangle is hit, you can compute the Vector2 between the ball center and the rectangle center. Getting its angle with Math.Atan2 you can easily know which face of the rectangle has been hit.
Looked up some Vector stuff, based on my comment.
Collision Style
The optimal way of colliding with a circular object is to collide using a vector between it and the nearest point of the object you're checking against. If the distance is less than or equal to the radius of the circle, there is a collision. The advantages of this method are that you don't have to keep track of a rectangle, you get circular collision, and you get the angle of the collision from the vector.
How You Do It
I'll assume you have some strategy to keep from considering every object every frame, and keep to the basic problem. Your paddle has 4 vertices, one for each corner. Because your ball is essentially a vertex with a picture drawn over it, you can easily check the distance between the ball and each corner of your paddle. Two will be nearest. From there, it's just a matter of finding out if that edge collides. I found a solution to that here, which includes a nice formula.
Does that help?
I have been trying to wrap my head around how my Linear and Vector Algerbra knowledge fits in with Computer Graphics. Particulary in the language C#
The knowledge I mean is:
Points
Vectors
Matrices
Matrix multiplaction - Rotations, Skews, etc..
Heres my goal: Create a simple box, and apply a rotation, translation, and skew to it via matrix multiplication. Afterwards, start messing around with the camera. I wish to do this all myself, only using the functions that actually take in the data and draw it. I wish to create all the logical stuff inbetween.
Heres what i've got so far:
My custom Vector3 class, which holds
-an X, Y, and Z variable (floats)
-Several static matrices (as 2x2 2d float arrays?) that hold ZERO and TRANSLATION matrices (for 2x2 and 3x3)
-Methods
1. Rotate(float inAngle) - Creates a rotation matrix and multiplies the xyz by it.
2. Translate(inx,iny,inz) - Adds the ins to the member variables
3. etc...
When complete, i translate the vector back into a C# Vector3 class and pass it to a drawing class, such as DrawPrimitiveShapes which would draw Lines.
The box class is like this:
4 Vector3's, UpperLeftX, UpperRightX, LowerLeftX, LowerRightX
a Draw class which uses the 4 points to then render lines to each one
My confusion comes at this:
How do I rotate this box? Am I on the right track by using 4 vector3's for the box?
Do I just rotate all four vector3's by the angle and be done with it? How does a texture get rotated if it's got all this texture data in the middle?
The way I learned is by using the upper level built in Xna methods and using 'Reflector' to see inside those methods to see how they work.
To rotate the box, each of the four vertices needs to be transformed from where they were to: a number of degrees about a particular axis.
In Xna 2d the axis is always the Z axis and that axis always runs through the worlds origin, the top left corner of the screen in xna.
So to rotate your four rectangle vertices in xna, you would do something like this:
foreach(Vector2 vert in vertices)
{
vert = Vector2.Transform(vert, Matrix.CreateRotationZ(someRadians));
}
This gets the vertices to rotate (orbit) the top left corner of the screen.
In order to have the box rotate in place, you would first move the box to the top left corner of the screen , rotate it a bit, then move it back. All this happens in a single frame so all the user sees is the rectangle rotating in place. There are many ways to do that in code but here is my favorite:
// assumes you know the center of the rectangle's x & y as a Vector2 'center'
foreach(Vector2 vert in vertices)
{
vert = Vector2.Transform(vert - center, Matrix.CreateRotationZ(someRadians)) + center;
}
Now if you were to reflect the "Matrix.CreateRotationZ" method, or the "Vector2.Transform" method, you would see the lines of code MS used to make that work. By working through them, you can learn the math behind more efficiently without so much trial and error.
Is there any way to generate a Curve class and then draw that curve in 2D on the screen in XNA?
I want to basically randomly generate some terrain using the Curve and then draw it. Hoping that I can then use that curve to detect collision with the ground.
It sounds like what you want is the 2D equivalent of a height-map. I'd avoid making a true "curve" and simply approximate one with line segments.
So basically you'll have an array or list of numbers that represent the height of your terrain at a series evenly spaced (horizontally) points. When you need a height between two points, you simply linearly interpolate between the two.
To generate it - you could set a few points randomly, and then do some form of smooth interpolation to set the rest. (It really depends on what kind of curve you want.)
To render it you could then just use a triangle strip. Each point in your height-map will have two vertices associated with it - one at the bottom of the screen, the other at the height of that point in the height-map.
To do collision detection - the easiest way is to have your objects be a single point (it sounds like you're making a artillery game like Scorched Earth) - simply take the X position of your object, get the Y position of your terrain at that X position, if the Y position of your object is below the terrain, set it so that it is on the terrain's surface.
That's the rough guide, anyway :)