15 [Icon(ManiaMapResources.Icons.RoomNode3DIcon)]
24 public Error EmitOnCellAreaEntered(
CellArea3D cell, Node collision) => EmitSignal(SignalName.OnCellAreaEntered, cell, collision);
32 public Error EmitOnCellAreaExited(
CellArea3D cell, Node collection) => EmitSignal(SignalName.OnCellAreaExited, cell, collection);
38 public Error EmitOnCellGridChanged() => EmitSignal(SignalName.OnCellGridChanged);
43 private int _rows = 1;
45 [Export(PropertyHint.Range,
"1,10,1,or_greater")]
public int Rows {
get => _rows;
set => SetSizeField(ref _rows, value); }
47 private int _columns = 1;
49 [Export(PropertyHint.Range,
"1,10,1,or_greater")]
public int Columns {
get => _columns;
set => SetSizeField(ref _columns, value); }
51 private Vector3 _cellSize = Vector3.One;
55 [Export(PropertyHint.Range,
"0,100,0.001,or_greater")]
public Vector3
CellSize {
get => _cellSize;
set => SetCellSizeField(ref _cellSize, value); }
58 [Export]
public Godot.Collections.Array<Godot.Collections.Array<
bool>>
ActiveCells {
get;
set; } =
new Godot.Collections.Array<Godot.Collections.Array<
bool>>();
73 private bool MouseButtonPressed {
get;
set; }
74 private Vector2 MouseButtonDownPosition {
get;
set; }
77 private void SetSizeField(ref
int field,
int value)
80 this.SizeActiveCells();
81 EmitOnCellGridChanged();
84 private void SetCellSizeField(ref Vector3 field, Vector3 value)
86 field =
new Vector3(Mathf.Max(value.X, 0.001f), Mathf.Max(value.Y, 0.001f), Mathf.Max(value.Z, 0.001f));
87 EmitOnCellGridChanged();
90 public override void _Ready()
95 if (Engine.IsEditorHint())
97 this.SizeActiveCells();
98 Editor.CellGrid3DGizmo.CreateInstance(
this);
107 public override void _ValidateProperty(Godot.Collections.Dictionary property)
109 base._ValidateProperty(property);
110 var name =
property[
"name"].AsStringName();
111 var usage =
property[
"usage"].As<PropertyUsageFlags>();
113 if (name == PropertyName.ActiveCells)
114 property[
"usage"] = (int)(usage & ~PropertyUsageFlags.Editor);
118 public override void _Process(
double delta)
120 base._Process(delta);
122 if (Engine.IsEditorHint())
123 ProcessEditCellInputs();
126 private static bool DisplayCells()
128 return Editor.ManiaMapPlugin.PluginIsValid()
129 && Editor.ManiaMapPlugin.Current.RoomNode3DToolbar.DisplayCells;
134 if (!Editor.ManiaMapPlugin.PluginIsValid())
136 return Editor.ManiaMapPlugin.Current.RoomNode3DToolbar.CellEditMode;
139 private void ProcessEditCellInputs()
144 if (Input.IsMouseButtonPressed(MouseButton.Left) && CameraIsLookingDown() && MouseIsInsideMainScreen())
146 if (!MouseButtonPressed)
147 MouseButtonDownPosition = GetMousePosition();
149 MouseButtonPressed =
true;
153 if (MouseButtonPressed && CameraIsLookingDown() && MouseIsInsideMainScreen())
155 var mousePosition = GetMousePosition();
156 var startPosition =
new Vector3(MouseButtonDownPosition.X, 0, MouseButtonDownPosition.Y);
157 var endPosition =
new Vector3(mousePosition.X, 0, mousePosition.Y);
160 this.SetCellActivities(startIndex, endIndex, CellEditMode());
161 EmitOnCellGridChanged();
164 MouseButtonPressed =
false;
167 private static Vector2 GetMousePosition()
169 var viewport = EditorInterface.Singleton.GetEditorViewport3D();
170 var camera = viewport.GetCamera3D();
171 var origin = camera.ProjectRayOrigin(viewport.GetMousePosition());
172 return new Vector2(origin.X, origin.Z);
175 private static bool CameraIsLookingDown()
177 var camera = EditorInterface.Singleton.GetEditorViewport3D().GetCamera3D();
178 var cameraDirection = camera.GlobalRotationDegrees;
179 return cameraDirection.IsEqualApprox(
new Vector3(-90, 0, 0));
182 private static bool MouseIsInsideMainScreen()
184 var mainScreen = EditorInterface.Singleton.GetEditorMainScreen();
185 var mousePosition = mainScreen.GetViewport().GetMousePosition();
186 var mainScreenRect =
new Rect2(mainScreen.GlobalPosition, mainScreen.Size);
187 return mainScreenRect.Encloses(
new Rect2(mousePosition, Vector2.Zero));
202 var roomLayout = layoutPack.
Layout.Rooms[id];
203 var roomState = layoutPack.
LayoutState.RoomStates[id];
205 return CreateInstance(scene, parent, layoutPack, roomLayout, roomState, collisionMask, assignLayoutPosition);
221 Room roomLayout,
RoomState roomState, uint cellCollisionMask,
bool assignLayoutPosition)
224 room.
Initialize(layoutPack, roomLayout, roomState, cellCollisionMask, assignLayoutPosition);
225 parent.AddChild(room);
244 uint cellCollisionMask,
bool assignLayoutPosition)
253 if (assignLayoutPosition)
271 for (
int j = 0; j < row.Count; j++)
316 var column = Mathf.FloorToInt(position.X /
CellSize.X);
317 var row = Mathf.FloorToInt(position.Z /
CellSize.Z);
319 if (this.CellIndexExists(row, column))
320 return new Vector2I(row, column);
322 return new Vector2I(-1, -1);
333 if (this.CellIndexExists(fastIndex.X, fastIndex.Y) &&
ActiveCells[fastIndex.X][fastIndex.Y])
336 var index = Vector2I.Zero;
337 var minDistance =
float.PositiveInfinity;
343 for (
int j = 0; j < row.Count; j++)
348 var distance =
new Vector2(delta.X, delta.Z).LengthSquared();
350 if (distance < minDistance)
352 minDistance = distance;
353 index =
new Vector2I(i, j);
371 Span<DoorDirection> directions = stackalloc DoorDirection[]
378 DoorDirection.Bottom,
381 Span<Vector3> vectors = stackalloc Vector3[]
383 new Vector3(0, 0, -1),
384 new Vector3(1, 0, 0),
385 new Vector3(0, 0, 1),
386 new Vector3(-1, 0, 0),
387 new Vector3(0, 1, 0),
388 new Vector3(0, -1, 0),
392 var maxDistance =
float.NegativeInfinity;
395 for (
int i = 0; i < vectors.Length; i++)
397 var distance = delta.Dot(vectors[i]);
399 if (distance > maxDistance)
401 maxDistance = distance;
406 return directions[index];
Provides area and body entering and exiting detection for a cell.
static CellArea3D CreateInstance(int row, int column, RoomNode3D room, uint collisionMask)
Creates a new instance with child collision shape and adds it as a child of the specified room.
Raised if a room is not initialized when its on ready method is called.
Holds the current Layout and LayoutState.
LayoutState LayoutState
The layout state.
ManiaMapSettings Settings
The settings.
uint CellCollisionMask
The cell collision mask used for detecting objects entering or exiting a CellArea2D....
A node serving as the top level of a 3D room.
static RoomNode3D CreateInstance(Uid id, LayoutPack layoutPack, PackedScene scene, Node parent, bool assignLayoutPosition=false)
Creates and initializes an instance of a room. The layout and layout state are assigned to the room b...
Vector2I FindClosestActiveCellIndex(Vector3 position)
Returns the closest active cell index to the specified global position.
delegate void OnCellAreaExitedEventHandler(CellArea3D cell, Node collision)
Signal emitted when a cell area is exited by a tracked area or body.
Godot.Collections.Array< Godot.Collections.Array< bool > > ActiveCells
void MoveToLayoutPosition()
Moves the room to its position in the Layout.
bool Initialize(LayoutPack layoutPack, Room roomLayout, RoomState roomState, uint cellCollisionMask, bool assignLayoutPosition)
Initializes the room. The room should be initialized before adding it to the scene tree since cell ch...
delegate void OnCellAreaEnteredEventHandler(CellArea3D cell, Node collision)
Signal emitted when a cell area is entered by a tracked area or body.
void CreateCellAreas(uint cellCollisionMask)
Creates CellArea3D for all active cells.
delegate void OnCellGridChangedEventHandler()
Signal emitted when the cell grid size or cell sizes are set.
Vector3 CellCenterLocalPosition(int row, int column)
Returns the cell center local position for the specified cell index.
Vector3 CellSize
The width and height of the room cells.
Vector2I GlobalPositionToCellIndex(Vector3 position)
Returns the row (x) and column (y) index corresponding to the specified global position....
RoomTemplateResource RoomTemplate
static RoomNode3D CreateInstance(PackedScene scene, Node parent, LayoutPack layoutPack, Room roomLayout, RoomState roomState, uint cellCollisionMask, bool assignLayoutPosition)
Creates and initializes an instance of a room.
DoorDirection FindClosestDoorDirection(int row, int column, Vector3 position)
Returns the closest door direction based on the cell index and specified global position....
Vector3 CellCenterGlobalPosition(int row, int column)
Returns the cell center global position for the specified cell index.
Vector2I LocalPositionToCellIndex(Vector3 position)
Returns the row (x) and column (y) index corresponding to the specified local position....
Provides a reference to a room scene and information for the room required by the procedural generato...
The interface for a room node.
CellActivity
Option for setting cell activities.