Boundaries Function not Working? Swift SpriteKit - swift

So first off, what I'm trying to do but clearly failing to is prevent a sprite "the player" from moving off the edge of the map "400x400px img".
The controls on the game are buttons for moving right, left, up and down.
I have it so when the buttons are pressed it runs a function that checks if the player's destination is off the map's area.
****Note That the Map is a 5x5 grid map, each square of the grid is 80x80 inside map image****
Here's the function that checks if the player's destination is off the map:
func checkBordersDownPlayer() {
if player.position.y - 80 == map.position.y - 80 {
print("Node cannot move. Map borders are stopping the Node from moving past it's boundaries.")
}
else {
player.runAction(moveDown)
print("Player was able to move!")
}
}
Now what troubles me is that the player automatically ignores the print() functions and the if function but still runs the SKAction to move it.

What I could asses from your post is that perhaps you are not clear about the position concept of sprite node.
Unlike UIKit in which position of a frame is at the top left corner of the Rectangle, in Spritekit a node's position is at its center by default unless you will play with its anchor point.
Again taking your situation into consideration, you should use the tools provided by Spritekit for efficiently handling such tasks, You should use Physics body around the map image and make your player another physics body assigning them different physics categories.
In your case you don't need to assign any contact test bit mask or collision bit mask untill you are not interested in getting informed when the player touches the boundary set by you. You can refer to this tutorial for more https://www.raywenderlich.com/123393/how-to-create-a-breakout-game-with-sprite-kit-and-swift
Hope this helps.

Without knowing more of how you calculate movement the best I can do is guess this is your problem.
player.position.y - 80 == map.position.y - 80
Instead you probably want something like this...
player.position.y - 80 <= map.position.y - 80
Hopefully that helps
edit
One step further would be to reset the players position too...
func checkBordersDownPlayer() {
if player.position.y - 80 <= map.position.y - 80 {
player.position.y = map.position.y - 80
print("Node cannot move. Map borders are stopping the Node from moving past it's boundaries.")
}
else {
player.runAction(moveDown)
print("Player was able to move!")
}
}

Related

How to get current frame from Animated Tile/Tilemap.animationFrameRate in Unity

I am using tilemaps and animated tiles from the 2dExtras in unity.
My tiles have 6 frames, at speed=2f, and my tilemap frame rate is 2.
New tiles placed always start on frame 1 and then immediately jump to the current frame of the other tiles already placed, the tilemap is keeping every tile at the same pace, which is working as I want.
However I would like the newly placed tiles to start at the frame the others are currently on,(instead of placing a tile that jumps from frame 1 to frame 4) I would like the new tile to start on frame 4
I've found how to pick the frame I want to start on, however I am having trouble retrieving which frame the animation is currently on, so I was wondering how exactly can I access the current frame of animation of a given tilemap ( Or a given tile, I can create a dummy tile and just read the info out of it, how can I get the current frame of an animated tile? )
The animated tilemaps feature seems to lack the feature to retrieve this information, also when I try tilemap.getsprite it always returns the first frame of the sequence(does not return the sprite currently displayed), and there doesn't seem to be any method to poll info from tilemap.animationFrameRate.
I thought another method would be to set a clock and sync it to the rate of the animation but since I can't get the exact framerate duration the clock eventually goes out of sync.
Any help would be appreciated!
I found a way to solve this question. But it's not 100% insurance.
First of all, I used SuperTile2Unity. That doesn't seem to be the point.
private void LateUpdate()
{
// I use this variable to monitor the run time of the game
this.totalTime += Time.deltaTime;
}
private void func()
{
// ...
TileBase[] currentTiles = tilemap.GetTilesBlock(new BoundsInt(new Vector3Int(0, 0, 0), new Vector3Int(x, y, 1)));
Dictionary<string, Sprite> tempTiles = new Dictionary<string, Sprite>();
//I use SuperTiled2Unity. But it doesn't matter, the point is to find animated tile
foreach (SuperTiled2Unity.SuperTile tile in currentTiles)
{
if (tile == null)
{
continue;
}
if (tile.m_AnimationSprites.Length > 1 && !tempTiles.ContainsKey(tile.name))
{
// find animated tile current frame
// You can easily find that the way SuperTile2Unity is used to process animation is to generate a sprite array based on the time of each frame set by Tiled animation and the value of AnimationFrameRate parameter.
// The length of array is always n times of AnimationFrameRate. You can debug to find this.
tempTiles.Add(tile.name, tile.m_AnimationSprites[GetProbablyFrameIndex(tile.m_AnimationSprites.Length)]);
}
}
//...
}
private int GetProbablyFrameIndex(int totalFrame)
{
//According to the total running time and the total length of tile animation and AnimationFrameRate, the approximate frame index can be deduced.
int overFrameTime = (int)(totalTime * animationFrameRate);
return overFrameTime % totalFrame;
}
I have done some tests. At least in 30 minutes, there will be no deviation in animations, but there may be a critical value. If the critical time is exceeded, there may be errors. It depends on the size of AnimationFrameRate and the accumulation mode of totalTime. After all, we don't know when and how the unity deals with animatedTile.
You could try using implementation presented in [1] which looks as follows:
MyAnimator.GetCurrentAnimatorClipInfo(0)[0].clip.length * (MyAnimator.GetCurrentAnimatorStateInfo(0).normalizedTime % 1) * MyAnimator.GetCurrentAnimatorClipInfo(0)[0].clip.frameRate;
[1] https://gamedev.stackexchange.com/questions/165289/how-to-fetch-a-frame-number-from-animation-clip

Force the SKAction.move to be completed - swift

I'm creating a Snake Game using swift and the library SpriteKit.
To control the direction of the snake, the user has to swipe on the screen. To check which was the direction of the swipe, I use UISwipeGestureRecognizer .
Now, I have to pass the information (direction of the swipe) from the GameViewController.swift file to the GameScene.swift file. To to that, I declare a 4 items array called movesConoller:
movesController[false, false, false, false]
If the user swipes up, the first element of the array turns true, if he scrolls down, the second element turns true and the first one false... etc. etc.
Now, in the GameScene.swift file I have to say what the Snake has to do if the player moves up.
For this reason, I use 2 more variables:
var playerX:CGFloat = 0
var playerY:CGFloat = 0
and then I created this code
if movesController[0] == true {
playerY += 56
}
if movesController[1] == true {
playerY -= 56
}
if movesController[2] == true {
playerX += 56
}
if movesController[3] == true {
playerX -= 56
}
Now I create the movement
let startPoint = CGPoint(x: player.position.x, y: player.position.y )
let endPoint = CGPoint(x: playerX + player.position.x, y: playerY + player.position.y)
let moveIt = SKAction.move(to: endPoint, duration:0.1)
player.run(moveIt)
So, every time the program is executed, the playerX and playerYvariables become equal to 0. Then, based on the direction of the swipe, they are added or subtracted 56.
To move the snake I just say to the head to move from his startPointto his endPoint in 0.1 seconds.
Another thing I added is the tail. To create it I use two arrays, snakeX and snakeY.
To these two empty arrays (of type CGFloat) I add the previous position of the snake and then, if the score remains the same, the last element of each array is deleted. Else, the last element isn't deleted and remains in his array.
Whit this method, I make the tail growing when the snake eats an apple.
BUT the head moves 56 in 0.1seconds. This means that he makes a movement of 8 pixels at each execution. Because of that, I have to add to snakeX and snakeY the X and Y values every 7 execution of the program.
This is the problem. If the player swipes on the screen just after 7 execution of the program, the movement of the tail will be perfect. But if the player swipes before the 7 execution, there will be a problem. Let's suppose the snake is moving right and the player swipes up when the program is at its 4th execution.
//snakeX and snakeY values before the swipe
snakeX[168, 112, 56, 0] //all this numbers are multiple of 56
snakeY[224, 224, 224, 224] //the snake is moving right, the Y value doesn't change.
//snakeX and snakeY values after the swipe
snakeX[168 ,112 ,56 , 0]
snakeY[248, 224, 224, 224] //look at the first element
248 is not a multiple of 56. The snake moved Up at the 4th execution, after 3 execution his position will be added to the arrays. But in 3 execution he had moved of 24pixel.
Because of that, I'll get this bug
as you can see, the tail doesn't make a perfect corner.
The snake head doesn't complete his movement of 56 pixels. When I swipe, it leaves his movement and starts another one. Is there a way I can tell the head to always complete his movement before doing another one?
You're sort of trying to use a pixel-based approach to what's basically a grid-based game, but maybe something like this will work...
Make a variable controlling whether movement is allowed:
var moveAllowed = true
Guard your movement code with that variable:
if moveAllowed {
if movesController[0] == true {
playerY += 56
}
...
}
When you schedule the movement action, toggle moveAllowed, and add a completion handler to toggle it back after the action finishes:
...
moveAllowed = false
let moveIt = SKAction.move(to: endPoint, duration:0.1)
player.run(moveIt) { self.moveAllowed = true }
(The self.moveAllowed might be just moveAllowed depending on how you have things structured, but I can't tell from your fragments.)
Edit: I just realized that maybe you're setting snakeX and snakeY based on player.position. It's not really clear. In any case, then you'd use the same idea but copying from player.position only when moveAllowed is true. Basically that variable is telling you if the action is still running or not.

SKSpriteNodes spawning in the wrong place - is the game scene itself moving?

[Long post ahead.]
I'm really confused as to why this is happening.
I have a game in which sprites (SKSpriteNodes) spawn at regular-ish intervals off the right side of the screen and move to the left.
The spawning sprites are children of a 'world' SKSpriteNode, which is a child of the game scene. The world is declared here (in didMove(to: view)):
world = self.childNode(withName: "world") as! SKSpriteNode
The spawns are added to the 'world' like this:
nowSpawn.position = CGPoint(x: 350, y: 0)
world.addChild(nowSpawn)
nowSpawn.run(SKAction.moveBy(x: -1000, y: 0, duration: 10))
This spawn-adding is inside the function addSpawn() which is called in another function called spawnDelays() that calculates the slight variations in intervals at which to add the spawns. spawnDelays() is called in didMove(to : view):
func spawnDelays () {
let randDuration = Double(arc4random_uniform(UInt32(2))) + (universalDuration/8)
let rerunSpawnDelays = SKAction.run{spawnDelays()}
run(SKAction.sequence([
SKAction.run(addSpawn),
SKAction.wait(forDuration: Double(randDuration)),
rerunSpawnDelays,
]), withKey: "spawning"
)
}
spawnDelays()
However, something weird is happening. For about the first 10-15 spawns it works as expected, with the spawns emerging from the right of the screen and moving to the left. However, soon after, the spawns start appearing further to the left (i.e. on screen), and keep appearing further to the left until they are completely off the left side of the screen.
To try and see what's going on, I've been printing the .position of each spawn and also of the world sprite every time a new spawn appears. However, even if the spawn is spawning in the wrong place (e.g. in the middle of the screen, whose position would be near (0,0)), the console still prints its position as being (350, 0) - i.e. the position where I add the spawns.
To check that the world sprite isn't moving, I've also been printing its position every time a spawn is spawned - and it is consistently (0.0000.., 0.0....).
My only possible explanation is that the world's parent - which is the game scene - is inching leftwards, and therefore the relative position of all the children sprites is shifted to the left. But that makes no sense.

Flipping a child sprite's xscale in Spritekit using Swift

Alright I'm offically stumped. I've been able to figure out my problems myself in the past but I'm lost on this one.
I'm trying to flip a child sprite's xscale. I want the flip to occur when the child's x position is negative. With the code below, the sprite does flip, every time the sprite reaches negative position, it loops back and forth flipping until reaching positive again.
I've tried numerous variations, but this is the code in it's simplest form. Any help or alternatives would be appreciative.
override func update(currentTime: CFTimeInterval) {
/* Called before each frame is rendered */
let pin = childNodeWithName(Pin1) as SKSpriteNode!
let guyPoint = guy.convertPoint(guy.position, fromNode: pin)
if guyPoint.x <= 0 {
guy.xScale = -1
}
else {
guy.xScale = 1
}
}
So if it is constantly flipping it's probably an issue of coordinate space. So check to make sure your convertPoint method is accurately returning the point you want. I would use println() to see what's going on there.
Probably what's happening is you want to flip the xScale when the child node is negative in the scene space or something (i.e. when the child is off the screen) but instead guyPoint might be the position of the child in its parent's coordinate space (so relative to the parent).
Also try with and without the else{} part to see if that changes anything.

How to detect collision of sprite in cocos2d [closed]

Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
Questions asking for code must demonstrate a minimal understanding of the problem being solved. Include attempted solutions, why they didn't work, and the expected results. See also: Stack Overflow question checklist
Closed 9 years ago.
Improve this question
i want to detect collision of a sprite with another sprite. but i want to check whether the sprite is touched with left part of other sprite or touched with right part of sprite.
i am using below code for detecting collision. but this detect the overall collision(sprite touched to at any point of other sprite). but want to count is as collision if the sprite is touched to front side of other sprite.
if (CGRectIntersectsRect(sprite1.boundingBox, sprite2.boundingBox)) {
NSLog(#"sprite1 to delete");
}
any one know how to do this?
Would you be able to compare the positions of the sprites at the time of collision?
Assume sprite1.anchorpoint, sprite2.anchorpoint = ccp(0,0). At time when collision is detected:
// left part of sprite 1 touched right part of sprite 2
if (sprite1.position.x == sprite2.position.x + sprite2.contentSize.width.x) {
}
// right part of sprite 1 touched left part of sprite 2
else if (sprite1.position.x + sprite1.contentSize.width.x == sprite2.position.x) {
}
By default in cocos2d the anchorpoint of a CCSprite is ccp(0.5, 0.5) which modifies the comparison of sprite positions.
Comparing positions for the purpose to check relative distance between sprites in a gameloop, I think the equality operator is not the best choice, greater/less than equal is better to prepare different position situations, sprite moving steps.
To understand better I included the sprite situations for example:
To check the relative position (to detect a sprite is on what side of the other sprite) you have different choices to program in your collision detection check:
1)
if (CGRectIntersectsRect(sprite1.boundingBox, sprite2.boundingBox)) {
CGPoint diff = ccpSub(sprite1.position, sprite2.position)
if (diff.x<=0) {
// sprite1 is on the left side
} else {
// sprite1 is on the right side
}
}
2)
if (CGRectIntersectsRect(sprite1.boundingBox, sprite2.boundingBox)) {
if (sprite1.position.x <= sprite2.position.x) {
// sprite1 is on the left side
} else {
// sprite1 is on the right side
}
}