问题
I want that when touches began the player (red circle) moves to the opposite side of the circular path. I already made that the player follows a path, but I havent find answer to my question on internet.
override func didMoveToView(view: SKView) {
player = SKSpriteNode(imageNamed: "circulo")
player.position = CGPoint(x: self.frame.width / 2, y: self.frame.height / 2 - 170)
player.color = colorGris
player.colorBlendFactor = 1
player.size = CGSize(width: 25, height: 25)
self.addChild(player)
player.zPosition = 3
}
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
/* Called when a touch begins */
if gameStarted == false {
gameStarted = true
moveClockWise()
movingClockWise = true
}
}
func moveClockWise(){
let dx = player.position.x - self.frame.width / 2
let dy = player.position.y - self.frame.height / 2
let rad = atan2(dy, dx)
path = UIBezierPath(arcCenter: CGPoint(x:self.frame.width / 2, y: self.frame.height / 2) , radius: 170, startAngle: rad, endAngle: rad + CGFloat(M_PI * 4), clockwise: true)
let follow = SKAction.followPath(path.CGPath, asOffset: false, orientToPath: true, speed: 200)
player.runAction(SKAction.repeatActionForever(follow).reversedAction())
}
回答1:
One of the easiest ways to move an object in a circular path is to
- Create a
SKNode
container - Create a sprite
- Add the container to the scene
- Set the sprite's
x
position to the radius of the circular path - Add the sprite to the container
- Rotate the container
If you want to move the sprite to the other side or change the rotation's radius, simply
- change the sprite's
x
position
If you want to change the direction of the rotation,
- reverse the container's rotation
Example Code:
// 1) Create the container node
let node = SKNode()
// 2) Create a sprite
let sprite = SKSpriteNode(color:SKColor.blueColor(),size:CGSizeMake(20,20))
var rotation:CGFloat = CGFloat(M_PI)
let radius:CGFloat = 50
override func didMoveToView(view: SKView) {
scaleMode = .ResizeFill
node.position = view.center
// 3) Add the container to the scene
addChild(node)
// 4) Set the sprite's x position
sprite.position = CGPointMake(radius, 0)
// 5) Add the sprite to the container
node.addChild(sprite)
// 6) Rotate the container
rotate()
}
// Rotate the container
func rotate() {
let action = SKAction.rotateByAngle(rotation, duration: 4)
node.runAction(SKAction.repeatActionForever(action),withKey: "rotate")
}
// 8) Reverse the direction of the rotation
func reverse() {
rotation = -rotation
}
// Stop rotating the container
func stopRotation() {
if node.actionForKey("rotate") != nil {
node.removeActionForKey("rotate")
}
}
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
/* 7) Change the sprite's x-position */
if sprite.actionForKey("move") == nil {
stopRotation()
let opposite = -sprite.position.x * 2
let move = SKAction.moveByX(opposite, y: 0, duration: 3)
let rotate = SKAction.runBlock {
self.rotate()
}
sprite.runAction(SKAction.sequence([move, rotate]), withKey: "move")
}
}
回答2:
I think you could follow these steps:
- stop the
runAction
of your player:
You can do for example:
let follow = SKAction.followPath(path.CGPath, asOffset: false, orientToPath: true, speed: 200)
player.runAction(SKAction.repeatActionForever(follow).reversedAction(),withKey:"followPath")
To stop do simply:
player.removeActionForKey("followPath")
- Re-build your path to have a new "moveToPoint" (the start point) wit the actual position:
To do it I try to use your code to make it understandable:
var myCircle : CGMutablePath! = CGPathCreateMutable()
let newDx = player.position.x - self.frame.width / 2
let newDy = player.position.y - self.frame.height / 2
let newRad = atan2(newDy, newDx)
let newPath = UIBezierPath(arcCenter: CGPoint(x:self.frame.width / 2, y: self.frame.height / 2) , radius: 170, startAngle: newRad, endAngle: newRad + CGFloat(M_PI * 4), clockwise: true)
- Mirroring the path:
To do this trick you can write:
var mirroring = CGAffineTransformMakeScale(1.0, -1.0) // flip horizontal
var mirrorPath : CGMutablePath! = CGPathCreateMutable()
CGPathAddPath(mirrorPath, &mirroring, newPath.CGPath)
- Restart the
runAction
:
Here you can re-launch:
let newFollow = SKAction.followPath(mirrorPath, asOffset: false, orientToPath: true, speed: 200)
player.runAction(SKAction.repeatActionForever(newFollow).reversedAction(),withKey:"followPath")
Addition:
If you can add some nice animation like for example the jump between the point position and the mirrored point in the circle, you need to know the CGPoint
destination (in the mirrorPath it will be the "moveToPoint" or the also the first point). Here you can find an extension to obtain all CGPath
points so:
var mirrorPoints = mirrorPath.getPathElementsPoints()
let destinationPoint = mirrorPoints.first!
In the Sprite-kit framework there isn't yet a jumpAction between the available SKAction's
, so you can create it with few code.
Usually the "jump" is maked by changing the Y coordinate, in you case your view is from high so you can do a zoomIn e zoomOut (scale).
来源:https://stackoverflow.com/questions/38167139/how-to-make-player-move-to-opposite-side-while-is-in-a-path