在线时间:8:00-16:00
迪恩网络APP
随时随地掌握行业动态
扫描二维码
关注迪恩网络微信公众号
开源软件名称:mysticfall/alleycat-godot开源软件地址:https://github.com/mysticfall/alleycat-godot开源编程语言:C# 99.5%开源软件介绍:IntroductionAlley Cat is a programmer friendly game framework for Godot engine. StatusIt's highly experimental at this stage, so don't even think about using it for anything serious yet! If you feel adventurous though, you are welcome to test it and file bug reports, or even send pull requests. UsageInstallationActually, there's no easy way to use this framework in your project yet. The reason is, Godot 3.0 still lacks proper support for writing addons in C#, so until it gets resolved you'll need to download the project itself and reuse it in the source level. SetupIn order to use the framework, you'll need to register Typed Node APIAlley Cat provides various generic extension methods for using AlleyCat.Common;
// Throws an excetion when not found.
this.GetNode<MyNode>("Children/MyNode");
// Returns null when not found.
this.GetNodeOrDefault<MyNode>("Children/MyNode");
// Create and add node if necessary.
this.GetOrCreateNode<MyNode>("Children/MyNode", _ => new MyNode());
// Find children by type.
this.GetChild<MyNode>();
this.GetChildren<MyNode>();
this.GetChildOrDefault<MyNode>();
this.GetOrCreateChild<MyNode>(_ => new MyNode()); Autowiring APIAlley Cat implements a simple dependency injection API with which you can easily reference other nodes or scoped services from any node. RequirementsIn order to make autowiring to work, you need to override using AlleyCat.Autowire;
public override void _Ready() => this.Autowire(); Injection CallbackAny method annotated with It is preferrable to use such methods instead of [PostConstruct]
private void OnInitialize() {
// It's safe to access your dependencies here.
} Node InjectionYou can inject other nodes as dependencies using // Find a node named `AnimationPlayer` under the current node. It will throw an
// exception when the specified node cannot be found.
[Node("AnimationPlayer")]
private AnimationPlayer _animationPlayer;
// Node can be referenced by specifying its path.
[Node("Children/MyNode")]
public MyNode MyNode { get; set; } // Auto property is also supported.
// Node name can be omitted when the member has the same name except for the leading `_`.
// It is assumed node name starts with a capital letter, so you can use either `_camera` or
// `Camera` as the member name for a child node named `Camera`.
[Node]
private Camera _camera;
// Singletons can be referenced in the same manner, and you can add `required = false` to
// make the dependency optional (does not throw an exception when missing).
[Node("/root/MyService", required = false)]
private MyService Service { get; private set; }
// You can also reference multiple nodes by their common type, as `IEnumerable<T>`.
[Node]
private IEnumerable<Button> Buttons;
// When you specify a node path, all child nodes under the node matching the type will be selected.
[Node("ButtonPanel")]
private IEnumerable<Button> _buttons { get; private set; } Service InjectionBasic UsageYou can also declare or reference any class as a dependency, using
To declare a singleton service, you can simply add [Singleton(typeof(IMyService)]
public class MyService : Node, IMyService {
// ...
}
[Service]
private IMyService _service;
// It follows similar semantics as the [Node] attribute.
[Service(required = false)]
private IMyService OptionalService { get; private set; } Alternatively, you can register your services using public class MyServiceProvider : Node, IServiceDefinitionProvider {
public IEnumerable<Type> ProvidedTypes => new[] { typeof(ILoggerFactory) };
public void AddServices(IServiceCollection collection)
{
var factory = new LoggerFactory();
var providers = this.GetChildren<ILoggerProvider>();
foreach (var provider in providers)
{
factory.AddProvider(provider);
}
collection.AddSingleton<ILoggerFactory>(factory);
}
//...
} Context HierarchiesBy default, all registered services belongs to the 'root context', which is represented by an
On the other hand, you can define other contexts other than the root and nest them to form a
context hierachy. In order to create a local context, all you have to do is to annotate a node
where you want to bind your context with [AutowireContext]
public class Console : Node {
//...
} What the above example does is creating a new context for the Having a local context in a hierarchy means that all descendant nodes of the node that the context is bound will use it to resolve and register dependencies. For exaample, if you make When a child node cannot find a suitable injection candidate from the immediate local context, it will try again with the next parent context instead of throwing an exception. It will follow up the context hierarchy until it can find a dependency or reaches the root context. If it fails to find a dependency in the root context, it will throw an exception as it would normally do. An important thing to remember about the context hierarchy is that dependencies registered to a context are shared between every nodes under its subtree regardless of their positions. For example, if The only exception to the rule is the node to which the context is defined. If such a node
declares itself as One of the notable use case of such a feature would be when you need to extend a node's
functionalities in a pluggable manner. For example, if there's a // The game console class.
[AutowireContext]
public class Console : Node {
[Service]
public IEnumerable<IConsoleCommand> Commands { get; private set; }
...
}
public interface IConsoleCommand {
void Execute(string[] args);
}
[Singleton]
public class HelpCommand : Node, IConsoleCommand {
//...
}
[Singleton]
public class QuitCommand : Node, IConsoleCommand {
//...
} You can add an empty node named Reactive IntegrationAlleyCat exposes various using AlleyCat.Event;
// Inside a node class.
this
.OnInput()
.Where(e => e.IsActionPressed("ui_console"))
.Select(_ => Visible ? "Hide" : "Show")
.Subscribe(a => _player.Play(a))
.AddTo(this);
this
.OnProcess()
.Select(delta => delta * speed)
.Subscribe(MovePlayer)
.AddTo(this);
Note that due to limitations of the implementation, the actual events you received from such observables are not from the node itself, but a child node that is automatically added to it. It is the reason why there's no Aside from lifecycle callbacks, signals can be accessed in the same manner as well: using AlleyCat.Event;
[Node]
private AnimationPlayer _player;
public void _Ready() {
_player.OnAnimationStart()
.Where(e => e.Animation == "Show")
.Select(e => e.Animation)
.Subscribe(name => GD.Print("Playing animation: " + name))
.AddTo(this);
} Currently, only File APIAlly Cat provides var provider = new FileProvider();
var directory = provider.GetDirectoryContents("user://");
for (var file in directory) {
GD.Print(file);
}
var file = new FileInfo("res://README.md");
using (var reader = new StreamReader(file.CreateReadStream()))
{
string line;
while ((line = reader.ReadLine()) != null)
{
GD.Print(line);
}
} ContactIf you have any questions or suggestions about the project, please visit Godot's Discord channel and leave a message to LICENSEThis project is provided under the terms of MIT License. CREDITSThis project has been developed with JetBrains Rider, which I believe to be the best C# IDE available on Linux platform. JetBrains kindly offered me a free license under their open source support program, so I mention it here to show my gratitude. |
2023-10-27
2022-08-15
2022-08-17
2022-09-23
2022-08-13
请发表评论