swift4(Xcode9)iPhoneアプリ、パズドラ風ゲームを作成する
こちらのサイトで紹介されていたコードはswift4環境だと
エラーが沢山出たので、修正したのを紹介する。

swiftという言語は頻繁にバージョンアップし内容も変わるので、超うんこ面倒くさい。
恐らく、数年もしないうちに、swift5、6・・・と出て、(2018年1月の現時点)互換性がすぐ無くなるだろうと思う。iphoneという機種が世代交代する度に機能に併せてバージョンアップしているから仕方ないかもしれない。(・・にしてもである(´Д` ))
プロジェクトはSingle View Appで作る。

modelフォルダを作成して、samp04.swift,GameSene4.swiftを新規作成、他のファイルはいじらない。
Assets.xcassetsにアイコン配置。

アイコンは以下を利用した。

(他のタイルについては、面倒なので用意していない。)
Mainstory.board、画面の上の左側をクリックして
custam classにsamp04(この画面で実行するクラス)を指定する。

samp04.swift
//
// samp04.swift
// Pazz
//
// Created by su5file on 2018/01/29.
// Copyright © 2018年 su5file. All rights reserved.
//
import UIKit
import SpriteKit
let _w = UIScreen.main.bounds.size.width
let _h = UIScreen.main.bounds.size.height
class samp04: UIViewController {
var skView : SKView?
override func viewDidLoad() {
super.viewDidLoad()
let sv = SKView(frame: CGRect(x:0, y:0,width:_w,height:_h))
let ss = GameScene4(size: sv.frame.size)
sv.presentScene(ss)
view.addSubview(sv)
}
open override var shouldAutorotate: Bool {
return true
}
open override var supportedInterfaceOrientations: UIInterfaceOrientationMask {
if UIDevice.current.userInterfaceIdiom == .phone {
return UIInterfaceOrientationMask(rawValue: UIInterfaceOrientationMask.RawValue(Int(UIInterfaceOrientationMask.allButUpsideDown.rawValue)));UIInterfaceOrientationMask.allButUpsideDown
} else {
return UIInterfaceOrientationMask(rawValue: UIInterfaceOrientationMask.RawValue(Int(UIInterfaceOrientationMask.all.rawValue)));UIInterfaceOrientationMask.all
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Release any cached data, images, etc that aren't in use.
}
// 追加
override var prefersStatusBarHidden: Bool {
return true
}
}
GameScene4.swift
//
// GameSene4.swift
// Pazz
//
// Created by su5file on 2018/01/29.
// Copyright © 2018年 su5file. All rights reserved.
//
import UIKit
import SpriteKit
let NumColumns = 6
let NumRows = 10
let TileSize:CGFloat = 50
let BoardLayerPosition = CGPoint(x:20, y:-80)
let TextFieldPosition = CGPoint(x:20, y:-20)
class GameScene4: SKScene {
var board = SKSpriteNode()
let boardLayer = SKNode()
let shapeLayer = SKNode()
let textLayer = SKNode()
let strLayer = SKNode()
let score = SKLabelNode()
var tileArrayPos = Array(repeating: Array(repeating: CGPoint(), count: NumRows), count: NumColumns)
var touchedNode = SKNode()
var moveActionFlag = false
var scorePoint = 0
override init(size:CGSize){
super.init(size: size)
backgroundColor = UIColor.gray
anchorPoint = CGPoint(x:0, y:1.0)
addChild(boardLayer)
addChild(textLayer)
board = SKSpriteNode(color:UIColor.white,size:CGSize(width:CGFloat(NumColumns)*TileSize, height:CGFloat(NumRows)*TileSize))
board.name = "board"
board.anchorPoint = CGPoint(x:0, y:1.0)
board.position = BoardLayerPosition
let textfield = SKSpriteNode(color:UIColor.white,size:CGSize(width:CGFloat(NumColumns)*TileSize,height: 80))
textfield.position = TextFieldPosition
textfield.anchorPoint = CGPoint(x:0, y:1.0)
score.fontColor = UIColor.black
score.position = CGPoint(x:textfield.position.x*10, y:textfield.position.y-30)
textfield.addChild(score)
strLayer.position = TextFieldPosition
strLayer.addChild(textfield)
textLayer.addChild(strLayer)
shapeLayer.position = BoardLayerPosition
shapeLayer.addChild(board)
boardLayer.addChild(shapeLayer)
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func didMove(to view: SKView) {
/* Setup your scene here */
initMakeTile()
}
//タイルの初期化
func randomColor()->UIColor{
//0:red,1:green,2:blue,3:yellow
let rnd = arc4random()%4
var color:UIColor!
switch rnd{
case 0:
color = UIColor.red
case 1:
color = UIColor.green
case 2:
color = UIColor.blue
case 3:
color = UIColor.yellow
default:
break
}
return color
}
//タイルの初期化
func initMakeTile(){
for i in 0..<NumColumns{
for j in 0..<NumRows{
let sprite = makeTileOne()
sprite.position = CGPoint(x:CGFloat(i)*TileSize,y:-CGFloat(j)*TileSize)
tileArrayPos[i][j] = sprite.position
board.addChild(sprite)
}
}
}
//タイルの初期化
func makeTileOne()->SKSpriteNode{
let sprite = SKSpriteNode()
sprite.anchorPoint = CGPoint(x:0, y:1.0)
sprite.alpha *= 0.8
sprite.color = randomColor()
sprite.size = CGSize(width:TileSize-1, height:TileSize-1)
if sprite.color == .red {
// 画像を変更
sprite.texture = SKTexture(imageNamed: "icons8cat.png")
}
return sprite
}
//タイルの移動
func moveTile(node:SKNode){
let touchedAction = SKAction.move(to: node.position, duration: 0.08)
let passeagedAction = SKAction.move(to: touchedNode.position, duration: 0.08)
moveActionFlag = true
touchedNode.run(touchedAction, completion: {self.moveActionFlag = false})
node.run(passeagedAction, completion: {self.moveActionFlag = false})
}
func searchNode(pos:CGPoint)->SKSpriteNode{
let node = self.atPoint(CGPoint(x:pos.x+TileSize,y:pos.y-4*TileSize))
return node as! SKSpriteNode
}
func searchEmpty(node:SKSpriteNode)-> Int{
var count = 0
if(node.name != "board"){
for k in Int(-1*node.position.y/TileSize)..<NumRows{
let sprite = searchNode(pos: tileArrayPos[Int(node.position.x/TileSize)][k])
if(sprite.name == "board"){
count+=1
}
}
}
return count
}
func insertArray( arrayA:inout [SKNode],arrayB:[SKNode]){
for node in arrayB{
arrayA.append(node)
}
}
func deleteColumns( array:inout [SKNode]){
var deleteColumnsArray = Array(arrayLiteral:SKNode())
for i in 0..<NumColumns{
var color = searchNode(pos: tileArrayPos[i][0]).color
var count = 0
for j in 0..<NumRows{
let node = searchNode(pos: tileArrayPos[i][j])
if(color == node.color){
deleteColumnsArray.append(node)
count+=1
}else{
if(count >= 3){
insertArray(arrayA: &array, arrayB: deleteColumnsArray)
}
deleteColumnsArray.removeAll()
deleteColumnsArray.append(node)
color = node.color
count = 1
}
}
if(count >= 3){
insertArray(arrayA: &array, arrayB: deleteColumnsArray)
}
deleteColumnsArray.removeAll()
}
}
func deleteRows( array:inout [SKNode]){
var deleteRowsArray = Array(arrayLiteral:SKNode())
for j in 0..<NumRows{
var color = searchNode(pos: tileArrayPos[0][j]).color
var count = 0
for i in 0..<NumColumns{
let node = searchNode(pos: tileArrayPos[i][j])
if(color == node.color){
deleteRowsArray.append(node)
count+=1
}else{
if(count >= 3){
insertArray(arrayA: &array, arrayB: deleteRowsArray)
}
deleteRowsArray.removeAll()
deleteRowsArray.append(node)
color = node.color
count = 1
}
}
if(count >= 3){
insertArray(arrayA: &array, arrayB: deleteRowsArray)
}
deleteRowsArray.removeAll()
}
}
//タイルの消去と落ちる処理
func dropTile(completion:@escaping ()->()){
for i in 0..<NumColumns{
for j in 0..<NumRows{
let k = searchEmpty(node: searchNode(pos: tileArrayPos[i][j]))
if(k != 0){
let sprite = searchNode(pos: tileArrayPos[i][j])
let action = SKAction.move(to: tileArrayPos[i][j+k], duration: 0.1)
sprite.run(action)
}
}
}
run(SKAction.wait(forDuration: 0.2), completion: completion)
}
func makeTileInEmpty(completion:@escaping ()->()){
var emptyList = Array(repeating:0, count:NumColumns)
for i in 0..<NumColumns{
var count = 0
for j in 0..<NumRows{
if(searchNode(pos: tileArrayPos[i][j]).name == "board"){
count+=1
scorePoint += 100
}
}
emptyList[i] = count
}
var i = 0
for k in emptyList{
for j in 0..<k{
let sprite = makeTileOne()
board.addChild(sprite)
let action = SKAction.move(to: tileArrayPos[i][j], duration: 0.1)
sprite.run(action)
}
i+=1
}
run(SKAction.wait(forDuration: 0.2), completion: completion)
}
//タイルの消去と落ちる処理
func deleteAndDropTile(){
var deleteTileArray = Array(arrayLiteral:SKNode())
deleteTileArray.removeAll()
deleteColumns(array: &deleteTileArray)
deleteRows(array: &deleteTileArray)
if(deleteTileArray.isEmpty){
moveActionFlag = false
return
}
board.removeChildren(in: deleteTileArray)
dropTile(){
self.makeTileInEmpty(){
self.deleteAndDropTile()
}
}
}
//タッチ操作
override func touchesBegan(_ touches: Set, with event: UIEvent?) {
/* Called when a touch begins */
for touch in touches {
let location = touch.location(in: self)
touchedNode = self.atPoint(location)
for node in self.board.children{
if(touchedNode == node as NSObject && !moveActionFlag){
touchedNode.alpha *= 0.5
}
}
}
}
override func touchesMoved(_ touches: Set, with event: UIEvent?) {
for touch in touches {
let location = touch.location(in: self)
let passagedNode = self.atPoint(location)
for node in self.board.children{
if(passagedNode == node as NSObject && touchedNode != passagedNode && !moveActionFlag){
moveTile(node: passagedNode)
}
}
}
}
override func touchesEnded(_ touches: Set, with event: UIEvent?) {
for touch in touches {
let location = touch.location(in: self)
let endedNode = self.atPoint(location)
for node in self.board.children{
if(endedNode == node as NSObject && !moveActionFlag){
moveActionFlag = true
deleteAndDropTile()
touchedNode.alpha *= 2
}
}
}
}
override func update(_ currentTime: CFTimeInterval) {
/* Called before each frame is rendered */
score.text = "Score : \(scorePoint)"
}
}
ちなみに、わしのパズドラのランクは379(´Д` )だす。
以上。
参考URL
https://qiita.com/konpeto000/items/0003db7e561fb03a4c8a