I would like my buttons to fade in when changing scene rather than just be their.
I am using sprite kit and UIView.animateWithDuration doesn't work.
How else could you do it using sprite kit in swift?
I'm assuming you are using UIButtons, and you really shouldn't, use only SKNodes (Sprites, Shapes, Labels, etc) and the methods of touch handle like:
touchBegan:
touchMoved:
TouchEnded:
If you want to build a button or a switch for generic use, you should try this control I made, the use its pretty straight forward:
You just initialize the type of Button/Switch you want (ColoredSprite, Textured or TextOnly)
let control = TWButton(normalColor: SKColor.blueColor(), highlightedColor: SKColor.redColor(), size: CGSize(width: 160, height: 80))`
And after initialize you add a closure to it (like addTargetForSelector on UIButton)
control.addClosureFor(.TouchUpInside, target: self, closure: { (scene, sender) -> () in
scene.testProperty = "Changed Property"
})
}
That’s it! There’s more info on the readme section on the GitHub page: https://github.com/txaidw/TWControls
Then you can use actions to fade your button
SKAction.fadeAlphaTo(alpha:, duration:)
Related
I am creating a game and I want to include a page control (the three dots on the bottom of the screen - I would post a picture but I need more reputation!). This is so the user knows what page they are on while they are flicking through the scenes.
I have created my game using SpriteKit and I was wondering if there is a way to add this programtically (without the use of story boards).
In an iOS Game template Playground I was able to achieve this with the following code (first two lines are from the template, the rest is my addition):
// Load the SKScene from 'GameScene.sks'
let sceneView = SKView(frame: CGRect(x:0 , y:0, width: 640, height: 480))
let pageControl = UIPageControl()
pageControl.translatesAutoresizingMaskIntoConstraints = false
pageControl.numberOfPages = 3
pageControl.currentPage = 1
sceneView.addSubview(pageControl)
// Centre the control left-to-right
pageControl.centerXAnchor.constraint(equalTo: sceneView.centerXAnchor).isActive = true
// Place the control 20 points up from the bottom edge
pageControl.bottomAnchor.constraint(equalTo: sceneView.bottomAnchor, constant: -20).isActive = true
To be notified of interaction with the UIPageControl, register a handler for the event:
pageControl.addTarget(thing, action: #selector(Thing.handlePagingEvent), for: .valueChanged)
(Where thing is of type Thing - your app structure will determine which object that should logically be)
This assumes you have a single SKView in which you present one of three SKScenes. If you actually have a UIScrollView containing three SKViews, then look to UIScrollView.indicatorStyle instead.
I am creating a SpriteKit game and want to be able to take advantage of textAlerts - like all the games I grew up playing. I also want them to be flexible so I can subclass them and add them throughout my game - I am not sure how to do this and so would be very grateful of any advice.
There are a number of ways that I have started to look into:
Use another SKScene
The idea here would be to add another scene immediately on top of our current one. This would have a faded out background and would be configured with the text to be displayed. This seems like the wrong approach
Use an SKNode
I could create a custom node and initialise it with my specific text. I would then disable movement and add the node at the bottom of the screen. I would then customise the actions that occur when it is tapped.
Use an SKLabel
SKLabels are designed to show text so these seem like a promising place to look. The issue is that I want to add an image into the popup view (this a headshot of the person you are talking to) and so it doesn't feel like I should be able to inject an image in.
Use something else
I don't know what this might be. Is what I am trying to do easy or harder than I think?
My problem is that I come from a swift background so am struggling to convert to a SpriteKit mindset. In Swift I would put together a custom UIView with all the UIKit components and add it to the screen. In SpriteKit we don't have the same tools so I don't know the right combinations to put together what I want.
Ideally I want to be able to configure the text popup with an array of text so that a conversation can be had with the user tapping for each new line.
Edit 1: What I have tried so far
Based on #ElTomatos comment I have experimented with adding a SKSpriteNode and an SKLabelNode on top of each other using the following code:
guard let camera = camera else { return }
let dialogueBackground = SKSpriteNode(texture: nil, color: .red, size: CGSize(width: screenSize.width / camera.xScale, height: screenSize.height / 3 / camera.xScale))
dialogueBackground.anchorPoint = CGPoint(x: 0, y: 0)
dialogueBackground.zPosition = 50
dialogueBackground.position = CGPoint(x: -screenSize.width, y: -screenSize.height)
camera.addChild(dialogueBackground)
let label = SKLabelNode(text: "Hello world")
label.zPosition = 100
label.position = CGPoint(x: -screenSize.width, y: 100 - screenSize.height)
camera.addChild(label)
As you can see the view doesn't go to the edge of the screen. Is this something to do with the safe area? It's difficult to get the width and height as the camera doesn't have a CGSize we can use.
I have a short line (MKPolyline) and a custom annotation class (MKPointAnnotaion). Right now I have the point annotation located at the midpoint of the polyline. However, I would like the callout to be displayed whenever any point on the polyline is touched, similar to how routing performs in Maps. Since polylines don't seem to have a touchable attribute like annotations, is there a way to have the annotation encompass the entire line?
I do not care about the annotations marker (it is actually a nuisance and would prefer to hide it), only the callout and associated class info.
If at all possible could someone provide a brief example code with the answer?
EDIT: Other posts seem to be from 5+ years ago with links that do not work anymore
A couple of thoughts:
I think your “add annotation” approach for where you want this callout to start from is going to be the easiest approach. If you start contemplating making an annotation view subclass that shows the path, I think that’s going to get pretty hairy pretty quickly (handling scaling changes, rotations, 3D, etc.). Overlays give you a bunch of behaviors for free, so I think you’ll want to stick with that. And annotations give you callout behaviors for free, too, so I think you’ll want to stay with that too.
If you don’t want your annotation view to show a pin/marker, just don’t subclass from MKPinAnnotationView or MKMarkerAnnotationView, but rather just use MKAnnotationView.
The tricky step is how to detect taps on the MKPolylineRenderer. One idea is to create a path that traces the outline of the path of the MKPolyline.
extension MKPolyline {
func contains(point: CGPoint, strokeWidth: CGFloat = 44, in mapView: MKMapView) -> Bool {
guard pointCount > 1 else { return false }
let path = UIBezierPath()
path.move(to: mapView.convert(from: points()[0]))
for i in 1 ..< pointCount {
path.addLine(to: mapView.convert(from: points()[i]))
}
let outline = path.cgPath.copy(strokingWithWidth: strokeWidth, lineCap: .round, lineJoin: .round, miterLimit: 0)
return outline.contains(point)
}
}
where
extension MKMapView {
func convert(from mapPoint: MKMapPoint) -> CGPoint {
return convert(mapPoint.coordinate, toPointTo: self)
}
}
You can then create a gesture recognizer that detects a tap, checks to see if it’s within this path that outlines the MKPolyline, or whatever. But these are the basic pieces of the solution.
Obviously, the answers here outline different, apparently looking at the distance to the paths. That conceivably would work, too.
I am transferring an app for iOS to a toolbar app in OSX. Although I am using swift, the objects are rather different. I am having one major problem, however, that I cannot seem to overcome.
The code below produces the NSButton shown, but I cannot get rid of the grey background. masktobound has no effect. I have tried masking each corner individually, no effect. I just want a simple round button.
I also have several buttons with rounded corners, however these also show the light grey background.
Any pointers? Sample code would be appreciated.
let connectButton = NSButton.init(title: NSLocalizedString(" ", comment: "OnButtonAccessibility"), target: self, action: #selector(toggle))
connectButton.wantsLayer = true
connectButton.isBordered = false
connectButton.layer?.masksToBounds=true
if #available(OSX 10.13, *) {
connectButton.layer?.maskedCorners=[.layerMaxXMaxYCorner]
} else {
connectButton.layer?.backgroundColor = NSColor.blue.cgColor
connectButton.layer?.cornerRadius=80
connectButton.layer?.borderColor=DarkerBlue.cgColor
connectButton.layer?.borderWidth=3
(connectButton.cell as! NSButtonCell).isBordered=false
(connectButton.cell as! NSButtonCell).backgroundColor=NSColor.clear
connectButton.isTransparent=true
connectButton.frame=CGRect(x: 80, y: self.view.frame.size.height-260, width: 160, height: 160)
connectButton.tag=1002
self.view.addSubview(connectButton)
It appears that you must at least touch the NSButton.cell to have it conform to the button style. The backgroundstyle used seems to make no difference is you have the button filled or containing an image.
connectButton.cell?.backgroundStyle=NSView.BackgroundStyle.dark
I have a problem with SpriteKit and Swift.
I'm adding SKSpriteNodes at different points of the code to the scene - some of them are clickable, some are not. I use the clickable Nodes as a Menu for the player. So, for example - if he clicks the InventoryButtonNode he jumps into the Inventory. In the Inventory he can touch the PlayButton and jumps back into the game. So, first i add the Nodes:
override func didMoveToView(view: SKView) {
PlayButton = SKSpriteNode(imageNamed: "PlayButton")
PlayButton.size = CGSize(width: 100, height: 100)
PlayButton.position = CGPoint ... // not important
PlayButton.zPosition = 200
PlayButton.name = "PlayButton"
self.addChild(PlayButton)
InventoryButton = SKSpriteNode(imageNamed: "InventoryButton")
InventoryButton.size = CGSize(width: 100, height: 100)
InventoryButton.position = CGPoint ... // different position than PlayButton
InventoryButton.zPosition = 200
InventoryButton.name = "PlayButton"
self.addChild(InventoryButton)
In the override func touchesBegan I use these "menu"-Nodes, here for example the InventoryButton-Node.
if InventoryButton.containsPoint(touch.locationInNode(self)) {
print("Show Inventory")
ShowInventory()
}
Now in the ShowInventory() function i want to remove those "menu"-Buttons from view so that i can add other nodes to show the Inventory of the Player.
func ShowInventory(){
PlayButton.removeFromParent()
InventoryButton.removeFromParent()
}
If I build and run this, the Nodes will be removed - or lets better say - they will get invisible.
Because, if i touch now at the position of InventoryButton I still get the print "Show Inventory" - so the function still reacts to my touch even if the node is not visible.
My problem is, that i have like 4 different functions like ShowInventory() .. I have ShowGame() and so on .. and i want in these functions to completely remove the Nodes and the "Touch"-Ability ..
I need a function which can remove the Nodes completely ..
I have even tried:
func ShowInventory(){
self.removeAllChildren()
}
I get a grey Background without any nodes .. but still - if I touch where the Inventory Buttons position was i get the function called and the print "Show Inventory" ... it's frustrating.
It is because your check for which button is pressed does not take into account whether the button is visible.
Even if a node has been removed from its parent, it still has a position and size. Those two properties are used by containsPoint: to determine if a point is in a node
The easiest way to fix it would be to just check if the button has a parent node before checking to see if the button contains the point.
if InventoryButton.parrent != nil && InventoryButton.containsPoint(touch.locationInNode(self)) {
print("Show Inventory")
ShowInventory()
}