Swift SpriteKit: Flipping parent sprite randomizes child nodes horizontal alignment - swift

I have a parent SKSpriteNode which contains a number of child SKShapeNodes, SKSpriteNodes and SKLabelNodes arranged in specific X,Y position relative to the parent.
When I flip the parent by running an SKAction on it:
SKAction.scaleXTo(-1, duration: duration)
It flips the parent including the children (which I want) but the horizontal alignment of all the children nodes is randomized.
I must mention that I have
parent.anchorPoint = CGPoint(x: 0,y: 0)

The reason this is happening is because of your anchor point. Scaling (And all transformations) happens on this point. To test, take a piece of paper, put a pencil on the top left corner, then try moving the right side over to the left. leaving the pencil where it is. You will notice that the right side is now -width of the paper
What you need to do in this case, is add the width back in to keep the paper at the same location.
Same rule with the sprites. You have to add the width in when doing a negative scale, then remove the width when going back to a positive scale
(or just put your anchor in the center)

Geometrical transformation you apply to a node are automatically applied to its descendants.
This is why when you move/rotate/scale a node the children (and the grandchildren...) are updated as well.
If you want apply a transformation to your sprite without involving other nodes simply change the structure of you scene moving the children of your sprite like shown below.
As it is now
In this image the green circle is your sprite. In the left scenario when you change the green node, it's children are updated accordingly. And you don't want that.
As it should be
So move to the right scenario. Create a new SKNode (the orange one) and place it as shown below.
Now the green node has no children so you can apply geometrical transformation to it without any side effect.

Related

SpriteKit sprite position inside node tree

Currently working on a simple 2D game, where I have player character that is split into multiple sprites (head, torso, legs, arms,...).
I have absolute coordinates right in Aseprite (if I take individual sprite and position them I get correct coordinates).
When I put everything into swift and use negative y instead of positive everything gets totally weird.
For example in Aseprite I have coordinates as follow: head (30, 17), torso (30, 24) and legs (28, 35). Everything aligns perfectly.
In SpriteKit I extend SKNode class and put every subsprites inside with just negative number for y. So instead of going up, I draw down. It looks like that coordinates give in pixels are not correct - sprites are off by few pixels. Mostly is off y coordinate but in some cases (character rotation) also x.
How to get from those absolute upper-left coordinates to correct SpriteKit coordinates then?
Ok I figured what was wrong (several things):
your parent class can be SKNode, but children has to have set anchor point at (0,1)
when changing texture of child sprite, always make sure that sprite size is set to new size of texture. If not it will use previous texture size and resize new texture to old size. This introduces additional problems with positioning. So you have to call: child.size = child.texture!.size() (I used force unwrap because I set (new) texture one step before so I'm 100% sure it exists.
when setting new texture set anchor point again (it seems it gets reset when changing texture of child sprite).

Find the Exact Frame of a rotated SKSpriteNode

I really want to know how to find the EXACT frame of an SKSpriteNode if it is rotated. Currently, the frame of an SKSpriteNode looks like this:
This frame is the rect.frame.
However, this frame includes a lot of empty space due to its zRotation. I don't want this empty space and instead want the frame of exactly the SKSpriteNode.
This is what I want:
How can I achieve this? If you have any idea how to find this 'exact' frame of an SKSpriteNode, I would really like to know. Please use SWIFT.
Thank you
This can be done.
Put a dummy node at the bottom left of your sprite that you know the exact size of. Probably use a perfect square. Anchor it's bottom left to the bottom left of your parent. The parent is the one you want the exact size definition of.
From there, two ways:
Scale the dummy sprite to the size of the sprite you're curious about, and use those measurements to determine where the sprite is and what size it is at any point in time.
Put another dummy sprite at the top right of the parent. In this case you can use the midpoint of your two dummy objects, you don't need to use their edges perfectly. Now you can find the position of these two dummies, at any time, and figure out the size/shape/outline of your sprite in world space units.
Here's way 1 animated

How to calculate sizeDelta in RectTransform?

I write a custom content fitter that is required for my custom layout. So, I need to control RectTransform.sizeDelta property when anchors aren't same but I can't get that shows this value.
I don't need Unity3D API reference, I read it and got a nothing cuz it says only:
The size of this RectTransform relative to the distances between the
anchors. If the anchors are together, sizeDelta is the same as size.
If the anchors are in each of the four corners of the parent, the
sizeDelta is how much bigger or smaller the rectangle is compared to
its parent.
Can anyone explain in normal language what does it mean? And how can I calculate it manually when anchors aren't same?
The definition is somewhat confusing, indeed.
sizeDelta, basically, returns the difference between the actual rectangle of the UI element and the rectangle defined by the anchors.
For example, given a rectangle of 300x200:
Anchors in the same place as the corners of the rectangle: sizeDelta is (0,0)
Left or right anchors at half width of the rectangle: sizeDelta is (150,0)
All four anchors in a point: sizeDelta is (300,200) (i.e.: same size as the rectangle)
As you can see, it doesn't matter at all where the center of the rectangle defined by the anchors is, the only thing that matters is the difference between the width and height of the element rectangle and the anchors rectangle.
In pseudo-code, it's like this:
sizeDelta.x = UIElementRectangle.width - AnchorsRectangle.width;
sizeDelta.y = UIElementRectangle.height - AnchorsRectangle.height;
So, if the UI Rectangle has a dimension bigger than the anchors' one, sizeDelta is positive, if it's smaller, sizeDelta is negative.
sizeDelta: If you made a search, and end up here for an explanation of what sizeDelta means, like GetComponent().sizeDelta.y, then clear your mind.
Visualize a small PANEL, resting on top of a big CANVAS, it's Parent object.
In the PANEL's Rect Transform component, there are 2 rectangles defined:
(a) The rectangle defined by its Anchors. Those triangles. Normally related to the Parent Object location and dimensions, in this case the CANVAS.
(b) The rectangle defined by its own size, the PANEL's own dimension.
sizeDelta = (b) - (a)
That's it. Because normally an interactive component like a Button, smaller in size compared to the object where it rests, like a Panel, and because of that, normally sizeDelta is a negative value. Button size - Panel size = a negative value, normally.
You know the term Negative Space, used in general Design theory?
Think of it, as the space NOT used by a Button resting on a Panel.
Example:
How to find the height of a Panel, that is a Child of a Canvas that is a Camera overlay, thus screen sized. The Anchors of the Panel are related to the Canvas dimensions. Script is on the Panel object:
panelHeight = Screen.height + this.GetComponent().sizeDelta.y;
Remember, sizeDelta is normally negative so it reads more like this pseudo code:
panelHeight = Screen.height - this.sizeDelta.y
Hope this helps you, drove me crazy for a while. Cheers!
References:
https://www.youtube.com/watch?v=VhGxKDIKRvc
https://www.youtube.com/watch?v=FeheZqu85WI
public Vector2 ActualSize(RectTransform trans, Canvas can)
{
var v = new Vector3[4];
trans.GetWorldCorners(v);
//method one
//return new Vector2(v[3].x - v[0].x, v[1].y - v[0].y);
//method two
return RectTransformUtility.PixelAdjustRect(trans, canvas).size;
}
this function works in start

How to stretch resize Unity UI element on swipe in C#

How stretch Unity UI with mouse or finger "swipe"?
I tried using onDrag to adjust the Left parameter of RectTransform:
But it shows error that transform.GetComponent<RectTransform>().rect; is read-only and I cannot edit it.
Also I tried to
Vector2 v2 = GetComponent<RectTransform>().sizeDelta;
v2.x = Input.mousePosition.x;
GetComponent<RectTransform>().sizeDelta = v2;
Which resized it all and I need just left edge to move, and right edge to remain in place:
What is good way to achieve it?
Thnx
You need to re-position the pivot.
Notice how your UI element is getting larger from its center (that is: both the left and right edges are moving as you add width). This is because the pivot for the object is in the center (which it is, (0.5, 0.5)). In order to make it scale outward only to the left you need to adjust the pivot to the right edge, (1, 0.5)

Unity3D localposition relation to parent

I'm trying to position some gameObjects relative to it's parent. I'm using localposition, but the gameObjects are not placed well. If I use local position the parent's width is considered to be 1, right? So if I have a plane unity3d considers it to be a 1X1 square.
I tried to put some models in the local position (1, 1) but they are not placed in the top right corner of the plane...
Do you guys have some thoughts of what might be the problem?
You're incorrect: the parents' width is the x/y/z scale of the parent; local co-ordinates are still measured in world units. If your plane is 100x100 horizontally, and centred at 0,0,0 then you need to put the model to (50,0,50) to be at the corner.