Sprite Kit de jeu Min. et Max. pour sauter

Je veux déplacer un SKSpriteNode sur l' Y-Axis Le SKSpriteNode appelé Player n'a pas de Velocity . Le joueur ne peut sauter que si une plate-forme est en contact.

Chaque fois que l'on touche l'écran, je veux donner au joueur une impulsion avec un minimum d'impulsion ou une impulsion maximum

Si vous appuyez brièvement sur l'écran, l'impulsion minimale doit être par exemple y = 50 . Si l'écran est en attente, cela signifie que le doigt est sur l'écran long, le maximum devrait être par exemple y = 100 .

Mais le joueur devrait aussi être capable de sauter entre la hauteur minimum et la hauteur maximale, si par exemple l'écran n'est pas long mais aussi pas pressé brièvement, le joueur devrait seulement avoir une impulsion de y = 70 .

Si l'écran est en attente, le joueur devrait sauter à sa hauteur maximum, tomber et s'il est à nouveau en contact avec la plate-forme, il devrait sauter, car vous maintenez toujours l'écran.

J'ai déjà essayé ceci avec la réponse suggérée dans ce fil: StackOverFlow Mais ceci ne donne pas le saut minimum, aussi aucun saut de presse.

Pour plus de clarté: L'impulsion ne devrait pas être après que le robinet est fait, mais pendant qu'il est tapoté. Plus vous tenez, plus le saut est long.

 import SpriteKit import GameKit struct Constants { static let minimumJumpForce:CGFloat = 40.0 static let maximumJumpForce:CGFloat = 60.0 static let characterSideSpeed:CGFloat = 18.0 } class GameScene: SKScene, SKPhysicsContactDelegate { var Player: SKSpriteNode! var Platform0: SKSpriteNode! var World: SKNode! var Camera: SKNode! var force: CGFloat = 40.0 var pressed = false var isCharacterOnGround = false ..... func SpawnPlatforms() { Platform0 = SKSpriteNode (color: SKColor.greenColor(), size: CGSize(width: self.frame.size.width , height: 25)) Platform0.position = CGPoint(x: self.frame.size.width / 2, y: -36) Platform0.zPosition = 1 Platform0.physicsBody = SKPhysicsBody(rectangleOfSize:Platform0.size) Platform0.physicsBody?.dynamic = false Platform0.physicsBody?.allowsRotation = false Platform0.physicsBody?.restitution = 0 Platform0.physicsBody?.usesPreciseCollisionDetection = true Platform0.physicsBody?.categoryBitMask = Platform0Category Platform0.physicsBody?.collisionBitMask = PlayerCategory Platform0.physicsBody?.contactTestBitMask = PlayerCategory World.addChild(Platform0) } func SpawnPlayer(){ Player = SKSpriteNode (imageNamed: "Image.png") Player.size = CGSize(width: 64, height: 64) Player.position = CGPoint(x: self.frame.size.width / 2, y: 0) Player.zPosition = 2 Player.physicsBody = SKPhysicsBody(rectangleOfSize:CGSize(width: 35, height: 50)) Player.physicsBody?.dynamic = true Player.physicsBody?.allowsRotation = false Player.physicsBody?.restitution = 0.1 Player.physicsBody?.usesPreciseCollisionDetection = true Player.physicsBody?.categoryBitMask = PlayerCategory Player.physicsBody?.collisionBitMask = Platform0Category Player.physicsBody?.contactTestBitMask = Platform0Category | Platform1Category | Platform2Category | Platform3Category | Platform4Category | Platform5Category World.addChild(Player) } func jump(force : CGFloat){ if(self.isCharacterOnGround){ self.Player.physicsBody?.applyImpulse(CGVectorMake(0, force)) self.isCharacterOnGround = false } } override func touchesBegan(touches: Set<NSObject>, withEvent event: UIEvent) { /* Called when a touch begins */ for touch in (touches as! Set<UITouch>) { let location = touch.locationInNode(self) self.pressed = true let timerAction = SKAction.waitForDuration(0.0) let update = SKAction.runBlock({ if(self.force < Constants.maximumJumpForce){ self.force += 2.0 }else{ self.jump(Constants.maximumJumpForce) self.force = Constants.maximumJumpForce } }) let sequence = SKAction.sequence([timerAction, update]) let repeat = SKAction.repeatActionForever(sequence) self.runAction(repeat, withKey:"repeatAction") } } override func touchesEnded(touches: Set<NSObject>, withEvent event: UIEvent) { for touch in (touches as! Set<UITouch>) { let location = touch.locationInNode(self) self.removeActionForKey("repeatAction") self.jump(self.force) self.force = Constants.minimumJumpForce self.pressed = false } } func didBeginContact(contact: SKPhysicsContact) { //this gets called automatically when two objects begin contact with each other let contactMask = contact.bodyA.categoryBitMask | contact.bodyB.categoryBitMask switch(contactMask) { case PlayerCategory | Platform0Category: //either the contactMask was the bro type or the ground type println("Contact Made0") Green = true self.isCharacterOnGround = true default: return } } 

Voici un exemple de travail sur comment faire quelque chose comme:

  • saut de pression long basé sur la durée de la presse
  • court (un saut de robinet)
  • restreindre le caractère pour sauter en l'air
  • garder le personnage qui saute pendant que le doigt est à l'écran

     import SpriteKit struct Constants { static let minimumJumpForce:CGFloat = 15.0 static let maximumJumpForce:CGFloat = 30.0 static let characterSideSpeed:CGFloat = 18.0 } class GameScene: SKScene,SKPhysicsContactDelegate { let CharacterCategory : UInt32 = 0x1 << 1 let PlatformCategory : UInt32 = 0x1 << 2 let WallCategory : UInt32 = 0x1 << 3 var force: CGFloat = 16.0 //Initial force var pressed = false var isCharacterOnGround = false // Use this to prevent jumping while in the air let character = SKSpriteNode(color: SKColor.greenColor(), size: CGSize(width: 30, height:30)) let debugLabel = SKLabelNode(fontNamed: "Geneva") override func didMoveToView(view: SKView) { //Setup contact delegate so we can use didBeginContact and didEndContact methods physicsWorld.contactDelegate = self physicsWorld.speed = 0.5 //Setup borders so character can't escape from us :-) self.physicsBody = SKPhysicsBody(edgeLoopFromRect: self.frame) self.physicsBody?.categoryBitMask = WallCategory self.physicsBody?.collisionBitMask = CharacterCategory //Setup character character.position = CGPoint(x: 150, y: 150) character.physicsBody = SKPhysicsBody(rectangleOfSize: character.size) character.physicsBody?.categoryBitMask = CharacterCategory character.physicsBody?.contactTestBitMask = PlatformCategory character.physicsBody?.collisionBitMask = PlatformCategory | WallCategory character.physicsBody?.allowsRotation = false character.physicsBody?.dynamic = true character.physicsBody?.restitution = 0.1 self.addChild(character) generatePlatforms() debugLabel.text = " DEBUG: " debugLabel.fontColor = SKColor.whiteColor() debugLabel.fontSize = 12.0 debugLabel.position = CGPoint(x: CGRectGetMidX(frame), y: CGRectGetMidY(frame)+100) self.addChild(debugLabel) } func generatePlatforms(){ for i in 1...4 { let position = CGPoint(x: CGRectGetMidX(frame), y: CGFloat(i)*140.0 - 100) let platform = createPlatformAtPosition(position) self.addChild(platform) } } func createPlatformAtPosition(position : CGPoint)->SKSpriteNode{ let platform = SKSpriteNode(color: SKColor.greenColor(), size: CGSize(width:frame.size.width, height:20)) platform.position = position platform.physicsBody = SKPhysicsBody( edgeFromPoint: CGPoint(x: -platform.size.width/2.0, y:platform.size.height/2.0), toPoint:CGPoint(x: platform.size.width/2.0, y: platform.size.height/2.0)) platform.physicsBody?.categoryBitMask = PlatformCategory platform.physicsBody?.contactTestBitMask = CharacterCategory platform.physicsBody?.collisionBitMask = CharacterCategory platform.physicsBody?.allowsRotation = false platform.name = "platform" platform.physicsBody?.dynamic = false platform.physicsBody?.restitution = 0.0 return platform } func jump(force : CGFloat){ if(self.isCharacterOnGround){ self.character.physicsBody?.applyImpulse(CGVectorMake(0, force)) self.character.physicsBody?.collisionBitMask = WallCategory self.isCharacterOnGround = false } } override func touchesBegan(touches: NSSet, withEvent event: UIEvent) { self.pressed = true let timerAction = SKAction.waitForDuration(0.05) let update = SKAction.runBlock({ if(self.force < Constants.maximumJumpForce){ self.force += 2.0 }else{ self.jump(Constants.maximumJumpForce) self.force = Constants.maximumJumpForce } }) let sequence = SKAction.sequence([timerAction, update]) let repeat = SKAction.repeatActionForever(sequence) self.runAction(repeat, withKey:"repeatAction") } override func touchesEnded(touches: NSSet, withEvent event: UIEvent) { self.removeActionForKey("repeatAction") self.jump(self.force) self.force = Constants.minimumJumpForce self.pressed = false } override func update(currentTime: NSTimeInterval) { debugLabel.text = "DEBUG: onTheGround : \(isCharacterOnGround), force \(force)" if(character.position.x <= character.size.width/2.0 + 5.0 && character.physicsBody?.velocity.dx < 0.0 ){ character.physicsBody?.applyForce(CGVectorMake(Constants.characterSideSpeed, 0.0)) }else if((character.position.x >= self.frame.size.width - character.size.width/2.0 - 5.0) && character.physicsBody?.velocity.dx >= 0.0){ character.physicsBody?.applyForce(CGVectorMake(-Constants.characterSideSpeed, 0.0)) }else if(character.physicsBody?.velocity.dx > 0.0){ character.physicsBody?.applyForce(CGVectorMake(Constants.characterSideSpeed, 0.0)) }else{ character.physicsBody?.applyForce(CGVectorMake(-Constants.characterSideSpeed, 0.0)) } } func didBeginContact(contact: SKPhysicsContact) { var firstBody, secondBody: SKPhysicsBody if contact.bodyA.categoryBitMask < contact.bodyB.categoryBitMask { firstBody = contact.bodyA secondBody = contact.bodyB } else { firstBody = contact.bodyB secondBody = contact.bodyA } if ((firstBody.categoryBitMask & CharacterCategory) != 0 && (secondBody.categoryBitMask & PlatformCategory != 0)) { let platform = secondBody.node as SKSpriteNode // platform.color = UIColor.redColor() let platformSurfaceYPos = platform.position.y + platform.size.height/2.0 let player = contact.bodyB.node as SKSpriteNode let playerLegsYPos = player.position.y - player.size.height/2.0 if((platformSurfaceYPos <= playerLegsYPos) ){ character.physicsBody?.collisionBitMask = PlatformCategory | WallCategory self.isCharacterOnGround = true if(self.pressed){ var characterDx = character.physicsBody?.velocity.dx character.physicsBody?.velocity = CGVector(dx: characterDx!, dy: 0.0) self.jump(Constants.maximumJumpForce) } } } } func didEndContact(contact: SKPhysicsContact) { var firstBody, secondBody: SKPhysicsBody if contact.bodyA.categoryBitMask < contact.bodyB.categoryBitMask { firstBody = contact.bodyA secondBody = contact.bodyB } else { firstBody = contact.bodyB secondBody = contact.bodyA } if ((firstBody.categoryBitMask & CharacterCategory) != 0 && (secondBody.categoryBitMask & PlatformCategory != 0)) { let platform = secondBody.node as SKSpriteNode let platformSurfaceYPos = platform.position.y + platform.size.height/2.0 let player = contact.bodyB.node as SKSpriteNode let playerLegsYPos = player.position.y - player.size.height/2.0 if((platformSurfaceYPos <= playerLegsYPos) && (character.physicsBody?.velocity.dy > 0.0)){ character.physicsBody?.collisionBitMask = WallCategory self.isCharacterOnGround = false } } } } 

Notez que c'est un exemple simple, et dans une application réelle, vous devrez probablement gérer des états comme isOnTheGround d'une manière différente. En ce moment, pour déterminer si le personnage est sur le terrain, il suffit de mettre isOnTheGround = true lorsque le personnage établit un contact avec la plateforme, et le définir sur false dans didEndContact … Mais il y a des situations où le personnage peut être en contact avec la plateforme air (par exemple, contact latéral) …

MODIFIER:

J'ai changé le code pour laisser le joueur sauter tout en appuyant. Voici le résultat:

entrez la description de l'image ici

Important:

La mise en place de la plate-forme et la gestion des contacts sont à vous et cela n'est pas testé. Le seul but de cet exemple est de vous montrer comment sauter tout en appuyant. Actuellement, physicsWorld.speed est mis à 0.5 pour physicsWorld.speed animation car il est plus facile de déboguer comme ça, mais vous pouvez changer cela en valeur par défaut (1.0).

Ainsi, comme vous pouvez le voir sur l'image, pendant que le joueur est sur la première plate-forme, de petits sauts sont présentés (par simple tapotement ou par appui court). Ensuite (le joueur est toujours sur la première plate-forme), une longue pression a été faite et le joueur a sauté sur la deuxième plate-forme. Après cela, une autre longue pression est faite, mais cette fois sans relâcher, et le joueur commence à sauter d'une plate-forme à l'autre en utilisant la force maximale.

Cela nécessite beaucoup de peaufinage et une bonne détection de plate-forme et de contact, mais cela peut vous donner une idée de la façon de mettre en œuvre le saut dont vous avez parlé.