Place object next to another in Unity and handle rotation - c#

I am trying to handle the position of a cube when I move it close to another one. When I drag a cube next to another, I want it to have the same rotation and be perfectly next to it. Here is an example of what I am trying to do :
When I drag the second square close to the one on the top, it must end up like this :
I implemented a function to clip the selected cube to another :
public override void clip(Cube other){
//print("North:" + allSides[north] +" East:" + allSides[east] +" South:" + allSides[south] +" West:" + allSides[west]);
float distX = this.transform.position.x - other.transform.position.x;
float distZ = this.transform.position.z - other.transform.position.z;
bool isClips = false;
if(Math.Abs(distX)<2.2 && Math.Abs (distZ)< 0.5){
transform.rotation = other.transform.rotation;
if(distX<0){
move(east,other.transform.position.x-SQUARE_BASE_LENGTH,other.transform.position.z,other);
}
if(distX>0){
move(west,other.transform.position.x+SQUARE_BASE_LENGTH,other.transform.position.z,other);
}
isClips = true;
}
if(Math.Abs(distZ)<2.2 && Math.Abs (distX)< 0.5){
transform.rotation = other.transform.rotation;
if(distZ<0){
move(north,other.transform.position.x,other.transform.position.z-SQUARE_BASE_LENGTH,other);
}
if(distZ>0){
move(south,other.transform.position.x,other.transform.position.z+SQUARE_BASE_LENGTH,other);
}
isClips = true;
}
}
But I have a result like this :
or
depending on which side is the closest. How can I make so that my 2 cubes attach each other as expected?

Some points for further calculation:
The diagonal distance between the two objects has to be your edge length afterwards.
Easiest would probably be to calculate the directional vector from the other into the direction you want to attach to, resize it to fit your edge length and add it to the position of the other object to get the position of the object you want attach.
You could also do some stuff with angles (sin/cos/tan) and pythagoras where the hypothenus would be your edge length, but I think this requires more calculation.

Related

Unity calculate how much object moved on a given axis

I am working on a VR project in Unity (2020.3.40f), and need to add the option to move an object on its axis based on the controller's (the user's hand) movement.
Currently I store the controller's position when it grabs the object, and continuously calculate the distance the controller has moved from the initial position.
But it is inaccurate, because the controller might have moved in a direction that shouldn't affect the object's position.
For example:
I have this blue lever that the user has to pull. I want to know how much the controller has moved along the green axis, so I can move the lever accordingly.
If the user moves their hand upwards, it shouldn't affect the lever (but in my current implementation, I use Vector3.Distance so the lever moves anyway).
My code:
private void OnTriggerEnter(Collider other)
{
controller = other.GetComponentInParent<IController>();
if (controller == null || controller.IsOccupied)
{
return;
}
controller.IsOccupied = true;
controllerStartPosition = controller.GetPosition();
}
private void Update()
{
if (controller == null) return;
Vector3 currentControllerPosition = controller.GetPosition();
float distance = Vector3.Distance(currentControllerPosition, controllerStartPosition);
transform.Translate(0, 0, distance * sensitivity); // The object always moves along its forward axis.
}
I assume that I need to project the controller's position on the object's forward axis and calculate the distance of that, but I have very basic knowledge in vectors maths so I am not sure about that.
So my question is, What are the calculations that I should do to get the correct distance?
As mentioned what you want to do is Vector3.Project your given hand movement onto the desired target axis direction and only move about this delta.
Something like
private void Update()
{
Vetcor3 currentControllerPosition = controller.GetPosition();
// the total vector in world space your hand has moved since start
Vector3 delta = currentControllerPosition - controllerStartPosition;
// the delta projected onto this objects forward vector in world space
// you can of course adjust the vector but from your usage this seems the desired one
Vector3 projectedDelta = Vector3.Project(delta, transform.forward);
// finally moving only about that projected vector in world space
transform.position += projectedDelta * sensitivity;
}
what you are currently doing is;
you are calculating the distance in every axis which the movment on every axis will change the outcome. What you need is when calculating the distance only pass in the parameters in the desired axis for example:
float distance = currentControllerPosition.x - controllerStartPosition.x;
this will give you the diffrence between the x axis of these points.
for example if it was at 5 and it moved to 8 this will return you 3 regardless the movement on the other axis.

Unity: How do I restrict the character's position or velocity to an exact number, making it unable to go past that point?

I'm still working on "perfect" ladder movement, and what I was able to come up with is a way to calculate the exact, specific distance the character needs to move while it is on the ladder to reach the point with which it will collide perfectly with the ground above the ladder.
I know this value is exactly specific because I allow my character to land on the ladder landing when the game starts (position.y = 3.6235), and when I print the movement value in the console I get exactly 3.6235.
I'm not sure that I'm implementing this correctly in code, though, as I've noticed that this value is still barely above "0" in the console once my character is all the way up the ladder. Is Mathf.Clamp() not the correct function to limit movement, or maybe I'm using it incorrectly?
public void ClimbUpLadder(ref Vector3 deltaMovement)
{
float rayLength = raycastOrigins.centerRayLength * 2;
RaycastHit2D[] hits = Physics2D.RaycastAll(new Vector2(raycastOrigins.center.x + deltaMovement.x,
(raycastOrigins.center.y - raycastOrigins.centerRayLength + skinWidth) + deltaMovement.y), Vector2.up,
rayLength, climbMask);
Debug.DrawRay(new Vector2(raycastOrigins.center.x + deltaMovement.x,
(raycastOrigins.center.y - raycastOrigins.centerRayLength + skinWidth) + deltaMovement.y), Vector2.up * rayLength, Color.green);
for (int i = 0; i < hits.Length; i++)
{
if (hits[i])
{
if (hits[i].collider.tag == "Ladder")
{
IsClimbingLadder = true;
}
if (i >= 1 && hits[i].collider.tag == "platformOneWay")
{
//This gives us the exact distance needed to finish climbing
GameObject platform = hits[i].collider.gameObject;
Transform platformTransform = platform.GetComponent<Transform>();
float finalMoveDistance = (platformTransform.position.y - characterTransform.position.y) + platformTransform.position.y;
deltaMovement.y = Mathf.Clamp(deltaMovement.y, 0, finalMoveDistance);
print(finalMoveDistance);
}
}
}
}
Unfortunately, after I set deltaMovement.y to this value it says that finalMoveDistance is around .9 or 1.0, so I still move slightly too far up the ladder. Do you think setting the character's transform.position.y directly is the best way to smooth out the movement? My goal is to eliminate any bounce when transitioning from climbing the ladder to walking on the ground again.
I think you're making a mistake here:
float finalMoveDistance = (platformTransform.position.y - characterTransform.position.y) + platformTransform.position.y;
Why do you add the platformTransform twice?
Try this:
float finalMoveDistance = (platformTransform.position.y - characterTransform.position.y);

Projectiles passing through other entities

I wrote a collision detection system for a game I am working on, and I am experiencing a weird glitch where, occasionally, projectiles will go through the player or walls scattered throughout the level. Because the projectiles can be fired at any angle, I decomposed the bounding box of each projectile into multiple, smaller bounding boxes that I then rotate around the center of the texture according to the rotation of the projectile in space. For some reason, occasionally a Spear projectile will go through the player or a wall even through others do not.
I use the following methods to determine the rotation of the texture and to translate the bounding boxes:
public double RotateToFaceTarget()
{
double rotation = Math.Atan2((double)_direction.Y, (double)_direction.X);
return rotation;
}
public List<BoundingBox> TranslateBoundingBox(List<BoundingBox> box, double rotation)
{
List<BoundingBox> newBounds = new List<BoundingBox>();
foreach (BoundingBox b in box)
{
Vector2 boundsOrigin = new Vector2(b.Pos.X + b.Size.X / 2, b.Pos.Y + b.Size.Y / 2);
Vector2 texOrigin = new Vector2(_pos.X + _texture.Width / 2, _pos.Y + _texture.Height / 2);
Vector2 newPosBasedOnOrigin = Vector2.Transform(boundsOrigin - texOrigin, Matrix.CreateRotationZ((float)rotation)) + boundsOrigin;
newBounds.Add(new BoundingBox(newPosBasedOnOrigin, b.Size));
}
return newBounds;
}
_direction is calculated by subtracting the position of the projectile from the target location and normalizing. I use this method to determine if the projectile is colliding with another entity:
public bool ProjectileCollision(Entity e, Projectile entity2)
{
if (entity2.CanCollide)
{
foreach(GameObject.BoundingBox b in entity2.BoundingBox)
{
foreach(GameObject.BoundingBox b2 in e.BoundingBox)
{
if (b2.Intersect(b) && (entity2.IgnoredEntities.Contains(e.Type) == false))
{
entity2.IsActive = false;
e.Health -= entity2.Damage;
return true;
}
return false;
}
}
return false;
}
return false;
}
And this is my Bounding Box Intersection method:
public bool Intersect(BoundingBox intersected)
{
if ((_pos.Y < intersected.Pos.Y + intersected.Size.Y) && (_pos.Y + _size.Y > intersected.Pos.Y) && (_pos.X + _size.X > intersected.Pos.X) && (_pos.X < intersected.Pos.X + intersected.Size.X))
{ return true; }
return false;
}
EDIT: On further testing, it seems that the projectile will always detect a hit if the player hits based on the top left corner ( which makes sense now that I look at my intersect code). Is there another way to re-write my Intersect method to use something more accurate than the top left corner?
EDIT2: I drew the hitboxes for certain objects, and this is one instance of when I catch the spear going through the player:
http://imgur.com/a/fAxZw
the player is the larger pink square. The hitboxes are not being translated correctly, but it shouldn't just stop working, for some and not others, right?
It could happen, because of high velocity and small object, projectile could fly through object. Beside of checking if objects are intersecting, you have to check if object will intersect, to check if object is in line of fire. You could achieve this by raycasting.
On those cases like your i had function that check if object is near other. Simple checking if object is inside of some radius of other object. If yes then i was checking if object is flying toward other object, and checking distance between them. When distance is really close then collision happened.

Jump animation using animation class

I need a little help in my little 2D game I want to create in XNA. I had almost no knowledge of programming before I got interested in XNA and C#, so maybe my problem is simple, but I just can't figure it out.
So basically, I have a base class, and I created an additional class Animation for animating sprites. I implemented some methods so that when the player presses "right" it would change the animation's current texture and increment X by a number of xf; anyway, the main idea is that I'm using just one instance of my class (basically, one object of type animation which changes its texture and properties based on what key is pressed).
So, I had no problems making it run right or left. Works out pretty well. The big problem started when I wanted to implement the jump sprite. So I created the 6 frames necessary for the sprite, but to animate it I have virtually no idea how to do it.
The only thing it does right now is to loop through the frames of the sprite, but the position (both .X and .Y) remain the same. The thing is, I have a Vector2 position which holds the animation's current position, and it's fine with running because I simply increment it. However, when it comes to jumping, I want it to increment .X, but the .Y should be decremented (thus going up) until frame number 3; after frame number 3, until the last frame, I want the .Y position to go down (thus fall) with the corresponding animations (erm, frames).
So, basically, I don't know how to modify the .X and .Y so that it would display the frames that I need in the time I need. I don't know if you really understood what I'm trying to say; basically when I press the "up" key, it loops through the frames but the position remains the same.
My idea was to use a reference to the actual Vector2 position which holds the animation's current position and pass it to the method in the other Animation.cs class, namely the PlayAnimJump, and modify the position after each frame and return it to the actual Game1.cs by reference. Even if I would do that (though I fail to see what good it would be), it wouldn't be updating the position as it should. So, any ideas?
Here is the code for the PlayAnimJump method from the Animation class:
public void PlayAnimJump(GameTime gameTime)
{
elapsed += (float)gameTime.ElapsedGameTime.Seconds;
sourceRect = new Rectangle(currentFrame * frameWidth, 0, frameWidth, frameHeight);
currentFrame = 0;
if (elapsed >= frameTime)
{
if (currentFrame <=3)
{
if (looping)
{
currentFrame++;
}
}
else if (currentFrame > 3)
{
currentFrame++;
}
elapsed = 0;
}
}
The default constructor for that class:
public Animation(ContentManager Content,string asset,float frameSpeed, int numbOfFrames, bool looping,Vector2 positionIT)
{
this.assetName = asset;
this.frameTime = frameSpeed;
this.numbOfFrames = numbOfFrames;
this.looping = looping;
this.animation = Content.Load<Texture2D>(asset);
frameWidth=(animation.Width / numbOfFrames);
frameHeight=animation.Height;
position = positionIT;
}
Here is the code (from the main) when the up key is pressed:
else if (up)
{
check = animation1.GetAsset();
if (check == "eright")
{
animation1.SetFrameSpeed(0.8f);
animation1.SetNumbOfFrames(6);
animation1.ChangeTexture(Content, "SarimCumVreJiorjica");
animation1.PlayAnimJump(gameTime);
/*position1.x +=2f;
position1.Y -=2f;
*/
}
So, I'm not sure how, but I'm supposed to change position1 according to the frame that's displayed by the animation in that second. Am I missing something?
If your animation class had a reference to the object that you wanted to move (i.e the object holding the position field) then you could modify it within the animation class, within the PlayAnimJump method.
Or, to reduce coupling, you could just have PlayAnimJump return a variable indicating how far into the jump you are (maybe a percentage of the jump, from 0 to 1). Then, you could use the percentage outside to set the objects position. So, if the jump is halfway done, the return value would be 0.5f, which you could use in an equation to determine the players y position. An example equation would be:
float percent = animation1.PlayAnimJump(gameTime);
float y = Math.Sin(percent * Math.PI) * maxJumpHeight;
player.positon.y = y;
This uses a sine wave to determine the players height throughout the jump animation. You would just need to write the code that determines the percentage of the way through the jump (currentFrame) in the PlayAnimJump method and return it.
Formula of the frŅƒefall for Y coordinate is
y = g * t ^ 2 / 2 + v0 * t + y0
Characters jump from height y0 vith start velocity v0 by Y axis and gravity gradually slows down and starts to fall.
Calculate deltaY using following formula
deltaY = g * t ^ 2 / 2 + v0 * t
First show the frame on which the character is pushed off the ground, then the frame on which it rises until it reaches the peak of the jump. Once the sign change deltaY from + to - show how the character change pose for fall. Something like that.

How to work out what direction an object is moving

SO I currently have an object which moves in the Y axis (up and down). How would I be able to program it so the program knows whether the object is moving up or down?
I understand I'd need an if statement like the following:
if (object is moving up)
{
//set direction to 1
}
else
{
//object must be going down, set direction to 2
}
I just don't understand what syntax I'd need to use. This would be easy if I was holding down the key and it was moving up or down however that's not the case. The object is a bouncing ball and therefore when you set a power the ball jumps, and bounces so it is constantly changing.
Thanks for your help, let me know if this wasn't described well and you need more info.
You need to save the current coordinates so that you can check them after the update method is called. Then you can check the differences between the previous and current location:
Declare it in Game1() constructor:
Point previous = new Point();
previous.X = myObject.InitialX;
previous.Y = myObject.InitialY;
In Update:
int deltaX = object.X - previous.X;
int deltaY = object.Y - previous.Y;
if (deltaX < 0)
{
object is moving upwards
}
else
{
object is moving downwards
}
if (deltaY < 0)
{
object is moving to the left
}
else
{
object is moving to the right
}
//update the previous state
previous.X = myObject.X;
previous.Y = myObject.Y;
When you update the position of the ball you have one position and you calculate the position for the next frame -> You can calculate the distance vector.
With the sign of the y-value of this distance vector you can decide if it's moving upwards, downwards or isn't moving (=0).

Categories