Need help on Mega Man-style camera movement

Updated on July 4, 2018 in [A] Unity Scripting
Share on Facebook0Tweet about this on TwitterShare on Google+0Share on Reddit0
0 on July 4, 2018

Hello there.

I am trying to write code to simulate camera movement similar to Mega Man, especially when the camera follows the player when he/she/it is away from the centre of the screen, similar to what is shown in this video: https://youtu.be/PcWApzWGpoI?t=55s

I am having some trouble with regards to simulate the camera movement if the player character is not at the centre of the screen. The following is my full code:

using UnityEngine;
public enum CameraPanDirection
{
 UP,
 DOWN,
 LEFT,
 RIGHT
}
[RequireComponent(typeof(Camera))]
public class PlayerCamera : MonoBehaviour
{
 public static PlayerCamera instance;
private const float BOX_HEIGHT = 10F;
private new Camera camera;
[SerializeField] private Vector2 rightCameraViewportPosition;
 [SerializeField] private Vector2 leftCameraViewportPosition;
private float positionX = 0f;
 private float positionY = 0f;
private Transform player;
 private Vector3 playerViewportPosition;
 private SebLague.PlayerInputManager inputManager;
private Bounds currentCameraBoundary;
private Bounds box;
 private float boxWidth = 0f;
#region FIELDS AND METHODS FOR PANNING
 private bool isPanning = false;
 public bool IsPanning { set { isPanning = value; } }
[SerializeField] private float panSpeed = 5f;
private CameraPanDirection panDirection;
 public CameraPanDirection PanDirection { set { panDirection = value; } }
private Vector3 panTargetPosition = Vector3.zero;
 #endregion
private void Awake()
 {
 instance = this;
camera = GetComponent<Camera>();
 if (gameObject.tag != "MainCamera")
 {
 gameObject.tag = "MainCamera";
 }
box = new Bounds();
 player = GameObject.FindGameObjectWithTag("Player").transform;
 inputManager = player.GetComponent<SebLague.PlayerInputManager>();
 }
private void Start()
 {
 InvokeRepeating("AdjustAccordingToAspectRatio", 0f, 0.01f);
 }
private void Update()
 {
 playerViewportPosition = camera.WorldToViewportPoint(player.position);
if (isPanning)
 {
 Pan();
 }
 }
private void LateUpdate()
 {
 if (!isPanning)
 {
 FollowPlayer();
 }
 }
private void AdjustAccordingToAspectRatio()
 {
 // 16:10
 if (camera.aspect >= 1.6f && camera.aspect < 1.7f)
 {
 boxWidth = 16f;
 }
// 16:9
 if (camera.aspect >= 1.7f && camera.aspect < 1.8f)
 {
 boxWidth = 17.7749998f;
 }
// 5:4
 if (camera.aspect >= 1.25f && camera.aspect < 1.3f)
 {
 boxWidth = 12.5f;
 }
// 4:3
 if (camera.aspect >= 1.3f && camera.aspect < 1.4f)
 {
 boxWidth = 13.35f;
 }
// 3:2
 if (camera.aspect >= 1.5f && camera.aspect < 1.6f)
 {
 boxWidth = 15f;
 }
box.size = new Vector2(boxWidth, BOX_HEIGHT);
 }
private void FollowPlayer()
 {
 if (GameObject.Find("Boundary") != null)
 {
 currentCameraBoundary = GameObject.Find("Boundary").GetComponent<BoxCollider2D>().bounds;
float halfSizeX = box.size.x / 2;
 float halfSizeY = box.size.y / 2;
 // Player's viewport x-position is less within the centre
 if (playerViewportPosition.x > 0.494f && playerViewportPosition.x < 0.504f)
 {
 Debug.Log("Follow player normally");
// Follow player normally
 positionX = Mathf.Clamp(player.position.x, currentCameraBoundary.min.x + halfSizeX, currentCameraBoundary.max.x - halfSizeX);
 positionY = Mathf.Clamp(player.position.y, currentCameraBoundary.min.y + halfSizeY, currentCameraBoundary.max.y - halfSizeY);
transform.position = new Vector3(positionX, positionY, transform.position.z);
return;
 }
 // Player's viewport x-position is greater than the centre
 else if (playerViewportPosition.x < 0.494f)
 {
 if (inputManager.DirectionalInput.x < 0f)
 {
 if (transform.position.x > currentCameraBoundary.min.x + halfSizeX)
 {
 Debug.Log("Keep moving to the left");
Vector3 newCameraPosition = camera.ViewportToWorldPoint(leftCameraViewportPosition);
 newCameraPosition.x = Mathf.Clamp(newCameraPosition.x, currentCameraBoundary.min.x + halfSizeX, currentCameraBoundary.max.x - halfSizeX);
 newCameraPosition.y = transform.position.y;
 newCameraPosition.z = transform.position.z;
 transform.position = newCameraPosition;
 }
 }
 else
 {
 // Do not follow player
 }
 }
 // Player's viewport x-position is less than the centre
 else if (playerViewportPosition.x > 0.504f)
 {
 if (inputManager.DirectionalInput.x > 0f)
 {
 if (transform.position.x < currentCameraBoundary.max.x - halfSizeX)
 {
 Debug.Log("Keep moving to the right");
Vector3 newCameraPosition = camera.ViewportToWorldPoint(rightCameraViewportPosition);
 newCameraPosition.x = Mathf.Clamp(newCameraPosition.x, currentCameraBoundary.min.x + halfSizeX, currentCameraBoundary.max.x - halfSizeX);
 newCameraPosition.y = transform.position.y;
 newCameraPosition.z = transform.position.z;
 transform.position = newCameraPosition;
 }
 }
 else
 {
 // Do not follow player
 }
 }
 }
 }
private void Pan()
 {
 Time.timeScale = 0f;
switch (panDirection)
 {
 case CameraPanDirection.UP:
 transform.Translate(panSpeed * Vector2.up * Time.unscaledDeltaTime);
 break;
 case CameraPanDirection.DOWN:
 transform.Translate(panSpeed * Vector2.down * Time.unscaledDeltaTime);
 break;
 case CameraPanDirection.LEFT:
 transform.Translate(panSpeed * Vector2.left * Time.unscaledDeltaTime);
 break;
 case CameraPanDirection.RIGHT:
 transform.Translate(panSpeed * Vector2.right * Time.unscaledDeltaTime);
 break;
 }
if ((panDirection == CameraPanDirection.UP && transform.position.y >= panTargetPosition.y) ||
 (panDirection == CameraPanDirection.DOWN && transform.position.y <= panTargetPosition.y) ||
 (panDirection == CameraPanDirection.LEFT && transform.position.x <= panTargetPosition.x) ||
 (panDirection == CameraPanDirection.RIGHT && transform.position.x >= panTargetPosition.x))
 {
 isPanning = false;
 Time.timeScale = 1f;
 }
 }
public void SetPanTargetPosition()
 {
 switch (panDirection)
 {
 case CameraPanDirection.UP:
 panTargetPosition = transform.position + new Vector3(0f, BOX_HEIGHT, 0f);
 break;
 case CameraPanDirection.DOWN:
 panTargetPosition = transform.position - new Vector3(0f, BOX_HEIGHT, 0f);
 break;
 case CameraPanDirection.LEFT:
 panTargetPosition = transform.position - new Vector3(boxWidth, 0f, 0f);
 break;
 case CameraPanDirection.RIGHT:
 panTargetPosition = transform.position + new Vector3(boxWidth, 0f, 0f);
 break;
 }
 }
}

 

using UnityEngine;
[RequireComponent(typeof(BoxCollider2D))]
public class BoundaryManager : MonoBehaviour
{
 private BoxCollider2D box;
 private Transform player;
 private GameObject boundary;
private bool PlayerIsInsideBoundary(Bounds _bounds, Vector3 _position)
 {
 return 
 _position.x >= _bounds.min.x && _position.x <= _bounds.max.x &&
 _position.y >= _bounds.min.y && _position.y <= _bounds.max.y;
 }
private void Awake()
 {
 box = GetComponent<BoxCollider2D>();
 player = GameObject.FindGameObjectWithTag("Player").transform;
 boundary = transform.GetChild(0).gameObject;
 }
private void Start()
 {
 InvokeRepeating("ManageBoundary", 0.001f, 0.001f);
 }
private void ManageBoundary()
 {
 if (boundary.activeInHierarchy && !PlayerIsInsideBoundary(box.bounds, player.position))
 {
 if (player.position.y > box.bounds.max.y)
 {
 PlayerCamera.instance.PanDirection = CameraPanDirection.UP;
 }
 else if (player.position.y < box.bounds.min.y)
 {
 PlayerCamera.instance.PanDirection = CameraPanDirection.DOWN;
 }
 else if (player.position.x < box.bounds.min.x)
 {
 PlayerCamera.instance.PanDirection = CameraPanDirection.LEFT;
 }
 else if (player.position.x > box.bounds.max.x)
 {
 PlayerCamera.instance.PanDirection = CameraPanDirection.RIGHT;
 }
PlayerCamera.instance.SetPanTargetPosition();
 PlayerCamera.instance.IsPanning = true;
 }
boundary.SetActive(PlayerIsInsideBoundary(box.bounds, player.position));
 }
}

I appreciate your prompt, detailed, and constructive feedback. Thank you very much!

  • Liked by
Reply