I tried to move sprites move randomly on screen but the sprite move once time to random position and stop to move
Here I call to make shapes func with timer
//Make shape Timer
func makeshapetimer () {
maketimer = Timer.scheduledTimer(timeInterval: 3.0, target: self, selector: #selector(makerandomShape), userInfo: nil, repeats: true)
}
//Make random shape
func makerandomShape () {
//Check if have more than 12 shapes
if shapesamount <= 12 {
let sprite = shape.copy() as! SKShapeNode
sprite.name = "Shpae \(shapesamount)"
sprite.position = CGPoint(x: frame.minX - sprite.frame.width, y: frame.maxY)
shapes.addChild(sprite)
shapesamount += 1
moveRandom(node: sprite)
}
}
And here I make a random position action and repeat the action forever but is run only once time per shape
//Move shape radmonly
func moveRandom (node: SKShapeNode) {
move = SKAction.move(to: CGPoint(x: CGFloat.random(min: frame.minX, max: frame.maxX), y: CGFloat.random(min: frame.minY, max: frame.maxY)), duration: shapespeed)
node.run(SKAction.repeatForever(move))
}
Your moveRandom function is called only once per sprite.
Here's what you tell it to do:
get a random x,y position --- let's say it got 120,200
move to 120,200 --- and repeat moving to 120,200 forever
So, the sprite dutifully moves to that random position, and keeps moving to that position. It never goes back to its starting point, and it never gets a new position to move to.
If you want the sprites to keep moving to new random positions, you need to create a new random position each time the current move finishes.
Related
How can I set up background animations only once and make them move forever?
I'm developing a game using iOS Swift and SpriteKit. I have a lot of background nodes in my game, like clouds, mountains, etc.
Currently I'm moving clouds around the scene like this. This code is in the override func update:
if self.cloud01.position.x < 0 - self.cloud01.size.width {
self.cloud01.position.x = self.frame.size.width + (self.cloud01.size.width / 2)
} else {
self.cloud01.position.x -= 0.5
}
Whenever the cloud moves out of the scene (left side) it will be reset to the right side and move again.
I want to take all these if-statements out of the update function and set them up only once. I've tried this:
//This is in my didMoveToView
runAction(SKAction.repeatActionForever(SKAction.runBlock(backgroundAnimations)))
//It calls this function
func backgroundAnimations() {
if self.cloud01.position.x < 0 - self.cloud01.size.width {
self.cloud01.position.x = self.frame.size.width + (self.cloud01.size.width / 2)
} else {
self.cloud01.position.x -= 0.5
}
}
How can I set up background animations only once and make them move forever?
Thanks!
You can use SKActions. Simply add this line when you initialize your clouds.
world - your clouds parentNode (probably you need to replace with self)
runAction(SKAction.repeatActionForever(SKAction.sequence([
SKAction.moveByX(-world.frame.size.width , y: 0, duration: 10.0),
SKAction.moveByX(world.frame.size.width , y: 0, duration: 0),
])))
I'm trying to move an object over a period of ten seconds from y coordinate 0 to y coordinate 10. the object is created at y coordinate 0. The problem is when the animation starts, the object pops to the end position for like one second or so then pops back down to the starting position and begins the animation properly. Why is the object moving to the end location instantly, and how can I prevent this from happening?
//create box bottom
func createGrabBox() {
grabbottom = grabBox.rootNode.childNodeWithName("grabbottom", recursively: true)!
grabbottom.position.y = 0
grabbottom.geometry!.firstMaterial!.transparency = 0.5
grabbottom.physicsBody = SCNPhysicsBody(type: SCNPhysicsBodyType.Dynamic, shape: nil)
scene.rootNode.addChildNode(grabbottom)
//animation snippet
SCNTransaction.begin()
SCNTransaction.setAnimationDuration(10.0)
SCNTransaction.setCompletionBlock() { }
grabbottom.position.y = 10
SCNTransaction.commit()
}
You can't manipulate the position of a dynamic body. Use a kinematic body for that.
I have a function in SpriteKit that spawns a sprite (which is a square) at the top of the screen, and then gravity pulls the sprite to the bottom of the screen. I'm trying to get the sprite to rotate smoothly for an indefinite amount of time until it is removed when it reaches the bottom of the screen. The following code is in the class for the sprite:
func rotate() {
var action = SKAction.rotateByAngle(CGFloat(M_PI_2), duration: NSTimeInterval(1.5))
var repeatAction = SKAction.repeatActionForever(action)
self.runAction(repeatAction)
}
The problem that I am having is that, as the sprite turns, the sprite travels in the direction of the bottom of itself, not towards the bottom of the screen (the direction gravity is supposed to be). To further clarify, the object rotates, but as it rotates to 90 degrees, it travels sideways instead of downwards. This doesn't make sense to me. This is the code I'm using to add gravity in the didMoveToView() function:
self.physicsWorld.gravity = CGVectorMake(0.0, -1.8)
and this is the code used to spawn the sprite (the rs.rotate() calls the rotate method that is listed above):
func spawnRedSquares() {
if !self.gameOver {
let rs = RedSquare()
var rsSpawnRange = randomNumberBetween(self.leftSideBar.position.x + rs.sprite.size.width / 2, secondNum: self.rightSideBar.position.x - rs.sprite.size.width / 2)
rs.position = CGPointMake(rsSpawnRange, CGRectGetMaxY(self.frame) + rs.sprite.size.height * 2)
rs.zPosition = 3
self.addChild(rs)
self.rsArray.append(rs)
rs.rotate()
let spawn = SKAction.runBlock(self.spawnRedSquares)
let delay = SKAction.waitForDuration(NSTimeInterval(timeBetweenRedSquares))
let spawnThenDelay = SKAction.sequence([delay, spawn])
self.runAction(spawnThenDelay)
}
}
How can I get the object to rotate, but still fall down as if it were affected by normal gravity?
It looks like you are adding the rotation action to 'self' which I would assume is your scene as opposed to your sprite. This is causing the entire scene to rotate, and therefore its gravity is rotating as well.
Add the rotating action to your sprite and that should solve the issue.
Example: assuming your square sprite is called squareSprite:
let action = SKAction.rotateByAngle(CGFloat(M_PI_2), duration: NSTimeInterval(2))
let repeatAction = SKAction.repeatActionForever(action)
squareSprite.runAction(repeatAction) //Add the repeatAction to your square sprite
I am building my first iPhone game using Xcode, SpriteKit and Swift. I am new to these technologies but I am familiar with general programming concepts.
Here is what I am trying to do in English. I want circles to randomly appear on the screen and then begin to expand in size. However, I do not want a circle to appear in a location where a circle currently exists. I am having trouble determining each circle's position.
Inside GameScene.swift I have the following code inside the didMoveToView:
runAction(SKAction.repeatActionForever(
SKAction.sequence([
SKAction.runBlock(addCircle), SKAction.waitForDuration(3, withRange: 2)]
)))
The piece of code above calls my "addCircle" method:
func addCircle() {
// Create sprite.
let circle = SKSpriteNode(imageNamed: "grad640x640_circle")
circle.name = "circle"
circle.xScale = 0.1
circle.yScale = 0.1
// Determine where to position the circle.
let posX = random(min: 50, max: 270)
let posY = random(min: 50, max: 518)
// ***Check to see if position is currently occupied by another circle here.
circle.position = CGPoint(x: posX, y: posY)
// Add circle to the scene.
addChild(circle)
// Expand the circle.
let expand = SKAction.scaleBy(2, duration: 0.5)
circle.runAction(expand)
}
The random function above just chooses a random number within the given range. How can I check to see if my random functions are generating a location that is currently occupied by another circle?
I was thinking of using a do..while loop to randomly generate a set of x and y coordinates and then check to see if a circle is at that location but I cannot find how to check for that condition. Any help would be greatly appreciated.
There are a few methods which can help you in this regard:
(BOOL) intersectsNode: (SKNode*)node, available with SKNode, and
CGRectContainsPoint() as well as the CGRectContainsRect() methods.
For instance the loop to check for intersection can look as follows:
var point: CGPoint
var exit:Bool = false
while (!exit) {
let posX = random(min: 50, max: 270)
let posY = random(min: 50, max: 518)
point = CGPoint(x: posX, y: posY)
var pointFound: Bool = true
self.enumerateChildNodesWithName("circle", usingBlock: {
node, stop in
let sprite:SKSpriteNode = node as SKSpriteNode
if (CGRectContainsPoint(sprite.frame, point))
{
pointFound = false
stop.memory = true
}
})
if (pointFound)
{
exit = true
}
}
//point contains CGPoint where no other circle exists
//Declare new circle at point
I have a sprite that move to the left, with animations of the character moving left. Then it waits and start moving right, with animations moving right.
The animations of moving left is a series of images that are shown over and over, so it should repeat endlessly, but when the character stops moving Left. It should change to animateRight and show these images over and over endlessly.
I am not quite sure how to do this.
// move left, then stop, then turn, move right, and repeat
let moveLeft = SKAction.moveToX(leftPosition, duration: NSTimeInterval(length * 3))
let wait = SKAction.waitForDuration(0.3)
let moveRight = SKAction.moveToX(xPos, duration: NSTimeInterval(length * 3))
// the animation of moving left should repeat (same series of images is shown over and over)
// but when moveLeft is done after a certain time is should stop
// it should maybe not be repeat action forever, but repeat for "duration: NSTimeInterval(length * 3))
// like move left, but can't find that method..
let animateLeft = SKAction.repeatActionForever(animationMovingLeft)
let animateRight = SKAction.repeatActionForever(animationMovingRight)
let groupActionsLeft = SKAction.group([animateLeft, moveLeft])
let groupActionsRight = SKAction.group([animateRight, moveRight])
// problem here, the groupActionsLeft runs forever, the animateLeft should stop at the same time
// as moveLeft
let sequence = SKAction.sequence([groupActionsLeft, wait, groupActionsRight, wait])
let repeatSequence = SKAction.repeatActionForever(sequence)
//sprite.runAction(animate, withKey: "snailAnimation")
sprite.runAction(repeatSequence, withKey: "snailMovement")
The following animates in one direction only (left in this case) and flips the sprite horizontally (by setting the sprite's xScale to -1), so it animates in the other direction when moving right.
// move left, then stop, then turn, move right, and repeat
let moveLeft = SKAction.moveToX(leftPosition, duration: NSTimeInterval(length * 3))
let wait = SKAction.waitForDuration(0.3)
let moveRight = SKAction.moveToX(xPos, duration: NSTimeInterval(length * 3))
let faceLeft = SKAction.scaleXTo(1.0, duration: 0)
// Setting the xScale to -1 will flip sprite horizontally
let faceRight = SKAction.scaleXTo(-1.0, duration: 0)
// like move left, but can't find that method..
let animateLeft = SKAction.repeatActionForever(animationMovingLeft)
// Animate in one direction only
sprite.runAction(animateLeft)
let groupActionsLeft = SKAction.group([faceLeft, moveLeft])
let groupActionsRight = SKAction.group([faceRight, moveRight])
let sequence = SKAction.sequence([groupActionsLeft, wait, groupActionsRight, wait])
let repeatSequence = SKAction.repeatActionForever(sequence)
//sprite.runAction(animate, withKey: "snailAnimation")
sprite.runAction(repeatSequence, withKey: "snailMovement")