Re-introduce simple terrain editing

main
copygirl 3 months ago
parent 49e1112ec2
commit 5541872d20
  1. 167
      terrain/editing/TerrainEditingControls+Editing.cs

@ -66,119 +66,69 @@ public partial class TerrainEditingControls
new Vector2(tile.X + 0.5f, tile.Y + 0.5f)) < distanceSqr);
}
UpdateEditToolMesh(terrain, ToolShape switch {
var tiles = (ToolShape switch {
// TODO: Edit corner, not full tile.
ToolShape.Corner => [tile],
ToolShape.Circle => GetTilesInRadius(),
ToolShape.Square => GetTilesInSquare(),
_ => throw new InvalidOperationException(),
});
}).ToHashSet();
// TODO: Handle different tool modes, such as painting.
// TODO: Add a flatten tool mode: Flattens everything selected to nearest corner height.
// TODO: Allow click-dragging which doesn't affect already changed tiles / corners.
// TODO: Support undo and redo.
// TODO: Support "disconnected" mode which can create vertical cliffs.
// Raise / lower the terrain if left / right mouse button is pressed.
if ((mouse is InputEventMouseButton { ButtonIndex: var button, Pressed: true })
&& (button is MouseButton.Left or MouseButton.Right))
{
GetViewport().SetInputAsHandled();
const float AdjustHeight = 0.5f;
var amount = (button == MouseButton.Left)
? AdjustHeight : -AdjustHeight;
// Find corners that are "connected" and should be raised.
var corners = new HashSet<(TilePos Position, Corner Corner)>();
foreach (var pos in tiles) {
var tile2 = terrain.GetTile(pos);
foreach (var corner2 in Enum.GetValues<Corner>()) {
var height = tile2.Height[corner2];
foreach (var (neighborPos, neighborCorner) in GetNeighbors(pos, corner2)) {
if (tiles.Contains(neighborPos)) continue;
var neighborHeight = terrain.GetTile(neighborPos).Height[neighborCorner];
if (neighborHeight == height) corners.Add((neighborPos, neighborCorner));
}
}
}
// Raise connected corners.
foreach (var group in corners.GroupBy(e => e.Position, e => e.Corner)) {
var pos = group.Key;
var tile2 = terrain.GetTile(pos);
foreach (var corner2 in group)
tile2.Height[corner2] += amount;
terrain.SetTile(pos, tile2);
}
// Raise selected tiles themselves.
foreach (var pos in tiles) {
var tile2 = terrain.GetTile(pos);
tile2.Height.Adjust(amount);
terrain.SetTile(pos, tile2);
}
terrain.UpdateMeshAndShape();
terrain.NotifyPropertyListChanged();
}
UpdateEditToolMesh(terrain, tiles);
} else {
ClearEditToolMesh();
}
}
// if (_isSelecting && (ev is InputEventMouseButton { ButtonIndex: MouseButton.Left, Pressed: false })) {
// _isSelecting = false;
// GetViewport().SetInputAsHandled();
// return;
// }
// if ((ev is InputEventMouseButton { ButtonIndex: var wheel, Pressed: var pressed, ShiftPressed: true })
// && (wheel is MouseButton.WheelUp or MouseButton.WheelDown) && (_selection != null))
// {
// // NOTE: Potential bug in the Godot editor?
// // Does it zoom both when mouse wheel is "pressed" and "released"?
// // Because just cancelling one of them still causes zooming to occur.
// GetViewport().SetInputAsHandled();
// if (!pressed) return;
// const float AdjustHeight = 0.5f;
// var amount = (wheel == MouseButton.WheelUp)
// ? AdjustHeight : -AdjustHeight;
// var selection = TileRegion.From(_selection.Value);
// // Raise connected corners.
// foreach (var innerCorner in Enum.GetValues<Corner>()) {
// var outerCorner = innerCorner.GetOpposite();
// var innerPos = selection.GetTileFor(innerCorner);
// var outerPos = innerPos.GetNeighbor(innerCorner);
// var outerTile = terrain.GetTile(outerPos);
// var innerHeight = terrain.GetTile(innerPos).Height[innerCorner];
// var outerHeight = outerTile.Height[outerCorner];
// if (IsEqualApprox(outerHeight, innerHeight)) {
// outerTile.Height[outerCorner] = innerHeight + amount;
// terrain.SetTile(outerPos, outerTile);
// }
// }
// // Raise connected sides.
// foreach (var side in Enum.GetValues<Side>()) {
// foreach (var innerPos in selection.GetTilesFor(side)) {
// var outerPos = innerPos.GetNeighbor(side);
// var innerTile = terrain.GetTile(innerPos);
// var outerTile = terrain.GetTile(outerPos);
// var (innerCorner1, innerCorner2) = side.GetCorners();
// var (outerCorner1, outerCorner2) = side.GetOpposite().GetCorners();
// var changed = false;
// var matchingCorners = new[]{ (innerCorner1, outerCorner1), (innerCorner2, outerCorner2) };
// foreach (var (innerCorner, outerCorner) in matchingCorners) {
// var innerHeight = innerTile.Height[innerCorner];
// var outerHeight = outerTile.Height[outerCorner];
// if (IsEqualApprox(outerHeight, innerHeight)) {
// outerTile.Height[outerCorner] = innerHeight + amount;
// changed = true;
// }
// }
// if (changed) terrain.SetTile(outerPos, outerTile);
// }
// }
// // Raise selected tiles themselves.
// foreach (var pos in selection.GetAllTiles()) {
// var tile = terrain.GetTile(pos);
// tile.Height.Adjust(amount);
// terrain.SetTile(pos, tile);
// }
// terrain.UpdateMeshAndShape();
// terrain.NotifyPropertyListChanged();
// return;
// }
// if ((ev is InputEventMouseButton { ButtonIndex: var wheel2, Pressed: var pressed2, CtrlPressed: true })
// && (wheel2 is MouseButton.WheelUp or MouseButton.WheelDown) && (_selection != null))
// {
// GetViewport().SetInputAsHandled();
// if (!pressed2) return;
// var amount = (wheel2 == MouseButton.WheelUp) ? 1 : -1;
// var selection = TileRegion.From(_selection.Value);
// foreach (var pos in selection.GetAllTiles()) {
// var tile = terrain.GetTile(pos);
// tile.TexturePrimary = PosMod(tile.TexturePrimary + amount, 4);
// terrain.SetTile(pos, tile);
// }
// terrain.UpdateMeshAndShape();
// terrain.NotifyPropertyListChanged();
// return;
// }
// if (ev is InputEventMouseMotion)
// _unhandledMotion = true;
// if ((ev is InputEventMouse mouse) && viewport.GetVisibleRect().HasPoint(mouse.Position))
// OnInputRayCastTerrain(terrain, mouse);
}
void UpdateEditToolMesh(Terrain terrain, IEnumerable<TilePos> tiles)
@ -255,4 +205,13 @@ public partial class TerrainEditingControls
return (tile, corner);
}
static readonly Dictionary<Corner, (int X, int Y, Corner Opposite)[]> _offsetLookup = new(){
[Corner.TopLeft ] = [(-1, -1, Corner.BottomRight), (-1, 0, Corner.TopRight ), (0, -1, Corner.BottomLeft )],
[Corner.TopRight ] = [(+1, -1, Corner.BottomLeft ), (+1, 0, Corner.TopLeft ), (0, -1, Corner.BottomRight)],
[Corner.BottomRight] = [(+1, +1, Corner.TopLeft ), (+1, 0, Corner.BottomLeft ), (0, +1, Corner.TopRight )],
[Corner.BottomLeft ] = [(-1, +1, Corner.TopRight ), (-1, 0, Corner.BottomRight), (0, +1, Corner.TopLeft )],
};
static IEnumerable<(TilePos, Corner)> GetNeighbors(TilePos pos, Corner corner)
=> _offsetLookup[corner].Select(e => (new TilePos(pos.X + e.X, pos.Y + e.Y), e.Opposite));
}

Loading…
Cancel
Save