I am doing the Swift Landmarks app tutorial on Xcode 13.2.1 on my 2019 Macbook Pro. I am up to the Working with UI Controls section. Every time I add the following lines of code to ProfileSummary.swift:
@EnvironmentObject var modelData: ModelData
.
.
.
Divider()
VStack(alignment: .leading)
{
Text("Recent Hikes")
.font(.headline)
HikeView(hike: modelData.hikes[0])
}
and I then try to view the preview I repeatedly get a crash report and everything stops working. When I remove those lines of code everything goes back to working fine.
The crash report is in this attachment:
Translated Crash Report
^ That is the translated report. If you guys would like the full report I will post it. I am stuck and don't know what to do any help will be appreciated!
In the fps im making, I am now working on mapping the levels. I have already made the walls and provided texture on them, and now I'm doing the same to the floor. I am able to code a red floor, however whenever I try to code texture on it I get the following error:
"Thread 1: Swift runtime failure: Unexpectedly found nil while unwrapping an Optional value"
The code appears at this line in ViewController.swift
return Textures(loader: { name in Bitmap(image: UIImage(named: name)!)!})
Here's the full code for ViewController.swift:
import Engine
private let joystickRadius: Double = 40
private let maximumTimeStep: Double = 1 / 20
private let worldTimeStep: Double = 1 / 120
private func loadTextures() -> Textures
{
return Textures(loader: { name in Bitmap(image: UIImage(named: name)!)!})
}
private func loadMap() -> Tilemap {
let jsonURL = Bundle.main.url(forResource: "Map", withExtension: "json")!
let jsonData = try! Data(contentsOf: jsonURL)
return try! JSONDecoder().decode(Tilemap.self, from: jsonData)
}
class ViewController: UIViewController {
private let imageView = UIImageView()
private let panGesture = UIPanGestureRecognizer()
private var world = World(map: loadMap())
private var lastFrameTime = CACurrentMediaTime()
private let textures = loadTextures()
override func viewDidLoad() {
super.viewDidLoad()
setUpImageView()
let displayLink = CADisplayLink(target: self, selector: #selector(update))
displayLink.add(to: .main, forMode: .common)
view.addGestureRecognizer(panGesture)
}
private var inputVector: Vector {
switch panGesture.state {
case .began, .changed:
let translation = panGesture.translation(in: view)
var vector = Vector(x: Double(translation.x), y: Double(translation.y))
vector /= max(joystickRadius, vector.length)
panGesture.setTranslation(CGPoint(
x: vector.x * joystickRadius,
y: vector.y * joystickRadius
), in: view)
return vector
default:
return Vector(x: 0, y: 0)
}
}
@objc func update(_ displayLink: CADisplayLink) {
let timeStep = min(maximumTimeStep, displayLink.timestamp - lastFrameTime)
let inputVector = self.inputVector
let rotation = inputVector.x * world.player.turningSpeed * worldTimeStep
let input = Input(speed: -inputVector.y, rotation: Rotation(sine: sin(rotation), cosine: cos(rotation)))
let worldSteps = (timeStep / worldTimeStep).rounded(.up)
for _ in 0 ..< Int(worldSteps) {
world.update(timeStep: timeStep / worldSteps, input: input)
}
lastFrameTime = displayLink.timestamp
let width = Int(imageView.bounds.width), height = Int(imageView.bounds.height)
var renderer = Renderer(width: width, height: height, textures: textures)
renderer.draw(world)
imageView.image = UIImage(bitmap: renderer.bitmap)
}
func setUpImageView() {
view.addSubview(imageView)
imageView.translatesAutoresizingMaskIntoConstraints = false
imageView.topAnchor.constraint(equalTo: view.topAnchor).isActive = true
imageView.leadingAnchor.constraint(equalTo: view.leadingAnchor).isActive = true
imageView.widthAnchor.constraint(equalTo: view.widthAnchor).isActive = true
imageView.heightAnchor.constraint(equalTo: view.heightAnchor).isActive = true
imageView.contentMode = .scaleAspectFit
imageView.backgroundColor = .black
imageView.layer.magnificationFilter = .nearest
}
}
Here's the code for other files that deal with the texturing of the floor and the level in general:
Textures.swift
{
case wall, wall2
case floor, ceiling
}
public struct Textures
{
private let textures: [Texture: Bitmap]
}
public extension Textures
{
init(loader: (String) -> Bitmap)
{
var textures = [Texture: Bitmap]()
for texture in Texture.allCases
{
textures[texture] = loader(texture.rawValue)
}
self.init(textures: textures)
}
subscript(_ texture: Texture) -> Bitmap
{
return textures[texture]!
}
}
Renderer.swift:
public private(set) var bitmap: Bitmap
private let textures: Textures
public init(width: Int, height: Int, textures: Textures) {
self.bitmap = Bitmap(width: width, height: height, color: .black)
self.textures = textures
}
}
public extension Renderer {
mutating func draw(_ world: World) {
let focalLength = 1.0
let viewWidth = Double(bitmap.width) / Double(bitmap.height)
let viewPlane = world.player.direction.orthogonal * viewWidth
let viewCenter = world.player.position + world.player.direction * focalLength
let viewStart = viewCenter - viewPlane / 2
// Cast rays
let columns = bitmap.width
let step = viewPlane / Double(columns)
var columnPosition = viewStart
for x in 0 ..< columns {
let rayDirection = columnPosition - world.player.position
let viewPlaneDistance = rayDirection.length
let ray = Ray(
origin: world.player.position,
direction: rayDirection / viewPlaneDistance
)
let end = world.map.hitTest(ray)
let wallDistance = (end - ray.origin).length
// Draw wall
let wallHeight = 1.0
let distanceRatio = viewPlaneDistance / focalLength
let perpendicular = wallDistance / distanceRatio
let height = wallHeight * focalLength / perpendicular * Double(bitmap.height)
let wallTexture: Bitmap
let wallX: Double
if end.x.rounded(.down) == end.x
{
wallTexture = textures[.wall]
wallX = end.y - end.y.rounded(.down)
}
else
{
wallTexture = textures[.wall2]
wallX = end.x - end.x.rounded(.down)
}
let textureX = Int(wallX * Double(wallTexture.width))
let wallStart = Vector(x: Double(x), y: (Double(bitmap.height) - height) / 2 - 0.001)
bitmap.drawColumn(textureX, of: wallTexture, at: wallStart, height: height)
// Draw floor
let floorTexture = textures[.floor]
let floorStart = Int(wallStart.y + height) + 1
for y in min(floorStart, bitmap.height) ..< bitmap.height {
let normalizedY = (Double(y) / Double(bitmap.height)) * 2 - 1
let perpendicular = wallHeight * focalLength / normalizedY
let distance = perpendicular * distanceRatio
let mapPosition = ray.origin + ray.direction * distance
let tileX = mapPosition.x.rounded(.down), tileY = mapPosition.y.rounded(.down)
let textureX = Int((mapPosition.x - tileX) * Double(floorTexture.width))
let textureY = Int((mapPosition.y - tileY) * Double(floorTexture.height))
bitmap[x, y] = floorTexture[textureX, textureY]
}
columnPosition += step
}
}
}
The rest of the code can be found in the link below:
https://github.com/KingDecorpel12/RampageFPS/tree/main/RetroRampage/Source
Any and all help will be greatly appreciated!
In the fps I'm making, I am making a 2D maze for the avatar to navigate in. I just finished coding it however whenever I compile it the app instantly crashes.
The error that makes it crash is the following "Thread 1: Swift runtime failure: Range requires lowerBound <= upperBound"
and occurs in this file
Bitmap.swift
import UIKit
public struct Bitmap
{
public private(set) var pixels: [Color]
public let width: Int
public init(width: Int, pixels: [Color], height: Int)
{
self.width = width
self.pixels = pixels
}
}
public extension Bitmap
{
var height: Int
{
let bitmapheight = pixels.count / width
return bitmapheight
}
subscript(x: Int, y: Int) -> Color
{
get { return pixels[y * width + x] }
set {
guard x >= 0, y >= 0, x < width, y < height else {
return
}
pixels[y * width + x] = newValue}
}
init(width: Int, height: Int, color: Color) {
self.pixels = Array(repeating: color, count: width * height)
self.width = width
}
mutating func fill(rect: Rect, color: Color)
{
for y in Int(rect.min.y) ..< Int(rect.max.y)
{
for x in Int(rect.min.x) ..< Int(rect.max.x)
{
self[x, y] = color
}
}
}
}
at the line
for x in Int(rect.min.x) ..< Int(rect.max.x)
When I put a breakout on the line and run the code I see the following when the compiler runs the line:
min Engine.Vector x = (Double) 51.75 y = (Double) 0 max Engine.Vector x = (Double) 2 y = (Double) 51.75
I also get this at the terminal:
Engine was compiled with optimization - stepping may behave oddly; variables may not be available.
Since it's a big project and there's multiple files calling from one another in both the main game files and the game engine files, you can find the rest of the source code in the link below:
https://github.com/KingDecorpel12/RampageFPS
Game Engine files, including Bitmap.swift, will be in Rampage/Source/Engine while the main game files will be in Rampage/Source/Rampage.
Any and all help will be greatly appreciated!.
I am coding a basic fps app on Xcode 12.5. As of right now, Im working on a file that acts as a bridge between UIKit and the game engine used for this game.
The code is provided below:
Bitmap.swift
import UIKit
public struct Bitmap
{
public private(set) var pixels: [Color]
public let width: Int
public init(width: Int, pixels: [Color])
{
self.width = width
self.pixels = pixels
}
}
public extension Bitmap
{
var height: Int
{
return pixels.count / width
}
subscript(x: Int, y: Int) -> Color
{
get { return pixels[y * width + x] }
set { pixels[y * width + x] = newValue}
}
init(width: Int, height: Int, color: Color) {
self.pixels = Array(repeating: color, count: width * height)
self.width = width
}
}
UIImage+Bitmap.swift
import UIKit
import Engine
extension UIImage {
convenience init?(bitmap: Bitmap) {
let alphaInfo = CGImageAlphaInfo.premultipliedLast
let bytesPerPixel = MemoryLayout<Color>.size
let bytesPerRow = bitmap.width * bytesPerPixel
guard let providerRef = CGDataProvider(data: Data(
bytes: bitmap.pixels, count: bitmap.height * bytesPerRow
) as CFData) else {
return nil
}
guard let cgImage = CGImage(
width: bitmap.width,
height: bitmap.height,
bitsPerComponent: 8,
bitsPerPixel: bytesPerPixel * 8,
bytesPerRow: bytesPerRow,
space: CGColorSpaceCreateDeviceRGB(),
bitmapInfo: CGBitmapInfo(rawValue: alphaInfo.rawValue),
provider: providerRef,
decode: nil,
shouldInterpolate: true,
intent: .defaultIntent
) else {
return nil
}
self.init(bitmap: cgImage)
}
}
For my UIImage+Bitmap.swift code I get the following error:
"'height' is inaccessible due to 'internal' protection level"
Any help will be appreciated!
Post not yet marked as solved
I'm working on a simple anime app project where you can view a list of the top anime, search for any anime, add them to either a watched, to watch or watching section as well view the info (such as synopsis for example) when clicking on an anime. For the most part, everything works except for viewing the anime info from the search results, an example being not able to view the info of Naruto when clicking on it in search results. My code is in the attachment below.
Continued