2.5D Editor Viewport for Mono C#

This commit is contained in:
Aaron Franke
2020-03-01 03:08:12 -05:00
parent cc68af17af
commit d1ba41da5d
11 changed files with 835 additions and 23 deletions

View File

@@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
@@ -53,6 +53,7 @@
</ItemGroup>
<ItemGroup>
<Compile Include="addons\node25d-cs\Basis25D.cs" />
<Compile Include="addons\node25d-cs\main_screen\Gizmo25D.cs" />
<Compile Include="addons\node25d-cs\Node25D.cs" />
<Compile Include="addons\node25d-cs\ShadowMath25D.cs" />
<Compile Include="addons\node25d-cs\Transform25D.cs" />
@@ -63,4 +64,4 @@
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
</Project>
</Project>

View File

@@ -83,6 +83,10 @@ public class Node25D : Node2D, IComparable<Node25D>
/// </summary>
protected void Node25DProcess()
{
if (transform25D.basis == new Basis25D())
{
SetViewMode(0);
}
CheckViewMode();
if (spatialNode != null)
{
@@ -92,34 +96,60 @@ public class Node25D : Node2D, IComparable<Node25D>
{
spatialNode = GetChild<Spatial>(0);
}
GlobalPosition = transform25D.FlatPosition;
}
public void SetViewMode(int viewModeIndex)
{
switch (viewModeIndex)
{
case 0:
transform25D.basis = Basis25D.FortyFive * SCALE;
break;
case 1:
transform25D.basis = Basis25D.Isometric * SCALE;
break;
case 2:
transform25D.basis = Basis25D.TopDown * SCALE;
break;
case 3:
transform25D.basis = Basis25D.FrontSide * SCALE;
break;
case 4:
transform25D.basis = Basis25D.ObliqueY * SCALE;
break;
case 5:
transform25D.basis = Basis25D.ObliqueZ * SCALE;
break;
}
}
private void CheckViewMode()
{
if (Input.IsActionJustPressed("top_down_mode"))
if (Input.IsActionJustPressed("forty_five_mode"))
{
transform25D.basis = Basis25D.TopDown * SCALE;
}
else if (Input.IsActionJustPressed("front_side_mode"))
{
transform25D.basis = Basis25D.FrontSide * SCALE;
}
else if (Input.IsActionJustPressed("forty_five_mode"))
{
transform25D.basis = Basis25D.FortyFive * SCALE;
SetViewMode(0);
}
else if (Input.IsActionJustPressed("isometric_mode"))
{
transform25D.basis = Basis25D.Isometric * SCALE;
SetViewMode(1);
}
else if (Input.IsActionJustPressed("top_down_mode"))
{
SetViewMode(2);
}
else if (Input.IsActionJustPressed("front_side_mode"))
{
SetViewMode(3);
}
else if (Input.IsActionJustPressed("oblique_y_mode"))
{
transform25D.basis = Basis25D.ObliqueY * SCALE;
SetViewMode(4);
}
else if (Input.IsActionJustPressed("oblique_z_mode"))
{
transform25D.basis = Basis25D.ObliqueZ * SCALE;
SetViewMode(5);
}
}

View File

@@ -0,0 +1,230 @@
using Godot;
// This is identical to the GDScript version, yet it doesn't work.
[Tool]
public class Viewport25D : Control
{
private int zoomLevel = 0;
private bool isPanning = false;
private Vector2 panCenter;
private Vector2 viewportCenter;
private int viewModeIndex = 0;
// The type or namespace name 'EditorInterface' could not be found (are you missing a using directive or an assembly reference?)
// No idea why this error shows up in VS Code. It builds fine...
public EditorInterface editorInterface; // Set in node25d_plugin.gd
private bool moving = false;
private Viewport viewport2d;
private Viewport viewportOverlay;
private ButtonGroup viewModeButtonGroup;
private Label zoomLabel;
private PackedScene gizmo25dScene;
public async override void _Ready()
{
// Give Godot a chance to fully load the scene. Should take two frames.
//yield(get_tree(), "idle_frame");
//yield(get_tree(), "idle_frame");
await ToSignal(GetTree(), "idle_frame");
await ToSignal(GetTree(), "idle_frame");
var editedSceneRoot = GetTree().EditedSceneRoot;
if (editedSceneRoot == null)
{
// Godot hasn't finished loading yet, so try loading the plugin again.
//editorInterface.SetPluginEnabled("node25d", false);
//editorInterface.SetPluginEnabled("node25d", true);
return;
}
// Alright, we're loaded up. Now check if we have a valid world and assign it.
var world2d = editedSceneRoot.GetViewport().World2d;
if (world2d == GetViewport().World2d)
{
return; // This is the MainScreen25D scene opened in the editor!
}
viewport2d.World2d = world2d;
// Onready vars.
viewport2d = GetNode<Viewport>("Viewport2D");
viewportOverlay = GetNode<Viewport>("ViewportOverlay");
viewModeButtonGroup = GetParent().GetNode("TopBar").GetNode("ViewModeButtons").GetNode<Button>("45Degree").Group;
zoomLabel = GetParent().GetNode("TopBar").GetNode("Zoom").GetNode<Label>("ZoomPercent");
gizmo25dScene = ResourceLoader.Load<PackedScene>("res://addons/node25d/main_screen/gizmo_25d.tscn");
}
public override void _Process(float delta)
{
if (editorInterface == null) // Something's not right... bail!
{
return;
}
// View mode polling.
var viewModeChangedThisFrame = false;
var newViewMode = viewModeButtonGroup.GetPressedButton().GetIndex();
if (viewModeIndex != newViewMode)
{
viewModeIndex = newViewMode;
viewModeChangedThisFrame = true;
RecursiveChangeViewMode(GetTree().EditedSceneRoot);
}
// Zooming.
if (Input.IsMouseButtonPressed((int)ButtonList.WheelUp))
{
zoomLevel += 1;
}
else if (Input.IsMouseButtonPressed((int)ButtonList.WheelDown))
{
zoomLevel -= 1;
}
float zoom = GetZoomAmount();
// Viewport size.
Vector2 size = GetGlobalRect().Size;
viewport2d.Size = size;
// Viewport transform.
Transform2D viewportTrans = Transform2D.Identity;
viewportTrans.x *= zoom;
viewportTrans.y *= zoom;
viewportTrans.origin = viewportTrans.BasisXform(viewportCenter) + size / 2;
viewport2d.CanvasTransform = viewportTrans;
viewportOverlay.CanvasTransform = viewportTrans;
// Delete unused gizmos.
var selection = editorInterface.GetSelection().GetSelectedNodes();
var overlayChildren = viewportOverlay.GetChildren();
foreach (Gizmo25D overlayChild in overlayChildren)
{
bool contains = false;
foreach (Node selected in selection)
{
if (selected == overlayChild.node25d && !viewModeChangedThisFrame)
{
contains = true;
}
}
if (!contains)
{
overlayChild.QueueFree();
}
}
// Add new gizmos.
foreach (Node sel in selection)
{
if (sel is Node25D selected)
{
var newNode = true;
foreach (Gizmo25D overlayChild2 in overlayChildren)
{
if (selected == overlayChild2.node25d)
{
newNode = false;
}
}
if (newNode)
{
Gizmo25D gizmo = (Gizmo25D)gizmo25dScene.Instance();
viewportOverlay.AddChild(gizmo);
gizmo.node25d = selected;
gizmo.Initialize();
}
}
}
}
// This only accepts input when the mouse is inside of the 2.5D viewport.
public override void _GuiInput(InputEvent inputEvent)
{
if (inputEvent is InputEventMouseButton mouseButtonEvent)
{
if (mouseButtonEvent.IsPressed())
{
if ((ButtonList)mouseButtonEvent.ButtonIndex == ButtonList.WheelUp)
{
zoomLevel += 1;
AcceptEvent();
}
else if ((ButtonList)mouseButtonEvent.ButtonIndex == ButtonList.WheelDown)
{
zoomLevel -= 1;
AcceptEvent();
}
else if ((ButtonList)mouseButtonEvent.ButtonIndex == ButtonList.Middle)
{
isPanning = true;
panCenter = viewportCenter - mouseButtonEvent.Position;
AcceptEvent();
}
else if ((ButtonList)mouseButtonEvent.ButtonIndex == ButtonList.Left)
{
var overlayChildren2 = viewportOverlay.GetChildren();
foreach (Gizmo25D overlayChild in overlayChildren2)
{
overlayChild.wantsToMove = true;
}
AcceptEvent();
}
}
else if ((ButtonList)mouseButtonEvent.ButtonIndex == ButtonList.Middle)
{
isPanning = false;
AcceptEvent();
}
else if ((ButtonList)mouseButtonEvent.ButtonIndex == ButtonList.Left)
{
var overlayChildren3 = viewportOverlay.GetChildren();
foreach (Gizmo25D overlayChild in overlayChildren3)
{
overlayChild.wantsToMove = false;
}
AcceptEvent();
}
}
else if (inputEvent is InputEventMouseMotion mouseEvent)
{
if (isPanning)
{
viewportCenter = panCenter + mouseEvent.Position;
AcceptEvent();
}
}
}
public void RecursiveChangeViewMode(Node currentNode)
{
// TODO
if (currentNode.HasMethod("SetViewMode"))
{
//currentNode.SetViewMode(viewModeIndex);
}
foreach (Node child in currentNode.GetChildren())
{
RecursiveChangeViewMode(child);
}
}
private float GetZoomAmount()
{
float zoomAmount = Mathf.Pow(1.05476607648f, zoomLevel); // 13th root of 2
zoomLabel.Text = Mathf.Round(zoomAmount * 1000) / 10 + "%";
return zoomAmount;
}
public void OnZoomOutPressed()
{
zoomLevel -= 1;
}
public void OnZoomInPressed()
{
zoomLevel += 1;
}
public void OnZoomResetPressed()
{
zoomLevel = 0;
}
}

View File

@@ -0,0 +1,168 @@
using Godot;
// This is identical to the GDScript version, yet it doesn't work.
[Tool]
public class Gizmo25D : Node2D
{
// Not pixel perfect for all axes in all modes, but works well enough.
// Rounding is not done until after the movement is finished.
private const bool RoughlyRoundToPixels = true;
// Set when the node is created.
public Node25D node25d;
public Spatial spatialNode;
// Input from Viewport25D, represents if the mouse is clicked.
public bool wantsToMove = false;
// Used to control the state of movement.
private bool _moving = false;
private Vector2 _startPosition = Vector2.Zero;
// Stores state of closest or currently used axis.
private int dominantAxis;
private Node2D linesRoot;
private Line2D[] lines = new Line2D[3];
public override void _Ready()
{
linesRoot = GetChild<Node2D>(0);
lines[0] = linesRoot.GetChild<Line2D>(0);
lines[1] = linesRoot.GetChild<Line2D>(1);
lines[2] = linesRoot.GetChild<Line2D>(2);
}
public override void _Process(float delta)
{
if (lines == null)
{
return; // Somehow this node hasn't been set up yet.
}
if (node25d == null)
{
return; // We're most likely viewing the Gizmo25D scene.
}
// While getting the mouse position works in any viewport, it doesn't do
// anything significant unless the mouse is in the 2.5D viewport.
Vector2 mousePosition = GetLocalMousePosition();
if (!_moving)
{
// If the mouse is farther than this many pixels, it won't grab anything.
float closestDistance = 20.0f;
dominantAxis = -1;
for (int i = 0; i < 3; i++)
{
// Unrelated, but needs a loop too.
Color modulateLine = lines[i].Modulate;
modulateLine.a = 0.8f;
lines[i].Modulate = modulateLine;
var distance = DistanceToSegmentAtIndex(i, mousePosition);
if (distance < closestDistance)
{
closestDistance = distance;
dominantAxis = i;
}
}
if (dominantAxis == -1)
{
// If we're not hovering over a line, ensure they are placed correctly.
linesRoot.GlobalPosition = node25d.GlobalPosition;
return;
}
}
Color modulate = lines[dominantAxis].Modulate;
modulate.a = 1;
lines[dominantAxis].Modulate = modulate;
if (!wantsToMove)
{
_moving = false;
}
else if (wantsToMove && !_moving)
{
_moving = true;
_startPosition = mousePosition;
}
if (_moving)
{
// Change modulate of unselected axes.
modulate = lines[(dominantAxis + 1) % 3].Modulate;
modulate.a = 0.5f;
lines[(dominantAxis + 1) % 3].Modulate = modulate;
lines[(dominantAxis + 2) % 3].Modulate = modulate;
// Calculate mouse movement and reset for next frame.
var mouseDiff = mousePosition - _startPosition;
_startPosition = mousePosition;
// Calculate movement.
var projectedDiff = mouseDiff.Project(lines[dominantAxis].Points[1]);
var movement = projectedDiff.Length() / Node25D.SCALE;
if (Mathf.IsEqualApprox(Mathf.Pi, projectedDiff.AngleTo(lines[dominantAxis].Points[1])))
{
movement *= -1;
}
// Apply movement.
Transform t = spatialNode.Transform;
t.origin += t.basis[dominantAxis] * movement;
spatialNode.Transform = t;
}
else
{
// Make sure the gizmo is located at the object.
GlobalPosition = node25d.GlobalPosition;
if (RoughlyRoundToPixels)
{
Transform t = spatialNode.Transform;
t.origin = (t.origin * Node25D.SCALE).Round() / Node25D.SCALE;
spatialNode.Transform = t;
}
}
// Move the gizmo lines appropriately.
linesRoot.GlobalPosition = node25d.GlobalPosition;
node25d.PropertyListChangedNotify();
}
// Initializes after _ready due to the onready vars, called manually in Viewport25D.gd.
// Sets up the points based on the basis values of the Node25D.
public void Initialize()
{
var basis = node25d.Basis25D;
for (int i = 0; i < 3; i++)
{
lines[i].Points[1] = basis[i] * 3;
}
GlobalPosition = node25d.GlobalPosition;
spatialNode = node25d.GetChild<Spatial>(0);
}
// Figures out if the mouse is very close to a segment. This method is
// specialized for this script, it assumes that each segment starts at
// (0, 0) and it provides a deadzone around the origin.
private float DistanceToSegmentAtIndex(int index, Vector2 point)
{
if (lines == null)
{
return Mathf.Inf;
}
if (point.LengthSquared() < 400)
{
return Mathf.Inf;
}
Vector2 segmentEnd = lines[index].Points[1];
float lengthSquared = segmentEnd.LengthSquared();
if (lengthSquared < 400)
{
return Mathf.Inf;
}
var t = Mathf.Clamp(point.Dot(segmentEnd) / lengthSquared, 0, 1);
var projection = t * segmentEnd;
return point.DistanceTo(projection);
}
}

View File

@@ -0,0 +1,23 @@
[gd_scene load_steps=2 format=2]
[ext_resource path="res://addons/node25d-cs/main_screen/Gizmo25D.cs" type="Script" id=1]
[node name="Gizmo25D" type="Node2D"]
script = ExtResource( 1 )
[node name="Lines" type="Node2D" parent="."]
[node name="X" type="Line2D" parent="Lines"]
modulate = Color( 1, 1, 1, 0.8 )
points = PoolVector2Array( 0, 0, 100, 0 )
default_color = Color( 0.91, 0.273, 0, 1 )
[node name="Y" type="Line2D" parent="Lines"]
modulate = Color( 1, 1, 1, 0.8 )
points = PoolVector2Array( 0, 0, 0, -100 )
default_color = Color( 0, 0.91, 0.273, 1 )
[node name="Z" type="Line2D" parent="Lines"]
modulate = Color( 1, 1, 1, 0.8 )
points = PoolVector2Array( 0, 0, 0, 100 )
default_color = Color( 0.3, 0, 1, 1 )

View File

@@ -0,0 +1,173 @@
[gd_scene load_steps=5 format=2]
[ext_resource path="res://addons/node25d-cs/main_screen/viewport_25d.gd" type="Script" id=1]
[ext_resource path="res://addons/node25d-cs/main_screen/view_mode_button_group.tres" type="ButtonGroup" id=2]
[sub_resource type="ViewportTexture" id=1]
viewport_path = NodePath("Viewport25D/Viewport2D")
[sub_resource type="ViewportTexture" id=2]
viewport_path = NodePath("Viewport25D/ViewportOverlay")
[node name="MainScreen25D" type="VBoxContainer"]
anchor_right = 1.0
anchor_bottom = 1.0
size_flags_horizontal = 3
size_flags_vertical = 3
__meta__ = {
"_edit_use_anchors_": false
}
[node name="TopBar" type="HBoxContainer" parent="."]
margin_right = 1600.0
margin_bottom = 32.0
rect_min_size = Vector2( 0, 32 )
size_flags_horizontal = 3
[node name="ViewModeButtons" type="HBoxContainer" parent="TopBar"]
margin_right = 798.0
margin_bottom = 32.0
size_flags_horizontal = 3
[node name="45Degree" type="CheckBox" parent="TopBar/ViewModeButtons"]
margin_right = 94.0
margin_bottom = 32.0
pressed = true
group = ExtResource( 2 )
text = "45 Degree"
__meta__ = {
"_edit_use_anchors_": false
}
[node name="Isometric" type="CheckBox" parent="TopBar/ViewModeButtons"]
margin_left = 98.0
margin_right = 188.0
margin_bottom = 32.0
group = ExtResource( 2 )
text = "Isometric"
__meta__ = {
"_edit_use_anchors_": false
}
[node name="TopDown" type="CheckBox" parent="TopBar/ViewModeButtons"]
margin_left = 192.0
margin_right = 283.0
margin_bottom = 32.0
group = ExtResource( 2 )
text = "Top Down"
__meta__ = {
"_edit_use_anchors_": false
}
[node name="FrontSide" type="CheckBox" parent="TopBar/ViewModeButtons"]
margin_left = 287.0
margin_right = 379.0
margin_bottom = 32.0
group = ExtResource( 2 )
text = "Front Side"
__meta__ = {
"_edit_use_anchors_": false
}
[node name="ObliqueY" type="CheckBox" parent="TopBar/ViewModeButtons"]
margin_left = 383.0
margin_right = 473.0
margin_bottom = 32.0
group = ExtResource( 2 )
text = "Oblique Y"
__meta__ = {
"_edit_use_anchors_": false
}
[node name="ObliqueZ" type="CheckBox" parent="TopBar/ViewModeButtons"]
margin_left = 477.0
margin_right = 568.0
margin_bottom = 32.0
group = ExtResource( 2 )
text = "Oblique Z"
__meta__ = {
"_edit_use_anchors_": false
}
[node name="Zoom" type="HBoxContainer" parent="TopBar"]
margin_left = 802.0
margin_right = 1600.0
margin_bottom = 32.0
size_flags_horizontal = 3
alignment = 2
[node name="ZoomOut" type="Button" parent="TopBar/Zoom"]
margin_left = 680.0
margin_right = 710.0
margin_bottom = 32.0
rect_min_size = Vector2( 30, 0 )
text = "-"
[node name="ZoomPercent" type="Label" parent="TopBar/Zoom"]
margin_left = 714.0
margin_top = 9.0
margin_right = 764.0
margin_bottom = 23.0
rect_min_size = Vector2( 50, 0 )
text = "100%"
align = 1
clip_text = true
[node name="ZoomReset" type="Button" parent="TopBar/Zoom/ZoomPercent"]
modulate = Color( 1, 1, 1, 0 )
anchor_right = 1.0
anchor_bottom = 1.0
__meta__ = {
"_edit_use_anchors_": false
}
[node name="ZoomIn" type="Button" parent="TopBar/Zoom"]
margin_left = 768.0
margin_right = 798.0
margin_bottom = 32.0
rect_min_size = Vector2( 30, 0 )
text = "+"
[node name="Viewport25D" type="ColorRect" parent="."]
margin_top = 36.0
margin_right = 1600.0
margin_bottom = 900.0
rect_clip_content = true
size_flags_horizontal = 3
size_flags_vertical = 3
color = Color( 0.301961, 0.301961, 0.301961, 1 )
script = ExtResource( 1 )
[node name="Viewport2D" type="Viewport" parent="Viewport25D"]
size = Vector2( 1600, 864 )
transparent_bg = true
disable_3d = true
usage = 1
render_target_v_flip = true
[node name="ViewportOverlay" type="Viewport" parent="Viewport25D"]
size = Vector2( 1600, 864 )
transparent_bg = true
disable_3d = true
usage = 1
render_target_v_flip = true
[node name="ViewportTexture" type="TextureRect" parent="Viewport25D"]
anchor_right = 1.0
anchor_bottom = 1.0
texture = SubResource( 1 )
expand = true
__meta__ = {
"_edit_use_anchors_": false
}
[node name="Overlay" type="TextureRect" parent="Viewport25D/ViewportTexture"]
anchor_right = 1.0
anchor_bottom = 1.0
texture = SubResource( 2 )
__meta__ = {
"_edit_use_anchors_": false
}
[connection signal="pressed" from="TopBar/Zoom/ZoomOut" to="Viewport25D" method="_on_ZoomOut_pressed"]
[connection signal="pressed" from="TopBar/Zoom/ZoomPercent/ZoomReset" to="Viewport25D" method="_on_ZoomReset_pressed"]
[connection signal="pressed" from="TopBar/Zoom/ZoomIn" to="Viewport25D" method="_on_ZoomIn_pressed"]

View File

@@ -0,0 +1,3 @@
[gd_resource type="ButtonGroup" format=2]
[resource]

View File

@@ -0,0 +1,149 @@
tool
extends Control
var zoom_level := 0
var is_panning = false
var pan_center: Vector2
var viewport_center: Vector2
var view_mode_index := 0
var editor_interface: EditorInterface # Set in node25d_plugin.gd
var moving = false
onready var viewport_2d = $Viewport2D
onready var viewport_overlay = $ViewportOverlay
onready var view_mode_button_group: ButtonGroup = $"../TopBar/ViewModeButtons/45Degree".group
onready var zoom_label: Label = $"../TopBar/Zoom/ZoomPercent"
onready var gizmo_25d_scene = preload("res://addons/node25d-cs/main_screen/gizmo_25d.tscn")
func _ready():
# Give Godot a chance to fully load the scene. Should take two frames.
yield(get_tree(), "idle_frame")
yield(get_tree(), "idle_frame")
var edited_scene_root = get_tree().edited_scene_root
if !edited_scene_root:
# Godot hasn't finished loading yet, so try loading the plugin again.
editor_interface.set_plugin_enabled("node25d", false)
editor_interface.set_plugin_enabled("node25d", true)
return
# Alright, we're loaded up. Now check if we have a valid world and assign it.
var world_2d = edited_scene_root.get_viewport().world_2d
if world_2d == get_viewport().world_2d:
return # This is the MainScreen25D scene opened in the editor!
viewport_2d.world_2d = world_2d
func _process(delta):
if !editor_interface: # Something's not right... bail!
return
# View mode polling.
var view_mode_changed_this_frame = false
var new_view_mode = view_mode_button_group.get_pressed_button().get_index()
if view_mode_index != new_view_mode:
view_mode_index = new_view_mode
view_mode_changed_this_frame = true
_recursive_change_view_mode(get_tree().edited_scene_root)
# Zooming.
if Input.is_mouse_button_pressed(BUTTON_WHEEL_UP):
zoom_level += 1
elif Input.is_mouse_button_pressed(BUTTON_WHEEL_DOWN):
zoom_level -= 1
var zoom = _get_zoom_amount()
# Viewport size.
var size = get_global_rect().size
viewport_2d.size = size
# Viewport transform.
var viewport_trans = Transform2D.IDENTITY
viewport_trans.x *= zoom
viewport_trans.y *= zoom
viewport_trans.origin = viewport_trans.basis_xform(viewport_center) + size / 2
viewport_2d.canvas_transform = viewport_trans
viewport_overlay.canvas_transform = viewport_trans
# Delete unused gizmos.
var selection = editor_interface.get_selection().get_selected_nodes()
var overlay_children = viewport_overlay.get_children()
for overlay_child in overlay_children:
var contains = false
for selected in selection:
if selected == overlay_child.get("node25d") and !view_mode_changed_this_frame:
contains = true
if !contains:
overlay_child.queue_free()
# Add new gizmos.
for selected in selection:
if selected.has_method("Node25DReady"):
var new = true
for overlay_child in overlay_children:
if selected == overlay_child.get("node25d"):
new = false
if new:
var gizmo = gizmo_25d_scene.instance()
viewport_overlay.add_child(gizmo)
gizmo.set("node25d", selected)
gizmo.call("Initialize")
# This only accepts input when the mouse is inside of the 2.5D viewport.
func _gui_input(event):
if event is InputEventMouseButton:
if event.is_pressed():
if event.button_index == BUTTON_WHEEL_UP:
zoom_level += 1
accept_event()
elif event.button_index == BUTTON_WHEEL_DOWN:
zoom_level -= 1
accept_event()
elif event.button_index == BUTTON_MIDDLE:
is_panning = true
pan_center = viewport_center - event.position
accept_event()
elif event.button_index == BUTTON_LEFT:
var overlay_children = viewport_overlay.get_children()
for overlay_child in overlay_children:
overlay_child.set("wantsToMove", true)
accept_event()
elif event.button_index == BUTTON_MIDDLE:
is_panning = false
accept_event()
elif event.button_index == BUTTON_LEFT:
var overlay_children = viewport_overlay.get_children()
for overlay_child in overlay_children:
overlay_child.set("wantsToMove", false)
accept_event()
elif event is InputEventMouseMotion:
if is_panning:
viewport_center = pan_center + event.position
accept_event()
func _recursive_change_view_mode(current_node):
if current_node.has_method("set_view_mode"):
current_node.set_view_mode(view_mode_index) # GDScript.
if current_node.has_method("SetViewMode"):
current_node.call("SetViewMode", view_mode_index) # C#.
for child in current_node.get_children():
_recursive_change_view_mode(child)
func _get_zoom_amount():
var zoom_amount = pow(1.05476607648, zoom_level) # 13th root of 2.
zoom_label.text = str(round(zoom_amount * 1000) / 10) + "%"
return zoom_amount
func _on_ZoomOut_pressed():
zoom_level -= 1
func _on_ZoomIn_pressed():
zoom_level += 1
func _on_ZoomReset_pressed():
zoom_level = 0

View File

@@ -1,14 +1,46 @@
tool
extends EditorPlugin
const MainPanel = preload("res://addons/node25d-cs/main_screen/main_screen_25d.tscn")
var main_panel_instance
func _enter_tree():
# When this plugin node enters tree, add the custom types
main_panel_instance = MainPanel.instance()
#main_panel_instance.get_child(1).set("editorInterface", get_editor_interface()) # For C#
main_panel_instance.get_child(1).editor_interface = get_editor_interface()
# Add the main panel to the editor's main viewport.
get_editor_interface().get_editor_viewport().add_child(main_panel_instance)
# Hide the main panel.
make_visible(false)
# When this plugin node enters tree, add the custom types.
add_custom_type("Node25D", "Node2D", preload("Node25D.cs"), preload("icons/node_25d_icon.png"))
add_custom_type("YSort25D", "Node", preload("YSort25D.cs"), preload("icons/y_sort_25d_icon.png"))
add_custom_type("ShadowMath25D", "KinematicBody", preload("ShadowMath25D.cs"), preload("icons/shadow_math_25d_icon.png"))
func _exit_tree():
# When the plugin node exits the tree, remove the custom types
main_panel_instance.queue_free()
# When the plugin node exits the tree, remove the custom types.
remove_custom_type("ShadowMath25D")
remove_custom_type("YSort25D")
remove_custom_type("Node25D")
func has_main_screen():
return true
func make_visible(visible):
if visible:
main_panel_instance.show()
else:
main_panel_instance.hide()
func get_plugin_name():
return "2.5D"

View File

@@ -26,18 +26,16 @@ extents = Vector3( 5, 0.5, 5 )
[node name="Overlay" parent="." instance=ExtResource( 3 )]
[node name="Player25D" parent="." instance=ExtResource( 4 )]
position = Vector2( 0, -226.274 )
z_index = -3952
[node name="Shadow25D" parent="." instance=ExtResource( 5 )]
visible = true
position = Vector2( 1.00261e-06, 11.2685 )
z_index = -3958
spatialPosition = Vector3( 3.13315e-08, -0.498, 3.13315e-08 )
position = Vector2( 0, -226.274 )
z_index = -3954
[node name="Platform0" type="Node2D" parent="."]
position = Vector2( -256, -113.137 )
z_index = -3954
z_index = -3956
script = ExtResource( 6 )
__meta__ = {
"_editor_icon": ExtResource( 7 )
@@ -62,7 +60,7 @@ script = ExtResource( 9 )
[node name="Platform1" type="Node2D" parent="."]
position = Vector2( -256, -339.411 )
z_index = -3956
z_index = -3958
script = ExtResource( 6 )
__meta__ = {
"_editor_icon": ExtResource( 7 )

View File

@@ -5,6 +5,7 @@ using real_t = System.Double;
using real_t = System.Single;
#endif
[Tool]
public class PlayerSprite : Sprite
{
private static Texture _stand = ResourceLoader.Load<Texture>("res://assets/player/textures/stand.png");
@@ -25,6 +26,10 @@ public class PlayerSprite : Sprite
public override void _Process(real_t delta)
{
if (Engine.EditorHint)
{
return; // Don't run this in the editor.
}
SpriteBasis();
bool movement = CheckMovement(); // Always run to get direction, but don't always use return bool.