Generates a Godot scene from Node
This commit is contained in:
@@ -0,0 +1,228 @@
|
||||
//
|
||||
// World.swift
|
||||
// Logic
|
||||
//
|
||||
// Created by Alex Loren on 8/26/26.
|
||||
//
|
||||
|
||||
import SwiftGodot
|
||||
|
||||
@Godot
|
||||
class World: Node {
|
||||
// MARK: - Properties
|
||||
private var lightColors: [String] = [
|
||||
"#95FDDE",
|
||||
"#8029F8",
|
||||
"#ED4881"
|
||||
]
|
||||
|
||||
private var randomLightColor: Color {
|
||||
get {
|
||||
if let color = lightColors.randomElement(), Color.htmlIsValid(color: color) {
|
||||
return Color.html(rgba: color)
|
||||
}
|
||||
print("Failed to get random light color, returning white.")
|
||||
return .white
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Functions
|
||||
override func _enterTree() {
|
||||
assemble()
|
||||
}
|
||||
|
||||
func assemble() {
|
||||
let camera = createCamera(at: Vector3(x: 0, y: -1.75, z: 4.5))
|
||||
camera.environment = createEnvironment()
|
||||
addChild(node: camera)
|
||||
addChild(node: createRotatingWalls())
|
||||
addChild(node: createPhysicsBounds())
|
||||
|
||||
for _ in 1...200 {
|
||||
let sphere = createSphereRigidBody()
|
||||
addChild(node: sphere)
|
||||
sphere.globalPosition = getRandomPosition()
|
||||
}
|
||||
|
||||
for _ in 1...100 {
|
||||
let box = createBoxRigidBody(size: 0.2)
|
||||
addChild(node: box)
|
||||
box.globalPosition = getRandomPosition()
|
||||
}
|
||||
|
||||
for index in 0...2 {
|
||||
let rotator = createNodeRotator()
|
||||
let light = createLight(range: 15, color: Color.html(rgba: lightColors[index]))
|
||||
rotator.addChild(node: light)
|
||||
light.position = getRandomPosition(lower: 3, upper: 4)
|
||||
addChild(node: rotator)
|
||||
}
|
||||
}
|
||||
|
||||
@discardableResult private func createCamera(at position: Vector3 = Vector3(x: 0, y: 0, z: 5)) -> Camera3D {
|
||||
let camera = Camera3D()
|
||||
camera.current = true
|
||||
camera.position = position
|
||||
return camera
|
||||
}
|
||||
|
||||
@discardableResult private func createRotatingWalls() -> Node3D {
|
||||
let rotator = PhysicsRotator()
|
||||
rotator.axis = Vector3(x: 1, y: 1, z: 1)
|
||||
rotator.speed = 0.5
|
||||
|
||||
// Top and bottom walls
|
||||
rotator.addChild(node: createCollidableWall(at: Vector3(x: 0, y: 2.5, z: 0)))
|
||||
rotator.addChild(node: createCollidableWall(at: Vector3(x: 0, y: -2.5, z: 0)))
|
||||
// Front and back walls
|
||||
rotator.addChild(node: createCollidableWall(at: Vector3(x: 2.5, y: 0, z: 0), rotation: Vector3(x: 0, y: 0, z: 90)))
|
||||
rotator.addChild(node: createCollidableWall(at: Vector3(x: -2.5, y: 0, z: 0), rotation: Vector3(x: 0, y: 0, z: 90)))
|
||||
// Left and right walls
|
||||
rotator.addChild(node: createCollidableWall(at: Vector3(x: 0, y: 0, z: 2.5), rotation: Vector3(x: 0, y: 90, z: 90)))
|
||||
rotator.addChild(node: createCollidableWall(at: Vector3(x: 0, y: 0, z: -2.5), rotation: Vector3(x: 0, y: 90, z: 90)))
|
||||
|
||||
return rotator
|
||||
}
|
||||
|
||||
@discardableResult private func createCollidableWall(at position: Vector3, rotation: Vector3 = .zero) -> CollisionShape3D {
|
||||
let shape = BoxShape3D()
|
||||
shape.size = Vector3(x: 5, y: 0.5, z: 5)
|
||||
let collider = CollisionShape3D()
|
||||
collider.shape = shape
|
||||
collider.position = position
|
||||
collider.rotationDegrees = rotation
|
||||
return collider
|
||||
}
|
||||
|
||||
@discardableResult private func createSphereRigidBody(radius: Double = 0.1, randomize: Bool = true, randomScale: Double = 0.05) -> RigidBody3D {
|
||||
let definedRadius = !randomize ? radius : Double.random(in: (radius - randomScale)...(radius + randomScale))
|
||||
let shape = SphereShape3D()
|
||||
shape.radius = definedRadius
|
||||
let collider = CollisionShape3D()
|
||||
collider.shape = shape
|
||||
|
||||
let mesh = SphereMesh()
|
||||
mesh.radius = definedRadius
|
||||
mesh.height = definedRadius * 2
|
||||
mesh.radialSegments = 8
|
||||
mesh.rings = 8
|
||||
let meshInstance = MeshInstance3D()
|
||||
meshInstance.mesh = mesh
|
||||
meshInstance.materialOverride = createMaterial()
|
||||
|
||||
let material = PhysicsMaterial()
|
||||
material.bounce = 0.8
|
||||
|
||||
let body = RigidBody3D()
|
||||
body.physicsMaterialOverride = material
|
||||
body.addChild(node: collider)
|
||||
body.addChild(node: meshInstance)
|
||||
return body
|
||||
}
|
||||
|
||||
@discardableResult private func createBoxRigidBody(size: Float = 0.1, randomize: Bool = true, randomScale: Float = 0.05) -> RigidBody3D {
|
||||
let definedSize = !randomize ? size : Float.random(in: (size - randomScale)...(size + randomScale))
|
||||
let shape = BoxShape3D()
|
||||
shape.size = Vector3(x: definedSize, y: definedSize, z: definedSize)
|
||||
let collider = CollisionShape3D()
|
||||
collider.shape = shape
|
||||
|
||||
let mesh = BoxMesh()
|
||||
mesh.size = Vector3(x: definedSize, y: definedSize, z: definedSize)
|
||||
let meshInstance = MeshInstance3D()
|
||||
meshInstance.mesh = mesh
|
||||
meshInstance.materialOverride = createMaterial()
|
||||
|
||||
let material = PhysicsMaterial()
|
||||
material.bounce = 0.8
|
||||
|
||||
let body = RigidBody3D()
|
||||
body.physicsMaterialOverride = material
|
||||
body.addChild(node: collider)
|
||||
body.addChild(node: meshInstance)
|
||||
return body
|
||||
}
|
||||
|
||||
@discardableResult private func createLight(range: Double = 5, color: Color = .white) -> OmniLight3D {
|
||||
let light = OmniLight3D()
|
||||
light.omniRange = range
|
||||
light.omniShadowMode = .cube
|
||||
light.shadowEnabled = true
|
||||
light.lightColor = color
|
||||
light.lightEnergy = 5
|
||||
return light
|
||||
}
|
||||
|
||||
@discardableResult private func createNodeRotator() -> NodeRotator {
|
||||
let randomOnAxis: [Float] = [
|
||||
Float(Int.random(in: -1...1)),
|
||||
Float(Int.random(in: -1...1)),
|
||||
Float(Int.random(in: -1...1))
|
||||
]
|
||||
|
||||
let rotator = NodeRotator()
|
||||
rotator.axis = Vector3(x: randomOnAxis[0], y: randomOnAxis[1], z: randomOnAxis[2])
|
||||
rotator.speed = Double.random(in: 0.3...0.6)
|
||||
return rotator
|
||||
}
|
||||
|
||||
private func createMaterial() -> StandardMaterial3D {
|
||||
let material = StandardMaterial3D()
|
||||
material.diffuseMode = .lambertWrap
|
||||
return material
|
||||
}
|
||||
|
||||
@discardableResult private func createEnvironment() -> Environment {
|
||||
let environment = Environment()
|
||||
environment.backgroundMode = .color
|
||||
environment.backgroundColor = .black
|
||||
environment.glowEnabled = true
|
||||
environment.glowIntensity = 0.6
|
||||
environment.glowStrength = 1.75
|
||||
return environment
|
||||
}
|
||||
|
||||
private func createPhysicsBounds() -> Area3D {
|
||||
let shape = SphereShape3D()
|
||||
shape.radius = 10
|
||||
let collider = CollisionShape3D()
|
||||
collider.shape = shape
|
||||
let area = Area3D()
|
||||
area.addChild(node: collider)
|
||||
|
||||
area.bodyExited.connect { [weak self] body in
|
||||
guard let self, let body = body as? RigidBody3D else {
|
||||
return
|
||||
}
|
||||
|
||||
body.getChildren().forEach { child in
|
||||
if let collider = child as? CollisionShape3D {
|
||||
switch collider.shape {
|
||||
case is SphereShape3D:
|
||||
let sphere = self.createSphereRigidBody()
|
||||
addChild(node: sphere)
|
||||
sphere.globalPosition = self.getRandomPosition()
|
||||
break
|
||||
case is BoxShape3D:
|
||||
let box = self.createBoxRigidBody()
|
||||
addChild(node: box)
|
||||
box.globalPosition = self.getRandomPosition()
|
||||
default:
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
body.queueFree()
|
||||
}
|
||||
|
||||
return area
|
||||
}
|
||||
|
||||
private func getRandomPosition(in range: Float = 2) -> Vector3 {
|
||||
return .init(x: Float.random(in: -range...range), y: Float.random(in: -range...range), z: Float.random(in: -range...range))
|
||||
}
|
||||
|
||||
private func getRandomPosition(lower: Float = 1, upper: Float = 3) -> Vector3{
|
||||
return .init(x: .random(in: lower...upper), y: .random(in: lower...upper), z: .random(in: lower...upper))
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user