Explanation of issue: Euler Angles
When using “int _yRotation = pState.lookingRight ? 0 : 180;” in “WallJump()”, it sets the “eulerAngles.y” to either [0] or [180], depending on the Player’s “lookingRight” bool. The idea is to have the player bounce off the wall and face away from the wall when they do so. The issue with this code is that “eulerAngles” aren’t affected by normal forms of rotation, like movement keys in game or the Transform Rotation in the inspector, as can be seen in here:
https://docs.unity3d.com/ScriptReference/Transform-eulerAngles.html#:~:text=eulerAngles%20represents%20rotation%20in%20world,localEulerAngles.
Rather, they have to be reset by code back to a [0] value / normal to have your Player matching up correctly with your intended actions. Thus, we reset the “eulerAngles.y” to 0 when we write the “StopWallJumping()” code, where the player bounces away from the wall and stays that way for the set “wallJumpingDuration” before being free to move.
Understanding how Euler Angles work, we can remove the differentiated “pState.lookingRight” code from “WallJump()” as they do not affect the “eulerAngles” as intended. Thus, allowing both directions of wall jumping to bounce off the wall.
3. Collectibles do not disappear when picking them up until after the pickup canvas has disappeared
Add “gameObject.GetComponent[SpriteRenderer]().enabled = false;” into all Collectibles’ scripts with ShowUI()
Then, go to HeartController.cs and change InstantiateHeartContainers() to a public void.
Move all the code from Start() into InstantiateHeartContatiners(), putting the code with UpdateHeartsHUD() to the bottom of the method and the rest above.
Finally, call InstantiateHeartContainers() using FindObjectOfType to find HeartController.
SaveData.cs
[System.Serializable]
public struct SaveData
{
public static SaveData Instance;
//player stuff
public int playerHealth;
public int playerMaxHealth;
public int playerHeartShards;
...
#region Player stuff
public void SavePlayerData()
{
using(BinaryWriter writer = new BinaryWriter(File.OpenWrite(Application.persistentDataPath + "/save.player.data")))
{
playerHealth = PlayerController.Instance.Health;
writer.Write(playerHealth);
playerMaxHealth = PlayerController.Instance.maxHealth;
writer.Write(playerMaxHealth);
playerHeartShards = PlayerController.Instance.heartShards;
writer.Write(playerHeartShards);
playerMana = PlayerController.Instance.Mana;
writer.Write(playerMana);
...
}
Debug.Log("saved player data");
}
public void LoadPlayerData()
{
if(File.Exists(Application.persistentDataPath + "/save.player.data"))
{
using(BinaryReader reader = new BinaryReader(File.OpenRead(Application.persistentDataPath + "/save.player.data")))
{
playerHealth = reader.ReadInt32();
playerMaxHealth = reader.ReadInt32();
playerHeartShards = reader.ReadInt32();
playerMana = reader.ReadSingle();
playerHalfMana = reader.ReadBoolean();
...
lastScene = reader.ReadString();
SceneManager.LoadScene(lastScene);
PlayerController.Instance.transform.position = playerPosition;
PlayerController.Instance.halfMana = playerHalfMana;
PlayerController.Instance.Health = playerHealth;
PlayerController.Instance.maxHealth = playerMaxHealth;
PlayerController.Instance.heartShards = playerHeartShards;
PlayerController.Instance.Mana = playerMana;
...
}
Debug.Log("load player data");
Debug.Log(playerHalfMana);
}
}
else
{
...
PlayerController.Instance.heartShards = 0;
}
#endregion
}
HeartController.cs
public void Start()
{
heartContainers = new GameObject[PlayerController.Instance.maxTotalHealth];
heartFills = new Image[PlayerController.Instance.maxTotalHealth];
InstantiateHeartContainers();
PlayerController.Instance.onHealthChangedCallback += UpdateHeartsHUD;
UpdateHeartsHUD();
}
public void InstantiateHeartContainers()
{
heartContainers = new GameObject[PlayerController.Instance.maxHealth];
heartFills = new Image[PlayerController.Instance.maxHealth];
for (int i = 0; i < PlayerController.Instance.maxTotalHealth; i++)
{
GameObject temp = Instantiate(heartContainerPrefab);
temp.transform.SetParent(heartsParent, false);
heartContainers[i] = temp;
heartFills[i] = temp.transform.Find("HeartFill").GetComponent<Image>();
}
PlayerController.Instance.onHealthChangedCallback += UpdateHeartsHUD;
UpdateHeartsHUD();
}
PlayerController.cs
// Start is called before the first frame update
void Start()
{
...
SaveData.Instance.LoadPlayerData();
if (halfMana)
{
UIManager.Instance.SwitchMana(UIManager.ManaState.HalfMana);
}
else
{
UIManager.Instance.SwitchMana(UIManager.ManaState.FullMana);
}
FindObjectOfType[HeartController]().InstantiateHeartContainers();
...
}
4.5. Alternative Method.
[We’ve found a simpler method for this issue after the change in SaveData.cs]
In HeartController.cs Start(), change the heartContainers and heartFills to reference the maxTotalHealth instead of maxHealth.
in InstantiateHeartContainers(), we’ll also reference the maxTotalHealth.
Finally, in our PlayerController.cs Start(), invoke the onHealthChangedCallback to ensure that when we load our player data, our maxHealth is also reset correctly on Start().
1. You can reduce the Wall Jumping Power to a lower more manageable value.
Lower Wall Jumping Power Y value.
2. Set the player’s Rigidbody2D’s Y velocity to [0] in StopWallJumping()
void StopWallJumping()
{
isWallJumping = false;
rb.velocity = new Vector2(rb.velocity.x, 0);
transform.eulerAngles = new Vector2(transform.eulerAngles.x, 0);
}
That will be all for Part 8.
Hopefully this can help you on any issues you may have. However, if you find that your issues weren’t addressed or is a unique circumstance, you can submit a forum post to go into detail on your problem for further assistance.