why i got this error while moving object in spritekit - swift

I am trying make a game something like Tower defense. I am adding units to my map and I want to try movepoint to another point.
My code is:
func setTheNode(position:[Int],speed:[Int]){
let moveDown1 = SKAction.moveToY(300, duration:4)
let moveRight1 = SKAction.moveToX(300, duration: 3)
let sequence = SKAction.sequence([moveDown1, moveRight1]);
self.runAction(sequence)
}
This works, however I want to read these position and durations from parameters.
When I try this way:
func setTheNode(position:[Int],speed:[Int]){
let moveDown1 = SKAction.moveToY(position[0], duration:speed[0])
let moveRight1 = SKAction.moveToY(position[1], duration:speed[1])
let sequence = SKAction.sequence([moveDown1, moveRight1]);
self.runAction(sequence)
}
I ger the error:
Cannot invoke 'moveToY' with an argument list of type '(Int, duration:
Int)'
I also tried
let moveDown1 = SKAction.moveToY(position[0] as? Int, duration:speed[0] as? Int)
And got the same error again. Could you help me on this?
Thank you.

SKAction.moveToY accept a CGFloat for Y and an NSTimeInterval for duration. Therefore you need to change position's type to [CGFloat] and speed's type to [NSTimeInterval].
There are a few other things I notice with your code:
1. I think it's a typo - you've written let moveRight1 = SKAction.moveToY in your second function. Should that be SKAction.moveToX?
2. You're using speed to represent time. That's going to give you some strange results because speed and time are inversely proportional. Therefore, with your implementation, if you increase speed it's going to take longer for your node to move...
I would recommend writing your function like so:
func setTheNode(deltaPosition dp: CGVector, times: (x: NSTimeInterval, y: NSTimeInterval)){
let moveDown1 = SKAction.moveToY(dp.dx, duration: times.x)
let moveRight1 = SKAction.moveToX(dp.dy, duration: times.y)
let sequence = SKAction.sequence([moveDown1, moveRight1]);
self.runAction(sequence)
}

Related

iOS RealityKit. Changing Entity's translation causes unexpected behaviour

I am trying to create some AR experience.
I load the Model with animations as an Entity. Lets call it a Toy.
I create an AnchorEntity.
I attach the Toy to the AnchorEntity. Up to this point everything works great.
I want the Toy to walk in random directions. And it does for the first time. Then it gets interesting, allow me to share my code:
First method uses a newly created Transform for the Toy with the modified translation x, y, to make the Toy move and that is it.
func walk(completion: #escaping () -> Void) {
guard let robot = robot else {
return
}
let currentTransform = robot.transform
guard let path = randomPath(from: currentTransform) else {
return
}
let (newTranslation , travelTime) = path
let newTransform = Transform(scale: currentTransform.scale,
rotation: currentTransform.rotation,
translation: newTranslation)
robot.move(to: newTransform, relativeTo: nil, duration: travelTime)
DispatchQueue.main.asyncAfter(deadline: .now() + travelTime + 1) {
completion()
}
}
We get that new Transform from the method below.
func randomPath(from currentTransform: Transform) -> (SIMD3<Float>, TimeInterval)? {
// Get the robot's current transform and translation
let robotTranslation = currentTransform.translation
// Generate random distances for a model to cross, relative to origin
let randomXTranslation = Float.random(in: 0.1...0.4) * [-1.0,1.0].randomElement()!
let randomZTranslation = Float.random(in: 0.1...0.4) * [-1.0,1.0].randomElement()!
// Create a translation relative to the current transform
let relativeXTranslation = robotTranslation.x + randomXTranslation
let relativeZTranslation = robotTranslation.z + randomZTranslation
// Find a path
var path = (randomXTranslation * randomXTranslation + randomZTranslation * randomZTranslation).squareRoot()
// Path only positive
if path < 0 { path = -path }
// Calculate the time of walking based on the distance and default speed
let timeOfWalking: Float = path / settings.robotSpeed
// Based on old trasnlation calculate the new one
let newTranslation: SIMD3<Float> = [relativeXTranslation,
Float(0),
relativeZTranslation]
return (newTranslation, TimeInterval(timeOfWalking))
}
The problem is that the value of Entity.transform.translation.y grows from 0 to some random value < 1. Always after the second time the walk() method is being called.
As you can see, every time the method is called, newTranslation sets the Y value to be 0. And yet the Toy's translation:
I am out of ideas any help is appreciated. I can share the whole code if needed.
I have managed to fix the issue by specifying parameter relativeTo as Toy's AnchorEntity:
toy.move(to: newTransform, relativeTo: anchorEntity, duration: travelTime)

How do I get SK sequences to run in swift

I found this pretty useful code online but I'm having trouble getting it to run. The variable names are all correct and I've used print statements to make sure it does make it to this function. It just doesn't seem to run the sequence on the Label nodes. Thanks
func fadeOutInfoText(){
infoLabel1.removeAllActions()
infoLabel2.removeAllActions()
speechIcon.removeAllActions()
let wait:SKAction = SKAction.wait(forDuration: 0.5)
let fade:SKAction = SKAction.fadeAlpha(to: 0, duration: 0.5)
let run:SKAction = SKAction.run {
self.infoLabel1.text = ""
self.infoLabel2.text = ""
self.infoLabel1.alpha = 1
self.infoLabel2.alpha = 1
self.speechIcon.alpha = 1
self.speechIcon.isHidden = true
}
let seq:SKAction = SKAction.sequence([wait,fade,run])
let seq2:SKAction = SKAction.sequence([wait,fade])
infoLabel1.run(seq)
infoLabel2.run(seq2)
speechIcon.run(seq2)
}
NOTE: This would be a comment (not enough reputation to do so yet :)
Executing the above code line-for-line (and adding in the nodes in an empty scene) gives what appears to be the desired result. Presumably you are not calling this function from the scene's update(_:) method, for this keeps the labels and speech icon from doing anything since the actions are removed before the scene performs the actions (see here). Make sure you aren't removing all actions and changing the alpha of the labels before this set of actions can complete elsewhere.
This is a sample code for Sequence.
let sprite = SKSpriteNode(imageNamed:"Spaceship")
let scale = SKAction.scale(to: 0.1, duration: 0.5)
let fade = SKAction.fadeOut(withDuration: 0.5)
let sequence = SKAction.sequence([scale, fade])
sprite.run(sequence)
Let me know it is useful or not.

SKAction with Key changes Sprite Behavior

I've been learning Swift while laid up from back surgery and any help with this is greatly appreciated.
Issue Description:
I have a function that pushes a sprite backwards when hit. When I use
self.runAction(jumpBackSequence)
I get the desired behavior. (The sprite is pushed back a good distance.)
Now when I update this to use "withKey" (because I need to be able to stop the forward action again on the next contact the forward movement is greatly dimished.
self.runAction(jumpBackSequence, withKey: "moveStraightLine")
My function creating this action is below:
func pushBack(){
self.removeActionForKey("moveStraightLine")
let height:CGFloat = 5
let jumpDistanceA:CGFloat = 20
let jumpDistanceB:CGFloat = 20
let duration:NSTimeInterval = 0.15
let jumpUp = SKAction.moveByX(0, y:height, duration:duration)
let moveBack = SKAction.moveByX(jumpDistanceA, y: 0, duration: duration)
let jStep1 = SKAction.group([jumpUp, moveBack])
let jumpDown = SKAction.moveByX(0, y:(height * -1), duration:duration)
let moveBack2 = SKAction.moveByX(jumpDistanceB, y: 0, duration: duration)
let jStep2 = SKAction.group([jumpDown, moveBack2])
let moveZombie1 = SKAction.moveToX(0, duration: spawnSpeed1() )
let removeZombie1 = SKAction.removeFromParent()
let moveAndRemoveZombie1 = SKAction.sequence([moveZombie1, removeZombie1])
let jumpBackSequence = SKAction.sequence([jStep1, jStep2, moveAndRemoveZombie1])
self.runAction(jumpBackSequence)
// self.runAction(jumpBackSequence, withKey: "moveStraightLine")
}
You are using moveTo, not moveBy, so when you add the action back in to move the zombie, you are now saying starting from the closer spot, take X seconds to move to the end, not take X seconds - the time already travelled. You do not want this due to the effect you see. Use moveBy, and the zombie speed will stay consistant
I'm not sure why this behavior happened, but I realized that the runAction withKey was actually moving the code the specified distance where as the example without the key was not. When I updated the code to use a fraction of screen width it behaves the same with and without a key - which makes me think this might actually be an minor bug in Swift.
To fix the issue I updated the distances to
let jumpDistanceA:CGFloat = (self.scene?.size.width)! * 0.15
let jumpDistanceB:CGFloat = (self.scene?.size.width)! * 0.15
I hope this helps someone else.
Best regards,
mpe

Wait For Duration Decreasing Parameter

I want to decreasing the parameter of SKAction.waitForDuration(X).
I'm using the Flappy Bird Tutorial (https://www.youtube.com/watch?v=RjUvEiNxWfc - see on minute 7) and I want to do something like
var timeToWait:Int = 8
let spawn = SKAction.runBlock({
() in
self.createWalls()
timeToWait--
})
let delay = SKAction.waitForDuration(timeToWait)
let SpawnDelay = SKAction.sequence([spawn, delay])
let spawnDelayForever = SKAction.repeatActionForever(SpawnDelay)
self.runAction(spawnDelayForever)
However, the parameter for waitForDuration is NSTimer and not a float. What could I do to change that parameter?
Thank you!
waitForDuration expects a value of type NSTimeInterval.
You can Type cast timeToWait when you pass it to the function:
let delay = SKAction.waitForDuration(NSTimeInterval(timeToWait))
By the way, your code seems to want to decrease the delay between each spawn but it will not do that because timeDelay is captured in your creation of the delay action and will not change that action's duration if you modify the variable afterward.
[EDIT]
Here's an example accelerates spawning interval (from 8 to 1) in cycles:
let spawn = SKAction.runBlock({ self.createWalls() })
var spawnCycle:[SKAction] = []
for timeToWait in (1...8).reverse()
{
spawnCycle.append(spawn)
spawnCycle.append(SKAction.waitForDuration(NSTimeInterval(timeToWait)))
}
self.runAction(SKAction.repeatActionForever(SKAction.sequence(spawnCycle)))

GameplayKit Pathfinding with obstacles and agents

I've been searching for days about this new framework and trying to make usage of some of it's funcionalities,
but... there're some things that are not fitting together for me, the demobot source code isn't helping at some points,
I miss some kind of simple tutorial but here goes my main doubts:
let obstacles = scene["obstacle"]
polygonObstacles = SKNode.obstaclesFromNodePhysicsBodies(obstacles)
graph = GKObstacleGraph(obstacles: polygonObstacles, bufferRadius: 60.0)
func drawGraph() {
for node in graph.nodes as! [GKGraphNode2D] {
for destination in node.connectedNodes as! [GKGraphNode2D] {
let points = [CGPoint(node.position), CGPoint(destination.position)]
let shapeNode = SKShapeNode(points: UnsafeMutablePointer<CGPoint>(points), count: 2)
shapeNode.strokeColor = SKColor(white: 1.0, alpha: 0.5)
shapeNode.lineWidth = 5.0
shapeNode.zPosition = 3
scene.addChild(shapeNode)
}
}
}
So, when I try to draw this graph and see the connections, I get this: http://i.imgur.com/EZ3dx5v.jpg
I find it really weird, anywhere I put my obstacles, even in low numbers, the left-corner portion of the screen have always more connections(the radius don't have influence on that)
I don't use GKComponents on my game, but I tried to run some GKAgents2D to hunt the player, like this:
func calculateBehaviorForAgents(){
let mainCharacterPosition = float2(scene.mainCharacter.position)
let mainCharacterGraphNode = GKGraphNode2D(point: mainCharacterPosition)
graph.connectNodeUsingObstacles(mainCharacterGraphNode)
for i in 0...monsters.count-1{
let monster = monsters[i]
let agent = agents[i]
let behavior = GKBehavior()
let monsterPosition = float2(monster.position)
let monsterGraphNode = GKGraphNode2D(point: monsterPosition)
graph.connectNodeUsingObstacles(monsterGraphNode)
let pathNodes = graph.findPathFromNode(monsterGraphNode, toNode: mainCharacterGraphNode) as! [GKGraphNode2D]
let path = GKPath(graphNodes: pathNodes, radius: 00.0)
let followPathGoal = GKGoal(toFollowPath: path, maxPredictionTime: 1.0, forward: true)
behavior.setWeight(1.0, forGoal: followPathGoal)
let stayOnPathGoal = GKGoal(toStayOnPath: path, maxPredictionTime: 1.0)
behavior.setWeight(1.0, forGoal: stayOnPathGoal)
agent.behavior = behavior
graph.removeNodes([monsterGraphNode])
}
graph.removeNodes([mainCharacterGraphNode])
}
Now when I call the updateWithDeltaTime method, his delegate methods:
func agentWillUpdate(agent: GKAgent){}
func agentDidUpdate(agent: GKAgent){}
give me unexpected values for the agents, it's position doesn't make any sense, with giant numbers that leads to outside of the battlefield
But I saw that the his velocity vector were making sense, so I matched it to my monster and updated the agent to the monster's position
func updateWithDeltaTime(currentTime : CFTimeInterval){
for i in 0...monsters.count-1{
let agent = agents[i]
let monster = monsters[i]
monster.physicsBody?.velocity = CGVectorMake(CGFloat(agent.velocity.x), CGFloat(agent.velocity.y))
agent.updateWithDeltaTime(currentTime)
agent.position = float2(monster.position)
monster.gameSceneUpdate(currentTime)
}
Now I was getting some results, but it's far away from what I want:
The monsters are not following the character to the edges or the right-top portion of screen, I remove their points from the graph but after make a path for them to follow (the image doesn't have this points, but they exists).
Apparently because there was no path leading to there, remember the image?
The question is: how to make this agent system to work?
Maybe I'm totally wrong at the usage of agents, goals and even the graphs! I read the documentation but I still can't make it right
And more...
At first, the monster were not avoid obstacles, even with GKGoals like "avoidObstacles", passing the same PolygonObstacles,
but when I change
graph.connectNodeUsingObstacles(mainCharacterGraphNode)
graph.connectNodeUsingObstacles(monsterGraphNode)
to
graph.connectNodeUsingObstacles(mainCharacterGraphNode, ignoringObstacles: polygonObstacles)
graph.connectNodeUsingObstacles(monsterGraphNode, ignoringObstacles: polygonObstacles)
it worked! o.O
I really need some help, thank you all :D!