Skip to content
Permalink
Browse files

Add screensaver build target (#19)

* screensaver builds and runs... sorta

but any external assets (sprites, sounds, particles) are not working

* ensure images load on other platforms

* finally got the particle to load in the screensaver build...

* grab files explicitly from bundle for screensaver support

* body parts load in screensaver mode

* looks like all images are loading properly now on all platforms

* run swiftformat

* fix issue with black colored creatures on mac
  • Loading branch information...
amiantos committed May 5, 2019
1 parent eb1f6e9 commit 13bf01555bdae2b2b35657b9bcc83f0449b380e8
Showing with 485 additions and 35 deletions.
  1. +45 −0 Aeon Garden Screensaver/AeonScreenSaverView.swift
  2. +20 −0 Aeon Garden Screensaver/GameView.swift
  3. +26 −0 Aeon Garden Screensaver/Info.plist
  4. +1 −1 Aeon Garden Shared/Assets.xcassets/aeonBodyShadow.imageset/Contents.json
  5. BIN Aeon Garden Shared/Assets.xcassets/aeonBodyShadow.imageset/{Ellipse 2.pdf → aeonBodyShadow.pdf}
  6. +1 −1 Aeon Garden Shared/Assets.xcassets/aeonCircle.imageset/Contents.json
  7. BIN Aeon Garden Shared/Assets.xcassets/aeonCircle.imageset/{Ellipse.pdf → aeonCircle.pdf}
  8. +1 −1 Aeon Garden Shared/Assets.xcassets/aeonFoodPellet.imageset/Contents.json
  9. BIN Aeon Garden Shared/Assets.xcassets/aeonFoodPellet.imageset/{Ellipse.pdf → aeonFoodPellet.pdf}
  10. +1 −1 Aeon Garden Shared/Assets.xcassets/aeonSelectionRing.imageset/Contents.json
  11. BIN ... Shared/Assets.xcassets/aeonSelectionRing.imageset/{Selection Circle.pdf → aeonSelectionRing.pdf}
  12. +1 −1 Aeon Garden Shared/Assets.xcassets/aeonSquare.imageset/Contents.json
  13. BIN Aeon Garden Shared/Assets.xcassets/aeonSquare.imageset/{Rectangle.pdf → aeonSquare.pdf}
  14. +1 −1 Aeon Garden Shared/Assets.xcassets/aeonTriangle.imageset/Contents.json
  15. BIN Aeon Garden Shared/Assets.xcassets/aeonTriangle.imageset/{Triangle.pdf → aeonTriangle.pdf}
  16. +4 −3 Aeon Garden Shared/Nodes/AeonCreatureNode/AeonCreatureNode.swift
  17. +2 −1 Aeon Garden Shared/Nodes/AeonCreatureNode/AeonLimbNode.swift
  18. +1 −1 Aeon Garden Shared/Nodes/AeonFoodNode.swift
  19. +11 −10 Aeon Garden Shared/Scenes/AeonTankScene.swift
  20. +54 −0 Aeon Garden Shared/Utilities/AeonAssetGrabber.swift
  21. +1 −0 Aeon Garden Shared/Utilities/AeonFonts.swift
  22. +10 −8 Aeon Garden Shared/Utilities/AeonNameGenerator/AeonNameGenerator.swift
  23. +16 −0 Aeon Garden macOS/AeonViewController.swift
  24. +202 −4 Aeon Garden.xcodeproj/project.pbxproj
  25. +80 −0 Aeon Garden.xcodeproj/xcshareddata/xcschemes/Aeon Garden SS.xcscheme
  26. +7 −2 Aeon Garden.xcodeproj/xcuserdata/bradroot.xcuserdatad/xcschemes/xcschememanagement.plist
@@ -0,0 +1,45 @@
//
// AeonScreenSaverView.swift
// Aeon Garden Screensaver
//
// Created by Bradley Root on 5/4/19.
// Copyright © 2019 Brad Root. All rights reserved.
//
import Cocoa
import ScreenSaver
import SpriteKit

class AeonScreenSaverView: ScreenSaverView {
var spriteView: GameView?

override init?(frame: NSRect, isPreview: Bool) {
super.init(frame: frame, isPreview: isPreview)
animationTimeInterval = 1.0
}

required init?(coder: NSCoder) {
super.init(coder: coder)
animationTimeInterval = 1.0
}

override var frame: NSRect {
didSet {
self.spriteView?.frame = frame
}
}

override func startAnimation() {
if spriteView == nil {
let spriteView = GameView(frame: frame)
spriteView.ignoresSiblingOrder = false
spriteView.showsFPS = false
spriteView.showsNodeCount = false
let scene = AeonTankScene(size: frame.size)
self.spriteView = spriteView
addSubview(spriteView)
spriteView.presentScene(scene)
}
super.startAnimation()
}
}
@@ -0,0 +1,20 @@
//
// GameView.swift
// SwiftScreenSaver
//
// Created by Patrick Winchell on 1/22/16.
// Copyright © 2016 Patrick Winchell. All rights reserved.
//
import Cocoa
import SpriteKit

class GameView: SKView {
override var acceptsFirstResponder: Bool { return false }

override var frame: NSRect {
didSet {
scene?.size = frame.size
}
}
}
@@ -0,0 +1,26 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>BNDL</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleVersion</key>
<string>1</string>
<key>NSHumanReadableCopyright</key>
<string>Copyright © 2019 Brad Root. All rights reserved.</string>
<key>NSPrincipalClass</key>
<string>Aeon_Garden_Screensaver.AeonScreenSaverView</string>
</dict>
</plist>
@@ -2,7 +2,7 @@
"images" : [
{
"idiom" : "universal",
"filename" : "Ellipse 2.pdf"
"filename" : "aeonBodyShadow.pdf"
}
],
"info" : {
@@ -2,7 +2,7 @@
"images" : [
{
"idiom" : "universal",
"filename" : "Ellipse.pdf"
"filename" : "aeonCircle.pdf"
}
],
"info" : {
@@ -2,7 +2,7 @@
"images" : [
{
"idiom" : "universal",
"filename" : "Ellipse.pdf"
"filename" : "aeonFoodPellet.pdf"
}
],
"info" : {
@@ -2,7 +2,7 @@
"images" : [
{
"idiom" : "universal",
"filename" : "Selection Circle.pdf"
"filename" : "aeonSelectionRing.pdf"
}
],
"info" : {
@@ -2,7 +2,7 @@
"images" : [
{
"idiom" : "universal",
"filename" : "Rectangle.pdf"
"filename" : "aeonSquare.pdf"
}
],
"info" : {
@@ -2,7 +2,7 @@
"images" : [
{
"idiom" : "universal",
"filename" : "Triangle.pdf"
"filename" : "aeonTriangle.pdf"
}
],
"info" : {
@@ -12,7 +12,7 @@
import SpriteKit

class AeonCreatureNode: SKNode, Updatable {
var selectionRing: SKSpriteNode = SKSpriteNode(imageNamed: "aeonSelectionRing")
var selectionRing: SKSpriteNode = SKSpriteNode(texture: AeonFileGrabber.shared.getSKTexture(named: "aeonSelectionRing"))

// MARK: - Creature Name
@@ -146,7 +146,7 @@ class AeonCreatureNode: SKNode, Updatable {
physicsBody?.linearDamping = 0.5
physicsBody?.angularDamping = 1

let underShadow = SKSpriteNode(imageNamed: "aeonBodyShadow")
let underShadow = SKSpriteNode(texture: AeonFileGrabber.shared.getSKTexture(named: "aeonBodyShadow"))
underShadow.size = CGSize(width: 40, height: 40)
underShadow.setScale(1.2)
underShadow.alpha = 0.2
@@ -269,7 +269,8 @@ class AeonCreatureNode: SKNode, Updatable {

brain?.printThought("Lo! Consciousness", emoji: "👼")

if let emitter = SKEmitterNode(fileNamed: "AeonCreatureBubbleTrail.sks") {
if let emitter = AeonFileGrabber.shared.getSKEmitterNode(named: "AeonCreatureBubbleTrail") {
emitter.particleTexture = AeonFileGrabber.shared.getSKTexture(named: "aeonTriangle")
emitter.name = "AeonCreatureBubbleTrail.sks"
emitter.isUserInteractionEnabled = false
emitter.zPosition = 1
@@ -58,7 +58,8 @@ class AeonLimbNode: SKSpriteNode {
saturation = randomCGFloat(min: 0.84, max: 0.96)
blend = CGFloat(randomCGFloat(min: 0.8, max: 1))

let texture = SKTexture(imageNamed: shape.rawValue)
// let texture = SKTexture(imageNamed: shape.rawValue)
let texture = AeonFileGrabber.shared.getSKTexture(named: shape.rawValue)
let color = SKColor(
hue: hue / 360,
saturation: saturation,
@@ -38,7 +38,7 @@ class AeonFoodNode: SKNode, Updatable {
name = "aeonFood"
zPosition = 1

let foodBody = SKSpriteNode(imageNamed: "aeonFoodPellet")
let foodBody = SKSpriteNode(texture: AeonFileGrabber.shared.getSKTexture(named: "aeonFoodPellet"))
foodBody.size = CGSize(width: 23, height: 33)
foodBody.zPosition = 1
foodBody.name = "AeonFoodSprite"
@@ -103,7 +103,8 @@ class AeonTankScene: SKScene {
}
selectedCreature = creature
creature.displaySelectionRing(withColor: .aeonBrightYellow)
camera?.run(SKAction.scale(to: UISettings.styles.cameraZoomScale, duration: 1))
// camera?.run(SKAction.scale(to: UISettings.styles.cameraZoomScale, duration: 1))
camera?.run(SKAction.scale(to: 0.4, duration: 1))
}

func deselectCreature() {
@@ -254,7 +255,7 @@ extension AeonTankScene {
fileprivate func createInitialCreatures() {
var totalCreatures: Int = 0
var initialCreatureHue: CGFloat = 0
let colorHueIncrement: CGFloat = CGFloat(360 / CGFloat(creatureMinimum))
let colorHueIncrement: CGFloat = CGFloat(360 / CGFloat(initialCreatures))

while totalCreatures < initialCreatures {
addNewCreatureToScene(withPrimaryHue: initialCreatureHue)
@@ -429,13 +430,13 @@ extension AeonTankScene {
// addChild(backgroundSmoke)
// }
if let backgroundSmoke2 = SKEmitterNode(fileNamed: "AeonOceanSquareBubbles.sks") {
backgroundSmoke2.position = CGPoint(x: size.width / 2, y: size.height / 2)
backgroundSmoke2.zPosition = -1
backgroundSmoke2.particlePositionRange = CGVector(dx: size.width, dy: size.height)
backgroundSmoke2.advanceSimulationTime(5)
backgroundSmoke2.name = "backgroundSparkle"
addChild(backgroundSmoke2)
}
guard let emitter = AeonFileGrabber.shared.getSKEmitterNode(named: "AeonOceanSquareBubbles") else { return }
emitter.particleTexture = AeonFileGrabber.shared.getSKTexture(named: "aeonSquare")
emitter.position = CGPoint(x: size.width / 2, y: size.height / 2)
emitter.zPosition = -1
emitter.particlePositionRange = CGVector(dx: size.width, dy: size.height)
emitter.advanceSimulationTime(5)
emitter.name = "backgroundSparkle"
addChild(emitter)
}
}
@@ -0,0 +1,54 @@
//
// AeonAssetGrabber.swift
// Aeon Garden
//
// Created by Bradley Root on 5/5/19.
// Copyright © 2019 Brad Root. All rights reserved.
//
import SpriteKit

#if os(macOS)
import Cocoa

// Step 1: Typealias UIImage to NSImage
typealias UIImage = NSImage
#endif

// For screensaver support, we need to manually grab files out of the bundle.
// This creates a lot of hassle that wouldn't be necessary otherwise.
class AeonFileGrabber {
let bundle: Bundle

static let shared: AeonFileGrabber = AeonFileGrabber()

init() {
guard let bundle = Bundle(identifier: "net.amiantos.Aeon-Garden") else { fatalError("Could not load main bundle.") }
self.bundle = bundle
}

private func getFileContents(named: String, ofType type: String) -> Data? {
guard let filePath = bundle.path(forResource: named, ofType: type) else { return nil }

guard let fileContents = FileManager.default.contents(atPath: filePath) else { return nil }

return fileContents
}

public func getSKEmitterNode(named: String) -> SKEmitterNode? {
guard let fileContents = getFileContents(named: named, ofType: "sks") else { return nil }
guard let decodedEmitter = try? NSKeyedUnarchiver.unarchiveTopLevelObjectWithData(fileContents) as? SKEmitterNode else { return nil }

return decodedEmitter
}

public func getSKTexture(named: String) -> SKTexture? {
#if os(macOS)
guard let image = bundle.image(forResource: named) else { return nil }
#else
guard let image = UIImage(named: named, in: bundle, compatibleWith: nil) else { return nil }
#endif
return SKTexture(image: image)
}
}
@@ -10,6 +10,7 @@
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
import SpriteKit
import UIKit

extension UIFont {
static let aeonDataTitleFontTV = UIFont(name: "HelveticaNeue-Bold", size: 24)!
@@ -15,17 +15,19 @@ class AeonNameGenerator {
static let shared = AeonNameGenerator()

func returnLastName() -> String {
let lastNames: [String] = "Surnames".contentsOrBlank().split(
separator: "\n", omittingEmptySubsequences: true
).map(String.init)
return (lastNames[randomInteger(min: 0, max: lastNames.count - 1)])
// let lastNames: [String] = "Surnames".contentsOrBlank().split(
// separator: "\n", omittingEmptySubsequences: true
// ).map(String.init)
// return (lastNames[randomInteger(min: 0, max: lastNames.count - 1)])
return "Root"
}

func returnFirstName() -> String {
let firstNames: [String] = "FirstNames".contentsOrBlank().split(
separator: "\n", omittingEmptySubsequences: true
).map(String.init)
return (firstNames[randomInteger(min: 0, max: firstNames.count - 1)])
// let firstNames: [String] = "FirstNames".contentsOrBlank().split(
// separator: "\n", omittingEmptySubsequences: true
// ).map(String.init)
// return (firstNames[randomInteger(min: 0, max: firstNames.count - 1)])
return "Brad"
}
}

@@ -30,6 +30,22 @@ class AeonViewController: NSViewController {
}

extension AeonViewController: AeonTankUIDelegate {
func updateClock(_: String) {
return
}

func updateSelectedCreatureDetails(_: AeonCreatureNode) {
return
}

func creatureDeselected() {
return
}

func creatureSelected(_: AeonCreatureNode) {
return
}

func updatePopulation(_: Int) {
return
}
Oops, something went wrong.

0 comments on commit 13bf015

Please sign in to comment.
You can’t perform that action at this time.