Repository: windstormeye/SwiftGame
Branch: master
Commit: d2f4eefc9e28
Files: 114
Total size: 179.6 KB
Directory structure:
gitextract_jbiqqmeb/
├── LICENSE
├── README.md
├── bounceGame/
│ ├── bounceGame/
│ │ ├── Actions.sks
│ │ ├── AppDelegate.swift
│ │ ├── Assets.xcassets/
│ │ │ ├── AppIcon.appiconset/
│ │ │ │ └── Contents.json
│ │ │ └── Contents.json
│ │ ├── Ball/
│ │ │ ├── Ball.swift
│ │ │ ├── Box.swift
│ │ │ └── Label.swift
│ │ ├── Base.lproj/
│ │ │ ├── LaunchScreen.storyboard
│ │ │ └── Main.storyboard
│ │ ├── Define.swift
│ │ ├── Extension.swift
│ │ ├── GameScene.sks
│ │ ├── GameScene.swift
│ │ ├── GameViewController.swift
│ │ └── Info.plist
│ └── bounceGame.xcodeproj/
│ ├── project.pbxproj
│ ├── project.xcworkspace/
│ │ ├── contents.xcworkspacedata
│ │ ├── xcshareddata/
│ │ │ └── IDEWorkspaceChecks.plist
│ │ └── xcuserdata/
│ │ └── pjhubs.xcuserdatad/
│ │ └── UserInterfaceState.xcuserstate
│ └── xcuserdata/
│ └── pjhubs.xcuserdatad/
│ ├── xcdebugger/
│ │ └── Breakpoints_v2.xcbkptlist
│ └── xcschemes/
│ └── xcschememanagement.plist
├── liGame/
│ ├── liGame/
│ │ ├── AppDelegate.swift
│ │ ├── Assets.xcassets/
│ │ │ ├── 01.imageset/
│ │ │ │ └── Contents.json
│ │ │ ├── AppIcon-1.appiconset/
│ │ │ │ └── Contents.json
│ │ │ ├── AppIcon.appiconset/
│ │ │ │ └── Contents.json
│ │ │ ├── Contents.json
│ │ │ ├── Line0.imageset/
│ │ │ │ └── Contents.json
│ │ │ ├── Line1.imageset/
│ │ │ │ └── Contents.json
│ │ │ ├── Line2.imageset/
│ │ │ │ └── Contents.json
│ │ │ ├── Line3.imageset/
│ │ │ │ └── Contents.json
│ │ │ ├── created_1.imageset/
│ │ │ │ └── Contents.json
│ │ │ ├── created_10.imageset/
│ │ │ │ └── Contents.json
│ │ │ ├── created_11.imageset/
│ │ │ │ └── Contents.json
│ │ │ ├── created_12.imageset/
│ │ │ │ └── Contents.json
│ │ │ ├── created_13.imageset/
│ │ │ │ └── Contents.json
│ │ │ ├── created_14.imageset/
│ │ │ │ └── Contents.json
│ │ │ ├── created_15.imageset/
│ │ │ │ └── Contents.json
│ │ │ ├── created_16.imageset/
│ │ │ │ └── Contents.json
│ │ │ ├── created_17.imageset/
│ │ │ │ └── Contents.json
│ │ │ ├── created_18.imageset/
│ │ │ │ └── Contents.json
│ │ │ ├── created_2.imageset/
│ │ │ │ └── Contents.json
│ │ │ ├── created_3.imageset/
│ │ │ │ └── Contents.json
│ │ │ ├── created_4.imageset/
│ │ │ │ └── Contents.json
│ │ │ ├── created_5.imageset/
│ │ │ │ └── Contents.json
│ │ │ ├── created_6.imageset/
│ │ │ │ └── Contents.json
│ │ │ ├── created_7.imageset/
│ │ │ │ └── Contents.json
│ │ │ ├── created_8.imageset/
│ │ │ │ └── Contents.json
│ │ │ ├── created_9.imageset/
│ │ │ │ └── Contents.json
│ │ │ ├── finalMan.imageset/
│ │ │ │ └── Contents.json
│ │ │ └── finalManContent.imageset/
│ │ │ └── Contents.json
│ │ ├── Base.lproj/
│ │ │ ├── LaunchScreen.storyboard
│ │ │ └── Main.storyboard
│ │ ├── Extension/
│ │ │ ├── Animation.swift
│ │ │ ├── Define.swift
│ │ │ ├── UIColor+Extension.swift
│ │ │ ├── UIImage+Extension.swift
│ │ │ └── UIView+Extension.swift
│ │ ├── Info.plist
│ │ ├── View/
│ │ │ ├── Bottom/
│ │ │ │ ├── LiBottomCollectionView.swift
│ │ │ │ ├── LiBottomCollectionViewCell.swift
│ │ │ │ └── LiBottomView.swift
│ │ │ └── Puzzle.swift
│ │ └── ViewController.swift
│ └── liGame.xcodeproj/
│ ├── project.pbxproj
│ ├── project.xcworkspace/
│ │ ├── contents.xcworkspacedata
│ │ ├── xcshareddata/
│ │ │ └── IDEWorkspaceChecks.plist
│ │ └── xcuserdata/
│ │ ├── pjhubs.xcuserdatad/
│ │ │ └── UserInterfaceState.xcuserstate
│ │ └── wengpeijun.xcuserdatad/
│ │ └── UserInterfaceState.xcuserstate
│ └── xcuserdata/
│ ├── pjhubs.xcuserdatad/
│ │ ├── xcdebugger/
│ │ │ └── Breakpoints_v2.xcbkptlist
│ │ └── xcschemes/
│ │ └── xcschememanagement.plist
│ └── wengpeijun.xcuserdatad/
│ ├── xcdebugger/
│ │ └── Breakpoints_v2.xcbkptlist
│ └── xcschemes/
│ └── xcschememanagement.plist
└── lightGame/
├── light-game/
│ ├── AppDelegate.swift
│ ├── Assets.xcassets/
│ │ ├── AppIcon.appiconset/
│ │ │ └── Contents.json
│ │ └── Contents.json
│ ├── Base.lproj/
│ │ └── LaunchScreen.storyboard
│ ├── ContentView.swift
│ ├── Info.plist
│ ├── Model/
│ │ ├── GameController.swift
│ │ ├── GameManager.swift
│ │ └── Light.swift
│ ├── Preview Content/
│ │ └── Preview Assets.xcassets/
│ │ └── Contents.json
│ └── SceneDelegate.swift
├── light-game.xcodeproj/
│ ├── project.pbxproj
│ ├── project.xcworkspace/
│ │ ├── contents.xcworkspacedata
│ │ ├── xcshareddata/
│ │ │ └── IDEWorkspaceChecks.plist
│ │ └── xcuserdata/
│ │ ├── pjhubs.xcuserdatad/
│ │ │ └── UserInterfaceState.xcuserstate
│ │ └── wengpeijun.xcuserdatad/
│ │ └── UserInterfaceState.xcuserstate
│ └── xcuserdata/
│ ├── pjhubs.xcuserdatad/
│ │ ├── xcdebugger/
│ │ │ └── Breakpoints_v2.xcbkptlist
│ │ └── xcschemes/
│ │ └── xcschememanagement.plist
│ └── wengpeijun.xcuserdatad/
│ ├── xcdebugger/
│ │ └── Breakpoints_v2.xcbkptlist
│ └── xcschemes/
│ └── xcschememanagement.plist
├── watchapp/
│ ├── Assets.xcassets/
│ │ ├── AppIcon.appiconset/
│ │ │ └── Contents.json
│ │ └── Contents.json
│ ├── Base.lproj/
│ │ └── Interface.storyboard
│ └── Info.plist
└── watchapp Extension/
├── Assets.xcassets/
│ ├── Complication.complicationset/
│ │ ├── Circular.imageset/
│ │ │ └── Contents.json
│ │ ├── Contents.json
│ │ ├── Extra Large.imageset/
│ │ │ └── Contents.json
│ │ ├── Graphic Bezel.imageset/
│ │ │ └── Contents.json
│ │ ├── Graphic Circular.imageset/
│ │ │ └── Contents.json
│ │ ├── Graphic Corner.imageset/
│ │ │ └── Contents.json
│ │ ├── Graphic Large Rectangular.imageset/
│ │ │ └── Contents.json
│ │ ├── Modular.imageset/
│ │ │ └── Contents.json
│ │ └── Utilitarian.imageset/
│ │ └── Contents.json
│ └── Contents.json
├── ExtensionDelegate.swift
├── HostingController.swift
├── Info.plist
├── Preview Content/
│ └── Preview Assets.xcassets/
│ └── Contents.json
├── WatchContentView.swift
└── WatchGameManager.swift
================================================
FILE CONTENTS
================================================
================================================
FILE: LICENSE
================================================
MIT License
Copyright (c) 2019 PJHubs
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
================================================
FILE: README.md
================================================
# 《Swift 游戏开发》
这里汇集了我的小专栏《Swift 游戏开发》的全部代码,小专栏地址:https://xiaozhuanlan.com/pjhubs-swift-game

[Swift 游戏开发序言](https://xiaozhuanlan.com/topic/9704163285)

[Swift 游戏开发之能否关个灯(〇)](https://xiaozhuanlan.com/topic/9806127435)
[Swift 游戏开发之能否关个灯(一)](https://xiaozhuanlan.com/topic/2564017938)
[Swift 游戏开发之能否关个灯(二)](https://xiaozhuanlan.com/topic/8654723190)

[Swift 游戏开发阶段总结(〇)](https://xiaozhuanlan.com/topic/7942150836)

[Swift 游戏开发之黎锦拼图(〇)](https://xiaozhuanlan.com/topic/8079642315)
[Swift 游戏开发之黎锦拼图(一)](https://xiaozhuanlan.com/topic/0312569847)
[Swift 游戏开发之黎锦拼图(二)](https://xiaozhuanlan.com/topic/9738401526)
[Swift 游戏开发之黎锦拼图(三)](https://xiaozhuanlan.com/topic/3968275140)
[Swift 游戏开发之黎锦拼图(四)](https://xiaozhuanlan.com/topic/7436519820)

[Swift 游戏开发阶段总结(一)](https://xiaozhuanlan.com/topic/8109647352)

[Swift 游戏开发之方块弹珠(〇))](https://xiaozhuanlan.com/topic/1758926340)
================================================
FILE: bounceGame/bounceGame/AppDelegate.swift
================================================
//
// AppDelegate.swift
// bounceGame
//
// Created by 翁培钧 on 2019/12/22.
// Copyright © 2019 翁培钧. All rights reserved.
//
import UIKit
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
return true
}
func applicationWillResignActive(_ application: UIApplication) {
// Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
// Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game.
}
func applicationDidEnterBackground(_ application: UIApplication) {
// Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
}
func applicationWillEnterForeground(_ application: UIApplication) {
// Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background.
}
func applicationDidBecomeActive(_ application: UIApplication) {
// Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
}
}
================================================
FILE: bounceGame/bounceGame/Assets.xcassets/AppIcon.appiconset/Contents.json
================================================
{
"images" : [
{
"idiom" : "iphone",
"size" : "20x20",
"scale" : "2x"
},
{
"idiom" : "iphone",
"size" : "20x20",
"scale" : "3x"
},
{
"idiom" : "iphone",
"size" : "29x29",
"scale" : "2x"
},
{
"idiom" : "iphone",
"size" : "29x29",
"scale" : "3x"
},
{
"idiom" : "iphone",
"size" : "40x40",
"scale" : "2x"
},
{
"idiom" : "iphone",
"size" : "40x40",
"scale" : "3x"
},
{
"idiom" : "iphone",
"size" : "60x60",
"scale" : "2x"
},
{
"idiom" : "iphone",
"size" : "60x60",
"scale" : "3x"
},
{
"idiom" : "ipad",
"size" : "20x20",
"scale" : "1x"
},
{
"idiom" : "ipad",
"size" : "20x20",
"scale" : "2x"
},
{
"idiom" : "ipad",
"size" : "29x29",
"scale" : "1x"
},
{
"idiom" : "ipad",
"size" : "29x29",
"scale" : "2x"
},
{
"idiom" : "ipad",
"size" : "40x40",
"scale" : "1x"
},
{
"idiom" : "ipad",
"size" : "40x40",
"scale" : "2x"
},
{
"idiom" : "ipad",
"size" : "76x76",
"scale" : "1x"
},
{
"idiom" : "ipad",
"size" : "76x76",
"scale" : "2x"
},
{
"idiom" : "ipad",
"size" : "83.5x83.5",
"scale" : "2x"
},
{
"idiom" : "ios-marketing",
"size" : "1024x1024",
"scale" : "1x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}
================================================
FILE: bounceGame/bounceGame/Assets.xcassets/Contents.json
================================================
{
"info" : {
"version" : 1,
"author" : "xcode"
}
}
================================================
FILE: bounceGame/bounceGame/Ball/Ball.swift
================================================
//
// Ball.swift
// bounceGame
//
// Created by 翁培钧 on 2019/12/29.
// Copyright © 2019 翁培钧. All rights reserved.
//
import SpriteKit
class Ball: SKShapeNode {
var isShot = false
override init() {
super.init()
initObject()
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
private func initObject() {
self.fillColor = .red
self.physicsBody = SKPhysicsBody(circleOfRadius: 10)
self.physicsBody?.categoryBitMask = BitMask.Ball
self.physicsBody?.contactTestBitMask = BitMask.Box | BitMask.Ground
self.physicsBody?.collisionBitMask = BitMask.Box
self.physicsBody?.usesPreciseCollisionDetection = true;
self.physicsBody?.linearDamping = 0
self.physicsBody?.restitution = 1.0
}
}
================================================
FILE: bounceGame/bounceGame/Ball/Box.swift
================================================
//
// Box.swift
// bounceGame
//
// Created by 翁培钧 on 2020/1/7.
// Copyright © 2020 翁培钧. All rights reserved.
//
import SpriteKit
class Box: SKShapeNode {
}
================================================
FILE: bounceGame/bounceGame/Ball/Label.swift
================================================
//
// Label.swift
// bounceGame
//
// Created by 翁培钧 on 2020/1/8.
// Copyright © 2020 翁培钧. All rights reserved.
//
import SpriteKit
class Label: SKLabelNode {
var typoTag = 0
}
================================================
FILE: bounceGame/bounceGame/Base.lproj/LaunchScreen.storyboard
================================================
================================================
FILE: bounceGame/bounceGame/Base.lproj/Main.storyboard
================================================
================================================
FILE: bounceGame/bounceGame/Define.swift
================================================
//
// Define.swift
// bounceGame
//
// Created by 翁培钧 on 2019/12/30.
// Copyright © 2019 翁培钧. All rights reserved.
//
import Foundation
struct BitMask {
static let Ball = UInt32(0x00001)
static let Box = UInt32(0x00002)
static let Wall = UInt32(0x00003)
static let Ground = UInt32(0x00004)
}
================================================
FILE: bounceGame/bounceGame/Extension.swift
================================================
//
// Extension.swift
// bounceGame
//
// Created by 翁培钧 on 2020/1/8.
// Copyright © 2020 翁培钧. All rights reserved.
//
import SpriteKit
================================================
FILE: bounceGame/bounceGame/GameScene.swift
================================================
//
// GameScene.swift
// bounceGame
//
// Created by 翁培钧 on 2019/12/22.
// Copyright © 2019 翁培钧. All rights reserved.
//
import SpriteKit
class GameScene: SKScene {
private var balls = [Ball]()
private var contactGroundBalls = [Ball]()
private var isBegin = false
private var ground = SKSpriteNode()
private var firstDownBall: Ball?
override init(size: CGSize) {
super.init(size: size)
physicsWorld.gravity = CGVector(dx: 0, dy: -1)
physicsWorld.contactDelegate = self
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
var contentCreated = false
override func didMove(to view: SKView) {
if !contentCreated {
createContent()
contentCreated = true
}
}
private func createContent() {
ground = SKSpriteNode(color: .gray, size: CGSize(width: size.width, height: 120))
ground.position = CGPoint(x: size.width / 2, y: ground.size.height / 2)
addChild(ground)
ground.physicsBody = SKPhysicsBody(rectangleOf: ground.size)
ground.physicsBody?.isDynamic = false
ground.physicsBody?.collisionBitMask = BitMask.Ball
ground.physicsBody?.categoryBitMask = BitMask.Ground
ground.physicsBody?.contactTestBitMask = BitMask.Ball
let wall = SKNode()
wall.position = CGPoint(x: 0, y: 0)
wall.physicsBody?.friction = 0
wall.physicsBody?.isDynamic = false
wall.physicsBody?.restitution = 1.0
wall.physicsBody?.collisionBitMask = BitMask.Wall
wall.physicsBody?.categoryBitMask = BitMask.Wall
wall.physicsBody?.contactTestBitMask = BitMask.Wall
wall.physicsBody = SKPhysicsBody(edgeLoopFrom: CGRect(x: 0, y: 0, width: size.width, height: size.height))
addChild(wall)
for _ in 0..<5 {
let ball = Ball(circleOfRadius: 10)
balls.append(ball)
addChild(ball)
ball.physicsBody?.isDynamic = false
ball.position = CGPoint(x: size.width / 2, y: ground.frame.size.height + ball.frame.size.height / 2)
}
for row in 1...5 {
let box = Box(rectOf: CGSize(width: 50, height: 50))
box.position = CGPoint(x: 50 + (row * 50 + 20), y: (800 - row * 50 + 20))
box.physicsBody = SKPhysicsBody(rectangleOf: CGSize(width: 50, height: 50))
box.physicsBody?.categoryBitMask = BitMask.Box
box.physicsBody?.contactTestBitMask = BitMask.Ball
box.physicsBody?.collisionBitMask = BitMask.Box
box.physicsBody?.linearDamping = 0
box.physicsBody?.restitution = 1.0
box.physicsBody?.isDynamic = false
box.fillColor = .red
let label = Label(text: "\(row)")
label.fontSize = 22
label.typoTag = 666
label.fontName = "Arial-BoldMT"
label.color = .white
label.position = CGPoint(x: 0, y: -label.frame.size.height / 2)
box.addChild(label)
addChild(box)
}
}
}
extension GameScene {
private func shot() {
for (index, ball) in balls.enumerated() {
DispatchQueue.main.asyncAfter(deadline: .now() + 0.1 * Double(index)) {
ball.physicsBody?.isDynamic = true
if (!self.children.contains(ball)) {
self.addChild(ball)
}
ball.physicsBody?.applyImpulse(CGVector(dx: 10, dy: 10))
ball.physicsBody?.applyTorque(1.8)
// ball.physicsBody?.applyForce(CGVector(dx: 400 + CGFloat(index) * 0.1, dy: 800))
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 0.1) {
ball.isShot = true
if (index == self.balls.count - 1) {
self.firstDownBall?.removeFromParent()
self.firstDownBall = nil
}
}
}
}
}
}
extension GameScene {
override func touchesEnded(_ touches: Set, with event: UIEvent?) {
shot()
}
}
extension GameScene: SKPhysicsContactDelegate {
func didBegin(_ contact: SKPhysicsContact) {
print("\(contact.bodyA.contactTestBitMask) == \(contact.bodyB.contactTestBitMask)")
switch contact.bodyA.categoryBitMask {
case BitMask.Box:
checkNodeIsBox(contact.bodyA.node)
checkNodeIsWall(contact.bodyB.node)
case BitMask.Wall:
checkNodeIsWall(contact.bodyB.node)
case BitMask.Ground:
checkNodeIsGround(contact.bodyB.node)
default:
break
}
switch contact.bodyB.categoryBitMask {
case BitMask.Box:
checkNodeIsBox(contact.bodyB.node)
checkNodeIsWall(contact.bodyA.node)
case BitMask.Wall:
checkNodeIsWall(contact.bodyA.node)
case BitMask.Ground:
checkNodeIsGround(contact.bodyA.node)
default:
break
}
}
}
extension GameScene {
private func checkNodeIsBox(_ node: SKNode?) {
guard let box = node else { return }
if box.physicsBody?.categoryBitMask == BitMask.Box {
let label = box.children.first! as! Label
var tag = Int(label.text!)!
if (tag > 1) {
tag -= 1
label.text = "\(tag)"
} else {
box.removeFromParent()
}
}
}
private func checkNodeIsWall(_ node: SKNode?) {
guard let ball = node as? Ball else { return }
ball.isShot = true
}
private func checkNodeIsGround(_ node: SKNode?) {
guard let ball = node as? Ball else { return }
// NOTE: 小球 & 发射出去
if (ball.physicsBody?.categoryBitMask == BitMask.Ball && ball.isShot) {
ball.removeFromParent();
// NOTE: 定位小球不存在 || 当前 Scene 中不包含定位小球
if (firstDownBall == nil || !children.contains(firstDownBall!)) {
firstDownBall = Ball(circleOfRadius: 10)
firstDownBall!.position = CGPoint(x: ball.position.x, y: ground.frame.size.height + ball.frame.size.height / 2 - 2)
addChild(firstDownBall!)
// NOTE: 静止
firstDownBall!.physicsBody?.isDynamic = false
}
// NOTE: 统一重设后续触底小球位置。二次发射时,直接读取各个小球的初始位置进行发射
ball.position = CGPoint(x: firstDownBall!.position.x, y: ground.frame.size.height + ball.frame.size.height / 2)
}
}
}
================================================
FILE: bounceGame/bounceGame/GameViewController.swift
================================================
//
// GameViewController.swift
// bounceGame
//
// Created by 翁培钧 on 2019/12/22.
// Copyright © 2019 翁培钧. All rights reserved.
//
import UIKit
import SpriteKit
class GameViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
if let view = self.view as! SKView? {
let scene = GameScene(size: view.frame.size)
scene.scaleMode = .aspectFill
view.presentScene(scene)
view.ignoresSiblingOrder = true
view.showsFPS = true
view.showsNodeCount = true
view.showsPhysics = true
}
}
override var prefersStatusBarHidden: Bool {
return true
}
}
================================================
FILE: bounceGame/bounceGame/Info.plist
================================================
CFBundleDevelopmentRegion
$(DEVELOPMENT_LANGUAGE)
CFBundleExecutable
$(EXECUTABLE_NAME)
CFBundleIdentifier
$(PRODUCT_BUNDLE_IDENTIFIER)
CFBundleInfoDictionaryVersion
6.0
CFBundleName
$(PRODUCT_NAME)
CFBundlePackageType
$(PRODUCT_BUNDLE_PACKAGE_TYPE)
CFBundleShortVersionString
1.0
CFBundleVersion
1
LSRequiresIPhoneOS
UILaunchStoryboardName
LaunchScreen
UIMainStoryboardFile
Main
UIRequiredDeviceCapabilities
armv7
UIStatusBarHidden
UISupportedInterfaceOrientations
UIInterfaceOrientationPortrait
UISupportedInterfaceOrientations~ipad
UIInterfaceOrientationPortrait
UIInterfaceOrientationPortraitUpsideDown
UIInterfaceOrientationLandscapeLeft
UIInterfaceOrientationLandscapeRight
================================================
FILE: bounceGame/bounceGame.xcodeproj/project.pbxproj
================================================
// !$*UTF8*$!
{
archiveVersion = 1;
classes = {
};
objectVersion = 50;
objects = {
/* Begin PBXBuildFile section */
0C8BB82F23C4C84B00F88BD6 /* Box.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0C8BB82E23C4C84B00F88BD6 /* Box.swift */; };
0C964EBD23B8E5D0001EA659 /* Ball.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0C964EBC23B8E5D0001EA659 /* Ball.swift */; };
0C964EBF23BA3FDF001EA659 /* Define.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0C964EBE23BA3FDF001EA659 /* Define.swift */; };
0CA02F8523AFAB7D004A580E /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0CA02F8423AFAB7D004A580E /* AppDelegate.swift */; };
0CA02F8723AFAB7D004A580E /* GameScene.sks in Resources */ = {isa = PBXBuildFile; fileRef = 0CA02F8623AFAB7D004A580E /* GameScene.sks */; };
0CA02F8923AFAB7D004A580E /* Actions.sks in Resources */ = {isa = PBXBuildFile; fileRef = 0CA02F8823AFAB7D004A580E /* Actions.sks */; };
0CA02F8B23AFAB7D004A580E /* GameScene.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0CA02F8A23AFAB7D004A580E /* GameScene.swift */; };
0CA02F8D23AFAB7D004A580E /* GameViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0CA02F8C23AFAB7D004A580E /* GameViewController.swift */; };
0CA02F9023AFAB7D004A580E /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 0CA02F8E23AFAB7D004A580E /* Main.storyboard */; };
0CA02F9223AFAB7E004A580E /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 0CA02F9123AFAB7E004A580E /* Assets.xcassets */; };
0CA02F9523AFAB7E004A580E /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 0CA02F9323AFAB7E004A580E /* LaunchScreen.storyboard */; };
0CFFFBBE23C629AD00BB3F13 /* Label.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0CFFFBBD23C629AD00BB3F13 /* Label.swift */; };
0CFFFBC223C62AD300BB3F13 /* Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0CFFFBC123C62AD300BB3F13 /* Extension.swift */; };
/* End PBXBuildFile section */
/* Begin PBXFileReference section */
0C8BB82E23C4C84B00F88BD6 /* Box.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Box.swift; sourceTree = ""; };
0C964EBC23B8E5D0001EA659 /* Ball.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Ball.swift; sourceTree = ""; };
0C964EBE23BA3FDF001EA659 /* Define.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Define.swift; sourceTree = ""; };
0CA02F8123AFAB7D004A580E /* bounceGame.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = bounceGame.app; sourceTree = BUILT_PRODUCTS_DIR; };
0CA02F8423AFAB7D004A580E /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; };
0CA02F8623AFAB7D004A580E /* GameScene.sks */ = {isa = PBXFileReference; lastKnownFileType = file.sks; path = GameScene.sks; sourceTree = ""; };
0CA02F8823AFAB7D004A580E /* Actions.sks */ = {isa = PBXFileReference; lastKnownFileType = file.sks; path = Actions.sks; sourceTree = ""; };
0CA02F8A23AFAB7D004A580E /* GameScene.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GameScene.swift; sourceTree = ""; };
0CA02F8C23AFAB7D004A580E /* GameViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GameViewController.swift; sourceTree = ""; };
0CA02F8F23AFAB7D004A580E /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; };
0CA02F9123AFAB7E004A580E /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; };
0CA02F9423AFAB7E004A580E /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; };
0CA02F9623AFAB7E004A580E /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
0CFFFBBD23C629AD00BB3F13 /* Label.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Label.swift; sourceTree = ""; };
0CFFFBC123C62AD300BB3F13 /* Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Extension.swift; sourceTree = ""; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
0CA02F7E23AFAB7D004A580E /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
0C964EBB23B8E5A6001EA659 /* Ball */ = {
isa = PBXGroup;
children = (
0C964EBC23B8E5D0001EA659 /* Ball.swift */,
0C8BB82E23C4C84B00F88BD6 /* Box.swift */,
0CFFFBBD23C629AD00BB3F13 /* Label.swift */,
);
path = Ball;
sourceTree = "";
};
0CA02F7823AFAB7D004A580E = {
isa = PBXGroup;
children = (
0CA02F8323AFAB7D004A580E /* bounceGame */,
0CA02F8223AFAB7D004A580E /* Products */,
);
sourceTree = "";
};
0CA02F8223AFAB7D004A580E /* Products */ = {
isa = PBXGroup;
children = (
0CA02F8123AFAB7D004A580E /* bounceGame.app */,
);
name = Products;
sourceTree = "";
};
0CA02F8323AFAB7D004A580E /* bounceGame */ = {
isa = PBXGroup;
children = (
0CA02F8423AFAB7D004A580E /* AppDelegate.swift */,
0CA02F8623AFAB7D004A580E /* GameScene.sks */,
0CA02F8823AFAB7D004A580E /* Actions.sks */,
0CA02F8A23AFAB7D004A580E /* GameScene.swift */,
0CA02F8C23AFAB7D004A580E /* GameViewController.swift */,
0C964EBE23BA3FDF001EA659 /* Define.swift */,
0CFFFBC123C62AD300BB3F13 /* Extension.swift */,
0C964EBB23B8E5A6001EA659 /* Ball */,
0CA02F8E23AFAB7D004A580E /* Main.storyboard */,
0CA02F9123AFAB7E004A580E /* Assets.xcassets */,
0CA02F9323AFAB7E004A580E /* LaunchScreen.storyboard */,
0CA02F9623AFAB7E004A580E /* Info.plist */,
);
path = bounceGame;
sourceTree = "";
};
/* End PBXGroup section */
/* Begin PBXNativeTarget section */
0CA02F8023AFAB7D004A580E /* bounceGame */ = {
isa = PBXNativeTarget;
buildConfigurationList = 0CA02F9923AFAB7E004A580E /* Build configuration list for PBXNativeTarget "bounceGame" */;
buildPhases = (
0CA02F7D23AFAB7D004A580E /* Sources */,
0CA02F7E23AFAB7D004A580E /* Frameworks */,
0CA02F7F23AFAB7D004A580E /* Resources */,
);
buildRules = (
);
dependencies = (
);
name = bounceGame;
productName = bounceGame;
productReference = 0CA02F8123AFAB7D004A580E /* bounceGame.app */;
productType = "com.apple.product-type.application";
};
/* End PBXNativeTarget section */
/* Begin PBXProject section */
0CA02F7923AFAB7D004A580E /* Project object */ = {
isa = PBXProject;
attributes = {
LastSwiftUpdateCheck = 1120;
LastUpgradeCheck = 1120;
ORGANIZATIONNAME = "翁培钧";
TargetAttributes = {
0CA02F8023AFAB7D004A580E = {
CreatedOnToolsVersion = 11.2.1;
};
};
};
buildConfigurationList = 0CA02F7C23AFAB7D004A580E /* Build configuration list for PBXProject "bounceGame" */;
compatibilityVersion = "Xcode 9.3";
developmentRegion = en;
hasScannedForEncodings = 0;
knownRegions = (
en,
Base,
);
mainGroup = 0CA02F7823AFAB7D004A580E;
productRefGroup = 0CA02F8223AFAB7D004A580E /* Products */;
projectDirPath = "";
projectRoot = "";
targets = (
0CA02F8023AFAB7D004A580E /* bounceGame */,
);
};
/* End PBXProject section */
/* Begin PBXResourcesBuildPhase section */
0CA02F7F23AFAB7D004A580E /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
0CA02F9023AFAB7D004A580E /* Main.storyboard in Resources */,
0CA02F8723AFAB7D004A580E /* GameScene.sks in Resources */,
0CA02F9223AFAB7E004A580E /* Assets.xcassets in Resources */,
0CA02F9523AFAB7E004A580E /* LaunchScreen.storyboard in Resources */,
0CA02F8923AFAB7D004A580E /* Actions.sks in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXResourcesBuildPhase section */
/* Begin PBXSourcesBuildPhase section */
0CA02F7D23AFAB7D004A580E /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
0C964EBD23B8E5D0001EA659 /* Ball.swift in Sources */,
0CA02F8B23AFAB7D004A580E /* GameScene.swift in Sources */,
0CA02F8D23AFAB7D004A580E /* GameViewController.swift in Sources */,
0C8BB82F23C4C84B00F88BD6 /* Box.swift in Sources */,
0C964EBF23BA3FDF001EA659 /* Define.swift in Sources */,
0CFFFBBE23C629AD00BB3F13 /* Label.swift in Sources */,
0CA02F8523AFAB7D004A580E /* AppDelegate.swift in Sources */,
0CFFFBC223C62AD300BB3F13 /* Extension.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXSourcesBuildPhase section */
/* Begin PBXVariantGroup section */
0CA02F8E23AFAB7D004A580E /* Main.storyboard */ = {
isa = PBXVariantGroup;
children = (
0CA02F8F23AFAB7D004A580E /* Base */,
);
name = Main.storyboard;
sourceTree = "";
};
0CA02F9323AFAB7E004A580E /* LaunchScreen.storyboard */ = {
isa = PBXVariantGroup;
children = (
0CA02F9423AFAB7E004A580E /* Base */,
);
name = LaunchScreen.storyboard;
sourceTree = "";
};
/* End PBXVariantGroup section */
/* Begin XCBuildConfiguration section */
0CA02F9723AFAB7E004A580E /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_NONNULL = YES;
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_ENABLE_OBJC_WEAK = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
COPY_PHASE_STRIP = NO;
DEBUG_INFORMATION_FORMAT = dwarf;
ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_TESTABILITY = YES;
GCC_C_LANGUAGE_STANDARD = gnu11;
GCC_DYNAMIC_NO_PIC = NO;
GCC_NO_COMMON_BLOCKS = YES;
GCC_OPTIMIZATION_LEVEL = 0;
GCC_PREPROCESSOR_DEFINITIONS = (
"DEBUG=1",
"$(inherited)",
);
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 13.2;
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
MTL_FAST_MATH = YES;
ONLY_ACTIVE_ARCH = YES;
SDKROOT = iphoneos;
SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
};
name = Debug;
};
0CA02F9823AFAB7E004A580E /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_NONNULL = YES;
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_ENABLE_OBJC_WEAK = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
COPY_PHASE_STRIP = NO;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
ENABLE_NS_ASSERTIONS = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
GCC_C_LANGUAGE_STANDARD = gnu11;
GCC_NO_COMMON_BLOCKS = YES;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 13.2;
MTL_ENABLE_DEBUG_INFO = NO;
MTL_FAST_MATH = YES;
SDKROOT = iphoneos;
SWIFT_COMPILATION_MODE = wholemodule;
SWIFT_OPTIMIZATION_LEVEL = "-O";
VALIDATE_PRODUCT = YES;
};
name = Release;
};
0CA02F9A23AFAB7E004A580E /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CODE_SIGN_STYLE = Automatic;
DEVELOPMENT_TEAM = U6J5965DZK;
INFOPLIST_FILE = bounceGame/Info.plist;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
);
PRODUCT_BUNDLE_IDENTIFIER = com.pjhubs.bounceGame;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = "1,2";
};
name = Debug;
};
0CA02F9B23AFAB7E004A580E /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CODE_SIGN_STYLE = Automatic;
DEVELOPMENT_TEAM = U6J5965DZK;
INFOPLIST_FILE = bounceGame/Info.plist;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
);
PRODUCT_BUNDLE_IDENTIFIER = com.pjhubs.bounceGame;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = "1,2";
};
name = Release;
};
/* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */
0CA02F7C23AFAB7D004A580E /* Build configuration list for PBXProject "bounceGame" */ = {
isa = XCConfigurationList;
buildConfigurations = (
0CA02F9723AFAB7E004A580E /* Debug */,
0CA02F9823AFAB7E004A580E /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
0CA02F9923AFAB7E004A580E /* Build configuration list for PBXNativeTarget "bounceGame" */ = {
isa = XCConfigurationList;
buildConfigurations = (
0CA02F9A23AFAB7E004A580E /* Debug */,
0CA02F9B23AFAB7E004A580E /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
/* End XCConfigurationList section */
};
rootObject = 0CA02F7923AFAB7D004A580E /* Project object */;
}
================================================
FILE: bounceGame/bounceGame.xcodeproj/project.xcworkspace/contents.xcworkspacedata
================================================
================================================
FILE: bounceGame/bounceGame.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist
================================================
IDEDidComputeMac32BitWarning
================================================
FILE: bounceGame/bounceGame.xcodeproj/xcuserdata/pjhubs.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist
================================================
================================================
FILE: bounceGame/bounceGame.xcodeproj/xcuserdata/pjhubs.xcuserdatad/xcschemes/xcschememanagement.plist
================================================
SchemeUserState
bounceGame.xcscheme_^#shared#^_
orderHint
0
================================================
FILE: liGame/liGame/AppDelegate.swift
================================================
//
// AppDelegate.swift
// liGame
//
// Created by 翁培钧 on 2019/9/4.
// Copyright © 2019 翁培钧. All rights reserved.
//
import UIKit
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
return true
}
func applicationWillResignActive(_ application: UIApplication) {
// Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
// Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game.
}
func applicationDidEnterBackground(_ application: UIApplication) {
// Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
// If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
}
func applicationWillEnterForeground(_ application: UIApplication) {
// Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background.
}
func applicationDidBecomeActive(_ application: UIApplication) {
// Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
}
func applicationWillTerminate(_ application: UIApplication) {
// Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
}
}
================================================
FILE: liGame/liGame/Assets.xcassets/01.imageset/Contents.json
================================================
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x"
},
{
"idiom" : "universal",
"filename" : "01.png",
"scale" : "2x"
},
{
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}
================================================
FILE: liGame/liGame/Assets.xcassets/AppIcon-1.appiconset/Contents.json
================================================
{
"images" : [
{
"idiom" : "iphone",
"size" : "20x20",
"scale" : "2x"
},
{
"idiom" : "iphone",
"size" : "20x20",
"scale" : "3x"
},
{
"idiom" : "iphone",
"size" : "29x29",
"scale" : "2x"
},
{
"idiom" : "iphone",
"size" : "29x29",
"scale" : "3x"
},
{
"idiom" : "iphone",
"size" : "40x40",
"scale" : "2x"
},
{
"idiom" : "iphone",
"size" : "40x40",
"scale" : "3x"
},
{
"idiom" : "iphone",
"size" : "60x60",
"scale" : "2x"
},
{
"idiom" : "iphone",
"size" : "60x60",
"scale" : "3x"
},
{
"idiom" : "ipad",
"size" : "20x20",
"scale" : "1x"
},
{
"idiom" : "ipad",
"size" : "20x20",
"scale" : "2x"
},
{
"idiom" : "ipad",
"size" : "29x29",
"scale" : "1x"
},
{
"idiom" : "ipad",
"size" : "29x29",
"scale" : "2x"
},
{
"idiom" : "ipad",
"size" : "40x40",
"scale" : "1x"
},
{
"idiom" : "ipad",
"size" : "40x40",
"scale" : "2x"
},
{
"idiom" : "ipad",
"size" : "76x76",
"scale" : "1x"
},
{
"idiom" : "ipad",
"size" : "76x76",
"scale" : "2x"
},
{
"idiom" : "ipad",
"size" : "83.5x83.5",
"scale" : "2x"
},
{
"idiom" : "ios-marketing",
"size" : "1024x1024",
"scale" : "1x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}
================================================
FILE: liGame/liGame/Assets.xcassets/AppIcon.appiconset/Contents.json
================================================
{
"images" : [
{
"idiom" : "iphone",
"size" : "20x20",
"scale" : "2x"
},
{
"idiom" : "iphone",
"size" : "20x20",
"scale" : "3x"
},
{
"idiom" : "iphone",
"size" : "29x29",
"scale" : "2x"
},
{
"idiom" : "iphone",
"size" : "29x29",
"scale" : "3x"
},
{
"idiom" : "iphone",
"size" : "40x40",
"scale" : "2x"
},
{
"idiom" : "iphone",
"size" : "40x40",
"scale" : "3x"
},
{
"idiom" : "iphone",
"size" : "60x60",
"scale" : "2x"
},
{
"idiom" : "iphone",
"size" : "60x60",
"scale" : "3x"
},
{
"idiom" : "ipad",
"size" : "20x20",
"scale" : "1x"
},
{
"idiom" : "ipad",
"size" : "20x20",
"scale" : "2x"
},
{
"idiom" : "ipad",
"size" : "29x29",
"scale" : "1x"
},
{
"idiom" : "ipad",
"size" : "29x29",
"scale" : "2x"
},
{
"idiom" : "ipad",
"size" : "40x40",
"scale" : "1x"
},
{
"idiom" : "ipad",
"size" : "40x40",
"scale" : "2x"
},
{
"idiom" : "ipad",
"size" : "76x76",
"scale" : "1x"
},
{
"idiom" : "ipad",
"size" : "76x76",
"scale" : "2x"
},
{
"idiom" : "ipad",
"size" : "83.5x83.5",
"scale" : "2x"
},
{
"idiom" : "ios-marketing",
"size" : "1024x1024",
"scale" : "1x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}
================================================
FILE: liGame/liGame/Assets.xcassets/Contents.json
================================================
{
"info" : {
"version" : 1,
"author" : "xcode"
}
}
================================================
FILE: liGame/liGame/Assets.xcassets/Line0.imageset/Contents.json
================================================
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x"
},
{
"idiom" : "universal",
"filename" : "Line0@2x.png",
"scale" : "2x"
},
{
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}
================================================
FILE: liGame/liGame/Assets.xcassets/Line1.imageset/Contents.json
================================================
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x"
},
{
"idiom" : "universal",
"filename" : "Line1@2x.png",
"scale" : "2x"
},
{
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}
================================================
FILE: liGame/liGame/Assets.xcassets/Line2.imageset/Contents.json
================================================
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x"
},
{
"idiom" : "universal",
"filename" : "Line2@2x.png",
"scale" : "2x"
},
{
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}
================================================
FILE: liGame/liGame/Assets.xcassets/Line3.imageset/Contents.json
================================================
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x"
},
{
"idiom" : "universal",
"filename" : "Line3@2x.png",
"scale" : "2x"
},
{
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}
================================================
FILE: liGame/liGame/Assets.xcassets/created_1.imageset/Contents.json
================================================
{
"images" : [
{
"idiom" : "universal",
"filename" : "created_1.png",
"scale" : "1x"
},
{
"idiom" : "universal",
"scale" : "2x"
},
{
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}
================================================
FILE: liGame/liGame/Assets.xcassets/created_10.imageset/Contents.json
================================================
{
"images" : [
{
"idiom" : "universal",
"filename" : "created_10.png",
"scale" : "1x"
},
{
"idiom" : "universal",
"scale" : "2x"
},
{
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}
================================================
FILE: liGame/liGame/Assets.xcassets/created_11.imageset/Contents.json
================================================
{
"images" : [
{
"idiom" : "universal",
"filename" : "created_11.png",
"scale" : "1x"
},
{
"idiom" : "universal",
"scale" : "2x"
},
{
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}
================================================
FILE: liGame/liGame/Assets.xcassets/created_12.imageset/Contents.json
================================================
{
"images" : [
{
"idiom" : "universal",
"filename" : "created_12.png",
"scale" : "1x"
},
{
"idiom" : "universal",
"scale" : "2x"
},
{
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}
================================================
FILE: liGame/liGame/Assets.xcassets/created_13.imageset/Contents.json
================================================
{
"images" : [
{
"idiom" : "universal",
"filename" : "created_13.png",
"scale" : "1x"
},
{
"idiom" : "universal",
"scale" : "2x"
},
{
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}
================================================
FILE: liGame/liGame/Assets.xcassets/created_14.imageset/Contents.json
================================================
{
"images" : [
{
"idiom" : "universal",
"filename" : "created_14.png",
"scale" : "1x"
},
{
"idiom" : "universal",
"scale" : "2x"
},
{
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}
================================================
FILE: liGame/liGame/Assets.xcassets/created_15.imageset/Contents.json
================================================
{
"images" : [
{
"idiom" : "universal",
"filename" : "created_15.png",
"scale" : "1x"
},
{
"idiom" : "universal",
"scale" : "2x"
},
{
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}
================================================
FILE: liGame/liGame/Assets.xcassets/created_16.imageset/Contents.json
================================================
{
"images" : [
{
"idiom" : "universal",
"filename" : "created_16.png",
"scale" : "1x"
},
{
"idiom" : "universal",
"scale" : "2x"
},
{
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}
================================================
FILE: liGame/liGame/Assets.xcassets/created_17.imageset/Contents.json
================================================
{
"images" : [
{
"idiom" : "universal",
"filename" : "created_1.png",
"scale" : "1x"
},
{
"idiom" : "universal",
"scale" : "2x"
},
{
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}
================================================
FILE: liGame/liGame/Assets.xcassets/created_18.imageset/Contents.json
================================================
{
"images" : [
{
"idiom" : "universal",
"filename" : "created_3.png",
"scale" : "1x"
},
{
"idiom" : "universal",
"scale" : "2x"
},
{
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}
================================================
FILE: liGame/liGame/Assets.xcassets/created_2.imageset/Contents.json
================================================
{
"images" : [
{
"idiom" : "universal",
"filename" : "created_2.png",
"scale" : "1x"
},
{
"idiom" : "universal",
"scale" : "2x"
},
{
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}
================================================
FILE: liGame/liGame/Assets.xcassets/created_3.imageset/Contents.json
================================================
{
"images" : [
{
"idiom" : "universal",
"filename" : "created_3.png",
"scale" : "1x"
},
{
"idiom" : "universal",
"scale" : "2x"
},
{
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}
================================================
FILE: liGame/liGame/Assets.xcassets/created_4.imageset/Contents.json
================================================
{
"images" : [
{
"idiom" : "universal",
"filename" : "created_4.png",
"scale" : "1x"
},
{
"idiom" : "universal",
"scale" : "2x"
},
{
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}
================================================
FILE: liGame/liGame/Assets.xcassets/created_5.imageset/Contents.json
================================================
{
"images" : [
{
"idiom" : "universal",
"filename" : "created_5.png",
"scale" : "1x"
},
{
"idiom" : "universal",
"scale" : "2x"
},
{
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}
================================================
FILE: liGame/liGame/Assets.xcassets/created_6.imageset/Contents.json
================================================
{
"images" : [
{
"idiom" : "universal",
"filename" : "created_6.png",
"scale" : "1x"
},
{
"idiom" : "universal",
"scale" : "2x"
},
{
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}
================================================
FILE: liGame/liGame/Assets.xcassets/created_7.imageset/Contents.json
================================================
{
"images" : [
{
"idiom" : "universal",
"filename" : "created_7.png",
"scale" : "1x"
},
{
"idiom" : "universal",
"scale" : "2x"
},
{
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}
================================================
FILE: liGame/liGame/Assets.xcassets/created_8.imageset/Contents.json
================================================
{
"images" : [
{
"idiom" : "universal",
"filename" : "created_8.png",
"scale" : "1x"
},
{
"idiom" : "universal",
"scale" : "2x"
},
{
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}
================================================
FILE: liGame/liGame/Assets.xcassets/created_9.imageset/Contents.json
================================================
{
"images" : [
{
"idiom" : "universal",
"filename" : "created_9.png",
"scale" : "1x"
},
{
"idiom" : "universal",
"scale" : "2x"
},
{
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}
================================================
FILE: liGame/liGame/Assets.xcassets/finalMan.imageset/Contents.json
================================================
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x"
},
{
"idiom" : "universal",
"filename" : "finalMan.png",
"scale" : "2x"
},
{
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}
================================================
FILE: liGame/liGame/Assets.xcassets/finalManContent.imageset/Contents.json
================================================
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x"
},
{
"idiom" : "universal",
"filename" : "finalMamContent.png",
"scale" : "2x"
},
{
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}
================================================
FILE: liGame/liGame/Base.lproj/LaunchScreen.storyboard
================================================
================================================
FILE: liGame/liGame/Base.lproj/Main.storyboard
================================================
================================================
FILE: liGame/liGame/Extension/Animation.swift
================================================
//
// Animation.swift
// WWDC19
//
// Created by PJHubs on 2019/3/20.
// Copyright © 2019 PJHubs. All rights reserved.
//
import UIKit
protocol PJParticleAnimationable {}
extension PJParticleAnimationable where Self: UIViewController {
func startParticleAnimation(_ point : CGPoint) {
let emitter = CAEmitterLayer()
emitter.emitterPosition = point
emitter.preservesDepth = true
var cells = [CAEmitterCell]()
for i in 0..<20 {
let cell = CAEmitterCell()
cell.velocity = 150
cell.velocityRange = 100
cell.scale = 0.7
cell.scaleRange = 0.3
cell.emissionLongitude = CGFloat(-Double.pi / 2)
cell.emissionRange = CGFloat(Double.pi / 2)
cell.lifetime = 3
cell.lifetimeRange = 1.5
cell.spin = CGFloat(Double.pi / 2)
cell.spinRange = CGFloat(Double.pi / 2 / 2)
cell.birthRate = 2
cell.contents = UIImage(named: "Line\(i)")?.cgImage
cells.append(cell)
}
emitter.emitterCells = cells
view.layer.addSublayer(emitter)
}
func stopParticleAnimation() {
view.layer.sublayers?.filter({ $0.isKind(of: CAEmitterLayer.self)}).first?.removeFromSuperlayer()
}
}
================================================
FILE: liGame/liGame/Extension/Define.swift
================================================
//
// Define.swift
// liGame
//
// Created by 翁培钧 on 2019/9/4.
// Copyright © 2019 翁培钧. All rights reserved.
//
import UIKit
/// 屏幕宽
let screenWidth = UIScreen.main.bounds.size.width
/// 屏幕高
let screenHeight = UIScreen.main.bounds.size.height
/// 底部安全距离
let bottomSafeAreaHeight = UIApplication.shared.windows.first?.safeAreaInsets.bottom ?? 0.0
///顶部的安全距离
let topSafeAreaHeight = UIApplication.shared.windows.first?.safeAreaInsets.top ?? 0.0
/// 状态栏高度
let statusBarHeight = UIApplication.shared.statusBarFrame.height;
/// 导航栏高度
let navigationBarHeight = CGFloat(44 + topSafeAreaHeight)
================================================
FILE: liGame/liGame/Extension/UIColor+Extension.swift
================================================
//
// UIColor+Extension.swift
// liGame
//
// Created by 翁培钧 on 2019/9/4.
// Copyright © 2019 翁培钧. All rights reserved.
//
import UIKit
extension UIColor {
class func rgb(_ r: CGFloat, _ g: CGFloat, _ b: CGFloat) -> UIColor {
return UIColor(red: r / 255.0, green: g / 255.0, blue: b / 255.0, alpha: 1)
}
class func rgba(_ r: CGFloat, _ g: CGFloat, _ b: CGFloat, _ a: CGFloat) -> UIColor {
return UIColor(red: r / 255.0, green: g / 255.0, blue: b / 255.0, alpha: a)
}
static var bgColor: UIColor {
return rgb(29, 36, 73)
}
}
================================================
FILE: liGame/liGame/Extension/UIImage+Extension.swift
================================================
//
// UIImage+Extension.swift
// liGame
//
// Created by 翁培钧 on 2019/9/6.
// Copyright © 2019 翁培钧. All rights reserved.
//
import UIKit
extension UIImage {
/// 通过原图获取 rect 大小的图片
func image(with rect: CGRect) -> UIImage {
let scale: CGFloat = 2
let x = rect.origin.x * scale
let y = rect.origin.y * scale
let w = rect.size.width * scale
let h = rect.size.height * scale
let finalRect = CGRect(x: x, y: y, width: w, height: h)
let originImageRef = self.cgImage
let finanImageRef = originImageRef!.cropping(to: finalRect)
let finanImage = UIImage(cgImage: finanImageRef!, scale: scale, orientation: .up)
return finanImage
}
}
================================================
FILE: liGame/liGame/Extension/UIView+Extension.swift
================================================
//
// UIView+Extension.swift
// liGame
//
// Created by 翁培钧 on 2019/9/4.
// Copyright © 2019 翁培钧. All rights reserved.
//
import UIKit
extension UIView {
static private let PJSCREEN_SCALE = UIScreen.main.scale
private func getPixintegral(pointValue: CGFloat) -> CGFloat {
return round(pointValue * UIView.PJSCREEN_SCALE) / UIView.PJSCREEN_SCALE
}
public var x: CGFloat {
get {
return self.frame.origin.x
}
set(x) {
self.frame = CGRect.init(
x: getPixintegral(pointValue: x),
y: self.y,
width: self.width,
height: self.height
)
}
}
public var y: CGFloat {
get {
return self.frame.origin.y
}
set(y) {
self.frame = CGRect.init(
x: self.x,
y: getPixintegral(pointValue: y),
width: self.width,
height: self.height
)
}
}
public var width: CGFloat {
get {
return self.frame.size.width
}
set(width) {
self.frame = CGRect.init(
x: self.x,
y: self.y,
width: getPixintegral(pointValue: width),
height: self.height
)
}
}
public var height: CGFloat {
get {
return self.frame.size.height
}
set (height) {
self.frame = CGRect.init(
x: self.x,
y: self.y,
width: self.width,
height: getPixintegral(pointValue: height)
)
}
}
public var bottom: CGFloat {
get {
return self.y + self.height
}
set(bottom) {
self.y = bottom - self.height
}
}
public var right: CGFloat {
get {
return self.x + self.width
}
set (right) {
self.x = right - self.width
}
}
public var left: CGFloat {
get {
return self.x
}
set(left) {
self.x = left
}
}
public var top: CGFloat {
get {
return self.y
}
set(top) {
self.y = top
}
}
public var centerX: CGFloat {
get {
return self.center.x
}
set(centerX) {
self.center = CGPoint.init(
x: getPixintegral(pointValue: centerX),
y: self.center.y
)
}
}
public var centerY: CGFloat {
get {
return self.center.y
}
set (centerY) {
self.center = CGPoint.init(x: self.center.x, y: getPixintegral(pointValue: centerY))
}
}
}
extension UIView {
func insertRoundingCorners() {
let path = UIBezierPath(roundedRect: bounds, byRoundingCorners: [.topLeft, .topRight], cornerRadii: CGSize(width: 8.0, height: 8.0))
let pathMaskLayer = CAShapeLayer()
pathMaskLayer.frame = bounds
pathMaskLayer.path = path.cgPath
layer.mask = pathMaskLayer
}
}
================================================
FILE: liGame/liGame/Info.plist
================================================
CFBundleDevelopmentRegion
$(DEVELOPMENT_LANGUAGE)
CFBundleExecutable
$(EXECUTABLE_NAME)
CFBundleIdentifier
$(PRODUCT_BUNDLE_IDENTIFIER)
CFBundleInfoDictionaryVersion
6.0
CFBundleName
$(PRODUCT_NAME)
CFBundlePackageType
APPL
CFBundleShortVersionString
1.0
CFBundleVersion
1
LSRequiresIPhoneOS
UILaunchStoryboardName
LaunchScreen
UIMainStoryboardFile
Main
UIRequiredDeviceCapabilities
armv7
UISupportedInterfaceOrientations
UIInterfaceOrientationPortrait
UIInterfaceOrientationLandscapeLeft
UIInterfaceOrientationLandscapeRight
UISupportedInterfaceOrientations~ipad
UIInterfaceOrientationPortrait
UIInterfaceOrientationPortraitUpsideDown
UIInterfaceOrientationLandscapeLeft
UIInterfaceOrientationLandscapeRight
================================================
FILE: liGame/liGame/View/Bottom/LiBottomCollectionView.swift
================================================
//
// LiBottomCollectionView.swift
// liGame
//
// Created by pjhubs on 2019/9/8.
// Copyright © 2019 翁培钧. All rights reserved.
//
import UIKit
class LiBottomCollectionView: UICollectionView {
var longTapBegan: ((Puzzle, CGPoint) -> ())?
var longTapChange: ((CGPoint) -> ())?
var longTapEnded: (() -> ())?
let cellIdentifier = "PJLineCollectionViewCell"
var viewModels = [Puzzle]()
override init(frame: CGRect, collectionViewLayout layout: UICollectionViewLayout) {
super.init(frame: frame, collectionViewLayout: layout)
initView()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
private func initView() {
backgroundColor = .clear
showsHorizontalScrollIndicator = false
isPagingEnabled = true
// isUserInteractionEnabled = true
dataSource = self
register(LiBottomCollectionViewCell.self, forCellWithReuseIdentifier: "LiBottomCollectionViewCell")
}
}
extension LiBottomCollectionView: UICollectionViewDataSource {
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return viewModels.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "LiBottomCollectionViewCell", for: indexPath) as! LiBottomCollectionViewCell
cell.cellIndex = indexPath.row
cell.gameIndex = viewModels[indexPath.row].tag
cell.viewModel = viewModels[indexPath.row]
cell.longTapBegan = { [weak self] index in
guard let self = self else { return }
guard self.viewModels.count != 0 else { return }
self.longTapBegan?(self.viewModels[index], cell.center)
}
cell.longTapChange = {
self.longTapChange?($0)
}
cell.longTapEnded = {
self.viewModels.remove(at: $0)
self.reloadData()
self.longTapEnded?()
}
return cell
}
}
================================================
FILE: liGame/liGame/View/Bottom/LiBottomCollectionViewCell.swift
================================================
//
// LiBottomCollectionViewCell.swift
// liGame
//
// Created by pjhubs on 2019/9/8.
// Copyright © 2019 翁培钧. All rights reserved.
//
import UIKit
class LiBottomCollectionViewCell: UICollectionViewCell {
var longTapBegan: ((Int) -> ())?
var longTapChange: ((CGPoint) -> ())?
var longTapEnded: ((Int) -> ())?
var cellIndex: Int?
var gameIndex: Int?
private var img = UIImageView()
private var tipLabel = UILabel()
var viewModel: Puzzle? {
didSet { setViewModel() }
}
override init(frame: CGRect) {
super.init(frame: frame)
layer.borderWidth = 1
layer.borderColor = UIColor.darkGray.cgColor
layer.shadowColor = UIColor.black.cgColor
layer.shadowRadius = 10
layer.shadowOffset = CGSize.zero
layer.shadowOpacity = 1
img.contentMode = .scaleAspectFit
img.frame = CGRect(x: 0, y: 0, width: width, height: height)
addSubview(img)
tipLabel = UILabel(frame: CGRect(x: width - 10, y: top - 10, width: 17, height: 17))
tipLabel.font = UIFont.systemFont(ofSize: 11)
tipLabel.backgroundColor = UIColor.rgb(80, 80, 80)
tipLabel.textColor = .white
tipLabel.textAlignment = .center
tipLabel.layer.cornerRadius = tipLabel.width / 2
tipLabel.layer.masksToBounds = true
addSubview(tipLabel)
let longTapGesture = UILongPressGestureRecognizer(target: self, action: .longTap)
addGestureRecognizer(longTapGesture)
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
private func setViewModel() {
img.image = viewModel?.image
tipLabel.text = "\(gameIndex!)"
}
}
extension LiBottomCollectionViewCell {
@objc
fileprivate func longTap(_ longTapGesture: UILongPressGestureRecognizer) {
guard let cellIndex = cellIndex else { return }
switch longTapGesture.state {
case .began:
longTapBegan?(cellIndex)
case .changed:
var translation = longTapGesture.location(in: superview)
let itemCount = 5
if cellIndex > itemCount {
translation.x = translation.x - CGFloat(cellIndex / itemCount * Int(screenWidth))
}
let point = CGPoint(x: translation.x, y: translation.y)
longTapChange?(point)
case .ended:
longTapEnded?(cellIndex)
default: break
}
}
}
private extension Selector {
static let longTap = #selector(LiBottomCollectionViewCell.longTap(_:))
}
================================================
FILE: liGame/liGame/View/Bottom/LiBottomView.swift
================================================
//
// LiBottomView.swift
// liGame
//
// Created by pjhubs on 2019/9/8.
// Copyright © 2019 翁培钧. All rights reserved.
//
import UIKit
class LiBottomView: UIView {
var viewModels = [Puzzle]() {
didSet { collectionView!.viewModels = viewModels }
}
var moveBegin: ((Puzzle) -> Void)?
var moveChanged: ((CGPoint) -> Void)?
var moveEnd: ((Puzzle) -> Void)?
var tempPuzzle: Puzzle?
var collectionView: LiBottomCollectionView?
var longPressView: UIView?
private var rightPoint: CGFloat = 0
private var leftaPoint: CGFloat = 0
private var topPoint: CGFloat = 0
private var bottomPoint: CGFloat = 0
public override init(frame: CGRect) {
super.init(frame: frame)
}
convenience init(frame: CGRect, longPressView: UIView?) {
self.init(frame: frame)
self.longPressView = self
initView()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
private func initView() {
backgroundColor = .clear
topPoint = topSafeAreaHeight
bottomPoint = screenHeight - bottomSafeAreaHeight
rightPoint = screenWidth / 2
leftaPoint = 0
let effect = UIBlurEffect(style: .extraLight)
let effectView = UIVisualEffectView(effect: effect)
effectView.frame = CGRect(x: 0, y: 0, width: width, height: height)
addSubview(effectView)
insertRoundingCorners()
let collectionViewLayout = UICollectionViewFlowLayout()
let itemW = 50
let innerW = (screenWidth - 5 * 50) / 5
collectionViewLayout.itemSize = CGSize(width: itemW , height: itemW)
collectionViewLayout.minimumLineSpacing = innerW
collectionViewLayout.minimumInteritemSpacing = 10
collectionViewLayout.scrollDirection = .horizontal
collectionViewLayout.sectionInset = UIEdgeInsets.init(top: 0, left: innerW / 2, bottom: 0, right: innerW / 2)
collectionView = LiBottomCollectionView(frame: CGRect(x: 0, y: 0, width: width, height: height), collectionViewLayout: collectionViewLayout)
addSubview(collectionView!)
collectionView!.longTapBegan = {
let center = $1
let tempPuzzle = Puzzle(size: $0.frame.size, isCopy: false)
// 补上游戏索引 tag
tempPuzzle.tag = $0.tag
tempPuzzle.image = $0.image
tempPuzzle.center = center
tempPuzzle.y += self.top
self.tempPuzzle = tempPuzzle
self.moveBegin?(tempPuzzle)
}
collectionView!.longTapChange = {
guard let tempPuzzle = self.tempPuzzle else { return }
tempPuzzle.center = CGPoint(x: $0.x, y: $0.y + self.top)
if tempPuzzle.right > self.rightPoint {
tempPuzzle.right = self.rightPoint
}
if tempPuzzle.left < self.leftaPoint {
tempPuzzle.left = self.leftaPoint
}
if tempPuzzle.top < self.topPoint {
tempPuzzle.top = self.topPoint
}
if tempPuzzle.bottom > self.bottomPoint {
tempPuzzle.bottom = self.bottomPoint
}
self.moveChanged?(tempPuzzle.center)
}
collectionView!.longTapEnded = {
guard let tempPuzzle = self.tempPuzzle else { return }
self.moveEnd?(tempPuzzle)
}
}
}
extension LiBottomView {
@objc
fileprivate func pan(_ panGesture: UIPanGestureRecognizer) {
let translation = panGesture.translation(in: superview)
panGesture.view!.center = CGPoint(x: panGesture.view!.center.x + translation.x,
y: panGesture.view!.center.y + translation.y)
panGesture.setTranslation(.zero, in: superview)
}
}
private extension Selector {
static let pan = #selector(LiBottomView.pan(_:))
}
================================================
FILE: liGame/liGame/View/Puzzle.swift
================================================
//
// Puzzle.swift
// liGame
//
// Created by 翁培钧 on 2019/9/6.
// Copyright © 2019 翁培钧. All rights reserved.
//
import UIKit
class Puzzle: UIImageView {
var panChange: ((CGPoint) -> ())?
var panEnded: (() -> ())?
var beginMovedPoint = CGPoint()
// 当前在 X 轴上的位置
var Xindex: Int?
// 当前在 Y 轴上的位置
var Yindex: Int?
/// 是否为「拷贝」拼图元素
private var isCopy = false
private var rightPoint: CGFloat = 0
private var leftaPoint: CGFloat = 0
private var topPoint: CGFloat = 0
private var bottomPoint: CGFloat = 0
override init(frame: CGRect) {
super.init(frame: frame)
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
convenience init(size: CGSize, isCopy: Bool) {
self.init(frame: CGRect(x: -1000, y: -1000, width: size.width, height: size.height))
self.isCopy = isCopy
initView()
}
// MARK: Init
private func initView() {
// 全部靠左,copyPuzzle 镜像对称
contentMode = .left
if !isCopy {
isUserInteractionEnabled = true
let panGesture = UIPanGestureRecognizer(target: self, action: .pan)
self.addGestureRecognizer(panGesture)
} else {
transform = CGAffineTransform(scaleX: -1, y: 1)
}
}
/// 更新边界
func updateEdge() {
if superview != nil {
if !isCopy {
topPoint = topSafeAreaHeight
bottomPoint = superview!.bottom - bottomSafeAreaHeight
rightPoint = superview!.width / 2
leftaPoint = 0
}
} else {
if superview != nil {
topPoint = superview!.top
bottomPoint = superview!.bottom
rightPoint = superview!.width
leftaPoint = superview!.width / 2
}
}
}
/// 移动 `rightPuzzle`
func copyPuzzleCenterChange(centerPoint: CGPoint) {
if !isCopy { return }
center = CGPoint(x: screenWidth - centerPoint.x, y: centerPoint.y)
}
}
extension Puzzle {
@objc
fileprivate func pan(_ panGesture: UIPanGestureRecognizer) {
let translation = panGesture.translation(in: superview)
switch panGesture.state {
case .began:
beginMovedPoint = center
layer.borderColor = UIColor.white.cgColor
layer.borderWidth = 1
case .changed:
if right > rightPoint {
right = rightPoint
}
if left < leftaPoint {
left = leftaPoint
}
if top < topPoint {
top = topPoint
}
if bottom > bottomPoint {
bottom = bottomPoint
}
case .ended:
layer.borderWidth = 0
self.panEnded?()
default: break
}
center = CGPoint(x: center.x + translation.x, y: center.y + translation.y)
panGesture.setTranslation(.zero, in: superview)
panChange?(center)
}
}
private extension Selector {
static let pan = #selector(Puzzle.pan(_:))
}
================================================
FILE: liGame/liGame/ViewController.swift
================================================
//
// ViewController.swift
// liGame
//
// Created by 翁培钧 on 2019/9/4.
// Copyright © 2019 翁培钧. All rights reserved.
//
import UIKit
class ViewController: UIViewController, PJParticleAnimationable {
private var lineImageView = UIImageView()
private var bottomView = LiBottomView()
private var puzzles = [Puzzle]()
private var defaultPuzzles = [Puzzle]()
private var finalPuzzleTags = [[Int]]()
private var leftPuzzles = [Puzzle]()
private var rightPuzzles = [Puzzle]()
private var tempCopyPuzzle: Puzzle?
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .bgColor
self.winLabel.isHidden = true
// 底图适配
let contentImage = UIImage(named: "01")!
let contentImageScale = view.width / contentImage.size.width
let contentImageViewHeight = contentImage.size.height * contentImageScale
let contentImageView = UIImageView(frame: CGRect(x: 0, y: topSafeAreaHeight, width: view.width, height: contentImageViewHeight))
contentImageView.image = contentImage
let imgView = UIImageView(frame: CGRect(x: view.width / 2, y: topSafeAreaHeight, width: 5, height: view.height - bottomSafeAreaHeight))
view.addSubview(imgView)
UIGraphicsBeginImageContext(imgView.frame.size) // 位图上下文绘制区域
imgView.image?.draw(in: imgView.bounds)
lineImageView = imgView
let context:CGContext = UIGraphicsGetCurrentContext()!
context.setLineCap(CGLineCap.square)
context.setStrokeColor(UIColor.white.cgColor)
context.setLineWidth(3)
context.setLineDash(phase: 0, lengths: [10,20])
context.move(to: CGPoint(x: 0, y: 0))
context.addLine(to: CGPoint(x: 0, y: view.height))
context.strokePath()
imgView.image = UIGraphicsGetImageFromCurrentImageContext()
// 一行六个
let itemHCount = 3
let itemW = Int(view.width / CGFloat(itemHCount * 2))
let itemH = itemW
let itemVCount = Int(contentImageView.height / CGFloat(itemW))
finalPuzzleTags = Array(repeating: Array(repeating: -1, count: itemHCount), count: itemVCount)
for itemY in 0.. 0 {
tempPuzzleXIndex += 1
}
var tempPuzzleYIndex = CGFloat(Int(tempPuzzleCenterPoint.y / tempPuzzle.height))
if Int(tempPuzzleCenterPoint.y) % Int(tempPuzzle.height) > 0 {
tempPuzzleYIndex += 1
}
let Xedge = tempPuzzleXIndex * tempPuzzle.width
let Yedge = tempPuzzleYIndex * tempPuzzle.height
if tempPuzzleCenterPoint.x < Xedge {
tempPuzzleCenterPoint.x = Xedge - tempPuzzle.width / 2
}
if tempPuzzleCenterPoint.y < Yedge {
// 当为最后一列时,往上移 20
if (Int(tempPuzzleYIndex) == finalPuzzleTags.count) {
tempPuzzleCenterPoint.y = Yedge - tempPuzzle.height / 2 - 20
} else {
tempPuzzleCenterPoint.y = Yedge - tempPuzzle.height / 2
}
}
// 超出最下边
if (Int(tempPuzzleYIndex) > self.finalPuzzleTags.count) {
tempPuzzle.center = tempPuzzle.beginMovedPoint
}
// 已经有的不能占据
if (self.finalPuzzleTags[Int(tempPuzzleYIndex - 1)][Int(tempPuzzleXIndex - 1)] == -1) {
self.finalPuzzleTags[Int(tempPuzzleYIndex - 1)][Int(tempPuzzleXIndex - 1)] = tempPuzzle.tag
if ((tempPuzzle.Xindex != nil) && (tempPuzzle.Yindex != nil)) {
self.finalPuzzleTags[tempPuzzle.Xindex!][tempPuzzle.Yindex!] = -1
}
tempPuzzle.Xindex = Int(tempPuzzleYIndex - 1)
tempPuzzle.Yindex = Int(tempPuzzleXIndex - 1)
tempPuzzle.center = tempPuzzleCenterPoint
} else {
tempPuzzle.center = tempPuzzle.beginMovedPoint
}
}
/// 判赢算法
private func isWin() -> Bool {
var winCount = 0
for (Vindex, HTags) in self.finalPuzzleTags.enumerated() {
for (Hindex, tag) in HTags.enumerated() {
let currentIndex = Vindex * 3 + Hindex
if defaultPuzzles.count - 1 >= currentIndex {
if defaultPuzzles[currentIndex].tag == tag {
winCount += 1
continue
}
}
return false
}
}
if winCount == defaultPuzzles.count {
return true
}
return false
}
private func winAnimate() {
startParticleAnimation(CGPoint(x: screenWidth / 2, y: screenHeight - 10))
UIView.animate(withDuration: 0.25, animations: {
self.bottomView.top = screenHeight
})
for sv in self.view.subviews {
sv.removeFromSuperview()
}
self.winLabel.isHidden = false
let finalManContentView = UIImageView(frame: CGRect(x: 0, y: 0,
width: screenWidth,
height: screenHeight - 64))
finalManContentView.image = UIImage(named: "finalManContent")
self.view.addSubview(finalManContentView)
let finalMan = UIImageView(frame: CGRect(x: 0, y: 0,
width: finalManContentView.width * 0.85,
height: finalManContentView.width * 0.8 * 0.85))
finalMan.center = self.view.center
finalMan.image = UIImage(named: "finalMan")
self.view.addSubview(finalMan)
UIView.animate(withDuration: 0.5, animations: {
finalMan.transform = CGAffineTransform(rotationAngle: 0.25)
}) { (finished) in
UIView.animate(withDuration: 0.5, animations: {
finalMan.transform = CGAffineTransform(rotationAngle: -0.25)
}, completion: { (finished) in
UIView.animate(withDuration: 0.5, animations: {
finalMan.transform = CGAffineTransform(rotationAngle: 0)
})
})
}
}
// MARK: - Lazy
lazy var winLabel: UILabel = {
let label = UILabel(frame: CGRect(x: 0, y: screenHeight - 64,
width: screenWidth, height: 64))
label.centerX = view.centerX
label.font = UIFont.systemFont(ofSize: 40,
weight: UIFont.Weight.light)
label.text = "Dàlì shén"
label.textAlignment = .center
label.textColor = .white
view.addSubview(label)
return label
}()
}
================================================
FILE: liGame/liGame.xcodeproj/project.pbxproj
================================================
// !$*UTF8*$!
{
archiveVersion = 1;
classes = {
};
objectVersion = 50;
objects = {
/* Begin PBXBuildFile section */
0C7ACB9C2322A97000AA4FA4 /* UIImage+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0C7ACB9B2322A97000AA4FA4 /* UIImage+Extension.swift */; };
0C99777123200DE600EA0130 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0C99777023200DE600EA0130 /* AppDelegate.swift */; };
0C99777323200DE600EA0130 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0C99777223200DE600EA0130 /* ViewController.swift */; };
0C99777623200DE600EA0130 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 0C99777423200DE600EA0130 /* Main.storyboard */; };
0C99777823200DE700EA0130 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 0C99777723200DE700EA0130 /* Assets.xcassets */; };
0C99777B23200DE700EA0130 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 0C99777923200DE700EA0130 /* LaunchScreen.storyboard */; };
0C9977832320135200EA0130 /* UIView+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0C9977822320135200EA0130 /* UIView+Extension.swift */; };
0C997785232013C300EA0130 /* UIColor+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0C997784232013C300EA0130 /* UIColor+Extension.swift */; };
0C997788232014A500EA0130 /* Define.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0C997787232014A500EA0130 /* Define.swift */; };
0CAE10A62321E76900CFECA5 /* Puzzle.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0CAE10A52321E76900CFECA5 /* Puzzle.swift */; };
0CE27C0A2371C4950032CF94 /* Animation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0CE27C092371C4950032CF94 /* Animation.swift */; };
A64F18812325121900F531F4 /* LiBottomCollectionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A64F18802325121900F531F4 /* LiBottomCollectionView.swift */; };
A64F18832325126800F531F4 /* LiBottomCollectionViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = A64F18822325126800F531F4 /* LiBottomCollectionViewCell.swift */; };
A64F18852325133E00F531F4 /* LiBottomView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A64F18842325133E00F531F4 /* LiBottomView.swift */; };
/* End PBXBuildFile section */
/* Begin PBXFileReference section */
0C7ACB9B2322A97000AA4FA4 /* UIImage+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIImage+Extension.swift"; sourceTree = ""; };
0C99776D23200DE600EA0130 /* liGame.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = liGame.app; sourceTree = BUILT_PRODUCTS_DIR; };
0C99777023200DE600EA0130 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; };
0C99777223200DE600EA0130 /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = ""; };
0C99777523200DE600EA0130 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; };
0C99777723200DE700EA0130 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; };
0C99777A23200DE700EA0130 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; };
0C99777C23200DE700EA0130 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
0C9977822320135200EA0130 /* UIView+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIView+Extension.swift"; sourceTree = ""; };
0C997784232013C300EA0130 /* UIColor+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIColor+Extension.swift"; sourceTree = ""; };
0C997787232014A500EA0130 /* Define.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Define.swift; sourceTree = ""; };
0CAE10A52321E76900CFECA5 /* Puzzle.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Puzzle.swift; sourceTree = ""; };
0CE27C092371C4950032CF94 /* Animation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Animation.swift; sourceTree = ""; };
A64F18802325121900F531F4 /* LiBottomCollectionView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LiBottomCollectionView.swift; sourceTree = ""; };
A64F18822325126800F531F4 /* LiBottomCollectionViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LiBottomCollectionViewCell.swift; sourceTree = ""; };
A64F18842325133E00F531F4 /* LiBottomView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LiBottomView.swift; sourceTree = ""; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
0C99776A23200DE600EA0130 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
0C99776423200DE600EA0130 = {
isa = PBXGroup;
children = (
0C99776F23200DE600EA0130 /* liGame */,
0C99776E23200DE600EA0130 /* Products */,
);
sourceTree = "";
};
0C99776E23200DE600EA0130 /* Products */ = {
isa = PBXGroup;
children = (
0C99776D23200DE600EA0130 /* liGame.app */,
);
name = Products;
sourceTree = "";
};
0C99776F23200DE600EA0130 /* liGame */ = {
isa = PBXGroup;
children = (
0C99777023200DE600EA0130 /* AppDelegate.swift */,
0C99777223200DE600EA0130 /* ViewController.swift */,
0C9977892321E70900EA0130 /* View */,
0C9977862320149900EA0130 /* Extension */,
0C99777423200DE600EA0130 /* Main.storyboard */,
0C99777723200DE700EA0130 /* Assets.xcassets */,
0C99777923200DE700EA0130 /* LaunchScreen.storyboard */,
0C99777C23200DE700EA0130 /* Info.plist */,
);
path = liGame;
sourceTree = "";
};
0C9977862320149900EA0130 /* Extension */ = {
isa = PBXGroup;
children = (
0CE27C092371C4950032CF94 /* Animation.swift */,
0C9977822320135200EA0130 /* UIView+Extension.swift */,
0C997784232013C300EA0130 /* UIColor+Extension.swift */,
0C997787232014A500EA0130 /* Define.swift */,
0C7ACB9B2322A97000AA4FA4 /* UIImage+Extension.swift */,
);
path = Extension;
sourceTree = "";
};
0C9977892321E70900EA0130 /* View */ = {
isa = PBXGroup;
children = (
A64F187F232511F500F531F4 /* Bottom */,
0CAE10A52321E76900CFECA5 /* Puzzle.swift */,
);
path = View;
sourceTree = "";
};
A64F187F232511F500F531F4 /* Bottom */ = {
isa = PBXGroup;
children = (
A64F18802325121900F531F4 /* LiBottomCollectionView.swift */,
A64F18822325126800F531F4 /* LiBottomCollectionViewCell.swift */,
A64F18842325133E00F531F4 /* LiBottomView.swift */,
);
path = Bottom;
sourceTree = "";
};
/* End PBXGroup section */
/* Begin PBXNativeTarget section */
0C99776C23200DE600EA0130 /* liGame */ = {
isa = PBXNativeTarget;
buildConfigurationList = 0C99777F23200DE700EA0130 /* Build configuration list for PBXNativeTarget "liGame" */;
buildPhases = (
0C99776923200DE600EA0130 /* Sources */,
0C99776A23200DE600EA0130 /* Frameworks */,
0C99776B23200DE600EA0130 /* Resources */,
);
buildRules = (
);
dependencies = (
);
name = liGame;
productName = liGame;
productReference = 0C99776D23200DE600EA0130 /* liGame.app */;
productType = "com.apple.product-type.application";
};
/* End PBXNativeTarget section */
/* Begin PBXProject section */
0C99776523200DE600EA0130 /* Project object */ = {
isa = PBXProject;
attributes = {
LastSwiftUpdateCheck = 1020;
LastUpgradeCheck = 1020;
ORGANIZATIONNAME = "翁培钧";
TargetAttributes = {
0C99776C23200DE600EA0130 = {
CreatedOnToolsVersion = 10.2.1;
};
};
};
buildConfigurationList = 0C99776823200DE600EA0130 /* Build configuration list for PBXProject "liGame" */;
compatibilityVersion = "Xcode 9.3";
developmentRegion = en;
hasScannedForEncodings = 0;
knownRegions = (
en,
Base,
);
mainGroup = 0C99776423200DE600EA0130;
productRefGroup = 0C99776E23200DE600EA0130 /* Products */;
projectDirPath = "";
projectRoot = "";
targets = (
0C99776C23200DE600EA0130 /* liGame */,
);
};
/* End PBXProject section */
/* Begin PBXResourcesBuildPhase section */
0C99776B23200DE600EA0130 /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
0C99777B23200DE700EA0130 /* LaunchScreen.storyboard in Resources */,
0C99777823200DE700EA0130 /* Assets.xcassets in Resources */,
0C99777623200DE600EA0130 /* Main.storyboard in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXResourcesBuildPhase section */
/* Begin PBXSourcesBuildPhase section */
0C99776923200DE600EA0130 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
0CE27C0A2371C4950032CF94 /* Animation.swift in Sources */,
A64F18812325121900F531F4 /* LiBottomCollectionView.swift in Sources */,
0C9977832320135200EA0130 /* UIView+Extension.swift in Sources */,
0C7ACB9C2322A97000AA4FA4 /* UIImage+Extension.swift in Sources */,
0C99777323200DE600EA0130 /* ViewController.swift in Sources */,
A64F18832325126800F531F4 /* LiBottomCollectionViewCell.swift in Sources */,
0C99777123200DE600EA0130 /* AppDelegate.swift in Sources */,
0CAE10A62321E76900CFECA5 /* Puzzle.swift in Sources */,
0C997788232014A500EA0130 /* Define.swift in Sources */,
A64F18852325133E00F531F4 /* LiBottomView.swift in Sources */,
0C997785232013C300EA0130 /* UIColor+Extension.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXSourcesBuildPhase section */
/* Begin PBXVariantGroup section */
0C99777423200DE600EA0130 /* Main.storyboard */ = {
isa = PBXVariantGroup;
children = (
0C99777523200DE600EA0130 /* Base */,
);
name = Main.storyboard;
sourceTree = "";
};
0C99777923200DE700EA0130 /* LaunchScreen.storyboard */ = {
isa = PBXVariantGroup;
children = (
0C99777A23200DE700EA0130 /* Base */,
);
name = LaunchScreen.storyboard;
sourceTree = "";
};
/* End PBXVariantGroup section */
/* Begin XCBuildConfiguration section */
0C99777D23200DE700EA0130 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_NONNULL = YES;
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_ENABLE_OBJC_WEAK = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
CODE_SIGN_IDENTITY = "iPhone Developer";
COPY_PHASE_STRIP = NO;
DEBUG_INFORMATION_FORMAT = dwarf;
ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_TESTABILITY = YES;
GCC_C_LANGUAGE_STANDARD = gnu11;
GCC_DYNAMIC_NO_PIC = NO;
GCC_NO_COMMON_BLOCKS = YES;
GCC_OPTIMIZATION_LEVEL = 0;
GCC_PREPROCESSOR_DEFINITIONS = (
"DEBUG=1",
"$(inherited)",
);
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 12.2;
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
MTL_FAST_MATH = YES;
ONLY_ACTIVE_ARCH = YES;
SDKROOT = iphoneos;
SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
};
name = Debug;
};
0C99777E23200DE700EA0130 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_NONNULL = YES;
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_ENABLE_OBJC_WEAK = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
CODE_SIGN_IDENTITY = "iPhone Developer";
COPY_PHASE_STRIP = NO;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
ENABLE_NS_ASSERTIONS = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
GCC_C_LANGUAGE_STANDARD = gnu11;
GCC_NO_COMMON_BLOCKS = YES;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 12.2;
MTL_ENABLE_DEBUG_INFO = NO;
MTL_FAST_MATH = YES;
SDKROOT = iphoneos;
SWIFT_COMPILATION_MODE = wholemodule;
SWIFT_OPTIMIZATION_LEVEL = "-O";
VALIDATE_PRODUCT = YES;
};
name = Release;
};
0C99778023200DE700EA0130 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CODE_SIGN_STYLE = Automatic;
DEVELOPMENT_TEAM = U6J5965DZK;
INFOPLIST_FILE = liGame/Info.plist;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
);
PRODUCT_BUNDLE_IDENTIFIER = com.pjhubs.liGame;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = "1,2";
};
name = Debug;
};
0C99778123200DE700EA0130 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CODE_SIGN_STYLE = Automatic;
DEVELOPMENT_TEAM = U6J5965DZK;
INFOPLIST_FILE = liGame/Info.plist;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
);
PRODUCT_BUNDLE_IDENTIFIER = com.pjhubs.liGame;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = "1,2";
};
name = Release;
};
/* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */
0C99776823200DE600EA0130 /* Build configuration list for PBXProject "liGame" */ = {
isa = XCConfigurationList;
buildConfigurations = (
0C99777D23200DE700EA0130 /* Debug */,
0C99777E23200DE700EA0130 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
0C99777F23200DE700EA0130 /* Build configuration list for PBXNativeTarget "liGame" */ = {
isa = XCConfigurationList;
buildConfigurations = (
0C99778023200DE700EA0130 /* Debug */,
0C99778123200DE700EA0130 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
/* End XCConfigurationList section */
};
rootObject = 0C99776523200DE600EA0130 /* Project object */;
}
================================================
FILE: liGame/liGame.xcodeproj/project.xcworkspace/contents.xcworkspacedata
================================================
================================================
FILE: liGame/liGame.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist
================================================
IDEDidComputeMac32BitWarning
================================================
FILE: liGame/liGame.xcodeproj/xcuserdata/pjhubs.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist
================================================
================================================
FILE: liGame/liGame.xcodeproj/xcuserdata/pjhubs.xcuserdatad/xcschemes/xcschememanagement.plist
================================================
SchemeUserState
liGame.xcscheme_^#shared#^_
orderHint
0
================================================
FILE: liGame/liGame.xcodeproj/xcuserdata/wengpeijun.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist
================================================
================================================
FILE: liGame/liGame.xcodeproj/xcuserdata/wengpeijun.xcuserdatad/xcschemes/xcschememanagement.plist
================================================
SchemeUserState
liGame.xcscheme_^#shared#^_
orderHint
0
================================================
FILE: lightGame/light-game/AppDelegate.swift
================================================
//
// AppDelegate.swift
// light-game
//
// Created by pjhubs on 2019/8/29.
// Copyright © 2019 PJHubs. All rights reserved.
//
import UIKit
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
return true
}
// MARK: UISceneSession Lifecycle
func application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration {
// Called when a new scene session is being created.
// Use this method to select a configuration to create the new scene with.
return UISceneConfiguration(name: "Default Configuration", sessionRole: connectingSceneSession.role)
}
func application(_ application: UIApplication, didDiscardSceneSessions sceneSessions: Set) {
// Called when the user discards a scene session.
// If any sessions were discarded while the application was not running, this will be called shortly after application:didFinishLaunchingWithOptions.
// Use this method to release any resources that were specific to the discarded scenes, as they will not return.
}
}
================================================
FILE: lightGame/light-game/Assets.xcassets/AppIcon.appiconset/Contents.json
================================================
{
"images" : [
{
"idiom" : "iphone",
"size" : "20x20",
"scale" : "2x"
},
{
"idiom" : "iphone",
"size" : "20x20",
"scale" : "3x"
},
{
"idiom" : "iphone",
"size" : "29x29",
"scale" : "2x"
},
{
"idiom" : "iphone",
"size" : "29x29",
"scale" : "3x"
},
{
"idiom" : "iphone",
"size" : "40x40",
"scale" : "2x"
},
{
"idiom" : "iphone",
"size" : "40x40",
"scale" : "3x"
},
{
"idiom" : "iphone",
"size" : "60x60",
"scale" : "2x"
},
{
"idiom" : "iphone",
"size" : "60x60",
"scale" : "3x"
},
{
"idiom" : "ipad",
"size" : "20x20",
"scale" : "1x"
},
{
"idiom" : "ipad",
"size" : "20x20",
"scale" : "2x"
},
{
"idiom" : "ipad",
"size" : "29x29",
"scale" : "1x"
},
{
"idiom" : "ipad",
"size" : "29x29",
"scale" : "2x"
},
{
"idiom" : "ipad",
"size" : "40x40",
"scale" : "1x"
},
{
"idiom" : "ipad",
"size" : "40x40",
"scale" : "2x"
},
{
"idiom" : "ipad",
"size" : "76x76",
"scale" : "1x"
},
{
"idiom" : "ipad",
"size" : "76x76",
"scale" : "2x"
},
{
"idiom" : "ipad",
"size" : "83.5x83.5",
"scale" : "2x"
},
{
"idiom" : "ios-marketing",
"size" : "1024x1024",
"scale" : "1x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}
================================================
FILE: lightGame/light-game/Assets.xcassets/Contents.json
================================================
{
"info" : {
"version" : 1,
"author" : "xcode"
}
}
================================================
FILE: lightGame/light-game/Base.lproj/LaunchScreen.storyboard
================================================
================================================
FILE: lightGame/light-game/ContentView.swift
================================================
//
// ContentView.swift
// light-game
//
// Created by pjhubs on 2019/8/29.
// Copyright © 2019 PJHubs. All rights reserved.
//
import SwiftUI
struct ContentView: View {
@ObservedObject var gameManager = GameManager(size: 5, lightSequence: [1, 2, 3])
@State var isShowHistory = false
var body: some View {
VStack {
HStack {
Text("\(gameManager.timeString)")
.font(.system(size: 45))
Spacer()
Text("\(gameManager.clickTimes)步")
.font(.system(size: 45))
}
.padding(20)
ForEach(0..
CFBundleDevelopmentRegion
$(DEVELOPMENT_LANGUAGE)
CFBundleExecutable
$(EXECUTABLE_NAME)
CFBundleIdentifier
$(PRODUCT_BUNDLE_IDENTIFIER)
CFBundleInfoDictionaryVersion
6.0
CFBundleName
$(PRODUCT_NAME)
CFBundlePackageType
$(PRODUCT_BUNDLE_PACKAGE_TYPE)
CFBundleShortVersionString
1.0
CFBundleVersion
1
LSRequiresIPhoneOS
UIApplicationSceneManifest
UIApplicationSupportsMultipleScenes
UISceneConfigurations
UIWindowSceneSessionRoleApplication
UISceneConfigurationName
Default Configuration
UISceneDelegateClassName
$(PRODUCT_MODULE_NAME).SceneDelegate
UILaunchStoryboardName
LaunchScreen
UIRequiredDeviceCapabilities
armv7
UISupportedInterfaceOrientations
UIInterfaceOrientationPortrait
UIInterfaceOrientationLandscapeLeft
UIInterfaceOrientationLandscapeRight
UISupportedInterfaceOrientations~ipad
UIInterfaceOrientationPortrait
UIInterfaceOrientationPortraitUpsideDown
UIInterfaceOrientationLandscapeLeft
UIInterfaceOrientationLandscapeRight
================================================
FILE: lightGame/light-game/Model/GameController.swift
================================================
//
// GameController.swift
// light-game
//
// Created by 翁培钧 on 2019/11/30.
// Copyright © 2019 PJHubs. All rights reserved.
//
import GameController
class GameController {
var movingX = false
var movingY = false
var isSelectX: ((Bool) -> ())?
var isSelectY: ((Bool) -> ())?
var isTapButtonA: (() -> ())?
var isTapButtonB: (() -> ())?
init() {
NotificationCenter.default.addObserver(self, selector: .didConnect, name: .GCControllerDidConnect, object: nil)
NotificationCenter.default.addObserver(self, selector: .didConnect, name: .GCControllerDidDisconnect, object: nil)
}
}
extension GameController {
@objc fileprivate func gameControllerDidConnect() {
for controller in GCController.controllers() {
if controller.extendedGamepad != nil {
setupControllerControls(controller: controller)
}
}
}
@objc fileprivate func gameControllerDidDisconnect() {
}
func setupControllerControls(controller: GCController) {
controller.extendedGamepad?.valueChangedHandler = {
(gamepad: GCExtendedGamepad, element: GCControllerElement) in
self.controllerInput(gamePad: gamepad, element: element)
}
}
private func controllerInput(gamePad: GCExtendedGamepad, element: GCControllerElement) {
// gamePad 为支持的类型,element 为当前手柄的输入
// 不能 return,因为单次出发会带入多个按键的值
if (gamePad.leftThumbstick == element) {
if (gamePad.leftThumbstick.yAxis.value != 0 && !movingY && !movingX) {
movingY = true
isSelectY?(gamePad.leftThumbstick.yAxis.value > 0)
} else if (gamePad.leftThumbstick.yAxis.value == 0) {
movingY = false
}
if (gamePad.leftThumbstick.xAxis.value != 0 && !movingX && !movingY) {
isSelectX?(gamePad.leftThumbstick.xAxis.value > 0)
movingX = true
} else if (gamePad.leftThumbstick.xAxis.value == 0) {
movingX = false
}
} else if (gamePad.rightThumbstick == element) {
if (gamePad.rightThumbstick.xAxis.value != 0) {
print("rightThumbstickXAxis: \(gamePad.rightThumbstick.xAxis)")
}
} else if (gamePad.dpad == element) {
if (gamePad.dpad.xAxis.value != 0) {
isSelectX?(gamePad.dpad.xAxis.value > 0)
} else if (gamePad.dpad.xAxis.value == 0) {
}
if (gamePad.dpad.yAxis.value != 0) {
isSelectY?(gamePad.dpad.yAxis.value > 0)
} else if (gamePad.dpad.yAxis.value == 0) {
}
} else if (gamePad.buttonA == element) {
if (gamePad.buttonA.value != 0) {
isTapButtonA?()
}
} else if (gamePad.buttonB == element) {
if (gamePad.buttonB.value != 0) {
isTapButtonB?()
}
} else if (gamePad.buttonY == element) {
if (gamePad.buttonY.value != 0) {
// print("Y-Button Pressed!")
// buttonYTap = true
}
} else if (gamePad.buttonX == element) {
if (gamePad.buttonX.value != 0) {
// print("X-Button Pressed!")
// buttonXTap = true
}
}
}
}
private extension Selector {
static let didConnect = #selector(GameController.gameControllerDidConnect)
static let didDisConnect = #selector(GameController.gameControllerDidDisconnect)
}
================================================
FILE: lightGame/light-game/Model/GameManager.swift
================================================
//
// GameManager.swift
// light-game
//
// Created by pjhubs on 2019/8/30.
// Copyright © 2019 PJHubs. All rights reserved.
//
import SwiftUI
import Combine
class GameManager: ObservableObject {
/// 对外发布的格式化计时器字符串
@Published var timeString = "00:00"
/// 点击次数
@Published var clickTimes = 0
/// 灯状态
@Published var lights = [[Light]]()
@Published var isWin = false
/// 当前游戏状态
private var currentStatus: GameStatus = .during {
didSet {
switch currentStatus {
case .win: isWin = true
case .lose: isWin = false
case .during: break
}
}
}
/// 游戏尺寸大小
private(set) var size: Int?
/// 游戏计时器
private var timer: Timer?
/// 游戏持续时间
private var durations = 1
private var gameController = GameController()
private var row = 0
private var column = 0
private var pRow = 0
private var pColumn = 0
/// 游戏控制器暂停
private var isPause = false
// MARK: - Init
/// 便捷构造方法
/// - Parameters:
/// - size: 游戏布局尺寸,默认值 5x5
/// - lightSequence: 亮灯序列,默认全灭
convenience init(size: Int = 5,
lightSequence: [Int] = [Int]()) {
self.init()
var size = size
// 太大了不好玩
if size > 8 {
size = 7
}
// 太小了没意思
if size < 2 {
size = 2
}
self.size = size
lights = Array(repeating: Array(repeating: Light(), count: size), count: size)
initGameController()
start(lightSequence)
}
// MARK: Public
/// 游戏配置
/// - Parameter lightSequence: 亮灯序列
func start(_ lightSequence: [Int]) {
currentStatus = .during
clickTimes = 0
updateLightStatus(lightSequence)
timer = Timer.scheduledTimer(withTimeInterval: 1, repeats: true, block: { timer in
let min = self.durations >= 60 ? self.durations / 60 : 0
let seconds = self.durations - min * 60
let minString = min >= 10 ? "\(min)" : "0\(min)"
let secondString = self.durations - min * 60 >= 10 ? "\(seconds)" : "0\(seconds)"
self.timeString = minString + ":" + secondString
self.durations += 1
})
}
/// 停止
func timerStop() {
timer?.fireDate = Date.distantFuture
}
/// 重新创建
func timerRestart() {
isPause = false
durations = 0
timeString = "00:00"
timer?.fireDate = Date()
}
/// 获取灯的尺寸
func circleWidth() -> CGFloat {
guard let size = size else { return 0 }
/// 距离屏幕左右两边的间距
let padding: CGFloat = 20
/// 左右两灯之间的间距
let innerSpacing: CGFloat = 20
var circleWidth = (UIScreen.main.bounds.width - padding - (CGFloat(size) * innerSpacing)) / CGFloat(size)
// 太大了会很丑,过滤下
if circleWidth > UIScreen.main.bounds.width / 5 {
circleWidth = UIScreen.main.bounds.width / 5
}
return circleWidth
}
/// 通过坐标索引修改灯状态
/// - Parameters:
/// - column: 灯-列索引
/// - size: 灯-行索引
func updateLightStatus(column: Int, row: Int, userTouch: Bool) {
lights[row][column].status.toggle()
self.column = row
self.row = column
// 上
let top = row - 1
if !(top < 0) {
lights[top][column].status.toggle()
}
// 下
let bottom = row + 1
if !(bottom > lights.count - 1) {
lights[bottom][column].status.toggle()
}
// 左
let left = column - 1
if !(left < 0) {
lights[row][left].status.toggle()
}
// 右
let right = column + 1
if !(right > lights.count - 1) {
lights[row][right].status.toggle()
}
updateGameStatus()
if (userTouch) {
disSelectedGameControllerStatus()
}
}
// MARK: Private
/// 通过亮灯序列修改灯状态
/// - Parameter lightSequence: 亮灯序列
private func updateLightStatus(_ lightSequence: [Int]) {
guard let size = size else { return }
for lightIndex in lightSequence {
var index = lightIndex
// 防止数组越出最大边界处
if index >= size * size {
index = size * size - 1
}
let row = lightIndex / size
let column = lightIndex % size
// column 不为 0,说明非最后一个
// row 为 0,说明为第一行
updateLightStatus(column: column, row: row, userTouch: true)
}
}
private func updateLightSelected() {
lights[pColumn][pRow].selected = false
lights[column][row].selected = true
pRow = row
pColumn = column
}
private func disSelectedGameControllerStatus() {
lights[pColumn][pRow].selected = false
}
/// 判赢
private func updateGameStatus() {
guard let size = size else { return }
var lightingCount = 0
for lightArr in lights {
for light in lightArr {
if light.status { lightingCount += 1 }
}
}
if lightingCount == size * size {
timerStop()
currentStatus = .lose
return
}
if lightingCount == 0 {
timerStop()
currentStatus = .win
isPause = true
return
}
}
private func initGameController() {
gameController.isSelectX = {
guard !self.isPause else { return }
if $0 {
if (self.row < self.lights.count - 1) {
self.row += 1
}
} else {
if self.row > 0 {
self.row -= 1
}
}
self.updateLightSelected()
}
gameController.isSelectY = {
guard !self.isPause else { return }
if $0 {
if (self.column > 0) {
self.column -= 1
}
} else {
if (self.column < self.lights.count - 1) {
self.column += 1
}
}
self.updateLightSelected()
}
gameController.isTapButtonA = {
self.clickTimes += 1
self.updateLightStatus(column: self.row, row: self.column, userTouch: false)
}
}
}
extension GameManager {
enum GameStatus {
/// 赢
case win
/// 输
case lose
/// 进行中
case during
}
}
================================================
FILE: lightGame/light-game/Model/Light.swift
================================================
//
// Light.swift
// light-game
//
// Created by pjhubs on 2019/8/29.
// Copyright © 2019 PJHubs. All rights reserved.
//
import Foundation
struct Light {
/// 开关状态
var status = false
/// 选中状态
var selected = false
}
================================================
FILE: lightGame/light-game/Preview Content/Preview Assets.xcassets/Contents.json
================================================
{
"info" : {
"version" : 1,
"author" : "xcode"
}
}
================================================
FILE: lightGame/light-game/SceneDelegate.swift
================================================
//
// SceneDelegate.swift
// light-game
//
// Created by pjhubs on 2019/8/29.
// Copyright © 2019 PJHubs. All rights reserved.
//
import UIKit
import SwiftUI
class SceneDelegate: UIResponder, UIWindowSceneDelegate {
var window: UIWindow?
func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
// Use this method to optionally configure and attach the UIWindow `window` to the provided UIWindowScene `scene`.
// If using a storyboard, the `window` property will automatically be initialized and attached to the scene.
// This delegate does not imply the connecting scene or session are new (see `application:configurationForConnectingSceneSession` instead).
// Create the SwiftUI view that provides the window contents.
#if !os(watchOS)
let contentView = ContentView()
#else
let contentView = WatchContentView()
#endif
// Use a UIHostingController as window root view controller.
if let windowScene = scene as? UIWindowScene {
let window = UIWindow(windowScene: windowScene)
window.rootViewController = UIHostingController(rootView: contentView)
self.window = window
window.makeKeyAndVisible()
}
}
func sceneDidDisconnect(_ scene: UIScene) {
// Called as the scene is being released by the system.
// This occurs shortly after the scene enters the background, or when its session is discarded.
// Release any resources associated with this scene that can be re-created the next time the scene connects.
// The scene may re-connect later, as its session was not neccessarily discarded (see `application:didDiscardSceneSessions` instead).
}
func sceneDidBecomeActive(_ scene: UIScene) {
// Called when the scene has moved from an inactive state to an active state.
// Use this method to restart any tasks that were paused (or not yet started) when the scene was inactive.
}
func sceneWillResignActive(_ scene: UIScene) {
// Called when the scene will move from an active state to an inactive state.
// This may occur due to temporary interruptions (ex. an incoming phone call).
}
func sceneWillEnterForeground(_ scene: UIScene) {
// Called as the scene transitions from the background to the foreground.
// Use this method to undo the changes made on entering the background.
}
func sceneDidEnterBackground(_ scene: UIScene) {
// Called as the scene transitions from the foreground to the background.
// Use this method to save data, release shared resources, and store enough scene-specific state information
// to restore the scene back to its current state.
}
}
================================================
FILE: lightGame/light-game.xcodeproj/project.pbxproj
================================================
// !$*UTF8*$!
{
archiveVersion = 1;
classes = {
};
objectVersion = 50;
objects = {
/* Begin PBXBuildFile section */
0C39CB06239BEF1100444729 /* Light.swift in Sources */ = {isa = PBXBuildFile; fileRef = A601DB2A2317775100327867 /* Light.swift */; };
0C39CB0B239BF2EE00444729 /* WatchGameManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0C39CB0A239BF2EE00444729 /* WatchGameManager.swift */; };
0C39CB0D239C020000444729 /* WatchContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0C39CB0C239C020000444729 /* WatchContentView.swift */; };
0C3DCCE42392A5CC00C762A9 /* GameController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0C3DCCE32392A5CC00C762A9 /* GameController.swift */; };
0C751029239BEAA500E85E20 /* Interface.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 0C751027239BEAA500E85E20 /* Interface.storyboard */; };
0C75102B239BEAA800E85E20 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 0C75102A239BEAA800E85E20 /* Assets.xcassets */; };
0C751032239BEAA900E85E20 /* watchapp Extension.appex in Embed App Extensions */ = {isa = PBXBuildFile; fileRef = 0C751031239BEAA900E85E20 /* watchapp Extension.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
0C751039239BEAA900E85E20 /* HostingController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0C751038239BEAA900E85E20 /* HostingController.swift */; };
0C75103B239BEAA900E85E20 /* ExtensionDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0C75103A239BEAA900E85E20 /* ExtensionDelegate.swift */; };
0C75103D239BEAA900E85E20 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 0C75103C239BEAA900E85E20 /* Assets.xcassets */; };
0C751040239BEAA900E85E20 /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 0C75103F239BEAA900E85E20 /* Preview Assets.xcassets */; };
0C751044239BEAA900E85E20 /* watchapp.app in Embed Watch Content */ = {isa = PBXBuildFile; fileRef = 0C751025239BEAA500E85E20 /* watchapp.app */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
A601DB2B2317775100327867 /* Light.swift in Sources */ = {isa = PBXBuildFile; fileRef = A601DB2A2317775100327867 /* Light.swift */; };
A62D002F231904F80062A70E /* GameManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = A62D002E231904F80062A70E /* GameManager.swift */; };
A676EA93231771D3002074BF /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = A676EA92231771D3002074BF /* AppDelegate.swift */; };
A676EA95231771D3002074BF /* SceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = A676EA94231771D3002074BF /* SceneDelegate.swift */; };
A676EA97231771D3002074BF /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A676EA96231771D3002074BF /* ContentView.swift */; };
A676EA99231771D5002074BF /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = A676EA98231771D5002074BF /* Assets.xcassets */; };
A676EA9C231771D5002074BF /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = A676EA9B231771D5002074BF /* Preview Assets.xcassets */; };
A676EA9F231771D5002074BF /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = A676EA9D231771D5002074BF /* LaunchScreen.storyboard */; };
/* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */
0C751033239BEAA900E85E20 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = A676EA87231771D2002074BF /* Project object */;
proxyType = 1;
remoteGlobalIDString = 0C751030239BEAA900E85E20;
remoteInfo = "watchapp Extension";
};
0C751042239BEAA900E85E20 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = A676EA87231771D2002074BF /* Project object */;
proxyType = 1;
remoteGlobalIDString = 0C751024239BEAA500E85E20;
remoteInfo = watchapp;
};
/* End PBXContainerItemProxy section */
/* Begin PBXCopyFilesBuildPhase section */
0C751045239BEAA900E85E20 /* Embed Watch Content */ = {
isa = PBXCopyFilesBuildPhase;
buildActionMask = 2147483647;
dstPath = "$(CONTENTS_FOLDER_PATH)/Watch";
dstSubfolderSpec = 16;
files = (
0C751044239BEAA900E85E20 /* watchapp.app in Embed Watch Content */,
);
name = "Embed Watch Content";
runOnlyForDeploymentPostprocessing = 0;
};
0C751048239BEAA900E85E20 /* Embed App Extensions */ = {
isa = PBXCopyFilesBuildPhase;
buildActionMask = 2147483647;
dstPath = "";
dstSubfolderSpec = 13;
files = (
0C751032239BEAA900E85E20 /* watchapp Extension.appex in Embed App Extensions */,
);
name = "Embed App Extensions";
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXCopyFilesBuildPhase section */
/* Begin PBXFileReference section */
0C39CB0A239BF2EE00444729 /* WatchGameManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WatchGameManager.swift; sourceTree = ""; };
0C39CB0C239C020000444729 /* WatchContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WatchContentView.swift; sourceTree = ""; };
0C3DCCE32392A5CC00C762A9 /* GameController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GameController.swift; sourceTree = ""; };
0C751025239BEAA500E85E20 /* watchapp.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = watchapp.app; sourceTree = BUILT_PRODUCTS_DIR; };
0C751028239BEAA500E85E20 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Interface.storyboard; sourceTree = ""; };
0C75102A239BEAA800E85E20 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; };
0C75102C239BEAA800E85E20 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
0C751031239BEAA900E85E20 /* watchapp Extension.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = "watchapp Extension.appex"; sourceTree = BUILT_PRODUCTS_DIR; };
0C751038239BEAA900E85E20 /* HostingController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HostingController.swift; sourceTree = ""; };
0C75103A239BEAA900E85E20 /* ExtensionDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ExtensionDelegate.swift; sourceTree = ""; };
0C75103C239BEAA900E85E20 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; };
0C75103F239BEAA900E85E20 /* Preview Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = "Preview Assets.xcassets"; sourceTree = ""; };
0C751041239BEAA900E85E20 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
A601DB2A2317775100327867 /* Light.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Light.swift; sourceTree = ""; };
A62D002E231904F80062A70E /* GameManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GameManager.swift; sourceTree = ""; };
A676EA8F231771D3002074BF /* light-game.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "light-game.app"; sourceTree = BUILT_PRODUCTS_DIR; };
A676EA92231771D3002074BF /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; };
A676EA94231771D3002074BF /* SceneDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SceneDelegate.swift; sourceTree = ""; };
A676EA96231771D3002074BF /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = ""; };
A676EA98231771D5002074BF /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; };
A676EA9B231771D5002074BF /* Preview Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = "Preview Assets.xcassets"; sourceTree = ""; };
A676EA9E231771D5002074BF /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; };
A676EAA0231771D5002074BF /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
0C75102E239BEAA900E85E20 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
A676EA8C231771D2002074BF /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
0C751026239BEAA500E85E20 /* watchapp */ = {
isa = PBXGroup;
children = (
0C751027239BEAA500E85E20 /* Interface.storyboard */,
0C75102A239BEAA800E85E20 /* Assets.xcassets */,
0C75102C239BEAA800E85E20 /* Info.plist */,
);
path = watchapp;
sourceTree = "";
};
0C751035239BEAA900E85E20 /* watchapp Extension */ = {
isa = PBXGroup;
children = (
0C751038239BEAA900E85E20 /* HostingController.swift */,
0C39CB0C239C020000444729 /* WatchContentView.swift */,
0C39CB0A239BF2EE00444729 /* WatchGameManager.swift */,
0C75103A239BEAA900E85E20 /* ExtensionDelegate.swift */,
0C75103C239BEAA900E85E20 /* Assets.xcassets */,
0C751041239BEAA900E85E20 /* Info.plist */,
0C75103E239BEAA900E85E20 /* Preview Content */,
);
path = "watchapp Extension";
sourceTree = "";
};
0C75103E239BEAA900E85E20 /* Preview Content */ = {
isa = PBXGroup;
children = (
0C75103F239BEAA900E85E20 /* Preview Assets.xcassets */,
);
path = "Preview Content";
sourceTree = "";
};
A601DB292317774600327867 /* Model */ = {
isa = PBXGroup;
children = (
A601DB2A2317775100327867 /* Light.swift */,
A62D002E231904F80062A70E /* GameManager.swift */,
0C3DCCE32392A5CC00C762A9 /* GameController.swift */,
);
path = Model;
sourceTree = "";
};
A676EA86231771D2002074BF = {
isa = PBXGroup;
children = (
A676EA91231771D3002074BF /* light-game */,
0C751026239BEAA500E85E20 /* watchapp */,
0C751035239BEAA900E85E20 /* watchapp Extension */,
A676EA90231771D3002074BF /* Products */,
);
sourceTree = "";
};
A676EA90231771D3002074BF /* Products */ = {
isa = PBXGroup;
children = (
A676EA8F231771D3002074BF /* light-game.app */,
0C751025239BEAA500E85E20 /* watchapp.app */,
0C751031239BEAA900E85E20 /* watchapp Extension.appex */,
);
name = Products;
sourceTree = "";
};
A676EA91231771D3002074BF /* light-game */ = {
isa = PBXGroup;
children = (
A676EA92231771D3002074BF /* AppDelegate.swift */,
A676EA94231771D3002074BF /* SceneDelegate.swift */,
A676EA96231771D3002074BF /* ContentView.swift */,
A601DB292317774600327867 /* Model */,
A676EA98231771D5002074BF /* Assets.xcassets */,
A676EA9D231771D5002074BF /* LaunchScreen.storyboard */,
A676EAA0231771D5002074BF /* Info.plist */,
A676EA9A231771D5002074BF /* Preview Content */,
);
path = "light-game";
sourceTree = "";
};
A676EA9A231771D5002074BF /* Preview Content */ = {
isa = PBXGroup;
children = (
A676EA9B231771D5002074BF /* Preview Assets.xcassets */,
);
path = "Preview Content";
sourceTree = "";
};
/* End PBXGroup section */
/* Begin PBXNativeTarget section */
0C751024239BEAA500E85E20 /* watchapp */ = {
isa = PBXNativeTarget;
buildConfigurationList = 0C75104C239BEAA900E85E20 /* Build configuration list for PBXNativeTarget "watchapp" */;
buildPhases = (
0C751023239BEAA500E85E20 /* Resources */,
0C751048239BEAA900E85E20 /* Embed App Extensions */,
);
buildRules = (
);
dependencies = (
0C751034239BEAA900E85E20 /* PBXTargetDependency */,
);
name = watchapp;
productName = watchapp;
productReference = 0C751025239BEAA500E85E20 /* watchapp.app */;
productType = "com.apple.product-type.application.watchapp2";
};
0C751030239BEAA900E85E20 /* watchapp Extension */ = {
isa = PBXNativeTarget;
buildConfigurationList = 0C75104B239BEAA900E85E20 /* Build configuration list for PBXNativeTarget "watchapp Extension" */;
buildPhases = (
0C75102D239BEAA900E85E20 /* Sources */,
0C75102E239BEAA900E85E20 /* Frameworks */,
0C75102F239BEAA900E85E20 /* Resources */,
);
buildRules = (
);
dependencies = (
);
name = "watchapp Extension";
productName = "watchapp Extension";
productReference = 0C751031239BEAA900E85E20 /* watchapp Extension.appex */;
productType = "com.apple.product-type.watchkit2-extension";
};
A676EA8E231771D2002074BF /* light-game */ = {
isa = PBXNativeTarget;
buildConfigurationList = A676EAA3231771D5002074BF /* Build configuration list for PBXNativeTarget "light-game" */;
buildPhases = (
A676EA8B231771D2002074BF /* Sources */,
A676EA8C231771D2002074BF /* Frameworks */,
A676EA8D231771D2002074BF /* Resources */,
0C751045239BEAA900E85E20 /* Embed Watch Content */,
);
buildRules = (
);
dependencies = (
0C751043239BEAA900E85E20 /* PBXTargetDependency */,
);
name = "light-game";
productName = "light-game";
productReference = A676EA8F231771D3002074BF /* light-game.app */;
productType = "com.apple.product-type.application";
};
/* End PBXNativeTarget section */
/* Begin PBXProject section */
A676EA87231771D2002074BF /* Project object */ = {
isa = PBXProject;
attributes = {
LastSwiftUpdateCheck = 1120;
LastUpgradeCheck = 1100;
ORGANIZATIONNAME = PJHubs;
TargetAttributes = {
0C751024239BEAA500E85E20 = {
CreatedOnToolsVersion = 11.2.1;
};
0C751030239BEAA900E85E20 = {
CreatedOnToolsVersion = 11.2.1;
};
A676EA8E231771D2002074BF = {
CreatedOnToolsVersion = 11.0;
};
};
};
buildConfigurationList = A676EA8A231771D2002074BF /* Build configuration list for PBXProject "light-game" */;
compatibilityVersion = "Xcode 9.3";
developmentRegion = en;
hasScannedForEncodings = 0;
knownRegions = (
en,
Base,
);
mainGroup = A676EA86231771D2002074BF;
productRefGroup = A676EA90231771D3002074BF /* Products */;
projectDirPath = "";
projectRoot = "";
targets = (
A676EA8E231771D2002074BF /* light-game */,
0C751024239BEAA500E85E20 /* watchapp */,
0C751030239BEAA900E85E20 /* watchapp Extension */,
);
};
/* End PBXProject section */
/* Begin PBXResourcesBuildPhase section */
0C751023239BEAA500E85E20 /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
0C75102B239BEAA800E85E20 /* Assets.xcassets in Resources */,
0C751029239BEAA500E85E20 /* Interface.storyboard in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
0C75102F239BEAA900E85E20 /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
0C751040239BEAA900E85E20 /* Preview Assets.xcassets in Resources */,
0C75103D239BEAA900E85E20 /* Assets.xcassets in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
A676EA8D231771D2002074BF /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
A676EA9F231771D5002074BF /* LaunchScreen.storyboard in Resources */,
A676EA9C231771D5002074BF /* Preview Assets.xcassets in Resources */,
A676EA99231771D5002074BF /* Assets.xcassets in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXResourcesBuildPhase section */
/* Begin PBXSourcesBuildPhase section */
0C75102D239BEAA900E85E20 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
0C751039239BEAA900E85E20 /* HostingController.swift in Sources */,
0C39CB0B239BF2EE00444729 /* WatchGameManager.swift in Sources */,
0C39CB0D239C020000444729 /* WatchContentView.swift in Sources */,
0C39CB06239BEF1100444729 /* Light.swift in Sources */,
0C75103B239BEAA900E85E20 /* ExtensionDelegate.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
A676EA8B231771D2002074BF /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
A676EA93231771D3002074BF /* AppDelegate.swift in Sources */,
0C3DCCE42392A5CC00C762A9 /* GameController.swift in Sources */,
A676EA95231771D3002074BF /* SceneDelegate.swift in Sources */,
A601DB2B2317775100327867 /* Light.swift in Sources */,
A676EA97231771D3002074BF /* ContentView.swift in Sources */,
A62D002F231904F80062A70E /* GameManager.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXSourcesBuildPhase section */
/* Begin PBXTargetDependency section */
0C751034239BEAA900E85E20 /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
target = 0C751030239BEAA900E85E20 /* watchapp Extension */;
targetProxy = 0C751033239BEAA900E85E20 /* PBXContainerItemProxy */;
};
0C751043239BEAA900E85E20 /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
target = 0C751024239BEAA500E85E20 /* watchapp */;
targetProxy = 0C751042239BEAA900E85E20 /* PBXContainerItemProxy */;
};
/* End PBXTargetDependency section */
/* Begin PBXVariantGroup section */
0C751027239BEAA500E85E20 /* Interface.storyboard */ = {
isa = PBXVariantGroup;
children = (
0C751028239BEAA500E85E20 /* Base */,
);
name = Interface.storyboard;
sourceTree = "";
};
A676EA9D231771D5002074BF /* LaunchScreen.storyboard */ = {
isa = PBXVariantGroup;
children = (
A676EA9E231771D5002074BF /* Base */,
);
name = LaunchScreen.storyboard;
sourceTree = "";
};
/* End PBXVariantGroup section */
/* Begin XCBuildConfiguration section */
0C751046239BEAA900E85E20 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CODE_SIGN_STYLE = Automatic;
DEVELOPMENT_TEAM = U6J5965DZK;
IBSC_MODULE = watchapp_Extension;
INFOPLIST_FILE = watchapp/Info.plist;
PRODUCT_BUNDLE_IDENTIFIER = "com.pjhubs.light-game.watchkitapp";
PRODUCT_NAME = "$(TARGET_NAME)";
SDKROOT = watchos;
SKIP_INSTALL = YES;
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = 4;
WATCHOS_DEPLOYMENT_TARGET = 6.1;
};
name = Debug;
};
0C751047239BEAA900E85E20 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CODE_SIGN_STYLE = Automatic;
DEVELOPMENT_TEAM = U6J5965DZK;
IBSC_MODULE = watchapp_Extension;
INFOPLIST_FILE = watchapp/Info.plist;
PRODUCT_BUNDLE_IDENTIFIER = "com.pjhubs.light-game.watchkitapp";
PRODUCT_NAME = "$(TARGET_NAME)";
SDKROOT = watchos;
SKIP_INSTALL = YES;
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = 4;
WATCHOS_DEPLOYMENT_TARGET = 6.1;
};
name = Release;
};
0C751049239BEAA900E85E20 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ASSETCATALOG_COMPILER_COMPLICATION_NAME = Complication;
CODE_SIGN_STYLE = Automatic;
DEVELOPMENT_ASSET_PATHS = "\"watchapp Extension/Preview Content\"";
DEVELOPMENT_TEAM = U6J5965DZK;
ENABLE_PREVIEWS = YES;
INFOPLIST_FILE = "watchapp Extension/Info.plist";
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
"@executable_path/../../Frameworks",
);
PRODUCT_BUNDLE_IDENTIFIER = "com.pjhubs.light-game.watchkitapp.watchkitextension";
PRODUCT_NAME = "${TARGET_NAME}";
SDKROOT = watchos;
SKIP_INSTALL = YES;
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = 4;
WATCHOS_DEPLOYMENT_TARGET = 6.1;
};
name = Debug;
};
0C75104A239BEAA900E85E20 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ASSETCATALOG_COMPILER_COMPLICATION_NAME = Complication;
CODE_SIGN_STYLE = Automatic;
DEVELOPMENT_ASSET_PATHS = "\"watchapp Extension/Preview Content\"";
DEVELOPMENT_TEAM = U6J5965DZK;
ENABLE_PREVIEWS = YES;
INFOPLIST_FILE = "watchapp Extension/Info.plist";
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
"@executable_path/../../Frameworks",
);
PRODUCT_BUNDLE_IDENTIFIER = "com.pjhubs.light-game.watchkitapp.watchkitextension";
PRODUCT_NAME = "${TARGET_NAME}";
SDKROOT = watchos;
SKIP_INSTALL = YES;
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = 4;
WATCHOS_DEPLOYMENT_TARGET = 6.1;
};
name = Release;
};
A676EAA1231771D5002074BF /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_NONNULL = YES;
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_ENABLE_OBJC_WEAK = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
COPY_PHASE_STRIP = NO;
DEBUG_INFORMATION_FORMAT = dwarf;
ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_TESTABILITY = YES;
GCC_C_LANGUAGE_STANDARD = gnu11;
GCC_DYNAMIC_NO_PIC = NO;
GCC_NO_COMMON_BLOCKS = YES;
GCC_OPTIMIZATION_LEVEL = 0;
GCC_PREPROCESSOR_DEFINITIONS = (
"DEBUG=1",
"$(inherited)",
);
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 13.0;
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
MTL_FAST_MATH = YES;
ONLY_ACTIVE_ARCH = YES;
SDKROOT = iphoneos;
SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
};
name = Debug;
};
A676EAA2231771D5002074BF /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_NONNULL = YES;
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_ENABLE_OBJC_WEAK = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
COPY_PHASE_STRIP = NO;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
ENABLE_NS_ASSERTIONS = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
GCC_C_LANGUAGE_STANDARD = gnu11;
GCC_NO_COMMON_BLOCKS = YES;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 13.0;
MTL_ENABLE_DEBUG_INFO = NO;
MTL_FAST_MATH = YES;
SDKROOT = iphoneos;
SWIFT_COMPILATION_MODE = wholemodule;
SWIFT_OPTIMIZATION_LEVEL = "-O";
VALIDATE_PRODUCT = YES;
};
name = Release;
};
A676EAA4231771D5002074BF /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CODE_SIGN_STYLE = Automatic;
DEVELOPMENT_ASSET_PATHS = "\"light-game/Preview Content\"";
DEVELOPMENT_TEAM = U6J5965DZK;
ENABLE_PREVIEWS = YES;
INFOPLIST_FILE = "light-game/Info.plist";
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
);
PRODUCT_BUNDLE_IDENTIFIER = "com.pjhubs.light-game";
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = "1,2";
};
name = Debug;
};
A676EAA5231771D5002074BF /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CODE_SIGN_STYLE = Automatic;
DEVELOPMENT_ASSET_PATHS = "\"light-game/Preview Content\"";
DEVELOPMENT_TEAM = U6J5965DZK;
ENABLE_PREVIEWS = YES;
INFOPLIST_FILE = "light-game/Info.plist";
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
);
PRODUCT_BUNDLE_IDENTIFIER = "com.pjhubs.light-game";
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = "1,2";
};
name = Release;
};
/* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */
0C75104B239BEAA900E85E20 /* Build configuration list for PBXNativeTarget "watchapp Extension" */ = {
isa = XCConfigurationList;
buildConfigurations = (
0C751049239BEAA900E85E20 /* Debug */,
0C75104A239BEAA900E85E20 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
0C75104C239BEAA900E85E20 /* Build configuration list for PBXNativeTarget "watchapp" */ = {
isa = XCConfigurationList;
buildConfigurations = (
0C751046239BEAA900E85E20 /* Debug */,
0C751047239BEAA900E85E20 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
A676EA8A231771D2002074BF /* Build configuration list for PBXProject "light-game" */ = {
isa = XCConfigurationList;
buildConfigurations = (
A676EAA1231771D5002074BF /* Debug */,
A676EAA2231771D5002074BF /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
A676EAA3231771D5002074BF /* Build configuration list for PBXNativeTarget "light-game" */ = {
isa = XCConfigurationList;
buildConfigurations = (
A676EAA4231771D5002074BF /* Debug */,
A676EAA5231771D5002074BF /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
/* End XCConfigurationList section */
};
rootObject = A676EA87231771D2002074BF /* Project object */;
}
================================================
FILE: lightGame/light-game.xcodeproj/project.xcworkspace/contents.xcworkspacedata
================================================
================================================
FILE: lightGame/light-game.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist
================================================
IDEDidComputeMac32BitWarning
================================================
FILE: lightGame/light-game.xcodeproj/xcuserdata/pjhubs.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist
================================================
================================================
FILE: lightGame/light-game.xcodeproj/xcuserdata/pjhubs.xcuserdatad/xcschemes/xcschememanagement.plist
================================================
SchemeUserState
light-game.xcscheme_^#shared#^_
orderHint
0
watchapp.xcscheme_^#shared#^_
orderHint
1
================================================
FILE: lightGame/light-game.xcodeproj/xcuserdata/wengpeijun.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist
================================================
================================================
FILE: lightGame/light-game.xcodeproj/xcuserdata/wengpeijun.xcuserdatad/xcschemes/xcschememanagement.plist
================================================
SchemeUserState
light-game.xcscheme_^#shared#^_
orderHint
0
================================================
FILE: lightGame/watchapp/Assets.xcassets/AppIcon.appiconset/Contents.json
================================================
{
"images" : [
{
"size" : "24x24",
"idiom" : "watch",
"scale" : "2x",
"role" : "notificationCenter",
"subtype" : "38mm"
},
{
"size" : "27.5x27.5",
"idiom" : "watch",
"scale" : "2x",
"role" : "notificationCenter",
"subtype" : "42mm"
},
{
"size" : "29x29",
"idiom" : "watch",
"role" : "companionSettings",
"scale" : "2x"
},
{
"size" : "29x29",
"idiom" : "watch",
"role" : "companionSettings",
"scale" : "3x"
},
{
"size" : "40x40",
"idiom" : "watch",
"scale" : "2x",
"role" : "appLauncher",
"subtype" : "38mm"
},
{
"size" : "44x44",
"idiom" : "watch",
"scale" : "2x",
"role" : "appLauncher",
"subtype" : "40mm"
},
{
"size" : "50x50",
"idiom" : "watch",
"scale" : "2x",
"role" : "appLauncher",
"subtype" : "44mm"
},
{
"size" : "86x86",
"idiom" : "watch",
"scale" : "2x",
"role" : "quickLook",
"subtype" : "38mm"
},
{
"size" : "98x98",
"idiom" : "watch",
"scale" : "2x",
"role" : "quickLook",
"subtype" : "42mm"
},
{
"size" : "108x108",
"idiom" : "watch",
"scale" : "2x",
"role" : "quickLook",
"subtype" : "44mm"
},
{
"idiom" : "watch-marketing",
"size" : "1024x1024",
"scale" : "1x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}
================================================
FILE: lightGame/watchapp/Assets.xcassets/Contents.json
================================================
{
"info" : {
"version" : 1,
"author" : "xcode"
}
}
================================================
FILE: lightGame/watchapp/Base.lproj/Interface.storyboard
================================================
================================================
FILE: lightGame/watchapp/Info.plist
================================================
CFBundleDevelopmentRegion
$(DEVELOPMENT_LANGUAGE)
CFBundleDisplayName
light-game
CFBundleExecutable
$(EXECUTABLE_NAME)
CFBundleIdentifier
$(PRODUCT_BUNDLE_IDENTIFIER)
CFBundleInfoDictionaryVersion
6.0
CFBundleName
$(PRODUCT_NAME)
CFBundlePackageType
$(PRODUCT_BUNDLE_PACKAGE_TYPE)
CFBundleShortVersionString
1.0
CFBundleVersion
1
UISupportedInterfaceOrientations
UIInterfaceOrientationPortrait
UIInterfaceOrientationPortraitUpsideDown
WKCompanionAppBundleIdentifier
com.pjhubs.light-game
WKWatchKitApp
================================================
FILE: lightGame/watchapp Extension/Assets.xcassets/Complication.complicationset/Circular.imageset/Contents.json
================================================
{
"images" : [
{
"idiom" : "watch",
"scale" : "2x",
"screen-width" : "<=145"
},
{
"idiom" : "watch",
"scale" : "2x",
"screen-width" : ">161"
},
{
"idiom" : "watch",
"scale" : "2x",
"screen-width" : ">145"
},
{
"idiom" : "watch",
"scale" : "2x",
"screen-width" : ">183"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}
================================================
FILE: lightGame/watchapp Extension/Assets.xcassets/Complication.complicationset/Contents.json
================================================
{
"assets" : [
{
"idiom" : "watch",
"filename" : "Circular.imageset",
"role" : "circular"
},
{
"idiom" : "watch",
"filename" : "Extra Large.imageset",
"role" : "extra-large"
},
{
"idiom" : "watch",
"filename" : "Graphic Bezel.imageset",
"role" : "graphic-bezel"
},
{
"idiom" : "watch",
"filename" : "Graphic Circular.imageset",
"role" : "graphic-circular"
},
{
"idiom" : "watch",
"filename" : "Graphic Corner.imageset",
"role" : "graphic-corner"
},
{
"idiom" : "watch",
"filename" : "Graphic Large Rectangular.imageset",
"role" : "graphic-large-rectangular"
},
{
"idiom" : "watch",
"filename" : "Modular.imageset",
"role" : "modular"
},
{
"idiom" : "watch",
"filename" : "Utilitarian.imageset",
"role" : "utilitarian"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}
================================================
FILE: lightGame/watchapp Extension/Assets.xcassets/Complication.complicationset/Extra Large.imageset/Contents.json
================================================
{
"images" : [
{
"idiom" : "watch",
"scale" : "2x",
"screen-width" : "<=145"
},
{
"idiom" : "watch",
"scale" : "2x",
"screen-width" : ">161"
},
{
"idiom" : "watch",
"scale" : "2x",
"screen-width" : ">145"
},
{
"idiom" : "watch",
"scale" : "2x",
"screen-width" : ">183"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}
================================================
FILE: lightGame/watchapp Extension/Assets.xcassets/Complication.complicationset/Graphic Bezel.imageset/Contents.json
================================================
{
"images" : [
{
"idiom" : "watch",
"scale" : "2x",
"screen-width" : "<=145"
},
{
"idiom" : "watch",
"scale" : "2x",
"screen-width" : ">161"
},
{
"idiom" : "watch",
"scale" : "2x",
"screen-width" : ">145"
},
{
"idiom" : "watch",
"scale" : "2x",
"screen-width" : ">183"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}
================================================
FILE: lightGame/watchapp Extension/Assets.xcassets/Complication.complicationset/Graphic Circular.imageset/Contents.json
================================================
{
"images" : [
{
"idiom" : "watch",
"scale" : "2x",
"screen-width" : "<=145"
},
{
"idiom" : "watch",
"scale" : "2x",
"screen-width" : ">161"
},
{
"idiom" : "watch",
"scale" : "2x",
"screen-width" : ">145"
},
{
"idiom" : "watch",
"scale" : "2x",
"screen-width" : ">183"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}
================================================
FILE: lightGame/watchapp Extension/Assets.xcassets/Complication.complicationset/Graphic Corner.imageset/Contents.json
================================================
{
"images" : [
{
"idiom" : "watch",
"scale" : "2x",
"screen-width" : "<=145"
},
{
"idiom" : "watch",
"scale" : "2x",
"screen-width" : ">161"
},
{
"idiom" : "watch",
"scale" : "2x",
"screen-width" : ">145"
},
{
"idiom" : "watch",
"scale" : "2x",
"screen-width" : ">183"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}
================================================
FILE: lightGame/watchapp Extension/Assets.xcassets/Complication.complicationset/Graphic Large Rectangular.imageset/Contents.json
================================================
{
"images" : [
{
"idiom" : "watch",
"scale" : "2x",
"screen-width" : "<=145"
},
{
"idiom" : "watch",
"scale" : "2x",
"screen-width" : ">161"
},
{
"idiom" : "watch",
"scale" : "2x",
"screen-width" : ">145"
},
{
"idiom" : "watch",
"scale" : "2x",
"screen-width" : ">183"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}
================================================
FILE: lightGame/watchapp Extension/Assets.xcassets/Complication.complicationset/Modular.imageset/Contents.json
================================================
{
"images" : [
{
"idiom" : "watch",
"scale" : "2x",
"screen-width" : "<=145"
},
{
"idiom" : "watch",
"scale" : "2x",
"screen-width" : ">161"
},
{
"idiom" : "watch",
"scale" : "2x",
"screen-width" : ">145"
},
{
"idiom" : "watch",
"scale" : "2x",
"screen-width" : ">183"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}
================================================
FILE: lightGame/watchapp Extension/Assets.xcassets/Complication.complicationset/Utilitarian.imageset/Contents.json
================================================
{
"images" : [
{
"idiom" : "watch",
"scale" : "2x",
"screen-width" : "<=145"
},
{
"idiom" : "watch",
"scale" : "2x",
"screen-width" : ">161"
},
{
"idiom" : "watch",
"scale" : "2x",
"screen-width" : ">145"
},
{
"idiom" : "watch",
"scale" : "2x",
"screen-width" : ">183"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}
================================================
FILE: lightGame/watchapp Extension/Assets.xcassets/Contents.json
================================================
{
"info" : {
"version" : 1,
"author" : "xcode"
}
}
================================================
FILE: lightGame/watchapp Extension/ExtensionDelegate.swift
================================================
//
// ExtensionDelegate.swift
// watchapp Extension
//
// Created by 翁培钧 on 2019/12/7.
// Copyright © 2019 PJHubs. All rights reserved.
//
import WatchKit
class ExtensionDelegate: NSObject, WKExtensionDelegate {
func applicationDidFinishLaunching() {
// Perform any final initialization of your application.
}
func applicationDidBecomeActive() {
// Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
}
func applicationWillResignActive() {
// Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
// Use this method to pause ongoing tasks, disable timers, etc.
}
func handle(_ backgroundTasks: Set) {
// Sent when the system needs to launch the application in the background to process tasks. Tasks arrive in a set, so loop through and process each one.
for task in backgroundTasks {
// Use a switch statement to check the task type
switch task {
case let backgroundTask as WKApplicationRefreshBackgroundTask:
// Be sure to complete the background task once you’re done.
backgroundTask.setTaskCompletedWithSnapshot(false)
case let snapshotTask as WKSnapshotRefreshBackgroundTask:
// Snapshot tasks have a unique completion call, make sure to set your expiration date
snapshotTask.setTaskCompleted(restoredDefaultState: true, estimatedSnapshotExpiration: Date.distantFuture, userInfo: nil)
case let connectivityTask as WKWatchConnectivityRefreshBackgroundTask:
// Be sure to complete the connectivity task once you’re done.
connectivityTask.setTaskCompletedWithSnapshot(false)
case let urlSessionTask as WKURLSessionRefreshBackgroundTask:
// Be sure to complete the URL session task once you’re done.
urlSessionTask.setTaskCompletedWithSnapshot(false)
case let relevantShortcutTask as WKRelevantShortcutRefreshBackgroundTask:
// Be sure to complete the relevant-shortcut task once you're done.
relevantShortcutTask.setTaskCompletedWithSnapshot(false)
case let intentDidRunTask as WKIntentDidRunRefreshBackgroundTask:
// Be sure to complete the intent-did-run task once you're done.
intentDidRunTask.setTaskCompletedWithSnapshot(false)
default:
// make sure to complete unhandled task types
task.setTaskCompletedWithSnapshot(false)
}
}
}
}
================================================
FILE: lightGame/watchapp Extension/HostingController.swift
================================================
//
// HostingController.swift
// watchapp Extension
//
// Created by 翁培钧 on 2019/12/7.
// Copyright © 2019 PJHubs. All rights reserved.
//
import WatchKit
import Foundation
import SwiftUI
class HostingController: WKHostingController {
override var body: ContentView {
return ContentView()
}
}
================================================
FILE: lightGame/watchapp Extension/Info.plist
================================================
CFBundleDevelopmentRegion
$(DEVELOPMENT_LANGUAGE)
CFBundleDisplayName
watchapp Extension
CFBundleExecutable
$(EXECUTABLE_NAME)
CFBundleIdentifier
$(PRODUCT_BUNDLE_IDENTIFIER)
CFBundleInfoDictionaryVersion
6.0
CFBundleName
$(PRODUCT_NAME)
CFBundlePackageType
$(PRODUCT_BUNDLE_PACKAGE_TYPE)
CFBundleShortVersionString
1.0
CFBundleVersion
1
NSExtension
NSExtensionAttributes
WKAppBundleIdentifier
com.pjhubs.light-game.watchkitapp
NSExtensionPointIdentifier
com.apple.watchkit
WKExtensionDelegateClassName
$(PRODUCT_MODULE_NAME).ExtensionDelegate
WKRunsIndependentlyOfCompanionApp
================================================
FILE: lightGame/watchapp Extension/Preview Content/Preview Assets.xcassets/Contents.json
================================================
{
"info" : {
"version" : 1,
"author" : "xcode"
}
}
================================================
FILE: lightGame/watchapp Extension/WatchContentView.swift
================================================
//
// WatchContentView.swift
// watchapp Extension
//
// Created by 翁培钧 on 2019/12/7.
// Copyright © 2019 PJHubs. All rights reserved.
//
import SwiftUI
struct ContentView: View {
@ObservedObject var gameManager = WatchGameManager(size: 3, lightSequence: [1, 2, 3])
@State var isShowHistory = false
var body: some View {
VStack {
ForEach(0.. 8 {
size = 7
}
// 太小了没意思
if size < 2 {
size = 2
}
self.size = size
lights = Array(repeating: Array(repeating: Light(), count: size), count: size)
// initGameController()
start(lightSequence)
}
// MARK: Public
/// 游戏配置
/// - Parameter lightSequence: 亮灯序列
func start(_ lightSequence: [Int]) {
currentStatus = .during
clickTimes = 0
updateLightStatus(lightSequence)
timer = Timer.scheduledTimer(withTimeInterval: 1, repeats: true, block: { timer in
let min = self.durations >= 60 ? self.durations / 60 : 0
let seconds = self.durations - min * 60
let minString = min >= 10 ? "\(min)" : "0\(min)"
let secondString = self.durations - min * 60 >= 10 ? "\(seconds)" : "0\(seconds)"
self.timeString = minString + ":" + secondString
self.durations += 1
})
}
/// 停止
func timerStop() {
timer?.fireDate = Date.distantFuture
}
/// 重新创建
func timerRestart() {
isPause = false
durations = 0
timeString = "00:00"
timer?.fireDate = Date()
}
/// 获取灯的尺寸
func circleWidth() -> CGFloat {
guard let size = size else { return 0 }
/// 距离屏幕左右两边的间距
let padding: CGFloat = 20
/// 左右两灯之间的间距
let innerSpacing: CGFloat = 20
let screenBounds = WKInterfaceDevice.current().screenBounds
var circleWidth = (screenBounds.width - padding - (CGFloat(size) * innerSpacing)) / CGFloat(size)
// 太大了会很丑,过滤下
if circleWidth > screenBounds.width / 5 {
circleWidth = screenBounds.width / 5
}
return circleWidth
}
/// 通过坐标索引修改灯状态
/// - Parameters:
/// - column: 灯-列索引
/// - size: 灯-行索引
func updateLightStatus(column: Int, row: Int, userTouch: Bool) {
lights[row][column].status.toggle()
self.column = row
self.row = column
// 上
let top = row - 1
if !(top < 0) {
lights[top][column].status.toggle()
}
// 下
let bottom = row + 1
if !(bottom > lights.count - 1) {
lights[bottom][column].status.toggle()
}
// 左
let left = column - 1
if !(left < 0) {
lights[row][left].status.toggle()
}
// 右
let right = column + 1
if !(right > lights.count - 1) {
lights[row][right].status.toggle()
}
updateGameStatus()
// if (userTouch) {
// disSelectedGameControllerStatus()
// }
}
// MARK: Private
/// 通过亮灯序列修改灯状态
/// - Parameter lightSequence: 亮灯序列
private func updateLightStatus(_ lightSequence: [Int]) {
guard let size = size else { return }
for lightIndex in lightSequence {
var index = lightIndex
// 防止数组越出最大边界处
if index >= size * size {
index = size * size - 1
}
let row = lightIndex / size
let column = lightIndex % size
// column 不为 0,说明非最后一个
// row 为 0,说明为第一行
updateLightStatus(column: column, row: row, userTouch: true)
}
}
private func updateLightSelected() {
lights[pColumn][pRow].selected = false
lights[column][row].selected = true
pRow = row
pColumn = column
}
// private func disSelectedGameControllerStatus() {
// lights[pColumn][pRow].selected = false
// }
/// 判赢
private func updateGameStatus() {
guard let size = size else { return }
var lightingCount = 0
for lightArr in lights {
for light in lightArr {
if light.status { lightingCount += 1 }
}
}
if lightingCount == size * size {
timerStop()
currentStatus = .lose
return
}
if lightingCount == 0 {
timerStop()
currentStatus = .win
isPause = true
return
}
}
// private func initGameController() {
// gameController.isSelectX = {
// guard !self.isPause else { return }
//
// if $0 {
// if (self.row < self.lights.count - 1) {
// self.row += 1
// }
// } else {
// if self.row > 0 {
// self.row -= 1
// }
// }
//
// self.updateLightSelected()
// }
//
// gameController.isSelectY = {
// guard !self.isPause else { return }
//
// if $0 {
// if (self.column > 0) {
// self.column -= 1
// }
// } else {
// if (self.column < self.lights.count - 1) {
// self.column += 1
// }
// }
//
// self.updateLightSelected()
// }
//
// gameController.isTapButtonA = {
// self.clickTimes += 1
// self.updateLightStatus(column: self.row, row: self.column, userTouch: false)
// }
// }
}
extension WatchGameManager {
enum WatchGameStatus {
/// 赢
case win
/// 输
case lose
/// 进行中
case during
}
}