How to use SwiftUI with different views? - scenekit

I have SCNCylinder in a SCNScene and a button in a SwiftUI frame below it. Whenever the button is pressed the cylinder is expected to rotate by 90°. I am not getting the expected result with my code.
//SwiftUI
struct ContentView: View {
var body: some View {
VStack{
Button(action: {
// What to perform
let rotationangle = 180.0
}) {
// How the button looks like
Text("90°")
.frame(width: 100, height: 100)
.position(x: 225, y: 500)
}
SceneKitView()
.frame(width: 300, height: 300)
.position(x: 0, y: 200)
}
}
}
//SceneKit
struct SceneKitView: UIViewRepresentable {
func makeUIView(context:
UIViewRepresentableContext<SceneKitView>) -> SCNView {
//Scene properties
let sceneView = SCNView()
sceneView.scene = SCNScene()
sceneView.allowsCameraControl = true
sceneView.autoenablesDefaultLighting = true
sceneView.backgroundColor = UIColor.white
sceneView.frame = CGRect(x: 0, y: 10, width: 0, height: 1)
//Cylinder properties
let cylinder = SCNCylinder(radius: 0.02, height: 2.0)
let cylindernode = SCNNode(geometry: cylinder)
cylindernode.position = SCNVector3(x: 0, y: 0, z: 0)
cylinder.firstMaterial?.diffuse.contents = UIColor.green
//Pivot and rotation of the cylinder
func degreesToRadians(_ degrees: Float) -> CGFloat {
return CGFloat(degrees * .pi / 180)
}
cylindernode.pivot = SCNMatrix4MakeTranslation(0, -1, 0)
//Line with an error: Use of unresolved identifier ‘rotationangle’
let rotation = SCNAction.rotate(by: degreesToRadians(rotationangle), around: SCNVector3 (1, 0, 0), duration: 5)
sceneView.scene?.rootNode.addChildNode(cylindernode)
cylindernode.runAction(rotation)
return sceneView
}
func updateUIView(_ uiView: SCNView, context: UIViewRepresentableContext<SceneKitView>) {
}
typealias UIViewType = SCNView
}
I am having a error saying “ Use of unresolved identifier ‘rotationangle’ “ during using ‘rotationangle‘ in SCNAction.

You need to declare a #State in your ContentView and set the value of the property in your Button action.
You then need to declare an angle property in your SceneKitView as a #Binding and use that value for it to work properly.
I haven't yet tested this out. Keep in mind that you don't have cone declared anywhere so I'm not sure what that is.
import SwiftUI
import SceneKit
struct ContentView: View {
#State var rotationAngle: Float = 0.0
var body: some View {
VStack {
Button(action: {
// What to perform
self.rotationAngle = 180.0
}) {
// How the button looks like
Text("90°")
.frame(width: 100, height: 100)
.position(x: 225, y: 500)
}
SceneKitView(angle: self.$rotationAngle)
.frame(width: 300, height: 300)
.position(x: 0, y: 200)
}
}
}
//SceneKit
struct SceneKitView: UIViewRepresentable {
#Binding var angle: Float
func degreesToRadians(_ degrees: Float) -> CGFloat {
print(degrees)
return CGFloat(degrees * .pi / 180)
}
func makeUIView(context: UIViewRepresentableContext<SceneKitView>) -> SCNView {
// Scene properties
let sceneView = SCNView()
sceneView.scene = SCNScene()
sceneView.allowsCameraControl = true
sceneView.autoenablesDefaultLighting = true
sceneView.backgroundColor = UIColor.white
sceneView.frame = CGRect(x: 0, y: 10, width: 0, height: 1)
return sceneView
}
func updateUIView (_ sceneView: SCNView, context: UIViewRepresentableContext<SceneKitView>) {
if self.angle > 0 {
// Cylinder properties
let cylinder = SCNCylinder(radius: 0.02, height: 2.0)
let cylindernode = SCNNode(geometry: cylinder)
cylindernode.position = SCNVector3(x: 0, y: 0, z: 0)
// cone.firstMaterial?.diffuse.contents = UIColor.green
// Pivot and rotation of the cylinder
cylindernode.pivot = SCNMatrix4MakeTranslation(0, -1, 0)
sceneView.scene?.rootNode.addChildNode(cylindernode)
//Line with an error: Use of unresolved identifier ‘rotationangle’
let rotation = SCNAction.rotate(by: self.degreesToRadians(self.angle), around: SCNVector3 (1, 0, 0), duration: 5)
cylindernode.runAction(rotation)
}
}
}

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
}
}
}
}

Is it possible to make an if statement if a list item is equal to a certain number in swift?

I've been working on a truth or dare app, in which you spin a wheel and you randomly get a truth or dare, and I want to have a bunch of random truth questions and dares saved in a database.
I have it set up so when you press the spin button it randomly chooses a truth or dare out of an array.
i've tried it a little and couldn't seem to get it to work. so my question is would it be possible to do something like,
if self.number[0] == 0 || 2 || 3{ (this is where it would get the random truth)}
else{(this is where it would get the random dare)}
I don't know if it will help, but this is the rest of my code.
import SwiftUI
import CoreHaptics
class Colors{
static var drinkGradient = [LinearGradient(gradient: Gradient(colors: [Color("drinkcard"), Color("drinkcard2"), Color("drinkcard")]), startPoint: .top, endPoint: .bottom)]
static var truthGradient = [LinearGradient(gradient: Gradient(colors: [Color("truthcard"), Color("truthcard"), Color("truthcard")]), startPoint: .top, endPoint: .bottom)]
static var dareGradient = [LinearGradient(gradient: Gradient(colors: [Color("darecard"), Color("darecard"), Color("darecard")]), startPoint: .top, endPoint: .bottom)]
}
struct ContentView: View {
#State private var timer:Timer!
#State private var text = [String("Truth"), String("Dare"), String("Truth"), String("Dare"), String("Truth"), String("Dare"), String("Drink!!")]
#State private var foregrounds = [Color.white, Color.white, Color.white, Color.white, Color.white, Color.white, Color.black]
#State private var number = [0]
#State private var timeKeeper: Float = 0
#State private var angle: Double = 0
let generator = UINotificationFeedbackGenerator()
#State var backgrounds = [Colors.truthGradient[0], Colors.dareGradient[0], Colors.truthGradient[0], Colors.dareGradient[0], Colors.truthGradient[0], Colors.dareGradient[0], Colors.drinkGradient[0]]
var body: some View {
ZStack{
Rectangle()
.foregroundColor(Color("background"))
.edgesIgnoringSafeArea(.all)
VStack{
HStack {
Text("Truth, Dare or Drink")
.shadow(radius: 10)
.padding(.top, 20)
.foregroundColor(.white)
.font(.system(.largeTitle, design: .rounded) )
.frame(minWidth: 0, maxWidth: .infinity, minHeight: 0, maxHeight: 100)
.background(Color("banner"))
.edgesIgnoringSafeArea(.top)
.shadow(radius: 15)
}
Text("This is where the Truth or dare will go.")
.frame(width: 350, height: 200)
.foregroundColor(.white)
.font(.system(.headline, design: .rounded))
Spacer()
Text(text[number[0]])
.font(.system(.largeTitle, design: .rounded))
.foregroundColor(foregrounds[number[0]])
.frame(width: 250, height: 250)
.background(backgrounds[number[0]])
.clipShape(RoundedRectangle(cornerRadius: 15, style: .continuous))
.shadow(radius: 10)
.rotationEffect(.degrees(angle))
.animation(.easeIn)
Spacer()
Button(action: {
self.timer = Timer.scheduledTimer(withTimeInterval: 0.10, repeats: true, block: {_ in
self.timeKeeper += 0.10
if self.timeKeeper < 3{
if self.number[0] == self.text.count - 1{
self.number[0] = 0
self.angle += 360
let impactHeavy = UIImpactFeedbackGenerator(style: .heavy)
impactHeavy.impactOccurred()
}
else{
self.number[0] += 1
self.angle += 360
let impactHeavy = UIImpactFeedbackGenerator(style: .heavy)
impactHeavy.impactOccurred()
}
}
else{
self.number[0] = Int.random(in:
0...self.text.count - 1)
let impactHeavy = UIImpactFeedbackGenerator(style: .heavy)
impactHeavy.impactOccurred()
self.angle += 360
self.timeKeeper = 0
self.timer.invalidate()
}
})
}) {
Text("Spin")
.font(.system(.title, design: .rounded))
.foregroundColor(.white)
.frame(width: 250, height: 50)
.background(Color("button"))
.clipShape(RoundedRectangle(cornerRadius: 15, style: .continuous))
.shadow(radius: 15)
}
Spacer()
}
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
if (self.number[0] == 0 || self.number[0] == 2 || self.number[0] == 3) {
print("truth")
} else {
print("dare")
}

BMI Calculator always returns 0 in swift

I've been trying to learn swift and decided to build a little BMI calculator just to get used to everything. I thought I had everything about figured out, but for some reason it just returns 0 every time. I can't quite understand why exactly. I feel like it might be something to do with the #State var s but, I'm not sure cause the ones that aren't for the textinputs seem to work just find.
This is what I've got:
import SwiftUI
struct ContentView: View {
#State var heightFeet: String = ""
#State var heightInches: String = ""
#State var weight: String = ""
#State var bmi: String = ""
#State var bmiText: String = ""
#State var bmiDetail: String = ""
var body: some View{
VStack {
VStack {
VStack {
Text("BMI Calculator")
.font(.largeTitle)
.padding(.top)
.foregroundColor(Color.white)
}
.frame(minWidth: 0, maxWidth: .infinity, minHeight: 0, maxHeight: 100)
.background(Color.black)
.shadow(radius: 10)
VStack {
TextField("Enter height in feet", text: $heightFeet)
.padding(.all)
.frame(width: 300)
.textFieldStyle(RoundedBorderTextFieldStyle())
.background(Color.clear)
.foregroundColor(.black)
.shadow(radius: 5)
.keyboardType(.numberPad)
TextField("Enter height in inches", text: $heightInches)
.padding(.all)
.frame(width: 300)
.textFieldStyle(RoundedBorderTextFieldStyle())
.background(Color.clear)
.foregroundColor(.black)
.shadow(radius: 5)
.keyboardType(.numberPad)
TextField("Enter weight", text: $weight)
.padding(.all)
.frame(width: 300)
.textFieldStyle(RoundedBorderTextFieldStyle())
.background(Color.clear)
.foregroundColor(.black)
.shadow(radius: 5)
.keyboardType(.numberPad)
}
.frame(minWidth: 0, maxWidth: .infinity, minHeight: 0, maxHeight: .infinity)
.background(Color.gray)
VStack {
Text(bmiText)
.font(.title)
.foregroundColor(Color.black)
Text(bmi)
.font(.largeTitle)
.foregroundColor(Color.black)
Text(bmiDetail)
.padding(.all)
.font(.headline)
.foregroundColor(.black)
}
.frame(minWidth: 0, maxWidth: .infinity, minHeight: 0, maxHeight: .infinity)
.padding()
}
HStack {
Button(action: {
let heightInFeet = Int(self.heightFeet)
let heightInInches = Int(self.heightInches)
let weights = Int(self.weight)
let height = Int(heightInFeet! * 12 + heightInInches!)
let bmis = Int(weights! / (height * height) * 703)
self.bmi = "\(bmis)%"
self.bmiText = "Your BMI is"
if bmis > 30{
self.bmiDetail = "You are considered to be obese."
}
else if bmis > 25{
self.bmiDetail = "You are considered to be overweight."
}
else{
self.bmiDetail = "You are healthy!"
}
}) {
HStack {
Image(systemName: "plus.square")
Text("Calculate")
}
.frame(minWidth: 0, maxWidth: .infinity)
.font(.title)
.padding(.horizontal, 60.0)
.padding(.vertical, 20)
.background(Color("button"))
.cornerRadius(10)
.foregroundColor(Color.black)
.shadow(radius: 5)
.padding(.vertical, 40)
.padding(.horizontal, 20)
}
}
.background(Color.gray)
}
.frame(minWidth:0, maxWidth: .infinity, minHeight: 0, maxHeight: .infinity)
.background(Color.gray)
.edgesIgnoringSafeArea(.all)
.onTapGesture {
self.endTextEditing()
}
}
}
extension View {
func endTextEditing() {
UIApplication.shared.sendAction(#selector(UIResponder.resignFirstResponder),
to: nil, from: nil, for: nil)
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
The problem is not the code, but your calculation.
let bmis = Int(weights! / (height * height) * 703)
Example:
weights = 100 kg
height = 76 inch
result ==> 100 / (76 * 76) * 703 ==> 100 / 5776 * 703 ==> 100 / 4060528 ==> ~0
You can change the formula to
703 * weight / height * height
to get the correct result.
For the formula see www.cdc.gov

SwiftUI: add SwiftUI Path to Scenekit Scene

I'm trying to add add SwiftUI Path to a Scenekit Scene (as SCNShape).
I created:
Scenekit View (image 1)
SwiftUI Path (image 2)
Then I tried to call the SwiftUI Path, based on the approach bellow:
Unable to create circle using UIBezierPath and SCNShape
let scnpath = ContentView()
let shape = SCNShape(path: scnpath)
let shapeNode = SCNNode(geometry: shape)
Didn't work, as results bellow:
import SwiftUI
import SceneKit
struct ScenekitView : UIViewRepresentable {
let scene = SCNScene(named: "art.scnassets/ship.scn")!
func makeUIView(context: Context) -> SCNView {
// create and add a camera to the scene
let cameraNode = SCNNode()
cameraNode.camera = SCNCamera()
scene.rootNode.addChildNode(cameraNode)
// add SwiftUI Path to Scenekit Scene
let scnpath = ContentView()
let shape = SCNShape(path: scnpath)
let shapeNode = SCNNode(geometry: shape)
// place the camera
cameraNode.position = SCNVector3(x: 0, y: 0, z: 15)
// retrieve the SCNView
let scnView = SCNView()
return scnView
}
func updateUIView(_ scnView: SCNView, context: Context) {
scnView.scene = scene
}
}
#if DEBUG
struct ScenekitView_Previews : PreviewProvider {
static var previews: some View {
ScenekitView()
.colorScheme(.dark)
.previewDevice("iPad Pro (12.9-inch) (3rd generation)")
}
}
#endif
import SwiftUI
struct ContentView: View {
var body: some View {
Path { path in
path.move(to: CGPoint(x: 63.5, y: 98.38))
path.addLine(to: CGPoint(x: 920.14, y: 0))
path.addLine(to: CGPoint(x: 1094.24, y: 584.81))
path.addLine(to: CGPoint(x: 920.14, y: 938.58))
path.addLine(to: CGPoint(x: 498.47, y: 1279.73))
path.addLine(to: CGPoint(x: 211.79, y: 938.58))
path.addLine(to: CGPoint(x: 617.65, y: 584.81))
path.addLine(to: CGPoint(x: 735.35, y: 295.94))
path.addLine(to: CGPoint(x: 332.02, y: 349.08))
path.addLine(to: CGPoint(x: 0, y: 672.25))
path.addLine(to: CGPoint(x: 63.5, y: 98.38))
}
.stroke(Color.blue, lineWidth: 3)
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
Really appreciate any help!
Cheers
Your SwiftUI ContentView is a View, which is struct, but SCNShape expected UIBezierPath which is a class. So if you want to join those different concepts, you have to do something like the following:
In ContentView
struct ContentView: View {
let path = Path { path in
path.move(to: CGPoint(x: 63.5, y: 98.38))
path.addLine(to: CGPoint(x: 920.14, y: 0))
path.addLine(to: CGPoint(x: 1094.24, y: 584.81))
path.addLine(to: CGPoint(x: 920.14, y: 938.58))
path.addLine(to: CGPoint(x: 498.47, y: 1279.73))
path.addLine(to: CGPoint(x: 211.79, y: 938.58))
path.addLine(to: CGPoint(x: 617.65, y: 584.81))
path.addLine(to: CGPoint(x: 735.35, y: 295.94))
path.addLine(to: CGPoint(x: 332.02, y: 349.08))
path.addLine(to: CGPoint(x: 0, y: 672.25))
path.addLine(to: CGPoint(x: 63.5, y: 98.38))
}
var body: some View {
self.path
.stroke(Color.blue, lineWidth: 3)
}
}
In ScenekitView
let scnpath = ContentView().path.cgPath
let shape = SCNShape(path: UIBezierPath(cgPath: scnpath), extrusionDepth: 1.0)
try this:
1) you did not add your shapenode to the scene - so you won't see it
2) in the beginning, if you are not so well experienced with scenekit, you should not control the camera yourself...let this scenekit do for you, so i deleted your camera (because it needs the right position + angle so that you can really see something
3.) update the shape to your shape like asperi told you - this is one way you can go (i did not put this in my running example, because it would be too easy for you ;))
4.) result is as it is shown in picture
5.) i don't know whether you know: in the simulator you can only see scenekitviews if you tap the "play" button in the simulator...
struct ScenekitView : UIViewRepresentable {
let scene = SCNScene()
func makeUIView(context: Context) -> SCNView {
let uiView = UIView(frame: CGRect(x: 0, y: 0, width: 300, height: 300))
// create and add a camera to the scene
let cameraNode = SCNNode()
cameraNode.camera = SCNCamera()
// scene.rootNode.addChildNode(cameraNode)
// add SwiftUI Path to Scenekit Scene
let bezierPath = UIBezierPath(ovalIn: CGRect(x: 0, y: 0, width: 20, height: 20))
let shape = SCNShape(path: bezierPath, extrusionDepth: 50)
let shapeNode = SCNNode(geometry: shape)
// place the camera
cameraNode.position = SCNVector3(x: 0, y: 10, z: 25)
// scene.rootNode.addChildNode(cameraNode)
scene.rootNode.addChildNode(shapeNode)
// retrieve the SCNView
let scnView = SCNView()
scnView.scene = scene
scnView.backgroundColor = UIColor.blue
scnView.frame = CGRect(x: 0, y: 0, width: 500, height: 500)
return scnView
}
func updateUIView(_ scnView: SCNView, context: Context) {
print("test")
}
}
if you want to make it a bittle bit "sexier" you can add specular and a light...and you get:
code here:
struct ScenekitView : UIViewRepresentable {
let scene = SCNScene()
func makeUIView(context: Context) -> SCNView {
let uiView = UIView(frame: CGRect(x: 0, y: 0, width: 300, height: 300))
// create and add a camera to the scene
let cameraNode = SCNNode()
cameraNode.camera = SCNCamera()
let bezierPath = UIBezierPath(ovalIn: CGRect(x: 0, y: 0, width: 20, height: 20))
let shape = SCNShape(path: bezierPath, extrusionDepth: 40)
let shapeNode = SCNNode(geometry: shape)
let material = SCNMaterial()
material.diffuse.contents = UIColor.red
material.specular.contents = UIColor.white
let light = SCNLight()
light.type = .spot
cameraNode.light = light
shape.materials = [material]
shapeNode.rotation = SCNVector4(0.2, 0.3, 0.1, CGFloat.pi / 2)
// place the camera
cameraNode.position = SCNVector3(x: 5, y: 16, z: 85)
scene.rootNode.addChildNode(cameraNode)
scene.rootNode.addChildNode(shapeNode)
// retrieve the SCNView
let scnView = SCNView()
scnView.scene = scene
scnView.backgroundColor = UIColor.blue
scnView.frame = CGRect(x: 0, y: 0, width: 400, height: 400)
return scnView
}
func updateUIView(_ scnView: SCNView, context: Context) {
print("test")
}
}

Resources