If statements and strings error - swift

I Have
if rockNamesArray == "rock2" {
let firstPos: CGFloat = 300.0
UIView.animateWithDuration(3.0, animations: { () -> Void in
self.mrock.frame = CGRectMake(167, 600, CGFloat(self.mrock.bounds.size.width), CGFloat(self.mrock.bounds.size.height))
})}
as well as
var rockNamesArray:[String ] = ["bird", "rock2", "rock3"]
var rockpos = Int(arc4random_uniform(UInt32(3)))
var firstrockString:String = rockNamesArray[rockpos]
But its telling me I can't use "==" for the if statement. What would I use in place for it. "rock2" is a string

If you want to check if "rock2" is inside the array:
if contains(rockNamesArray, "rock2") {
// Do your stuff
}
Or if you want to check a certain index of the array and compare it to "rock2" with n being the index:
var rockNamesArray:[String ] = ["bird", "rock2", "rock3"]
var rockpos = Int(arc4random_uniform(UInt32(3)))
if rockNamesArray[rockpos] == "rock2" {
let firstPos: CGFloat = 300.0
UIView.animateWithDuration(3.0) {
self.mrock.frame = CGRectMake(167, 600, CGFloat(self.mrock.bounds.size.width), CGFloat(self.mrock.bounds.size.height))
}
}

Related

How to convert NSData to custom object array in swift

I convert the DrawObj Array (custom object array) to NSData and save it to cache directory use NSFileManager to save
then I use [NSData dataWithContentsOfFile:fileURL options:0 error:&err] to get NSData from filesystem
Now I try to restore the NSData to DrawObj Array ([DrawObjs])
How to do ?
I have try to use
extension Data {
func elements <T> () -> [T] {
return withUnsafeBytes {
Array(UnsafeBufferPointer<T>(start: $0, count: count/MemoryLayout<T>.size))
}
}
}
if let objs:[DrawObj] = self.readFromFile()?.elements() {
self.drawObjs = objs
}
but is crash
update show DrawObj model
class DrawObj{
var id : String!;
var height : CGFloat = 0.0;
var width : CGFloat = 0.0;
var points:[CGPoint] = [];
var oPoints:[CGPoint] = [];
var angle : CGFloat = 0.0;
var scaleX : CGFloat = 1.0;
var oStartPoint:CGPoint = CGPoint.zero
var oEndPoint:CGPoint = CGPoint.zero
var scaleY : CGFloat = 1.0;
var currentHeight : CGFloat = 0.0;
var currentWidth : CGFloat = 0.0;
var radius : CGFloat = 0.0;
var drawPara : DrawParam = DrawParam();
var text : String = "";
var isFlip:Bool = false;
var url:String = "";
var image:UIImage?
var fontSize : CGFloat = 16
var originX:String = "left"
var originY:String = "top"
var pathPoint:[PathPoint] = []
var stokeDashArray:[Int] = []
var beizerPath:UIBezierPath?
var nickName:String = ""
init(id: String ){
self.id = id;
}
init( id:String , drawType:DrawType , fillColor : DrawColor , stokeColor : DrawColor , lineWidth : DrawStokeWidth ) {
self.id = id;
self.drawPara.drawType = drawType
self.drawPara.fillColor = fillColor
self.drawPara.stokeColor = stokeColor
self.drawPara.lineWidth = lineWidth
}
}

UICollectionView is running before the data load from Web Api

UICollectionView is running before data(finalAllItems) is populated from web api. I should show UICollectionView with data. I have added below line end of the convertReturnsInToWantedType function. But it did not fix the problem. outletForTheCollectionView.reloadData() How can I show data in UICollectionView?
import UIKit
class HomeViewController: UIViewController {
#IBOutlet weak var outletForTheCollectionView: UICollectionView!
#IBOutlet weak var outletForThePageController: UIPageControl!
var howmanyWords : Int = 0
var dataList : [[String:Any]]?
var finalAllItems = [AllItems]()
override func viewDidLoad() {
super.viewDidLoad()
loadVerbs()
outletForTheCollectionView.delegate = self
outletForTheCollectionView.dataSource = self
let xib = UINib(nibName: "CustomCell", bundle: nil)
self.outletForTheCollectionView.register(xib, forCellWithReuseIdentifier: "ViewCellID")
}
func loadVerbs ()
{
let urlString = "http://somelink/english/vocabularyVerbs.ashx"
let url = URL(string: urlString)
let request = URLRequest(url: url!, cachePolicy: .reloadIgnoringLocalAndRemoteCacheData, timeoutInterval: 30.0)
let task = URLSession.shared.dataTask(with: request)
{
(data, response, error) in
if let result = try? JSONSerialization.jsonObject(with: data!, options: .mutableContainers) as? [[String:Any]]
{
DispatchQueue.main.async
{
self.dataList = result
self.convertReturnsInToWantedType()
}
}
}
task.resume()
}
func convertReturnsInToWantedType()
{
// I populate finalAllItems array of dictionary object in here.
// Code might be not well-written in this scope
var datalistCount = dataList!.count
howmanyWords = datalistCount
datalistCount = datalistCount - 1
let nullLabel : String = "variable is coming null from web api"
for n in 0...datalistCount {
let oneItem = self.dataList![n]
var itemWord : String = ""
if let itemWordTemp = oneItem["itemWord"] as? String
{
itemWord = itemWordTemp
}
else
{
itemWord = nullLabel
}
var itemMeaning : String = ""
if let itemMeaningTemp = oneItem["itemMeaning"] as? String
{
itemMeaning = itemMeaningTemp
}
else
{
itemMeaning = nullLabel
}
var itemVerb2Form : String = ""
if let itemVerb2FormTemp = oneItem["itemVerb2Form"] as? String
{
itemVerb2Form = itemVerb2FormTemp
}
else
{
itemVerb2Form = nullLabel
}
var itemVerb3Form : String = ""
if let itemVerb3FormTemp = oneItem["itemVerb3Form"] as? String
{
itemVerb3Form = itemVerb3FormTemp
}
else
{
itemVerb3Form = nullLabel
}
var itemDefination : String = ""
if let itemDefinationTemp = oneItem["itemDefination"] as? String
{
itemDefination = itemDefinationTemp
}
else
{
itemDefination = nullLabel
}
var itemUsingInSentence : String = ""
if let itemUsingInSentenceTemp = oneItem["itemUsingInSentence"] as? String
{
itemUsingInSentence = itemUsingInSentenceTemp
}
else
{
itemUsingInSentence = nullLabel
}
var itemThisWordIsRelatedWithThatWord : String = ""
if let itemThisWordIsRelatedWithThatWordTemp = oneItem["itemThisWordIsRelatedWithThatWord"] as? String
{
itemThisWordIsRelatedWithThatWord = itemThisWordIsRelatedWithThatWordTemp
}
else
{
itemThisWordIsRelatedWithThatWord = nullLabel
}
var itemTrapReply1 : String = ""
if let itemTrapReply1Temp = oneItem["itemTrapReply1"] as? String
{
itemTrapReply1 = itemTrapReply1Temp
}
else
{
itemTrapReply1 = nullLabel
}
var itemTrapReply2 : String = ""
if let itemTrapReply2Temp = oneItem["itemTrapReply2"] as? String
{
itemTrapReply2 = itemTrapReply2Temp
}
else
{
itemTrapReply2 = nullLabel
}
var itemTrapReply3 : String = ""
if let itemTrapReply3Temp = oneItem["itemTrapReply3"] as? String
{
itemTrapReply3 = itemTrapReply3Temp
}
else
{
itemTrapReply3 = nullLabel
}
var itemTrapReply4 : String = ""
if let itemTrapReply4Temp = oneItem["itemTrapReply4"] as? String
{
itemTrapReply4 = itemTrapReply4Temp
}
else
{
itemTrapReply4 = nullLabel
}
finalAllItems.append(
AllItems(
itemWord:itemWord,
itemWordMeaning: itemMeaning,
itemVerb2Form: itemVerb2Form,
itemVerb3Form: itemVerb3Form,
itemDefination: itemDefination,
itemUsingInSentence: itemUsingInSentence,
itemThisWordIsReleatedWithThatWord: itemThisWordIsRelatedWithThatWord,
itemTrapReply1: itemTrapReply1,
itemTrapReply2: itemTrapReply2,
itemTrapReply3: itemTrapReply3,
itemTrapReply4: itemTrapReply4
)
)
} // FOR LOOP ENDS
} // convertReturnsInToWantedType ENDS
override var prefersStatusBarHidden: Bool {
return true
}
}
extension HomeViewController: UICollectionViewDelegate, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout
{
func numberOfSections(in collectionView: UICollectionView) -> Int {
return 1
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
//return self.dataList.count
return self.howmanyWords
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = outletForTheCollectionView.dequeueReusableCell(withReuseIdentifier: "ViewCellID", for: indexPath) as! CustomCell
cell.outletForTheViewInCell.backgroundColor = .lightGray
// word label
cell.outletForTheLabelInCell.text = self.finalAllItems[indexPath.row].itemWord
print(finalAllItems[indexPath.row].itemWord)
var allRepliesArray =
[
self.finalAllItems[indexPath.row].itemTrapReply1,
self.finalAllItems[indexPath.row].itemTrapReply2,
self.finalAllItems[indexPath.row].itemTrapReply3,
self.finalAllItems[indexPath.row].itemTrapReply4,
self.finalAllItems[indexPath.row].itemWordMeaning
]
print(allRepliesArray)
print(allRepliesArray.count)
let randomIndex1 = Int(arc4random_uniform(UInt32(allRepliesArray.count)))
cell.btnOptionA.setTitle(allRepliesArray[randomIndex1], for: .normal)
allRepliesArray = allRepliesArray.filter {$0 != allRepliesArray[randomIndex1]}
print(allRepliesArray.count)
let randomIndex2 = Int(arc4random_uniform(UInt32(allRepliesArray.count)))
cell.btnOptionB.setTitle(allRepliesArray[randomIndex2], for: .normal)
allRepliesArray = allRepliesArray.filter {$0 != allRepliesArray[randomIndex2]}
let randomIndex3 = Int(arc4random_uniform(UInt32(allRepliesArray.count)))
cell.btnOptionC.setTitle(allRepliesArray[randomIndex3], for: .normal)
allRepliesArray = allRepliesArray.filter {$0 != allRepliesArray[randomIndex3]}
let randomIndex4 = Int(arc4random_uniform(UInt32(allRepliesArray.count)))
cell.btnOptionD.setTitle(allRepliesArray[randomIndex4], for: .normal)
allRepliesArray = allRepliesArray.filter {$0 != allRepliesArray[randomIndex4]}
cell.btnOptionE.setTitle(allRepliesArray[0], for: .normal)
cell.correctReply = self.correctAnswerArray[indexPath.row]
print("cevapDogruMu: \(cevapDogruMu)")
cell.dismiss = { [weak self] str in
//Here.
if str == "true"
{
cell.outletForTheViewInCell.backgroundColor = .green
}
else
{
cell.outletForTheViewInCell.backgroundColor = .red
}
}
return cell
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
let screenSize = UIScreen.main.bounds.size
return screenSize
}
func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
let index = self.outletForTheCollectionView.contentOffset.x / self.outletForTheCollectionView.frame.size.width
self.outletForThePageController.currentPage = Int(index)
//self.outletForThePageController.numberOfPages = dataList.count
self.outletForThePageController.numberOfPages = self.howmanyWords
}
class SnappingCollectionViewLayout: UICollectionViewFlowLayout {
override func targetContentOffset(forProposedContentOffset proposedContentOffset: CGPoint, withScrollingVelocity velocity: CGPoint) -> CGPoint {
guard let collectionView = collectionView else { return super.targetContentOffset(forProposedContentOffset: proposedContentOffset, withScrollingVelocity: velocity) }
var offsetAdjustment = CGFloat.greatestFiniteMagnitude
let horizontalOffset = proposedContentOffset.x + collectionView.contentInset.left
let targetRect = CGRect(x: proposedContentOffset.x, y: 0, width: collectionView.bounds.size.width, height: collectionView.bounds.size.height)
let layoutAttributesArray = super.layoutAttributesForElements(in: targetRect)
layoutAttributesArray?.forEach({ (layoutAttributes) in
let itemOffset = layoutAttributes.frame.origin.x
if fabsf(Float(itemOffset - horizontalOffset)) < fabsf(Float(offsetAdjustment)) {
offsetAdjustment = itemOffset - horizontalOffset
}
})
return CGPoint(x: proposedContentOffset.x + offsetAdjustment, y: proposedContentOffset.y)
}
}
} // extension ENDS
extension MutableCollection {
/// Shuffles the contents of this collection.
mutating func shuffle() {
let c = count
guard c > 1 else { return }
for (firstUnshuffled, unshuffledCount) in zip(indices, stride(from: c, to: 1, by: -1)) {
// Change `Int` in the next line to `IndexDistance` in < Swift 4.1
let d: Int = numericCast(arc4random_uniform(numericCast(unshuffledCount)))
let i = index(firstUnshuffled, offsetBy: d)
swapAt(firstUnshuffled, i)
}
}
}
extension Sequence {
/// Returns an array with the contents of this sequence, shuffled.
func shuffled() -> [Element] {
var result = Array(self)
result.shuffle()
return result
}
}
This is an example for the JSON return
[
{
"itemWord": "surpass",
"itemMeaning": "lorem",
"itemVerb2Form": "surpassVerb2",
"itemVerb3Form": "surpassVerb3",
"itemDefination": null,
"itemUsingInSentence": null,
"itemThisWordIsRelatedWithThatWord": null,
"itemTrapReply1": "lorem",
"itemTrapReply2": "lorem",
"itemTrapReply3": "lorem",
"itemTrapReply4": "lorem"
},
{
"itemWord": "affect",
"itemMeaning": "lorem",
"itemVerb2Form": "affectVerb2",
"itemVerb3Form": "affectVerb3",
"itemDefination": null,
"itemUsingInSentence": null,
"itemThisWordIsRelatedWithThatWord": null,
"itemTrapReply1": "lorem",
"itemTrapReply2": "lorem",
"itemTrapReply3": "lorem",
"itemTrapReply4": "lorem"
}
]
AllItems.swift file
import Foundation
class AllItems
{
var itemWord : String = "" // 1
var itemWordMeaning : String = "" // 2
var itemVerb2Form : String = "" // 3
var itemVerb3Form : String = "" // 4
var itemDefination : String = "Verb" // 5
var itemUsingInSentence: String = "" // 6
var itemThisWordIsReleatedWithThatWord : String = "" // 7
var itemTrapReply1 : String = ""
var itemTrapReply2 : String = ""
var itemTrapReply3 : String = ""
var itemTrapReply4 : String = ""
init(
itemWord:String,
itemWordMeaning:String,
itemVerb2Form:String,
itemVerb3Form:String,
itemDefination: String,
itemUsingInSentence:String,
itemThisWordIsReleatedWithThatWord: String,
itemTrapReply1: String,
itemTrapReply2: String,
itemTrapReply3: String,
itemTrapReply4: String)
{
self.itemWord = itemWord //1
self.itemWordMeaning = itemWordMeaning //2
self.itemVerb2Form = itemVerb2Form // 3
self.itemVerb3Form = itemVerb3Form // 4
self.itemDefination = itemDefination // 5
self.itemUsingInSentence = itemUsingInSentence // 6
self.itemThisWordIsReleatedWithThatWord = itemThisWordIsReleatedWithThatWord // 7
self.itemTrapReply1 = itemTrapReply1 // 8
self.itemTrapReply2 = itemTrapReply2 // 9
self.itemTrapReply3 = itemTrapReply3 // 10
self.itemTrapReply4 = itemTrapReply4 // 11
}
}
Data request from API is asynchronous. To solve your problem you can call the reloadData function when your finalAllItems variable is setted.
var finalAllItems = [AllItems]() {
didSet {
outletForTheCollectionView.reloadData()
}
}
I'm not sure, but I think you're not setting up the values in your cells.
Right now you're just seeing a bunch of gray cells, right? Maybe just one?
In the func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell, you should set up the values to be shown in the cells before returning them. All you're doing right now is setting up the background color, nothing else.
You should do something like cell.setUpData(finalAllItems[indexPath.row]) inside that function, and then in the cell class you have to create the setUpData method and do whatever you want to do with your data in the cell.
And yes, you should call outletForTheCollectionView.reloadData() every time you want to show new data.

SpriteKit enemy sprites skip after contact with player

I have made a game where the basic idea is that a player sprite has to either collide with or avoid falling enemy sprites depending on the letter assigned to the enemy. The problem is that when my player makes contact with a sprite, the surrounding enemies skip forward significantly. This makes the game too hard to play because there isn't enough time for the player to move out of the way of oncoming enemy sprites. This happens on the device and the simulator.
To see what I mean, look at this brief video. You can see the lag at 00:06 and 00:013: https://www.dropbox.com/s/8pp66baxc9uhy26/SimulatorScreenSnapz002.mov?dl=0
Here is my code for player and enemy contact:
class GameplaySceneClass: SKScene, SKPhysicsContactDelegate {
private var player:Player?
private var center = CGFloat()
private var canMove = false, moveLeft = false
private var itemController = ItemController()
private var scoreLabel: SKLabelNode?
private var wordLabel: SKLabelNode?
private var score = 0
private var theWord = ""
private var vowelPressed = false
let correct = SoundSFX("correct.wav")
let wrong = SoundSFX("nomatch.wav")
let explosion = SoundSFX("explosion.wav")
var arrayOfStrings: [String]?
var theCheckedWord = ""
var currentCount = 0
var itemsArray = [String]()
var partialExists = false
var characterScore = 0
var onePointLetters = [12, 14, 18, 19, 20]
var twoPointLetters = [4, 7]
var threePointLetters = [2, 3, 13, 16]
var fourPointLetters = [6, 8, 22, 23, 25]
var fivePointLetters = [11]
var eightPointLetters = [10, 24]
var tenPointLetters = [17, 26]
var letter = 0
var scoreArray = [Int]()
var matchingTerms = [String]()
var gravity:CGFloat = -0.35
var result = CGSize()
let synth = AVSpeechSynthesizer()
var myUtterance = AVSpeechUtterance(string:"")
override func didMove(to view: SKView) {
SoundEngine.shared.backgroundMusicVolume = 1.0
SoundEngine.shared.playBackgroundMusic("Jungle Audio-1.m4a", loop: true)
initializeGame()
}
override func update(_ currentTime: TimeInterval) {
managePlayer()
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
for touch in touches {
let location = touch.location (in: self)
if atPoint(location).name == "LetterA" {
print ("Letter A pressed")
vowelPressed = true
theWord = theWord + "A"
wordLabel?.text = theWord
if theWord.characters.count >= 3 {
checkWord()
}
vowelPressed = false
}
else if atPoint(location).name == "LetterE" {
print ("Letter E pressed")
vowelPressed = true
theWord = theWord + "E"
wordLabel?.text = theWord
if theWord.characters.count >= 3 {
checkWord()
}
vowelPressed = false
}
else if atPoint(location).name == "LetterI" {
print ("Letter I pressed")
vowelPressed = true
theWord = theWord + "I"
wordLabel?.text = theWord
if theWord.characters.count >= 3 {
checkWord()
}
vowelPressed = false
}
else if atPoint(location).name == "LetterO" {
print ("Letter O pressed")
vowelPressed = true
theWord = theWord + "O"
wordLabel?.text = theWord
if theWord.characters.count >= 3 {
checkWord()
}
vowelPressed = false
}
else if atPoint(location).name == "LetterU" {
print ("Letter U pressed")
vowelPressed = true
theWord = theWord + "U"
wordLabel?.text = theWord
if theWord.characters.count >= 3 {
checkWord()
}
vowelPressed = false
}
else if atPoint(location).name == "Pause" {
showPauseAlert()
}
else if atPoint(location).name == "delete" {
theWord = ""
theCheckedWord = ""
wordLabel?.text = theWord
}
else {
if location.x > center && !vowelPressed {
moveLeft = false
}
else if location.x < center && !vowelPressed {
moveLeft = true
}
canMove = true
}
}
}
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
canMove = false
}
func didBegin(_ contact: SKPhysicsContact) {
if !gamePaused {
var firstBody = SKPhysicsBody()
var secondBody = SKPhysicsBody()
if contact.bodyA.node?.name == "Player" {
firstBody = contact.bodyA
secondBody = contact.bodyB
}
else {
firstBody = contact.bodyB
secondBody = contact.bodyA
}
if firstBody.node?.name == "Player" && secondBody.node?.name == "Tile" {
letter = secondBody.node?.userData?.value(forKey:"key") as! Int
print ("The value of letter is \(letter)")
var letterCode = String(describing: letter)
var letterValue = Int(letterCode)
var finalLetterValue = letterValue!+64
var ASCIICode = Character(UnicodeScalar(finalLetterValue)!)
var letterString = String(describing:ASCIICode)
theWord = theWord + letterString
print (theWord)
if onePointLetters.contains(letter) {
characterScore += 1
}
else if twoPointLetters.contains(letter) {
characterScore += 2
}
else if threePointLetters.contains(letter) {
characterScore += 3
}
else if fourPointLetters.contains(letter) {
characterScore += 4
}
else if fivePointLetters.contains(letter) {
characterScore += 5
}
else if eightPointLetters.contains(letter) {
characterScore += 8
}
else if tenPointLetters.contains(letter) {
characterScore += 10
}
wordLabel?.text = theWord
theCheckedWord = theWord.lowercased()
print ("The checked word is \(theCheckedWord)")
checkWord()
secondBody.node?.removeFromParent()
}
if firstBody.node?.name == "Player" && secondBody.node?.name == "Bomb" {
explosion.play()
firstBody.node?.removeFromParent()
secondBody.node?.removeFromParent()
theWord = ""
score = 0
scoreLabel?.text = String(score)
var delayTimer = SKAction.wait(forDuration:1)
run (delayTimer)
restartGame()
}
}
}
private func initializeGame() {
do {
// This solution assumes you've got the file in your bundle
if let path = Bundle.main.path(forResource: "en", ofType: "txt"){
let data = try String(contentsOfFile:path, encoding: String.Encoding.utf8)
arrayOfStrings = data.components(separatedBy: "\n")
}
} catch let err as NSError {
// do something with Error
print(err)
}
physicsWorld.contactDelegate = self
physicsWorld.gravity = CGVector(dx:0,dy:gravity)
player = childNode(withName: "Player") as? Player!
player?.initializePlayer()
player?.position = CGPoint(x:0, y: -420)
scoreLabel = childNode(withName: "ScoreLabel") as? SKLabelNode!
scoreLabel?.text = String(score)
wordLabel = childNode(withName:"WordLabel") as? SKLabelNode!
wordLabel?.text = ""
center = self.frame.size.width/self.frame.size.height
var spawnBlocks = SKAction.repeatForever(SKAction.sequence([SKAction.wait(forDuration:1),SKAction.run(spawnItems)]))
var removeBlocks = SKAction.repeatForever(SKAction.sequence([SKAction.wait(forDuration:1),SKAction.run(removeItems)]))
if gamePaused == true {
self.scene?.isPaused = true
}
self.run(spawnBlocks)
self.run(removeBlocks)
}
private func checkWord() {
theCheckedWord = theWord.lowercased()
if (arrayOfStrings?.contains(theCheckedWord))! {
print ("Yes! \(theCheckedWord) is a word")
correct.play()
print ("The current value of score is \(score)")
score += characterScore
print ("Current gravity setting is \(gravity)")
scoreLabel?.text = String(score)
characterScore = 0
matchingTerms = (arrayOfStrings?.filter({$0.hasPrefix(theCheckedWord)
}))!
if matchingTerms.count == 1 {
characterScore = 0
print ("Current gravity setting is \(gravity)")
theWord = ""
theCheckedWord = ""
wordLabel?.text = ""
}
}
else if !(arrayOfStrings?.contains(theCheckedWord))! {
matchingTerms = (arrayOfStrings?.filter({$0.hasPrefix(theCheckedWord)
}))!
if matchingTerms.count == 0 {
wrong.play()
characterScore = 0
if score >= 5 {
score -= 5
}
theWord = ""
theCheckedWord = ""
wordLabel?.text = ""
}
}
}
Here is my code for the enemies:
import SpriteKit
struct ColliderType {
static let PLAYER: UInt32 = 0
static let TILE_AND_BOMB: UInt32 = 1;
}
public var bounds = UIScreen.main.bounds
public var width = bounds.size.width
public var height = bounds.size.height
class ItemController {
private var minX = CGFloat(-(width/2)), maxX = CGFloat(width/2)
private var vowelNumbers = [1, 5, 9, 15, 21]
func spawnItems() -> SKSpriteNode {
let item: SKSpriteNode?
if Int(randomBetweenNumbers(firstNum: 0, secondNum: 10)) > 7 {
item = SKSpriteNode(imageNamed: "Bomb")
item!.name = "Bomb"
item!.setScale(0.6)
item!.physicsBody = SKPhysicsBody(circleOfRadius: item!.size.height / 2)
print ("The value of width is \(width)")
} else {
var num = Int(randomBetweenNumbers(firstNum: 1, secondNum: 26))
if vowelNumbers.contains(num) {
num = num + 1
}
item = SKSpriteNode(imageNamed: "Tile \(num)")
item?.userData = NSMutableDictionary()
item!.name = "Tile"
item!.userData!.setValue(num, forKey:"key")
item!.zRotation = 0
item!.setScale(0.9)
item!.physicsBody = SKPhysicsBody(circleOfRadius: item!.size.height / 2)
if gamePaused == true {
item!.isPaused = true
}
else {
item!.isPaused = false
}
}
item!.physicsBody?.categoryBitMask = ColliderType.TILE_AND_BOMB;
item!.physicsBody?.isDynamic = true
item!.zPosition = 3
item!.anchorPoint = CGPoint(x: 0.5, y: 0.5)
item!.position.x = randomBetweenNumbers(firstNum: minX, secondNum: maxX)
item!.position.y = 600
return item!
}
func randomBetweenNumbers(firstNum: CGFloat, secondNum: CGFloat) -> CGFloat {
return CGFloat(arc4random()) / CGFloat(UINT32_MAX) * abs(firstNum - secondNum) + min(firstNum, secondNum);
}
}
And here is my code for the player:
import SpriteKit
class Player: SKSpriteNode {
private var minX = CGFloat(-300), maxX = CGFloat(300)
func initializePlayer() {
name = "Player"
physicsBody = SKPhysicsBody(circleOfRadius: size.height/2)
physicsBody?.affectedByGravity = false
physicsBody?.isDynamic = false
physicsBody?.categoryBitMask = ColliderType.PLAYER
physicsBody?.contactTestBitMask = ColliderType.TILE_AND_BOMB
}
func move(left:Bool){
if left {
position.x -= 15
if position.x < minX {
position.x = minX
}
}
else {
position.x += 15
if position.x > maxX {
position.x = maxX
}
}
}
}
Consider calling the checkWord() method from an SKAction:
let checkWordsAction = SKAction.run() {
[weak self] in
self?.checkWord()
}
self.run(checkWordsAction)
That way, if your array is too big, the code will not get interrupted because you are walking it to check for your word.
Also I'm not sure of what you are trying to do with the wait action at the end of the didBegin(contact:) method, when you are colliding with bombs. If you are trying to wait for 1 second before restarting the game, then keep in mind that calling the wait action the way you do will not pause your code. Actually it will simply put the scene on idle for 1 second and restart the game in the background. If that is the intended effect, it's ok, but you might be better using the run(_:completion:) method instead and call restartGame() from the completion closure:
let waitAction = SKAction.wait(1)
self.run(waitAction) { [weak self] in
self?.restartGame()
}
Hope this helps!
In didBegin(_ contact: SKPhysicsContact), you create two physics bodies in:
var firstBody = SKPhysicsBody()
var secondBody = SKPhysicsBody()
Maybe the lag is created because you create two new physics bodies. What if you don't create the physics bodies, but just create references to existing ones? I haven't tested this, but maybe try:
let firstBody: SKPhysicsBody
let secondBody: SKPhysicsBody
if contact.bodyA.node?.name == "Player" {
firstBody = contact.bodyA
secondBody = contact.bodyB
}
else {
firstBody = contact.bodyB
secondBody = contact.bodyA
}

Populating a generator. Is it possible?

I have a generator that generates a circle(SKShapeNode) every 2 seconds from the y-axis. (Moves up). I would like to know if it is possible to populate this generator uniformly(every x number of points.
Here is my code for said generator:
class CircleGen: SKShapeNode {
var circles = [WhiteCircles]()
var circleTracker = [WhiteCircles]()
var generationTimer: NSTimer!
var circ: WhiteCircles!
func generateCircles() {
for var i = 0; i < 4; i++ {
var scale: CGFloat
let rand = arc4random_uniform(10)
if rand == 0 {
scale = -15.0
} else {
scale = 15.0
}
let circle = WhiteCircles()
circle.position.x = lineGen.position.x
circle.physicsBody?.affectedByGravity = false
circle.position.y = 35
self.circles.append(circle)
circleTracker.append(circle)
foregroundNode.addChild(circle)
}
}
func startGeneratingEvery(seconds: NSTimeInterval) {
let callGenerateAction = SKAction.runBlock { () -> Void in
self.generateCircles()
}
let waitOneSecond = SKAction.waitForDuration(seconds)
let sequenceAction = SKAction.sequence([callGenerateAction, waitOneSecond])
let circleGenerateAction = SKAction.repeatActionForever(sequenceAction)
self.runAction(circleGenerateAction, withKey: "generateCircles")
}
}
Will post more code if necessary. Thank you in advance.

How can I sort array with two kind of objects in Swift?

This is my method when I sort elements by position property. Both DBSet and DBItem have that property.
#objc(DBCategory)
class DBCategory: NSManagedObject {
#NSManaged var identifier: String
#NSManaged var items: Set<DBItem>
#NSManaged var sets: Set<DBSet>
}
And this is how I use it
private var elements = [AnyObject]()
private func prepareElements() {
elements.removeAll(keepCapacity: false)
if let items = currentCategory?.items {
for item in items {
elements.append(item)
}
}
if let sets = currentCategory?.sets {
for set in sets {
elements.append(set)
}
}
elements.sort {
var previousPosition = 0
var currentPosition = 0
if let set = $0 as? DBSet {
previousPosition = Int(set.position)
}
if let item = $0 as? DBItem {
previousPosition = Int(item.position)
}
if let set = $1 as? DBSet {
currentPosition = Int(set.position)
}
if let item = $1 as? DBItem {
currentPosition = Int(item.position)
}
return previousPosition < currentPosition
}
}
position is type of Int16
How can I simplify that?
Create a protocol that defines your position property. Let's call it HasPosition. Declare an array of [HasPosition]. You can then sort the array directly with any of the standard sorting functions.
If .position returns the same type in both cases, and that type is comparable, you can simplify that to the following:
elements.sort {
let l = ($0 as? DBSet)?.position ?? ($0 as? DBItem)?.position
let r = ($1 as? DBSet)?.position ?? ($1 as? DBItem)?.position
return l < r
}
The key to this working is that there is a version of < that works for optionals, where nil is defined as less than any non-nil value. So values in the array not of one of the two types will be sorted to the beginning.
When you have the array as [AnyObject] and the position is Int16, this should works:
elements.sort {
($0.position as Int16?) < ($1.position as Int16?)
}
This works because AnyObject has any #objc properties as Optional.
Demo:
class DBItem:NSObject {
var position:Int16
init(position: Int16) { self.position = position }
override var description:String { return "DBItem(\(position))" }
}
class DBSet:NSObject {
var position:Int16
init(position: Int16) { self.position = position }
override var description:String { return "DBSet(\(position))" }
}
var elements:[AnyObject] = [
DBItem(position: 5),
DBSet(position: 2),
DBItem(position: 42),
DBSet(position: 62),
DBSet(position: 21),
DBItem(position: 6),
DBSet(position: 36),
DBItem(position: 24),
]
elements.sort {
($0.position as Int16?) < ($1.position as Int16?)
}
println(elements)
// -> [DBSet(2), DBItem(5), DBItem(6), DBSet(21), DBItem(24), DBSet(36), DBItem(42), DBSet(62)]
And your prepareElements() can be simplified as:
private func prepareElements() {
elements = []
if let ct = currentCategory {
elements += Array(ct.items) as [AnyObject]
elements += Array(ct.sets) as [AnyObject]
elements.sort {
($0.position as Int16?) < ($1.position as Int16?)
}
}
}