Node losing gravity after SCNAction - ios

I'd like to drop an object and then move it back to the top and let it fall again. The first part is working, but then the node seems to lose its gravity and isn't falling again. It looks like its physics body stays on the floor and is not moved by the SCNActions. What is the solution for this? Thanks
let shape = SCNPhysicsShape(geometry: SCNBox(width: boxSize, height: 0.001, length: boxSize, chamferRadius: 0), options:nil)
node.physicsBody = SCNPhysicsBody(type: .dynamic, shape: shape)
...
SCNTransaction.begin()
SCNTransaction.animationDuration = 5
let actions = SCNAction.sequence([
SCNAction.move(to: SCNVector3(x: 0, y: 3, z: -2), duration: 1),
SCNAction.rotate(by: .pi*2, around: SCNVector3(0,1,0), duration: 1)
])
node.runAction(actions)
//node.presentation.runAction(actions) //also not working
SCNTransaction.commit()

You will have to let the physics simulation know that the physics body has moved by calling -resetTransform.

Related

Repeat Texture on X axis over 3dObject in ARkit SCNODE - SWIFT

I wanted to move the texture over the SCNode in my current scene.
I am currently animating the node but i want the texture to run over the object instead of animating it.
let moveup = SCNAction.moveBy(x: 0.01, y: 0, z: 0, duration: 1)
moveup.timingMode = .easeInEaseOut
moveup.speed = CGFloat(20.5)
let moveDown = SCNAction.moveBy(x: -0.01, y: 0, z: 0, duration: 1)
moveDown.timingMode = .easeInEaseOut;
moveDown.speed = CGFloat(20.5)
let moveupSequence = SCNAction.sequence([moveup, moveDown])
print(moveupSequence.duration, moveupSequence.speed)
WaterNode?.runAction(moveupSequence)
This is my code for annimating the object. I need to know how can i access the texture and move them to X axis.
There is contentsTransform property of material
let action = SCNAction.customAction(duration: 1) { (node, elapsedTime) in
let c = node.geometry?.materials.first?.diffuse.contentsTransform
node.geometry?.materials.first?.diffuse.contentsTransform = SCNMatrix4MakeTranslation((c?.m41)! + 0.01, (c?.m42)!, (c?.m43)!)
}

Scene Kit node not rotating

I am trying to rotate by scene kit node, however it is not rotating.
I want it to rotate around the y axis. It is a sphere.
let node = SCNNode()
node.geometry = SCNSphere(radius: 1)
node.geometry?.firstMaterial?.diffuse.contents = UIImage(named: "diffuse.png")
node.geometry?.firstMaterial?.specular.contents = UIImage(named: "specular.png")
node.geometry?.firstMaterial?.emission.contents = UIImage(named: "emission.png")
scene.rootNode.addChildNode(node)
let action = SCNAction.rotate(by:360 * CGFloat((Double.pi)/180.0), around: SCNVector3(x: 0, y: 1, z: 0), duration: 8)
let repeatAction = SCNAction.repeatForever(action)
node.runAction(repeatAction)
Are you certain it isn't rotating? I'm not sure what your diffuse, specular and emission images are but maybe because it's a sphere it just doesn't really look like it is rotating because it looks the same from all sides.
Running the same action on a cube in viewDidAppear is working for me, so it could just be that you can't really notice the sphere rotating. I used this code:
let node = SCNNode()
node.geometry = SCNBox (width: 0.5, height: 0.5, length: 0.5, chamferRadius: 0.1)
node.position = SCNVector3Make(0, 0, -1)
sceneView.scene.rootNode.addChildNode(node)
let action = SCNAction.rotate(by:360 * CGFloat((Double.pi)/180.0), around: SCNVector3(x: 0, y: 1, z: 0), duration: 8)
let repeatAction = SCNAction.repeatForever(action)
node.runAction(repeatAction)
The cube is rotating fine with the way that you rotated the SCNNode.
Hope this helps

Sprite-Kit and Swift Update Position to Another Sprite

Like many here asking questions I'm new to programing, but I'm going to do my best to describe my dilemma. Thanks for any help in advance.
I've included a picture of my goal.
The Green line is a node that rotates around the center of the screen. I have its anchor point set to 1,1 and position x,y to the center of the device. Using SKActions I've made the node rotate so many degrees causing it to move like the second hand of a clock would around its center post. All the code to this point I've got down. Here is where I've reached a mental brick wall. I want to have a sprite constantly placed at the tip of the rotating node so that the sprite will move around the center in a circular motion. The sprite is represented by the Pink circle.
This was my plan of attack, but my lack of knowledge of the swift language prevents me from executing it.
Is there a way to add a reference point to the tip of the node? If so I was thinking of doing that, then in the update function set the position of the sprite to the x,y of that reference point. I hope I've included enough information. If anyone has a better approach to this, please let me hear it. Thanks so much in advance.
I am posting an answer, even though it was answered in the comments. If Leo posts the answer, I'll delete this one.
I am assuming that your ball is a child of the line, so you'd just offset the x position of your ball the width of the line. Which as noted in comments is the radius of the circle path your ball is following.
Your secondary issue could be solved by using another SKAction to offset the zRotation of the line. For example :
let lineRotateAction = SKAction.rotateByAngle(CGFloat(360).degreesToRadians, duration: 6)
let ballRotateAction = SKAction.rotateByAngle(CGFloat(-360).degreesToRadians, duration: 6)
You can simply put create the hands as children of an empty SKNode, position both hands correctly in relation to these SKNodes and then rotate the SKNodes themselves.
Two different ways: First using a parent node (which is potentially what you want):
let body = SKSpriteNode(color: .clear, size: CGSize(width: 20, height: 150))
body.anchorPoint = CGPoint(x: 0.5, y: 0)
body.position = CGPoint(x: frame.midX, y: frame.midY)
body.run(SKAction.repeatForever(SKAction.rotate(byAngle: CGFloat(M_PI * 2), duration: 10)))
let hand = SKSpriteNode(color: .blue, size: CGSize(width: body.size.width/2, height: body.size.height))
hand.position = CGPoint(x: 0, y: body.size.height/2)
let ball = SKSpriteNode(color: .green, size: CGSize(width: body.size.width, height: body.size.width))
ball.position = CGPoint(x: 0, y: body.size.height - ball.size.height/2)
body.addChild(hand)
body.addChild(ball)
addChild(body)
Second is using physics, which produces a similar effect only on the surface but it might give you other ideas too:
let hand = SKSpriteNode(color: .blue, size: CGSize(width: 10, height: 150))
hand.anchorPoint = CGPoint(x: 0.5, y: 1)
hand.position = CGPoint(x: frame.midX, y: frame.midY)
hand.physicsBody = SKPhysicsBody(rectangleOf: hand.size)
hand.physicsBody?.affectedByGravity = false
hand.physicsBody?.isDynamic = false
hand.run(SKAction.repeatForever(SKAction.rotate(byAngle: CGFloat(M_PI * 2), duration: 10)))
addChild(hand)
let ball = SKSpriteNode(color: .green, size: CGSize(width: 20, height: 20))
ball.anchorPoint = CGPoint(x: 0.5, y: 0.5)
ball.position = CGPoint(x: frame.midX, y: frame.midY - hand.size.height)
ball.physicsBody = SKPhysicsBody(rectangleOf: ball.size)
addChild(ball)
let joint = SKPhysicsJointPin.joint(withBodyA: hand.physicsBody!,
bodyB: ball.physicsBody!,
anchor: ball.position)
physicsWorld.add(joint)
Have fun!

Create smoother edges or otherwise fix jagged edges on box in SCNView?

The code below generates a red box in a SCNView. However, the edges are jagged along the top and bottom of the side/element facing you (as illustrated by the attachment). The goal is to render smoother edges similar to Minecraft boxes. Changing the camera position reduces the pixelation of certain edges, so is this a camera angle issue? If yes, is it possible to render boxes with smooth edges no matter the camera angle?
For instance setting the camera position to SCNVector3(x: 0.0, y: 0.0, z: 10.0) renders the box effectively in 2D and with crisp edges (second attachment).
let sceneView = SCNView(frame: self.view.frame)
self.view.addSubview(sceneView)
let scene = SCNScene()
sceneView.scene = scene
let camera = SCNCamera()
let cameraNode = SCNNode()
cameraNode.camera = camera
cameraNode.position = SCNVector3(x: -3.0, y: 0.0, z: 10.0)
let ambientLight = SCNLight()
ambientLight.type = SCNLightTypeAmbient
ambientLight.color = UIColor(red: 0.2, green: 0.2, blue: 0.2, alpha: 1.0)
cameraNode.light = ambientLight
let light = SCNLight()
light.type = SCNLightTypeOmni
let lightNode = SCNNode()
lightNode.light = light
lightNode.position = SCNVector3(x: 0, y: 20, z: 10)
let cubeGeometry = SCNBox(width: 3.0, height: 3.0, length: 3.0, chamferRadius: 0.0)
let cubeNode = SCNNode(geometry: cubeGeometry)
let planeGeometry = SCNPlane(width: 100.0, height: 100.0)
let planeNode = SCNNode(geometry: planeGeometry)
planeNode.eulerAngles = SCNVector3(x: GLKMathDegreesToRadians(-90), y: 0, z: 0)
planeNode.position = SCNVector3(x: 0, y: -0.5, z: 0)
let redMaterial = SCNMaterial()
redMaterial.diffuse.contents = UIColor.redColor()
cubeGeometry.materials = [redMaterial]
let greenMaterial = SCNMaterial()
greenMaterial.diffuse.contents = UIColor.greenColor()
planeGeometry.materials = [greenMaterial]
let constraint = SCNLookAtConstraint(target: cubeNode)
constraint.gimbalLockEnabled = true
cameraNode.constraints = [constraint]
lightNode.constraints = [constraint]
scene.rootNode.addChildNode(lightNode)
scene.rootNode.addChildNode(cameraNode)
scene.rootNode.addChildNode(cubeNode)
scene.rootNode.addChildNode(planeNode)
As mentioned in the comments, if you want to antialias every frame set the antialiasingMode. It doesn’t do as nice a job as CoreGraphics but it’s reasonably nice. However, it does increase the workload a ton, so you’re going to burn batteries and slow down your framerate.
On OS X the default is to 4x multisample every frame. On iOS the default is no multisampling, since it’s so expensive.
Luckily there’s a solution I much prefer, which is to turn on jittering. It’s kind of like multisampling but lazy. When objects are moving they are rendered normally (with jaggies), but when they stop moving the renderer runs like 96 more frames in the background and smooths out all the jaggies.
The final look is much better than antialiasing (because there’s no “96x antialiasing mode”) and on fast hardware most people I’ve shown it to don’t realize that the quality is changing when objects move.

Scale SCNNode in SceneKit

I have the following SCNNode:
let box = SCNBox(width: 10.0, height: 10.0, length: 10.0, chamferRadius: 0)
let boxNode = SCNNode(geometry: box)
boxNode.position = SCNVector3(x: 0, y: 0, z: 0)
If I apply:
boxNode.scale = SCNVector3(x: 0.5, y: 0.5, z: 0.5)
it appears to have no effect on the size of the box. I've checked this with boxNode.getBoundingBoxMin(&v1, max: &v2). It's always the same and appears the same on-screen.
Am I missing something? The docs imply that setting the scale should affect the node's geometry and thus be a different size.
Thanks.
J.
I just tested in a playground and it worked perfectly for me. Perhaps your camera is zooming in to compensate for the smaller box?
import SceneKit
import SpriteKit
import XCPlayground
let sceneView = SCNView(frame: CGRect(x: 0, y: 0, width: 800, height: 600))
XCPlaygroundPage.currentPage.liveView = sceneView
var scene = SCNScene()
sceneView.scene = scene
sceneView.backgroundColor = SKColor.greenColor()
sceneView.debugOptions = .ShowWireframe
// default lighting
sceneView.autoenablesDefaultLighting = true
// a camera
var cameraNode = SCNNode()
cameraNode.camera = SCNCamera()
cameraNode.position = SCNVector3(x: 15, y: 15, z: 30)
scene.rootNode.addChildNode(cameraNode)
let box = SCNBox(width: 10.0, height: 10.0, length: 10.0, chamferRadius: 0)
let boxNode = SCNNode(geometry: box)
boxNode.position = SCNVector3(x: 0, y: 0, z: 0)
scene.rootNode.addChildNode(boxNode)
let centerConstraint = SCNLookAtConstraint(target: boxNode)
cameraNode.constraints = [centerConstraint]
let sphere = SCNSphere(radius: 4)
let sphereNode = SCNNode(geometry: sphere)
sphereNode.position = SCNVector3(x:15, y:0, z:0)
scene.rootNode.addChildNode(sphereNode)
//boxNode.scale = SCNVector3(x: 0.5, y: 0.5, z: 0.5)
Uncomment the last line and you'll see the box (10 x 10 x 10) switch switch from being larger than the sphere (diameter of 8) to being smaller than the sphere. Here it is after the scaling:

Resources