wpf游戏引擎的Components的entity组件实现

发布于:2025-06-13 ⋅ 阅读:(19) ⋅ 点赞:(0)

1.GameEntity.cs

using PrimalEditor.Common;
using PrimalEditor.GameProject;
using PrimalEditor.Utilities;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.Runtime.Serialization;
using System.Windows.Input;

namespace PrimalEditor.Components
{
    [DataContract]
    [KnownType(typeof(Transform))]
    [KnownType(typeof(Script))]
    class GameEntity : ViewModelBase
    {
        private bool _isActive;
        [DataMember]

        public bool IsActive
        {
            get => _isActive;
            set
            {
                if (_isActive != value)
                {
                    _isActive = value;
                    OnPropertyChanged(nameof(IsActive));


                }

            }


        }

        private bool _isEnabled;
        [DataMember]

        public bool IsEnabled
        {
            get => _isEnabled;
            set
            {
                if (_isEnabled != value)
                {
                    _isEnabled = value;
                    OnPropertyChanged(nameof(IsEnabled));


                }

            }


        }

        private string _name;
        [DataMember]

        public string Name
        {
            get => _name;
            set
            {
                if (_name != value)
                {
                    _name = value;
                    OnPropertyChanged(nameof(Name));


                }

            }


        }

        [DataMember]
        public Scene ParentScene { get; private set; }

        [DataMember(Name = nameof(Components))]

        private readonly ObservableCollection<Component> _components = new ObservableCollection<Component>();

        public ReadOnlyObservableCollection<Component> Components { get; private set; }


        public Component GetComponent(Type type) => Components.FirstOrDefault(c => c.GetType() == type);
        public T GetComponent<T>() where T : Component => GetComponent(typeof(T)) as T;

        public bool AddComponent(Component component)
        {

            Debug.Assert(component != null);
            if (!Components.Any(x => x.GetType() == component.GetType()))
            {

                IsActive = false;
                _components.Add(component);
                IsActive = true;
                return true;


            }

            Logger.Log(MessageType.Warning, $"Entity {Name} already has a {component.GetType().Name} component");
            return false;


        }

        public void RemoveComponent(Component componnet)
        {
            Debug.Assert(componnet != null);
            if (componnet is Transform) return;

            if (_components.Contains(componnet))
            {

                IsActive = false;
                _components.Remove(componnet);
                IsActive = true;

            }


        }


        public ICommand RenameCommand { get; private set; }

        public ICommand IsEnableCommand { get; private set; }

        public object? DataContext { get; internal set; }
        public GameEntity EntityId { get; internal set; }

        [OnDeserialized]

        void OnDeserialized(StreamingContext context)
        {
            if (_components != null)
            {
                Components = new ReadOnlyObservableCollection<Component>(_components);
                OnPropertyChanged(nameof(Components));


            }

            RenameCommand = new RelayCommand<string>(x =>
            {
                var oldName = _name;
                Name = x;


                Project.UndoRedo.Add(new UndoRedoAction(nameof(Name), this,

                    oldName, x, $"Rename entity '{oldName}' to '{x}'"

                    ));


            }, x => x != _name

            );

            IsEnableCommand = new RelayCommand<bool>(x =>
            {

                var oldValue = _isEnabled;
                IsEnabled = x;

                Project.UndoRedo.Add(new UndoRedoAction(nameof(IsEnabled), this,
                    oldValue, x, x ? $"Enable {Name}" : $"Disable {Name}"));


            });

        }

        public GameEntity(Scene scene)
        {

            Debug.Assert(scene != null);
            ParentScene = scene;
            _components.Add(new Transform(this));
            OnDeserialized(new StreamingContext());

        }


    }

    abstract class MSEntity : ViewModelBase
    {
        private bool _enableUpdates = true;


        private bool? _isEnabled;

        [DataMember]
        public bool? IsEnabled
        {

            get => _isEnabled;
            set
            {
                if (_isEnabled != value)
                {
                    _isEnabled = value;

                    OnPropertyChanged(nameof(IsEnabled));


                }


            }

        }

        private string _name;

        [DataMember]
        public string Name
        {

            get => _name;
            set
            {
                if (_name != value)
                {
                    _name = value;

                    OnPropertyChanged(nameof(Name));


                }
            }
        }


        private readonly ObservableCollection<IMSComponent> _components = new ObservableCollection<IMSComponent>();
        public ReadOnlyObservableCollection<IMSComponent> Components { get; private set; }

        public T GetMSComponent<T>() where T : IMSComponent
        {

            return (T)Components.FirstOrDefault(x => x.GetType() == typeof(T));

        }

        public List<GameEntity> SelectedEntities { get; }


        private void MakeComponentList()
        {
            _components.Clear();
            var firstEntity = SelectedEntities.FirstOrDefault();
            if (firstEntity == null) return;


            foreach (var component in firstEntity.Components)
            {
                var type = component.GetType();
                if (!SelectedEntities.Skip(1).Any(entity => entity.GetComponent(type) == null))
                {

                    Debug.Assert(Components.FirstOrDefault(x => x.GetType() == type) == null);
                    // _components.Add(component.GetMultiselectionComponent(this));


                }

            }

        }


        public static float? GetMixedValue<T>(List<T> objects, Func<T, float> getProperty)
        {

            var value = getProperty(objects.First());

            return objects.Skip(1).Any(x => !getProperty(x).IsTheSameAs(value)) ? (float?)null : value;


        }


        public static bool? GetMixedValue<T>(List<T> objects, Func<T, bool> getProperty)
        {

            var value = getProperty(objects.First());
            return objects.Skip(1).Any(x => value != getProperty(x)) ? (bool?)null : value;


        }

        public static string? GetMixedValue<T>(List<T> objects, Func<T, string> getProperty)
        {

            var value = getProperty(objects.First());
            return objects.Skip(1).Any(x => value != getProperty(x)) ? null : value;

        }


        protected virtual bool UpdateGameEntities(string propertyName)
        {


            switch (propertyName)
            {

                case nameof(IsEnabled): SelectedEntities.ForEach(x => x.IsEnabled = IsEnabled.Value); return true;
                case nameof(Name): SelectedEntities.ForEach(x => x.Name = Name); return true;


            }

            return false;


        }

        protected virtual bool UpdateMSGameEntity()
        {

            IsEnabled = GetMixedValue(SelectedEntities, new Func<GameEntity, bool>(x => x.IsEnabled));
            Name = GetMixedValue(SelectedEntities, new Func<GameEntity, string>(x => x.Name));

            return true;
        }

        public void Refresh()
        {
            _enableUpdates = false;
            UpdateMSGameEntity();
            MakeComponentList();
            _enableUpdates = true;

        }

        public MSEntity(List<GameEntity> entities)
        {

            Debug.Assert(!entities.Any() == true);
            Components = new ReadOnlyObservableCollection<IMSComponent>(_components);
            SelectedEntities = entities;
            PropertyChanged += (s, e) => { if (_enableUpdates) UpdateGameEntities(e.PropertyName); };

        }

    }

    class MSGameEntity : MSEntity
    {
        public MSGameEntity(List<GameEntity> entities) : base(entities)
        {


            Refresh();

        }

    }


}