예제 #1
0
        private void UpdateEditorState <TMeasureSystem>(
            ParachuteConfig config,
            ParachuteProperties <TMeasureSystem> props)
            where TMeasureSystem : MeasureSystem
        {
            var editorOrigin        = transform.MakeImmutable();
            var canopyCentroidWorld = editorOrigin.TranslateLocally(ParachuteMaths.GetCanopyCentroid(config));

            _heightOffsetWidget.transform.Set(editorOrigin.TranslateLocally(y: 1f));
            _heightOffsetText.transform.Set(editorOrigin.TranslateLocally(y: config.HeightOffset + 1f, z: -0.5f));
            _heightOffsetText.Text.Clear();
            props.HeightOffset.FormatTo(_heightOffsetText.Text, precision: 2);

            _riggingAngleGizmo.transform.Set(canopyCentroidWorld);

            _cellColorPicker.CurrentColor = config.Color;

            _summaryText.Text.Clear();
            _summaryText.Text
            .Append("Difficulty level: ")
            .Append(ParachuteMaths.GetDifficulty(config).Stringify())
            .Append("\n")
            .Append(config.NumCells)
            .Append(" cells (")
            .Append(config.NumToggleControlledCells)
            .Append(" braked), ");
            props.CanopyMass.FormatTo(_summaryText.Text, precision: 1);
            _summaryText.Text.Append("\n");
            props.Span.FormatTo(_summaryText.Text, precision: 1);
            _summaryText.Text.Append(" × ");
            props.Chord.FormatTo(_summaryText.Text, precision: 1);
            _summaryText.Text.Append(" = ");
            props.Area.FormatTo(_summaryText.Text, precision: 0);
            _summaryText.transform.Set(canopyCentroidWorld.TranslateLocally(new Vector3(-3f, 2.5f, 0f)));

            // TODO Use mutable strings
            _riggingAngle.transform.Set(canopyCentroidWorld);
            _riggingAngle.Text.Clear();
            props.RiggingAngle.FormatTo(_riggingAngle.Text, precision: 0);

//            _rigAttachPositionText.text = string.Format("{0:0.##}, {1:0.##}, {2:0.##}",
//                props.RigAttachPosition.Value.x,
//                props.RigAttachPosition.Value.y,
//                props.RigAttachPosition.Value.z);
//            _rigAttachPositionText.transform.Set(rigAttachPositionTransform);

            var pilotWeightTransform = editorOrigin.TranslateLocally(y: -0.8f);

            _pilotWeight.transform.Set(pilotWeightTransform.TranslateLocally(y: -0.4f));
            _pilotWeightGizmo.transform.Set(pilotWeightTransform);

            _pilotWeight.Text.Clear();
            props.PilotWeight.FormatTo(_pilotWeight.Text, precision: 0);
            _pilotWeight.Text.Append(" (");
            props.WingLoading.FormatTo(_pilotWeight.Text, precision: 2);
            _pilotWeight.Text.Append(")");

            var pilotWeightShiftTransform = editorOrigin;

            _weightShiftMagnitudeGizmo.transform.Set(pilotWeightShiftTransform);
            _pilotWeightShiftMagnitude.transform.Set(pilotWeightShiftTransform.TranslateLocally(x: -1.1f));
            _weightShiftVisualizer.transform.position = pilotWeightShiftTransform.Position;
            _weightShiftVisualizer.Radius             = config.WeightshiftMagnitude;

            _pilotWeightShiftMagnitude.Text.Clear();
            props.WeightShiftMagnitude.FormatTo(_pilotWeightShiftMagnitude.Text, precision: 2);

            _radiusGizmo.UpdateState();
            _heightOffsetWidget.UpdateState();
            _rigAttachPosition.UpdateState();
            _pilotWeightGizmo.UpdateState();
            _weightShiftMagnitudeGizmo.UpdateState();
        }
예제 #2
0
        public void Initialize(ITypedDataCursor <EditorState> editorState, IObservable <Parachute> editorParachute)
        {
            if (!_isInitialized)
            {
                var configCursor = editorState.To(c => c.Config);

                var parachuteConfigViewModel = new ParachuteConfigViewModel(configCursor);
                _parachuteConfigView.Initialize(parachuteConfigViewModel);
                RegisterUIHover(_additionalSettingsParent.AddComponent <DefaultHoverEventSource>());

                var parachuteColor = configCursor.To(c => c.Color);
                _cellColorPicker.onValueChanged.AddListener(color => parachuteColor.Set(color));
                RegisterUIHover(_cellColorPicker.gameObject.AddComponent <DefaultHoverEventSource>());

                _selectedWidget = editorState.To(c => c.SelectedWidget);

                configDescription = new ConfigDescription(configCursor, _pilotTorsoScale);

                // TODO Use GUI camera?
                var mainCamera = _cameraManager.Rig.GetMainCamera();

                _radiusGizmo.InputRange               = configDescription.Radius;
                _pilotWeightGizmo.InputRange          = configDescription.PilotWeight;
                _weightShiftMagnitudeGizmo.InputRange = configDescription.WeightShiftMagnitude;
                _heightOffsetWidget.InputRange        = configDescription.HeightOffset;
                _rigAttachPosition.InputRange         = configDescription.RigAttachPosition;
                _riggingAngleGizmo.InputRange         = configDescription.RiggingAngle;
                _riggingAngleGizmo.Camera             = mainCamera;

                RegisterDraggable(_radiusGizmo.gameObject, WidgetId.Radius);
                RegisterDraggable(_pilotWeightGizmo.gameObject, WidgetId.PilotWeight);
                RegisterDraggable(_heightOffsetWidget.gameObject, WidgetId.HeightOffset);
                RegisterDraggable(_weightShiftMagnitudeGizmo.gameObject, WidgetId.WeightShiftMagnitude);
                RegisterGizmoHandlers(_riggingAngleGizmo, WidgetId.RiggingAngle);

                editorState.To(c => c.SelectedWidget)
                .OnUpdate
                .Subscribe(selectedWidget => {
                    // Render tooltip
                    //_rigAttachPositionText.gameObject.SetActive(selectedWidget == WidgetId.RigAttachPosition);

                    if (selectedWidget.HasValue)
                    {
                        var tooltip     = Tooltips[selectedWidget.Value];
                        var description = tooltip.Description + "\n\n<i>" + tooltip.Effect + "</i>";
                        _tooltipView.SetState(tooltip.Name, description);
                        _tooltipView.gameObject.SetActive(true);
                    }
                    else
                    {
                        _tooltipView.gameObject.SetActive(false);
                    }
                });

                var colliderSet = ColliderSet.Box("ParachuteUICellColliders", LayerMask.NameToLayer("UI"));

                editorState.To(c => c.IsEditing)
                .OnUpdate
                .Subscribe(isEditing => {
                    colliderSet.Parent.SetActive(isEditing);
                    _gizmosParent.SetActive(isEditing);
                    _additionalSettingsParent.SetActive(isEditing);
                    _cellColorPicker.gameObject.SetActive(isEditing);
                });

                configCursor.OnUpdate
                .CombineLatest(
                    _gameSettingsProvider.SettingChanges,
                    _activeLanguage.TableUpdates,
                    (config, settings, languageTable) => new { config, settings, languageTable })
                .Subscribe(x => {
                    _parachuteConfigView.SetState(x.languageTable.AsFunc);

                    var props = ParachuteProperties.FromConfig(x.config);
                    if (x.settings.Gameplay.UnitSystem == UnitSystem.Metric)
                    {
                        UpdateEditorState(x.config, props);
                    }
                    else
                    {
                        UpdateEditorState(x.config, props.ToImperial());
                    }
                });

                colliderSet.Parent.SetParent(gameObject);
                var canopyDragHandler = colliderSet.Parent.AddComponent <SurfaceDragHandler>();
                canopyDragHandler.Dragging += (camTransform, value) => {
                    var currentValue = configDescription.Volume.Value;
                    currentValue.x += value.x;
                    currentValue.z -= value.y;
                    configDescription.Volume.SetValue(currentValue);
                };
                _canopyHighlight.Highlightable = canopyDragHandler;

                RegisterDraggable(colliderSet.Parent, WidgetId.Area);
                editorParachute.Subscribe(p => {
                    _canopyHighlight.Renderer = p.CanopyMesh;

                    _rigAttachPosition.transform.position = p.Pilot.Torso.transform.position;
                    _rigAttachPosition.transform.rotation = p.Pilot.Torso.transform.rotation;

                    colliderSet.SetSize(p.Sections.Count);
                    for (var i = 0; i < p.Sections.Count; i++)
                    {
                        var cell = p.Sections[i].Cell;
                        colliderSet.UpdateCollider(i, cell.Collider);

                        var isLastCell = i == p.Sections.Count - 1;
                        if (isLastCell)
                        {
                            var gizmoTransform = cell.transform.MakeImmutable()
                                                 .TranslateLocally(0.8f)
                                                 .UpdateScale(Vector3.one)
                                                 .UpdateRotation(p.Root.rotation);
                            _radiusGizmo.transform.Set(gizmoTransform);
                        }
                    }
                });

//                _rigAttachPosition.OnPositionChanged += newPosition => {
//                    configDescription.RigAttachPosition.SetValue(newPosition);
//                };
//                _rigAttachPosition.ActiveAxes = ActiveAxis.X | ActiveAxis.Y | ActiveAxis.Z;
                RegisterDraggable(_rigAttachPosition.gameObject, WidgetId.RigAttachPosition);

                /*
                 * What are the problems that we need to solve:
                 * - Use a single source of truth to render the parachute
                 * - Use a single source of truth to render the GUI
                 * - The GUI widgets should not know more than just the value they need to update and
                 *   what the value is they need to render (use cursors into the app state to do this)
                 * - Use unity as a rendering engine but not as a logic engine (possibly too hard to do this now)
                 *
                 *
                 *
                 * Gizmo:
                 *
                 * - Show scaling and rotation widgets at all times and
                 *   couple them to an InputRange.
                 * - (optional) Draw box around selected thing
                 *
                 */

                _isInitialized = true;
            }
        }