I have a square sprite (width == height) and I want to scale it so that both width and height are exactly one fifth of the width of screen.
To find the desired pixel width I do:
float desiredWidthPixels = Screen.width * 0.2f;
float desiredHeightPixels = Screen.width * 0.2f;
How do I apply these values to the sprite?
It depends if your camera is Orthographic or not.
You will have to Scale the object up or down, depending on its original size.
float cameraHeight = Camera.main.orthographicSize * 2;
float cameraWidth = cameraHeight * Screen.width / Screen.height; // cameraHeight * aspect ratio
gameObject.transform.localScale = Vector3.one * cameraHeight / 5.0f;
The code goes into a Script file attached to the GameObject (in your case the sprite) since gameObject means the Game Object it is on. If you are doing it from another script file then you will need to find the object first in the tree before scaling it.
Related
I would like to rotate a camera using a joystick.
The camera should rotate up and down and left and right, but it should not rotate around z.
I have tried the following lines:
float speed = 3.0f;
float yRotation = speed * fY;
float xRotation = speed * fX;
camera.transform.Rotate(-yRotation, xRotation, 0.0f);
It seems to work, but after a few joystick movements, I can see that the camera rotation's z-value has changed, and it looks like this:
Does anybody see an obvious mistake in my code, or is the problem located somewhere else?
Ok, here's how to do it, I have to use eulerAngles:
yaw += speedH * fX;
pitch -= speedV * fY;
pitch = Mathf.Clamp(pitch, -20, 30);
camera.transform.eulerAngles = new Vector3(pitch, yaw, 0.0f);
I am having a hard time figuring out how to find correct rect that represents a ui element area. I get the Ui element RectTransform. I tried to use it directly, using a function and RectTransformUtility, but nothing seems to wok.
Here is the code.
RenderTexture.active = scr;
//adjust rect position
//Rect rect = RectUtils.RectTransformToScreenSpace (rectTransform);
int width = System.Convert.ToInt32 (rect.width);
int height = System.Convert.ToInt32 (rect.height);
// Create a texture the size of the screen, RGB24 format
Texture2D tex = new Texture2D(width, height, TextureFormat.RGBA32, false);
RenderTexture.active = scr;
// Read screen contents into the texture
tex.ReadPixels(rect, 0, 0);
tex.Apply();
RenderTexture.active = null;
// Encode texture into PNG
byte[] bytes = tex.EncodeToPNG();
//todo destroy the texture
Object.Destroy (tex);
// For testing purposes, also write to a file in the project folder
File.WriteAllBytes(path, bytes);
I tried to create rect in different ways like:
Methood 1:
Vector2 size = Vector2.Scale(transform.rect.size, transform.lossyScale);
Rect rect = new Rect(transform.position.x, Screen.height - transform.position.y, size.x, size.y);
rect.x -= (transform.pivot.x * size.x);
rect.y -= ((1.0f - transform.pivot.y) * size.y);
return rect;
Method 2:
Vector2 temp = rectT.transform.position;
var startX = temp.x - width/2;
var startY = temp.y - height/2;
var tex = new Texture2D (width, height, TextureFormat.RGB24, false);
tex.ReadPixels (new Rect(startX, startY, width, height), 0, 0);
I am using Unity 5.5 Mac version.
when i pass to ReadPixels new Rect (0, 0, Screen.width, Screen.height) i see the whole RenderTexture in its defined dimensions 1920x1080
I want to use this as a baker of UI elements as I am having performance issue, and definitively no other solution to implement the required behavior.
I also struggled with this problem. Here's how I solved it.
First we need the position of RectTransform in screen and for this I used RectTransformUtility. Then since the rect x, y is the starting point at left bottom (note: in GUI x, y is at left top) we subtract respectively the half of width and height.
Vector2 rectPos = RectTransformUtility.WorldToScreenPoint (Camera.main, rectTransform.position);
float startX = rectPos.x - width / 2;
float startY = rectPos.y - height / 2;
Rect screenRect = new Rect (startX, startY, width, height);
Note: width height should be integer.
Edit: The above solution when we use Screen overlay and change resolution from standard to any other do not work. Even if I used the lossyscale I could not get consistent behavior.
One method of RecTransformUtility is really helpful for this situation (WorldToScreenPoint).
Vector3[] bounds = new Vector3[4];
rectTransform.GetWorldCorners (bounds);
Vector2 rectPos = RectTransformUtility.WorldToScreenPoint (camera, rectTransform.position);
Vector2 minPosition = RectTransformUtility.WorldToScreenPoint (camera, bounds[0]);
Vector2 maxPosition = RectTransformUtility.WorldToScreenPoint (camera, bounds[2]);
Vector2 size = maxPosition - minPosition;
float startX = rectPos.x - size.x / 2;
float startY = rectPos.y - size.y / 2;
return new Rect (startX, startY, size.x, size.y);
In unity I am trying to scale the scene to fit the screen size without loosing it’s aspect ratio. I have tried one solution of aspect utility but it is not working properly, it is showing black strips and so UI do not look good.
I want to target both devices android as well as iPad( e.g 16:9, 4:3 ratio)
Can anybody guide me how to achieve scaling on any kind of devices?
You can use NGUI plugin and attach UIStretchScript on the Image.
try this...name the script as "camera.cs"....add it to your camera...and paste the following code :
using UnityEngine;
using System.Collections;
public class camera : MonoBehaviour {
// Use this for initialization
void Start ()
{
// set the desired aspect ratio (the values in this example are
// hard-coded for 16:9, but you could make them into public
// variables instead so you can set them at design time)
float targetaspect = 16.0f / 9.0f;
// determine the game window's current aspect ratio
float windowaspect = (float)Screen.width / (float)Screen.height;
// current viewport height should be scaled by this amount
float scaleheight = windowaspect / targetaspect;
// obtain camera component so we can modify its viewport
Camera camera = GetComponent<Camera>();
// if scaled height is less than current height, add letterbox
if (scaleheight < 1.0f)
{
Rect rect = camera.rect;
rect.width = 1.0f;
rect.height = scaleheight;
rect.x = 0;
rect.y = (1.0f - scaleheight) / 2.0f;
camera.rect = rect;
}
else // add pillarbox
{
float scalewidth = 1.0f / scaleheight;
Rect rect = camera.rect;
rect.width = scalewidth;
rect.height = 1.0f;
rect.x = (1.0f - scalewidth) / 2.0f;
rect.y = 0;
camera.rect = rect;
}
}
// Update is called once per frame
void Update () {
}
}
There's only two ways to maintain the game's aspect ratio with differing viewport aspect ratios. First, stretching in a given direction, which is never a good option. Second, letterboxing (black bars), which can affect usability, especially on handheld screens. My recommendation would be to allow the game view to scale according to the screen's aspect ratio (which I think is the default functionality in Unity), and design the GUI to be responsive to the screen size (i.e. don't draw GUI elements with pixel specific coords, but with coords relative to the screen size).
I am trying to change my Sprite anchor point so that I can rotate over a 0.0f,0.0f anchorpoint. At first my object is rotation at the default anchor point (0.5f,0.5f). However later on I need it to rotate over a 0.0,0.0 AnchorPoint.
The problem is I cannot change the anchor point and change the position accordingly, so it stays on the same position, without the object appearing to quickly move and reposition to its original point.
Is there a way I can set the anchor point and the position of my Sprite at once, without it moving at all?. Thank you.
-Oscar
I found a solution to this with a UIView elsewhere, and rewrote it for cocos2d:
- (void)setAnchorPoint:(CGPoint)anchorPoint forSprite:(CCSprite *)sprite
{
CGPoint newPoint = CGPointMake(sprite.contentSize.width * anchorPoint.x, sprite.contentSize.height * anchorPoint.y);
CGPoint oldPoint = CGPointMake(sprite.contentSize.width * sprite.anchorPoint.x, sprite.contentSize.height * sprite.anchorPoint.y);
newPoint = CGPointApplyAffineTransform(newPoint, [sprite nodeToWorldTransform]);
oldPoint = CGPointApplyAffineTransform(oldPoint, [sprite nodeToWorldTransform]);
CGPoint position = sprite.position;
position.x -= oldPoint.x;
position.x += newPoint.x;
position.y -= oldPoint.y;
position.y += newPoint.y;
sprite.position = position;
sprite.anchorPoint = anchorPoint;
}
This is a good question, and I don't know the full answer yet.
As you may have noticed, the anchorPoint cannot be changed without affecting scale and rotation.
For scaled sprites:
You have to simultaneously change the anchorPoint and position of your sprite. See this question for a hint
For rotated sprites:
Intuition says you would need to simultaneously change anchorPoint, rotation, and position. (I have no idea how to compute this.)
NOTE: I'm still learning graphics programming, so I'm not 100% able to compute this stuff yet.
I've needed this a couple of times and decided to make a extension for CCNode, tested it abit and seems to work fine. Can be really useful to some :)
It's tested with 1.x but It should work fine in 2.x too. Supports transformed nodes and HD.
Just add this to your project and import whenever you need it - It will be added to all classes deriving from CCNode. (CCSprite, CCLayer)
Interface
#import "cocos2d.h"
#interface CCNode (Extensions)
// Returns the parent coordinate for an anchorpoint. Useful for aligning nodes with different anchorpoints for instance
-(CGPoint)positionOfAnchorPoint:(CGPoint)anchor;
// As above but using anchorpoint in points rather than percentage
-(CGPoint)positionOfAnchorPointInPoints:(CGPoint)anchor;
//Sets the anchorpoint, to not move the node set lockPosition to `YES`. Setting it to `NO` is equal to setAnchorPoint, I thought this would be good for readability so you always know what you do when you move the anchorpoint
-(void)setAnchorPoint:(CGPoint)a lockPosition:(BOOL)lockPosition;
#end
Implementation
#import "CCNode+AnchorPos.h"
#implementation CCNode (Extensions)
-(CGPoint)positionOfAnchorPoint:(CGPoint)anchor
{
float x = anchor.x * self.contentSizeInPixels.width;
float y = anchor.y * self.contentSizeInPixels.height;
CGPoint pos = ccp(x,y);
pos = CGPointApplyAffineTransform(pos, [self nodeToParentTransform]);
return ccpMult(pos, 1/CC_CONTENT_SCALE_FACTOR());
}
-(CGPoint)positionOfAnchorPointInPoints:(CGPoint)anchor;
{
CGPoint anchorPointInPercent = ccp(anchor.x/self.contentSize.width, anchor.y/self.contentSize.height);
return [self positionOfAnchorPoint:anchorPointInPercent];
}
-(void)setAnchorPoint:(CGPoint)a lockPosition:(BOOL)lockPosition
{
CGPoint tempPos = [self positionOfAnchorPoint:a];
self.anchorPoint = a;
if(lockPosition)
{
self.position = tempPos;
}
}
#end
Cocos2d-x + Fixed scale
YourClass.h
virtual cocos2d::Vec2 positionFromSprite(cocos2d::Vec2 newAnchorPoint, cocos2d::Sprite *sprite);
YourClass.m
Vec2 YourClass::positionFromSprite(Vec2 newAnchorPoint, cocos2d::Sprite *sprite) {
Rect rect = sprite->getSpriteFrame()->getRect();
Vec2 oldAnchorPoint = sprite->getAnchorPoint();
float scaleX = sprite->getScaleX();
float scaleY = sprite->getScaleY();
Vec2 newPoint = Vec2(rect.size.width * newAnchorPoint.x * scaleX, rect.size.height * newAnchorPoint.y * scaleY);
Vec2 oldPoint = Vec2(rect.size.width * oldAnchorPoint.x * scaleX, rect.size.height * oldAnchorPoint.y * scaleY);
Vec2 position = sprite->getPosition();
position.x -= oldPoint.x;
position.x += newPoint.x;
position.y -= oldPoint.y;
position.y += newPoint.y;
return position;
}
i have implementing moving image using UIAccelerometer.I have used below code.
code:
float gravX = (acceleration. x * kFilteringFactor) + (gravX * (1 - kFilteringFactor));
float gravY = (acceleration. y * kFilteringFactor) + (gravY * (1 - kFilteringFactor));
float moveX = acceleration. x - gravX;
float moveY = acceleration. y - gravY;
CGPoint MoveCenter = [moveImage center];
float Movex = moveX * 30 + MoveCenter. x;
float Movey = moveY * 30 + MoveCenter. y;
moveImage.center = CGPointMake(Movex, Movey);
In this code there is one problem.If i move device on top side then image is moving on left side,if device is move left side then image is moving top side.can you give me advice.
Maybe is a problem of the coordinates. I'm not sure this is the problem but in Quartz the (0,0) is on bottom left while on UIKit is on top left.
Try to change the coordinates with frame.origin.x and frame.origin.y instead of using CGPoint.