how to make contents in my app universal? - swift

I have made an app that fits all my contents perfectly on Iphone 6, but when I run it on any other device, the positions are shifted. How do I fix this using UIKit on Xcode

make the size and position relevant to the screen size for example:
Image.position = CGPoint(x: (scene?.size.width)! * 0.1, y: (scene?.size.height)! * 0.2)
Image.size = CGSize(x: (scene?.size.width)! * 0.6, y: (scene?.size.height)! * 0.6)
i use scene as a reference majority of the time but frame size works as well by replacing the (scene.size.height)! portion with
(self.frame.size.width) or (self.frame.size.height)

Related

SpriteKit: SKPhysicsJointLimit not respecting 'maxLength'

I'm trying to create a chain-like structure in SpriteKit and I'm having trouble understanding the behavior of SKPhysicsJointLimit's maxLength property. It seems not to do anything at all.
This question didn't solve my problem.
According to the documentation, maxLength is The maximum distance allowed between the two physics bodies connected by the limit joint.
However, my two nodes become oriented much farther apart than their maxLength value. It's true that I'm setting their initial positions to be farther apart than maxLength -- but I would expect the nodes to pull together during the simulation, as if tied together by a stretchy rope. Instead, the nodes remain far apart.
So, here's some code that sets a joint between two SKSpriteNodes.
let screen = UIScreen.main.bounds
let bodyA = SKSpriteNode(imageNamed: "box.png")
let bodyB = SKSpriteNode(imageNamed: "box.png")
bodyA.size = CGSize(width: 20, height: 20)
bodyB.size = CGSize(width: 20, height: 20)
bodyA.position = CGPoint(x: screen.width*0.4, y: screen.height*0.8)
bodyB.position = CGPoint(x: screen.width*0.6, y: screen.height*0.8)
bodyA.physicsBody = SKPhysicsBody(circleOfRadius: 20)
bodyB.physicsBody = SKPhysicsBody(circleOfRadius: 20)
addChild(bodyA)
addChild(bodyB)
let pinJoint = SKPhysicsJointLimit.joint(withBodyA: bodyA.physicsBody!, bodyB: bodyB.physicsBody!, anchorA: CGPoint(x: 0.5, y: 0.5), anchorB: CGPoint(x: 0.5, y: 0.5))
//This doesn't seem to do anything:
pinJoint.maxLength = 5.0
scene?.physicsWorld.add(pinJoint)
In the simulation, it's clear that there is a physics joint connecting the two nodes -- it's just that the nodes are much farther apart than they should be.
Why doesn't my maxLength value change the behavior of my two nodes, and how do I fix the problem? What am I not understanding?
Thanks for your input!
Be sure that the anchor points are in scene coordinates, as described in the documentation. The (0.5, 0.5) is likely intended to be "center of the sprite" or something like that, but that's not correct for a joint.

SpriteKit sprite not following path correctly

I'm currently converting my android game to iOS, and I'm trying to get a bat enemy to 'swoop' the player. I have the curve created in SpriteKit and it looks fine, however the bat does not appear to follow the line correctly, it disappears for a few seconds and then zips past the top right corner going upwards despite running an action.follow on a path that looks drawn properly. The path is attached to a shapeNode which follows the player.
Code:
func createPath(){
//All x values are moved back 1 / 4 of the screens width due to the camera being 1 / 4 of the screens width ahead of the player, and y values are halved due to the player being in the centre of y axis
path.move(to: CGPoint(x: gameScene.frame.width * 3 / 4, y: gameScene.frame.height / 2)) //top right corner
path.addCurve(to: CGPoint(x: -(gameScene.frame.width / 3.5), y: gameScene.frame.height / 6), control1: CGPoint(x: gameScene.frame.width / 2, y: -(gameScene.frame.height / 9)), control2: CGPoint(x: 0, y: -(gameScene.frame.width / 9)))
//to = off screen
//control1 3 / 4 across screen, slighly higher than player
//control2 exactly on player (players node height is screen width / 4.5)
followLine = SKAction.follow(path, asOffset: true, orientToPath: false, duration: 3)
viewLine.path = path
gameScene.addChild(viewLine)
}
func update(dt: Double){
if(GameScene.gV.distanceM == 4 && !run){//DistanceM is just a timer (seconds)
run = true
bat.run(followLine)
}
if run {
/*time += dt//timer to reset bats position
if time > 4 {
run = false
time = 0
}*/
} else {
bat.position = CGPoint(x: gameScene.pigeonCam.position.x + gameScene.frame.width / 2, y: gameScene.pigeonCam.position.x + gameScene.frame.height / 2)//keep bat at top right of screen
}
viewLine.position = gameScene.pigeon.pigeon.position//get node to follow the player
}
My best guess is that while moving the shapeNode appears to move the path it actually doesn't, if so, any other way I could get this path to "follow" the player
After much trial and error I realised the node asOffset is referring to is the one that runs the action, so I put the bat at the top right corner of the screen and adjusted the values, my final values looked as so:
let width = gameScene.frame.width
let height = gameScene.frame.height
path.move(to: CGPoint(x: 0, y: 0)) //top right corner
//0, 0
path.addCurve(to: CGPoint(x: -(width * 1.2), y: -(height / 3.5)), control1: CGPoint(x: -(width / 4), y: -(height / 1.5)), control2: CGPoint(x: -(width * 3 / 4), y: -(height / 2)))
This makes the bat follow the line perfectly, though the visual representation of the line is messed up

Swift SceneKit — physical blocks do not stick to each other

Blocks just crumble apart.
How can this problem be solved?
Initializing blocks:
var boxNode = SCNNode(geometry: SCNBox(width: 0.75, height: 0.15, length: 0.25, chamferRadius: 0))
boxNode.position = SCNVector3(x: x1, y: y, z: z1)
boxNode.geometry?.firstMaterial = SCNMaterial()
boxNode.geometry?.firstMaterial?.diffuse.contents = UIImage(named: "wood.jpg")
boxNode.physicsBody = SCNPhysicsBody(type: .dynamic, shape: nil)
boxNode.eulerAngles.y = Float(Double.pi / 2) * rotation
boxNode.physicsBody?.friction = 1
boxNode.physicsBody?.mass = 0.5
boxNode.physicsBody?.angularDamping = 1.0
boxNode.physicsBody?.damping = 1
picture
video
full code
I won't be able to tell you how to fix it as I have the exact same problem which I wasn't able to solve. However, as I played around I figured out a couple of things (which you may find useful):
The same problem hasn't happened to me in pure SceneKit, hence I think it's a bug in ARKit
Node with physics has to be added to the rootNode of the scene, otherwise odd stuff happens (elements passing through each other, gravity behaving in an inconsistent way)
If you pass nil as shape parameter, SceneKit will figure bounding box based on the geometry of the node. This hasn't worked properly for me so what I've done (using SceneKit editor) was to duplicate the geometry and then set it as a custom shape for the bounding box (have a look at the attached image)
Overall I've found physics simulation in SceneKit when used with ARKit to be extremely buggy and I spent a lot of time "tricking" it into working more-or-less how I wanted it to work.

Struggle creating correct physicsbody

In my current project I create some node that I would like to create physics bodies for.
This creates the nodes:
let seg = SKShapeNode(ellipseOf: CGSize(width: 10 / xScale, height: 10 / yScale))
let offset = (seg.frame.height / 1.5) * CGFloat(i + 1)
seg.position = CGPoint(x: anchorPoint.x, y: ((size.height / 2) / yScale) + (10 / yScale) - offset)
segments.append(seg)
addChild(seg)
And this is how I currently try to create the bodies:
seg.physicsBody = SKPhysicsBody(circleOfRadius: 10 / xScale / yScale / 2)
I dont know how I would go about creating the correct one. It should function like a normal physics body(edge based bodies don't collide with stuff).
Currently when the circles roll down it looks like this although they are initially circles:
Also they look very pixelated. Do you have any idea why?
Thanks for your help!

SpriteKit - get absolute size of SKNode

I'm programming a small game in Swift and SpriteKit, which is made of a boxes (4 * 8).
Scene (1024 * 768)
boxes (964 * 452)
row1 (932 * 25)
col1 (24 * 116)
col2 (24 * 116)
col3 (24 * 116)
...
row2...
I want to give them a texture, but I don't know how big the image file should be. And the box node's size seems to be relative to its parent node. How can I get the absolute size of an SKNode, the size the node takes on the screen?
All SKNodes have a method called calculateAccumulatedFrame
Any texture will be scaled to fill the Node. Just make sure the aspect ratio of the texture and the node are the same (e.g. make them both square).
The "size" property of a Node works! For example:
let test = SKSpriteNode(color: .clear, size: CGSize(width: 100.0, height: 100.0))
print(test.size)
test.setScale(2.0)
print(test.size)
correctly prints:
(100.0, 100.0)
(200.0, 200.0)