I am trying to include enumerateChildNode with a For Loop. My code is below.
func movement() {
scene?.enumerateChildNodes(withName: "//enemy") {
(node, stop) in
enemyArray.append(node as! SKSpriteNode)
}
for i in enemyArray {
if enemy.position = player.position + 1 {
player.position = player.position + 1
}
continue
}
What the code above does is check for every enemy SKSpriteNode on the screen (lets say it finds 6), and then checks their positions relative to the player. If the players position is near the enemy position, it moves the players position, and then continues the for loop from where it was and checks the players position from the remaining enemies.
However, if the player moves near an enemy position that the for loop already checked (which was false at the time), it will miss that the player is near that enemy. EG: The for loop checks enemies 1,2,3 (finds 3 is near player and moves the player near 2) then checks 4,5,6. It will miss 2...
What I want the code to do
If enemy.position = player.position + 1 {
//move player
*stop the loop, and check the players position from the beginning of the for loop*
}
Call the method again and break out of the loop. But, this causes an infinite loop as you know while posting your question. Not sure how you're planning on changing the value of "i" since it's scope is within the method. Anyways here's how you achieve this:
var array = [1,2,3,4,5,6]
movement()
func movement() {
for i in array {
if i == 3 {
print("hi")
movement()
break
}
}
}
Related
I'm creating a Snake Game using swift and the library SpriteKit.
At the top of my program I declare a variable
import SpriteKit
class GameScene: SKScene, SKPhysicsContactDelegate {
var player = SKSpriteNode(imageNamed: "head")
[...]
}
In this way I can access to this variable in all of my functions. But I'd like to change the snake's image when the it moves.
For example, if the snake moves Up, I'd like to display the image of the snake looking up.
So I have this code to control the movements of the snake
if movesController[0]==true{
playerY += 56.0000000
}
if movesController[1]==true{
playerY -= 56.0000000
}
if movesController[2]==true{
playerX += 56.0000000
}
if movesController[3]==true{
playerX -= 56.0000000
}
and to change the image of the snake I thought I could just do this
if movesController[0]==true{
playerY += 56.0000000
player = SKSpriteNode(imageNamed: "head_up")
}
if movesController[1]==true{
playerY -= 56.0000000
player = SKSpriteNode(imageNamed: "head_down")
}
if movesController[2]==true{
playerX += 56.0000000
player = SKSpriteNode(imageNamed: "head_right")
}
if movesController[3]==true{
playerX -= 56.0000000
player = SKSpriteNode(imageNamed: "head_left")
}
But adding this 4 lines, the Snake is unable to move...
So I tried changing the declaration of the player variable
import SpriteKit
class GameScene: SKScene, SKPhysicsContactDelegate {
var imageName = "head"
var player = SKSpriteNode(imageNamed: "\("imageName)")
[...]
}
and then change the 4 lines I added before with imageName = "move_up" (or down - left - right)
But at the start of the program it gave me an error
Cannot use instance member 'imageName' within property initializer; property initializers run before 'self' is available
What should I do? My last option is to create another playerVariable and put it above the real snake image, but it would mean adding more nodes for nothing.
You must change player's texture, but not create new player at each step. Try add this function:
func changeHead(imageNamed name: String){
player.texture = SKTexture(imageNamed: name)
}
And the program text will be changed in this way:
if movesController[0]==true{
playerY += 56.0000000
changeHead(imageNamed: "head_up")
}
if movesController[1]==true{
playerY -= 56.0000000
changeHead(imageNamed: "head_down")
}
if movesController[2]==true{
playerX += 56.0000000
changeHead(imageNamed: "head_right")
}
if movesController[3]==true{
playerX -= 56.0000000
changeHead(imageNamed: "head_left")
}
Actually, your way to solve this problem is true.Put self before the imageName variable. It would be work.
import SpriteKit
class GameScene: SKScene, SKPhysicsContactDelegate {
var imageName = "head"
var player = SKSpriteNode(imageNamed: "\("self.imageName)")
[...]
}
I have two images: ball and obstacle. If the ball hits the obstacle it's game over.
But since my obstacle and ball are not shaped as a rectangle, it looks like it's gameover before they hit each other. I understand that their frame actually does hit each other. But in the game, my gameover function is called before it looks like my ball and obstacle intersect.
Hope to find some help so I can have the result that my two images really looks like they hit each other before my gameover function is called.
if CGRectIntersectsRect(ball.frame, obstacle.frame) {
gameOver()
}
extension CGPoint {
func distance(to p: CGPoint) -> CGFloat {
return sqrt((p.x - self.x) * (p.x - self.x) + (p.y - self.y) * (p.y - self.y))
}
}
extension UIView {
func collided(with otherView: UIView) -> Bool {
let myRadius = bounds.width/2
let hisRadius = otherView.bounds.width/2
return self.center.distance(to: otherView.center) <= myRadius + hisRadius
}
}
Now it reads nicely too:
if ball.collided(with: obstacle) {
gameOver()
}
I want to make a character jump only when he is with his feet on the ground. I don't want him to be able to 'air-jump', so I came with this solution:
if (JumpButtonPressed()) {
if (GetComponent<BoxCollider2D>().IsTouchingLayers(LayerMask.NameToLayer("Ground"))) {
velocity.y = jumpForce;
}
}
The idea is that only when in touch with a "Ground" Layer, it can jump. But this is what happens:
It doesnt work just on his foot. If he is touching a platform by the side, it can jump as well. What could I do?
Use circle overlap with a position vector which is placed at the bottom on the player. Detect layer from there.
You may need to use different layer for platform if you want to write features like ledge grab, jump.
Create a bool isJumping and set it to true while in the air. When it reaches the ground - set it to false. Smth like that if your snippet is in Update():
bool isJumping = false;
if (JumpButtonPressed() && !isJumping) {
if (GetComponent<BoxCollider2D>().IsTouchingLayers(LayerMask.NameToLayer("Ground"))) {
velocity.y = jumpForce;
isJumping = true;
}
}
if (GetComponent<BoxCollider2D>().IsTouchingLayers(LayerMask.NameToLayer("Ground"))) {
isJumping = false;
}
I'm trying to move a sprite object (the hero) to the current location of the began touch event on the stage. Every time I touch on the stage it reads out the current globalX and globalY coordinates, but the sprite disappears from the stage so I don't know what I am doing wrong.
Here is my code:
private function onTouch(e:TouchEvent):void
{
var touch:Touch = e.getTouch(stage);
if(touch)
{
if(touch.phase == TouchPhase.BEGAN)
{
hero.x += touch.globalX;
hero.y += touch.globalY;
trace("Touched stage at position: " + touch)
}
else if(touch.phase == TouchPhase.ENDED)
{
//The Touch ended (MouseUp)
}
else if(touch.phase == TouchPhase.MOVED)
{
//dragging
}
}
}
Probably your hero sprite is added to Spirte with different size than the object you assigned the touch event. You need a sprite with for example screen size and the hero and the event added to it.
Hope that help :)
The problem is when the player collides with the blackB the player doesn't stop. It slowly continues through the blackB. The IBAction is being used with a game loop. I need a way to freeze the player completely when it collides with the blackB. Any help is welcome, I am a beginner programmer. Thank you!
player and blackB are both UIImageViews
- (IBAction)right
{
direction = kright;
if (direction == kright)
{
rightMovement = CGPointMake(kMovement,0);
blockVelocity.x += rightMovement.x;
player.center = CGPointMake(player.center.x + blockVelocity.x,player.center.y);
if(CGRectIntersectsRect(player.frame, blackB.frame))
{
if(player.center.x < blackB.center.x)
{
if(blockVelocity.x > 0)
{blockVelocity.x = zero;
}
}
}
}
}
Sort of a sloppy answer, but in pseudo code:
-(IBAction)right {
if (playerCanMove==1) {
//move player
}
}
Set playerCanMove to 1 when the game loads, and set it to 0 on collision.