In order to prevent a lot of the same code, I want to refer to every single node(all children of the same parent) on the scene with one call. I have a gate at the bottom of the scene and I want to detect if any node(many different nodes getting added to the scene) passes the y position of this gate.
This is how my update function looks now:
override func update(_ currentTime: TimeInterval) {
// code I want to simplify
if Cap.position.y < illustration2.position.y
|| Cap2.position.y < illustration2.position.y
|| Cap3.position.y < illustration2.position.y
|| Cap4.position.y < illustration2.position.y
|| Cap5.position.y < illustration2.position.y
|| Cap6.position.y < illustration2.position.y
|| Cap7.position.y < illustration2.position.y
|| Cap8.position.y < illustration2.position.y
|| Cap9.position.y < illustration2.position.y
|| Cap10.position.y < illustration2.position.y {
// Transitioning to game over
let transition = SKTransition.crossFade(withDuration: 0)
let gameScene = GameOver(size: self.size)
self.view?.presentScene(gameScene, transition: transition)
}
}
All Caps are children of illustration2, so I was thinking about something like:
//if the y position of any child is below the illustration2 y position the game over scene starts
if dontaiIllustration2.children.position.y < dontaiIllustration2.position.y {
}
Or another approach could be to check that the illustration2 node has the lowest y position from all nodes at the scene.
You can’t. You need to place them into a collection (array, dictionary, set, etc) and then find a way to traverse through them with something like foreach, map, compactMap (formally flatMap), reduced, etc. in your case, I would use reduce.
let caps = [Cap1,Cap2,Cap3,Cap4,Cap5,Cap6,Cap7,Cap8,Cap9,Cap10]
let result = caps.reduce(false,{value,cap in return value || cap.position.y < illustration2.position.y})
if result {
// Transitioning to game over
let transition = SKTransition.crossFade(withDuration: 0)
let gameScene = GameOver(size: self.size)
self.view?.presentScene(gameScene, transition: transition)
}
What this is doing, is going through each of your nodes, and evaluating the current equation with the previous result.
So we start at a false, then it will check if cap y > illustration y. If true, then our value becomes true, and this value carries over to the next cap. It repeats this until you run out of caps, and then returns the final value, which will be a false or a true.
Not really proud of this but you can do a forEach on the children of a parent node.
let node = SKNode()
var checker = false
node.children.forEach { (node) in
if node.position.y < illustration2.position.y {
checker = true
}
}
if checker {
// Game over
}
or you can enumerate them if you only want targets with specific names:
node.enumerateChildNodes(withName: "all can have same name") { (node, stop) in
if node.position.y < illustration2.position.y {
checker = true
}
}
You could also one-line it by using filter:
node.children.filter({$0.position.y < illustration2.position.y}).count > 0
Either way, i would put this in an extension of SKNode.
Related
I'm trying to activate collision detection while dragging an object. The behaviour I'm looking for can be seen with the second example (circles) seen here with another library:
library example
https://codepen.io/osublake/pen/bb6983d03e1c3582f9aac486ab9069f8
From my understanding, Phaser's collision engine will only work when object position is automatically updated through its velocity. Is it really the case ? If so, what would be a clean solution ?
My best solution right now is to change velocity in the update() method and use the pointer movement along with the delta time to calculate velocity. With constant deltas, the object movement would match the pointer movement. However, the result is a bit sketchy and has problems when the mouse stops to move (with button still down).
if (obj.membre.isDragging){
let prevPos = {x: obj.membre.x, y: obj.membre.y};
let pointer = scene.input.activePointer;
let velocityX = 0;
let velocityY = 0;
if (pointer.position.x !== status.pointerX && pointer.position.y !== status.pointerY){
status.pointerX = pointer.position.x;
status.pointerY = pointer.position.y;
velocityX = (pointer.position.x-pointer.prevPosition.x)/status.deltaS;
velocityY = (pointer.position.y-pointer.prevPosition.y)/status.deltaS;
}
obj.membre.setVelocity(velocityX, velocityY);
}
Matter engine would make it work, but here is an acceptable solution with arcade engine. The trick is to add LOTS of drag (as in friction). It also seams to work fine in the drag callback.
scene.input.on('drag', function (pointer, gameObject, dragX, dragY) {
gameObject.body.setAllowGravity(false);
gameobject.setDrag(1000,1000);
//set velocity to match pointer movement - status.deltaS is frame delta in seconds
velocityX = (pointer.position.x-pointer.prevPosition.x)/status.deltaS;
velocityY = (pointer.position.y-pointer.prevPosition.y)/status.deltaS;
gameObject.setVelocity(velocityX, velocityY);
});
Here is the solution a finally retained. It uses a custom speration function, based on the example http://labs.phaser.io/edit.html?src=src%5Cphysics%5Carcade%5Ccustom%20separate.js
collider in create()
this.physics.add.collider(obj.dynamicGroup,obj.dynamicGroup,customSeparate);
adjust body properties for all objects (necessary? based on example)
object.body.customSeparateX = true;
object.body.customSeparateY = true;
regular drag
scene.input.on('drag', function (pointer, gameObject, dragX, dragY) {
gameObject.x = dragX;
gameObject.y = dragY;
}
and here is the custom seperation function. I didn't know how to make it cleaner.
function customSeparate(s1, s2) {
var b1 = s1.body;
var b2 = s2.body;
//for dragged object, we have no velocity, so we take pointer direction
let pointFacingX = "left";
let pointFacingY = "top";
if (scene.input.activePointer.position.x > scene.input.activePointer.prevPosition.x) pointFacingX = "right";
if (scene.input.activePointer.position.y > scene.input.activePointer.prevPosition.y) pointFacingY = "bottom";
//if we have velocity we use that - could add priority to fastest object
if (b1.velocity.x > 0) pointFacingX = "right";
if (b2.velocity.x > 0) pointFacingX = "right";
if (b1.velocity.y > 0) pointFacingY = "bottom";
if (b2.velocity.y > 0) pointFacingY = "bottom";
let overlapX = 0;
let overlapY = 0;
if(b1.x > b2.x) {
overlapX = b2.right - b1.left;
}
else {
overlapX = b1.right - b2.left;
}
if(b1.y > b2.y) {
overlapY = b2.bottom - b1.top;
}
else {
overlapY = b1.bottom - b2.top;
}
//we move according to smallest overlap **no overlap is coded at 10000
if (overlapX <= 0) overlapX = 10000;
if (overlapY <= 0) overlapY = 10000;
if(overlapX < overlapY){
if (pointFacingX === "left"){
if (b1.x > b2.x) {
b2.x -= overlapX;
b2.stop();
}
else {
b1.x -= overlapX;
b1.stop();
}
}
else{
if (b1.x < b2.x) {
b2.x += overlapX;
b2.stop();
}
else {
b1.x += overlapX;
b1.stop();
}
}
}
else{
if (pointFacingY === "top"){
if (b1.y > b2.y) {
b2.y -= overlapY;
b2.stop();
}
else {
b1.y -= overlapY;
b1.stop();
}
}
else{
if (b1.y < b2.y) {
b2.y += overlapY;
b2.stop();
}
else {
b1.y += overlapY;
b1.stop();
}
}
}
}
I have a game with 10 levels and each level has an orb that a user can collect. When the user collects the orb the first time it should add +1 to the label and save using NSUserDefaults. That works fine but when I play the same level and I collect the orb again it shouldnt add another +1 to the label. I only need to add +1 for each orb in each of the levels. So that would be a total of 10 orbs saved in the label if the user collects all the orbs. What am I doing wrong?
class LevelOne: SKScene, SKPhysicsContactDelegate {
var didCollectOrb = true
override func didMove(to view: SKView) {
if didCollectOrb == true {
UserDefaults().set(UserDefaults().integer(forKey: "saveOrbs")+0, forKey:"saveOrbs")
print("will add nothing to label")
}
}
func didBegin(_ contact:SKPhysicsContact){
var firstBody: SKPhysicsBody
var secondBody: SKPhysicsBody
// 2. Assign the two physics bodies so that the one with the lower category is always stored in firstBody
if contact.bodyA.categoryBitMask < contact.bodyB.categoryBitMask {
firstBody = contact.bodyA
secondBody = contact.bodyB
} else {
firstBody = contact.bodyB
secondBody = contact.bodyA
}
if firstBody.categoryBitMask == HeroCategory && secondBody.categoryBitMask == OrbCategory {
//saves orbs
if didCollectOrb {
UserDefaults().set(UserDefaults().integer(forKey: "saveOrbs")+1, forKey:"saveOrbs")
print("will add +1 to label")
}
}
}
}
Tracking the Int value in UserDefaults is probably not the best way since there is no innate duplication prevention. If a person completes level 1 10 times, then they have collected 10 orbs according to that UserDefaults value. Perhaps you would prefer a binary or boolean storing method. For example, an easy way to implement it would be either a dictionary or array, e.g.:
let levels = [false, false, false, false, false, false, false, false, false, false] //10 values for 10 levels
func completeLevel(level: Int) { //takes a level from 1-10
self.levels[level - 1] = true
}
Then completing a level multiple times:
completeLevel(level: 1)
completeLevel(level: 1)
completeLevel(level: 1)
completeLevel(level: 1)
completeLevel(level: 1)
Will still only show true at that level index. So getting the "total number of collected orbs" is something like:
func getOrbs() -> Int {
var orbs = 0
self.levels.forEach { orbs += $0 ? 1 : 0 }
return orbs
}
I wouldn't recommend just copying and pasting this since this isn't a great implementation. Just try to understand how this works so that you can find a better way of storing the score while preventing unwanted duplication of orb counts.
I don't know if there is a better way of doing this, my solution works but just seems to repetitive.
I have a life indicator which is represented using an icon within SpriteBuilder, these are set to not visible, and then within source I have implemented the following code:
lives = 3 // this is reduced or increased within game
if (lives == 5) {
lifeIcon1.visible = true
lifeIcon2.visible = true
lifeIcon3.visible = true
lifeIcon4.visible = true
lifeIcon5.visible = true
} else if (lives == 4) {
lifeIcon1.visible = true
lifeIcon2.visible = true
lifeIcon3.visible = true
lifeIcon4.visible = true
} else if (lives == 3) {
lifeIcon1.visible = true
lifeIcon2.visible = true
lifeIcon3.visible = true
} else if (lives == 2) {
lifeIcon1.visible = true
lifeIcon2.visible = true
} else if (lives == 1) {
lifeIcon1.visible = true
}
This works fine but just seems repetitive, and is difficult to scale if I wanted to increase the lives to more than 5 at a later date.
Any suggestions?
Assuming you want to set your visible to false when you decrease your lives, you can use something like this:
let lifeIcons = [lifeIcon1, lifeIcon2, lifeIcon3, lifeIcon4, lifeIcon5]
...
for (index, lifeIcon) in lifeIcons.enumerate() {
lifeIcon.visible = index < lives
}
Or if you like using closures:
lifeIcons.enumerate().forEach{$1.visible = $0 < lives}
(Here $1 is the current life icon in the iteration, and $0 is the index of that icon)
The key point here is to use an array, instead of multiple variables to keep track of your life icons. You can then iterate through this array, using the indices of the elements in order to determine which icon they are. enumerate() is used in order to create a lazy sequence of pairs of elements with their indices.
In this case we can compare the indices of the elements with the current number of lives. Because indices are 0 based, we can check whether a given index is less than the current number of lives in order to determine whether it should be visible.
How about this:
let icons = [lifeIcon1, lifeIcon2, lifeIcon3, lifeIcon4, lifeIcon5]
icons[0..<lives].forEach { $0.visible = true }
It is similar to #Adam Heeg's answer, but the c-style loops are in the process of being deprecated. I would slice the array by subscript and use forEach instead.
It seems like you have some other code which you don't wnat to change. I would suggest the following.
Load all your lifeIcon's into an array then do the following. (adjust for if you are 0 based or not).
for (int i = 0; i < lives; i++)
{
lifeIconArray[i].visible = true;
}
(Sorry for the cross-post, but I put this up on GameDev.Stackexchange and it's not getting much traffic, so I thought I'd try here as well.)
I'm programming a simple tile-based puzzle game, and I've gotten stuck trying to work out a pathfinding algorithm.
Here's how the game is set out:
The game board is (arbitrarily) 8 tiles wide by 8 tiles tall.
Each tile can be one of four types (shown below as red, green, blue and yellow)
Additionally, a tile could be a reactor (the starting point of a path - this will become clear later on)
The board would look something like this:
(The reactors are the circles; the other tiles have no special properties.)
What I need to do is: starting from a reactor, trace the longest path along adjoining tiles of the same color as the reactor. Something like this:
The blue reactor is simple(ish) as its path doesn't branch. However, as you can see from the green reactor's start position, its path can branch two ways at the start (up or down), and take a detour midway through.
The path I'm looking for is the longest one, so that's the one that's highlighted in the screengrab (the first path only crosses two tiles, and the detour midway results in a sorter path).
When certain conditions have been fulfilled, the reactor will cause all the tiles in the longest path (where the arrows cross in the diagram) to disappear and be replaced with new ones. All other tiles will remain in place, including the extraneous green tiles adjacent to the green reactor's path.
The tiles are stored in an approximation of a 2D array (Swift doesn't have a robust native implementation of that yet, so I'm using the one described in this tutorial). They're retrieved using tile[column, row].
With some help from a friend, I've written a recursive function that should return the longest path. It's looping through correctly, but it's not pruning shorter branches from the longestPath array (for example, the longest path would include the 2-tile branch below the reactor, as well as the single-tile detour at the top of the arch).
Can anyone see where I'm going wrong in this code?
Here's the recursive function:
func pathfinder(startingTile: Tile, pathToThisPoint: Chain, var iteration: Int? = 1) -> Chain
{
var longestPath: Chain? = nil
var availableTiles = getNeighbouringTiles(startingTile)
for var nextTile = 0; nextTile < availableTiles.count; nextTile++
{
let column = availableTiles[nextTile].column
let row = availableTiles[nextTile].row
if tiles[column, row]!.tileType == startingTile.tileType && (tiles[column, row]!.isReactor == false || startingTile.isReactor)
{
// if we haven't been here before
if !pathToThisPoint.tiles.contains(tiles[column, row]!)
{
print(iteration)
iteration = iteration! + 1
// add this tile to the pathtothispoint
// go to the next unexplored tile (recurse this function)
pathToThisPointaddTile(tiles[column, row]!)
let tempPath = pathfinder(tiles[column, row]!, pathToThisPoint: pathToThisPoint)
// if the resulting path is longer...
if tempPath.length > longestPath.length
{
// then tempPath is now the longest path
for var i:Int = 0; i < tempPath.length; i++
{
let tile = Tile(column: pathToThisPoint.tiles[i].column, row: pathToThisPoint.tiles[i].row, tileType: pathToThisPoint.tiles[i].tileType)
longestPath?.addTile(tile)
}
}
}
}
if longestPath != nil
{
return longestPath!
}
else
{
return pathToThisPoint
}
}
It's dependent on the getNeighboringTiles function (shown below) that returns an array of valid tiles of the same type, excluding reactors:
func getNeighbouringTiles(tile: Tile, previousTile: Tile? = nil) -> Array<Tile>
{
var validNeighbouringTiles = Array<Tile>()
var neighbourTile: Tile
// check top, right, bottom, left
if tile.row < NumRows - 1
{
neighbourTile = tiles[tile.column, tile.row + 1]!
if neighbourTile.tileType == tile.tileType && !neighbourTile.isReactor && (previousTile == nil || previousTile != neighbourTile)
{
validNeighbouringTiles.append(neighbourTile)
}
}
if tile.column < NumColumns - 1
{
neighbourTile = tiles[tile.column + 1, tile.row]!
if neighbourTile.tileType == tile.tileType && !neighbourTile.isReactor && (previousTile == nil || previousTile != neighbourTile)
{
validNeighbouringTiles.append(neighbourTile)
}
}
if tile.row > 0
{
neighbourTile = tiles[tile.column, tile.row - 1]!
if neighbourTile.tileType == tile.tileType && !neighbourTile.isReactor && (previousTile == nil || previousTile != neighbourTile)
{
validNeighbouringTiles.append(neighbourTile)
}
}
if tile.column > 0
{
neighbourTile = tiles[tile.column - 1, tile.row]!
if neighbourTile.tileType == tile.tileType && !neighbourTile.isReactor && (previousTile == nil || previousTile != neighbourTile)
{
validNeighbouringTiles.append(neighbourTile)
}
}
// if we get this far, they have no neighbour
return validNeighbouringTiles
}
The Tile class looks like this (methods omitted for brevity):
class Tile: CustomStringConvertible, Hashable
{
var column:Int
var row:Int
var tileType: TileType // enum, 1 - 4, mapping to colors
var isReactor: Bool = false
// if the tile is a reactor, we can store is longest available path here
var reactorPath: Chain! = Chain()
}
And finally, the chain class looks like this (again, methods omitted for brevity):
class Chain {
// The tiles that are part of this chain.
var tiles = [Tile]()
func addTile(tile: Tile) {
tiles.append(tile)
}
func firstTile() -> Tile {
return tiles[0]
}
func lastTile() -> Tile {
return tiles[tiles.count - 1]
}
var length: Int {
return tiles.count
}
}
----------------------- EDIT : REPLACEMENT PATHFINDER ------------------------
I've attempted to convert User2464424's code to Swift. Here's what I've got:
func calculatePathsFromReactor(reactor: Tile) -> Chain?
{
func countDirections(neighbours: [Bool]) -> Int
{
var count: Int = 0
for var i:Int = 0; i < neighbours.count; i++
{
if neighbours[i] == true
{
count++
}
}
return count
}
var longestChain: Chain? = nil
longestChain = Chain()
var temp: Chain = Chain()
var lastBranch: Tile = reactor
var lastMove: Int? = reactor.neighbours.indexOf(true)
func looper(var currentTile: Tile)
{
if currentTile != reactor
{
if countDirections(currentTile.neighbours) > 2 //is branch
{
lastBranch = currentTile
}
if countDirections(currentTile.neighbours) == 1 //is endpoint
{
lastBranch.neighbours[lastMove!] = false // block move out of the last branch found
if longestChain.length < temp.length
{
longestChain = temp
}
currentTile = reactor // return to reactor and redo
lastVisitedTile = reactor
temp = Chain() //reset to empty array
lastBranch = reactor
lastMove = reactor.neighbours.indexOf(true)
looper(currentTile)
}
}
//let tempTile: Tile = Tile(column: currentTile.column, row: currentTile.row, tileType: currentTile.tileType, isReactor: currentTile.isReactor, movesRemaining: currentTile.movesRemaining)
//tempTile.neighbours = currentTile.neighbours
if currentTile.neighbours[0] == true
{
if !temp.tiles.contains(currentTile)
{
temp.addTile(currentTile)
}
if countDirections(currentTile.neighbours) > 2
{
lastMove = 0
}
lastVisitedTile = currentTile
currentTile = tiles[currentTile.column, currentTile.row + 1]! //must avoid going backwards
if !temp.tiles.contains(currentTile)
{
looper(currentTile)
}
}
if currentTile.neighbours[1] == true
{
if !temp.tiles.contains(currentTile)
{
temp.addTile(currentTile)
}
if countDirections(currentTile.neighbours) > 2
{
lastMove = 1
}
lastVisitedTile = currentTile
currentTile = tiles[currentTile.column + 1, currentTile.row]! //must avoid going backwards
if !temp.tiles.contains(currentTile)
{
looper(currentTile)
}
}
if currentTile.neighbours[2] == true
{
if !temp.tiles.contains(currentTile)
{
temp.addTile(currentTile)
}
if countDirections(currentTile.neighbours) > 2
{
lastMove = 2
}
lastVisitedTile = currentTile
currentTile = tiles[currentTile.column, currentTile.row - 1]! //must avoid going backwards
if !temp.tiles.contains(currentTile)
{
looper(currentTile)
}
}
if currentTile.neighbours[3] == true
{
if !temp.tiles.contains(currentTile)
{
temp.addTile(currentTile)
}
if countDirections(currentTile.neighbours) > 2
{
lastMove = 3
}
lastVisitedTile = currentTile
currentTile = tiles[currentTile.column - 1, currentTile.row]! //must avoid going backwards
if !temp.tiles.contains(currentTile)
{
looper(currentTile)
}
}
}
// trigger the function for the reactor tile
looper(reactor)
return longestChain
}
(The neighbours property is a struct containing four named variables: above, right, below and left, each initialised to false and then set to true by a function that runs immediately before the pathfinder.)
I'm finding a couple of issues now. The code loops as it should, but stops at the top of the arch, under the single-tile detour - the path that's returned is only 4 tiles long (including the reactor).
The other problem I'm having - which I'll worry about when the correct paths are being returned - is that I'm getting a memory access error when shifting the tiles in the third column down by one. I think it's getting confused when there's a block of tiles (2x2 or higher) rather than a path that's only ever a single tile wide.
I can't fix your code, but i have an idea for a system that doesn't require recursion.
You can try doing all possible paths from a reactor and block paths that you already traversed by being aware of the moves you have done when encountering a branch.
In the tile class, add another array of 4 integers initialized to 0 (called "dir" for example).
Pseudocode.
Do a preprocess loop first:
foreach tiles:
if tileHasNORTHNeighbor: tile.dir[0] = 1;
if tileHasEASTNeighbor: tile.dir[1] = 1;
if tileHasSOUTHNeighbor: tile.dir[2] = 1;
if tileHasWESTNeighbor: tile.dir[3] = 1;
Then do:
tile currentTile = reactor;
array longest;
array temp;
tile lastBranch = reactor;
int lastMove = any key of "reactor.dir" with "1" as value;
function int countOnes(array dir):
int count = 0;
int t;
for (t=0;t<4;t++):
if dir[t]==1:
count++;
return count;
:start
if currentTile != reactor:
if countOnes(currentTile.dir) > 2: //is branch
lastBranch = currentTile;
if countOnes(currentTile.dir) == 1: //is endpoint
lastBranch.dir[lastMove] = 0; // block move out of the last branch found
if longest.length < temp.length:
longest = temp;
currentTile = reactor; // return to reactor and redo
array temp = []; //reset to empty array
lastBranch = reactor;
lastMove = next "reactor.dir" key with "1" as value;
goto start;
if currentTile.dir[0] == 1:
temp.append(currentTile);
if countOnes(currentTile.dir) > 2:
lastMove = 0;
currentTile = getTileAtNORTH; //must avoid going backwards
goto start;
if currentTile.dir[1] == 1:
temp.append(currentTile);
if countOnes(currentTile.dir) > 2:
lastMove = 1;
currentTile = getTileAtEAST; //must avoid going backwards
goto start;
if currentTile.dir[2] == 1:
temp.append(currentTile);
if countOnes(currentTile.dir) > 2:
lastMove = 2;
currentTile = getTileAtSOUTH; //must avoid going backwards
goto start;
if currentTile.dir[3] == 1:
temp.append(currentTile);
if countOnes(currentTile.dir) > 2:
lastMove = 3;
currentTile = getTileAtWEST; //must avoid going backwards
goto start;
You could use the BFS Algorithm and easily modify it to give you the longest path.
You've got a implementation example here. Or you've got at least SwiftStructures and SwiftGraph github repositories with graph and search algorithms already implemented in swift.
I'm building a sprite kit game in swift and I need the score to increase by 1 when collision between 2 nodes is detected. The score is stored in a variable named animalsCount and is outputted to a label node:
//Score count in stats bar
//Animal score count
animalsCount = 0
animalsCountLabel.text = "\(animalsCount)"
animalsCountLabel.fontSize = 45
animalsCountLabel.fontColor = SKColor.blackColor()
animalsCountLabel.position = CGPoint (x: 630, y: 40)
addChild(animalsCountLabel)
The two sprite nodes that are colliding are savior and chicken1. Right now, I am keeping score and detecting collision using the following code:
func didBeginContact(contact: SKPhysicsContact) {
//Chicken1
if (contact.bodyA.categoryBitMask == ColliderType.Savior.rawValue && contact.bodyB.categoryBitMask == ColliderType.Chicken1.rawValue ) {
println("chicken1 contact made")
chicken1.hidden = true
chicken1.setScale(0)
animalsCount++
animalsCountLabel.text = "\(animalsCount)"
} else if (contact.bodyA.categoryBitMask == ColliderType.Chicken1.rawValue && contact.bodyB.categoryBitMask == ColliderType.Savior.rawValue) {
println("chicken1 contact made")
chicken1.hidden = true
chicken1.setScale(0)
}
Score is not increased in the else if statement because it can't happen in my game.
The problem is that animalsCount increases by 2, not 1, every time savior and chicken1 collide.
After some troubleshooting, I found out this is NOT because the score is being increased for both of the colliding bodies. This is not the case because only 1 line of code is ever satisfied. This is the only line that is satisfied:
if (contact.bodyA.categoryBitMask == ColliderType.Savior.rawValue)
The score goes up by 2 instead of 1 because savior seems to "bounce" off of chicken1 so that contact.bodyA.categoryBitMask is set equal to ColliderType.Savior.rawValue TWICE every time collision appears to occur ONCE.
I don't know how to fix this problem. How do I make it so that collision is only detected ONCE and so the score is only increased once?
I eventually solved the problem using an Int variable that controlled if statements so collision could only be detected once until the sprite node cycled through and the variable was reset.
I declared a variable called chickenHasBeenGrabbed and set it at 0 initially. Once collision had been detected that first time, I set chickenHasBeenGrabbed to 1. Only after chickenHasBeenGrabbed was set back to 0 could collision be detected again:
func didBeginContact(contact: SKPhysicsContact) {
//Chicken1
if chickenHasBeenGrabbed == 0 {
if (contact.bodyA.categoryBitMask == ColliderType.Savior.rawValue && contact.bodyB.categoryBitMask == ColliderType.Chicken1.rawValue ) {
println("chicken1 contact made")
chicken1.hidden = true
chicken1.setScale(0)
animalsCount += 1
animalsCountLabel.text = "\(animalsCount)"
chickenHasBeenGrabbed = 1
} else if (contact.bodyA.categoryBitMask == ColliderType.Chicken1.rawValue && contact.bodyB.categoryBitMask == ColliderType.Savior.rawValue) {
println("chicken1 contact made")
chicken1.hidden = true
chicken1.setScale(0)
}
}
else if chickenHasBeenGrabbed == 1 {
if (contact.bodyA.categoryBitMask == ColliderType.Savior.rawValue && contact.bodyB.categoryBitMask == ColliderType.Chicken1.rawValue ) {
println("nothing to do; chicken was already grabbed!")
} else if (contact.bodyA.categoryBitMask == ColliderType.Chicken1.rawValue && contact.bodyB.categoryBitMask == ColliderType.Savior.rawValue) {
println("nothing to do; chicken was already grabbed!")
}}