Système solaire

Des pivots Node3D imbriqués, chacun tournant à son rythme. Une lune orbite sa planète et hérite gratuitement de l'orbite de la planète.

L'éditeur ci-dessus fait tourner ce projet. Changez une ligne et il se recharge.

Classes Godot utilisées

Node3DMeshInstance3DOmniLight3D

Le code

scripts/main.gd
extends Node

const PLANETS: Array[Dictionary] = [
	{size = 0.45, orbit = 4.2, speed = 0.85, color = '#8da5f3', moons = 0},
	{size = 0.75, orbit = 6.6, speed = 0.55, color = '#8eef97', moons = 1},
	{size = 0.6, orbit = 9.2, speed = 0.38, color = '#fc7f7f', moons = 2},
	{size = 1.05, orbit = 12.4, speed = 0.24, color = '#f3d48d', moons = 1},
]

var pivots: Array[Node3D] = []
var speeds: Array[float] = []


func _ready() -> void:
	_add_environment()
	_add_sun()

	for i in PLANETS.size():
		_add_planet(PLANETS[i], float(i))

	var camera: Camera3D = Camera3D.new()
	camera.fov = 55.0
	camera.position = Vector3(0, 11, 23)
	add_child(camera)
	camera.look_at(Vector3.ZERO, Vector3.UP)
	camera.current = true

	print('every level is a Node3D pivot spinning at its own rate, so a moon inherits the planet orbit')


func _process(delta: float) -> void:
	for i in pivots.size():
		pivots[i].rotate_y(delta * speeds[i])


func _add_planet(data: Dictionary, index: float) -> void:
	_add_orbit_ring(data.orbit)

	var pivot: Node3D = Node3D.new()
	pivot.rotation.y = index * 1.7
	add_child(pivot)
	_track(pivot, data.speed)

	var planet: MeshInstance3D = _make_ball(data.size, data.color, 0.0)
	planet.position = Vector3(data.orbit, 0, 0)
	pivot.add_child(planet)

	for m in data.moons:
		var moon_pivot: Node3D = Node3D.new()
		moon_pivot.rotation.y = m * 2.1
		moon_pivot.rotation.z = 0.35
		planet.add_child(moon_pivot)
		_track(moon_pivot, 1.8 + m * 0.7)

		var moon: MeshInstance3D = _make_ball(data.size * 0.32, '#c8ccd8', 0.0)
		moon.position = Vector3(data.size + 0.9 + m * 0.6, 0, 0)
		moon_pivot.add_child(moon)


func _add_orbit_ring(radius: float) -> void:
	var mesh: TorusMesh = TorusMesh.new()
	mesh.inner_radius = radius - 0.03
	mesh.outer_radius = radius + 0.03
	mesh.ring_segments = 6
	mesh.rings = 96

	var material: StandardMaterial3D = StandardMaterial3D.new()
	material.albedo_color = Color(0.55, 0.62, 0.85, 0.22)
	material.shading_mode = BaseMaterial3D.SHADING_MODE_UNSHADED
	material.transparency = BaseMaterial3D.TRANSPARENCY_ALPHA

	var ring: MeshInstance3D = MeshInstance3D.new()
	ring.mesh = mesh
	ring.material_override = material
	ring.rotation_degrees = Vector3(-90, 0, 0)
	add_child(ring)


func _add_sun() -> void:
	add_child(_make_ball(1.9, '#f3d48d', 0.9))

	var light: OmniLight3D = OmniLight3D.new()
	light.light_color = Color('#ffe9bd')
	light.light_energy = 4.5
	light.omni_range = 60.0
	light.omni_attenuation = 0.6
	add_child(light)


func _make_ball(size: float, hex: String, glow: float) -> MeshInstance3D:
	var mesh: SphereMesh = SphereMesh.new()
	mesh.radius = size
	mesh.height = size * 2.0

	var material: StandardMaterial3D = StandardMaterial3D.new()
	material.albedo_color = Color(hex)
	material.roughness = 0.7

	if glow > 0.0:
		material.emission_enabled = true
		material.emission = Color(hex)
		material.emission_energy_multiplier = glow

	var ball: MeshInstance3D = MeshInstance3D.new()
	ball.mesh = mesh
	ball.material_override = material

	return ball


func _track(pivot: Node3D, speed: float) -> void:
	pivots.append(pivot)
	speeds.append(speed)


func _add_environment() -> void:
	var env: Environment = Environment.new()
	env.background_mode = Environment.BG_COLOR
	env.background_color = Color(0.012, 0.014, 0.035)
	# a near black background gives no usable ambient, so the night sides need a fill color instead
	env.ambient_light_source = Environment.AMBIENT_SOURCE_COLOR
	env.ambient_light_color = Color(0.42, 0.48, 0.7)
	env.ambient_light_energy = 0.55
	env.tonemap_mode = Environment.TONE_MAPPER_FILMIC
	env.glow_enabled = true
	env.glow_intensity = 0.35
	env.glow_bloom = 0.1

	var world: WorldEnvironment = WorldEnvironment.new()
	world.environment = env
	add_child(world)

Plus d'exemples de Scène 3D