Good afternoon everyone, I have a super simple OnDrag method, it works great, even if the sprite and "remains" of the cursor, after a moment it catches up with it
public void OnDrag(PointerEventData eventData)
{
arc = rectTransform.anchoredPosition + eventData.delta / canvas.scaleFactor;
rectTransform.anchoredPosition = arc;
enter image description here
However, when I try to add a border to a UI element using Clamp, the cursor stops "catching up" with the UI element, and the further it goes, the more it stays. Could you please suggest me a solution to fix this. Thank you in advance.
arc = rectTransform.anchoredPosition + eventData.delta / canvas.scaleFactor;
arc.x = Mathf.Clamp(arc.x, -500f, 500f);
arc.y = Mathf.Clamp(arc.y, -500f, 500f);
rectTransform.anchoredPosition = arc;
enter image description here
Turn Off Vsync helps a little bit.I understand that the whole thing is in calculations that do not keep up with the update of frames or something like that.
Related
So, Hey guys. Im new to Unity and Im trying a very simple code that allows the player to Zoom-in & Zoom-Out. Here's the code of it:
[Header("Vertical Zooming")]
[SerializeField] private float zoomSpeed;
private void Update()
{
VerticalZooming();
}
private void VerticalZooming()
{
Vector3 initialPosition = new Vector3();
// bool canMove = false;
if (Input.GetMouseButtonDown(0))
{
initialPosition = mCamRef.ScreenToViewportPoint(Input.mousePosition);
Debug.Log(initialPosition.y);
}
if (Input.GetMouseButton(0))
{
Vector3 newPosition = mCamRef.ScreenToViewportPoint(Input.mousePosition);
Debug.Log("newPosition" + newPosition.y);
if (newPosition.y < initialPosition.y)
{
Zoom((zoomSpeed * Time.deltaTime) * -1f);
}
if (newPosition.y > initialPosition.y)
{
Zoom(zoomSpeed * Time.deltaTime);
}
intialPosition = newPosition;
}
}
private void Zoom(float inZoomSpeed)
{
transform.Translate(mCamRef.transform.position.z * inZoomSpeed * transform.forward);
}
So, if you see the code above. On mousebuttondown we note down the initial position and on holding the mouse button we keep track of new position constantly.. What i want is pretty simple. With reference to my initial mouse click im checking if my new position is greater in y is yes i need to zoom out. If new position is lower than initial position in y-axis. Them, i need to zoom in. Which I did, But for some reason its not working.
Two problems here:
Though if there is no change to newposition i.e., even if both my newposition variable and initial position variable are in same spot my camera moves(Zoom-out in my case) which shouldn't happen. It should only happen if my newPosition.y variable is greater that that of initialposition.y. I'm not able to figure out why this is happening. I tried using bool conditions to do this, but failed.
If i play test this in my mobile.. Its only going on one direction. in my case its only zooming out continously though my zoom-in if-condition meets. But when playtesting in unity game window. The zoom in works when my mouse is out of the game-screen. Because its only working outside the game screen.This is the reason its not working in mobile as there is no space outside mobile display. Which i dont know why this is happening or dont know how to overcome this.
Let me know why! Im stuck at it for a long time and not getting any idea. Thanks <3
If Any doubt in question let me know. Sorry for a huge explanation. Just wanted to be very precise on the question.
I have seen people suggesting zoom in zoom out through using FOV. But i wanna do it using translate or move the camera itself.
So your problem here is on taking count on the screenToViewPort point.
Instead just try this..
if (Input.GetMouseButtonDown(0))
{
mInitialPosition = Input.mousePosition.y;
}
if (Input.GetMouseButton(0))
{
mChangedPosition = Input.mousePosition.y;
if (mChangedPosition == mInitialPosition)
{
return;
}
if (mChangedPosition < mInitialPosition)
{
Zoom((mZoomSpeed * -1f) * Time.deltaTime);
}
if (mChangedPosition > mInitialPosition)
{
Zoom(mZoomSpeed * Time.deltaTime);
}
}
private void Zoom(float inZoomSpeed)
{
transform.Translate(mCamRef.transform.position.z * inZoomSpeed * transform.forward);
}
Not sure how ScreenToViewport point works... But I guess this code should do the magic for you... Here I'm just straight away taking the mouse.y value on click and hold and did the same functions as you did and also telling it not to do anything when both the y values are same and return the function... So meaning that you already had everything in your code itself... Have a nice day
I'm really new to using unity and C# so excuse me if this is a dumb question but I really haven't been able to figure it out..
I just want to flip my sprite in my 2D game but when I do that using localScale the location of the sprite changes too.
It's like this:
flipped right:
| [sprite facing right]
flipped left:
[sprite facing left] |
the "|" sign stays in one location in the game. Wow this is so hard to describe without pictures but I hope you can understand me. I can't post images because I'm new to the forum.
So the issue is:
When I change the localScale the whole sprite moves and I don't understand why.
Could someone please help me? Thanks in advance!
My code:
private void HandleInput()
{
if (Input.GetKey(KeyCode.D))
{
_normalizedHorizontalSpeed = 1;
if (!_isFacingRight)
Flip();
}
else if (Input.GetKey(KeyCode.A))
{
_normalizedHorizontalSpeed = -1;
if (_isFacingRight)
Flip();
}
else
{
_normalizedHorizontalSpeed = 0;
}
if(_controller.CanJump && Input.GetKeyDown(KeyCode.Space))
{
_controller.Jump();
}
}
private void Flip()
{
transform.localScale = new Vector3(-transform.localScale.x, transform.localScale.y, transform.localScale.z);
_isFacingRight = transform.localScale.x > 0;
}
}
Make sure the origin of your sprite is configured correctly. In most cases, the origin of the sprite should be in the very middle, which would make a negative transform flip it around the center. If however the origin is in a corner, that position stays the same at any scale, meaning it'll be in the same place and your sprite will appear to move when flipping. This can also happen if your sprite only occupies a portion of the image used for the sprite - it's not actually moving, but since you can't see the rest of the image, it appears to be.
I'm making an infinite runner in unity, I have an tile spawner/generator and its generating GameObjects based on screen height and width, I managed to make it work with the width but when changing the height the camera doesn't follow and I can't manage to make that work.
Anyway, my code isn't good, I have spent the last 6 hours into that and I don't appreciate the result.
As I found out you can define an aspect ratio to the camera and it will auto-scale your ratio to that one, but it distorts the image and doesn't look great.
Since all those notes, which is the best way to auto-scale a 2D platform game (NOT CONSIDERING GUI, only GameObjects)
I' m using this script to stretch sprites based on their size, works for most cases. I use 5 for the orthographicSize of camera.
using UnityEngine;
using System.Collections;
#if UNITY_EDITOR
[ExecuteInEditMode]
#endif
public class SpriteStretch : MonoBehaviour {
public enum Stretch{Horizontal, Vertical, Both};
public Stretch stretchDirection = Stretch.Horizontal;
public Vector2 offset = new Vector2(0f,0f);
SpriteRenderer sprite;
Transform _thisTransform;
void Start ()
{
_thisTransform = transform;
sprite = GetComponent<SpriteRenderer>();
StartCoroutine("stretch");
}
#if UNITY_EDITOR
void Update()
{
scale();
}
#endif
IEnumerator stretch()
{
yield return new WaitForEndOfFrame();
scale();
}
void scale()
{
float worldScreenHeight = Camera.main.orthographicSize *2f;
float worldScreenWidth = worldScreenHeight / Screen.height * Screen.width;
float ratioScale = worldScreenWidth / sprite.sprite.bounds.size.x;
ratioScale += offset.x;
float h = worldScreenHeight / sprite.sprite.bounds.size.y;
h += offset.y;
switch(stretchDirection)
{
case Stretch.Horizontal:
_thisTransform.localScale = new Vector3(ratioScale,_thisTransform.localScale.y,_thisTransform.localScale.z);
break;
case Stretch.Vertical:
_thisTransform.localScale = new Vector3(_thisTransform.localScale.x, h,_thisTransform.localScale.z);
break;
case Stretch.Both:
_thisTransform.localScale = new Vector3(ratioScale, h,_thisTransform.localScale.z);
break;
default:break;
}
}
}
First i want to say there are no good solutions only less bad.
The easiest is to just support one aspect ratio that way you can just scale everything up and down without distortion but that almost never an option.
The second easiest is to make the game be in one aspect ratio and add black bars (or something) to the edges to made the actual game area the same aspect ratio.
If you still want different aspect ratios the solution is to increase the game area but that might cause people with different aspect ratios to get an advantage since they can see further ahead or higher and it might mess up your level design.
I just posted an answer to how make everything work automatically as long as you have constant aspect ration here https://stackoverflow.com/a/25160299/2885785
I have a 2D game in XNA which has a scrolling camera. Unfortunately, when screen is moved, I can see some artifacts - mostly blur and additional lines on the screen.
I thought about changing coordinates before drawing (approximating with Ceiling() or Floor() consistently), but this seems a little inefficient. Is this the only way?
I use SpriteBatch for rendering.
This is my drawing method from Camera:
Vector2D works on doubles, Vector2 works on floats (used by XNA), Srpite is just a class with data for spriteBatch.Draw.
public void DrawSprite(Sprite toDraw)
{
Vector2D drawingPostion;
Vector2 drawingPos;
drawingPostion = toDraw.Position - transform.Position;
drawingPos.X = (float) drawingPostion.X*UnitToPixels;
drawingPos.Y = (float) drawingPostion.Y*UnitToPixels;
spriteBatch.Draw(toDraw.Texture, drawingPos, toDraw.Source, toDraw.Color,
toDraw.Rotation, toDraw.Origin, toDraw.Scale, toDraw.Effects, toDraw.LayerDepth + zsortingValue);
}
My idea is to do this:
drawingPos.X = (float) Math.Floor(drawingPostion.X*UnitToPixels);
drawingPos.Y = (float) Math.Floor(drawingPostion.Y*UnitToPixels);
And it solves the problem. I think I can accept it this way. But are there any other options?
GraphicsDevice.SamplerStates[0] = SamplerState.PointWrap;
This isn't so much a problem with your camera as it is the sampler. Using a Point Sampler state tells the video card to take a single point color sample directly from the texture depending on the position. Other default modes like LinearWrap and LinearClamp will interpolate between texels (pixels on your source texture) and give it a very mushy, blurred look. If you're going for pixel-graphics, you need Point sampling.
With linear interpolation, if you have red and white next to each other in your texture, and it samples between the two (by some aspect of the camera), you will get pink. With point sampling, you get either red or white. Nothing in between.
Yes it is possible... try something this...
bool redrawSprite = false;
Sprite toDraw;
void MainRenderer()
{
if (redrawSprite)
{
DrawSprite(toDraw);
redrawSprite = false;
}
}
void ManualRefresh()
{
"Create or set your sprite and set it to 'toDraw'"
redrawSprite = true;
}
This way you will let main loop do the work like is intended.
I have this problem, that I want to be able to click on a "tile" on the screen and then a pop-up menu should be shown just next to the tile. I can click on the tile and then a pop-up menu shows up but not where I want it.
On the picture here I've clicked on the top left one.
My code for placing the picture is as following:
using UnityEngine;
using System.Collections;
public class TowerMenu : MonoBehaviour
{
bool showMenu = false;
float x;
float y;
GUIStyle myStyle;
public Texture2D[] towers;
void OnGUI()
{
if(showMenu)
{
//Bear tower
GUI.Button(new Rect(x + 10, y - 25, 50, 50), towers[0]);
//Seal tower
GUI.Button(new Rect(x + 10, y + 25, 50, 50), towers[1]);
}
}
public void ShowMenu(Vector2 pos)
{
showMenu = true;
x = pos.x;
y = pos.y;
}
}
Hope anyone can help me :)
Sry, i cant comment because i dont have enough rep, this is a comment to Steven Mills answer and comments to that post.
The first error comes because you are calling WorldToViewportPoint as if it was a static member function which it isnt(Think of if you had 2 Cameras you would have to specify which Camera you want, reading up on what a static member is would be helpful here). What you need to do to fix this is get a reference of your MainCamera and call the function from that instance(best method would probably be with a public variable and dragging the camera on the script in the editor)
The second error occurs because you are trying to give a Vector3 to ShowMenu() which requires a Vector2. The third is probably a product of the compiler trying to fix error 2
This is a logical error because the tiles are GameObjects and thus the transform.position are positions in 3d space. What you actually want is the 2d-pixel-position on the screen of your MainCamera. To get this you need to call WorldToScreenPoint instead of WorldToViewportPoint. Sadly, as you will notice you will also get a Vector3 here which is not what you want, but you can just take the x and y coordinates as your pixel screen coordinates. the z-coordinate denotes the distance from the camera.
Hope that clears it up a little instead of confusing you ;D
Feel free to ask again, but also try to read the Unity Script Reference and try to understand what is written there and what it means :)
By the look of it, your ShowMenu method is receiving a pos of (0,0), which is why the two buttons are placed at what seems to be a position of (10,-25) and (10,25) respectively.
Without seeing the code calling ShowMenu I can't be sure what location you're giving, but my guess would be that the tiles belong to a parent object, and you're passing the local position instead of the world position.
If you post the code in which you call ShowMenu I may be able to point out any problems.
EDIT:
Based on the information provided in the comments, the problem is that the position needs converting between the world coordinates and screen coordinates:
void OnMouseDown()
{
if(state == State.water)
{
errorHandler.sendError("You can't click on that");
}
if(state == State.ice)
{
towerMenu.ShowMenu(camera.WorldToViewportPoint(this.transform.position));
}
}
and change the ShowMenu to this:
public void ShowMenu(Vector3 pos)
{
showMenu = true;
x = pos.x;
y = pos.y;
}