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

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();

}

}

}

相关推荐
探求虚无1 天前
用 AI 在 Unity 里做一款 RTS:最难的不是生成代码,而是证明它真的能玩
人工智能·unity·游戏引擎
samble3 天前
从零搭建半导体设备上位机(九):拖拽与交互,Adorner、DragDrop 与晶圆拖放信息
wpf·拖拽·adorner
寂寞的船3 天前
【Unity知识速递】第10期 Unity GC 零分配实战:从 UnityEngine.Pool 到手动 GC 控制的全链路优化
jvm·unity·c#·游戏引擎·lucene
Martina_03214 天前
AI生成3D场景的霓虹灯一开就糊成光团?用6步检查Emissive、Bloom与曝光
人工智能·3d·ai·自然语言处理·游戏引擎·材质·贴图
郝学胜-神的一滴4 天前
AI 编程智能体 27:吃透MCP通信机制
人工智能·python·langchain·wpf·numpy·scikit-learn
波力海苔夹心脆6755 天前
C# WPF 资源字典详解:ResourceDictionary、MergedDictionaries 与自定义控件案例
开发语言·c#·wpf·入门教程·resource·资源字典
陈仓主教5 天前
# WPF CheckBox 控件详解与使用—WPF 中的控件(6)--复选框控件(CheckBox)
wpf
寂寞的船5 天前
【Unity知识速递】第8期 IL2CPP 托管堆内存碎片与原生堆交互机制深度解析
unity·游戏引擎·交互
淡海水6 天前
09-04-内存-Unity原生对象生命周期
unity·c#·游戏引擎·gc
寂寞的船6 天前
【Unity Bug挑战】第10期 SerializeReference 内存泄漏之谜
unity·c#·游戏引擎·bug