I'm making an app where you controll the ship's movement with a joystick, and fires a bullet with a shoot button. These two functions works great separately but if i tap the shooting button while i move the ship with the joystick, the joystick becomes uncontrolable. So what i need is that the joystick functions normally when i tap anywhere on the screen.
import SpriteKit
import GameplayKit
class GameScene: SKScene {
let player=SKSpriteNode(imageNamed: "prez")
let joystickback=SKSpriteNode(imageNamed: "0")
let joystickbutton=SKSpriteNode(imageNamed: "1")
let shootbutton=SKSpriteNode(imageNamed: "1")
var joystickinuse=false
var velocityX : CGFloat=0.0
var velocityY : CGFloat=0.0
override func didMove(to view: SKView) {
let background=SKSpriteNode(imageNamed: "back")
background.size=self.size
background.position=CGPoint(x: self.size.width/2, y: self.size.height/2)
background.zPosition=0
self.addChild(background)
//joystick back
self.joystickback.position=CGPoint(x: (self.view?.frame.width)!*0.1, y: (self.view?.frame.height)!/5)
self.joystickback.zPosition=1
//jostick butt
self.joystickbutton.position=CGPoint(x: (self.view?.frame.width)!*0.1, y: (self.view?.frame.height)!/5)
self.joystickbutton.zPosition=2
//shootingbutton
self.shootbutton.position=CGPoint(x: (self.view?.frame.width)!*0.9, y: (self.view?.frame.height)!/5)
self.shootbutton.zPosition=2
self.shootbutton.setScale(0.4)
self.ship.position=CGPoint(x: (self.view?.frame.width)!/2, y: (self.view?.frame.height)!/2)
self.ship.setScale(0.2)
self.ship.zPosition=3
self.joystickback.setScale(0.5)
self.joystickbutton.setScale(0.5)
self.addChild(shootbutton)
self.addChild(ship)
self.addChild(joystickback)
self.addChild(joystickbutton)
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
for t in touches{
let location=t.location(in: self)
if (joystickbutton.frame.contains(location)){
joystickinuse=true
}
}
}
func touchMoved(touch:UITouch){
let location=touch.location(in: self)
if (joystickinuse){
let vecktor=CGVector(dx: location.x-joystickback.position.x, dy: location.y-joystickback.position.y)
let angle=atan2(vecktor.dy, vecktor.dx)
let DistanceFromCenter=CGFloat(joystickback.frame.size.height/2)
let DistanceX=CGFloat(sin(angle-CGFloat(M_PI)/2)*DistanceFromCenter)
let DistanceY=CGFloat(cos(angle-CGFloat(M_PI)/2)*DistanceFromCenter)
if(joystickback.frame.contains(location)){
joystickbutton.position=location
}
else{
joystickbutton.position=CGPoint(x: joystickback.position.x-DistanceX, y: joystickback.position.y+DistanceY)
}
velocityX=(joystickbutton.position.x-joystickback.position.x)/10
velocityY=(joystickbutton.position.y-joystickback.position.y)/10
}
}
func firebullet(){
let bullet=SKSpriteNode(imageNamed: "rocket")
bullet.position=urhajo.position
bullet.setScale(0.2)
bullet.zPosition=1
self.addChild(bullet)
let movebullet=SKAction.moveTo(x: self.size.width+bullet.size.width, duration: 1)
let deletebullet=SKAction.removeFromParent()
let bulletsequence=SKAction.sequence([movebullet,deletebullet])
bullet.run(bulletsequence)
}
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
for t in touches{
self.touchMoved(touch: t)
}
}
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
if(joystickinuse){
movementOver()
}
}
override func touchesCancelled(_ touches: Set<UITouch>, with event: UIEvent?) {
if(joystickinuse){
movementOver()
}
}
func movementOver(){
let moveBack=SKAction.move(to: CGPoint(x: joystickback.position.x,y: joystickback.position.y), duration: TimeInterval(floatLiteral:0.1))
moveBack.timingMode = .linear
joystickbutton.run(moveBack)
joystickinuse=false
velocityY=0
velocityX=0
}
override func update(_ currentTime: TimeInterval) {
if(ship.position.x>=(self.view?.frame.width)!+urhajo.frame.width/2){
}
else{ self.ship.position.x+=velocityX
}
self.ship.position.y+=velocityY
}
}
try setting this is your Scene code
func didMove(to view: SKView) {
self.view!.isMultipleTouchEnabled = true
}
Related
I'm my game I'm using a custom SKSpriteNode which the player are going to be able to drag and drop at a position of his/hers desire.
My custom node is made of this code in file DraggableNode.swift:
class DraggableNode : SKSpriteNode {
var nodeSelected : SKNode?
init() {
let texture = SKTexture(imageNamed: "draggableNode_1")
super.init(texture: texture, color: UIColor.white, size: texture.size())
self.isUserInteractionEnabled = true
self.zPosition = 1
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
if let touch = touches.first {
let location = touch.location(in: self)
let touchedNodes = self.nodes(at: location)
for node in touchedNodes.reversed() {
nodeSelected = node
}
}
}
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
if let touch = touches.first, let node = self.nodeSelected {
let touchLocation = touch.location(in: self)
node.position = touchLocation
}
}
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
nodeSelected = nil
}
override func touchesCancelled(_ touches: Set<UITouch>, with event: UIEvent?) {
nodeSelected = nil
}
}
In my GameScene.swift I add the custom node in this way:
let node = DraggableNode()
node.position = CGPoint(x: randomX, y: randomY)
self.addChild(node)
Now, the problem is that when I start to drag the node it's all jump and is placed a total random place - sometimes even out of the screenarea.
I wonder if the problem consists of the fact that it's a custom node inherited from a SKSpriteNode?
If anyone can point me in the right direction, I'd be a happy man :-)
I am currently creating the main menu of a mobile game, and it works fine however To make it look nicer I would like to add an effect when I touch one of my SKSpriteNodes which is an image of a button. I would like it to slightly move down then back up before transitioning to the game, im having some difficulty. Currently when the button is pressed it changed scenes to the game scene.
class MainMenuScene: SKScene{
let startGame = SKSpriteNode(imageNamed: "StartButton")
override func didMove(to view: SKView) {
let background = SKSpriteNode(imageNamed: "Menu")
background.size = self.size
background.position = CGPoint(x: self.size.width/2, y:self.size.height/2)
background.zPosition = 0
self.addChild(background)
startGame.position = CGPoint(x: self.size.width/2, y: self.size.height*0.6)
startGame.zPosition = 1
startGame.name = "startButton"
self.addChild(startGame)
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
for touch: AnyObject in touches{
let pointOfTouch = touch.location(in: self)
let nodeITapped = atPoint(pointOfTouch)
if nodeITapped.name == "startButton" {
let sceneToMoveTo = GameScene(size: self.size)
sceneToMoveTo.scaleMode = self.scaleMode
let myTransition = SKTransition.fade(withDuration: 0.5)
self.view!.presentScene(sceneToMoveTo, transition: myTransition)
}
}
}
}
You could make your logic in the function touchesEnded and then you call a SKAction in your button, passing the moveToScene logic as completion.
Something like:
var shouldMoveToNewScene: Bool = False
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
for touch: AnyObject in touches{
let pointOfTouch = touch.location(in: self)
let nodeITapped = atPoint(pointOfTouch)
shouldMoveToNewScene = nodeITapped.name == "startButton" ? True : False
}
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
guard shouldMoveToNewScene, touces.count == 1 else { return }
startButton.run(myAnimation, completion: {
moveToScene()
})
}
private func moveToScene() {
//do your transition scene logic here
{
I haven't tried it yet, but hopefully you could get the idea.
If you're not familiar with SKAction you should consider follow this guide.
I am trying to make a game where you can click a ball using SpriteKit. At the moment, I can click anywhere on the screen and the ball moves up.
I want it to only move or bounce when I click the ball. What am I doing wrong?
import SpriteKit
import GameplayKit
class GameScene: SKScene {
var ball = SKSpriteNode()
var grass = SKSpriteNode()
override func didMove(to view: SKView) {
ball = (self.childNode(withName: "ball") as? SKSpriteNode)!
let border = SKPhysicsBody(edgeLoopFrom: self.frame)
border.friction = 0
border.restitution = 1
self.physicsBody = border
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
for t in touches { self.touchDown(atPoint: t.location(in: self)) }
}
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
for t in touches { self.touchUp(atPoint: t.location(in: self)) }
}
func touchDown(atPoint pos: CGPoint) {
jump()
}
func touchUp(atPoint pos: CGPoint) {
ball.texture = SKTexture(imageNamed: "football-161132_640")
}
func jump() {
ball.texture = SKTexture(imageNamed: "football-161132_640")
ball.physicsBody?.applyImpulse(CGVector(dx: Int.random(in: -5...5), dy: 80))
}
}
Multiple touches:
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
for touch in touches {
let location = touch.location(in: self)
if ball.contains(location) {
jump()
}
}
}
Single touch:
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
if let touch = touches.first {
let location = touch.location(in: self)
if ball.contains(location) {
jump()
}
}
}
My code isn't behaving the way I want it, why is the so? I don't understand what went wrong. So I'm playing around with swift, trying to transition from android to swift, I'm trying to make this simple app that draws lines, its not working as I want it, can someone please help me with what I'm doing wrong?
//
// DrawView.swift
// IOSTouch
import Foundation
import UIKit
class DrawView: UIView {
var currentLine: Line?
var finishedLines = [Line]();
//for debug
let line1 = Line(begin: CGPoint(x:50,y:50), end: CGPoint(x:100,y:100));
let line2 = Line(begin: CGPoint(x:50,y:100), end: CGPoint(x:100,y:300));
func strokeLine(line: Line){
//Use BezierPath to draw lines
let path = UIBezierPath();
path.lineWidth = 5;
path.lineCapStyle = CGLineCap.round;
path.move(to: line.begin);
path.addLine(to: line.end);
path.stroke(); //actually draw the path
}
override func draw(_ rect: CGRect) {
//draw the finished lines
UIColor.black.setStroke() //finished lines in black
for line in finishedLines{
strokeLine(line: line);
}
//for debug
strokeLine(line: line1);
strokeLine(line: line2);
//draw current line if it exists
if let line = currentLine {
UIColor.red.setStroke(); //current line in red
strokeLine(line: line);
}
}
//Override Touch Functions
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
print(#function) //for debugging
let touch = touches.first!; //get first touch event and unwrap optional
let location = touch.location(in: self); //get location in view co-ordinate
currentLine = Line(begin: location, end: location);
setNeedsDisplay(); //this view needs to be updated
}
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
//TODO
setNeedsDisplay()
}
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
//TODO
setNeedsDisplay()
}
override func touchesCancelled(_ touches: Set<UITouch>?, with event: UIEvent?) {
//TODO
}
#IBInspectable var finishedLineColor: UIColor = UIColor.black {
didSet {
setNeedsDisplay()
}
}
#IBInspectable var currentLineColor: UIColor = UIColor.red {
didSet {
setNeedsDisplay()
}
}
#IBInspectable var lineThickness: CGFloat = 10 {
didSet {
setNeedsDisplay()
}
}
}
another file
import Foundation
import CoreGraphics
struct Line {
var begin = CGPoint.zero
var end = CGPoint.zero
}
This code is works, I use it:
import UIKit
class ViewController: UIViewController {
var firstPoint: CGPoint?
var secondPoint: CGPoint?
var currentLine: CAShapeLayer?
override func viewDidLoad() {
super.viewDidLoad()
}
func addLine(fromPoint start: CGPoint, toPoint end:CGPoint) {
let line = CAShapeLayer()
let linePath = UIBezierPath()
linePath.move(to: start)
linePath.addLine(to: end)
line.path = linePath.cgPath
line.strokeColor = UIColor.black.cgColor
line.lineWidth = 3
line.lineJoin = kCALineJoinRound
self.view.layer.addSublayer(line)
}
func setCurrentLine(fromPoint start: CGPoint, toPoint end: CGPoint) {
let line = CAShapeLayer()
let linePath = UIBezierPath()
linePath.move(to: start)
linePath.addLine(to: end)
line.path = linePath.cgPath
line.strokeColor = UIColor.red.cgColor
line.lineWidth = 3
line.lineJoin = kCALineJoinRound
currentLine = line
if let current = currentLine {
self.view.layer.addSublayer(current)
}
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
firstPoint = touches.first?.location(in: self.view)
}
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
currentLine?.removeFromSuperlayer()
currentLine = nil
if let first = firstPoint, let current = touches.first?.location(in: self.view) {
setCurrentLine(fromPoint: first, toPoint: current)
}
}
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
secondPoint = touches.first?.location(in: self.view)
if let first = firstPoint, let second = secondPoint {
addLine(fromPoint: first, toPoint: second)
currentLine?.removeFromSuperlayer()
currentLine = nil
}
}
}
It should work now
override func touchesMoved(_ touches: Set, with event: UIEvent?) {
print(#function)
let touch = touches.first!
let location = touch.location(in: self);
currentLine?.end = location;
setNeedsDisplay();
}
override func touchesEnded(_ touches: Set, with event: UIEvent?) {
print(#function) //for debugging
if var line = currentLine {
let touch = touches.first!;
let location = touch.location(in: self);
line.end = location;
finishedLines.append(line);
}
currentLine = nil;
setNeedsDisplay();
}
override func touchesCancelled(_ touches: Set<UITouch>?, with event: UIEvent?) {
print(#function) //for debugging
currentLine = nil;
setNeedsDisplay();
}
I want to make the image jump by clicking on the sprite, rather than clicking the screen to make it jump.
func jump() {
Football?.texture = SKTexture(imageNamed: "Football")
Football?.physicsBody?.applyImpulse(CGVector(dx: 100, dy: 2000))
}
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
for t in touches { self.touchUp(atPoint: t.location(in: self)) }
}
func touchUp(atPoint pos: CGPoint) {
Football?.texture = SKTexture(imageNamed: "Football")
}
override func update(_ currentTime: TimeInterval) {
// Called before each frame is rendered
}
this is a really basic way of testing if the sprite is touched
BTW your variable is named Football proper nomenclature says thay you should be using lower case variable names "football"
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
if let touch = touches.first as UITouch! {
let touchLocation = touch.location(in: self)
if Football.contains(touchLocation) {
//jump code here
}
}
}