A game where you get to play as a slime, made with Godot.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

133 lines
3.9 KiB

[Tool]
public partial class Terrain
{
bool _unhandledMouseMotion = false; // Used to detect when mouse moves off the terrain.
Vector2I? _tileHover = null; // Position of currently hovered tile.
bool _isSelecting = false; // Whether left mouse is held down to select tiles.
(Vector2I Start, Vector2I End)? _selection = null;
public override void _Input(InputEvent ev)
{
if (!IsEditing()) return;
if (_isSelecting && ev is InputEventMouseButton { ButtonIndex: MouseButton.Left, Pressed: false }) {
_isSelecting = false;
GetViewport().SetInputAsHandled();
}
if ((ev is InputEventMouseButton { ButtonIndex: var wheel, ShiftPressed: true })
&& (wheel is MouseButton.WheelUp or MouseButton.WheelDown))
{
const float AdjustHeight = 0.5f;
var value = (wheel == MouseButton.WheelUp) ? 1.0f : -1.0f;
foreach (var tile in GetSelectedTiles())
AdjustTileHeight(tile, value * AdjustHeight);
if (_selection != null)
UpdateMeshAndShape();
NotifyPropertyListChanged();
GetViewport().SetInputAsHandled();
}
if (ev is InputEventMouseMotion)
_unhandledMouseMotion = true;
}
public override void _InputEvent(Camera3D camera, InputEvent ev, Vector3 position, Vector3 normal, int shapeIdx)
{
if (!IsEditing()) return;
var localPos = ToLocal(position);
var tilePos = ToTilePos(localPos);
if (ev is InputEventMouseButton { ButtonIndex: MouseButton.Left, Pressed: true }) {
_selection = (tilePos, tilePos);
_isSelecting = true;
GetViewport().SetInputAsHandled();
}
if (ev is InputEventMouseMotion) {
_unhandledMouseMotion = false;
_tileHover = tilePos;
if (_isSelecting) _selection = _selection.Value with { End = tilePos };
}
}
public override void _Process(double delta)
{
if (!IsEditing()) {
_tileHover = null;
_selection = null;
_isSelecting = false;
}
if (_unhandledMouseMotion)
_tileHover = null;
if ((_tileHover != null) || (_selection != null)) {
var mesh = GetOrCreateMesh("EditToolMesh");
mesh.ClearSurfaces();
mesh.SurfaceBegin(Mesh.PrimitiveType.Lines);
void AddLine(Vector3 start, Vector3 end) {
mesh.SurfaceAddVertex(start);
mesh.SurfaceAddVertex(end);
}
void AddQuad(Vector3 topLeft, Vector3 topRight,
Vector3 bottomLeft, Vector3 bottomRight) {
AddLine(topLeft , topRight );
AddLine(topRight , bottomRight);
AddLine(bottomRight, bottomLeft );
AddLine(bottomLeft , topLeft );
}
if (_tileHover is Vector2I hover) {
var corners = GetGridCorners(hover);
var margin = 0.1f;
mesh.SurfaceSetColor(Colors.Black);
AddQuad(
corners.TopLeft + new Vector3(-margin, 0, -margin),
corners.TopRight + new Vector3(+margin, 0, -margin),
corners.BottomLeft + new Vector3(-margin, 0, +margin),
corners.BottomRight + new Vector3(+margin, 0, +margin)
);
}
mesh.SurfaceSetColor(Colors.Blue);
foreach (var tilePos in GetSelectedTiles()) {
var corners = GetGridCorners(tilePos);
AddQuad(corners.TopLeft, corners.TopRight, corners.BottomLeft, corners.BottomRight);
}
mesh.SurfaceEnd();
mesh.SurfaceSetMaterial(0, _editToolMaterial);
} else {
var meshInstance = (MeshInstance3D)GetNodeOrNull("EditToolMesh");
var mesh = (ImmediateMesh)meshInstance?.Mesh;
mesh?.ClearSurfaces();
}
}
bool IsEditing()
{
if (Engine.IsEditorHint()) {
var selection = EditorInterface.Singleton.GetSelection();
return selection.GetSelectedNodes().Contains(this);
} else {
return false;
}
}
IEnumerable<Vector2I> GetSelectedTiles()
{
if (_selection is not (Vector2I start, Vector2I end)) yield break;
// Ensure start.X/Y is smaller than end.X/Y.
(start, end) = (new(Min(start.X, end.X), Min(start.Y, end.Y)),
new(Max(start.X, end.X), Max(start.Y, end.Y)));
// Go over all tiles in the range and yield each one.
for (var x = start.X; x <= end.X; x++)
for (var y = start.Y; y <= end.Y; y++)
yield return new(x, y);
}
}