使用Godot引擎制作3D上位机界面
本文介绍了如何使用Godot游戏引擎创建与PLC设备通信的动态3D场景
目录
开始
Godot作为一款游戏引擎在MIT许可证下是完全免费和开源的,可以使用NuGet包来添加PLC通讯库实现在3D场景中的设备状态显示、动态变化。
1.新建项目
下载.NET版本的Godot引擎
新建项目后选择编辑器选项卡-编辑器设置-常规-.NET-编辑器里External Editor
属性选择脚本代码的编辑器(这里选择Visual Studio)
打开Visual Studio,在拓展-管理拓展中搜索“Force UTF-8”安装该拓展:
3.新建3D场景
添加新的3D场景,将设备部件的dae模型文件导入3D根节点下,dae模型文件会转化为Node3D节点:
之后分别加入Camera3D
相机节点和DirectionalLight3D
光照节点,勾选3D视图中的预览按钮,调整相机和光照的角度位置到合适:
调整完成后Ctrl+S保存场景:
2.新建2D场景
点击2D场景创建根节点:
在根节点中分别添加:SubViewport
、Control
、Sprite2D
子节点:
在Sprite2D
的属性Texture
中,选择新建ViewportTexture
:
选择刚才创建的SubViewport
节点,并将Sprite2D
移动到合适的位置:
调整SubViewport
的Size大小、启用Transparent
:
将之前保存的3D场景拖进SubViewport
节点中:
可以看到Sprite2D
节点显示出了3D场景:
接下来在Control
节点下根据PLC程序的需要添加CheckButton
Button
Label
LineEdit
等按钮、开关、文本控件:
4.新建2D脚本
点击2D场景的根节点右键添加脚本:
脚本语言选择C#:
如果提前在编辑器选项卡里设置脚本编辑器为Visual Studio的话,创建脚本后会自动打开Visual Studio:
在Visual Studio可以直接通过 项目-管理NuGet程序包 下载对应PLC的通讯NuGet程序包:
5.编辑脚本
5.1添加脚本中要用到的节点变量
public partial class 2D场景名称 : Node2D
{
private Vector3 velocity1, velocity2 = Vector3.Zero;//3D位置坐标
private CheckButton ChBut;//CheckButton控件
private Node3D But,Tray,Float;//3D场景中的Node3D节点
private Button LeftBut,RightBut,UpBut,DownBut,SUpBut,SDownBut,Conbut;//按钮控件
private Label MYLabel;//文本
private LineEdit Text1, Text2;//编辑文本行
// Called when the node enters the scene tree for the first time.
public override void _Ready()
{}
// Called every frame. 'delta' is the elapsed time since the previous frame.
public override void _Process(double delta)
{}
}
5.2在脚本的_Ready()动作中给节点变量赋值
public override void _Ready()
{
ChBut = GetNode<CheckButton>("Control/CheckButton");
But = GetNode<Node3D>("SubViewport/3DView/前护罩");
Conbut = GetNode<Button>("Control/Button");
LeftBut = GetNode<Button>("Control/GridContainer/Button");
RightBut = GetNode<Button>("Control/GridContainer/Button2");
UpBut = GetNode<Button>("Control/GridContainer/Button3");
DownBut = GetNode<Button>("Control/GridContainer/Button4");
SUpBut = GetNode<Button>("Control/GridContainer/Button5");
SDownBut = GetNode<Button>("Control/GridContainer/Button6");
Tray = GetNode<Node3D>("SubViewport/3DView/载板");
Float = GetNode<Node3D>("SubViewport/3DView/升降台");
MYLabel = GetNode<Label>("Control/Label");
Text1 = GetNode<LineEdit>("Control/GridContainer/LineEdit");
Text2 = GetNode<LineEdit>("Control/GridContainer/LineEdit2");
acceptDialog = GetNode<AcceptDialog>("AcceptDialog");
Conbut.Pressed += Connect;
}
private void Connect()
{
ConPlc.ConnectPlc();
}
以3D场景中的载板模型为例,它的路径为:3DView/载板
而在2D场景中,载板所处3D场景的节点路径为:Node2D/SubViewport/3DView
综合两条路径,省略掉脚本本身所处的节点,可以在脚本中获取载板模型所处的Node3D节点:
Tray = GetNode<Node3D>("SubViewport/3DView/载板");
5.3在脚本的_Process()动作中进行画面更新
public override void _Process(double delta)
{
DataValueRead dataValueRead = new DataValueRead();
dataValueRead.CacheData(dataValueRead.ReadValue);//读取PLC中的变量参数
But.Visible = !ChBut.ButtonPressed;//控制节点是否显示
velocity1.X = (float)(dataValueRead.ReadValue.D1 / 100);
velocity1.Y = (float)(dataValueRead.ReadValue.D3 / 100);
Tray.Position = velocity1;//更新载板模型位置
velocity2.Y = (float)(dataValueRead.ReadValue.D3 / 100);
Float.Position = velocity2;//更新平台模型位置
string Text = "当前横移位置:" + dataValueRead.ReadValue.D1.ToString("F2") + "\r\n";
Text += "当前横移速度:" + dataValueRead.ReadValue.D2.ToString("F2") + "\r\n";
Text += "当前升降位置:" + dataValueRead.ReadValue.D3.ToString("F2") + "\r\n";
Text += "当前升降速度:" + dataValueRead.ReadValue.D4.ToString("F2") + "\r\n";
MYLabel.Text = Text;//更新显示文本
dataValueRead.WriteValue = dataValueRead.ReadValue;
dataValueRead.WriteValue.B4 = LeftBut.ButtonPressed;
dataValueRead.WriteValue.B5 = RightBut.ButtonPressed;
dataValueRead.WriteValue.B10 = UpBut.ButtonPressed;
dataValueRead.WriteValue.B11 = DownBut.ButtonPressed;
dataValueRead.WriteValue.B12 = SUpBut.ButtonPressed;
dataValueRead.WriteValue.B13 = SDownBut.ButtonPressed;
if(Text1.Text != null)
{
dataValueRead.WriteValue.F1 = float.Parse(Text1.Text);
}
if(Text2.Text != null)
{
dataValueRead.WriteValue.F2 = float.Parse(Text2.Text);
}
dataValueRead.WriteData(dataValueRead.WriteValue);//向PLC中写入当前参数
}
6.读写PLC变量
PLC重连:
using S7.Net;
internal class ConPlc
{
internal static Plc plc = new Plc(CpuType.S71500, "192.168.0.1", 0, 1);
internal static bool ReConPlc = false;
internal static void ConnectPlc()
{
try
{
plc.Open();
}
catch
{
MainView.acceptDialog.Visible = true;
ReConPlc = true;
}
}
}
读写PLC变量:
internal class DataValueRead
{
internal DataStatic WriteValue = new DataStatic();
internal DataStatic ReadValue = new DataStatic();
public void CacheData(DataStatic DR)
{
try
{
if (ConPlc.plc.IsConnected)
{
ConPlc.plc.ReadClass(DR, 3, 0);
}
}
catch ()
{
}
}
public void WriteData(DataStatic DR)
{
try
{
if (ConPlc.plc.IsConnected)
{
ConPlc.plc.WriteClass(DR, 3, 0);
}
}
catch ()
{
}
}
}
定义结构体:
internal class DataStatic
{
public bool B1 { get; set; }
public bool B2 { get; set; }
public bool B3 { get; set; }
public bool B4 { get; set; }//点动前进
public bool B5 { get; set; }//点动后退
public float F1 { get; set; }//横移点动速度
public double D1 { get; set; }//横移当前位置
public double D2 { get; set; }//横移当前速度
public bool B6 { get; set; }
public bool B7 { get; set; }
public bool B8 { get; set; }
public bool B9 { get; set; }
public bool B10 { get; set; }//点动上升
public bool B11 { get; set; }//点动下降
public float F2 { get; set; }//升降速度
public double D3 { get; set; }//升降当前位置
public double D4 { get; set; }//升降当前速度
public bool B12 { get; set; }//步进上升
public bool B13 { get; set; }//步进下降
public float F3 { get; set; }
public float F4 { get; set; }
}
7.运行效果
按F5运行项目DEBUG:
250528演示
更多推荐
所有评论(0)