Skip to content

Commit

Permalink
#479 Added implemented MarkAction, MarkNetAction and GameModeMarker
Browse files Browse the repository at this point in the history
Marker sphere placement needs to be fixed yet.
  • Loading branch information
m4xxed committed Oct 21, 2022
1 parent 240742a commit ee5f3b0
Show file tree
Hide file tree
Showing 3 changed files with 270 additions and 0 deletions.
138 changes: 138 additions & 0 deletions Assets/SEE/Controls/Actions/MarkAction.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
using System.Collections.Generic;
using SEE.Game;
using SEE.GO;
using SEE.Net;
using SEE.Utils;
using UnityEngine;

namespace SEE.Controls.Actions
{
/// <summary>
/// Action to visually mark/unmark a node as selected via a floating sphere above it.
/// </summary>
internal class MarkAction : AbstractPlayerAction
{
/// <summary>
/// If the user clicks with the mouse hitting a game object representing a graph node,
/// the graphs selection status is toggled. Being selected means a sphere is floating above the node.
/// <see cref="ReversibleAction.Update"/>.
/// </summary>
/// <returns>true if completed</returns>
public override bool Update()
{
bool result = false;

// FIXME: Needs adaptation for VR where no mouse is available. (applies here too)
if (Input.GetMouseButtonDown(0)
&& Raycasting.RaycastGraphElement(out RaycastHit raycastHit, out GraphElementRef _) == HitGraphElement.Node)
{
// the hit object that is either selected or unselected
GameObject targetNode = raycastHit.collider.gameObject;

GameObject markerSphere = GameNodeMarker.TryMarking(targetNode);

memento = new Memento(markerSphere);

new MarkNetAction(markerSphere).Execute();

// propagate (MarkNetAction)
result = true;
currentState = ReversibleAction.Progress.Completed;

}
return result;
}

/// <summary>
/// Memento capturing the data necessary to re-do this action.
/// </summary>
private Memento memento;

/// <summary>
/// The information we need to re-add a marker whose addition was undone.
/// </summary>
private struct Memento
{
/// <summary>
/// The node marked by the marker.
/// </summary>
public readonly GameObject MarkedNode;

/// <summary>
/// The node ID for the added node. It must be kept to re-use the
/// original name of the node in Redo().
/// </summary>
public string MarkerID;

/// <summary>
/// Constructor setting the information necessary to re-do this action.
/// </summary>
/// <param name="parent">the node targeted by our MarkAction</param>
public Memento(GameObject markedNode)
{
MarkedNode = markedNode;
MarkerID = markedNode.ID();
}
}

/// <summary>
/// Undoes this MarkAction.
/// </summary>
public override void Undo()
{
base.Undo();
GameNodeMarker.TryMarking(memento.MarkedNode);
new MarkNetAction(memento.MarkedNode).Execute();
}

/// <summary>
/// Redoes this MarkAction.
/// </summary>
public override void Redo()
{
base.Redo();
GameNodeMarker.TryMarking(memento.MarkedNode);
new MarkNetAction(memento.MarkedNode).Execute();
}

/// <summary>
/// Returns a new instance of <see cref="MarkAction"/>.
/// </summary>
/// <returns>new instance</returns>
public static ReversibleAction CreateReversibleAction()
{
return new MarkAction();
}

/// <summary>
/// Returns a new instance of <see cref="MarkAction"/>.
/// </summary>
/// <returns>new instance</returns>
public override ReversibleAction NewInstance()
{
return CreateReversibleAction();
}

/// <summary>
/// Returns the <see cref="ActionStateType"/> of this action.
/// </summary>
/// <returns><see cref="ActionStateType.NewNode"/></returns>
public override ActionStateType GetActionStateType()
{
return ActionStateType.Mark;
}

/// <summary>
/// Returns all IDs of gameObjects manipulated by this action.
/// </summary>
/// <returns>all IDs of gameObjects manipulated by this action</returns>
public override HashSet<string> GetChangedObjects()
{
return new HashSet<string>
{
memento.MarkedNode.name,
memento.MarkerID
};
}
}
}
81 changes: 81 additions & 0 deletions Assets/SEE/Game/GameNodeMarker.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
using System;
using SEE.DataModel;
using SEE.DataModel.DG;
using SEE.Game.City;
using SEE.GO;
using SEE.Utils;
using UnityEngine;

namespace SEE.Game
{
/// <summary>
/// Creates new game objects representing graph nodes or deleting these again,
/// respectively.
/// </summary>
public static class GameNodeMarker
{

/// <summary>
/// Check the transfered target node whether it was been marked already, and toggle it to the other state.
/// <param name="targetNode">the node that was targeted for marking.</param>
/// </summary>
/// <returns>new instance</returns>
public static GameObject TryMarking(GameObject targetNode)
{

// save the sphere that was used as a marker
GameObject markerSphere = null;

// iterate over all children of the targeted node
foreach (Transform child in targetNode.transform)
{
// exit the loop if a (/the) marker was found
if (child.name == "MarkerSphere" + targetNode.name)
{
markerSphere = child.gameObject;
break;
}
}

if (markerSphere != null)
{
// delete existing marker sphere
Destroyer.DestroyGameObject(markerSphere);
return null;
}
else
{
// create a new marker sphere because there is none currently
GameObject newMarkerSphere = GameObject.CreatePrimitive(PrimitiveType.Sphere);

Debug.Log("X is:" + newMarkerSphere.transform.localScale.x);
Debug.Log("Y is:" + newMarkerSphere.transform.localScale.y);
Debug.Log("Z is:" + newMarkerSphere.transform.localScale.z);

// the diameter of the is the minimum of the width (x-axis) and depth (y-axis) of the marked node
newMarkerSphere.transform.localScale = Math.Min(targetNode.transform.localScale.x, targetNode.transform.localScale.z) * .5f * Vector3.one;

// the position of the marker sphere is above the marked node
newMarkerSphere.transform.position = new Vector3(targetNode.transform.position.x,
targetNode.transform.position.y,
// + targetNode.transform.localScale.y
// + newMarkerSphere.GetComponent<SphereCollider>().radius,
// + 0.1f,
targetNode.transform.position.z);

// FIXME: (?) ensure markers are not blocking us from unmarking or marking other nodes
newMarkerSphere.GetComponent<SphereCollider>().radius = 0;

newMarkerSphere.SetColor(Color.magenta);

// marker spheres can be recognized by their name-prefix "MarkerSphere"
newMarkerSphere.name = "MarkerSphere" + targetNode.name;

// assign the marker sphere to the node it marks
newMarkerSphere.transform.SetParent(targetNode.transform);

return newMarkerSphere;
}
}
}
}
51 changes: 51 additions & 0 deletions Assets/SEE/Net/Actions/MarkNetAction.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
using SEE.Game;
using UnityEngine;

namespace SEE.Net
{
/// <summary>
/// This class is responsible for marking a node via network from one client to all others and
/// to the server.
/// </summary>
public class MarkNetAction : AbstractNetAction
{
// Note: All attributes are made public so that they will be serialized
// for the network transfer.

/// <summary>
/// The GameObject that is targeted for marking.
/// </summary>
public GameObject TargetNode;

/// <summary>
/// Constructor.
/// </summary>
/// <param name="targetNode">the node that was targeted for marking.</param>
public MarkNetAction
(GameObject targetNode)
: base()
{
this.TargetNode = targetNode;
}

/// <summary>
/// Things to execute on the server (none for this class). Necessary because it is abstract
/// in the superclass.
/// </summary>
protected override void ExecuteOnServer()
{
// Intentionally left blank.
}

/// <summary>
/// Tries marking on each client.
/// </summary>
protected override void ExecuteOnClient()
{
if (!IsRequester())
{
GameObject markerSphere = GameNodeMarker.TryMarking(TargetNode);
}
}
}
}

0 comments on commit ee5f3b0

Please sign in to comment.