Added dynamic spawning and despawning of objects
This commit is contained in:
parent
adbb208436
commit
e0cf8d9755
23 changed files with 794 additions and 350 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
|
@ -2,6 +2,7 @@
|
||||||
# Godot 4+ specific ignores
|
# Godot 4+ specific ignores
|
||||||
.godot/
|
.godot/
|
||||||
/android/
|
/android/
|
||||||
|
build
|
||||||
|
|
||||||
# Godot-specific ignores
|
# Godot-specific ignores
|
||||||
.import/
|
.import/
|
||||||
|
|
|
||||||
6
prefabs/gameObjects/node.tscn
Normal file
6
prefabs/gameObjects/node.tscn
Normal file
|
|
@ -0,0 +1,6 @@
|
||||||
|
[gd_scene format=3 uid="uid://b6c17xutiecq5"]
|
||||||
|
|
||||||
|
[ext_resource type="Script" uid="uid://dknsws58ej0bp" path="res://scripts/GameObject.cs" id="1_gt1sn"]
|
||||||
|
|
||||||
|
[node name="Node" type="StaticBody3D" unique_id=1306600716]
|
||||||
|
script = ExtResource("1_gt1sn")
|
||||||
31
prefabs/gameObjects/player.tscn
Normal file
31
prefabs/gameObjects/player.tscn
Normal file
|
|
@ -0,0 +1,31 @@
|
||||||
|
[gd_scene format=3 uid="uid://tlc6h5arfa6p"]
|
||||||
|
|
||||||
|
[ext_resource type="Script" uid="uid://cue3c56axvyja" path="res://scripts/Player.cs" id="1_74mkb"]
|
||||||
|
[ext_resource type="Script" uid="uid://bwpdtkgmwjs7g" path="res://scripts/GravityReceiver.cs" id="2_y1ton"]
|
||||||
|
|
||||||
|
[sub_resource type="CapsuleMesh" id="CapsuleMesh_8cj0n"]
|
||||||
|
|
||||||
|
[sub_resource type="CapsuleShape3D" id="CapsuleShape3D_uwrxv"]
|
||||||
|
|
||||||
|
[node name="Player" type="CharacterBody3D" unique_id=1391068938]
|
||||||
|
script = ExtResource("1_74mkb")
|
||||||
|
SprintMultiplier = 500.0
|
||||||
|
|
||||||
|
[node name="Camera" type="Camera3D" parent="." unique_id=1639995310]
|
||||||
|
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.6, 0)
|
||||||
|
fov = 90.0
|
||||||
|
|
||||||
|
[node name="PlayerMesh" type="MeshInstance3D" parent="." unique_id=1449639248]
|
||||||
|
mesh = SubResource("CapsuleMesh_8cj0n")
|
||||||
|
|
||||||
|
[node name="PlayerCollider" type="CollisionShape3D" parent="." unique_id=944580540]
|
||||||
|
shape = SubResource("CapsuleShape3D_uwrxv")
|
||||||
|
|
||||||
|
[node name="GravityReceiver" type="Node3D" parent="." unique_id=2127509723]
|
||||||
|
script = ExtResource("2_y1ton")
|
||||||
|
|
||||||
|
[node name="SpotLight3D" type="SpotLight3D" parent="." unique_id=1804770241]
|
||||||
|
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.06334634196567002, -0.29036251889898157)
|
||||||
|
shadow_enabled = true
|
||||||
|
spot_range = 25.0
|
||||||
|
spot_angle = 90.0
|
||||||
|
|
@ -66,6 +66,11 @@ rotate_right={
|
||||||
"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":69,"key_label":0,"unicode":101,"location":0,"echo":false,"script":null)
|
"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":69,"key_label":0,"unicode":101,"location":0,"echo":false,"script":null)
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
sprint={
|
||||||
|
"deadzone": 0.2,
|
||||||
|
"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":4194325,"key_label":0,"unicode":0,"location":0,"echo":false,"script":null)
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
[physics]
|
[physics]
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,7 @@
|
||||||
[gd_scene format=3 uid="uid://b3yh6h7fdt160"]
|
[gd_scene format=3 uid="uid://b3yh6h7fdt160"]
|
||||||
|
|
||||||
[ext_resource type="Script" uid="uid://cue3c56axvyja" path="res://scripts/Player.cs" id="1_uwrxv"]
|
|
||||||
[ext_resource type="Script" uid="uid://cy8nuarxbnd" path="res://scripts/GravityZone.cs" id="1_yqjtg"]
|
[ext_resource type="Script" uid="uid://cy8nuarxbnd" path="res://scripts/GravityZone.cs" id="1_yqjtg"]
|
||||||
[ext_resource type="Script" uid="uid://bwpdtkgmwjs7g" path="res://scripts/GravityReceiver.cs" id="3_lnu2h"]
|
[ext_resource type="Script" uid="uid://dr6y711ano07p" path="res://scripts/QueueManager.cs" id="4_iywne"]
|
||||||
[ext_resource type="Script" uid="uid://n557xfrv0i6x" path="res://scripts/GameControlManager.cs" id="4_lbhrr"]
|
[ext_resource type="Script" uid="uid://n557xfrv0i6x" path="res://scripts/GameControlManager.cs" id="4_lbhrr"]
|
||||||
[ext_resource type="Script" uid="uid://bwgjvm21oi3d6" path="res://scripts/GameManager.cs" id="4_p57ef"]
|
[ext_resource type="Script" uid="uid://bwgjvm21oi3d6" path="res://scripts/GameManager.cs" id="4_p57ef"]
|
||||||
[ext_resource type="Script" uid="uid://betypbypf6bf2" path="res://scripts/GameMenuController.cs" id="5_iywne"]
|
[ext_resource type="Script" uid="uid://betypbypf6bf2" path="res://scripts/GameMenuController.cs" id="5_iywne"]
|
||||||
|
|
@ -16,14 +15,14 @@ size = Vector3(10, 0.5, 10)
|
||||||
[sub_resource type="BoxShape3D" id="BoxShape3D_uwrxv"]
|
[sub_resource type="BoxShape3D" id="BoxShape3D_uwrxv"]
|
||||||
size = Vector3(10, 5, 10)
|
size = Vector3(10, 5, 10)
|
||||||
|
|
||||||
[sub_resource type="CapsuleMesh" id="CapsuleMesh_8cj0n"]
|
[node name="Game" type="Node3D" unique_id=1201210338 node_paths=PackedStringArray("GameMenu", "QueueManager")]
|
||||||
|
script = ExtResource("4_p57ef")
|
||||||
[sub_resource type="CapsuleShape3D" id="CapsuleShape3D_uwrxv"]
|
GameMenu = NodePath("GameMenu")
|
||||||
|
QueueManager = NodePath("QueueManager")
|
||||||
[node name="Game" type="Node3D" unique_id=1201210338]
|
closeTickInterval = 0.01
|
||||||
|
|
||||||
[node name="Plane" type="StaticBody3D" parent="." unique_id=1260154250]
|
[node name="Plane" type="StaticBody3D" parent="." unique_id=1260154250]
|
||||||
transform = Transform3D(1, 0, 0, 0, 0.99999994, 0, 0, 0, 0.99999994, 20, 0, 0)
|
transform = Transform3D(1, 0, 0, 0, 0.99999994, 0, 0, 0, 0.99999994, 0, -10, 0)
|
||||||
|
|
||||||
[node name="PlaneMesh" type="MeshInstance3D" parent="Plane" unique_id=107049489]
|
[node name="PlaneMesh" type="MeshInstance3D" parent="Plane" unique_id=107049489]
|
||||||
transform = Transform3D(5, 0, 0, 0, 1, 0, 0, 0, 5, 0, 0, 0)
|
transform = Transform3D(5, 0, 0, 0, 1, 0, 0, 0, 5, 0, 0, 0)
|
||||||
|
|
@ -41,37 +40,13 @@ script = ExtResource("1_yqjtg")
|
||||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 2.5, 0)
|
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 2.5, 0)
|
||||||
shape = SubResource("BoxShape3D_uwrxv")
|
shape = SubResource("BoxShape3D_uwrxv")
|
||||||
|
|
||||||
[node name="Player" type="CharacterBody3D" parent="." unique_id=612572257 node_paths=PackedStringArray("GameMenu")]
|
|
||||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 8.823173, 0.7854848)
|
|
||||||
script = ExtResource("1_uwrxv")
|
|
||||||
GameMenu = NodePath("../GameMenu")
|
|
||||||
|
|
||||||
[node name="Camera" type="Camera3D" parent="Player" unique_id=1097983892]
|
|
||||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.6, 0)
|
|
||||||
fov = 90.0
|
|
||||||
|
|
||||||
[node name="PlayerMesh" type="MeshInstance3D" parent="Player" unique_id=1440613415]
|
|
||||||
mesh = SubResource("CapsuleMesh_8cj0n")
|
|
||||||
|
|
||||||
[node name="PlayerCollider" type="CollisionShape3D" parent="Player" unique_id=886478863]
|
|
||||||
shape = SubResource("CapsuleShape3D_uwrxv")
|
|
||||||
|
|
||||||
[node name="GravityReceiver" type="Node3D" parent="Player" unique_id=1963556576]
|
|
||||||
script = ExtResource("3_lnu2h")
|
|
||||||
|
|
||||||
[node name="OmniLight" type="OmniLight3D" parent="." unique_id=1887866205]
|
|
||||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1.6497431, -4.41529)
|
|
||||||
omni_range = 500.0
|
|
||||||
omni_attenuation = 0.1
|
|
||||||
|
|
||||||
[node name="GameManager" type="Node" parent="." unique_id=267630256 node_paths=PackedStringArray("player")]
|
|
||||||
script = ExtResource("4_p57ef")
|
|
||||||
player = NodePath("../Player")
|
|
||||||
|
|
||||||
[node name="GameControlManager" type="Node" parent="." unique_id=1751385863 node_paths=PackedStringArray("GameMenu")]
|
[node name="GameControlManager" type="Node" parent="." unique_id=1751385863 node_paths=PackedStringArray("GameMenu")]
|
||||||
script = ExtResource("4_lbhrr")
|
script = ExtResource("4_lbhrr")
|
||||||
GameMenu = NodePath("../GameMenu")
|
GameMenu = NodePath("../GameMenu")
|
||||||
|
|
||||||
|
[node name="QueueManager" type="Node" parent="." unique_id=355148200]
|
||||||
|
script = ExtResource("4_iywne")
|
||||||
|
|
||||||
[node name="GameMenu" type="Control" parent="." unique_id=223510406]
|
[node name="GameMenu" type="Control" parent="." unique_id=223510406]
|
||||||
visible = false
|
visible = false
|
||||||
layout_mode = 3
|
layout_mode = 3
|
||||||
|
|
@ -102,6 +77,8 @@ offset_bottom = 63.0
|
||||||
layout_mode = 2
|
layout_mode = 2
|
||||||
text = "Main Menu"
|
text = "Main Menu"
|
||||||
|
|
||||||
|
[node name="DirectionalLight3D" type="DirectionalLight3D" parent="." unique_id=226559047]
|
||||||
|
|
||||||
[connection signal="body_entered" from="Plane/GravityZone" to="Plane/GravityZone" method="OnBodyEntered"]
|
[connection signal="body_entered" from="Plane/GravityZone" to="Plane/GravityZone" method="OnBodyEntered"]
|
||||||
[connection signal="body_exited" from="Plane/GravityZone" to="Plane/GravityZone" method="OnBodyExited"]
|
[connection signal="body_exited" from="Plane/GravityZone" to="Plane/GravityZone" method="OnBodyExited"]
|
||||||
[connection signal="pressed" from="GameMenu/VBoxContainer/MainMenuButton" to="GameMenu" method="OnMainMenu"]
|
[connection signal="pressed" from="GameMenu/VBoxContainer/MainMenuButton" to="GameMenu" method="OnMainMenu"]
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,8 @@ public class FastUniqueList<T>
|
||||||
|
|
||||||
public T this[int index] => list[index];
|
public T this[int index] => list[index];
|
||||||
|
|
||||||
|
public IEnumerator<T> GetEnumerator() => list.GetEnumerator();
|
||||||
|
|
||||||
public bool Contains(T item)
|
public bool Contains(T item)
|
||||||
{
|
{
|
||||||
return set.Contains(item);
|
return set.Contains(item);
|
||||||
|
|
|
||||||
|
|
@ -1,148 +1,246 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Concurrent;
|
||||||
|
using System.Collections.Generic;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Godot;
|
using Godot;
|
||||||
|
|
||||||
public partial class GameManager : Node
|
public partial class GameManager : Node3D
|
||||||
{
|
{
|
||||||
[Export] Player player;
|
[Export] public Control GameMenu { get; private set; }
|
||||||
|
[Export] public QueueManager QueueManager { get; private set; }
|
||||||
|
|
||||||
[Export] double closeTickInterval = 1;
|
[Export] public double closeTickInterval = 1;
|
||||||
[Export] double farTickInterval = 10;
|
[Export] public double farTickInterval = 10;
|
||||||
[Export] int maxFarThreads = 16;
|
[Export] public int maxFarThreads = 16;
|
||||||
|
|
||||||
public static GameManager Singleton { get; private set; }
|
public Player MainPlayer { get; private set; }
|
||||||
public IGenerator Generator { get; private set; }
|
|
||||||
|
|
||||||
public Universe GameUniverse { get; private set; }
|
public static GameManager Singleton { get; private set; }
|
||||||
public Sector CurrentSector { get; private set; }
|
public IGenerator Generator { get; private set; }
|
||||||
|
|
||||||
private double closeTickTimer = 0;
|
public Universe GameUniverse { get; private set; }
|
||||||
private double farTickTimer = 0;
|
|
||||||
|
|
||||||
public override void _Ready()
|
private double closeTickTimer = 0;
|
||||||
{
|
private double farTickTimer = 0;
|
||||||
Singleton = this;
|
|
||||||
|
|
||||||
Generator = new TestGenerator();
|
public bool simulating = false;
|
||||||
Generator.GenerateUniverse((universe) =>
|
|
||||||
{
|
|
||||||
GameUniverse = universe;
|
|
||||||
CurrentSector = universe.Sectors[1, 1, 1];
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void _Process(double delta)
|
private readonly Dictionary<GameObject, Node3D> spawnedObjects = [];
|
||||||
{
|
private readonly ConcurrentQueue<GameObject> spawnQueue = [];
|
||||||
closeTickTimer += delta;
|
|
||||||
farTickTimer += delta;
|
|
||||||
|
|
||||||
if (closeTickTimer >= closeTickInterval)
|
public override void _Ready()
|
||||||
{
|
{
|
||||||
SimulateClose(closeTickTimer);
|
Singleton = this;
|
||||||
closeTickTimer = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (farTickTimer >= farTickInterval)
|
Generator = new TestGenerator();
|
||||||
{
|
GameUniverse = Generator.GenerateUniverse();
|
||||||
SimulateFar(farTickTimer);
|
|
||||||
farTickTimer = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void SimulateClose(double delta)
|
Character character = new(GameUniverse.Sectors[50, 50, 50], new(0, 0, 0));
|
||||||
{
|
MainPlayer = character.InstantiatePlayer();
|
||||||
Vector3I currentCoordinates = CurrentSector.Coordinates;
|
MainPlayer.GameMenu = GameMenu;
|
||||||
|
spawnedObjects.Add(character, MainPlayer);
|
||||||
|
CallDeferred("add_child", MainPlayer);
|
||||||
|
|
||||||
Sector[,,] sectors = GameUniverse.Sectors;
|
SpawnClose();
|
||||||
|
}
|
||||||
|
|
||||||
int sizeX = sectors.GetLength(0);
|
public override void _Process(double delta)
|
||||||
int sizeY = sectors.GetLength(1);
|
{
|
||||||
int sizeZ = sectors.GetLength(2);
|
closeTickTimer += delta;
|
||||||
|
farTickTimer += delta;
|
||||||
|
|
||||||
int startX = Mathf.Clamp(currentCoordinates.X - 1, 0, sizeX);
|
if (closeTickTimer >= closeTickInterval)
|
||||||
int startY = Mathf.Clamp(currentCoordinates.Y - 1, 0, sizeY);
|
{
|
||||||
int startZ = Mathf.Clamp(currentCoordinates.Z - 1, 0, sizeZ);
|
SimulateClose(closeTickTimer);
|
||||||
|
closeTickTimer = 0;
|
||||||
|
}
|
||||||
|
|
||||||
int endX = Mathf.Clamp(currentCoordinates.X + 1, 0, sizeX);
|
if (simulating)
|
||||||
int endY = Mathf.Clamp(currentCoordinates.Y + 1, 0, sizeY);
|
{
|
||||||
int endZ = Mathf.Clamp(currentCoordinates.Z + 1, 0, sizeZ);
|
farTickTimer = 0;
|
||||||
|
}
|
||||||
|
|
||||||
for (int x = startX; x <= endX; x++)
|
if (farTickTimer >= farTickInterval)
|
||||||
{
|
{
|
||||||
for (int y = startY; y <= endY; y++)
|
double taskFarTickTimer = farTickTimer;
|
||||||
{
|
Task.Run(() =>
|
||||||
for (int z = startZ; z <= endZ; z++)
|
{
|
||||||
{
|
SimulateFar(taskFarTickTimer);
|
||||||
int taskX = x;
|
});
|
||||||
int taskY = y;
|
|
||||||
int taskZ = z;
|
|
||||||
|
|
||||||
Task.Run(() =>
|
farTickTimer = 0;
|
||||||
{
|
}
|
||||||
sectors[taskX, taskY, taskZ].Simulate(delta);
|
}
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void SimulateFar(double delta)
|
public Sector GetCurrentSector()
|
||||||
{
|
{
|
||||||
Sector[,,] sectors = GameUniverse.Sectors;
|
return MainPlayer.PlayerData.CurrentSector;
|
||||||
|
}
|
||||||
|
|
||||||
int sizeX = sectors.GetLength(0);
|
private void SimulateClose(double delta)
|
||||||
int countX = Mathf.Clamp(sizeX / maxFarThreads, 1, int.MaxValue);
|
{
|
||||||
|
List<Sector> neighbours = GetCurrentSector().GetNeighbouringSectors();
|
||||||
|
|
||||||
for (int x = 0; x < sizeX; x += countX)
|
neighbours.ForEach(sector =>
|
||||||
{
|
{
|
||||||
double taskDelta = delta;
|
Task.Run(() =>
|
||||||
int taskStartX = x;
|
{
|
||||||
int taskCountX = countX;
|
sector.Simulate(delta);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
_ = SimulateFarThreaded(taskDelta, taskStartX, taskCountX);
|
private void SimulateFar(double delta)
|
||||||
}
|
{
|
||||||
}
|
simulating = true;
|
||||||
|
|
||||||
private async Task SimulateFarThreaded(double delta, int startX, int countX)
|
List<Task> tasks = [];
|
||||||
{
|
|
||||||
Vector3I currentCoordinates = CurrentSector.Coordinates;
|
|
||||||
|
|
||||||
Sector[,,] sectors = GameUniverse.Sectors;
|
Sector[,,] sectors = GameUniverse.Sectors;
|
||||||
|
|
||||||
int sizeX = sectors.GetLength(0);
|
int sizeX = sectors.GetLength(0);
|
||||||
int sizeY = sectors.GetLength(1);
|
int countX = Mathf.Clamp(sizeX / maxFarThreads, 1, int.MaxValue);
|
||||||
int sizeZ = sectors.GetLength(2);
|
|
||||||
|
|
||||||
int startSkipX = Mathf.Clamp(currentCoordinates.X - 1, 0, sizeX);
|
for (int x = 0; x < sizeX; x += countX)
|
||||||
int startSkipY = Mathf.Clamp(currentCoordinates.Y - 1, 0, sizeY);
|
{
|
||||||
int startSkipZ = Mathf.Clamp(currentCoordinates.Z - 1, 0, sizeZ);
|
double taskDelta = delta;
|
||||||
|
int taskStartX = x;
|
||||||
|
int taskCountX = countX;
|
||||||
|
|
||||||
int endSkipX = Mathf.Clamp(currentCoordinates.X + 1, 0, sizeX);
|
Task clusteredTask = Task.Run(() =>
|
||||||
int endSkipY = Mathf.Clamp(currentCoordinates.Y + 1, 0, sizeY);
|
{
|
||||||
int endSkipZ = Mathf.Clamp(currentCoordinates.Z + 1, 0, sizeZ);
|
SimulateFarClustered(taskDelta, taskStartX, taskCountX);
|
||||||
|
});
|
||||||
|
|
||||||
int endX = Mathf.Clamp(startX + countX, 0, sizeX);
|
tasks.Add(clusteredTask);
|
||||||
|
}
|
||||||
|
|
||||||
for (int x = startX; x < endX; x++)
|
Task.WaitAll([.. tasks]);
|
||||||
{
|
|
||||||
for (int y = 0; y < sizeY; y++)
|
|
||||||
{
|
|
||||||
for (int z = 0; z < sizeZ; z++)
|
|
||||||
{
|
|
||||||
if (Helpers.IsBetweenInclusive(x, startSkipX, endSkipX))
|
|
||||||
{
|
|
||||||
if (Helpers.IsBetweenInclusive(y, startSkipY, endSkipY))
|
|
||||||
{
|
|
||||||
if (Helpers.IsBetweenInclusive(z, startSkipZ, endSkipZ))
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
sectors[x, y, z].Simulate(delta);
|
simulating = false;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
private void SimulateFarClustered(double delta, int startX, int countX)
|
||||||
}
|
{
|
||||||
|
Vector3I currentCoordinates = GetCurrentSector().Coordinates;
|
||||||
|
|
||||||
|
Sector[,,] sectors = GameUniverse.Sectors;
|
||||||
|
|
||||||
|
int sizeX = sectors.GetLength(0);
|
||||||
|
int sizeY = sectors.GetLength(1);
|
||||||
|
int sizeZ = sectors.GetLength(2);
|
||||||
|
|
||||||
|
int startSkipX = Mathf.Clamp(currentCoordinates.X - 1, 0, sizeX);
|
||||||
|
int startSkipY = Mathf.Clamp(currentCoordinates.Y - 1, 0, sizeY);
|
||||||
|
int startSkipZ = Mathf.Clamp(currentCoordinates.Z - 1, 0, sizeZ);
|
||||||
|
|
||||||
|
int endSkipX = Mathf.Clamp(currentCoordinates.X + 1, 0, sizeX);
|
||||||
|
int endSkipY = Mathf.Clamp(currentCoordinates.Y + 1, 0, sizeY);
|
||||||
|
int endSkipZ = Mathf.Clamp(currentCoordinates.Z + 1, 0, sizeZ);
|
||||||
|
|
||||||
|
int endX = Mathf.Clamp(startX + countX, 0, sizeX);
|
||||||
|
|
||||||
|
for (int x = startX; x < endX; x++)
|
||||||
|
{
|
||||||
|
QueueManager.LogQueue.Enqueue("Simulating: " + x);
|
||||||
|
for (int y = 0; y < sizeY; y++)
|
||||||
|
{
|
||||||
|
Thread.Sleep(5);
|
||||||
|
for (int z = 0; z < sizeZ; z++)
|
||||||
|
{
|
||||||
|
if (Helpers.IsBetweenInclusive(x, startSkipX, endSkipX))
|
||||||
|
{
|
||||||
|
if (Helpers.IsBetweenInclusive(y, startSkipY, endSkipY))
|
||||||
|
{
|
||||||
|
if (Helpers.IsBetweenInclusive(z, startSkipZ, endSkipZ))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
sectors[x, y, z].Simulate(delta);
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
QueueManager.LogQueue.Enqueue("EXCEPTION: " + e.Message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void SpawnClose()
|
||||||
|
{
|
||||||
|
List<Sector> neighbours = GetCurrentSector().GetNeighbouringSectors();
|
||||||
|
|
||||||
|
neighbours.ForEach(sector => sector.SpawnObjects());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Spawn(GameObject gameObject)
|
||||||
|
{
|
||||||
|
spawnQueue.Enqueue(gameObject);
|
||||||
|
|
||||||
|
CallDeferred(nameof(ProcessSpawnQueue));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ProcessSpawnQueue()
|
||||||
|
{
|
||||||
|
spawnQueue.TryDequeue(out GameObject gameObject);
|
||||||
|
if (gameObject == null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (spawnedObjects.ContainsKey(gameObject))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Node3D instance = gameObject.Instantiate(GetCurrentSector());
|
||||||
|
spawnedObjects.Add(gameObject, instance);
|
||||||
|
|
||||||
|
CallDeferred("add_child", instance);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Despawn(GameObject gameObject)
|
||||||
|
{
|
||||||
|
if (!spawnedObjects.ContainsKey(gameObject))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Node3D nodeToDespawn = spawnedObjects.GetValueOrDefault(gameObject);
|
||||||
|
spawnedObjects.Remove(gameObject);
|
||||||
|
|
||||||
|
CallDeferred("remove_child", nodeToDespawn);
|
||||||
|
nodeToDespawn.CallDeferred("queue_free");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ApplyOrigin()
|
||||||
|
{
|
||||||
|
Sector current = GetCurrentSector();
|
||||||
|
|
||||||
|
List<Sector> nearby = current.GetNeighbouringSectors();
|
||||||
|
|
||||||
|
foreach (Sector sector in nearby)
|
||||||
|
{
|
||||||
|
foreach (GameObject gameObject in sector.GameObjects)
|
||||||
|
{
|
||||||
|
gameObject.UpdateSectorOffset(current);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (GameObject spawned in spawnedObjects.Keys)
|
||||||
|
{
|
||||||
|
if (!nearby.Contains(spawned.CurrentSector))
|
||||||
|
{
|
||||||
|
Despawn(spawned);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
nearby.ForEach(sector => sector.SpawnObjects());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,71 +1,157 @@
|
||||||
|
using System.Collections.Generic;
|
||||||
using Godot;
|
using Godot;
|
||||||
|
|
||||||
public abstract class GameObject
|
public abstract class GameObject
|
||||||
{
|
{
|
||||||
public Sector CurrentSector { get; private set; }
|
public Sector CurrentSector { get; protected set; }
|
||||||
public Vector3 LocalCoordinates;
|
public Vector3 LocalCoordinates { get; protected set; }
|
||||||
public Vector3Dec GlobalCoordinates;
|
public Vector3Dec GlobalCoordinates { get; protected set; }
|
||||||
|
|
||||||
public GameObject(Sector sector, Vector3 localCoordinates)
|
public Vector3 SectorOffset { get; set; }
|
||||||
{
|
|
||||||
CurrentSector = sector;
|
|
||||||
LocalCoordinates = localCoordinates;
|
|
||||||
|
|
||||||
GlobalCoordinates = new
|
private bool reassigning = false;
|
||||||
(
|
|
||||||
sector.GlobalStartCoordinates.X + (decimal)localCoordinates.X,
|
|
||||||
sector.GlobalStartCoordinates.Y + (decimal)localCoordinates.Y,
|
|
||||||
sector.GlobalStartCoordinates.Z + (decimal)localCoordinates.Z
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
public GameObject(Sector sector, double localX, double localY, double localZ)
|
public GameObject(Sector sector, Vector3 localCoordinates)
|
||||||
{
|
{
|
||||||
CurrentSector = sector;
|
CurrentSector = sector;
|
||||||
LocalCoordinates = new(localX, localY, localZ);
|
LocalCoordinates = localCoordinates;
|
||||||
|
|
||||||
GlobalCoordinates = new
|
GlobalCoordinates = new
|
||||||
(
|
(
|
||||||
sector.GlobalStartCoordinates.X + (decimal)localX,
|
sector.GlobalCenterCoordinates.X + (decimal)localCoordinates.X,
|
||||||
sector.GlobalStartCoordinates.Y + (decimal)localY,
|
sector.GlobalCenterCoordinates.Y + (decimal)localCoordinates.Y,
|
||||||
sector.GlobalStartCoordinates.Z + (decimal)localZ
|
sector.GlobalCenterCoordinates.Z + (decimal)localCoordinates.Z
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public GameObject(Vector3Dec coordinates)
|
public GameObject(Sector sector, double localX, double localY, double localZ)
|
||||||
{
|
{
|
||||||
GlobalCoordinates = coordinates;
|
CurrentSector = sector;
|
||||||
UpdateSector();
|
LocalCoordinates = new(localX, localY, localZ);
|
||||||
}
|
|
||||||
|
|
||||||
public GameObject(decimal x, decimal y, decimal z)
|
GlobalCoordinates = new
|
||||||
{
|
(
|
||||||
GlobalCoordinates = new(x, y, z);
|
sector.GlobalStartCoordinates.X + (decimal)localX,
|
||||||
UpdateSector();
|
sector.GlobalStartCoordinates.Y + (decimal)localY,
|
||||||
}
|
sector.GlobalStartCoordinates.Z + (decimal)localZ
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
public Vector3 GetSectorCoordinates()
|
public GameObject(Vector3Dec coordinates)
|
||||||
{
|
{
|
||||||
Vector3Dec relativeSectorCoordinates = GlobalCoordinates - CurrentSector.GlobalStartCoordinates;
|
GlobalCoordinates = coordinates;
|
||||||
|
UpdateSector();
|
||||||
|
}
|
||||||
|
|
||||||
return relativeSectorCoordinates.ToVector3();
|
public GameObject(decimal x, decimal y, decimal z)
|
||||||
}
|
{
|
||||||
|
GlobalCoordinates = new(x, y, z);
|
||||||
|
UpdateSector();
|
||||||
|
}
|
||||||
|
|
||||||
public bool IsInSector()
|
public bool IsInCurrentSector()
|
||||||
{
|
{
|
||||||
return Helpers.IsInsideArea(CurrentSector.Size, GetSectorCoordinates());
|
return Helpers.IsInsideArea(CurrentSector.Size / 2, LocalCoordinates);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void UpdateSector()
|
public void UpdateSector()
|
||||||
{
|
{
|
||||||
|
List<Sector> neighbours = CurrentSector.GetNeighbouringSectors();
|
||||||
|
foreach (Sector sector in neighbours)
|
||||||
|
{
|
||||||
|
if (sector.IsObjectInSector(this))
|
||||||
|
{
|
||||||
|
sector.AssignObject(this);
|
||||||
|
reassigning = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
foreach (Sector sector in GameManager.Singleton.GameUniverse.Sectors)
|
||||||
|
{
|
||||||
|
if (sector.IsObjectInSector(this))
|
||||||
|
{
|
||||||
|
sector.AssignObject(this);
|
||||||
|
reassigning = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public virtual void Simulate(double delta)
|
public void AssignSector(Sector sector)
|
||||||
{
|
{
|
||||||
if (!IsInSector())
|
CurrentSector = sector;
|
||||||
{
|
ResetLocalCoordinates();
|
||||||
UpdateSector();
|
|
||||||
}
|
SectorOffset = GetSectorOffset(GameManager.Singleton.GetCurrentSector());
|
||||||
}
|
|
||||||
|
if (this is Character)
|
||||||
|
{
|
||||||
|
GameManager.Singleton.ApplyOrigin();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this is not Character)
|
||||||
|
{
|
||||||
|
List<Sector> neighbours = GameManager.Singleton.GetCurrentSector().GetNeighbouringSectors();
|
||||||
|
|
||||||
|
if (neighbours.Contains(sector))
|
||||||
|
{
|
||||||
|
GameManager.Singleton.Spawn(this);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
GameManager.Singleton.Despawn(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
reassigning = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Vector3 GetSectorOffset(Sector sector)
|
||||||
|
{
|
||||||
|
Vector3Dec relative = CurrentSector.GlobalCenterCoordinates - sector.GlobalCenterCoordinates;
|
||||||
|
return relative.ToVector3();
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual void UpdateSectorOffset(Sector sector)
|
||||||
|
{
|
||||||
|
SectorOffset = GetSectorOffset(sector);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetCoordinatesFromGlobal(Vector3Dec globalCoordinates)
|
||||||
|
{
|
||||||
|
GlobalCoordinates = globalCoordinates;
|
||||||
|
LocalCoordinates = (globalCoordinates - CurrentSector.GlobalCenterCoordinates).ToVector3();
|
||||||
|
|
||||||
|
UpdateNodePosition();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetCoordinatesFromLocal(Vector3 localCoordinates)
|
||||||
|
{
|
||||||
|
LocalCoordinates = localCoordinates;
|
||||||
|
GlobalCoordinates = Vector3Dec.FromVector3(localCoordinates) + CurrentSector.GlobalCenterCoordinates;
|
||||||
|
|
||||||
|
UpdateNodePosition();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ResetLocalCoordinates()
|
||||||
|
{
|
||||||
|
SetCoordinatesFromGlobal(GlobalCoordinates);
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual void UpdateNodePosition() { }
|
||||||
|
|
||||||
|
public virtual void Simulate(double delta)
|
||||||
|
{
|
||||||
|
if (!reassigning && !IsInCurrentSector())
|
||||||
|
{
|
||||||
|
UpdateSector();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual Node3D Instantiate(Sector sector)
|
||||||
|
{
|
||||||
|
PackedScene modulePrefab = ResourceLoader.Load<PackedScene>("res://prefabs/gameObjects/node.tscn");
|
||||||
|
return modulePrefab.Instantiate<Node3D>();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
22
scripts/GameObjects/Character.cs
Normal file
22
scripts/GameObjects/Character.cs
Normal file
|
|
@ -0,0 +1,22 @@
|
||||||
|
using Godot;
|
||||||
|
|
||||||
|
public class Character(Sector sector, Vector3 localCoordinates) : GameObject(sector, localCoordinates)
|
||||||
|
{
|
||||||
|
private Player player;
|
||||||
|
|
||||||
|
public Player InstantiatePlayer()
|
||||||
|
{
|
||||||
|
PackedScene prefab = ResourceLoader.Load<PackedScene>("res://prefabs/gameObjects/player.tscn");
|
||||||
|
Player instance = prefab.Instantiate<Player>();
|
||||||
|
|
||||||
|
instance.PlayerData = this;
|
||||||
|
player = instance;
|
||||||
|
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void UpdateNodePosition()
|
||||||
|
{
|
||||||
|
player.GlobalPosition = LocalCoordinates;
|
||||||
|
}
|
||||||
|
}
|
||||||
1
scripts/GameObjects/Character.cs.uid
Normal file
1
scripts/GameObjects/Character.cs.uid
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
uid://dbl3bjk8yp3eb
|
||||||
|
|
@ -1,5 +1,16 @@
|
||||||
using Godot;
|
using Godot;
|
||||||
|
|
||||||
public partial class StarNode : Node
|
public partial class StarNode : StaticBody3D
|
||||||
{
|
{
|
||||||
|
public Star StarData { get; set; }
|
||||||
|
|
||||||
|
public override void _Ready()
|
||||||
|
{
|
||||||
|
GlobalPosition = StarData.LocalCoordinates + StarData.SectorOffset;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void _Process(double delta)
|
||||||
|
{
|
||||||
|
GlobalPosition = StarData.LocalCoordinates + StarData.SectorOffset;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,5 +5,18 @@ public class Star(Sector sector, Vector3 localCoordinates) : GameObject(sector,
|
||||||
public override void Simulate(double delta)
|
public override void Simulate(double delta)
|
||||||
{
|
{
|
||||||
base.Simulate(delta);
|
base.Simulate(delta);
|
||||||
|
|
||||||
|
SetCoordinatesFromGlobal(new(GlobalCoordinates.X, GlobalCoordinates.Y, GlobalCoordinates.Z + 1 * (decimal)delta));
|
||||||
|
}
|
||||||
|
|
||||||
|
public override Node3D Instantiate(Sector sector)
|
||||||
|
{
|
||||||
|
PackedScene prefab = ResourceLoader.Load<PackedScene>("res://prefabs/gameObjects/star.tscn");
|
||||||
|
StarNode instance = prefab.Instantiate<StarNode>();
|
||||||
|
|
||||||
|
instance.StarData = this;
|
||||||
|
SectorOffset = GetSectorOffset(sector);
|
||||||
|
|
||||||
|
return instance;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,12 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Threading.Tasks;
|
|
||||||
using Godot;
|
using Godot;
|
||||||
|
|
||||||
public interface IGenerator
|
public interface IGenerator
|
||||||
{
|
{
|
||||||
public Vector3I GetUniverseSize();
|
public Vector3I GetUniverseSize();
|
||||||
public Vector3 GetSectorSizeEachDirection();
|
public Vector3 GetSectorSize();
|
||||||
|
|
||||||
public Task GenerateUniverse(Action<Universe> callback);
|
public Universe GenerateUniverse();
|
||||||
public Sector GenerateSector(Vector3I coordinates);
|
public Sector GenerateSector(Vector3I coordinates);
|
||||||
|
|
||||||
public Star GenerateStar(Sector sector, Vector3 localCoordinates);
|
public Star GenerateStar(Sector sector, Vector3 localCoordinates);
|
||||||
|
|
|
||||||
|
|
@ -1,134 +1,169 @@
|
||||||
using System;
|
using System.Collections.Generic;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Godot;
|
using Godot;
|
||||||
|
|
||||||
public class TestGenerator : IGenerator
|
public class TestGenerator : IGenerator
|
||||||
{
|
{
|
||||||
public static Vector3I UNIVERSE_SIZE = new(3, 3, 3);
|
public static Vector3I UNIVERSE_SIZE = new(100, 100, 100);
|
||||||
public static Vector3 SECTOR_SIZE_EACH_DIRECTION = new(1000, 1000, 1000);
|
public static Vector3 SECTOR_SIZE = new(5000, 5000, 5000);
|
||||||
public static int STARS_PER_SECTOR = 5;
|
public static int STARS_PER_SECTOR = 100;
|
||||||
public static int STARS_PER_SECTOR_VARIANCE = 2;
|
public static int STARS_PER_SECTOR_VARIANCE = 5;
|
||||||
public static int SHIPS_PER_SECTOR = 0;
|
public static int SHIPS_PER_SECTOR = 0;
|
||||||
public static int SHIPS_PER_SECTOR_VARIANCE = 0;
|
public static int SHIPS_PER_SECTOR_VARIANCE = 0;
|
||||||
public static int STATIONS_PER_SECTOR = 0;
|
public static int STATIONS_PER_SECTOR = 0;
|
||||||
public static int STATIONS_PER_SECTOR_VARIANCE = 0;
|
public static int STATIONS_PER_SECTOR_VARIANCE = 0;
|
||||||
|
|
||||||
private RandomNumberGenerator rng;
|
private readonly int threads = 16;
|
||||||
|
|
||||||
public Vector3I GetUniverseSize()
|
private RandomNumberGenerator rng;
|
||||||
{
|
|
||||||
return UNIVERSE_SIZE;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Vector3 GetSectorSizeEachDirection()
|
public Vector3I GetUniverseSize()
|
||||||
{
|
{
|
||||||
return SECTOR_SIZE_EACH_DIRECTION;
|
return UNIVERSE_SIZE;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task GenerateUniverse(Action<Universe> callback)
|
public Vector3I GetSectorOffset()
|
||||||
{
|
{
|
||||||
rng = new();
|
return new(
|
||||||
|
(int)Mathf.Floor(UNIVERSE_SIZE.X / 2),
|
||||||
|
(int)Mathf.Floor(UNIVERSE_SIZE.X / 2),
|
||||||
|
(int)Mathf.Floor(UNIVERSE_SIZE.X / 2)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
Universe universe = new(UNIVERSE_SIZE);
|
public Vector3 GetSectorSize()
|
||||||
for (int x = 0; x < UNIVERSE_SIZE.X; x++)
|
{
|
||||||
{
|
return SECTOR_SIZE;
|
||||||
for (int y = 0; y < UNIVERSE_SIZE.Y; y++)
|
}
|
||||||
{
|
|
||||||
for (int z = 0; z < UNIVERSE_SIZE.Z; z++)
|
|
||||||
{
|
|
||||||
universe.Sectors[x, y, z] = GenerateSector(new(x, y, z));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
callback(universe);
|
public Universe GenerateUniverse()
|
||||||
}
|
{
|
||||||
|
rng = new();
|
||||||
|
|
||||||
public Sector GenerateSector(Vector3I coordinates)
|
List<Task> tasks = [];
|
||||||
{
|
|
||||||
Sector sector = new(coordinates, SECTOR_SIZE_EACH_DIRECTION);
|
|
||||||
|
|
||||||
int starCount = rng.RandiRange(
|
Universe universe = new(UNIVERSE_SIZE);
|
||||||
STARS_PER_SECTOR - STARS_PER_SECTOR_VARIANCE,
|
int countX = Mathf.Clamp(UNIVERSE_SIZE.X / threads, 1, int.MaxValue);
|
||||||
STARS_PER_SECTOR + STARS_PER_SECTOR_VARIANCE
|
|
||||||
);
|
|
||||||
starCount = Mathf.Clamp(starCount, 0, int.MaxValue);
|
|
||||||
|
|
||||||
for (int i = 0; i < starCount; i++)
|
for (int x = 0; x < UNIVERSE_SIZE.X; x += countX)
|
||||||
{
|
{
|
||||||
Vector3 localCoordinates = GenerateLocalCoordinates();
|
int taskStartX = x;
|
||||||
Star star = GenerateStar(sector, localCoordinates);
|
int taskCountX = countX;
|
||||||
|
|
||||||
sector.GameObjects.Add(star);
|
Task clusteredTask = Task.Run(() =>
|
||||||
}
|
{
|
||||||
|
GenerateClustered(universe, taskStartX, taskCountX);
|
||||||
|
});
|
||||||
|
|
||||||
int shipCount = rng.RandiRange(
|
tasks.Add(clusteredTask);
|
||||||
SHIPS_PER_SECTOR - SHIPS_PER_SECTOR_VARIANCE,
|
}
|
||||||
SHIPS_PER_SECTOR + SHIPS_PER_SECTOR_VARIANCE
|
|
||||||
);
|
|
||||||
shipCount = Mathf.Clamp(shipCount, 0, int.MaxValue);
|
|
||||||
|
|
||||||
for (int i = 0; i < shipCount; i++)
|
Task.WaitAll([.. tasks]);
|
||||||
{
|
|
||||||
Vector3 localCoordinates = GenerateLocalCoordinates();
|
|
||||||
Vessel ship = GenerateShip(sector, localCoordinates);
|
|
||||||
|
|
||||||
sector.GameObjects.Add(ship);
|
return universe;
|
||||||
}
|
}
|
||||||
|
|
||||||
int stationCount = rng.RandiRange(
|
private void GenerateClustered(Universe universe, int startX, int countX)
|
||||||
STATIONS_PER_SECTOR - STATIONS_PER_SECTOR_VARIANCE,
|
{
|
||||||
STATIONS_PER_SECTOR + STATIONS_PER_SECTOR_VARIANCE
|
int endX = Mathf.Clamp(startX + countX, 0, UNIVERSE_SIZE.X);
|
||||||
);
|
|
||||||
stationCount = Mathf.Clamp(stationCount, 0, int.MaxValue);
|
|
||||||
|
|
||||||
for (int i = 0; i < stationCount; i++)
|
for (int x = startX; x < endX; x++)
|
||||||
{
|
{
|
||||||
Vector3 localCoordinates = GenerateLocalCoordinates();
|
for (int y = 0; y < UNIVERSE_SIZE.Y; y++)
|
||||||
Vessel station = GenerateStation(sector, localCoordinates);
|
{
|
||||||
|
for (int z = 0; z < UNIVERSE_SIZE.Z; z++)
|
||||||
|
{
|
||||||
|
universe.Sectors[x, y, z] = GenerateSector(new(x, y, z));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
sector.GameObjects.Add(station);
|
public Sector GenerateSector(Vector3I coordinates)
|
||||||
}
|
{
|
||||||
|
Sector sector = new(coordinates, GetSectorOffset(), SECTOR_SIZE);
|
||||||
|
|
||||||
return sector;
|
int starCount = rng.RandiRange(
|
||||||
}
|
STARS_PER_SECTOR - STARS_PER_SECTOR_VARIANCE,
|
||||||
|
STARS_PER_SECTOR + STARS_PER_SECTOR_VARIANCE
|
||||||
|
);
|
||||||
|
starCount = Mathf.Clamp(starCount, 0, int.MaxValue);
|
||||||
|
|
||||||
public Star GenerateStar(Sector sector, Vector3 localCoordinates)
|
for (int i = 0; i < starCount; i++)
|
||||||
{
|
{
|
||||||
return new Star(sector, localCoordinates);
|
Vector3 localCoordinates = GenerateLocalCoordinates();
|
||||||
}
|
Star star = GenerateStar(sector, localCoordinates);
|
||||||
|
|
||||||
public Star GenerateStar(Sector sector)
|
sector.GameObjects.Add(star);
|
||||||
{
|
}
|
||||||
return GenerateStar(sector, GenerateLocalCoordinates());
|
|
||||||
}
|
|
||||||
|
|
||||||
public Vessel GenerateShip(Sector sector, Vector3 localCoordinates)
|
int shipCount = rng.RandiRange(
|
||||||
{
|
SHIPS_PER_SECTOR - SHIPS_PER_SECTOR_VARIANCE,
|
||||||
return new Vessel(sector, localCoordinates);
|
SHIPS_PER_SECTOR + SHIPS_PER_SECTOR_VARIANCE
|
||||||
}
|
);
|
||||||
|
shipCount = Mathf.Clamp(shipCount, 0, int.MaxValue);
|
||||||
|
|
||||||
public Vessel GenerateShip(Sector sector)
|
for (int i = 0; i < shipCount; i++)
|
||||||
{
|
{
|
||||||
return GenerateShip(sector, GenerateLocalCoordinates());
|
Vector3 localCoordinates = GenerateLocalCoordinates();
|
||||||
}
|
Vessel ship = GenerateShip(sector, localCoordinates);
|
||||||
|
|
||||||
public Vessel GenerateStation(Sector sector, Vector3 localCoordinates)
|
sector.GameObjects.Add(ship);
|
||||||
{
|
}
|
||||||
return new Vessel(sector, localCoordinates);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Vessel GenerateStation(Sector sector)
|
int stationCount = rng.RandiRange(
|
||||||
{
|
STATIONS_PER_SECTOR - STATIONS_PER_SECTOR_VARIANCE,
|
||||||
return GenerateStation(sector, GenerateLocalCoordinates());
|
STATIONS_PER_SECTOR + STATIONS_PER_SECTOR_VARIANCE
|
||||||
}
|
);
|
||||||
|
stationCount = Mathf.Clamp(stationCount, 0, int.MaxValue);
|
||||||
|
|
||||||
public Vector3 GenerateLocalCoordinates()
|
for (int i = 0; i < stationCount; i++)
|
||||||
{
|
{
|
||||||
double x = rng.Randf() * SECTOR_SIZE_EACH_DIRECTION.X;
|
Vector3 localCoordinates = GenerateLocalCoordinates();
|
||||||
double y = rng.Randf() * SECTOR_SIZE_EACH_DIRECTION.Y;
|
Vessel station = GenerateStation(sector, localCoordinates);
|
||||||
double z = rng.Randf() * SECTOR_SIZE_EACH_DIRECTION.Z;
|
|
||||||
|
|
||||||
return new(x, y, z);
|
sector.GameObjects.Add(station);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return sector;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Star GenerateStar(Sector sector, Vector3 localCoordinates)
|
||||||
|
{
|
||||||
|
return new Star(sector, localCoordinates);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Star GenerateStar(Sector sector)
|
||||||
|
{
|
||||||
|
return GenerateStar(sector, GenerateLocalCoordinates());
|
||||||
|
}
|
||||||
|
|
||||||
|
public Vessel GenerateShip(Sector sector, Vector3 localCoordinates)
|
||||||
|
{
|
||||||
|
return new Vessel(sector, localCoordinates);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Vessel GenerateShip(Sector sector)
|
||||||
|
{
|
||||||
|
return GenerateShip(sector, GenerateLocalCoordinates());
|
||||||
|
}
|
||||||
|
|
||||||
|
public Vessel GenerateStation(Sector sector, Vector3 localCoordinates)
|
||||||
|
{
|
||||||
|
return new Vessel(sector, localCoordinates);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Vessel GenerateStation(Sector sector)
|
||||||
|
{
|
||||||
|
return GenerateStation(sector, GenerateLocalCoordinates());
|
||||||
|
}
|
||||||
|
|
||||||
|
public Vector3 GenerateLocalCoordinates()
|
||||||
|
{
|
||||||
|
double x = (rng.Randf() - 0.5) * SECTOR_SIZE.X;
|
||||||
|
double y = (rng.Randf() - 0.5) * SECTOR_SIZE.Y;
|
||||||
|
double z = (rng.Randf() - 0.5) * SECTOR_SIZE.Z;
|
||||||
|
|
||||||
|
return new(x, y, z);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -9,12 +9,27 @@ public static class Helpers
|
||||||
|
|
||||||
public static bool IsInsideArea(Vector3 area, Vector3 coordinates)
|
public static bool IsInsideArea(Vector3 area, Vector3 coordinates)
|
||||||
{
|
{
|
||||||
if (coordinates.X >= area.X && coordinates.Y >= area.Y && coordinates.Z >= area.Z)
|
if (coordinates.X >= area.X || coordinates.Y >= area.Y || coordinates.Z >= area.Z)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (coordinates.X < -area.X && coordinates.Y < -area.Y && coordinates.Z < -area.Z)
|
if (coordinates.X < -area.X || coordinates.Y < -area.Y || coordinates.Z < -area.Z)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool IsInsideGlobalArea(Vector3Dec areaStart, Vector3Dec areaEnd, Vector3Dec coordinates)
|
||||||
|
{
|
||||||
|
if (coordinates.X >= areaEnd.X || coordinates.Y >= areaEnd.Y || coordinates.Z >= areaEnd.Z)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (coordinates.X < areaStart.X || coordinates.Y < areaStart.Y || coordinates.Z < areaStart.Z)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,15 +2,19 @@ using Godot;
|
||||||
|
|
||||||
public partial class Player : CharacterBody3D
|
public partial class Player : CharacterBody3D
|
||||||
{
|
{
|
||||||
[Export] Control GameMenu;
|
|
||||||
|
|
||||||
[Export] public float Speed = 5f;
|
[Export] public double Speed = 5;
|
||||||
[Export] public float JumpForce = 5f;
|
[Export] public double SprintMultiplier = 2;
|
||||||
[Export] public float MouseSensitivity = 0.2f;
|
[Export] public double JumpForce = 5;
|
||||||
|
[Export] public double MouseSensitivity = 0.2;
|
||||||
|
|
||||||
|
public Control GameMenu { get; set; }
|
||||||
|
|
||||||
|
public Character PlayerData { get; set; }
|
||||||
|
|
||||||
private Vector3 gravityVelocity = Vector3.Zero;
|
private Vector3 gravityVelocity = Vector3.Zero;
|
||||||
private Vector3 movementVelocity = Vector3.Zero;
|
private Vector3 movementVelocity = Vector3.Zero;
|
||||||
private double cameraPitch = 0f;
|
private double cameraPitch = 0;
|
||||||
private Camera3D camera;
|
private Camera3D camera;
|
||||||
private GravityReceiver gravityReceiver;
|
private GravityReceiver gravityReceiver;
|
||||||
|
|
||||||
|
|
@ -18,6 +22,14 @@ public partial class Player : CharacterBody3D
|
||||||
{
|
{
|
||||||
camera = GetNode<Camera3D>("Camera");
|
camera = GetNode<Camera3D>("Camera");
|
||||||
gravityReceiver = GetNode<GravityReceiver>("GravityReceiver");
|
gravityReceiver = GetNode<GravityReceiver>("GravityReceiver");
|
||||||
|
|
||||||
|
PlayerData.UpdateNodePosition();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void _Process(double delta)
|
||||||
|
{
|
||||||
|
PlayerData.SetCoordinatesFromLocal(GlobalPosition);
|
||||||
|
PlayerData.Simulate(delta);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void _PhysicsProcess(double delta)
|
public override void _PhysicsProcess(double delta)
|
||||||
|
|
@ -69,7 +81,7 @@ public partial class Player : CharacterBody3D
|
||||||
|
|
||||||
if (IsInGravity())
|
if (IsInGravity())
|
||||||
{
|
{
|
||||||
cameraPitch = Mathf.Clamp(cameraPitch + pitchDelta, -90f, 90f);
|
cameraPitch = Mathf.Clamp(cameraPitch + pitchDelta, -90, 90);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
@ -82,7 +94,7 @@ public partial class Player : CharacterBody3D
|
||||||
|
|
||||||
public bool IsInGravity()
|
public bool IsInGravity()
|
||||||
{
|
{
|
||||||
return gravityReceiver.InGravityZone && gravityReceiver.GetGravityStrength() > 0f;
|
return gravityReceiver.InGravityZone && gravityReceiver.GetGravityStrength() > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool IsOnGravityFloor()
|
public bool IsOnGravityFloor()
|
||||||
|
|
@ -94,7 +106,7 @@ public partial class Player : CharacterBody3D
|
||||||
|
|
||||||
double alignment = collisionNormal.Dot(gravityReceiver.GetGravityDirection());
|
double alignment = collisionNormal.Dot(gravityReceiver.GetGravityDirection());
|
||||||
|
|
||||||
if (alignment > 0.7f)
|
if (alignment > 0.7)
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
@ -118,28 +130,28 @@ public partial class Player : CharacterBody3D
|
||||||
Vector3 targetUp = gravityReceiver.GetGravityDirection();
|
Vector3 targetUp = gravityReceiver.GetGravityDirection();
|
||||||
|
|
||||||
Vector3 axis = currentUp.Cross(targetUp);
|
Vector3 axis = currentUp.Cross(targetUp);
|
||||||
if (axis.Length() < 0.00001f)
|
if (axis.Length() < 0.00001)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
double angle = currentUp.AngleTo(targetUp);
|
double angle = currentUp.AngleTo(targetUp);
|
||||||
|
|
||||||
GlobalRotate(axis.Normalized(), angle * delta * 10f);
|
GlobalRotate(axis.Normalized(), angle * delta * 10);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ProcessCamera(double delta)
|
private void ProcessCamera(double delta)
|
||||||
{
|
{
|
||||||
if (cameraPitch > 0.01f)
|
if (cameraPitch > 0.01)
|
||||||
{
|
{
|
||||||
cameraPitch -= 90f * delta;
|
cameraPitch -= 90 * delta;
|
||||||
}
|
}
|
||||||
else if (cameraPitch < -0.001f)
|
else if (cameraPitch < -0.001)
|
||||||
{
|
{
|
||||||
cameraPitch += 90f * delta;
|
cameraPitch += 90 * delta;
|
||||||
}
|
}
|
||||||
if (Mathf.Abs(cameraPitch) < 1f)
|
if (Mathf.Abs(cameraPitch) < 1)
|
||||||
{
|
{
|
||||||
cameraPitch = 0f;
|
cameraPitch = 0;
|
||||||
}
|
}
|
||||||
camera.RotationDegrees = new Vector3(cameraPitch, 0, 0);
|
camera.RotationDegrees = new Vector3(cameraPitch, 0, 0);
|
||||||
}
|
}
|
||||||
|
|
@ -149,19 +161,21 @@ public partial class Player : CharacterBody3D
|
||||||
float inputX = Input.GetAxis("move_left", "move_right");
|
float inputX = Input.GetAxis("move_left", "move_right");
|
||||||
float inputZ = Input.GetAxis("move_forward", "move_back");
|
float inputZ = Input.GetAxis("move_forward", "move_back");
|
||||||
|
|
||||||
|
bool sprint = Input.IsActionPressed("sprint");
|
||||||
|
|
||||||
Vector3 direction = GlobalTransform.Basis.X * inputX + GlobalTransform.Basis.Z * inputZ;
|
Vector3 direction = GlobalTransform.Basis.X * inputX + GlobalTransform.Basis.Z * inputZ;
|
||||||
|
|
||||||
if (direction != Vector3.Zero)
|
if (direction != Vector3.Zero)
|
||||||
{
|
{
|
||||||
newMovementVelocity.X = direction.X * Speed;
|
newMovementVelocity.X = direction.X * Speed * (sprint ? SprintMultiplier : 1);
|
||||||
newMovementVelocity.Y = direction.Y * Speed;
|
newMovementVelocity.Y = direction.Y * Speed * (sprint ? SprintMultiplier : 1);
|
||||||
newMovementVelocity.Z = direction.Z * Speed;
|
newMovementVelocity.Z = direction.Z * Speed * (sprint ? SprintMultiplier : 1);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
newMovementVelocity.X = 0f;
|
newMovementVelocity.X = 0;
|
||||||
newMovementVelocity.Y = 0f;
|
newMovementVelocity.Y = 0;
|
||||||
newMovementVelocity.Z = 0f;
|
newMovementVelocity.Z = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Input.IsActionJustPressed("jump") && IsOnGravityFloor())
|
if (Input.IsActionJustPressed("jump") && IsOnGravityFloor())
|
||||||
|
|
@ -176,19 +190,21 @@ public partial class Player : CharacterBody3D
|
||||||
float inputY = -Input.GetAxis("move_up", "move_down");
|
float inputY = -Input.GetAxis("move_up", "move_down");
|
||||||
float inputZ = Input.GetAxis("move_forward", "move_back");
|
float inputZ = Input.GetAxis("move_forward", "move_back");
|
||||||
|
|
||||||
|
bool sprint = Input.IsActionPressed("sprint");
|
||||||
|
|
||||||
Vector3 direction = Transform.Basis.X * inputX + Transform.Basis.Y * inputY + Transform.Basis.Z * inputZ;
|
Vector3 direction = Transform.Basis.X * inputX + Transform.Basis.Y * inputY + Transform.Basis.Z * inputZ;
|
||||||
|
|
||||||
if (direction != Vector3.Zero)
|
if (direction != Vector3.Zero)
|
||||||
{
|
{
|
||||||
newMovementVelocity.X = direction.X * Speed;
|
newMovementVelocity.X = direction.X * Speed * (sprint ? SprintMultiplier : 1);
|
||||||
newMovementVelocity.Y = direction.Y * Speed;
|
newMovementVelocity.Y = direction.Y * Speed * (sprint ? SprintMultiplier : 1);
|
||||||
newMovementVelocity.Z = direction.Z * Speed;
|
newMovementVelocity.Z = direction.Z * Speed * (sprint ? SprintMultiplier : 1);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
newMovementVelocity.X = 0f;
|
newMovementVelocity.X = 0;
|
||||||
newMovementVelocity.Y = 0f;
|
newMovementVelocity.Y = 0;
|
||||||
newMovementVelocity.Z = 0f;
|
newMovementVelocity.Z = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
double inputRotateZ = Input.GetAxis("rotate_left", "rotate_right");
|
double inputRotateZ = Input.GetAxis("rotate_left", "rotate_right");
|
||||||
|
|
|
||||||
43
scripts/QueueManager.cs
Normal file
43
scripts/QueueManager.cs
Normal file
|
|
@ -0,0 +1,43 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Concurrent;
|
||||||
|
using Godot;
|
||||||
|
|
||||||
|
public partial class QueueManager : Node
|
||||||
|
{
|
||||||
|
public static ConcurrentQueue<string> LogQueue = new();
|
||||||
|
public static ConcurrentQueue<Action> ActionQueue = new();
|
||||||
|
|
||||||
|
public static ConcurrentQueue<(Sector, GameObject)> SectorReassignQueue = new();
|
||||||
|
|
||||||
|
private readonly int sectorReassignQueueRateLimit = 500;
|
||||||
|
|
||||||
|
public override void _Process(double delta)
|
||||||
|
{
|
||||||
|
while (LogQueue.TryDequeue(out string text))
|
||||||
|
{
|
||||||
|
GD.Print(text);
|
||||||
|
}
|
||||||
|
|
||||||
|
while (ActionQueue.TryDequeue(out Action action))
|
||||||
|
{
|
||||||
|
action();
|
||||||
|
}
|
||||||
|
|
||||||
|
GD.Print(SectorReassignQueue.Count);
|
||||||
|
|
||||||
|
int sectorReassignQueueProcessed = 0;
|
||||||
|
while (
|
||||||
|
!GameManager.Singleton.simulating
|
||||||
|
&& sectorReassignQueueProcessed++ < sectorReassignQueueRateLimit
|
||||||
|
&& SectorReassignQueue.TryDequeue(out var item)
|
||||||
|
)
|
||||||
|
{
|
||||||
|
var (sector, gameObject) = item;
|
||||||
|
|
||||||
|
gameObject.CurrentSector.GameObjects.Remove(gameObject);
|
||||||
|
sector.GameObjects.Add(gameObject);
|
||||||
|
|
||||||
|
gameObject.AssignSector(sector);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
1
scripts/QueueManager.cs.uid
Normal file
1
scripts/QueueManager.cs.uid
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
uid://dr6y711ano07p
|
||||||
|
|
@ -1,37 +1,95 @@
|
||||||
using System.Threading;
|
using System.Collections.Generic;
|
||||||
using Godot;
|
using Godot;
|
||||||
|
|
||||||
public class Sector
|
public class Sector
|
||||||
{
|
{
|
||||||
public Vector3I Coordinates;
|
public Vector3I Coordinates;
|
||||||
public Vector3Dec GlobalStartCoordinates;
|
public Vector3Dec GlobalStartCoordinates;
|
||||||
|
public Vector3Dec GlobalCenterCoordinates;
|
||||||
public Vector3Dec GlobalEndCoordinates;
|
public Vector3Dec GlobalEndCoordinates;
|
||||||
public Vector3 Size;
|
public Vector3 Size;
|
||||||
|
|
||||||
public FastUniqueList<GameObject> GameObjects = new();
|
public FastUniqueList<GameObject> GameObjects = new();
|
||||||
|
|
||||||
public Sector(Vector3I coordinates, Vector3 size)
|
public Sector(Vector3I coordinates, Vector3I offset, Vector3 size)
|
||||||
{
|
{
|
||||||
Coordinates = coordinates;
|
Coordinates = coordinates;
|
||||||
|
|
||||||
decimal startX = Coordinates.X * (decimal)size.X;
|
Vector3Dec sizeDec = Vector3Dec.FromVector3(size);
|
||||||
decimal startY = Coordinates.Y * (decimal)size.Y;
|
|
||||||
decimal startZ = Coordinates.Z * (decimal)size.Z;
|
decimal startX = (coordinates.X - offset.X) * sizeDec.X;
|
||||||
|
decimal startY = (coordinates.Y - offset.Y) * sizeDec.Y;
|
||||||
|
decimal startZ = (coordinates.Z - offset.Z) * sizeDec.Z;
|
||||||
|
|
||||||
GlobalStartCoordinates = new(startX, startY, startZ);
|
GlobalStartCoordinates = new(startX, startY, startZ);
|
||||||
|
|
||||||
|
GlobalCenterCoordinates = new(
|
||||||
|
startX + sizeDec.X / 2,
|
||||||
|
startY + sizeDec.Y / 2,
|
||||||
|
startZ + sizeDec.Z / 2
|
||||||
|
);
|
||||||
|
|
||||||
|
GlobalEndCoordinates = new(
|
||||||
|
startX + sizeDec.X,
|
||||||
|
startY + sizeDec.Y,
|
||||||
|
startZ + sizeDec.Z
|
||||||
|
);
|
||||||
|
|
||||||
Size = size;
|
Size = size;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Sector(int x, int y, int z, Vector3 size) : this(new(x, y, z), size) { }
|
|
||||||
|
|
||||||
public void Simulate(double delta)
|
public void Simulate(double delta)
|
||||||
{
|
{
|
||||||
//GD.Print(Thread.CurrentThread.ManagedThreadId);
|
|
||||||
|
|
||||||
GameObjects.ForEach(gameObject =>
|
GameObjects.ForEach(gameObject =>
|
||||||
{
|
{
|
||||||
gameObject.Simulate(delta);
|
gameObject.Simulate(delta);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public bool IsObjectInSector(GameObject gameObject)
|
||||||
|
{
|
||||||
|
return Helpers.IsInsideGlobalArea(GlobalStartCoordinates, GlobalEndCoordinates, gameObject.GlobalCoordinates);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void AssignObject(GameObject gameObject)
|
||||||
|
{
|
||||||
|
QueueManager.SectorReassignQueue.Enqueue((this, gameObject));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SpawnObjects()
|
||||||
|
{
|
||||||
|
GameObjects.ForEach(GameManager.Singleton.Spawn);
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<Sector> GetNeighbouringSectors()
|
||||||
|
{
|
||||||
|
List<Sector> neighbours = [];
|
||||||
|
|
||||||
|
Sector[,,] allSectors = GameManager.Singleton.GameUniverse.Sectors;
|
||||||
|
|
||||||
|
int sizeX = allSectors.GetLength(0);
|
||||||
|
int sizeY = allSectors.GetLength(1);
|
||||||
|
int sizeZ = allSectors.GetLength(2);
|
||||||
|
|
||||||
|
int startX = Mathf.Clamp(Coordinates.X - 1, 0, sizeX - 1);
|
||||||
|
int startY = Mathf.Clamp(Coordinates.Y - 1, 0, sizeY - 1);
|
||||||
|
int startZ = Mathf.Clamp(Coordinates.Z - 1, 0, sizeZ - 1);
|
||||||
|
|
||||||
|
int endX = Mathf.Clamp(Coordinates.X + 1, 0, sizeX - 1);
|
||||||
|
int endY = Mathf.Clamp(Coordinates.Y + 1, 0, sizeY - 1);
|
||||||
|
int endZ = Mathf.Clamp(Coordinates.Z + 1, 0, sizeZ - 1);
|
||||||
|
|
||||||
|
for (int x = startX; x <= endX; x++)
|
||||||
|
{
|
||||||
|
for (int y = startY; y <= endY; y++)
|
||||||
|
{
|
||||||
|
for (int z = startZ; z <= endZ; z++)
|
||||||
|
{
|
||||||
|
neighbours.Add(allSectors[x, y, z]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return neighbours;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,4 @@
|
||||||
|
using System;
|
||||||
using Godot;
|
using Godot;
|
||||||
|
|
||||||
public class Universe
|
public class Universe
|
||||||
|
|
@ -23,4 +24,22 @@ public class Universe
|
||||||
{
|
{
|
||||||
return Sectors[x, y, z];
|
return Sectors[x, y, z];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void ForEachSector(Action<Sector> action)
|
||||||
|
{
|
||||||
|
int sizeX = Sectors.GetLength(0);
|
||||||
|
int sizeY = Sectors.GetLength(1);
|
||||||
|
int sizeZ = Sectors.GetLength(2);
|
||||||
|
|
||||||
|
for (int x = 0; x < sizeX; x++)
|
||||||
|
{
|
||||||
|
for (int y = 0; y < sizeY; y++)
|
||||||
|
{
|
||||||
|
for (int z = 0; z < sizeZ; z++)
|
||||||
|
{
|
||||||
|
action(Sectors[x, y, z]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
using System;
|
using System;
|
||||||
using Godot;
|
using Godot;
|
||||||
|
|
||||||
public class Vector3Dec(decimal x, decimal y, decimal z)
|
public readonly struct Vector3Dec(decimal x, decimal y, decimal z)
|
||||||
{
|
{
|
||||||
public static Vector3Dec Zero { get; } = new(0, 0, 0);
|
public static Vector3Dec Zero { get; } = new(0, 0, 0);
|
||||||
|
|
||||||
|
|
@ -14,6 +14,11 @@ public class Vector3Dec(decimal x, decimal y, decimal z)
|
||||||
return new((double)X, (double)Y, (double)Z);
|
return new((double)X, (double)Y, (double)Z);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static Vector3Dec FromVector3(Vector3 vec)
|
||||||
|
{
|
||||||
|
return new((decimal)vec.X, (decimal)vec.Y, (decimal)vec.Z);
|
||||||
|
}
|
||||||
|
|
||||||
public static Vector3Dec operator +(Vector3Dec vec1, Vector3Dec vec2)
|
public static Vector3Dec operator +(Vector3Dec vec1, Vector3Dec vec2)
|
||||||
{
|
{
|
||||||
return new(vec1.X + vec2.X, vec1.Y + vec2.Y, vec1.Z + vec2.Z);
|
return new(vec1.X + vec2.X, vec1.Y + vec2.Y, vec1.Z + vec2.Z);
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue