Can't figure out math formula for changing one value based on another.
enter image description here
I wanna do mechanic where player gets bigger when comes close to bottom border and shrinks when comes close to top. Red is Y coordinates (should not really matter but just to example) and green is desired player scale. So when player at the bottom of the screen he should be 1.25 scale and at the top 0.75.
In course I am doing teacher uses this version (but this one doesn't work for me):
private void AdjustPerspective() {
Vector3 scale = transform.localScale;
scale.x = perspectiveScale * (scaleRatio - transform.position.y);
scale.y = perspectiveScale * (scaleRatio - transform.position.y);
transform.localScale = scale;
}
First line just declare future scale variable.
Second and third changing X and Y of scale (perspectiveScale and scaleRatio float variables which we created ourselves for control and transform.position.y is player's Y position every frame)
Fourth line is assigning new scale.
Can someone please help me with formula for this? Need to update scale value dynamically depending on Y coordinate.
Try this:
float scale = 1 + perspectiveScale * (scaleRatio - transform.position.y);
In your case, with values like:
scaleRatio = 0
perspectiveScale = -0.25 / 4.2
And I recommend you to use intermediary variable, like this:
Vector3 scale = transform.localScale;
float newScale = 1 + perspectiveScale * (scaleRatio - transform.position.y);
scale.x = newScale;
scale.y = newScale;
transform.localScale = scale;
This way, you avoid error if you have to change your formula in the future.
Also, if nothing happens, don't forget to call your method in Update
Related
So, here is what i have:
SteamVR's hand gameobject
3D sphere.
what i want:
The sphere to move to same direction/position as the hand does, but it to move further with a multiplier. E.g. i move the VR controller and the hand moves 1 unit. I want that the sphere moves to the same direction in a same amount of time but e.g. 2 units. how do i do this?
i tried simple
sphere.transform.position = ControllerToFollow.position +2f;
but then the sphere is always offset.
position is a Vector3, which is essentially 3 floats - you can't plus a Vector3 with a float unless you overload the + operator. Otherwise what you can do is the following:
Vector3 followPos = new Vector3(ControllerToFollow.position.x + 2f,
ControllerToFollow.position.y + 2f,
ControllerToFollow.position.z + 2f);
sphere.transform.position = followPos;
If you only want it to follow on one axis, then you can do the following:
Vector3 followPos = new Vector3(ControllerToFollow.position.x + 2f, // Follow on x Axis
ControllerToFollow.position.y, // Y axis is the same
ControllerToFollow.position.z); // X Axis is the same
sphere.transform.position = followPos;
Edit: I think I understand your problem better now. Here's a better version.
if (Vector3.Distance(sphere.transform.position, ControllerToFollow.position) >= 2f)
{
// Code that makes the sphere follow the controlling
}
Just track the movement Delta of the hand and multiply it by a certain multiplier.
At the beginning of the manipulation store
private Vector3 lastControllerPosition;
...
lastControllerPosition = ControllerToFollow.position;
then in every frame compare
var delta = ControllerToFollow.position - lastHandPosition;
// Don't forget to update lastControllerPosition for the next frame
lastControllerPosition = ControllerToFollow.position;
Now in delta you have a movement of the controller since the last frame. So you can assign it to the sphere with a multiplier using Transform.Translate
sphere.transform.Translate(delta * multiplier, Space.World);
or simply using
sphere.transform.position += delta * multiplier;
I have two 3d vectors containing position data for two objects within my game. One of the objects needs to turn its camera directly to the other based on the current positions (the setting of the pitch/yaw are absolute so realistically I can ignore those two variables). What I need help with is the math, honestly I just can't find anything about doing this properly.
//An example in pseudocode
//(x, y, z)
Vector3 mychar = new Vector3(100, 100, 100);
Vector3 explosion = new Vector3(555, 1000, 300);
//(pitch, yaw)
Vector2 myRotation = new Vector2(0, 0); //Can assume this is always the case because the setting of rotation is absolute rather than relative
Vector2 expRotation = new Vector2(35, 14);
//The math I cant seem to figure out would be in this function
Vector2 newRotationj = GetRotationBetween(myRotation, mychar, explosion);
Here's what I have so far but I'm getting problems with the Y rotations (its the "up" direction and the horizon is at 0 degrees) Randomly my character will look in the mirrored direction in y (IE if the object is -20 below horizon it does +20) however it's only sometimes and I dont see where my math is wrong.
float dx = posIt.x - posMe.x;
float dy = posIt.y - posMe.y;
float dz = posIt.z - posMe.z;
yaw = Convert.ToSingle(Math.Atan(dx / dz) * 180 / Math.PI);
pitch = Convert.ToSingle(Math.Atan(dy / dz) * 180 / Math.PI);
I am currently making a game in Unity, where characters are moving towards a point at the bottom of the screen, from a random x-position at the top of the screen. As they have to keep a constant speed (and later on possibly be able to move in specific patterns), I cannot use Vector3.Lerpfor this.
Instead, I tried using some simple math. StaticInfo.instance.GetPlayerPosition() is the targeted position. The code happens in the character's FixedUpdate().
float aVal = (myTransform.localPosition.y - StaticInfo.instance.GetPlayerPosition().y) /
(myTransform.localPosition.x - StaticInfo.instance.GetPlayerPosition().x);
float degrees = Mathf.Atan(aVal) * Mathf.Rad2Deg;
Vector3 newPos = new Vector3(myTransform.localPosition.x - (distance * speed * Mathf.Cos(degrees)),
myTransform.localPosition.y - (distance * speed * Mathf.Sin(degrees)),
1);
myTransform.localPosition = newPos;
My problem is when these characters are created (instantiated from prefab), they make a small 180-degrees loop before moving in the wanted direction. After that, they move exactly as wanted.
Is using math the best solution? And if it is, why does it do a funky drift when initialized?
This may be a more simple solution to what you are trying to achieve:
Vector3 moveDirection = (StaticInfo.instance.GetPlayerPosition() - myTransform.localPosition).normalized;
Vector3 newPos = myTransform.localPosition + moveDirection * distance * speed;
myTransform.localPosition = newPos;
If you want the object to point in the direction of the movement you can do:
myTransform.rotation = Quaternion.Euler(0, 0, Mathf.atan2(moveDirection.y, moveDirection.x)*Mathf.Rad2Deg - 90); // may not need to offset by 90 degrees here;
I have a Vector2-variable where vector.x and vector.y have been clamped so that both are only allowed a value between 0 and 4. Obviously, this leaves me to having a quadratic space around the coordinate 2, 2 to move a gameobject around on.
But what I want to achieve is having a circular space to move a gameobject on, which means that I need it to clamp the value of vector.x+vector.y to be a total value in between 0 and 4, but I can't seem to make it work. Is there another function I should use instead of clamp?
This is what I have at the moment:
Vector2 pos = rigidbody2D.transform.position;
pos.x = Mathf.Clamp (pos.x, 19.5f, 24);
pos.y = Mathf.Clamp (pos.y, 3.3f, 6);
rigidbody2D.transform.position = pos;
Instead of clamping each axis individually, how can I give them a total minimum- and maximum-value?
There is a similar function for Vectors: Vector2.ClampMagnitude and Vector3.ClampMagnitude
You can only specify a maximum length, so you have to take care of the minimum yourself. The problem with the minimum value is, that the function would not know what to do if the vector has a length of 0. In which direction should the vector point to achieve the minimum length?
Limit input to a circle
If you only want to limit the movement to a circle, you don't need a minimum value. Instead define the center as (2,2) and limit the movement to a radius of 2.
Vector2 center = new Vector2(2f, 2f);
Vector2 moveBy = new Vector(4f, 7f); // set this to whatever your input is
moveBy = Vector2.ClampMagnitude(moveBy, 2f);
Vector2 newPosition = center + moveBy;
newPosition will be inside a circle with a radius of 2 around your center at (2,2)
Limit given position to a circle
If you want to clamp a given position to a circle, you can slightly modify the version above. It's like putting the object on a leash and pull it back when it leaves the circle.
Vector2 center = new Vector2(2f, 2f);
Vector2 position = new Vector2(6f, 5f); // outside your desired circle
Vector2 offset = position - center;
Vector2.ClampMagnitude(offset, 2f);
position = center + offset;
Unfortunately There is no in-built function available same as clamp function. but if you don't want to use CLAMP function then you can use IF statements.
if(pos.x > 19.5f )
{
//put logic here
}
if( pos.x < 24f)
{
//put logic here
}
if(pos.y > 3.3f)
{
//put logic here
}
if( pos.y < 6f)
{
//put logic here
}
you can do this. but in my opinion Mathf.Clamp() is the best option for Restricting values in unity,if conditions will not be accurate as Mathf.Clamp() Function.
Not C#, but here's a snippet I use for limiting the touchpad knob to the area of the touchpad in a libgdx project of mine:
Vector2 maxPos = new Vector2(screenX, screenY);
if (maxPos.dst(new Vector2(Settings.touchpadPositionX, Settings.touchpadPositionY)) > painter.getTouchpadSize())
{
maxPos.sub(Settings.touchpadPositionX,Settings.touchpadPositionY);
maxPos.nor();
maxPos.scl(painter.getTouchpadSize());
maxPos.add(Settings.touchpadPositionX,Settings.touchpadPositionY);
}
painter.updateTouchpadPos((int)maxPos.x, (int)maxPos.y);
I am encountering an issue when updating a bullet's position when I rotate the ship that shoots it. Currently the code almost works except that at most angles the bullet is not fired from where i want it to. Sometimes it fires slightly upward than the centre where it should be, and sometimes downwards. I'm pretty sure it has something to do with the trigonometry but I'm having a hard time finding the problem.
This code is in the constructor; it sets the bullet's initial position and rotation based on the ship's position (sp.position) and its rotation (Controls.rotation):
this.backgroundRect = new RotatedRectangle(Rectangle.Empty, Controls.rotation);
//get centre of ship
this.position = new Vector2(sp.getPosition().X + sp.getTexture().Width/2,
(sp.getPosition().Y + sp.getTexture().Height / 2));
//get blast pos
this.position = new Vector2((float)(this.position.X + (sp.getTexture().Width / 2 *
Math.Cos(this.backgroundRect.Rotation))), (float)(this.position.Y +
(sp.getTexture().Width / 2 * Math.Sin(this.backgroundRect.Rotation))));
//get blast pos + texture height / 2
this.position = new Vector2((float)(this.position.X + (this.texture.Height / 2 *
Math.Cos(this.backgroundRect.Rotation))), (float)(this.position.Y +
(this.texture.Height / 2 * Math.Sin(this.backgroundRect.Rotation))));
this.backgroundRect = new RotatedRectangle(new Rectangle((int)this.position.X,
(int)this.position.Y, this.texture.Width, this.texture.Height), Controls.rotation);
speed = defSpeed;
Then in the update method I use the following code; I'm pretty sure this is working fine though:
this.position.X = this.position.X + defSpeed *
(float)Math.Cos(this.getRectangle().Rotation);
this.position.Y = this.position.Y + defSpeed *
(float)Math.Sin(this.getRectangle().Rotation);
this.getRectangle().CollisionRectangle.X = (int)(position.X + defSpeed *
(float)Math.Cos(this.getRectangle().Rotation));
this.getRectangle().CollisionRectangle.Y = (int)(position.Y + defSpeed *
(float)Math.Sin(this.getRectangle().Rotation));
Also I should mention that my ship had not been working correctly when I rotated it since the origin (center of rotation) was (0,0). To remedy this I changed the origin to the center of the ship (width/2,height/2) and also added those values to the drawing rectangle so that the sprite would draw correctly. I imagine this could be the problem and suppose there's a better way of going around this. The game is in 2D by the way.
The problem is that the sprites are not drawn on the positions they are supposed to be. When calculating the center position, you assume that the sprite is not rotated. This causes some trouble. Furthermore, rotating an arbitrary vector is not as easy as you did. You can only rotate a vector by multiplying its components with sin/cos when it is on the x-axis.
Here is how you can rotate arbitrary vectors:
Vector2 vecRotate(Vector2 vec, double phi)
{
double length = vec.Length(); //Save length of vector
vec.Normalize();
double alpha = Math.Acos(vec.X); //Angle of vector against x-axis
if(vec.Y < 0)
alpha = 2 * Math.PI - alpha
alpha += phi;
vec.X = Math.Cos(alpha) * length;
vec.Y = Math.Sin(alpha) * length;
return vec;
}
Make sure, the angle is in radians.
With that you can calculate the correct position of the ship:
Vector2 ShipCenter = sp.Position() + vecRotate(new Vector2(sp.getTexture().Width/2, sp.getTexture().Height/2), Controls.Rotation);
You can use the same function to determine the position of the bullet's center. I don't exactly know, where you want to place the bullet. I will assume, it is at the center of the right edge:
Vector2 offset = new Vector2(sp.getTexture.Width/2, 0);
this.position = ShipCenter + vecRotate(offset, Controls.Rotation);
If you then need the position of the upper left corner of the bullet, you can go further:
this.position -= vecRotate(new Vector2(this.texture.Width/2, this.texture.Height/2), Controls.Rotation)
However, as I stated, it is probably easier to handle the ship's and bullets' positions as central positions. Doing so, you need far less trigonometry.