简体   繁体   English

将 Unity C# 代码与“普通”C# 代码分开

[英]Separating Unity C# code from "normal" C# code

I had thought about separating Unity C# code (code that I can only use with using UnityEngine) from "normal" C# code ( int x = 3; bool isKnockMeDead = true; void KnockMeDead(); etc.)我曾想过将 Unity C# 代码(我只能与使用 UnityEngine 一起使用的代码)与“普通”C# 代码( int x = 3; bool isKnockMeDead = true; void KnockMeDead();等) int x = 3; bool isKnockMeDead = true; void KnockMeDead();

Why?为什么? So that I could (for example) switch from Unity to Wpf without having to rewrite the whole logic.这样我就可以(例如)从 Unity 切换到 Wpf,而无需重写整个逻辑。 So my EngineObject is then Window instead of MonoBehviour...所以我的 EngineObject 是 Window 而不是 MonoBehviour ...

I already have a few solutions to this problem:我已经有一些解决这个问题的方法:

But I'm not 100% satisfied with any of them, because...但我对其中任何一个都不是 100% 满意,因为......

1st solution - InheritanceSolution.cs第一个解决方案 - InheritanceSolution.cs

It's the quickest way to do this, but you doesn't have a 100% visual separation and the danger of using Unity Code in the Child class is also given.这是执行此操作的最快方法,但您没有 100% 的视觉分离,并且还给出了在 Child 类中使用 Unity Code 的危险。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using UnityEngine;

namespace Assets
{
    //Unity C#
    public class InheritanceSolutionParent : MonoBehaviour
    {
        public MusicPlayer EngineMusicPlayer { get; private set; }

        public void SetObjectName(string name)
        {
            gameObject.name = name;
        }

        public void MoveObjectUp(decimal y)
        {
            gameObject.transform.position += new Vector3(0, (float)y);
        }
    }

    public class MusicPlayer : MonoBehaviour, IMusicPlayer
    {
    }

    //C#
    public class InheritanceSolutionChild : InheritanceSolutionParent // => Unity
    {
        private IMusicPlayer _universalMusicPlayer;
        private List<Sound> _sounds;

        public void Start() /* => Unity */ => UniversalStart();
        public void Update() /* => Unity */ => UniversalUpdate();

        private void UniversalStart()
        {
            Initionalization();

            _sounds.Add(new Sound("Toilettenspülung", "Assets/Sounds/Toilettenspülung.mp3"));

            _universalMusicPlayer.Play(_sounds[0]);
        }

        private void Initionalization()
        {
            SetObjectName("PartialSolution");
            _universalMusicPlayer = EngineMusicPlayer; // => Unity
            _sounds = new List<Sound>();
        }

        private void UniversalUpdate()
        {
            MoveObjectUp(5);
            MoveObjectUp(2);
        }
    }

    public class Sound
    {
        public Sound(string soundName, string soundFileDataPath)
        {
            SoundName = soundName;
            SoundFileDataPath = soundFileDataPath;
        }

        public string SoundName { get; private set; }
        public string SoundFileDataPath { get; private set; }
    }

    public interface IMusicPlayer
    {
        void Play(Sound sound);
    }
}

2nd solution - PartialSolution.cs第二个解决方案 - PartialSolution.cs

The keyword is actually used if several people want to work on a class without being disturbed and/or if autogenerated code should be separated from the user.如果几个人想要在不受打扰的情况下处理一个类和/或如果自动生成的代码应该与用户分开,则实际使用该关键字。

I just use it to separate code, which is ok, but it should not be used to be able to say that every class has 200 lines, because it simply remains one class over when compiling.我只是用它来分隔代码,这没关系,但它不应该用来说每个类都有 200 行,因为它在编译时只是保留一个类。

And there is the problem :/有问题:/

Visual separation would be perfect, but nothing changes in the implementation and I can still use Unity code in both(one) Classes.视觉分离将是完美的,但实现中没有任何变化,我仍然可以在两个(一个)类中使用 Unity 代码。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using UnityEngine;

namespace Assets
{
    //Unity C#
    public partial class PartialSolution : MonoBehaviour 
    {
        [SerializeField] private MusicPlayer _engineMusicPlayer;

        private void Start() => UniversalStart();
        private void Update() => UniversalUpdate();

        private void SetObjectName(string name)
        {
            gameObject.name = name;
        }

        private void SetUniversalMusicPlayer()
        {
            _universalMusicPlayer = _engineMusicPlayer;
        }

        private void MoveObjectUp(decimal y)
        {
            gameObject.transform.position += new Vector3(0, (float)y);
        }
    }

    public class MusicPlayer : MonoBehaviour, IMusicPlayer
    {
    }

    //C#
    public partial class PartialSolution
    {
        private IMusicPlayer _universalMusicPlayer;
        private List<Sound> _sounds;

        private void UniversalStart()
        {
            Initionalization();

            _sounds.Add(new Sound("Toilettenspülung", "Assets/Sounds/Toilettenspülung.mp3"));

            _universalMusicPlayer.Play(_sounds[0]);
        }

        private void Initionalization()
        {
            SetObjectName("PartialSolution");
            SetUniversalMusicPlayer();
            _sounds = new List<Sound>();
        }

        private void UniversalUpdate()
        {
            MoveObjectUp(5);
            MoveObjectUp(2);
        }
    }

    public class Sound
    {
        public Sound(string soundName, string soundFileDataPath)
        {
            SoundName = soundName;
            SoundFileDataPath = soundFileDataPath;
        }

        public string SoundName { get; private set; }
        public string SoundFileDataPath { get; private set; }
    }

    public interface IMusicPlayer
    {
        void Play(Sound sound);
    }
}

3rd solution - InterfaceSolution.cs第三个解决方案 - InterfaceSolution.cs

(Ey Max please separate the class GameController (big project)... (Ey Max 请将类 GameController(大项目)分开...

uh... gotta go run )呃……要跑了

The solution is actually perfect, but the effort is quite high!解决方案其实很完美,但是下功夫还是挺高的!

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using UnityEngine;

namespace Assets
{
    //Unity C#
    public class InterfaceSolutionUnity : MonoBehaviour, IInterfaceSolutionUniversalEngine
    {
        IInterfaceSolutionUniversal _universalInstance;

        [SerializeField] private MusicPlayer _musicPlayer;

        public void Start()
        {
            _universalInstance = new InterfaceSolutionUniversal(this, _musicPlayer);
            _universalInstance.UniversalStart();
        }

        public void Update() => _universalInstance.UniversalUpdate();

        public void SetObjectName(string name)
        {
            gameObject.name = name;
        }

        public void MoveObjectUp(decimal y)
        {
            gameObject.transform.position += new Vector3(0, (float)y);
        }
    }

    public class MusicPlayer : MonoBehaviour, IMusicPlayer
    {
    }

    //C#
    public interface IInterfaceSolutionUniversal
    {
        void UniversalStart();
        void UniversalUpdate();
    }

    public class InterfaceSolutionUniversal : IInterfaceSolutionUniversal
    {
        private IInterfaceSolutionUniversalEngine _universalEngineInstance;

        private IMusicPlayer _musicPlayer;
        private List<Sound> _sounds;

        public InterfaceSolutionUniversal(IInterfaceSolutionUniversalEngine universalEngineInstance, IMusicPlayer musicPlayer)
        {
            _universalEngineInstance = universalEngineInstance;
            _musicPlayer = musicPlayer;
            _sounds = new List<Sound>();
        }

        public void UniversalStart()
        {
            _universalEngineInstance.SetObjectName("PartialSolution");

            _sounds.Add(new Sound("Toilettenspülung", "Assets/Sounds/Toilettenspülung.mp3"));

            _musicPlayer.Play(_sounds[0]);
        }

        public void UniversalUpdate()
        {
            _universalEngineInstance.MoveObjectUp(5);
            _universalEngineInstance.MoveObjectUp(2);
        }
    }

    public interface IInterfaceSolutionUniversalEngine
    {
        void MoveObjectUp(decimal y);
        void SetObjectName(string name);
    }

    public class Sound
    {
        public Sound(string soundName, string soundFileDataPath)
        {
            SoundName = soundName;
            SoundFileDataPath = soundFileDataPath;
        }

        public string SoundName { get; private set; }
        public string SoundFileDataPath { get; private set; }
    }

    public interface IMusicPlayer
    {
        void Play(Sound sound);
    }
}

My questions:我的问题:

  1. Is it even necessary?甚至有必要吗? If yes, when?如果是,什么时候?

  2. Which of the three would be the best in your opinion?在您看来,这三个中哪个最好?

  3. Is there a better one?有没有更好的?

In summary, I just want to be a bit more independent from Unity, but I don't want to program a new engine right away.总而言之,我只是想更独立于 Unity,但我不想立即编写新引擎。

You can leave up to me how I should design it in the end.你可以让我决定我最终应该如何设计它。 (MVVM, MVC, etc.) :) (MVVM、MVC 等):)

I look forward to your answers.我期待着你的回答。 Please be my heroes!请成为我的英雄!

I've worked on a project like this.我曾参与过这样的项目。 It was great, but also a lot of headache of constantly fighting Unity.这很棒,但也很头疼不断与 Unity 战斗。 Our reason was to have a deterministic game and run an instance of it as an authoritative server without getting Unity involved.我们的原因是拥有一个确定性游戏,并在不让 Unity 参与的情况下将其实例作为权威服务器运行。

MVC is a great for this. MVC 非常适合这一点。

I've made minimal project a while ago.不久前我做了一个最小的项目 Have a look.看一看。

  • Models contain data only.模型仅包含数据。
  • View is a MonoBehaviour with SpriteRenderers/AudioSources that listens for events. View 是一个 MonoBehaviour,带有 SpriteRenderers/AudioSources 来监听事件。
  • Events are model changes that view is interested in.事件是视图感兴趣的模型更改。
  • Services are a collection of methods that modify the model.服务是修改模型的方法的集合。
  • Simulator ticks the model.模拟器勾选模型。
  • Context is where it all begins.上下文是一切开始的地方。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM