change architecture to entity-component

This commit is contained in:
Niko Jochim 2020-05-01 17:55:42 +02:00
parent 6127f89e78
commit 706c879351
14 changed files with 195 additions and 302 deletions

View File

@ -20,6 +20,9 @@
11036113244B3E30008610AF /* MenuScene.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11036112244B3E30008610AF /* MenuScene.swift */; };
116060F7245C57D2004E5A36 /* EntityManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 116060F6245C57D2004E5A36 /* EntityManager.swift */; };
11738A3B24508F68004426F1 /* Unit.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11738A3A24508F68004426F1 /* Unit.swift */; };
9E286A88245C6C6800EB32B8 /* TeamComponent.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9E286A87245C6C6800EB32B8 /* TeamComponent.swift */; };
9EA3ABE9245C6DAA006BC61D /* DefaultBaseComponent.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9EA3ABE8245C6DAA006BC61D /* DefaultBaseComponent.swift */; };
9EA3ABEB245C6DFA006BC61D /* BaseNode.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9EA3ABEA245C6DFA006BC61D /* BaseNode.swift */; };
ABA03DA0244BD54F00A66916 /* Base.swift in Sources */ = {isa = PBXBuildFile; fileRef = ABA03D9F244BD54F00A66916 /* Base.swift */; };
/* End PBXBuildFile section */
@ -60,6 +63,9 @@
11036112244B3E30008610AF /* MenuScene.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MenuScene.swift; sourceTree = "<group>"; };
116060F6245C57D2004E5A36 /* EntityManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EntityManager.swift; sourceTree = "<group>"; };
11738A3A24508F68004426F1 /* Unit.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Unit.swift; sourceTree = "<group>"; };
9E286A87245C6C6800EB32B8 /* TeamComponent.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = TeamComponent.swift; path = ../../../../MonsterWars/MonsterWars/Components/TeamComponent.swift; sourceTree = "<group>"; };
9EA3ABE8245C6DAA006BC61D /* DefaultBaseComponent.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DefaultBaseComponent.swift; sourceTree = "<group>"; };
9EA3ABEA245C6DFA006BC61D /* BaseNode.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BaseNode.swift; sourceTree = "<group>"; };
ABA03D9F244BD54F00A66916 /* Base.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Base.swift; sourceTree = "<group>"; };
/* End PBXFileReference section */
@ -113,7 +119,6 @@
children = (
116060F5245C5709004E5A36 /* Entities */,
116060F4245C56EA004E5A36 /* Components */,
ABA03D9F244BD54F00A66916 /* Base.swift */,
11738A3A24508F68004426F1 /* Unit.swift */,
11036112244B3E30008610AF /* MenuScene.swift */,
11036110244B3D6A008610AF /* MenuScene.sks */,
@ -151,6 +156,9 @@
116060F4245C56EA004E5A36 /* Components */ = {
isa = PBXGroup;
children = (
9E286A87245C6C6800EB32B8 /* TeamComponent.swift */,
9EA3ABE8245C6DAA006BC61D /* DefaultBaseComponent.swift */,
9EA3ABEA245C6DFA006BC61D /* BaseNode.swift */,
);
path = Components;
sourceTree = "<group>";
@ -158,6 +166,7 @@
116060F5245C5709004E5A36 /* Entities */ = {
isa = PBXGroup;
children = (
ABA03D9F244BD54F00A66916 /* Base.swift */,
);
path = Entities;
sourceTree = "<group>";
@ -295,11 +304,14 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
9EA3ABEB245C6DFA006BC61D /* BaseNode.swift in Sources */,
110360D9244B101A008610AF /* GameScene.swift in Sources */,
116060F7245C57D2004E5A36 /* EntityManager.swift in Sources */,
11738A3B24508F68004426F1 /* Unit.swift in Sources */,
11036113244B3E30008610AF /* MenuScene.swift in Sources */,
9EA3ABE9245C6DAA006BC61D /* DefaultBaseComponent.swift in Sources */,
ABA03DA0244BD54F00A66916 /* Base.swift in Sources */,
9E286A88245C6C6800EB32B8 /* TeamComponent.swift in Sources */,
110360DB244B101A008610AF /* GameViewController.swift in Sources */,
110360D3244B101A008610AF /* AppDelegate.swift in Sources */,
);
@ -475,6 +487,7 @@
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CODE_SIGN_STYLE = Automatic;
DEVELOPMENT_TEAM = DDKFQG46BQ;
INFOPLIST_FILE = GoldWars/Info.plist;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
@ -492,6 +505,7 @@
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CODE_SIGN_STYLE = Automatic;
DEVELOPMENT_TEAM = DDKFQG46BQ;
INFOPLIST_FILE = GoldWars/Info.plist;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",

View File

@ -1,17 +1,17 @@
{
"images" : [
{
"filename" : "base-small.png",
"filename" : "base.png",
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "base-medium.png",
"filename" : "base-1.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "base-large.png",
"filename" : "base-2.png",
"idiom" : "universal",
"scale" : "3x"
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 202 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 202 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 54 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 202 KiB

View File

@ -1,71 +0,0 @@
//
// Base.swift
// GoldWars
//
// Created by Marcel Schwarz on 18.04.20.
// Copyright © 2020 SP2. All rights reserved.
//
import SpriteKit
import GameplayKit
class Base : SKSpriteNode{
public static let colorSelected = SKColor.yellow
var availableBases = [Base]()
var defaultColor = SKColor.green
var unitType: Unit = Unit.General;
var unitCount: Int = 0;
init(color: UIColor, position: CGPoint, name: String, unitCount: Int = 0, unitType: Unit = Unit.General) {
super.init(texture: SKTexture(imageNamed: "Base"),
color: color,
size: CGSize(width: 50.0, height: 50.0)
)
defaultColor = color
self.colorBlendFactor = 1
self.name = name
self.position = position
self.zPosition = 2
self.isUserInteractionEnabled = true
self.unitCount = unitCount
self.unitType = unitType
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
func addAvailableBase(base: Base) {
availableBases.append(base)
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
self.run(
SKAction.sequence(
[
SKAction.resize(byWidth: 20, height: 20, duration: 0.5),
SKAction.resize(byWidth: -20, height: -20, duration: 0.5)
]
)
)
}
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
self.color = SKColor.yellow
for base in availableBases {
base.color = Base.colorSelected
base.size = CGSize(width: 60, height: 60)
}
}
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
self.color = defaultColor
for base in availableBases {
base.color = base.defaultColor
base.size = CGSize(width: 50, height: 50)
}
}
}

View File

@ -0,0 +1,37 @@
//
// BaseNode.swift
// GoldWars
//
// Created by Niko Jochim on 01.05.20.
// Copyright © 2020 SP2. All rights reserved.
//
import Foundation
import SpriteKit
class BaseNode: SKSpriteNode{
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
// TODO: PopUp Einheiten + Close PopUp
self.run(
SKAction.sequence(
[
SKAction.resize(byWidth: 20, height: 20, duration: 0.5),
SKAction.resize(byWidth: -20, height: -20, duration: 0.5)
]
)
)
}
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
// TODO: zeige Angirff Effect
}
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
// TODO: Open Slider PopUp
}
}

View File

@ -0,0 +1,24 @@
//
// DefaultBaseComponent.swift
// GoldWars
//
// Created by Niko Jochim on 01.05.20.
// Copyright © 2020 SP2. All rights reserved.
//
import Foundation
import GameplayKit
import SpriteKit
class DefaultBaseComponent: GKComponent {
var spriteNode: BaseNode
init(texture: SKTexture) {
spriteNode = BaseNode(texture: texture, size: CGSize(width: 80, height: 80))
super.init()
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}

View File

@ -0,0 +1,26 @@
//
// Base.swift
// GoldWars
//
// Created by Marcel Schwarz on 18.04.20.
// Copyright © 2020 SP2. All rights reserved.
//
import SpriteKit
import GameplayKit
class Base : GKEntity{
init(textureName:String, team: Team? ) {
super.init()
addComponent(DefaultBaseComponent(texture: SKTexture(imageNamed: textureName)))
if(team != nil){
addComponent(TeamComponent(team: team!))
}
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}

View File

@ -21,17 +21,32 @@ class EntityManager {
func add(_ entity: GKEntity) {
entities.insert(entity)
if let spriteNode = entity.component(ofType: SpriteComponent.self)?.node {
if let spriteNode = entity.component(ofType: DefaultBaseComponent.self)?.spriteNode {
scene.addChild(spriteNode)
}
}
func remove(_ entity: GKEntity) {
if let spriteNode = entity.component(ofType: SpriteComponent.self)?.node {
if let spriteNode = entity.component(ofType: DefaultBaseComponent.self)?.spriteNode {
spriteNode.removeFromParent()
}
entities.remove(entity)
}
func base(for team: Team) -> GKEntity? {
for entity in entities {
if let teamComponent = entity.component(ofType: TeamComponent.self),
let _ = entity.component(ofType: DefaultBaseComponent.self) {
if teamComponent.team == team {
return entity
}
}
}
return nil
}
func baseNode(for team: Team) -> SKSpriteNode?{
return base(for: team)?.component(ofType: DefaultBaseComponent.self)?.spriteNode
}
}

View File

@ -9,125 +9,29 @@
import SpriteKit
import GameplayKit
class GameScene: SKScene, SKPhysicsContactDelegate {
class GameScene: SKScene{
var entities = [GKEntity]()
var graphs = [String : GKGraph]()
var bases = [Base]()
var player = [Base]()
var popUpOnBaseCollision = SKSpriteNode()
// TODO: Refactoring following as Components in Sprint 2
var timer = SKLabelNode()
var backBtn = SKShapeNode(circleOfRadius: 40)
var backLabel = SKLabelNode()
var atkBoostSkill = SKShapeNode(circleOfRadius: 30)
var defBoostSkill = SKShapeNode(circleOfRadius: 30)
var spySkill = SKShapeNode(circleOfRadius: 30)
var atkBoostLabel = SKLabelNode()
var defBoostLabel = SKLabelNode()
var spyLabel = SKLabelNode()
// TODO: END
struct physicsBodyNumber {
static let basePlayer1Number: UInt32 = 0b1
static let basePlayer2Number: UInt32 = 0b10
static let base5Number: UInt32 = 0b101
static let base6Number: UInt32 = 0b110
static let base7Number: UInt32 = 0b111
static let emptyNumber: UInt32 = 0b100
}
var entityManager: EntityManager!
override func sceneDidLoad() {
entityManager = EntityManager(scene: self)
entityManager.add(Base(textureName: "Base", team: .team1))
entityManager.add(Base(textureName: "Base", team: .team2))
self.physicsWorld.gravity = CGVector(dx: 0, dy: 0)
self.physicsWorld.contactDelegate = self
initMap()
}
let maxX = self.size.width
let midY = self.size.height / 2
// TODO: Issue #24 create Map generation Service
func initMap() {
let basePlayer1 = Base(color: SKColor.red, position: CGPoint(x: maxX * 0.1, y: midY), name: "Player1", unitCount: 100, unitType: Unit.General)
let basePlayer2 = Base(color: SKColor.blue, position: CGPoint(x: maxX * 0.9, y: midY), name: "Player2", unitCount: 100, unitType: Unit.General)
basePlayer2.physicsBody = SKPhysicsBody(circleOfRadius: 50)
basePlayer2.physicsBody?.categoryBitMask = physicsBodyNumber.basePlayer2Number
basePlayer2.physicsBody?.collisionBitMask = physicsBodyNumber.emptyNumber
basePlayer2.physicsBody?.contactTestBitMask = physicsBodyNumber.base5Number & physicsBodyNumber.base6Number & physicsBodyNumber.base7Number
popUpOnBaseCollision = SKSpriteNode(color: SKColor.blue , size: CGSize(width: self.size.width * 0.4, height: self.size.height * 0.4))
popUpOnBaseCollision.position = CGPoint(x: self.size.width * 0.5, y: self.size.height * 0.5)
popUpOnBaseCollision.zPosition = 2
self.addChild(basePlayer1)
self.addChild(basePlayer2)
player.append(basePlayer1)
player.append(basePlayer2)
entityManager.baseNode(for: .team1)?.position = CGPoint(x: self.size.width * 0.1, y: self.size.height / 2)
entityManager.baseNode(for: .team2)?.position = CGPoint(x: self.size.width * 0.9, y: self.size.height / 2)
createVirginBases()
connectBases()
addPhysicsBodyToBase()
}
override func didMove(to view: SKView) {
let background = SKSpriteNode(imageNamed: "Background")
background.position = CGPoint(x: self.size.width / 2, y: self.size.height / 2)
background.zPosition = -1
background.size = self.size
self.addChild(background)
// TODO: Refactor following as Components in Sprint 2
timer.text = "Roundtime: 30 Seconds left"
timer.fontColor = SKColor.black
timer.fontSize = 40
timer.position = CGPoint(x: self.size.width/2, y: self.size.height * 0.9)
backBtn.position = CGPoint(x: 40, y: self.size.height * 0.9)
backBtn.fillColor = SKColor.gray
backLabel.text = "Back"
backLabel.position = CGPoint(x: backBtn.position.x, y: backBtn.position.y - 15)
spySkill.position = CGPoint(x: self.size.width * 0.75, y: 40)
spySkill.fillColor = SKColor.gray
spyLabel.text = "Spy"
spyLabel.position = CGPoint(x: spySkill.position.x, y: spySkill.position.y - 15);
atkBoostSkill.position = CGPoint(x: self.size.width * 0.85, y: 40)
atkBoostSkill.fillColor = SKColor.gray
atkBoostLabel.text = "Atk"
atkBoostLabel.position = CGPoint(x: atkBoostSkill.position.x, y: atkBoostSkill.position.y - 15)
defBoostSkill.position = CGPoint(x: self.size.width * 0.95, y: 40)
defBoostSkill.fillColor = SKColor.gray
defBoostLabel.text = "Def"
defBoostLabel.position = CGPoint(x: defBoostSkill.position.x, y: defBoostSkill.position.y - 15)
self.addChild(timer)
self.addChild(backBtn)
self.addChild(backLabel)
self.addChild(atkBoostSkill)
self.addChild(defBoostSkill)
self.addChild(spySkill)
self.addChild(atkBoostLabel)
self.addChild(defBoostLabel)
self.addChild(spyLabel)
// TODO: END
}
func addPhysicsBodyToBase() {
bases[5].physicsBody = SKPhysicsBody(circleOfRadius: 20)
bases[5].physicsBody?.categoryBitMask = physicsBodyNumber.base5Number
bases[5].physicsBody?.collisionBitMask = physicsBodyNumber.emptyNumber
bases[5].physicsBody?.contactTestBitMask = physicsBodyNumber.basePlayer2Number
bases[6].physicsBody = SKPhysicsBody(circleOfRadius: 20)
bases[6].physicsBody?.categoryBitMask = physicsBodyNumber.base6Number
bases[6].physicsBody?.collisionBitMask = physicsBodyNumber.emptyNumber
bases[6].physicsBody?.contactTestBitMask = physicsBodyNumber.basePlayer2Number
bases[7].physicsBody = SKPhysicsBody(circleOfRadius: 20)
bases[7].physicsBody?.categoryBitMask = physicsBodyNumber.base7Number
bases[7].physicsBody?.collisionBitMask = physicsBodyNumber.emptyNumber
bases[7].physicsBody?.contactTestBitMask = physicsBodyNumber.basePlayer2Number
}
func createVirginBases() {
for i in 0...7 {
let base:Base
let color = SKColor.green
var position = CGPoint(x: 0, y: 0)
switch i {
case 0...2:
@ -169,86 +73,30 @@ class GameScene: SKScene, SKPhysicsContactDelegate {
default:
break
}
base = Base(color: color, position: position, name: "Base\(i)")
bases.append(base)
self.addChild(base)
}
base = Base(textureName: "Base", team: nil)
base.component(ofType: DefaultBaseComponent.self)?.spriteNode.position = position
entityManager.add(base)
}
func addLine(base1: Base , base2: Base){
let line = SKShapeNode()
let linePath = CGMutablePath()
linePath.move(to: base1.position)
linePath.addLine(to: base2.position)
line.path = linePath
line.strokeColor = SKColor.white
addChild(line)
}
func connectBases(){
player[0].addAvailableBase(base: bases[0])
player[0].addAvailableBase(base: bases[1])
player[0].addAvailableBase(base: bases[2])
bases[0].addAvailableBase(base: bases[3])
bases[1].addAvailableBase(base: bases[3])
bases[1].addAvailableBase(base: bases[4])
bases[2].addAvailableBase(base: bases[4])
bases[3].addAvailableBase(base: bases[5])
bases[3].addAvailableBase(base: bases[6])
bases[4].addAvailableBase(base: bases[7])
bases[4].addAvailableBase(base: bases[6])
player[1].addAvailableBase(base: bases[5])
player[1].addAvailableBase(base: bases[6])
player[1].addAvailableBase(base: bases[7])
for base in player{
for availableBase in base.availableBases{
addLine(base1: base, base2: availableBase)
}
}
for base in bases{
for availableBase in base.availableBases{
addLine(base1: base, base2: availableBase)
}
}
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
for touch in touches {
let locationUser = touch.location(in: self)
if atPoint(locationUser) == popUpOnBaseCollision {
popUpOnBaseCollision.removeFromParent()
}
guard let touch = touches.first else {
return
}
let touchLocation = touch.location(in: self)
for entity in entityManager.entities {
let spriteNode = entity.component(ofType: DefaultBaseComponent.self)?.spriteNode
if atPoint(touchLocation) == spriteNode {
spriteNode?.touchesBegan(touches, with: event)
}
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
for touch in touches {
let locationUser = touch.location(in: self)
if atPoint(locationUser) == player[1]{
player[1].position = locationUser
}
}
}
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
let maxX = self.size.width
let midY = self.size.height / 2
player[1].position = CGPoint(x: maxX * 0.9, y: midY)
}
func didBegin(_ contact: SKPhysicsContact) {
self.addChild(popUpOnBaseCollision)
}
}