Accessing element in array, saving it and overwriting it - arrays

My Goal: to access an element in an SKnode array and its property between my two scenes and also save and retrieve it the array that contains my achievement SKNodes that hold different values.
So I have two scenes one that is my actual game scene and the second one being my achievements menu that contains the list of all my achievements. When the achievementMenu scene starts it produces 27 Achievements which are a subclass of SKNode called “Achievements” which is seen below”
It is made in a func like so:
for _ in 0...0 {
let Counter = 0
let Achievement = Achievements()
Achievement.achCounter = Counter
Achievement.getAchievementProperties()
Achievement.position = CGPoint(x: self.frame.midX, y: self.frame.midY)
Achievement.zPosition = 100
Achievement.name = "Ach0"
Achievements3.append(Achievement)
moveableArea.addChild(Achievement)
}
Here is the Subclass of the SKNode that holds all the achievements Properties:
class Achievements: SKNode {
//Nodes used throughout the SKNode class
var achievementLabel = SKLabelNode()
var achievementTitleLabel = SKLabelNode()
var achievementNode = SKSpriteNode()
//Counter used to determine the Achievements properties
var achCounter = 0
//Amount Variables used as Achievement Properties
var image: String = "locked"
var information: String = ""
var title: String = ""
var amount = 0
var neededAmount = 0
var incrementAmount = 0
var incrementAmount2 = 0
var stage = 0
func createAchievement() {
let tex:SKTexture = SKTexture(imageNamed: image)
achievementNode = SKSpriteNode(texture: tex, color: SKColor.black, size: CGSize(width: 75, height: 75)) //frame.maxX / 20, height: frame.maxY / 20))
achievementNode.zPosition = -10
achievementNode.name = "AchievementNode"
self.addChild(achievementNode)
self.zPosition = -11
createAchievementLabels()
}
func createAchievementLabels() {
achievementTitleLabel = SKLabelNode(fontNamed: "Avenir-Black")
achievementTitleLabel.fontColor = UIColor.black;
achievementTitleLabel.fontSize = 13 //self.frame.maxY/30
achievementTitleLabel.position = CGPoint (x: 0, y: 45)
achievementTitleLabel.text = "\(title)"
achievementTitleLabel.zPosition = -9
addChild(achievementTitleLabel)
achievementTitleLabel.name = "AchievementTitleLabel"
achievementLabel = SKLabelNode(fontNamed: "Avenir-Black")
achievementLabel.fontColor = UIColor.black;
achievementLabel.fontSize = 13 //self.frame.maxY/30
achievementLabel.position = CGPoint (x: 0, y: -50)
achievementLabel.text = ("\(amount) / \(neededAmount)")
achievementLabel.zPosition = -9
addChild(achievementLabel)
achievementLabel.name = "AmountLabel"
}
func UpdateText() {
achievementLabel.text = ("\(amount) / \(neededAmount)")
}
func getAchievementProperties(){
switch achCounter {
case 0:
amount = 0;
neededAmount = 10;
incrementAmount = 100;
incrementAmount2 = 1000;
information = "No. Deaths"
title = "DAILY"
stage = 0
case 1:
amount = 0;
neededAmount = 5;
incrementAmount = 10;
incrementAmount2 = 70;
information = "No. Deaths"
title = "DAILY"
stage = 0
these are then put into a global array variable that is called “Achievements3” that is defined like so:
var Achievements3 = [SKNode]()
I am trying to get the achievements array to save when the game is “switched off” and when it is switched back on for it to replace the new nodes it generates in the AchievementMenu scene with the existing ones so that the data can be written over and the progress is still there. Along with this i am also trying to add one to the amount property of a certain achievement that is contained within the Array when something happens in the game scene such as the player dying for example. I can’t seem to find a way to access a specific element in an array and then add to its property it was given when it was generated from the sub class. I was going to use the NSUserdefaults to store all the SKNodes individually but It is too much just to store each individual achievement.
Can some please tell me what i’m doing wrong. if you would like to see my whole achievement menu scene it can be viewed below:
import Foundation
import SpriteKit
var Achievements3 = [SKNode]()
class AchievementMenu: SKScene {
//Array for Achievement Sprites
//establishing scroll
var startY: CGFloat = 0.0
var lastY: CGFloat = 0.0
var moveableArea = SKNode()
//Universal Buttons
var characterMenu = SKSpriteNode()
var itemShopMenu = SKSpriteNode()
var achievementMenu = SKSpriteNode()
var universalBackButton = SKSpriteNode()
//Labels for Sections of Achievements
var dailySection = SKLabelNode()
var achievementSection = SKLabelNode()
var bossAchievementSection = SKLabelNode()
var exitInfoMenu = SKSpriteNode()
var TEMPBUTTONTOADDSTUFF = SKSpriteNode()
override func didMove(to view: SKView) {
//setting up scrollling
moveableArea.position = CGPoint(x: 0, y: 0)
moveableArea.zPosition = -12
self.addChild(moveableArea)
//Labels for Dividing Sections of the Achievement Menu
dailySection = SKLabelNode(fontNamed: "Avenir-Black"); dailySection.fontColor = UIColor.black; dailySection.fontSize = self.frame.maxY/30
dailySection.position = CGPoint(x:self.frame.midX, y:self.self.frame.midY * 1.27)
dailySection.text = "--------------------------Daily-------------------------"
moveableArea.addChild(dailySection)
achievementSection = SKLabelNode(fontNamed: "Avenir-Black"); achievementSection.fontColor = UIColor.black; achievementSection.fontSize = self.frame.maxY/30
achievementSection.position = CGPoint(x:self.frame.midX, y:self.self.frame.midY * 0.65)
achievementSection.text = "--------------------------Achievements-------------------------"
moveableArea.addChild(achievementSection)
bossAchievementSection = SKLabelNode(fontNamed: "Avenir-Black"); bossAchievementSection.fontColor = UIColor.black; bossAchievementSection.fontSize = self.frame.maxY/30
bossAchievementSection.position = CGPoint(x:self.frame.midX, y:self.self.frame.midY * -1.3)
bossAchievementSection.text = "--------------------------Boss-------------------------"
moveableArea.addChild(bossAchievementSection)
//Buttons For Navigating the Interface
universalBackButton = SKSpriteNode(color: SKColor.orange, size: CGSize(width: 75, height: 50))
universalBackButton.position = CGPoint(x:50, y: 35)
universalBackButton.zPosition = 100001
addChild(universalBackButton)
characterMenu = SKSpriteNode(color: SKColor.orange, size: CGSize(width: 75, height: 50))
characterMenu.position = CGPoint(x:142.5, y: 35)
characterMenu.zPosition = 100001
addChild(characterMenu)
itemShopMenu = SKSpriteNode(color: SKColor.orange, size: CGSize(width: 75, height: 50))
itemShopMenu.position = CGPoint(x:232.5, y: 35)
itemShopMenu.zPosition = 100001
addChild(itemShopMenu)
achievementMenu = SKSpriteNode(color: SKColor.red, size: CGSize(width: 75, height: 50))
achievementMenu.position = CGPoint(x:325, y: 35)
achievementMenu.zPosition = 100001
addChild(achievementMenu)
exitInfoMenu = SKSpriteNode(color: SKColor.darkGray, size: CGSize(width: 75, height: 50))
exitInfoMenu.position = CGPoint(x:frame.midX, y: frame.midY - frame.midY / 2)
exitInfoMenu.zPosition = 100001
exitInfoMenu.isHidden = true
addChild(exitInfoMenu)
TEMPBUTTONTOADDSTUFF = SKSpriteNode(color: SKColor.orange, size: CGSize(width: 75, height: 50))
TEMPBUTTONTOADDSTUFF.position = CGPoint(x:frame.midX, y: 550)
TEMPBUTTONTOADDSTUFF.zPosition = 100
addChild(TEMPBUTTONTOADDSTUFF)
createAchievements()
}
func createAchievements() {
for _ in 0...0 {
//let Achievement = SKSpriteNode(color: SKColor.blue, size: CGSize(width: 100, height: 100))
let Counter = 0
let Achievement = Achievements()
Achievement.achCounter = Counter
Achievement.getAchievementProperties()
Achievement.position = CGPoint(x: self.frame.midX, y: self.frame.midY)
Achievement.zPosition = 100
Achievement.name = "Ach0"
Achievements3.append(Achievement)
moveableArea.addChild(Achievement)
}
for _ in 0...0 {
let Counter = 1
let Achievement = Achievements()
Achievement.achCounter = Counter
Achievement.getAchievementProperties()
Achievement.position = CGPoint(x: self.frame.midX*0.35, y: self.frame.midY)
Achievement.zPosition = 100
moveableArea.addChild(Achievement)
Achievement.name = "Ach1"
Achievements3.append(Achievement)
}
for _ in 0...0 {
let Counter = 2
let Achievement = Achievements()
Achievement.achCounter = Counter
Achievement.getAchievementProperties()
Achievement.position = CGPoint(x: self.frame.midX*1.65, y: self.frame.midY)
Achievement.zPosition = 100
Achievement.name = "Ach2"
Achievements3.append(Achievement)
moveableArea.addChild(Achievement)
}
for _ in 0...0 {
let Counter = 3
let Achievement = Achievements()
Achievement.achCounter = Counter
Achievement.getAchievementProperties()
Achievement.position = CGPoint(x: self.frame.midX, y: self.frame.midY*0.4)
Achievement.zPosition = 100
Achievement.name = "Ach3"
Achievements3.append(Achievement)
moveableArea.addChild(Achievement)
}
for _ in 0...0 {
let Counter = 4
let Achievement = Achievements()
Achievement.achCounter = Counter
Achievement.getAchievementProperties()
Achievement.position = CGPoint(x: self.frame.midX*0.35, y: self.frame.midY*0.4)
Achievement.zPosition = 100
Achievement.name = "Ach4"
Achievements3.append(Achievement)
moveableArea.addChild(Achievement)
}
for _ in 0...0 {
let Counter = 5
let Achievement = Achievements()
Achievement.achCounter = Counter
Achievement.getAchievementProperties()
Achievement.position = CGPoint(x: self.frame.midX*1.65, y: self.frame.midY*0.4)
Achievement.zPosition = 100
Achievement.name = "Ach5"
Achievements3.append(Achievement)
moveableArea.addChild(Achievement)
}
for _ in 0...0 {
let Counter = 6
let Achievement = Achievements()
Achievement.achCounter = Counter
Achievement.getAchievementProperties()
Achievement.position = CGPoint(x: self.frame.midX, y: self.frame.midY*0.05)
Achievement.zPosition = 100
Achievement.name = "Ach6"
Achievements3.append(Achievement)
moveableArea.addChild(Achievement)
}
}
func BringUpAchievementInfo(achName: String) {
var title = SKLabelNode()
var info = SKLabelNode()
var atexture = SKSpriteNode()
var amountLabel = SKLabelNode()
var stageLabel = SKLabelNode()
let node45 = SKNode()
node45.zPosition = 997
node45.name = "LOL"
addChild(node45)
exitInfoMenu.isHidden = false
universalBackButton.isHidden = true; characterMenu.isHidden = true; itemShopMenu.isHidden = true; achievementMenu.isHidden = true
let backgroundNode = SKSpriteNode(color: SKColor.darkGray, size: CGSize(width: frame.maxX, height: frame.maxY))
backgroundNode.position = CGPoint(x: frame.midX, y: frame.midY)
backgroundNode.alpha = 0.5
backgroundNode.zPosition = 998
node45.addChild(backgroundNode)
let infoNode = SKSpriteNode(color: SKColor.white, size: CGSize(width: frame.size.width, height: frame.size.height / 2))
infoNode.position = CGPoint(x: frame.midX, y: frame.midY + frame.midY / 6)
infoNode.zPosition = 999
node45.addChild(infoNode)
moveableArea.enumerateChildNodes(withName: achName ) {
node, stop in
let achievements = node as! Achievements
if node is Achievements {
title = SKLabelNode(fontNamed: "Avenir-Black"); title.fontColor = UIColor.black; title.fontSize = 25
title.position = CGPoint(x: 0, y: 100)
title.text = "\(achievements.title)"
title.zPosition = 1001
infoNode.addChild(title)
info = SKLabelNode(fontNamed: "Avenir-Black"); info.fontColor = UIColor.black; info.fontSize = 15
info.position = CGPoint(x: 0, y: -80)
info.text = "\(achievements.information)"
info.zPosition = 1001
infoNode.addChild(info)
amountLabel = SKLabelNode(fontNamed: "Avenir-Black"); amountLabel.fontColor = UIColor.black; amountLabel.fontSize = 15
amountLabel.position = CGPoint(x: 0, y: -100)
amountLabel.text = ("\(achievements.amount) / \(achievements.neededAmount)")
amountLabel.zPosition = 1001
infoNode.addChild(amountLabel)
atexture = SKSpriteNode(texture: achievements.achievementNode.texture, color: SKColor.blue, size: CGSize(width: 100, height: 100 ))
atexture.position = CGPoint(x: 0, y: 20)
atexture.zPosition = 1000
infoNode.addChild(atexture)
stageLabel = SKLabelNode(fontNamed: "Avenir-Black"); stageLabel.fontColor = UIColor.black; stageLabel.fontSize = 15
stageLabel.position = CGPoint(x: 0, y: -140)
stageLabel.text = ("Stage: \(achievements.stage)")
stageLabel.zPosition = 1001
infoNode.addChild(stageLabel)
}
}
}
func addOneToAchievementAndUpdateText(name1: String) {
moveableArea.enumerateChildNodes(withName: name1) {
node, stop in
if node is Achievements {
let achievements = node as! Achievements
achievements.amount += 1
achievements.UpdateText()
self.checkForAchievementStageCompletion(name2: name1)
}
}
}
func checkForAchievementStageCompletion(name2: String) {
moveableArea.enumerateChildNodes(withName: name2) {
node, stop in
if node is Achievements {
let achievements = node as! Achievements
if achievements.amount == achievements.neededAmount {
achievements.enumerateChildNodes(withName: "AchievementNode") {
node, stop in
if achievements.stage == 0 {
let changeTexture = SKAction.setTexture(SKTexture(imageNamed: "diamonds1"))
node.run(changeTexture)
achievements.neededAmount = achievements.incrementAmount
achievements.stage = 1
} else if achievements.stage == 1 {
let changeTexture = SKAction.setTexture(SKTexture(imageNamed: "diamonds2"))
node.run(changeTexture)
achievements.neededAmount = achievements.incrementAmount2
achievements.stage = 2
} else if achievements.stage == 2 {
let changeTexture = SKAction.setTexture(SKTexture(imageNamed: "diamondicon"))
node.run(changeTexture)
achievements.stage = 3
}
}
}
}
}
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
let touch: UITouch = touches.first!
let location = touch.location(in: self)
let node = self.atPoint(touch.location(in: self))
startY = location.y
lastY = location.y
switch node {
case universalBackButton:
let scene = GameScene(size: self.view!.bounds.size)
GameState.current = .gameStart
scene.scaleMode = .aspectFill
scene.backgroundColor = UIColor.clear
let transition = SKTransition.crossFade(withDuration: 0.5)
self.scene?.view?.presentScene(scene, transition: transition)
case characterMenu:
let scene = CharacterMenu(size: self.view!.bounds.size)
scene.scaleMode = .aspectFill
scene.backgroundColor = UIColor.white
self.scene?.view?.presentScene(scene)
case itemShopMenu:
let scene = ShopItemMenu(size: self.view!.bounds.size)
scene.scaleMode = .aspectFill
scene.backgroundColor = UIColor.white
self.scene?.view?.presentScene(scene)
case exitInfoMenu:
let node = childNode(withName: "LOL")
node?.removeFromParent()
exitInfoMenu.isHidden = true
universalBackButton.isHidden = false; characterMenu.isHidden = false; itemShopMenu.isHidden = false; achievementMenu.isHidden = false
case TEMPBUTTONTOADDSTUFF:
addOneToAchievementAndUpdateText(name1: "Ach0")
addOneToAchievementAndUpdateText(name1: "Ach1")
addOneToAchievementAndUpdateText(name1: "Ach2")
case Achievements3[0]:
BringUpAchievementInfo(achName: "Ach0")
case Achievements3[1]:
BringUpAchievementInfo(achName: "Ach1")
case Achievements3[2]:
BringUpAchievementInfo(achName: "Ach2")
case Achievements3[3]:
BringUpAchievementInfo(achName: "Ach3")
case Achievements3[4]:
BringUpAchievementInfo(achName: "Ach4")
case Achievements3[5]:
BringUpAchievementInfo(achName: "Ach5")
case Achievements3[6]:
BringUpAchievementInfo(achName: "Ach6")
default: return
}
}
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
let touch: UITouch = touches.first!
let location = touch.location(in: self)
let currentY = location.y
// Set Top and Bottom scroll distances, measured in screenlengths
let topLimit:CGFloat = 0.0
let bottomLimit:CGFloat = 1.33
// Set scrolling speed - Higher number is faster speed
let scrollSpeed:CGFloat = 0.2
// calculate distance moved since last touch registered and add it to current position
let newY = moveableArea.position.y + ((currentY - lastY)*scrollSpeed)
// perform checks to see if new position will be over the limits, otherwise set as new position
if newY < self.size.height*(-topLimit) {
moveableArea.position = CGPoint(x: moveableArea.position.x, y: self.size.height*(-topLimit))
}
else if newY > self.size.height*bottomLimit {
moveableArea.position = CGPoint(x: moveableArea.position.x, y: self.size.height*bottomLimit)
}
else {
moveableArea.position = CGPoint(x: moveableArea.position.x, y: newY)
}
}
}
class Achievements: SKNode {
//Nodes used throughout the SKNode class
var achievementLabel = SKLabelNode()
var achievementTitleLabel = SKLabelNode()
var achievementNode = SKSpriteNode()
//Counter used to determine the Achievements properties
var achCounter = 0
//Amount Variables used as Achievement Properties
var image: String = "locked"
var information: String = ""
var title: String = ""
var amount = 0
var neededAmount = 0
var incrementAmount = 0
var incrementAmount2 = 0
var stage = 0
func createAchievement() {
let tex:SKTexture = SKTexture(imageNamed: image)
achievementNode = SKSpriteNode(texture: tex, color: SKColor.black, size: CGSize(width: 75, height: 75)) //frame.maxX / 20, height: frame.maxY / 20))
achievementNode.zPosition = -10
achievementNode.name = "AchievementNode"
self.addChild(achievementNode)
self.zPosition = -11
createAchievementLabels()
}
func createAchievementLabels() {
achievementTitleLabel = SKLabelNode(fontNamed: "Avenir-Black")
achievementTitleLabel.fontColor = UIColor.black;
achievementTitleLabel.fontSize = 13 //self.frame.maxY/30
achievementTitleLabel.position = CGPoint (x: 0, y: 45)
achievementTitleLabel.text = "\(title)"
achievementTitleLabel.zPosition = -9
addChild(achievementTitleLabel)
achievementTitleLabel.name = "AchievementTitleLabel"
achievementLabel = SKLabelNode(fontNamed: "Avenir-Black")
achievementLabel.fontColor = UIColor.black;
achievementLabel.fontSize = 13 //self.frame.maxY/30
achievementLabel.position = CGPoint (x: 0, y: -50)
achievementLabel.text = ("\(amount) / \(neededAmount)")
achievementLabel.zPosition = -9
addChild(achievementLabel)
achievementLabel.name = "AmountLabel"
}
func UpdateText() {
achievementLabel.text = ("\(amount) / \(neededAmount)")
}
func getAchievementProperties(){
switch achCounter {
case 0:
amount = 0;
neededAmount = 10;
incrementAmount = 100;
incrementAmount2 = 1000;
information = "No. Deaths"
title = "DAILY"
stage = 0
case 1:
amount = 0;
neededAmount = 5;
incrementAmount = 10;
incrementAmount2 = 70;
information = "No. Deaths"
title = "DAILY"
stage = 0
case 2:
amount = 0;
neededAmount = 70;
incrementAmount = 10;
incrementAmount2 = 70;
information = "No. Deaths"
title = "DAILY"
stage = 0
case 3:
amount = 0;
neededAmount = 70;
incrementAmount = 10;
incrementAmount2 = 70;
information = "No. Deaths"
title = "ROOKIE"
stage = 0
case 4:
amount = 0;
neededAmount = 70;
incrementAmount = 10;
incrementAmount2 = 70;
information = "No. Deaths"
title = "PLAYER"
stage = 0
default: return
}
createAchievement()
}
}

Related

ForEach (0..< doesn't start at 0

I've the following code:
VStack (spacing: 0) {
ForEach (0..<myMaze.height, id: \.self) { (y: Int) in
HStack (spacing: 0) {
ForEach (0..<myMaze.width, id: \.self) { (x: Int) in
DrawRoom(xPos: x, yPos: y)
} // ForEach x
} // HSTack
} // ForEach y
} // VSTack
and
struct DrawRoom: View {
#ObservedObject var myMaze = Maze.sharedInstance
var xPos: Int
var yPos: Int
var body: some View {
Square(value: myMaze.value)
.stroke(Color.gray, style: StrokeStyle(lineWidth: 3))
.frame(width: myMaze.sideLength, height: myMaze.sideLength)
}
init(xPos: Int, yPos: Int) {
self.xPos = xPos
self.yPos = yPos
myMaze.value = myMaze.mazeData[xPos][yPos]
print("DrawRoom: [\(xPos), \(yPos)]")
}
}
... with the following output in the console:
X, Y
DrawRoom: [0, 2]
DrawRoom: [1, 2]
DrawRoom: [2, 2]
DrawRoom: [0, 0]
DrawRoom: [1, 0]
DrawRoom: [2, 0]
DrawRoom: [0, 1]
DrawRoom: [1, 1]
DrawRoom: [2, 1]
Surprisingly the "Y" starts at 2 then 0 and finally 1 but it should be as follows:
X, Y
DrawRoom: [0, 0]
DrawRoom: [1, 0]
DrawRoom: [2, 0]
DrawRoom: [0, 1]
DrawRoom: [1, 1]
DrawRoom: [2, 1]
DrawRoom: [0, 2]
DrawRoom: [1, 2]
DrawRoom: [2, 2]
Can somebody explain me why, is there something wrong in my coding?
For info, "Square" draws lines according to the value of myMaze.mazeData[xPos][yPos]
See below the whole code:
//
// Maze.swift
// NewMaze
//
// Created by Philippe Lagarrigue on 26/12/2020.
//
import Foundation
import SwiftUI
let side = ["North", "East", "South", "West"]
let direction = [1, 2, 4, 8]
let wall = (North: 1, East: 2, South: 4, West: 8) // 15 means all walls
let exit = (toNorth: 16, toEast: 32, toSouth: 64, toWest: 128) // 0 means no exit
struct Room {
var x: Int
var y: Int
var roomsToExit: Int
}
class Maze: ObservableObject {
// Properties
static let sharedInstance = Maze()
var viewWidth = CGFloat(0.0) //{ didSet { update(flag: 2) } }
var viewHeight = CGFloat(0.0) //{ didSet { update(flag: 2) } }
var ready2Draw = false
var width = 0 // Number of rooms (horizontally)
var height = 0 // Number of rooms (vertically)
#Published var widthDouble = CGFloat(3.0) { didSet { ready2Draw = false } }
#Published var heightDouble = CGFloat(3.0) { didSet { ready2Draw = false } }
var oneWay = true
var exitRoom = Room(x: 0, y: 0, roomsToExit: 0)
var farestRoom = Room(x: 0, y: 0, roomsToExit: 0)
var currentPos = Room(x: 0, y: 0, roomsToExit: 0)
var mazeData = [[Int]]()
//var width: Int { return Int(widthDouble) } // Number of rooms (horizontally)
//var height: Int { return Int(heightDouble) } // Number of rooms (vertically)
var numberOfRooms: Int { return self.width * self.height }
var sideLength = CGFloat(40.0) //{ didSet { print("sideLength: \(sideLength)") } }
var value = 15 // { didSet { print("value: \(value)") } }
func defineExit() {
let choosenSide = Int.random(in: 0...3) // N, E, S or W
// Fill array with 15 which means that all walls are set
mazeData = Array(repeating: Array(repeating: 15, count: self.height), count: self.width)
//var count = 0
//for x in 0..<width {
// for y in 0..<height {
// print(x, y, count, count/height, count%height)
// mazeData[x][y] = 15
// count += 1
// }
//}
print("\nchoosenSide: \(side[choosenSide]) (\(choosenSide))")
if (choosenSide + 1) % 2 == 0 {
print("Axe: E-W")
exitRoom.x = choosenSide == 3 ? 0 : self.width - 1
exitRoom.y = Int.random(in: 1..<self.height)
} else {
print("Axe: N-S")
exitRoom.x = Int.random(in: 1..<self.width)
exitRoom.y = choosenSide == 2 ? self.height - 1 : 0
}
currentPos.x = exitRoom.x
currentPos.y = exitRoom.y
currentPos.roomsToExit = 1
//print("The exit room is at \(exitRoom.x), \(exitRoom.y)")
mazeData[currentPos.x][currentPos.y] = 15 - direction[choosenSide]
print("The exit room is at [\(exitRoom.x), \(exitRoom.y)] => \(mazeData[currentPos.x][currentPos.y])")
}
init() {
//buildMaze()
}
func update(flag: Int) {
if flag & 1 == 1 {
width = Int(widthDouble)
height = Int(heightDouble)
}
if flag & 2 == 2 {
let viewW = viewWidth/widthDouble
let viewH = viewHeight/heightDouble
let side = (viewW < viewH ? viewW : viewH) - 1.0
self.sideLength = side - side * 0.1
print("Maze init:", width, "x", height, "=", numberOfRooms)
}
ready2Draw = false
}
func dummy() {
let wd = widthDouble
let hd = heightDouble
widthDouble = 3
heightDouble = 3
update(flag: 3)
defineExit()
widthDouble = wd
heightDouble = hd
}
func buildMaze(){
dummy() // This is the only way I found to get the maze displayed correctly
update(flag: 3)
defineExit()
//var rooms = numberOfRooms
//while (rooms > 0) {
// newRoom()
// rooms -= 1
//}
ready2Draw = true
}
func newRoom() {
}
}
//
// ContentView.swift
// NewMaze
//
// Created by Philippe Lagarrigue on 26/12/2020.
//
import SwiftUI
import Combine // << needed for Just publisher below
struct ContentView: View {
#ObservedObject var myMaze: Maze = .init()
#State private var selectedView = 0
let timer = Timer.publish(every: 1, on: .main, in: .common).autoconnect()
var body: some View {
TabView(selection: $selectedView) {
NavigationView() .tabItem { Image("navigation"); Text("Navigation") }.tag(0)
.onReceive(timer) { input in selectedView = 1; self.timer.upstream.connect().cancel() }
SettingsView() .tabItem { Image("settings"); Text("Settings") }.tag(1)
MapView() .tabItem { Image("map"); Text("Map") }.tag(2)
}
//.onReceive(Just(selectedView)) { print($0) }
//.onLongPressGesture { myMaze.ready2Draw = true }
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
struct NavigationView : View {
#ObservedObject var myMaze = Maze.sharedInstance
var body : some View {
GeometryReader { geometry in
Path { path in
myMaze.viewWidth = geometry.size.width
myMaze.viewHeight = geometry.size.width
}
}
}
}
struct Square: Shape {
//#ObservedObject var myMaze = Maze.sharedInstance
var value: Int
func path(in rect: CGRect) -> Path {
var path = Path()
if (value & wall.North == wall.North) {
path.move(to: CGPoint(x: rect.minX, y: rect.minY))
path.addLine(to: CGPoint(x: rect.minX, y: rect.maxY))
}
if (value & wall.East == wall.East) {
path.move(to: CGPoint(x: rect.minX, y: rect.maxY))
path.addLine(to: CGPoint(x: rect.maxX, y: rect.maxY))
}
if (value & wall.South == wall.South) {
path.move(to: CGPoint(x: rect.maxX, y: rect.maxY))
path.addLine(to: CGPoint(x: rect.maxX, y: rect.minY))
}
if (value & wall.West == wall.West) {
path.move(to: CGPoint(x: rect.maxX, y: rect.minY))
path.addLine(to: CGPoint(x: rect.minX, y: rect.minY))
}
return path
}
init(value: Int) {
self.value = value
//if value != 15 {
// print("Square: \(value)")
//}
}
}
struct DrawRoom: View {
#ObservedObject var myMaze = Maze.sharedInstance
var xPos: Int
var yPos: Int
let numbers = false
var body: some View {
if numbers {
Text("\(myMaze.value, specifier: "%.02d")")
.font(.system(size: 18, design: .monospaced))
.foregroundColor(myMaze.value == 15 ? Color.black : Color.red)
} else {
Square(value: myMaze.value)
.stroke(Color.gray, style: StrokeStyle(lineWidth: 3))
.frame(width: myMaze.sideLength, height: myMaze.sideLength)
}
}
init(xPos: Int, yPos: Int) {
self.xPos = xPos
self.yPos = yPos
myMaze.value = myMaze.mazeData[xPos][yPos]
print("DrawRoom: [\(xPos), \(yPos)]")
}
}
struct MapView : View {
#ObservedObject var myMaze = Maze.sharedInstance
var body : some View {
if myMaze.ready2Draw {
VStack (spacing: 0) {
ForEach (0..<myMaze.height, id: \.self) { (y: Int) in
HStack (spacing: 0) {
ForEach (0..<myMaze.width, id: \.self) { (x: Int) in
DrawRoom(xPos: x, yPos: y)
} // ForEach x
} // HSTack
} // ForEach y
} // VSTack
} else {
Button(action: { action() }) { Text("Build maze") }
.padding()
.background(Color.red)
.cornerRadius(20)
.foregroundColor(.white)
.font(.title)
.shadow(color: .gray, radius: 20.0, x: 10, y: 10)
}
} // body
func action() {
myMaze.buildMaze()
}
}
struct SettingsView : View {
#ObservedObject var myMaze = Maze.sharedInstance
#State private var isEditing1 = false
#State private var isEditing2 = false
var body : some View {
HStack(alignment: VerticalAlignment.top) {
VStack(alignment: .leading) {
Text("Settings\n") .font(.title)
Text("Number of rooms (horizontally): \(myMaze.widthDouble, specifier: "%.0f")")
.foregroundColor(isEditing1 ? .red : .black)
Slider(value: $myMaze.widthDouble, in: 3...32, step: 1,
onEditingChanged: { editing in isEditing1 = editing })
Text("\nNumber of rooms (vertically): \(myMaze.heightDouble, specifier: "%.0f")")
.foregroundColor(isEditing2 ? .red : .black)
Slider(value: $myMaze.heightDouble, in: 3...32, step: 1,
onEditingChanged: { editing in isEditing2 = editing })
Text("\nIn a maze with only one way, you can find the exit by touching the wall or hedge with the hand nearest to it, left or right. Keep that same hand touching the wall and keep walking. This may take you on a horribly long route, but it will get you out.")
Toggle("One way", isOn: $myMaze.oneWay)
Spacer()
Button(action: { action() }) { Text("Build maze") }
.padding()
.background(Color.red)
.cornerRadius(20)
.foregroundColor(.white)
.font(.title)
.shadow(color: .gray, radius: 20.0, x: 10, y: 10)
Spacer()
} .padding()
}
}
func action() {
myMaze.buildMaze()
}
}

how to transfer part of characters below others in swift

enter image description here> I make the word game, the problem is this. When the word is big, the
cells come out of the screen, I need these cells to move below the
other cells and be centered. and the cells should have a fixed width =
20. that's all in my application Help implement.
p.s. I tried to add elements to the stackview, but the space between the words did not appear in the stackview
1. TileView.swift
import UIKit
protocol TileDragDelegateProtocol {
func tileView(tileView: TileView, didDragToPoint: CGPoint)
}
class TileView: UIImageView {
var letter: Character?
var isMatch = false
private var xOffset: CGFloat = 0.0
private var yOffset: CGFloat = 0.0
var dragDelegate: TileDragDelegateProtocol?
init(letter: Character, sideLength: CGFloat) {
self.letter = letter
//let scale = CGRect(x: 0, y: 0, width: self.bounds.size.width /* scale*/, height: self.bounds.size.height /** scale*/)
// super.init(frame: scale)
// let scale = CGRect(x: 0, y: 0, width: self.bounds.size.width /* scale*/, height: self.bounds.size.height /** scale*/)
let image = UIImage(named: "tile")
super.init(image: image)
let scale = sideLength / (image?.size.width)!
self.frame = CGRect(x: 0, y: 0, width: (image?.size.width)! * scale, height: (image?.size.height)! * scale)
// self.frame = CGRect(x: 0, y: 0, width: self.bounds.size.width /* scale*/, height: self.bounds.size.height /** scale*/)
//self.layer.cornerRadius = 23
//self.clipsToBounds = true
let letterLabel = UILabel(frame: self.bounds)
letterLabel.textAlignment = .center
letterLabel.textColor = .white
letterLabel.backgroundColor = .clear
letterLabel.text = String(letter).uppercased()
letterLabel.font = .boldSystemFont(ofSize: 40.0 / 3) //.systemFont(ofSize: 78.0 / 3/*scale*/)
//letterLabel.layer.cornerRadius = 23
//letterLabel.clipsToBounds = true
// self.backgroundColor = .red
// self.textAlignment = .center
// self.textColor = .white
// self.backgroundColor = .black
// self.text = String(letter).uppercased()
// self.font = .boldSystemFont(ofSize: 50.0 / 3)
self.addSubview(letterLabel)
self.isUserInteractionEnabled = true
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
if let touch = touches.first {
let point = touch.location(in: self.superview)
xOffset = point.x - self.center.x
yOffset = point.y - self.center.y
}
}
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
if let touch = touches.first {
let point = touch.location(in: self.superview)
self.center = CGPoint(x: point.x - xOffset, y: point.y - yOffset)
}
}
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
self.touchesMoved(touches, with: event)
dragDelegate?.tileView(tileView: self, didDragToPoint: self.center)
}
}
2.TargetView.swift
import UIKit
class TargetView: UILabel {
var letter: Character!
var isMatch = false
init(letter: Character, sideLength: CGFloat) {
self.letter = letter
//let image = UIImage(named: "slot")
//super.init(image: image)
//let scale = CGRect(x: 0, y: 0, width: (image?.size.width)! * scale, height: (image?.size.height)! * scale)
super.init(frame: CGRect(x: 0, y: 0, width: 15, height: 30))
self.backgroundColor = .red
self.textAlignment = .center
self.font = .boldSystemFont(ofSize: 60.0 / 3)
self.text = "_"//String(letter).uppercased()
self.textColor = .white
self.lineBreakMode = .byWordWrapping
self.adjustsFontSizeToFitWidth = true
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
3. ViewController
import UIKit
class ViewController: UIViewController {
// let ScreenWidth = UIScreen.main.bounds.size.width
// let ScreenHeight = UIScreen.main.bounds.size.height
//frame: CGRect(x: 0, y: 0, width: UIScreen.main.bounds.size.width, height: UIScreen.main.bounds.size.height)
//var gameView = UIView()
private var tiles = [TileView]()
private var targets = [TargetView]()
let tileMargin : CGFloat = 0.0
var words = "Hellomyf rie nds?"
// lazy var stackView: UIStackView = {
// let stack = UIStackView()
// stack.axis = .horizontal
// stack.spacing = 0
// stack.distribution = .fillEqually
// stack.translatesAutoresizingMaskIntoConstraints = false
// return stack
// }()
//
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .lightGray
dealRandomAnagram()
}
func dealRandomAnagram() {
let anagram1 = words
let anagram1length = anagram1.count
print("phrase1[\(anagram1length)]: \(anagram1)")
// Рассчет размера плитки //Tile size calculation
let tileSize = ceil(UIScreen.main.bounds.size.width * 0.8 / CGFloat(min(anagram1length, anagram1length))) + tileMargin // * 1
//Поиск х позиции первой плитки // Finding x position of the first tile
var xOffset = (UIScreen.main.bounds.size.width - CGFloat(max(anagram1length, anagram1length)) * (15 + tileMargin)) / 2.0
//+ tileMargin
//let yOffset = (UIScreen.main.bounds.size.height - CGFloat(max(anagram1length, anagram1length)) * (15 + tileMargin)) / 2.0
//+ tileMargin
//настройка центра плитки (вместо источника плитки)
xOffset += tileSize / 2.0
tiles = []
// создание плитки
for (index, letter) in anagram1.enumerated() {
if letter != " " {
let tile = TileView(letter: letter, sideLength: tileSize)
tile.center = CGPoint(x: xOffset + CGFloat(index) * (tileSize + tileMargin), y: UIScreen.main.bounds.size.height/4*3)
view.addSubview(tile)
tile.dragDelegate = self
tiles.append(tile)
}
}
targets = []
for (index,letter) in anagram1.enumerated() {
let target = TargetView(letter: letter, sideLength: 15)
if letter != " " || index > 15 {
// let target = TargetView(letter: letter, sideLength: 15)
target.center = CGPoint(x: xOffset + CGFloat(index) /* * 20 */ * (15 + tileMargin), y: UIScreen.main.bounds.size.height - 100) //100 //UIScreen.main.bounds.size.height - CGFloat(index) * 50
view.addSubview(target)
targets.append(target)
//stackView.addArrangedSubview(target)
//targets.append(target)
}
}
}
//xOffset + CGFloat(index) /* * 20 */ * (tileSize + tileMargin )
//UIScreen.main.bounds.size.height - 100
func placeTile(tileView: TileView, targetView: TargetView) {
tileView.isMatch = true
targetView.isMatch = true
tileView.isUserInteractionEnabled = false
UIView.animate(withDuration: 0.35, delay: 0.0, options: UIView.AnimationOptions.curveEaseOut, animations: {
tileView.center = targetView.center
tileView.backgroundColor = .clear
targetView.transform = .identity
}, completion: {
(value: Bool) in
targetView.isHidden = true
})
}
func checkValidate() {
for targetView in targets {
if !targetView.isMatch {
return
}
}
print("Valid")
}
}
extension ViewController: TileDragDelegateProtocol {
func tileView(tileView: TileView, didDragToPoint: CGPoint) {
var targetView: TargetView?
for tv in targets {
if tv.frame.contains(didDragToPoint) && !tv.isMatch {
targetView = tv
break
}
}
if let targetView = targetView {
//2 check if letter matches
if targetView.letter == tileView.letter {
//3
self.placeTile(tileView: tileView, targetView: targetView)
print("Success! You should place the tile here!")
//more stuff to do on success here
self.checkValidate()
print("Check if the player has completed the phrase")
} else {
//4
UIView.animate(withDuration:0.35,
delay:0.00,
options :UIView.AnimationOptions.curveEaseOut,
animations: {
tileView.center = CGPoint(x: tileView.center.x,
y: tileView.center.y - (200))
},
completion: nil)
print("Failure. Let the player know this tile doesn't belong here")
//more stuff to do on failure here
}
}
}
}

Cannot check array range in swift

I have different arrays, they store a different number of elements, at the click of a button the index of the array is increased by 1 and the element is added to another array, I did an array range check, but it does not work. what could be the problem
xCode console: Fatal error: Index out of range: file
class ViewController: UIViewController {
var currentIndex = 0
var arrayIndex = -1
var arrayWords: [Words]? {
didSet {
// wordTextLabel.text = arrayWords?[0].arrayWords?[currentIndex].name
// wordImage.image = arrayWords?[0].arrayWords?[currentIndex].image
// wordArray.append((arrayWords?[0].arrayWords?[currentIndex])!)
}
}
var testArray = ["Hello","Energy","Disk","Duck","Wafles"]
var wordArray: [String] = [] //[ArrayWords] = []
lazy var wordTextLabel: UILabel = {
let label = UILabel()
label.text = testArray[currentIndex]//arrayWords?[0].arrayWords?[currentIndex].name
label.textColor = .white
label.font = UIFont(name: "OpenSans-ExtraBold", size: 20)
label.textAlignment = .center
label.translatesAutoresizingMaskIntoConstraints = false
label.isUserInteractionEnabled = true
return label
}()
lazy var wordImage: UIImageView = {
let image = UIImageView()
image.contentMode = .scaleAspectFit
image.tintColor = .white
image.translatesAutoresizingMaskIntoConstraints = false
return image
}()
lazy var button1: UIButton = {
let button = UIButton()
button.backgroundColor = .white
button.setTitle("Good", for: .normal)
button.setTitleColor(.black, for: .normal)
button.addTarget(self, action: #selector(buttonAction), for: .touchUpInside)
button.layer.cornerRadius = 40
button.clipsToBounds = true
button.translatesAutoresizingMaskIntoConstraints = false
return button
}()
lazy var button2: UIButton = {
let button = UIButton()
button.backgroundColor = .white
button.setTitle("No", for: .normal)
button.setTitleColor(.black, for: .normal)
button.layer.cornerRadius = 40
button.translatesAutoresizingMaskIntoConstraints = false
return button
}()
override func viewDidLoad() {
super.viewDidLoad()
setupView()
}
func setupView() {
view.setGradient(colorOne: Color.purpleColor, colorTwo: Color.pinkColor,
startPoint: CGPoint(x: 1.0, y: 0.1), endPoint: CGPoint(x: 0.1, y: 1.0))
view.addSubview(wordTextLabel)
//wordTextLabel.addSubview(wordImage)
//view.addSubview(wordImage)
view.addSubview(button1)
view.addSubview(button2)
NSLayoutConstraint.activate(NSLayoutConstraint.constraints(withVisualFormat: "H:|-120-[v0]-120-|", metrics: nil, views: ["v0": wordTextLabel]))
button1.bottomAnchor.constraint(lessThanOrEqualTo: view.bottomAnchor, constant: -40).isActive = true
button1.leftAnchor.constraint(equalTo: view.leftAnchor, constant: 30).isActive = true
button1.heightAnchor.constraint(equalToConstant: 80).isActive = true
button1.widthAnchor.constraint(equalToConstant: 80).isActive = true
button2.bottomAnchor.constraint(lessThanOrEqualTo: view.bottomAnchor, constant: -40).isActive = true
button2.rightAnchor.constraint(equalTo: view.rightAnchor, constant: -30).isActive = true
button2.heightAnchor.constraint(equalToConstant: 80).isActive = true
button2.widthAnchor.constraint(equalToConstant: 80).isActive = true
// wordArray.append((arrayWords?[0].arrayWords?[currentIndex])!)
}
#objc func buttonAction(sender: Any!) {
print("Button tapped")
action()
}
func action() {
if currentIndex < testArray.count/*arrayWords?[0].arrayWords?.count*/ { //!= 2 // !=
currentIndex += 1
arrayIndex += 1
wordTextLabel.text = testArray[currentIndex]//arrayWords?[0].arrayWords?[currentIndex].name
wordArray.append(testArray[arrayIndex])//((arrayWords?[0].arrayWords?[arrayIndex])!)
} else if arrayIndex != 3 {
arrayIndex += 1
wordArray.append(testArray[arrayIndex])//((arrayWords?[0].arrayWords?[arrayIndex])!)
}
}
}
Change action() as below and it will work fine. There is no need to maintain two index variables and without the second variable you don't need the else if... either
func action() {
if currentIndex < testArray.count {
wordTextLabel.text = testArray[currentIndex]
wordArray.append(testArray[currentIndex])
}
currentIndex += 1
}

How to insert data to a textfield that goes to an empty array and in turn displays in a label?

I found this ready code that prints out an already stored array called (let dataArr = ["25","51","57","73","68"]) in rows into a label.
I have now made a text field that can insert to another array(my array = String) I want this array to be swaped with the first array.
But know when I swap to empty array that has already been populated via a text field it doesn’t appear in label.
I was hoping to swap the dataArr to an empty array called array that files up with data when inserted via the text field but for reason when I am doing that it doesn’t get shown in the label I am posting now to see what I am doing wrong.
But when I print the array it appears in the console but not in the label.
let dataArr = ["2,5","5,1","5,7"]
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .yellow
var yPos = 90
for i in 0..<dataArr.count {
let element = dataArr[i]
let labelNum = UILabel()
let num1Nnum2 = "number 1 : \(element)"
labelNum.text = num1Nnum2
labelNum.textAlignment = .center
labelNum.frame = CGRect( x:10, y:yPos, width:250, height: 80)
yPos += 80
self.view.addSubview(labelNum)
}
}
var array = [String]()
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .yellow
var yPos = 90
for i in 0..<array.count {
let element = array[i]
let labelNum = UILabel()
let num1Nnum2 = "number 1 : \(element)"
labelNum.text = num1Nnum2
labelNum.textAlignment = .center
labelNum.frame = CGRect( x:10, y:yPos, width:250, height: 80)
yPos += 80
self.view.addSubview(labelNum)
}
}
Ran your code and got the following result.
Is this what you were expecting?
UPDATE :
Here's what whipped up.
lazy var myText: UITextField = {
let input = UITextField(frame: CGRect(x: 0, y: 0, width: 300, height: 40))
input.backgroundColor = .white
input.placeholder = "Enter data here!"
return input
}()
lazy var enterButton: UIButton = {
let button = UIButton(frame: CGRect(x: 0, y: 0, width: 50, height: 50))
button.backgroundColor = .gray
button.setTitle("ENTER", for: .normal)
button.titleLabel?.font = UIFont.boldSystemFont(ofSize: 11)
button.addTarget(self, action: #selector(btnEnter), for: .touchUpInside)
return button
}()
lazy var doneButton: UIButton = {
let button = UIButton(frame: CGRect(x: 0, y: 0, width: 50, height: 50))
button.backgroundColor = .gray
button.setTitle("Done", for: .normal)
button.titleLabel?.font = UIFont.boldSystemFont(ofSize: 11)
button.addTarget(self, action: #selector(btnDone), for: .touchUpInside)
return button
}()
var array = [String]()
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
if (!array.isEmpty) {
view.backgroundColor = .yellow
var yPos = 90
for i in 0..<array.count {
let element = array[i]
let labelNum = UILabel()
let num1Nnum2 = "number 1 : \(element)"
labelNum.text = num1Nnum2
labelNum.textAlignment = .center
labelNum.frame = CGRect( x:10, y:yPos, width:250, height: 80)
yPos += 80
myText.removeFromSuperview()
enterButton.removeFromSuperview()
doneButton.removeFromSuperview()
self.view.addSubview(labelNum)
}
}
else
{
view.backgroundColor = .green
setUpMyText()
setUpEnterButton()
setUpDoneButton()
}
}
private func setUpMyText() {
self.view.addSubview(myText)
myText.translatesAutoresizingMaskIntoConstraints = false
myText.centerXAnchor.constraint(equalTo: self.view.centerXAnchor).isActive = true
myText.centerYAnchor.constraint(equalTo: self.view.centerYAnchor).isActive = true
myText.widthAnchor.constraint(equalToConstant: myText.bounds.width).isActive = true
myText.heightAnchor.constraint(equalToConstant: myText.bounds.height).isActive = true
}
private func setUpEnterButton() {
self.view.addSubview(enterButton)
enterButton.translatesAutoresizingMaskIntoConstraints = false
enterButton.centerXAnchor.constraint(equalTo: self.view.centerXAnchor).isActive = true
enterButton.topAnchor.constraint(equalTo: myText.bottomAnchor, constant: 10).isActive = true
}
private func setUpDoneButton() {
self.view.addSubview(doneButton)
doneButton.translatesAutoresizingMaskIntoConstraints = false
doneButton.centerXAnchor.constraint(equalTo: self.view.centerXAnchor).isActive = true
doneButton.topAnchor.constraint(equalTo: enterButton.bottomAnchor, constant: 10).isActive = true
}
#objc fileprivate func btnEnter() {
print(myText)
array.append(myText.text!)
myText.text = ""
}
#objc fileprivate func btnDone() {
print("Done")
self.viewDidLoad()
}

combine an array of images to a single image which is a row of images in swift

Trying to combine an array of images to a single image which looks like a long row of the images.
(note: images may or may not be of similar sizes)
here is the code, which currently works for single size images only
func combine(images: NSMutableArray) -> UIImage {
var contextSize = CGSizeZero
var xMaxSize : CGFloat = 0
for image in images {
//
xMaxSize = xMaxSize + image.size.width
//contextSize.width = max(contextSize.width , image.size.width )
contextSize.height = max(contextSize.height, image.size.height)
}
contextSize.width = xMaxSize
UIGraphicsBeginImageContextWithOptions(contextSize, false, UIScreen.mainScreen().scale)
var imageXPlace :CGFloat = 0
for image in images {
let originX = imageXPlace
let originY = (contextSize.height - image.size.height) / 2
image.drawInRect(CGRectMake(originX, originY, image.size.width, image.size.height))
imageXPlace = imageXPlace + image.size.width
}
let combinedImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return combinedImage
}
This question is also related to this one
Images has different sizes
Height of the combined image - the smallest height in UIImage
ViewController.swift
import UIKit
struct ImageToCombine {
var image = UIImage()
var size: CGSize {
get {
return CGSize(width: image.size.width, height: image.size.height)
}
}
var widthAndHeightRatio: CGFloat {
get {
return image.size.width/image.size.height
}
}
init (image: UIImage) {
self.image = image
}
}
class ViewController: UIViewController {
var imageView = UIImageView()
var images = [ImageToCombine]()
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
imageView = UIImageView(frame: UIScreen.mainScreen().bounds)
imageView.contentMode = .ScaleAspectFit
view.addSubview(imageView)
images.append(ImageToCombine(image: UIImage(named: "image1")!))
images.append(ImageToCombine(image: UIImage(named: "image2")!))
images.append(ImageToCombine(image: UIImage(named: "image3")!))
imageView.image = combine(images, spaceBetweenImages: 10)
}
func combine(images: [ImageToCombine], spaceBetweenImages:CGFloat) -> UIImage {
var fullWidth:CGFloat = 0
var minHeight:CGFloat = images[0].size.height
for index in 0..<images.count {
fullWidth += images[index].size.width
if (index+1 < images.count) {
fullWidth += spaceBetweenImages
}
if (minHeight > images[index].size.height) {
minHeight = images[index].size.height
}
}
let quality = CGFloat(4)
let boundForBetter = CGRectMake(0, 0, fullWidth*quality, minHeight*quality)
UIGraphicsBeginImageContext(boundForBetter.size)
let context = UIGraphicsGetCurrentContext()
for index in 0..<images.count {
var imageX:CGFloat = 0
for index2 in 0..<index {
imageX += images[index2].size.width
if (index2+1 < images.count) {
imageX += spaceBetweenImages
}
}
let imageY:CGFloat = (minHeight - images[index].size.height)*quality/2
let rect = CGRect(x: imageX*quality, y: imageY, width: images[index].size.width*quality, height: images[index].size.height*quality)
CGContextDrawImage(context, rect, images[index].image.CGImage)
}
let combinedImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
let resultImageimage = UIImage(CGImage: imageResize(combinedImage, sizeChange:CGSize(width: fullWidth/quality, height: minHeight/quality)).CGImage!, scale: 1.0, orientation: .DownMirrored)
return resultImageimage
}
func imageResize(imageObj:UIImage, sizeChange:CGSize)-> UIImage {
let hasAlpha = true
let scale: CGFloat = 0.0 // Automatically use scale factor of main screen
UIGraphicsBeginImageContextWithOptions(sizeChange, !hasAlpha, scale)
imageObj.drawInRect(CGRect(origin: CGPointZero, size: sizeChange))
let scaledImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext() // !!!
return scaledImage
}
}
result:

Resources