How can i make a path like the number 8 (SpriteKit, Swift) - swift

I'm trying to create a path for an object to follow that is in the shape of the number 8. Is it possible to create a path with curves like the shape of a number 8?
If it's not, how would you suggest I do this?
Thanks (:

SKPhysicsBody Path Generator is powerful tool that you can create with him what you want!
very comfortable and easy to create your path!
Basic Instruction
Drag and drop the sprite image into drop zone.
Start drawing path by clicking on coordinates.
The link

Here's a simple example:
var curve = UIBezierPath()
let startPoint = CGPoint(x: 100, y: 50)
curve.moveToPoint(startPoint)
// top right
curve.addCurveToPoint(CGPoint(x: 100, y: 250),
controlPoint1: CGPoint(x: 200, y: 50),
controlPoint2: CGPoint(x: 200, y: 250))
// bottom left
curve.addCurveToPoint(CGPoint(x: 100, y: 450),
controlPoint1: CGPoint(x: 0, y: 250),
controlPoint2: CGPoint(x: 0, y: 450))
// bottom right
curve.addCurveToPoint(CGPoint(x: 100, y: 250),
controlPoint1: CGPoint(x: 200, y: 450),
controlPoint2: CGPoint(x: 200, y: 250))
// top left
curve.addCurveToPoint(CGPoint(x: 100, y: 50),
controlPoint1: CGPoint(x: 0, y: 250),
controlPoint2: CGPoint(x: 0, y: 50))
curve.closePath()

Related

How to draw a curve path after straight lines in SwiftUI

What I need is to draw a curve like the one shown on the right side of the picture below.
struct DrawingPaths: View {
var body: some View {
Path { path in
path.move(to: CGPoint(x: 0, y: 0))
path.addLine(to: CGPoint(x: 0, y: 300))
path.addLine(to: CGPoint(x: 430, y: 0))
path.addQuadCurve(to: CGPoint(x:430, y: 0), control: CGPoint(x: 300, y: 5))
}
.fill(.blue)
}
That is a quad curve with 2 control points.
struct DrawingPaths: View {
var body: some View {
Path { path in
//Top left
path.move(to: CGPoint(x: 0, y: 0))
//Left vertical bound
path.addLine(to: CGPoint(x: 0, y: 300))
//Curve
path.addCurve(to: CGPoint(x: 430, y: 200), control1: CGPoint(x: 175, y: 350), control2: CGPoint(x: 250, y: 80))
//Right vertical bound
path.addLine(to: CGPoint(x: 450, y: 0))
}
.fill(.blue)
.edgesIgnoringSafeArea(.top)
}
}

How to give corner radius in one side to Imageview in swift?

How can I give corner radius in one side to Imageview like zig zag?
like in image
In this image I want like a large image witch is highlighted in Blue line.
If anyone know about this Please help me.
And I apologize if I could not explane my problem properly.
Solve the problem using bezier path
Study the bezier path principle and find the appropriate control point
Here is the sample code
let imageView = UIImageView(frame: CGRect(x: 0, y: 0, width: self.view.frame.width, height: self.view.frame.height/3))
let path = UIBezierPath()
path.move(to: CGPoint(x: 0.0, y: 0.0))
path.addLine(to: CGPoint(x: self.view.frame.width, y: 0))
path.addLine(to: CGPoint(x: self.view.frame.width, y: self.view.frame.size.height/3))
path.addCurve(to: CGPoint(x: 0, y: self.view.frame.size.height/3 - 50),
controlPoint1: CGPoint(x: 200, y: self.view.frame.size.height/3 - 20),
controlPoint2: CGPoint(x: self.view.frame.width/2, y: self.view.frame.size.height/3 - 100))
path.close()
let shapeLayer = CAShapeLayer()
shapeLayer.path = path.cgPath
imageView.layer.mask = shapeLayer
imageView.image = UIImage(named: "spider.jpg")
self.view.addSubview(imageView)

Xcode Swift, Keyframe animation has unwanted delay between animations loops on a bezier curve

Im attempting to animate a UIView along an oval using a bezier curve. The code works except that there is a delay between each loop of the animation. I'm at a loss as to what is causing this.
let myView = UIView()
myView.backgroundColor = UIColor.blue
myView.frame = CGRect(x: 0, y:0, width: 30, height: 30)
let path = UIBezierPath(ovalIn: CGRect(x: 0, y: 0, width: 200, height: 200))
let animation = CAKeyframeAnimation(keyPath: "position")
animation.path = path.cgPath
animation.repeatCount = 1000
animation.duration = 1
myView.layer.add(animation, forKey: "animate along path")
Found a solution. The pause between animation loops only takes place when making a path with the UIBezierPath(ovalIn:) constructor. There's no delay when manually making your own path. So I made my own oval.
Replaced this
let path = UIBezierPath(ovalIn: CGRect(x: 0, y: 0, width: 200, height: 200))
with this
let rect = CGRect(x: 0, y: 0, width: 200, height: 200)
let path = UIBezierPath()
path.move(to: CGPoint(x: rect.maxX, y: rect.midY))
path.addQuadCurve(to: CGPoint(x: rect.midX, y: rect.maxY), controlPoint: CGPoint(x: rect.maxX, y: rect.maxY))
path.addQuadCurve(to: CGPoint(x: rect.minX, y: rect.midY), controlPoint: CGPoint(x: rect.minX, y: rect.maxY))
path.addQuadCurve(to: CGPoint(x: rect.midX, y: rect.minY), controlPoint: CGPoint(x: rect.minX, y: rect.minY))
path.addQuadCurve(to: CGPoint(x: rect.maxX, y: rect.midY), controlPoint: CGPoint(x: rect.maxX, y: rect.minY))

How do I cast two shadows from an UIImageView with a SF Symbol as the image?

I want to cast a shadow to the lower left AND the lower right of my Image. But I'm struggling to get the second shadow cast (layer2)...
I've created a subclass of UIImage view and use that in IB:
import UIKit
class ShadowImageView: UIImageView {
var layer2 = CALayer()
override func layoutSubviews() {
super.layoutSubviews()
self.layer2 = CALayer(layer: self.layer)
self.clipsToBounds = false
self.layer.shadowColor = UIColor.gray.cgColor
self.layer.shadowOffset = CGSize(width: -16, height: 16)
self.layer.shadowOpacity = 0.33
self.layer.shadowRadius = 3
self.layer.masksToBounds = false
self.layer2.shadowColor = UIColor.gray.cgColor
self.layer2.shadowOffset = CGSize(width: 16, height: 16)
self.layer2.shadowOpacity = 0.33
self.layer2.shadowRadius = 3
self.layer2.masksToBounds = false
self.layer.insertSublayer(self.layer2, at: 0)
print("\(self.layer)\n")
if let sublayers = self.layer.sublayers {
for layer in sublayers {
print("\(layer)\n")
}
}
}
}
Am I going in the right direction to copy the layer and apply a new shadow to it or should I look in a different direction?
Fixed the shadow problem. I was able to generate double shadows by adding 3 layers on my UIView. The furthest behind (the first sublayer of the view's layer) is the darker shadow, the one on top of that is the lighter shadow and on top of that I have one with the normal color.
I'm 'drawing' the images on the layers by applying a shadow path & color.
The image I'm drawing is coming from a method like listed below, but it's not being generated from a SFSymbols. I would like to generate it during runtime so I end up with a simple method of using symbols to place Neumorphic elements in our apps. The manual generation of these BezierPaths isn't really pleasant.
static var shieldFill: UIBezierPath = {
let bezierPath = UIBezierPath()
bezierPath.move(to: CGPoint(x: 58.94, y: 115.53))
bezierPath.addCurve(to: CGPoint(x: 62.84, y: 114.4), controlPoint1: CGPoint(x: 60.06, y: 115.53), controlPoint2: CGPoint(x: 61.57, y: 115.04))
bezierPath.addCurve(to: CGPoint(x: 101.76, y: 74.46), controlPoint1: CGPoint(x: 91.5, y: 100.49), controlPoint2: CGPoint(x: 101.76, y: 91.89))
bezierPath.addLine(to: CGPoint(x: 101.76, y: 39.94))
bezierPath.addCurve(to: CGPoint(x: 92.04, y: 25.05), controlPoint1: CGPoint(x: 101.76, y: 31.84), controlPoint2: CGPoint(x: 99.41, y: 28.12))
bezierPath.addCurve(to: CGPoint(x: 67.63, y: 16.85), controlPoint1: CGPoint(x: 87.89, y: 23.29), controlPoint2: CGPoint(x: 71.29, y: 17.97))
bezierPath.addCurve(to: CGPoint(x: 58.94, y: 15.53), controlPoint1: CGPoint(x: 64.94, y: 16.11), controlPoint2: CGPoint(x: 61.52, y: 15.53))
bezierPath.addCurve(to: CGPoint(x: 50.24, y: 16.85), controlPoint1: CGPoint(x: 56.35, y: 15.53), controlPoint2: CGPoint(x: 52.93, y: 16.11))
bezierPath.addCurve(to: CGPoint(x: 25.83, y: 25.05), controlPoint1: CGPoint(x: 46.53, y: 17.97), controlPoint2: CGPoint(x: 29.93, y: 23.29))
bezierPath.addCurve(to: CGPoint(x: 16.11, y: 39.94), controlPoint1: CGPoint(x: 18.46, y: 28.12), controlPoint2: CGPoint(x: 16.11, y: 31.84))
bezierPath.addLine(to: CGPoint(x: 16.11, y: 74.46))
bezierPath.addCurve(to: CGPoint(x: 55.03, y: 114.4), controlPoint1: CGPoint(x: 16.11, y: 91.89), controlPoint2: CGPoint(x: 26.46, y: 100.29))
bezierPath.addCurve(to: CGPoint(x: 58.94, y: 115.53), controlPoint1: CGPoint(x: 56.3, y: 115.04), controlPoint2: CGPoint(x: 57.76, y: 115.53))
bezierPath.close()
return bezierPath
}()
I was able to get this very easily:
That seems to be the sort of thing you're after.
The double shadow stems from the fact that in a graphics context, shadow drawing is a state applied to any future drawing. So if you set the context's shadow to be down-and-to-the-left and draw the symbol image, and then set the context's shadow to be down-and-to-the-right and draw the symbol image, you get the double shadow.
It is true that the symbol image itself is drawn twice but that does not necessarily change the way it appears; if I hadn't told you I'd drawn it twice, I don't think you'd have known.

How to set physics body for a sprite with rounded corners

I have created a SKShapeNode in the following way,
let sprite = SKShapeNode(rect: CGRect(x: -20, y: -10, width: 40, height: 20), cornerRadius: 10)
I also set a physics body like so,
sprite.physicsBody = SKPhysicsBody(rectangleOf: sprite.frame.size)
but I realized that the collisions and contacts weren't precise, so I changed showsPhysics to true and got the following. How can I make the physics body precise, even for the rounded corners?
Remember that too much precision is very bad for performance. Read this:
https://developer.apple.com/reference/spritekit/skphysicsbody
For general cases, it would be better to ignore the corners and stick with the normal rectangle physics, unless you REALLY need that precision. If you do, you could use a SKTexture on a SKSpriteNode instead of a ShapeNode. That would be much easier, because you could simply do this:
let size = CGSize(width: 100, height: 50)
let roundedRectangleTexture = SKTexture(image: UIImage(named: "textureImage")!)
let mySpriteNode = SKSpriteNode(texture: roundedRectangleTexture, size: size)
mySpriteNode.physicsBody = SKPhysicsBody(texture: roundedRectangleTexture, size: size)
With a texture, you can easily make a more detailed and precise physicsBody by simply using the SKPhysicsBody(texture: size:) constructor.
From the documentation:
Maybe the #4 is your case
let spaceShipTexture = SKTexture(imageNamed: "spaceShip.png")
Spaceship 1: circular physics body
let circularSpaceShip = SKSpriteNode(texture: spaceShipTexture)
circularSpaceShip.physicsBody = SKPhysicsBody(circleOfRadius: max(circularSpaceShip.size.width / 2,
circularSpaceShip.size.height / 2))
Spaceship 2: rectangular physics body
let rectangularSpaceShip = SKSpriteNode(texture: spaceShipTexture)
rectangularSpaceShip.physicsBody = SKPhysicsBody(rectangleOf: CGSize(width: circularSpaceShip.size.width,
height: circularSpaceShip.size.height))
Spaceship 3: polygonal physics body
let polygonalSpaceShip = SKSpriteNode(texture: spaceShipTexture)
let path = CGMutablePath()
path.addLines(between: [CGPoint(x: -5, y: 37), CGPoint(x: 5, y: 37), CGPoint(x: 10, y: 20),
CGPoint(x: 56, y: -5), CGPoint(x: 37, y: -35), CGPoint(x: 15, y: -30),
CGPoint(x: 12, y: -37), CGPoint(x: -12, y: -37), CGPoint(x: -15, y: -30),
CGPoint(x: -37, y: -35), CGPoint(x: -56, y: -5), CGPoint(x: -10, y: 20),
CGPoint(x: -5, y: 37)])
path.closeSubpath()
polygonalSpaceShip.physicsBody = SKPhysicsBody(polygonFrom: path)
Spaceship 4: physics body using texture’s alpha channel
let texturedSpaceShip = SKSpriteNode(texture: spaceShipTexture)
texturedSpaceShip.physicsBody = SKPhysicsBody(texture: spaceShipTexture,
size: CGSize(width: circularSpaceShip.size.width,
height: circularSpaceShip.size.height))
I would follow the documentation of SKPhysicsBody, and create a polygonal shape that approximates the rounded corners of your sprite.
An example on the documentation shows that you can define a polygonal physics body like so:
// Spaceship 3: polygonal physics body
let polygonalSpaceShip = SKSpriteNode(texture: spaceShipTexture)
let path = CGMutablePath()
path.addLines(between: [CGPoint(x: -5, y: 37), CGPoint(x: 5, y: 37), CGPoint(x: 10, y: 20),
CGPoint(x: 56, y: -5), CGPoint(x: 37, y: -35), CGPoint(x: 15, y: -30),
CGPoint(x: 12, y: -37), CGPoint(x: -12, y: -37), CGPoint(x: -15, y: -30),
CGPoint(x: -37, y: -35), CGPoint(x: -56, y: -5), CGPoint(x: -10, y: 20),
CGPoint(x: -5, y: 37)])
path.closeSubpath()
polygonalSpaceShip.physicsBody = SKPhysicsBody(polygonFrom: path)