Ball rolling and turning effect with SpriteKit - swift3

I have created a ball node, and applied the texture images from my 3d model. I have captured totally 6 images, 3 images (with having 120deg) for rolling around x axis, and other 3 images for rolling around y axis. I want sprite kit to simulate it with following code below.When i apply impulse, it starts sliding instead rolling and when it collides to sides, then it starts turning but again not rolling. Normally, depending on the impulse on the ball, it should turn and roll together sometimes. The effect on "8 ball pool game" balls can be an example which i want to get a result.
var ball = SKSpriteNode()
var textureAtlas = SKTextureAtlas()
var textureArray = [SKTexture]()
override func didMove(to view: SKView) {
textureAtlas = SKTextureAtlas(named: "white")
for i in 0... textureAtlas.textureNames.count {
let name = "ball_\(i).png"
textureArray.append(SKTexture(imageNamed: name))
}
ball = SKSpriteNode(imageNamed: textureAtlas.textureNames[0])
ball.size = CGSize(width: ballRadius*2, height: ballRadius*2)
ball.position = CGPoint(x: -ballRadius/2-20, y: -ballRadius-20)
ball.zPosition = 0
ball.physicsBody = SKPhysicsBody(circleOfRadius: ballRadius)
ball.physicsBody?.isDynamic = true
ball.physicsBody?.restitution = 0.3
ball.physicsBody?.linearDamping = 0
ball.physicsBody?.allowsRotation = true
addChild(ball)}

You need to apply angular impulse to get it to rotate
node.physicsBody!.applyAngularImpulse(1.0)

Related

extension file making image flip upside down (swift3)

The following extension file generates my image upside down. All i need to do is flip my image by 180 degrees.
case .landscapeLeft:
var transform: CGAffineTransform = CGAffineTransform.identity
transform = transform.translatedBy(x: self.size.width, y: self.size.height)
transform = transform.rotated(by: CGFloat(Double.pi/2))
guard let cgImage = self.cgImage, let colorSpace = cgImage.colorSpace, let context: CGContext = CGContext(data: nil, width: Int(self.size.width), height: Int(self.size.height), bitsPerComponent: cgImage.bitsPerComponent, bytesPerRow: 0, space: colorSpace, bitmapInfo: CGImageAlphaInfo.premultipliedLast.rawValue) else { return self }
context.concatenate(transform)
context.draw(cgImage, in: CGRect(x: 0, y: 0, width: self.size.width, height: self.size.height))
guard let transformed = context.makeImage() else { return self }
return UIImage(cgImage: transformed)
return imageResult!
I have tried to use 3 * Double.pi / 2 but that makes no image appear on the image view. The only math formula that gets a image on the image view is double.pi / 2 for my code.
Your code rotates the image about the origin of the image which happens to be the top left hand corner. You need to translate the origin to be the centre of the image before applying the rotation and then after translate the origin back to the top left corner. If you replace your transform construction with the following it should work
var transform: CGAffineTransform = CGAffineTransform.identity
transform = transform.translatedBy(x: self.size.width/2, y: self.size.height/2)
transform = transform.rotated(by: angle)
transform = transform.translatedBy(x: -self.size.width/2, y: -self.size.height/2)

How to visualize PhysicsWorld / CollisionShape with debug renderer?

My test scene for Urho3D/Urhosharp contains two boxes (see screenshot).
For both, the red and the green box I added a RigidBody and a CollisionShape.
The shape for the red box is a sphere and for the blue one a box. I've enabled debug visualisation by adding:
app.Engine.SubscribeToPostRenderUpdate(args => {
app.Renderer.DrawDebugGeometry(false);
});
However, this does not render the collision shapes but only the wireframe of the objects (green lines).
Here's the code for the blue node:
var floorNode = app.RootNode.CreateChild("Floor");
floorNode.Position = Vector3.Zero;
floorNode.Scale = new Vector3(10, 1, 10);
var floorComp = floorNode.CreateComponent<Box>();
floorComp.SetMaterial(Material.FromColor(new Color(0, 0, 1, 0.5f)));
var rigidBody = floorNode.CreateComponent<RigidBody>();
rigidBody.Mass = 0;
var collNode = floorNode.CreateComponent<CollisionShape>();
collNode.SetBox(Vector3.One, Vector3.Zero, Quaternion.Identity);
And for the red one:
var boxNode = app.RootNode.CreateChild("Box");
boxNode.SetScale(2f);
var boxComp = boxNode.CreateComponent<Box>();
boxComp.Color = Color.Red;
boxComp.SetMaterial(Material.FromColor(Color.Red));
var rigidBody = boxNode.CreateComponent<RigidBody>();
rigidBody.Mass = 0f;
var collNode = boxNode.CreateComponent<CollisionShape>();
collNode.SetBox(Vector3.One, Vector3.Zero, Quaternion.Identity);
collNode.SetSphere(3f, Vector3.Zero, Quaternion.Identity);
The collision works but I'd love to see the physics world because it makes it easier to experiment.
And here's the solution: the default debug output of the Urho3D renderer does not include the physics components. It has to be added manually.
app.Engine.SubscribeToPostRenderUpdate(args => {
// Default debug rendering.
app.Renderer.DrawDebugGeometry(false);
// Use debug renderer to output physics world debug.
var debugRendererComp = app.Scene.GetComponent<DebugRenderer>();
var physicsComp = app.Scene.GetComponent<PhysicsWorld>();
if(physicsComp != null)
{
physicsComp.DrawDebugGeometry(debugRendererComp, false);
}
});
For this to work the scene must of course have a debug renderer and a physics component:
app.Scene.GetOrCreateComponent<PhysicsWorld>();
app.Scene.GetOrCreateComponent<DebugRenderer>();
Then the result is as expected. In the image below the red box has got a spherical collision shape:
The nice thing I noticed: since the collision shape is a child node of the actual node it will scale together with the node. This means if the box or sphere (or whatever) is created with a size of Vector3.One it will always match the actual node size.

How to scale CAShapeLayer to different UIImageView

I have a UIImageView that you can tap on and it draws a circle. I store the location of the circles in an Array of Dictionaries. This allows me to "replay" the drawing of the circles. However, when the UIImageView is a different size from the original, the circles don't scale to the new UIImageView.
How can I get the circles to scale? For demonstration purposes, the top picture is the size of the UIImageView used for input and the second one is the size for replay.
Inputing the circles:
Replay the circles (the circles should be in the blue UIImageView
import Foundation
import UIKit
class DrawPuck {
func drawPuck(circle: CGPoint, circleColour: CGColor, circleSize: CGFloat, imageView: UIImageView) {
let circleBezierPath = UIBezierPath(arcCenter: CGPoint(x: circle.x,y: circle.y), radius: CGFloat(circleSize), startAngle: CGFloat(0), endAngle:CGFloat(M_PI * 2), clockwise: true)
let shapeLayer = CAShapeLayer()
shapeLayer.path = circleBezierPath.cgPath
//change the fill color
shapeLayer.fillColor = circleColour
//you can change the stroke color
shapeLayer.strokeColor = UIColor.white.cgColor
//you can change the line width
shapeLayer.lineWidth = 0.5
imageView.layer.addSublayer(shapeLayer)
}
}
I was able to resolve this with CATransform3DMakeScale As long as I keep the original aspect ratio of the original image it works great.
let width = yellowImageView.frame.width / blueImageView.frame.width
let height = yellowImageView.frame.height / blueImageView.frame.height
shapeLayer.transform = CATransform3DMakeScale(height, width, 1.0)
view.layer.addSublayer(shapeLayer)

AVCapture and zooming of previewLayer in Swift

I have a camera app which allows the user to both take pictures and record video. The iPhone is attached to a medical otoscope using an adapter, so the video that is captured is very small (about the size of a dime). I need to be able to zoom the video to fill the screen, but have not been able to figure out how to do so.
I found this answer here on SO that uses ObjC but have not had success in translating it to Swift. I am very close but am getting stuck. Here is my code for handling a UIPinchGestureRecgoznier:
#IBAction func handlePinchGesture(sender: UIPinchGestureRecognizer) {
var initialVideoZoomFactor: CGFloat = 0.0
if (sender.state == UIGestureRecognizerState.began) {
initialVideoZoomFactor = (captureDevice?.videoZoomFactor)!
} else {
let scale: CGFloat = min(max(1, initialVideoZoomFactor * sender.scale), 4)
CATransaction.begin()
CATransaction.setAnimationDuration(0.01)
previewLayer?.transform = CGAffineTransform(scaleX: scale, y: scale)
CATransaction.commit()
if ((captureDevice?.lockForConfiguration()) != nil) {
captureDevice?.videoZoomFactor = scale
captureDevice?.unlockForConfiguration()
}
}
}
This line...
previewLayer?.transform = CGAffineTransform(scaleX: scale, y: scale)
... gives me the error 'Cannot assign value of type 'CGAffineTransform' to type 'CGTransform3D'. I'm trying to figure this out but my attempts to fix this have been unfruitful.
Figured it out: Changed the problematic line to:
previewLayer?.setAffineTransform(CGAffineTransform(scaleX: scale, y: scale))

3D rotation of a element in RaphaelJS

I am hoping you might be able to help me determine if the following animation is allowed in raphael.js. I am trying to have an element fly off the page, the idea is to have it appear to fall/fly off in 3D. I am able to tell the element to rotate X degrees and slide off but its lacking the look of the element being independent of hte background. What I would like to do is be able to tell raphael to rotate the top corner "out" as it falls giving the illusion of it falling out of view as picture falling off of a wall. Is this even possible or does Raphael only operate in two dimensional space?
Raphael only deals with 2D space. To implement a 3D flip you have to fake it. Thankfully Raphael implements Scale(sx,sy,x,y) as a transform op, so you can scale about an origin to fake a 3D 'flip' rotation.
For example:
Raphael.el.flipXTransform = function (parentBbox) {
var x = this.getBBox().x;
var width = this.getBBox().width;
parentBbox = parentBbox || { width:width, x: x};
var parentWidth = parentBbox.width;
var parentX = parentBbox.x;
var originX = parentX - x + parentWidth / 2;
return 's-1,1,' + originX + ',0';
};
Raphael.el.flipX = function (duration, easing, parentBbox) {
duration = duration || 500;
easing = easing || 'easeInOut';
var scale = this.flipXTransform(parentBbox);
this.animate({ transform: '...' + scale }, duration, easing);
};
Here's a fiddle example for you to play with. The downside is this doesn't convey a perspective like a true 3D rotate does.