/// <summary> /// Captures the current values for a given entity and creates a keyframe /// at the given time and with the captured values /// </summary> /// <param name="entity">entity to capture</param> /// <param name="time">Time to create keyframe at</param> public void Capture(Entity entity, int time) { if (entity == null) { throw new ArgumentNullException(nameof(entity), "entity cannot be null"); } PerfStopwatch stopwatch = PerfStopwatch.StartNew("Capturing New keyframe"); //Get all behaviours on entity IEnumerable <BehaviourComponent> behaviours = entity.Components; List <KeyframePropertyData> propertyData = new List <KeyframePropertyData>(); foreach (BehaviourComponent behaviour in behaviours) { //Check if the cache contains entry for this behaviour if (!keyframeInfoCache.ContainsKey(behaviour)) { //Get all properties with the KeyframeAnimationProperty attribute Type behaviourType = behaviour.GetType(); IEnumerable <PropertyInfo> reflectedProperties = behaviourType.GetProperties().Where( prop => Attribute.IsDefined(prop, typeof(KeyframeProperty)) ); List <KeyframePropertyInfo> propInfos = new List <KeyframePropertyInfo>(); foreach (PropertyInfo propInfo in reflectedProperties) { if (!propInfo.CanWrite || !propInfo.CanRead) { DebugUtil.LogWithLocation($"Property {propInfo.Name} needs both read and write access"); continue; } propInfos.Add(new KeyframePropertyInfo(propInfo, PropertyType.Interpolatable)); } keyframeInfoCache.Add(behaviour, propInfos.ToArray()); } KeyframePropertyInfo[] properties = keyframeInfoCache[behaviour]; for (int i = 0, l = properties.Length; i < l; i++) { object currentPropertyValue = properties[i].Property.GetValue(behaviour); KeyframePropertyData key = new ValueKeyframe(properties[i], behaviour, currentPropertyValue); //Add it to the timeline propertyData.Add(key); } } //Check if entity has a timeline or if we need to create one for it if (!timelines.ContainsKey(entity)) { CreateTimeline(entity); } KeyContainer newKey = new KeyContainer(propertyData); newKey.Time = time; timelines[entity].AddKeyframe(newKey); stopwatch.Stop(); }
private void SeekValueKeyframe(KeyframeTimeline timeline, KeyframePropertyInfo property, int time) { //Get closest keys KeySet interval = timeline.GetClosestKeys(property, time); //int t = 5; Type valueType = property.Property.PropertyType; //If both keys are the same, no need for interpolation if (interval.TimeBefore == interval.TimeAfter) { ValueKeyframe value = timeline.GetPropertyKey(property, interval.TimeBefore) as ValueKeyframe; if (value == null) { //Property had no keyframes or was not a value keyframe there is nothing to do, just return return; } property.Property.SetValue(value.Target, value.Value); } else { if (interpolatorCache.ContainsKey(valueType)) { ValueKeyframe from = timeline.GetPropertyKey(property, interval.TimeBefore) as ValueKeyframe; ValueKeyframe to = timeline.GetPropertyKey(property, interval.TimeAfter) as ValueKeyframe; double diff = interval.TimeAfter - interval.TimeBefore; double diffFromLowest = time - interval.TimeBefore; if (diff == 0) { DebugUtil.LogWithLocation($"Difference between keyframes was 0, cannot continue"); return; } double t = diffFromLowest / diff; object interpolatedValue = interpolatorCache[valueType].InterpolateBetween(from.Value, to.Value, t); property.Property.SetValue(from.Target, interpolatedValue); } else { DebugUtil.LogWithLocation($"Interpolator cache did not contain a implementation for type {valueType}"); } } }