使用Godot和CSharp开发桌面应用软件

原文链接

欢迎大家对于本站的访问 - AsterCasc

前言

本来我的想法是使用Kotlin Multiplatform来做为安卓端和桌面端应用软件跨平台的解决方案,参考本站前文构建跨平台的客户端界面。但是在撰写和尝试更完整的跨平台应用的时候发现,目前使用Kotlin Multiplatform社区组件选择以及部分组件的兼容性还有编辑器的显示支持上都不够优秀,简单来说遇到了不少的坑,虽然基本都能解决,但是实在不能作为一个具有长期借鉴意义的文章发出(比如可能会介绍蛮多坑,但是这些坑会在之后版本中被修复)。另外由于目前他们还在积极的更新和迭代中,我仍然觉得这是一个对于跨平台应用开发非常值得的选择,在之后他们各个功能都比较完善了,本站会出一个包含源码完整的跨平台应用的实现

想要写跨平台应用的原因也是想给astercasc.com出一个移动&桌面版本的应用程序,一方面看视频听音乐也比较方便(😄),另一方面能相对比较简单地观察到后端服务的状态。个人开发,不考虑其他人的维护性的话,肯定是跨平台的项目性价比更高的,而且也更具有学习价值和有趣。所以既然目前Kotlin Multiplatform不是特别好用的话,由于这个想法也没有特别着急,所以这个东西可以暂时搁置。肯定是不会考虑写两份代码的,比如写一套Kotlin Android写一套Qt,这种就没意义,纯纯在上班,也出不了文章

这个时候就可以考虑一些可能可以实现跨平台,但是即使没实现也有意思的东西了。于是我查了一下清单,发现之前有写过不少做游戏的点子,按照目前的我的时间,做游戏肯定是没空,但是游戏引擎对于跨平台的支持导出也是一种可以尝试的方案,即使最后效果不理想,也可以了解一下游戏开发

游戏开发引擎的选择,我们这里选择Godot,没有选择虚幻的原因是虚幻太大了,这个《大》更多的是对于游戏各种功能的支持,这里我们更希望有个轻量级的工具可以处理,不选择Unity的原因,大伙都知道,就属于懂的都懂了

Which platforms are supported by Godot?

For the editor:

  • Windows
  • macOS
  • Linux, *BSD
  • Android (experimental)
  • Web (experimental)

For exporting your games:

  • Windows
  • macOS
  • Linux, *BSD
  • Android
  • iOS
  • Web

CSharp环境构建

对于我们jetbrains全家桶来说,肯定是使用Rider进行开发的,下载Rider然后根据提示安装环境即可,目前的默认支持为:

.NET VersionRider VersionSupport
.NET SDK 8Rider 2023.3Full support
.NET SDK 7Rider 2022.3Full support
.NET SDK 6Rider 2021.3Full support
.NET SDK 5Rider 2020.3Full support

Godot配置

Godot官网下载所需版本,这里我们选择Godot Engine-.Net版本,然后解压,运行即可

这里有个小坑,Godot获取dotnet不是通过环境变量获取的,也就是说,我们在使用Rider安装运行环境之后,即使加入环境变量中,Godot也无法检测到,即使你的命令行可以调通dotnet --versionGodot获取dotnetWindows下是直接在Program Files里面拿的,所以我们需要将Rider下载的.dotnet复制成Program Files下的dotnet才能让Godot正常工作。当然你如果使用的是Visual Studio就不用这么麻烦了,直接在Visual Studio里面安装就可以直接使用

项目构建

对于Godot而言,虽然官网的介绍比较详细,但是我这里以前端对应来简单再介绍下。整个Godot项目为树状结构,整个树状结构为场景树The scene tree,对应了前端的html标签。在树上场景Scene就像是可复用的前端组件,级联选择器,分页表格等,游戏场景不执着于场景,可以是人物,装饰,武器等。而节点Node就像是我们的基础标签,buttoninput等。最后信号Signal就对应了前端信号,将事件传递给各个组件

这里就是Godot几个核心概念:场景树,场景,节点以及信号。官网有简单游戏的创建流程Your first 2D game,非常详细,我们这里就不再重复了,我们这里以网站首页举例,看看构建一个网站页面需要的工作量,下面的内容以您已完成官网的最佳实践为前提或者对Godot有初步了解

在项目设置中调整基础页面参数,比如初始窗口的宽高,主场景,自定义字体,如果需要使用快捷键也在这里配置,基本配置完成后,我们从基本组件开始,首先是卡片

由于我们这里并不是真的要用这个实现,做个简单的即可,调整后基本代码如下

[gd_scene load_steps=9 format=3 uid="uid://0sffbl8ylhnw"]

[ext_resource type="StyleBox" uid="uid://bawggbd2nu5ye" path="res://style/articlesimplebk.tres" id="1_s1tlr"]
[ext_resource type="StyleBox" uid="uid://bqeox8tc7ff3u" path="res://style/articleinbtn.tres" id="2_qhtdo"]
[ext_resource type="StyleBox" uid="uid://cao5ggt1fjedp" path="res://style/articleinbtn-hover.tres" id="3_4eymw"]

[sub_resource type="StyleBoxEmpty" id="StyleBoxEmpty_fb4l4"]

[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_j0kbe"]
bg_color = Color(0.223529, 0.223529, 0.247059, 1)
corner_radius_top_left = 25
corner_radius_top_right = 25
corner_radius_bottom_right = 25
corner_radius_bottom_left = 25

[sub_resource type="StyleBoxEmpty" id="StyleBoxEmpty_a8ibj"]
content_margin_left = 20.0
content_margin_right = 20.0

[sub_resource type="StyleBoxEmpty" id="StyleBoxEmpty_rjk3e"]
content_margin_left = 20.0
content_margin_top = 60.0
content_margin_right = 20.0
content_margin_bottom = 20.0

[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_1c2hf"]
draw_center = false

[node name="CardOut" type="PanelContainer"]
custom_minimum_size = Vector2(450, 300)
offset_right = 450.0
offset_bottom = 300.0
theme_override_styles/panel = SubResource("StyleBoxEmpty_fb4l4")

[node name="Card" type="PanelContainer" parent="."]
layout_mode = 2
size_flags_vertical = 0
theme_override_styles/panel = ExtResource("1_s1tlr")

[node name="CardContainer" type="MarginContainer" parent="Card"]
custom_minimum_size = Vector2(0, 40)
layout_mode = 2
size_flags_horizontal = 0
size_flags_vertical = 0
theme_override_constants/margin_left = -25
theme_override_constants/margin_top = -25

[node name="CardBgContainer" type="PanelContainer" parent="Card/CardContainer"]
layout_mode = 2
theme_override_styles/panel = SubResource("StyleBoxFlat_j0kbe")

[node name="Title" type="Label" parent="Card/CardContainer/CardBgContainer"]
layout_mode = 2
theme_override_font_sizes/font_size = 25
theme_override_styles/normal = SubResource("StyleBoxEmpty_a8ibj")
text = "this is  a article title"

[node name="CardContentContainer" type="VBoxContainer" parent="Card"]
layout_mode = 2

[node name="CardContent" type="Label" parent="Card/CardContentContainer"]
custom_minimum_size = Vector2(100, 100)
layout_mode = 2
size_flags_vertical = 0
theme_override_colors/font_color = Color(0, 0, 0, 1)
theme_override_font_sizes/font_size = 20
theme_override_styles/normal = SubResource("StyleBoxEmpty_rjk3e")
text = "this is content this is content this is content this is content this is content
this is contentthis is contentthis is content"
autowrap_mode = 3

[node name="Go" type="Button" parent="Card/CardContentContainer"]
layout_mode = 2
size_flags_horizontal = 8
size_flags_vertical = 8
theme_override_colors/font_color = Color(0.972549, 0.972549, 0.972549, 1)
theme_override_font_sizes/font_size = 20
theme_override_styles/normal = ExtResource("2_qhtdo")
theme_override_styles/hover = ExtResource("3_4eymw")
theme_override_styles/pressed = ExtResource("3_4eymw")
theme_override_styles/focus = SubResource("StyleBoxFlat_1c2hf")
text = "更多内容"

这里我们在创建的时候为了复用使用自定义的tres,可以认为是css文件,可以直接导入需要的标签复用,以articlesimplebk.tres为例:

[gd_resource type="StyleBoxFlat" format=3 uid="uid://bawggbd2nu5ye"]

[resource]
content_margin_left = 0.0
content_margin_top = 0.0
content_margin_right = 40.0
content_margin_bottom = 35.0
bg_color = Color(1, 1, 1, 0.784314)
corner_radius_top_left = 25
corner_radius_top_right = 25
corner_radius_bottom_right = 25
corner_radius_bottom_left = 25
shadow_color = Color(1, 1, 1, 0.0784314)
shadow_size = 20

这样一个我们一个基础组件(场景)就制作好了

现在我们写个主场景树:

[gd_scene load_steps=7 format=3 uid="uid://cr14hf5hn4tp5"]

[ext_resource type="Texture2D" uid="uid://bqe782vjeix25" path="res://img/backgroud.png" id="1_51gst"]
[ext_resource type="Script" path="res://YunoDesktop.cs" id="1_ogbat"]
[ext_resource type="StyleBox" uid="uid://cfh1uqw6lpksw" path="res://style/transbk.tres" id="2_gsi10"]
[ext_resource type="Theme" uid="uid://c8f4q4asmagvt" path="res://style/titlelabel.tres" id="3_6cb30"]
[ext_resource type="Script" path="res://HomeProject.cs" id="3_gbua5"]

[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_gnpks"]
bg_color = Color(1, 1, 1, 1)

[node name="YunoDesktop" type="Node"]
script = ExtResource("1_ogbat")

[node name="HomeScroll" type="ScrollContainer" parent="."]
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2

[node name="HomeContainer" type="PanelContainer" parent="HomeScroll"]
layout_mode = 2
size_flags_horizontal = 3
theme_override_styles/panel = SubResource("StyleBoxFlat_gnpks")

[node name="Home" type="VBoxContainer" parent="HomeScroll/HomeContainer"]
layout_mode = 2
size_flags_horizontal = 3
theme_override_constants/separation = 0

[node name="HomeBkColor" type="ColorRect" parent="HomeScroll/HomeContainer/Home"]
layout_mode = 2

[node name="HomeBkImg" type="TextureRect" parent="HomeScroll/HomeContainer/Home"]
layout_mode = 2
texture = ExtResource("1_51gst")
expand_mode = 5

[node name="HomeMain" type="MarginContainer" parent="HomeScroll/HomeContainer/Home"]
layout_mode = 2
theme_override_constants/margin_left = 50
theme_override_constants/margin_top = -200
theme_override_constants/margin_right = 50
theme_override_constants/margin_bottom = 100

[node name="HomeStyle" type="PanelContainer" parent="HomeScroll/HomeContainer/Home/HomeMain"]
layout_mode = 2
theme_override_styles/panel = ExtResource("2_gsi10")

[node name="HomeProject" type="VBoxContainer" parent="HomeScroll/HomeContainer/Home/HomeMain/HomeStyle"]
layout_mode = 2
script = ExtResource("3_gbua5")

[node name="HomeArticle" type="Label" parent="HomeScroll/HomeContainer/Home/HomeMain/HomeStyle/HomeProject"]
layout_mode = 2
theme = ExtResource("3_6cb30")
text = "技术备录"

[node name="HomeArticleContainer" type="HFlowContainer" parent="HomeScroll/HomeContainer/Home/HomeMain/HomeStyle/HomeProject"]
layout_mode = 2
theme_override_constants/h_separation = 100
theme_override_constants/v_separation = 100

[node name="HomeLife" type="Label" parent="HomeScroll/HomeContainer/Home/HomeMain/HomeStyle/HomeProject"]
layout_mode = 2
theme = ExtResource("3_6cb30")
text = "生活题记"

[node name="HomeLifeContainer" type="HFlowContainer" parent="HomeScroll/HomeContainer/Home/HomeMain/HomeStyle/HomeProject"]
layout_mode = 2
theme_override_constants/h_separation = 100
theme_override_constants/v_separation = 100

[node name="ArticleRequest" type="HTTPRequest" parent="HomeScroll/HomeContainer/Home/HomeMain/HomeStyle/HomeProject"]

[node name="LifeRequest" type="HTTPRequest" parent="HomeScroll/HomeContainer/Home/HomeMain/HomeStyle/HomeProject"]

我们需要根据后端请求更新在该场景树上的卡片场景:

using Godot;
using System;
using System.Text;
using System.Text.Encodings.Web;

public partial class HomeProject : VBoxContainer
{
	public override void _Ready()
	{
		HttpRequest articleRequest = GetNode<HttpRequest>("ArticleRequest");
		articleRequest.RequestCompleted += OnArticleReqCompleted;
		articleRequest.Request(ServerInfo.ServerBase.KotomiAddress + "/article/list?articleType=1&offset=0&limit=10");

		HttpRequest lifeRequest = GetNode<HttpRequest>("LifeRequest");
		lifeRequest.RequestCompleted += OnLiftReqCompleted;
		lifeRequest.Request(ServerInfo.ServerBase.KotomiAddress + "/article/list?articleType=2&offset=0&limit=10");
	}

	private void OnArticleReqCompleted(long result, long responseCode, string[] headers, byte[] body)
	{
		rentCard(body, "HomeArticleContainer");
	}

	private void OnLiftReqCompleted(long result, long responseCode, string[] headers, byte[] body)
	{
		rentCard(body, "HomeLifeContainer");
	}

	private void rentCard(byte[] body, string containerName)
	{
		Godot.Collections.Dictionary json = Json.ParseString(Encoding.UTF8.GetString(body)).AsGodotDictionary();
		var articleList = json["data"].AsGodotArray();
		if (articleList.Count > 0)
		{
			var articleContainer = GetNode<HFlowContainer>(containerName);
			var scene = GD.Load<PackedScene>("res://ArticleSimple.tscn");
			for (int count = 0; count < articleList.Count; count++)
			{
				var objDic = articleList[count].AsGodotDictionary();
				var instance = scene.Instantiate();
				var thisLabel = instance.GetNode<Label>("Card/CardContainer/CardBgContainer/Title");
				thisLabel.Text = objDic["articleTitle"].AsString();
				var thisContent = instance.GetNode<Label>("Card/CardContentContainer/CardContent");
				thisContent.Text = objDic["articleBrief"].AsString().Replace("\n", "") + "...\n";
				var thisBtn = instance.GetNode<Button>("Card/CardContentContainer/Go");
				thisBtn.Pressed += () => onPressToReadMore(objDic["id"].AsString());
				articleContainer.AddChild(instance);
			}
		}
	}

	private void onPressToReadMore(string articleId)
	{
		GD.Print(articleId);
		OS.Alert("不支持当前功能,请移步astercasc.com体验完整功能");
	}
}

最后我们运行主场景可以得到:

项目发布

这里我们可以选择发安卓端以及桌面端,桌面端基本直接导出就可以了,安卓端需要填写密钥库,创建后即可发布。经过测试,桌面端基本没有问题,安卓端部分功能在转换之后还是有点问题,但是如果是做游戏应该不影响,因为做游戏一般也用不到侧边栏滑动

最后

全部代码可以在yuno-door-godot找到。可能是我不是很熟练的原因,用godot来模拟web端逻辑上没有什么问题,但有两个痛点,第一个是很多web以及android比较方便就可以实现的功能,由于游戏里面不存在,在转换脚本里面没有处理(比如侧边栏滑动)需要单独处理。第二个是写样式太痛苦了,同样的样式可能web或者android只需要一行,在godot需要迭代两到三层

参考

godot

godotgithub

chickensoft

原文链接

欢迎大家对于本站的访问 - AsterCasc

  • 28
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 我无法准确地回答您的问题,因为我不了解您的开发需求和技能水平。不过我可以告诉您一些关于 Godot 和 Panda3D 的信息,希望能对您有所帮助。 Godot 是一个开源的游戏引擎,它提供了一整套的工具,可以帮助开发者创建 2D 和 3D 游戏。它的功能包括角色控制、物理引擎、动画系统和渲染引擎。Godot 的主要优势在于它提供了许多方便的功能,可以大大简化游戏开发的流程。 Panda3D 是一个开源的 3D 游戏引擎,它使用 Python 作为脚本语言,可以方便地创建 3D 游戏和应用。Panda3D 提供了许多专业级的渲染功能,可以创建高质量的 3D 场景和角色。它也可以与其他库和工具,如 PyOpenGL 和 PyBullet,集成使用。 总的来说,哪个引擎更方便取决于您的个人喜好和技能水平。如果您熟悉 Python,那么 Panda3D 可能会更方便一些。如果您更喜欢可视化的编辑器和图形用户界面,那么 Godot 可能更合适。我建议您可以尝试一下这两个引擎,看 ### 回答2: godot和panda3d都是广泛使用的游戏开发引擎之一,它们都有各自的优点和适用场景。 首先,godot是一款开源的跨平台游戏开发引擎,具有易于上手、简洁的脚本编程和直观的可视化界面编辑器等特点。它支持多种语言编程,例如GDScript、C#和VisualScript等。godot提供了丰富的内置功能和工具,如节点系统、资源管理和物理引擎等,这使得开发者可以快速创建游戏,并且到目前为止,已经有大量的游戏成功使用godot引擎开发和发布。对于有一定编程基础的开发者来说,godot是一个非常方便和强大的选择。 而panda3d是一款高度灵活和强大的游戏开发框架,也是一个可靠的选择。它支持Python语言开发,对于熟悉Python的开发者来说非常友好。panda3d提供了丰富的功能和库,包括3D渲染、物理引擎和音频系统等,同时还有一个强大的社区支持。由于其灵活性,panda3d提供了更多自定义和底层控制的能力,适用于那些对游戏开发有更高要求,且愿意花更多时间和精力来实现特定功能的开发者。 总的来说,godot更适合那些想要快速上手并且希望最大程度利用内置功能和工具的开发者。而panda3d则更适合那些对自定义和灵活性有更高要求的开发者。选择哪个更方便,还要根据个人偏好、开发需求和技术能力来决定。无论选择哪个引擎,都需要一定的学习和实践来熟悉其特点和使用方法。 ### 回答3: 面对选择使用哪个游戏开发引擎,Godot和Panda3D都有不同的优势和便利之处。就方便程度而言,我的观点是Godot相对更为方便。 首先,Godot具有友好的界面和简单易用的工作流程,适合新手和有经验的开发者。它提供了直观的拖放式图形用户界面(GUI),使得添加、编辑和调整游戏对象变得简单。此外,Godot的脚本语言GDScript类似于Python,易于学习和使用,可加快开发速度。它还支持其他编程语言,如C#和VisualScript,方便开发者根据自己的喜好进行编程。 其次,Godot内置了许多功能,如碰撞检测、动画、物理引擎等,可以减少开发过程中需要自己编写的代码量。这些功能的集成使得开发者可以更专注于游戏逻辑和玩法设计,而不需要从头开始构建基础功能。 第三,Godot提供了强大的跨平台支持。无论是在Windows、MacOS还是Linux系统上进行开发,Godot都能提供良好的支持和适配。它还可以导出到多个平台,如PC、移动设备和网页,使得游戏能够在不同的平台上进行推广和发布。 最后,Godot拥有一个活跃的社区和大量的开发者贡献。这意味着你可以在社区论坛上获得许多帮助和资源,并且可以从其他开发者的经验中学习。社区还定期发布更新和修复BUG,保证Godot的稳定性和功能增强。 相比之下,Panda3D虽然也是一个功能强大的游戏引擎,但上手和使用上可能相对更具挑战性。它更适合有一定编程经验并且对底层细节有更大控制需求的开发者。 总之,虽然选择游戏引擎依赖于具体项目需求和个人偏好,但在方便程度上,从初学者到有经验的开发者,Godot相对更为友好和方便。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值