How can I move smooth slowly a Canvas Child? - c#

I have this structure in the hierarchy:
The object Save Slots is a Canvas :
I can't move the Canvas and I don't want to change the Canvas Render Mode so I'm trying to move the Canvas Child:
The Child is a Scroll View ui and on the Scroll View I attached a script name Move Scroll View.
This is the script :
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class MoveScrollView : MonoBehaviour
{
float seconds;
Vector3 begin;
Vector3 end;
Vector3 difference;
void Start()
{
seconds = 50;
begin = transform.localPosition;
end = new Vector3(0, -1, 0);
difference = end - begin;
}
void Update()
{
transform.localPosition += difference * Time.deltaTime * seconds;
}
}
I want to move the Scroll View to the right from its current position to position 0, -1, 0
Its current position when starting the game is: -540, -1, 0
What it does is move the Scroll View, but very fast and nonstop on the X and Y instead of only on the X and is not affected by the time; no matter if the seconds are 5 or 50, it will move too fast and nonstop.

Suggestion:
If you only want to affect one direction, then only affect changes on that axis.
transform.localPosition.x might be the ticket.
I'm really weak when it comes to determining how to slow things down, but I see a lot of gameObject examples where they implement a speed float that is always somewhere between 0f and 1f. Consider, instead of going by "number of seconds", you try a "move at this speed until the goal is reached"
Also, it may help to re-calculate difference during the Update method. Your position is different every frame, so the distance you need to travel is different every frame.
void Update
{
//Possibly needs rethought
if(transform.localPositon.x < end.x)
{
//Basic move me at a certain speed
transform.localPosition.x += speed * Time.deltaTime;
//You may also be able to use the difference variable to control the speed
// speed * difference.x * Time.deltaTime;
// Update Difference
difference = end - transform.localPosition;
}
}
You could even get fancy with this and try to implement a coroutine.
May not be perfect, but I hope this helps. Let me know if gets you closer to what your trying achieve.

Related

How to design a smooth UI scroll inside Update() for a Unity VR application?

I am developing a VR application in Unity and I am struggling to develop a smooth UI scroll using my VR controller's joystick. So far what I have looks like this...
private void Update()
{
float joyStickDirection = globals.menuInteraction_Scroll.GetAxis(SteamVR_Input_Sources.Any).y; // this is either 1 for up or -1 for down
if (joyStickDirection != 0)
{
float multiplier = joyStickDirection * 5f;
scrollRect.verticalNormalizedPosition = scrollRect.verticalNormalizedPosition + (multiplier * Time.deltaTime);
}
}
...this works, but has two problems. Firstly, it scrolls at different speeds depending how big the scrolling container is. Secondly, the scrolling is not very smooth, as it is clearly just skipping varying gaps between 0 and 1.
I think I know what's wrong but I don't have enough experience working inside Update() to figure out the correct approach. Can anyone advise?
Actually you don't necessarily go through the ScrollRect component itself.
I usually would simply do
public class ScrollExample : MonoBehaviour
{
public float speed = 5f;
public Transform ScrollContent;
void Update()
{
// this is either 1 for up or -1 for down
var joyStickDirection = globals.menuInteraction_Scroll.GetAxis(SteamVR_Input_Sources.Any).y;
if (joyStickDirection != 0)
{
var multiplier = joyStickDirection * speed;
// You want to invert the direction since scrolling down actually means
// moving the content up
ScrollContent.position -= Vector3.up * multiplier * Time.deltaTime;
}
}
}
The ScrollRect then updates and handles the rest itself. The speed is in Units/seconds or in a Screenspace Overlay canvas in pixels per seconds regardless of how big the content is.
Usually you would want to adjust the elasticity of the ScrollRect or simply set the Movement Type to Clamped right away.

Calculating changing Mathf.Clamp() values for object of changing size

I've been wracking my brain over this problem for a while. I have a controllable object (only moveable up and down) that I have clamped on the top and bottom. However, every time a certain trigger is activated, the object shrinks 10% until it is 90% of the original size. The problem comes in when I shrink it. When it shrinks, the min and max values of the clamp don't change at all and this results in the object clamping to soon on the min and max. They need to decrease and increase respectively so that it clamps in the exact same place. How would one do this? I've tried so many different methods but to no avail...
This is the way I shrink my player:
playerWidth /= 1.1f;
playerHeight /= 1.1f;
Vector3 scale = new Vector3(playerWidth, playerHeight, 1f);
playerOneShrink.transform.localScale = scale;
Many Thanks!
EDIT 1:
Let me give an example using a game that might help get my point across better. Basically think flappy bird, but the player uses the up and down arrows to move and not space-bar. When the bird dies, the bird would reset but become smaller. It seems that because the bird is smaller it now moves 'less' up and down, and doesn't touch the top and bottom of the screen anymore. I want the bird to still be touching the top and bottom of the screen.
EDIT 2:
So apparently my first edit didn't clarify as much as I thought so I'm going to show my code for a test scene I'm trying this all in. I haven't shown the changing of minValue and maxValue because that's what I'm struggling with...
private static Rigidbody2D playerOneRB;
GameObject player1;
float verticalMovement = 0;
public static float playerHeight = 0.3417f;
public static float playerWidth = 0.05400001f;
public float minValue = 0;
public float maxValue = 10;
public static float p1VerticalSpeed = 3;
public GameObject playerOneShrink;
// Start is called before the first frame update
void Start()
{
playerOneRB = GameObject.FindGameObjectWithTag("P1 Normal").GetComponent<Rigidbody2D>();
player1= GameObject.Find("P1 Normal");
}
// Update is called once per frame
void Update()
{
verticalMovement = Input.GetAxis("Player 1 V"); //Looking for axis defined in our input manager
playerOneRB.velocity = new Vector3(0f, verticalMovement * p1VerticalSpeed, playerOneRB.velocity.x);
Vector3 scale1 = new Vector3(playerWidth, playerHeight, 1f);
Vector3 position = transform.position;
player1.transform.position = new Vector3(player1.transform.position.x, (Mathf.Clamp(player1.transform.position.y, minValue, maxValue)), 0f); //Restricting how far the players can move (aka, not off the screen)
if (Input.GetKeyDown(KeyCode.Alpha1))
{
playerWidth /= 1.1f;
playerHeight /= 1.1f;
scale1 = new Vector3(playerWidth, playerHeight, 1f);
paddleOneShrink.transform.localScale = scale1;
}
}
Here's a photo of what's happening:
1. Photo of position it reaches before shrinking
2. Photo of position it reaches after shrinking
I want the player in image 2 to be able to get to the same top position as in image 1 after it shrinks.
It sounds like you want to scale the object, but keep it pivoted, so if it's at the top most position, and scales, it stays at the top most position? If so, the code and answers here will help:
https://answers.unity.com/questions/14170/scaling-an-object-from-a-different-center.html
You'll of course need to add in some conditional code to check whether it's a top or bottom pivot.
Hope I understood your problem.
So let's assume the scale of the player is 1 unit and you have to clamp in y axis between 0 and 10.
so you will have to clamp the Y position of player like
Vector3 scale = new Vector3(playerWidth, playerHeight, 1f);
Vector3 position = transform.position;
position.y = mathf.clamp(0 + scale.x ,10 - scale.x ,position.y );
transform.position = position;
so if the player's scale is 1 then it will limit the y position between 1 (0+1) and 9 (10-1).
if the player's scale is 0.9 then it will be between 0.9 (0+0.9 ) and 9.1 (10-0.9)
if the scale is 3 then between 3 (0+3) and 7 (10-3)

How to create a 180 degree camera orbit over X seconds in Unity?

I have a camera that orbits a point on the screen. Clicking and dragging your mouse left and right will orbit around the focus point and releasing the mouse will leave the camera at that angle.
I'm trying to create a function that will orbit the camera 180 degrees, smoothly. So for example, if the camera is behind the "player" and this function gets called, the camera will orbit to the front of the player over the course of X seconds and stop in the exact opposite position of where it started.
Here's the code I'm currently using for camera rotation based on mouse click and drag:
Quaternion camTurnAngle =
Quaternion.AngleAxis(Input.GetAxis("Mouse X") * rotationSpeed, Vector3.up);
this.cameraOffset = camTurnAngle * this.cameraOffset;
Vector3 newPos = this.currentFocusPoint + this.cameraOffset;
transform.position = Vector3.Slerp(transform.position, newPos, smoothFactor);
transform.LookAt(this.currentFocusPoint);
I am trying to replace this mouse-drag based camera rotate with a UI button (aka, a single function call) that will fully orbit the camera 180 degrees over a short period of time, and then it will rotate back if pressed again. Here's an MS paint drawing just in case my explanation is confusing:
I'm not sure how do to something like this. It sounds similar to using Vector3.Slerp, but I cannot find a solution that works. I am so far from a solution that I don't really have any sensible code to post. I'll just say that I've tried two methods so far:
1) I've tried using transform.RotateAround, where angle I pass in is rotateSpeed * Time.deltaTime. My issue is I don't know how to check for an end condition, and without one my camera will rotate forever.
2) I've tried messing with Quaternion.Slerp, but the results are seeing are not what I expected.
How can I achieve a smooth 180 degree camera orbit, that takes a predetermined amount of time to complete?
This is a textbook use for a coroutine. Basically, start a coroutine that keeps track of how much time is left in the orbit, then either updates cameraOffset based on the time that's left or Time.deltaTime, whatever is shorter.
private IEnumerator RotateCam(float rotateDuration)
{
float timeLeft = rotateDuration;
// possibly - disable control of camera here
while (timeLeft > 0)
{
yield return null;
float elapsedRotationTime = Mathf.Min(timeLeft, Time.deltaTime);
float angleThisFrame = 180f * elapsedRotationTime / rotateDuration;
Quaternion camTurnAngle = Quaternion.AngleAxis(angleThisFrame, Vector3.up);
this.cameraOffset = camTurnAngle * this.cameraOffset;
transform.position = this.currentFocusPoint + this.cameraOffset;
transform.LookAt(this.currentFocusPoint);
timeLeft -= Time.deltaTime;
}
// possibly - re-enable control of camera here
}
Then, when you want to begin the rotation:
// private Coroutine rotateCoroutine
this.rotateCoroutine = StartCoroutine(RotateCam(2f));

Rotation of a group of objects in Unity is too fast

I'm trying to rotate a group of objects 90 degrees in unity, so I set all of the objects to the same parent, then rotated the parent, it rotated just fine but it's too fast that I can't see, how can I slow it down? I tried both of codes below and both are the same :\ this code appears in a function that is called by update when the user presses on a button
float totalRotation = 0;
while (Mathf.Abs(totalRotation) < 90){
totalRotation += Time.deltaTime;
Parent.transform.RotateAround(temp.transform.position, flag*Vector3.right, Time.deltaTime);
}
and this one
Parent.transform.RotateAround(temp.transform.position, flag*Vector3.right, 90f);
thanks in advance!
Use a factor for the angle, something like
Parent.transform.RotateAround(temp.transform.position, flag*Vector3.right, Time.deltaTime * 0.5f);
Based on the while I would guess that you actually don't do this in Update. Either way this will not work since update is one frame. You don't want a while to do anything time related like this. Make your while an if instead. That way the rotation will probably be too slow so make the factor bigger. Currently your rotation is instant.
Edit:
Something like this would work:
public bool isRotating = false;
public float speed = 20.0f;
public Vector3 targetRotation;
void Update()
{
if(isRotating)
{
if(Vector3.Distance(transform.eulerAngles, targetRotation) > 1.0f)
{
transform.Rotate(Vector3.up * Time.deltaTime * speed);
}
else
{
transform.eulerAngles = targetRotation;
isRotating = false;
}
}
}
This would be around y only.
This part of the answer doesn't work. Please see the update
Actually you did it in the wrong way. Movements in Unity should be done slowly through updates, not just once. Like ChristophKn, I suggest using Coroutine.
const float speed = 180;
IEnumerator Rotate () {
float rotated = 0;
while (rotated < 90) {
float rotation = speed*Time.fixedDeltaTime;
rotated += rotation;
Parent.transform.RotateAround(temp.transform.position, flag*Vector3.right, rotation);
//wait for the next fixed update to continue.
yield return new WaitForFixedUpdate ();
}
}
To start rotating, call StartCoroutine(Rotate);
EDIT
I have another idea to do this, not using script but animation:
First, add a rotating animation to your parent objects, which rotates the angle you want.
To rotate the group of objects, set them to that parent like you did in your question, then start the animation.
At the end of the animation (you can call your methods at that point using animation events), call SetParent(null,true) for all your objects in the group. This will remove the parent but keep the world position.
Finally, set your parent's rotation to the original value.
Hope this will help.

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.

Categories