Draw a circular SKSpriteNode with texture? - swift

Is there a way to draw a circular SKSpriteNode with texture? Or alternatively, draw a SKShapeNode with texture?

It is to consider that all images are rectangle/squares. What we see as round, is how we show colored pixels: what is outside the circle, is transparent and what is inside, is the colored part.
we need a circle
we texture it
we add it to the scene
we take back a new texture from this shape node that we just added to the scene
we make a new sprite using this new texture
we add the sprite to the scene
let shape: SKShapeNode = SKShapeNode(circleOfRadius: 50)
shape.name = "shape"
shape.lineWidth = 1 // this way we see that this is a circle
shape.fillColor = .white // to see the true colors of our image
//shape.strokeColor = .white
//shape.glowWidth = 0
shape.fillTexture = SKTexture(imageNamed:"myImage")
shape.position = CGPoint(x: 0, y:200)
self.addChild(shape)
let newTexture: SKTexture = (self.view?.texture(from: self.childNode(withName: "shape")!))!
let sprite: SKSpriteNode = SKSpriteNode(texture: newTexture)
self.addChild(sprite)
shape.removeFromParent()

Related

Combining 3D and 2D in macOS

I need to draw 2D legends, 2D frame, etc. on top of a 3D scene. Here, I am trying to display a 2D label on top of a 3D sphere, so that the label will always face the user, even if they rotate the scene.
I am using a SCNView to draw the 3D scene (=> works fine)
I am using its NSView parent (subclassed to override its draw function) to display the 2D text (=> nothing is displayed)
(var twoDCoordinates:CGPoint is extern)
in my viewController:
#IBOutlet weak var sceneView: SCNView!
func sceneSetup() {
let scene = SCNScene()
// (I set the light and the camera...)
// Adding the sphere
let geometry = SCNSphere (radius: 4.0)
geometry.firstMaterial!.diffuse.contents = CGColor.red
geometry.firstMaterial!.specular.contents = CGColor.white
sphereNode = SCNNode (geometry: geometry)
sphereNode.position = SCNVector3Make(-6, 0, 0)
scene.rootNode.addChildNode (sphereNode)
sceneView.scene = scene
sceneView.allowsCameraControl = true
// compute the 2D coordinates of the text to be displayed
var q = sphereNode.position
q.x += 6.0; q.y += 6.0; q.z += 6.0 // outside of the sphere
let projected = sceneView.projectPoint (q)
twoDCoordinates = CGPoint (x: projected.x, y: projected.y)
sceneView.needsDisplay = true
}
=> The 3D sphere is correctly displayed; twoDCoordinates is correct
In TwoDView:NSView class (which is the sceneView container)
override func draw(_ dirtyRect: NSRect) {
super.draw(dirtyRect)
// Drawing code here.
let paragraphStyle = NSMutableParagraphStyle()
paragraphStyle.lineBreakMode = .byTruncatingTail
paragraphStyle.alignment = .left
let textAttributes = [
NSAttributedString.Key.font: NSFont.systemFont(ofSize: 72.0),
NSAttributedString.Key.paragraphStyle: paragraphStyle]
let label = "Sphere Label"
let size = label (withAttributes: textAttributes)
let rect = CGRect(x: twoDCoordinates.x, y: twoDCoordinates.y, width: size.width, height: size.height)
label.draw(in: rect, withAttributes: textAttributes)
}
=> the function draw is called, but no text is displayed.
I expect the text "Sphere label" to be displayed next to the 3D sphere, but only the 3D scene is displayed., even though function draw is called.

Best way to create a drawing app which can use images as fill

I'm trying to create a section of an app where the user can draw freestyle shapes and fill these shapes with an image.
I have tried using UIBezierPaths and CAShapeLayers, and have been able to create a drawing app which fills all images with a single colour.
I want each shape to be able to be filled with a different colour, so eventually the individual shapes can be filled with separate images.
I'm having trouble separating each drawing so they can be filled individually, and have so far been unable to fill a drawing with an image.
If anyone has suggestions of other ways I could go about doing this, I would appreciate any ideas!
Have you thought about maybe using SpriteKit for the drawing portion of your app? Using Spritekit you can create your shapes using SKShapeNode and fill them with different colors using the fillColor property of SKShapeNode. For filling the newly create shape with an image you can place your image in an SKSpriteNode then crop it using SKCropNode and set the maskNode property of SKCropNode to the SKShapeNode you created.
Eample:
import UIKit
import SpriteKit
class DrawView: SKScene {
override func didMoveToView(view: SKView) {
scaleMode = .ResizeFill
backgroundColor = UIColor.whiteColor()
//creating a triangle and filling it with the color blue
let path = CGPathCreateMutable()
CGPathAddArc(path, nil, 160, 284, 0, 0, CGFloat(M_PI*2), true)
CGPathAddLineToPoint(path, nill, 60, 184)
CGPathAddLineToPoint(path, nill, 260, 184)
CGPathAddLineToPoint(path, nill, 60, 284)
let triangle = SKShapeNode()
triangle.lineCap = .Round
triangle.lineJoin = .Round
triangle.fillColor = UIColor.blueColor()
triangle.path = path
addChild(triangle)
//placing image into SKSpriteNode
let image = SKSpriteNode(imageNamed: "yourImage")
image.size = CGSizeMake(320, 568)
image.position = CGPointMake(160, 284)
//creating an SKCropNode
let imageCrop = SKCropNode()
imageCrop.position = CGPointMake(0, 0)
imageCrop.addChild(image) //adding image to the SKCropNode
imageCrop.maskNode = triangle //using the triangle created as a mask
addChild(imageCrop)
}
}
class ViewController: UIViewController {
override func viewDidLoad() {
//create spritekit scene
let skView = SKView(frame: CGRectMake(0, 0, self.view.bounds.size.width, self.view.bounds.size.height))
skView.center = CGPointMake(self.view.bounds.size.width/2, self.view.bounds.size.height/2)
self.view.addSubview(skView)
//add drawing view to the scene
let drawView = DrawView()
sKView.presentScene(drawView)
}
}
The tricky part is going to be repositioning the SKSpriteNode and SKCropNode to fill the SKShapeNode.

Changing color of Ball Type in swift 2

I am trying to fill my ball in my swift game with two colors> I want them to be half white and half blue. I have tried changed the ball to a SKSpriteNode but it ruins the whole project and all of the physics. Is there anyway to make a Ball type two colors or place an image over the ball? thanks
Instead of use SKSpriteNode, try to use SKShapeNode:
let textureBall : SKTexture! = SKTexture(imageNamed:"ball.png")
let ballSize: CGSize = textureBall.size
ball = SKShapeNode.init(circleOfRadius: ballSize.width/2)
ball.fillTexture = textureBall
ball.strokeColor = UIColor.clearColor()
ball.position = CGPointMake(CGRectGetMidX(self.frame),CGRectGetMidY(self.frame))
ball.name = "ball"
ball.zPosition = 1
ball.fillColor = UIColor.redColor() // use the color you want
self.addChild(ball)

Rotate a SKShapeNode with texture

I'm trying to rotate an SKShapeNode with a texture, but it's not working. Basically, I have a circle with a texture and I'm trying to make it rotate using the same way I have done with an SKSpriteNode:
let spin = SKAction.rotateByAngle(CGFloat(M_PI/4.0), duration: 1)
The problem is that the circle is rotating, but not the texture. I can check this by using this code:
let wait = SKAction.waitForDuration(0.5)
let block = SKAction.runBlock({
print(self.circle.zRotation)
})
let sequence = SKAction.sequence([wait, block])
self.runAction(SKAction.repeatActionForever(sequence))
This is the code I have for creating the SKShapeNode:
let tex:SKTexture = SKTexture(image: image)
let circle = SKShapeNode(circleOfRadius: 100 )
circle.position = CGPoint(x: self.frame.width / 2, y: self.frame.height / 2 + 200)
circle.strokeColor = SKColor.clearColor()
circle.glowWidth = 1.0
circle.fillColor = SKColor.whiteColor()
circle.fillTexture = tex
self.addChild(circle)
// Runing the action
circle.runAction(spin)
Please help. Thanks in advance!
PS: I know that using an SKSpriteNode would be better but my goal is to place a square image in a circular frame and I figured that using an SKShapeNode would be perfect. If anyone know how to create a circular SKSpriteNode, feel free to post it in the answers section! :)
This is what I'm trying to achieve (with the capability of rotating it):
You can achieve what you want by using SKCropNode and setting its mask property to be a circle texture:
override func didMoveToView(view: SKView) {
let maskShapeTexture = SKTexture(imageNamed: "circle")
let texture = SKTexture(imageNamed: "pictureToMask")
let pictureToMask = SKSpriteNode(texture: texture, size: texture.size())
let mask = SKSpriteNode(texture: maskShapeTexture) //make a circular mask
let cropNode = SKCropNode()
cropNode.maskNode = mask
cropNode.addChild(pictureToMask)
cropNode.position = CGPoint(x: frame.midX, y: frame.midY)
addChild(cropNode)
}
Let's say that picture to mask has a size of 300x300 pixels. The circle you are using as a mask, in that case, has to have the same size. Means the circle itself has to have a radius of 150 pixels (diameter of 300 pixels) when made in image editor.
Mask node determines the visible area of a picture. So don't make it too large. Mask node has to be a fully opaque circle with transparent background.

Swift. Masking a SKTexture on top of a SKSpriteNode

Okay so I have som problems, trying to mask a SKTexture on top op a SKSpriteNode. I've been looking in to SKCropNode, but cant figure it out.
(I'm kinda new to this)
How can i mask this SKTexture: (This is the image called "Mask")
on top of this SKSpriteNode:
so its going to turn out like this:
I tried this, but nothing showed up:
picture.size = CGSize(width: menuLine.frame.height, height: menuLine.frame.height)
picture.zPosition = 10
let cropNode = SKCropNode()
cropNode.addChild(picture)
cropNode.maskNode = SKSpriteNode(imageNamed("Mask")
self.addChild(cropNode)
cropNode.position = CGPoint(x: CGRectGetMidX(self.frame), y: CGRectGetMidY(self.frame))
cropNode.zPosition = 10