/// <summary> /// Actives the collider associated with the given shape type. /// Should only be used internally and by the save/load system. /// </summary> /// <param name="colliderType">Shape type to change the collider to.</param> public void ChangeColliderType(ShapeData.ShapeType colliderType) { activeColliderType = colliderType; switch (colliderType) { // BoxCollider2D case ShapeData.ShapeType.BOX: EnableOneColliderType(boxColliders); break; // CircleCollider2D case ShapeData.ShapeType.CIRCLE: EnableOneColliderType(circleColliders); break; // Triangle needs to be a specific kind of polygon collider case ShapeData.ShapeType.TRIANGLE: MorphPolygonToShape(ShapeData.TRIANGLE_POINTS); EnableOneColliderType(polygonColliders); break; default: Debug.LogError("Unhandled ColliderType of '" + colliderType + "' in PlayerColliderController.cs"); break; } }
/// <summary>Coroutine to smoothly change the shape of the mesh</summary> /// <param name="onFinishMeshChange">Function to call once the mesh has finished changing</param> private IEnumerator ChangeMeshCoroutine(ShapeData.ShapeType shapeType, FinishChange onFinishMeshChange) { changeMeshCoroutFin = false; // Get the initial values for each of the blend shapes float[] startBlendShapes = new float[BLEND_SHAPE_AMOUNT]; for (int i = 0; i < BLEND_SHAPE_AMOUNT; ++i) { startBlendShapes[i] = targetRenderers[0].GetBlendShapeWeight(i); } // Get index of the target blend shape int targetBlendIndex = GetBlendIndexFromShape(shapeType); // The amount of lerps that will be done float t = 0; while (t < 1) { // Lerp it LerpRenderers(targetBlendIndex, startBlendShapes, t); // Step t += changeSpeed * Time.deltaTime; yield return(null); } // Set the variables without lerping now that we are done LerpRenderers(targetBlendIndex, startBlendShapes, 1); changeMeshCoroutFin = true; // Call the specified functionality after changing meshes onFinishMeshChange?.Invoke(); yield return(null); }
/// <summary>Called when an avaible spot is found in change form controller. /// Updates the state and plays the sound. /// Starts chaning the mesh</summary> private void OnAvailableSpotFound() { ShapeData prevData = GetCurrentState(); ShapeData data = SkillData.GetData(curAttemptedStateIndex); // If the direction affects how the shape scales or we are swapping to a new state if (data.DirectionAffectsScale || !IsCurrentState(curAttemptedStateIndex)) { // Update the state UpdateCurrentState(curAttemptedStateIndex); // Start changing shape if we need to if (data.TypeOfShape != curShape) { // Start updating the mesh meshTransitioner.StartChangeShape(data.TypeOfShape); // Check if we need to invoke the shape change behaviors if (prevData.HasShapeChangeBehavior) { // Call change from on the old data prevData.ShapeChangeBehave.ChangeFrom(); } if (data.HasShapeChangeBehavior) { // Call change to on the new data data.ShapeChangeBehave.ChangeTo(); } } // Set the current shape to the new one curShape = data.TypeOfShape; } }
/// <summary> /// Creates and returns PlayerCollidersSaveData holding the data for the /// player's collider controller. /// </summary> /// <returns></returns> public override object Save() { // Get the current active collider type ShapeData.ShapeType colliderType = colliderCont.GetActiveColliderType(); // Return the new data return(new PlayerCollidersSaveData(colliderType)); }
/// <summary>Shows the visual for the player not fitting somewhere.</summary> /// <param name="shapeType">Type of shape the player tried to change to.</param> /// <param name="size">Size the player tried to change to.</param> /// <param name="rotation">Rotation of the shape to display.</param> private void ShowCannotFitHere(ShapeData.ShapeType shapeType, Vector2 pos, Vector2Int size, float rotation) { // Activate the cannot fit controller to show itself Vector3 posV3 = new Vector3(pos.x, pos.y, cannotFitCont.transform.position.z); Vector3 sizeV3 = new Vector3(size.x, size.y); cannotFitCont.Activate(posV3, sizeV3, rotation, shapeType); }
/// <summary>Sets the active state to the given state without using the skill. /// Should only be used for loading save data. /// Also sets the attempted state and current shape type to the /// state information associated with the specified state.</summary> public override void FakeUse(int stateIndex) { base.FakeUse(stateIndex); ShapeData data = SkillData.GetData(stateIndex); curAttemptedStateIndex = stateIndex; curShape = data.TypeOfShape; changeFormCont.CurShapeData = data; }
/// <summary> /// Creates save data for the rotating visuals. /// </summary> /// <param name="type">Type of shape the player is.</param> /// <param name="col">Color the player is.</param> public PlayerScaleVisualsSaveData(ShapeData.ShapeType type, Color col) { // Cast the enum to an int shapeType = (int)type; // Save the color in an array of floats color[0] = col.r; color[1] = col.g; color[2] = col.b; }
/// <summary> /// Creates and returns PlayerRotVisualsSaveData holding the current shape/color renderer's data. /// </summary> /// <returns></returns> public override object Save() { // Type of shape the player is right now ShapeData.ShapeType shapeType = blendTransitioner.CurrentShapeType; // Color the player is right now Color color = meshRenderer.material.color; // Return the data return(new PlayerScaleVisualsSaveData(shapeType, color)); }
/// <summary>Turns on the colliders for the given shape's type. /// Returns an AvailableSpot to hold if the player was able to fit in the current location and what location the spot was found. /// If a spot was found, the colliders were updated. /// If a spot was not found, they cannot fit in their current location and their colliders were not changed.</summary> /// <param name="colliderType">Type of collider to activate</param> /// <param name="size">The actual size of the collider to test</param> /// /// <param name="rotation">Rotation of the shape.</param> public AvailableSpot ActivateCollider(ShapeData.ShapeType colliderType, Vector2Int size, float rotation) { AvailableSpot availSpot = TestColliderChange(colliderType, size, rotation); if (availSpot.Available) { ChangeColliderType(colliderType); } return(availSpot); }
/// <summary>Starts smoothly changing the shape given</summary> /// <param name="onFinishMeshChange">Function to call once the mesh has finished changing</param> public void StartChangeShape(ShapeData.ShapeType shapeType, FinishChange onFinishMeshChange = null) { currentShapeType = shapeType; // If there is an ongoing coroutine, stop it if (!changeMeshCoroutFin) { StopCoroutine(changeMeshCorout); } // Start a new coroutine changeMeshCorout = StartCoroutine(ChangeMeshCoroutine(shapeType, onFinishMeshChange)); }
/// <summary> /// Load the skill data from the serialized object and /// reapply the loaded data to the active player's renderer. /// </summary> /// <param name="serializedObj">object with the player's visual's saved data</param> public override void Load(object serializedObj) { // Cast the data PlayerScaleVisualsSaveData data = serializedObj as PlayerScaleVisualsSaveData; // Change the shape of the player ShapeData.ShapeType shapeType = data.GetShapeType(); blendTransitioner.ChangeShapeInstant(shapeType); // Change the color of the player Color color = data.GetColor(); meshRenderer.material = new Material(meshRenderer.material); meshRenderer.material.color = color; }
/// <summary>Shows the cannot fit visual at the given position as the given size and shape.</summary> /// <param name="pos">Position to move the cannot fit visual to.</param> /// <param name="size">Shape size to set.</param> /// <param name="rotation">Rotation of the shape.</param> /// <param name="shapeType">ShapeType to set the cannot fit visual to.</param> public void Activate(Vector3 pos, Vector3 size, float rotation, ShapeData.ShapeType shapeType) { // Move to the player's position. transform.position = pos; // Rotate the shape Vector3 angles = transform.eulerAngles; angles.z = rotation; transform.eulerAngles = angles; // Make it fit the size and shape the player attempted to change to. scaleCont.ShapeScale = size; blendTrans.ChangeShapeInstant(shapeType); StartFadeOutCoroutine(); }
/// <summary>Instantly changes the shape to the specified shape type.</summary> /// <param name="shapeType">Shape to change to.</param> public void ChangeShapeInstant(ShapeData.ShapeType shapeType) { currentShapeType = shapeType; // Get the initial values for each of the blend shapes float[] startBlendShapes = new float[BLEND_SHAPE_AMOUNT]; for (int i = 0; i < BLEND_SHAPE_AMOUNT; ++i) { startBlendShapes[i] = targetRenderers[0].GetBlendShapeWeight(i); } // Get index of the target blend shape int targetBlendIndex = GetBlendIndexFromShape(shapeType); // Lerp with a value of 1. LerpRenderers(targetBlendIndex, startBlendShapes, 1); }
private bool ShapeCast(ShapeData.ShapeType shape, Vector2 pos, Vector2 size, float rotation, LayerMask layerMask, bool isTest = false) { // Turn on the test collider of the given type see if there is a collision with a wall switch (shape) { // BoxCollider2D case ShapeData.ShapeType.BOX: if (isTest) { return(PhysicsDebugging.OverlapBox(pos, size, rotation, layerMask)); } return(Physics2D.OverlapBox(pos, size, rotation, layerMask)); // CircleCollider2D case ShapeData.ShapeType.CIRCLE: if (isTest) { return(PhysicsDebugging.OverlapCircle(pos, size.x * 0.5f, layerMask)); } return(Physics2D.OverlapCircle(pos, size.x * 0.5f, layerMask)); // Triangle needs to be a specific kind of polygon collider case ShapeData.ShapeType.TRIANGLE: RaycastHit2D[] polyhits; if (isTest) { polyhits = PhysicsDebugging.OverlapPolygon(pos, size, rotation, ShapeData.TRIANGLE_POINTS, layerMask); } else { polyhits = OverlapPolygon(pos, size, rotation, ShapeData.TRIANGLE_POINTS, layerMask); } foreach (RaycastHit2D pHit in polyhits) { if (pHit) { return(true); } } return(false); default: Debug.LogError($"Unhandled ColliderType of '{shape}' in PlayerColliderController.cs"); return(true); } }
/// <summary>Returns blend index corresponding to the given shape. /// Returns -2 if ShapeType is unrecognized. Returns -1 if shape is base shape.</summary> private int GetBlendIndexFromShape(ShapeData.ShapeType shape) { switch (shape) { case ShapeData.ShapeType.BOX: return(0); case ShapeData.ShapeType.CIRCLE: return(-1); case ShapeData.ShapeType.TRIANGLE: return(1); default: Debug.LogError("Unhandled Shape Type " + shape); break; } return(-2); }
/// <summary>Checks if the type of type of collider given will hit any unpassable walls if changed to. /// Returns an available spot which holds if a spot was found (True) or not (False) and /// the location the available spot was found</summary> /// <param name="colliderType">Shape of collider to turn into</param> /// <param name="size">The actual size of the collider</param> /// <param name="rotation">Rotation of the shape.</param> public AvailableSpot CheckIfColliderWillHitWall(ShapeData.ShapeType colliderType, Vector2 size, float rotation) { // Colored wall layer mask LayerMask colorWallLayerMask = GetCurrentColoredWallLayerMask(); Vector2 gridPos = ActiveGrid.Instance.CastToGridPosition(transform.position, new Vector2(size.x, size.y), rotation); // Physics casts don't play well with negatives sizes, so fix that size = new Vector2(Mathf.Abs(size.x) - COLLIDER_OFFSET_AMOUNT, Mathf.Abs(size.y) - COLLIDER_OFFSET_AMOUNT); // Try in multiple spots around the player // x and y for offset // i | x | y // --------- // 0 | 0 | 0 // 1 | 0 | 1 // 2 | 1 | 0 // 3 | 1 | 1 for (int i = 0; i < 4; ++i) { float tileSize = ActiveGrid.Instance.GetTileSize(); int x = i >= 2 ? 1 : 0; int y = i % 2; Vector2 offset = new Vector2(x, y) * tileSize; Vector2 curPos; // Add or subtract based on where the rounded position is int xSign = transform.position.x < gridPos.x ? -1 : 1; int ySign = transform.position.y < gridPos.y ? -1 : 1; curPos.x = gridPos.x + offset.x * xSign; curPos.y = gridPos.y + offset.y * ySign; // If there was no hit, we found a place the player can be if (!ShapeCast(colliderType, curPos, size, rotation, colorWallLayerMask)) { return(new AvailableSpot(true, curPos)); } } // If there was a hit, we cannot change return(new AvailableSpot(false, gridPos)); }
/// <summary> /// Creates save data for the player's collider controller. /// </summary> /// <param name="shapeType">Type of collider that is currently active.</param> public PlayerCollidersSaveData(ShapeData.ShapeType shapeType) { colliderType = shapeType; }
/// <summary>Tests if the given type of shape will fit in the player's current position. /// Returns an AvailableSpot to hold if a spot was found (player can fit) and /// where that spot is.</summary> /// <param name="colliderType">Shape of the collider to test.s</param> /// <param name="size">The actual size of the collider to test.</param> /// <param name="rotation">Rotation of the shape.</param> public AvailableSpot TestColliderChange(ShapeData.ShapeType colliderType, Vector2Int size, float rotation) { return(testColliderRef.CheckIfColliderWillHitWall(colliderType, size, rotation)); }