Swift: Value Of A Variable Public But Still Local? - swift

I change the value in a function and want to access the value in another function within the same class. My code:
class person{
var fieldsWidth = CGFloat()
var xPos = CGFloat()
var yPos = CGFloat()
var player = SKSpriteNode()
func addPlayer(gameScene: GameScene, x: CGFloat, y: CGFloat){
fieldsWidth = gameScene.screenWidth / CGFloat(hintergrund().fieldsX)
player = SKSpriteNode(imageNamed: "player")
player.size = CGSize(width: fieldsWidth, height: fieldsWidth)
player.position = CGPoint(x: x, y: y)
gameScene.addChild(player)
xPos = x
}
func move(gameScene: GameScene, point: CGPoint, fWidth: CGFloat){
print(xPos)
}
}
and the GameScene:
class GameScene: SKScene {
var screenWidth = CGFloat()
var screenHeight = CGFloat()
var touchLocation = CGFloat()
var fieldsWidth = CGFloat()
let player = person()
override func didMoveToView(view: SKView) {
screenWidth = self.size.width
screenHeight = self.size.height
fieldsWidth = screenWidth / CGFloat(hintergrund().fieldsX)
person().addPlayer(self, x: fieldsWidth/2, y: fieldsWidth/2)
}
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
/* Called when a touch begins */
let touch = touches.first
var point = CGPoint()
point = touch!.locationInNode(self)
player.move(self, point: point, fWidth: fieldsWidth)
}
}
Somehow the value of xPos is just local in addPlayer. How can I access the value from xPos correctly? Hopefully you can help me.

The following code runs exactly as expected for me in a XCode Version 7.1 (7B91b) playground
class person{
var yPos = CGFloat()
func function1(y: CGFloat){
yPos = y
print(yPos) //Value of yPos is 31.25; correct!
}
func function2(){
print(yPos) //Value of yPos is 0.0; wrong!??
}
}
let foo = person()
foo.function1(31.25)
foo.function2() //Outputs 31.25

I think CGFloat is 0.0 by default so the most likely cause of your error is that you call function 2 before function one in your code. The error is somewhere else.
EDIT since you posted code. I would try this (create a new player and retain it -- I am not a sprite kit expert):
class GameScene: SKScene {
var screenWidth = CGFloat()
var screenHeight = CGFloat()
var touchLocation = CGFloat()
var fieldsWidth = CGFloat()
var player = person() // SEE HERE - Variable, so that you can reassign it
override func didMoveToView(view: SKView) {
screenWidth = self.size.width
screenHeight = self.size.height
fieldsWidth = screenWidth / CGFloat(hintergrund().fieldsX)
player = person().addPlayer(self, x: fieldsWidth/2, y: fieldsWidth/2) // SEE HERE - Create new player and retain it into your scene
}
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
/* Called when a touch begins */
let touch = touches.first
var point = CGPoint()
point = touch!.locationInNode(self)
player.move(self, point: point, fWidth: fieldsWidth)
}
}
PS: The above might work but really, from what I understand you need to create a player each time didMoveToView is called. If that is the case, then instead of doing this contrived addPlayer funciton, I would make a designated initialiser for the player class. Something like (untested):
func init(scene: SKScene, x: CGFLoat, y: CGFloat) {
// ETC...
}

Related

Moving and rotating sprite with touches using SKSpriteKit and Swift 4

I am wanting my sprite "Character" to move and rotate "follow" my finger as I move it around. I had it working fine but somehow have managed to screw it up. I'm not sure what I've done but can't for the life of me figure it out.
Any help would be greatly appreciated. Im sure its something stupid that I'm just overlooking. Thanks in advance.
Mark
GameScene.swift
import SpriteKit
import GameplayKit
//MARK: ---------------Global Variables Section
var nodeType: String = String()
var characterNode = Character()
let characterImage: String = String("default_pose")
var characterTexture:SKTexture = SKTexture()
let characterSize: CGSize = CGSize(width: 64, height: 64)
let characterPosition: CGPoint = CGPoint(x: 0, y: 0)
var enemyNode = Enemy()
let enemyImage: String = String("blob1")
var enemyTexture = SKTexture()
let enemySize: CGSize = CGSize(width: 50, height: 50)
let enemyPosition: CGPoint = CGPoint(x: 150, y: 150)
class GameScene: SKScene, SKPhysicsContactDelegate {
//MARK: --------------------Class Variables Section
var affectedByGravity: Bool = false
var dynamic: Bool = true
var rotation: Bool = false
var lastUpdateTime: CFTimeInterval = 0
//MARK: --------------------DidMove to View Section
override func didMove(to view: SKView) {
var node = SKSpriteNode()
node = addNode(NodeType: "Character")
applyPhysics(physicsNode: node, nodeImage: characterImage, nodeSize: characterSize, nodeName: node.name!)
node.zPosition = 10
addChild(node)
node = addNode(NodeType: "Enemy")
applyPhysics(physicsNode: node, nodeImage: enemyImage, nodeSize: enemySize, nodeName: node.name!)
node.zPosition = 9
addChild(node)
}
//MARK: -----------------------Add Node Section
func addNode(NodeType: String) -> SKSpriteNode {
var node = SKSpriteNode()
switch NodeType {
case "Enemy":
node = enemyNode.setupNode(nodeName: "Enemy", nodeImage: "blob1", nodeSize: enemySize, nodePosition: enemyPosition)
default:
node = characterNode.setupNode(nodeName: "Player", nodeImage: "default_pose", nodeSize: characterSize, nodePosition: characterPosition)
}
return node
}
//MARK: ------------------------Physics Section
func applyPhysics(physicsNode: SKSpriteNode, nodeImage: String, nodeSize: CGSize, nodeName: String) {
let nodeTexture: SKTexture = SKTexture(imageNamed: nodeImage)
physicsNode.physicsBody = SKPhysicsBody(texture: nodeTexture, size: nodeSize)
physicsNode.physicsBody?.isDynamic = dynamic
physicsNode.physicsBody?.affectedByGravity = affectedByGravity
physicsNode.physicsBody?.allowsRotation = rotation
physicsNode.physicsBody?.categoryBitMask = 1
physicsNode.physicsBody?.contactTestBitMask = 1
physicsNode.physicsBody?.collisionBitMask = 1
}
//MARK: ------------------------Movement and Rotation Section
func moveAndRotate(sprite: Character, toPosition position: CGPoint) {
let angle = atan2(position.y - sprite.position.y, position.x - sprite.position.x)
let rotateAction = SKAction.rotate(toAngle: angle - .pi / 2, duration: 0.05, shortestUnitArc:true)
sprite.run(rotateAction)
let offsetX = position.x - (sprite.position.x)
let offsetY = position.y - (sprite.position.y)
let normal = simd_normalize(simd_double2(x: Double(offsetX), y:Double(offsetY)))
characterNode.velocity = CGVector(dx: CGFloat(normal.x) * sprite.movePointsPerSecond, dy: CGFloat(normal.y) * sprite.movePointsPerSecond)
}
//MARK: ----------------------Touches Section
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
if let touch = touches.first {
let touchLocation = touch.location(in: self)
characterNode.isMoving = true
moveAndRotate(sprite: characterNode, toPosition: touchLocation)
}
}
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
if let touch = touches.first {
let touchLocation = touch.location(in: self)
moveAndRotate(sprite: characterNode, toPosition: touchLocation)
}
}
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
characterNode.isMoving = false
}
//MARK: ------------------Update Section
override func update(_ currentTime: TimeInterval) {
let deltaTime = max(1.0/30, currentTime - lastUpdateTime)
lastUpdateTime = currentTime
update(character: characterNode, dt: deltaTime)
}
func update(character: Character, dt: CFTimeInterval) {
if characterNode.isMoving == true {
let newX = character.position.x + character.velocity.dx * CGFloat(dt)
let newY = character.position.y + character.velocity.dy * CGFloat(dt)
character.position = CGPoint(x: newX, y: newY)
}
}
}
Character.swift
import SpriteKit
import GameplayKit
class Character: SKSpriteNode {
let movePointsPerSecond: CGFloat = 150.0
var velocity = CGVector(dx: 0.0, dy: 0.0)
var isMoving = false
var node: SKSpriteNode = SKSpriteNode()
func setupNode(nodeName: String, nodeImage: String, nodeSize: CGSize, nodePosition: CGPoint) -> SKSpriteNode {
node = SKSpriteNode(imageNamed: nodeImage)
node.name = nodeName
node.position = nodePosition
return node
}
}
Your node does not move because you never assign characterNode to the node on your screen
override func didMove(to view: SKView) {
var node = SKSpriteNode()
node = addNode(NodeType: "Character")
applyPhysics(physicsNode: node, nodeImage: characterImage, nodeSize: characterSize, nodeName: node.name!)
node.zPosition = 10
addChild(node)
characterNode = node //ADD THIS LINE
node = addNode(NodeType: "Enemy")
applyPhysics(physicsNode: node, nodeImage: enemyImage, nodeSize: enemySize, nodeName: node.name!)
node.zPosition = 9
addChild(node)
}

Moving sprite with finger gesture

I'm trying to move the sprite (red dot) whenever I move my finger anywhere on the screen of the device. The following code seems to work only within a small invisible circle rather than in the whole area of the screen, meaning the sprite seems to encounter some sort of wall and doesn't go any further. Anyone can figure out why?
import SpriteKit
import GameplayKit
var positionX = CGFloat()
var positionY = CGFloat()
var newPositionX = CGFloat()
var newPositionY = CGFloat()
var redDotPosition = CGPoint()
var oldPosition = CGPoint()
var newPosition = CGPoint()
class GameScene: SKScene {
var redDot : SKSpriteNode?
var entities = [GKEntity]()
var graphs = [String : GKGraph]()
private var lastUpdateTime : TimeInterval = 0
private var label : SKLabelNode?
private var spinnyNode : SKShapeNode?
override func sceneDidLoad() {
redDot = childNode(withName: "redDot") as? SKSpriteNode
redDot?.texture = SKTexture(imageNamed: "redDot")
redDot?.position = CGPoint(x: frame.midX , y: frame.midX)
}
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
for t in touches { self.touchMoved(toPoint: t.location(in: self))
oldPosition = t.previousLocation(in: self)
let oldPositionX = oldPosition.x
let oldPositionY = oldPosition.y
newPositionX = t.location(in: self).x
newPositionY = t.location(in: self).y
deltaX = newPositionX - oldPositionX
deltaY = newPositionY - oldPositionY
redDot?.position = CGPoint(x: redDot!.position.x + deltaX , y: redDot!.position.y + deltaY)
}
}
Nevermind!
the problem lied in the fact that I had accidentally anchored my sprite to the scene, therefore it wasn't moving more than a certain amount.

How do I set it up so that only my player and an object have a physics body?

Creating a game like Doodle Jump, except for bouncing off platforms, my hero bounces off objects to collect points and progress in the game. As my hero "bounces off" the object, I set it to removeFromParent and it is working like it should. However, if my hero misses the object and accidentally hits the wall or ground, the object disappears as well which is odd because my ground doesn't have a physics body.
Here is my code for my GameScene:
import SpriteKit
var player: Player!
var ground: Ground!
var snowflake: Snowflake!
var isFingerOnPlayer = false
var gameOver = false
var playerTouched = false
var touching: Bool = false
var lastTouch: CGPoint? = nil
let xPlayerForce: CGFloat = 40
let yPlayerForce: CGFloat = 50
var touchPoint: CGPoint = CGPoint()
struct Collision {
static let player: UInt32 = 1
static let snowflake: UInt32 = 2
}
class GameScene: SKScene, SKPhysicsContactDelegate {
override func didMoveToView(view: SKView) {
player = Player()
player.position = CGPointMake(20, 150)
addChild(player)
ground = Ground()
ground.position = CGPointMake(10, -37)
addChild(ground)
player.physicsBody?.linearDamping = 0.0
player.physicsBody?.angularDamping = 500.0
player.physicsBody = SKPhysicsBody(rectangleOfSize: player.size)
player.physicsBody?.allowsRotation = false
player.physicsBody?.mass = 0
player.physicsBody?.friction = 1
player.physicsBody?.dynamic = true
physicsWorld.contactDelegate = self
physicsWorld.gravity = CGVector(dx: 0.0, dy: -3.0)
self.backgroundColor = SKColor(red: 0.15, green: 0.15, blue: 0.3, alpha: 1.0)
snowflake = Snowflake()
addChild(snowflake)
self.physicsBody = SKPhysicsBody(edgeLoopFromRect: self.frame)
}
override func touchesBegan(touches: Set<NSObject>, withEvent event: UIEvent) {
for touch: AnyObject in touches {
let touchLocation = touch.locationInNode(self)
lastTouch = touchLocation
player.physicsBody?.categoryBitMask = snowCategory
player.physicsBody?.contactTestBitMask = playerCategory
player.physicsBody?.affectedByGravity = true
player.physicsBody?.collisionBitMask = playerCategory
player.physicsBody?.usesPreciseCollisionDetection = true
}
}
func touchedPlayer() {
playerTouched = true
snowflake.removeFromParent()
player.bounceOff()
}
override func touchesMoved(touches: Set<NSObject>, withEvent event: UIEvent) {
lastTouch = nil
}
override func touchesEnded(touches: Set<NSObject>, withEvent event: UIEvent) {
lastTouch = nil
}
override func update(currentTime: NSTimeInterval) {
if let touch = lastTouch {
var xForce: CGFloat = 0.0
var yForce: CGFloat = 0.0
let xTouchOffset = (touch.x - player.position.x)
let yTouchOffset = (touch.y - player.position.y)
if xTouchOffset > 0.0 {
xForce = xPlayerForce
} else if xTouchOffset < 0.0 {
xForce = -xPlayerForce
} // else we do nothing
if yTouchOffset > 0.0 {
yForce = yPlayerForce
} else if xTouchOffset > 0.0 {
yForce = -yPlayerForce
}
// here you can choose whether you want it to push
// the player node down, using similar code from the
// above if statement
let impulseVector = CGVector(dx: xForce, dy: yForce)
player.physicsBody?.applyImpulse(impulseVector)
}
}
func didBeginContact(contact: SKPhysicsContact) {
touchedPlayer()
}
}
In spite of the fact that it's not clear what is snow flake entity.
There is a code:
self.physicsBody = SKPhysicsBody(edgeLoopFromRect: self.frame)
You have an edge around your frame.
From the description:
Creates an edge loop from a CGRect. Edges have no volume and are intended to be used to create static environments. Edges can collide with body's of volume, but not with each other.
In the method
func didBeginContact(contact: SKPhysicsContact)
use contact.contactBodyA.categoryBitMask to ignore this contact.(Should be zero).

Add sprites over a circular CGPath Swift

How can I spawn a sprite repeatedly over the coordinates of a circular path?
So I have a circular path and I want the sprite to appear every 30ยบ for example (so in that case I would end up having the same sprite 12 times). The problem is that it doesn't matter what I do I cant get it to do so. Recently I found an article were it was shown how to do a clock, I used that sample code but I'm still stuck, I don't know what to replace drawRect for or if I have any other errors.
I would appreciate any help.
import SpriteKit
import UIKit
class GameScene: SKScene {
override func didMoveToView(view: SKView) {
/* Setup your scene here */
func degree2radian(a:CGFloat)->CGFloat {
let b = CGFloat(M_PI) * a/180
return b
}
func circleCircumferencePoints(sides:Int,x:CGFloat,y:CGFloat,radius:CGFloat,adjustment:CGFloat=0)->[CGPoint] {
let angle = degree2radian(360/CGFloat(sides))
let cx = x
let cy = y
let r = radius
var i = sides
var points = [CGPoint]()
while points.count <= sides {
let xpo = cx - r * cos(angle * CGFloat(i)+degree2radian(adjustment))
let ypo = cy - r * sin(angle * CGFloat(i)+degree2radian(adjustment))
points.append(CGPoint(x: xpo, y: ypo))
i--;
}
return points
}
func pointsLocation(#x:CGFloat, #y:CGFloat, #radius:CGFloat, #sides:Int) {
let points = circleCircumferencePoints(sides,x,y,radius)
let path = CGPathCreateMutable()
for p in enumerate(points) {
CGPathMoveToPoint(path, nil, p.element.x, p.element.y)
let blueDot = SKSpriteNode(imageNamed: "arrow.png")
blueDot.position.x = p.element.x
blueDot.position.y = p.element.y
addChild(blueDot)
CGPathCloseSubpath(path)
class View: UIView {
override func drawRect(rect: CGRect)
let rad = CGRectGetWidth(rect)/3.5
pointsLocation(x: CGRectGetMidX(rect), y: CGRectGetMidY(rect), radius: rad, sides: 8)
}
override func touchesBegan(touches: NSSet, withEvent event: UIEvent) {
/* Called when a touch begins */
}
override func update(currentTime: CFTimeInterval) {
/* Called before each frame is rendered */
}
}
You code has a lot of syntax errors. That's why it doesn't work. After correcting the errors, the logic you used works.
class GameScene: SKScene,SKPhysicsContactDelegate {
override func didMoveToView(view: SKView) {
pointsLocation(x: 100, y: 100, radius: 50, sides: 12)
}
func degree2radian(a:CGFloat)->CGFloat {
let b = CGFloat(M_PI) * a/180
return b
}
func circleCircumferencePoints(sides:Int,x:CGFloat,y:CGFloat,radius:CGFloat,adjustment:CGFloat=0)->[CGPoint] {
let angle = degree2radian(360/CGFloat(sides))
let cx = x
let cy = y
let r = radius
var i = sides
var points = [CGPoint]()
while points.count <= sides {
let xpo = cx - r * cos(angle * CGFloat(i)+degree2radian(adjustment))
let ypo = cy - r * sin(angle * CGFloat(i)+degree2radian(adjustment))
points.append(CGPoint(x: xpo, y: ypo))
i--;
}
return points
}
func pointsLocation(#x:CGFloat, y:CGFloat, radius:CGFloat, sides:Int) {
let points = circleCircumferencePoints(sides,x: x,y: y,radius: radius)
let path = CGPathCreateMutable()
for p in enumerate(points) {
let blueDot = SKSpriteNode(imageNamed: "arrow.png")
blueDot.position.x = p.element.x
blueDot.position.y = p.element.y
addChild(blueDot)
}
}
override func touchesBegan(touches: NSSet, withEvent event: UIEvent) {
/* Called when a touch begins */
}
override func update(currentTime: CFTimeInterval) {
/* Called before each frame is rendered */
}
}

sprite-kit collision not working

Hi everyone I am trying to make a basic line drawing test with xcode 6 using swift. But my collision system isn't working at all. This is the code of my collision system:
func drawLines() {
CGPathMoveToPoint(path, nil, location.x, location.y)
CGPathAddLineToPoint(path, nil, self.frame.size.width/2, self.frame.size.height / 5)
drawLine.append(SKShapeNode())
drawLine[index] = SKShapeNode()
line.append(drawLine[index])
line[index].path = path
line[index].strokeColor = UIColor.redColor()
line[index].lineWidth = 5.0
line[index].physicsBody = SKPhysicsBody(rectangleOfSize: line[index].frame.size)
line[index].physicsBody.dynamic = false
line[index].zPosition = 1
self.addChild(line[index])
index++
}
I can't figure out the problem but I think I made a mistake in that piece of code.
Here is the rest of my code:
class GameScene: SKScene {
var line: [SKShapeNode] = []
var drawLine: [SKShapeNode] = []
var path = CGPathCreateMutable()
var touch: UITouch!
var location:CGPoint!
var index = 0
let player = SKSpriteNode(imageNamed: "player")
override func didMoveToView(view: SKView) {
player.position = CGPointMake(self.frame.size.width / 2, self.frame.size.height / 2)
player.physicsBody = SKPhysicsBody(rectangleOfSize: player.size)
player.physicsBody.dynamic = true
self.physicsWorld.gravity = CGVectorMake(0,-1)
player.zPosition = 1
self.addChild(player)
}
override func touchesBegan(touches: NSSet, withEvent event: UIEvent) {
/* Called when a touch begins */
touch = touches.anyObject() as UITouch!
location = touch.locationInNode(self)
drawLines()
}
func drawLines() {
CGPathMoveToPoint(path, nil, location.x, location.y)
CGPathAddLineToPoint(path, nil, self.frame.size.width/2, self.frame.size.height / 5)
drawLine.append(SKShapeNode())
drawLine[index] = SKShapeNode()
line.append(drawLine[index])
line[index].path = path
line[index].strokeColor = UIColor.redColor()
line[index].lineWidth = 5.0
line[index].physicsBody = SKPhysicsBody(rectangleOfSize: line[index].frame.size)
line[index].physicsBody.dynamic = false
line[index].zPosition = 1
self.addChild(line[index])
index++
}
override func update(currentTime: CFTimeInterval) {
/* Called before each frame is rendered */
}
-------------------EDIT -------------------
I now use this line of code for the physics of my line:
line[index].physicsBody = SKPhysicsBody(rectangleOfSize:
CGSizeMake(line[index].frame.width*2 ,line[index].frame.height*2))
This problem here I think is that when I draw my line at an angle the rectangle doesn't turn with it so my rectangle ends up way to big.
As far as I know, touchesBegan returns an NSSet of touches (an array of touches roughly saying), therefore you would want to loop through them or access a specific touch by its index. I would recommend looping through touches like the following code.
override func touchesBegan(touches:NSSet) {
for touch: AnyObject in touches {
var location:CGPoint = touch.locationInNode(self.scene)
performSomethingCrazy(withLocationAt: location)
}
}
Enjoy.