In SpriteKit you are able to enumerate through each node with a specific name. Say I have 10 sprites with the name property set to "foo" I can then run the code below and it will move each "food" node up 5 pixels every time the function is called.
enumerateChildNodesWithName("foo"){node, stop in
let sprite:SKSpriteNode = node as! SKSpriteNode
sprite.position.x += 5
}
Now, I would like to do this with UIImageView (if possible).
Here's my current setup
In my app I have code that runs every second. It is supposed to add a UIImageView using the following code
var mView:UIImageView = UIImageView(image: UIImage(named: "swirl"))
self.view.addSubview(mView)
Finally, I have a for loop that doesn't seem to be targeting each specific view. But it should be moving each individual image view in a circle. Currently it only looks like a single image is moving even while I think I've added more image views.
for view in self.view.subviews as [UIView] {
if let ind = view as? UIImageView {
let OrCe:CGPoint = mView.center
mView.center = CGPoint(x: OrCe.x + sin(tick)*50,
y: OrCe.y + cos(tick)*50)
}
}
I feel like what I'm doing is really wrong :( Is it possible for me to do what I am trying to do? I would like to do this so that I do not have to use SpriteKit. I want to try and create graphics at a lower level framework. Can I go lower then this even? How can I most efficiently render these 10 moving images?
I assume all the two peaces are consecutive.
var mView:UIImageView = UIImageView(image: UIImage(named: "swirl"))
self.view.addSubview(mView)
for view in self.view.subviews as [UIView] {
if let ind = view as? UIImageView {
let OrCe:CGPoint = view.center
view.center = CGPoint(x: OrCe.x + sin(tick)*50,
y: OrCe.y + cos(tick)*50)
}
}
If got you correct this should work.
Related
I have 2 UIImageViews in a ViewController and I'm trying to work out when they intersect.
imageViewA: is in my storyboard view, with constraints, and is in a hierarchy of views as follows:
- Background
-- Images
--- imageViewA
imageViewB: is created dynamically and is dragged around the screen using a UIPanGestureRecognizer.
When the drag ends, I want to check if imageViewB intersects with imageViewB. I used the intersects function, but don't get the results I expect, I suppose because imageViewA is in a hierachy of views, which means it's in a different coordinate system. So I want to convert both views to the same coordinate system. How I can do this?
I've tried the following:
let frameA = imageViewA.convert(imageViewA.frame, to: self.view)
let frameB = imageViewB.convert(imageViewB.frame, to: self.view)
But it doesn't give me the results I expect, which frameB having a much larger Y coordinate.
Do I need to do something like this:
let frameA = imageViewA.superview?.superview?.convert(imageViewA.superview?.superview?.frame, to: self.view)
There are other questions covering conversion to coordinate systems, but they don't seem to tackle what to do when the view is in a hierarchy.
Your problem is that imageViewA.frame is in the geometry (coordinate system) of imageViewA.superview, but UIView.convert(_ rect: to view:) expects rect to be in the geometry of imageViewA.
UPDATE
The simplest solution is to convert imageViewA.bounds (which is in imageViewA's geometry) directly to imageViewB's geometry, and then see if it intersects imageViewB.bounds, which is also in imageViewB's geometry:
let aInB = imageViewA.convert(imageViewA.bounds, to: imageViewB)
if aInB.intersects(imageViewB.bounds) {
...
ORIGINAL
The simplest solution is to convert imageViewA.bounds, which is in imageViewA's own geometry:
let frameA = imageViewA.convert(imageViewA.bounds, to: self.view)
let frameB = imageViewB.convert(imageViewB.bounds, to: self.view)
I misunderstood the convert function. Just in case it's useful for anyone else, the solution looks like this:
let convertedFrameB = frameA.superview?.convert(frameA.frame, from self.view)
if(convertedFrameB.intersects(frameA.frame) {...
...
}
Here's an extension that might be useful:
extension UIView {
func intersectsIgnoringCoordinateSpace(_ view2: UIView) -> Bool {
let frameOne = self.convert(self.bounds, to: self.topLevelView)
let frameTwo = view2.convert(self.bounds, to: self.topLevelView)
return frameOne.intersects(frameTwo)
}
var topLevelView: UIView? {
get {
var topView = self.superview
while(topView?.superview != nil) {
topView = topView?.superview
}
return topView
}
}
I am trying to make a basic game for iOS10 using swift 3 and scenekit. In one part of my games code I have a function that adds fishes to the screen, and gives each one a certain tag so i can find them later:
let fish = UIImageView(frame: CGRect(x: 0, y: 0, width: CGFloat(fishsize.0), height: CGFloat(fishsize.1)))
fish.contentMode = .scaleAspectFit
fish.center = CGPoint(x: CGFloat(fishsize.0) * -0.6, y: pos)
fish.animationImages = fImg(Fishes[j].size, front: Fishes[j].front)
fish.animationDuration = 0.7
fish.startAnimating()
fish.tag = j + 200
self.view.insertSubview(fish, belowSubview: big1)
What I would like is to be able to, at a certain point, recall the fish and
Change the images shown, and
Stop the animation.
Is this possible? I've been trying it with var fish = view.viewWithTag(killer+200)! but from this I can't seem to change any image properties of the new variable fish.
Any help would be much appreciated.
Tom
Try to cast the UIView to UIImageView like this.
if let fish = view.viewWithTag(killer+200) as? UIImageView {
//Perform your action on imageView object
}
So I am developing an Ipad app that allows the user to solve a jigsaw puzzle. I've worked out getting the panning motion for each piece, but getting them where I want to has not worked properly. I am trying to make a piece snap into it's final destination when it's within a small range, which is followed by a clicking sound.
Here is a bit of code for a single puzzle piece. When my new game button is pressed, an Image View gets set to the corresponding picture, and randomly placed on the canvas.
#IBAction func NewGameTapped(sender: UIButton){
let bounds = UIScreen.mainScreen().bounds
let height = bounds.size.height
let width = bounds.size.width
image1.image = UIImage(named:"puzzleImage1.png")
image1.center.x = CGFloat(100 + arc4random_uniform(UInt32(width)-300))
image1.center.y = CGFloat(100 + arc4random_uniform(UInt32(height)-300))
//Create Panning (Dragging) Gesture Recognizer for Image View 1
let panRecognizer1 = UIPanGestureRecognizer(target: self, action: "handlePanning1:")
// Add Panning (Dragging) Gesture Recognizer to Image View 1
image1.addGestureRecognizer(panRecognizer1)
}
This is where I am having some issues.
func handlePanning1(recognizer: UIPanGestureRecognizer) {
let center = dict1_image_coordinates["puzzleImage1"] as![Int]
let newTranslation: CGPoint = recognizer.translationInView(image1)
recognizer.view?.transform = CGAffineTransformMakeTranslation(lastTranslation1.x + newTranslation.x, lastTranslation1.y + newTranslation.y)
if recognizer.state == UIGestureRecognizerState.Ended {
lastTranslation1.x += newTranslation.x
lastTranslation1.y += newTranslation.y
}
checkPosition(image1, center: center)
}
func checkPosition(image: UIImageView, center: [Int]){
let distance: Double = sqrt(pow((Double(image.center.x) - Double(center[0])),2) + pow((Double(image.center.y) - Double(center[1])),2))
//if the distance is within range, set image to new location.
if distance <= 20{
image.center.x = CGFloat(center[0])
image.center.y = CGFloat(center[1])
AudioServicesPlaySystemSound(clickSoundID)
}
For whatever reason, the puzzle piece only wants to snap to it's spot when the piece begins the game within the acceptable snap distance. I have tried checking for the object position in various different parts of my program, but nothing has worked so far. Any help or other tips are greatly appreciated.
The issue is likely caused by this line
image1.addGestureRecognizer(panRecognizer1)
Usually people add gestureRecognizer on the parentView, or the rootView of the view controller instead of the image1 itself. The benefit is that the parentView never moves, where as the image1 is constantly being transformed, which may or may not affect the recognizer.translationInView(x) method return value.
do this instead:
self.view.addGestureRecognizer(panRecognizer1)
and change to this line in handlePanning1 function:
image1.transform = CGAffineTransformMakeTranslation(lastTranslation1.x + newTranslation.x, lastTranslation1.y + newTranslation.y)
We need to animate an object's size within GameScene.swift. Other Stack Overflow posts suggest using UIView.animateWithDuration, but this isn't available inside GameScene.swift. We need to animate inside GameScene.swift because we also need access to SKAction to run an action forever.
Right now, we are using the code below, but it is too clunky. The hope is animation will smooth out the appearance of the object as it shrinks.
runAction(SKAction.repeatActionForever(
SKAction.sequence([
SKAction.runBlock(shrinkItem),
SKAction.waitForDuration(0.5)
])
))
func shrinkItem() {
let curWidth = item.size.width
if curWidth < 15 {
return
}
item.size = CGSize( width: CGFloat(item.size.width - 20 ), height: CGFloat(bird.size.height - 20) )
}
What you are trying to do is to shrink your bird, right ? That correspond to scale it down.
Why are you doing it manually inside a runBlock ?
You might want to give a look at the SKAction Class Reference : http://goo.gl/ycPYcF.
Inside which you'll see all the possible actions, and scaleBy:duration: (or another one) might be what you're looking for.
let shrinkAction = SKAction.scaleBy(0.5, duration: 1.0)
let waitAction = SKAction.waitForDuration(0.5)
let sequenceAction = SKAction.sequence([shrinkAction, waitAction])
let repeatAction = SKAction.repeatActionForever(sequenceAction)
self.yourBirdNode.runAction(repeatAction)
Depending on what you'll do next, take note that some action are automatically reversible (through reversedAction) and some aren't.
I've been trying to learn and understand the emitter functions of CAEmitter, but I'm currently a little bit stuck. I want to add an image for the emitter and make it stop after a duration.
I've got a view that I'm using to emit some particles, and I want them to only appear emit when the view appears for around 10 seconds, then stop. I also am unsure how to attach a UI image with a png, instead of using CGrect.
Thanks for any help and advice!
import UIKit
class ParticleView: UIView {
// Only override drawRect: if you perform custom drawing.
// An empty implementation adversely affects performance during animation.
override func drawRect(rect: CGRect) {
UIGraphicsBeginImageContextWithOptions(CGSizeMake(15,8), false, 1)
let con = UIGraphicsGetCurrentContext()
CGContextAddRect(con, CGRectMake(0, 0, 15, 8))
CGContextSetFillColorWithColor(con, UIColor.whiteColor().CGColor)
CGContextFillPath(con)
let im = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
// make a cell with that image
var cell = CAEmitterCell()
cell.birthRate = 10
cell.color = UIColor(red:0.5, green:0.5, blue:0.5, alpha:1.0).CGColor
cell.redRange = 1
cell.blueRange = 1
cell.greenRange = 1
cell.lifetime = 5
cell.alphaSpeed = -1/cell.lifetime
cell.velocity = -100
cell.spinRange = 10.0
cell.scale = 1.0;
cell.scaleRange = 0.2;
cell.emissionRange = CGFloat(M_PI)/5.0
cell.contents = im.CGImage
var emit = CAEmitterLayer()
emit.emitterSize = CGSize(width: 100, height: 0)
emit.emitterPosition = CGPointMake(30,100)
emit.emitterShape = kCAEmitterLayerLine
emit.emitterMode = kCAEmitterLayerLine
emit.emitterCells = [cell]
self.layer.addSublayer(emit)
}
}
I have found a nice workaround to stop CAEmitter:
Create 2 identical view controllers with the same layout
Implement a Start and Stop button on both (to begin and end the CAEmitter)
Connect the Stop button of each view controller to each other with a “Show Detail (e.g. Replace) Segue and deselect "Animates"
When you hit “Stop” button it will make a seamless transition to the identical VC without emitter particles!! But what is really happening is that you are just switching to a replica view controller. This is not an elegant solution but it is the only reliable way that I have found to stop a CAEmitter (segue to a different VC) all of the other solutions are "buggy"
visual of how the VCs are set up