C#

Camera Relative Movement

Description

In many older 3D games (such as Mario 64 and the Legend of Zelda: Ocarina of Time)  for consoles like the N64 and Playstation games used a simple movement scheme called camera relative movement. In camera relative movement the player moves according to where the camera is. For example if the player holds the left button, the players avatar will run to the left in a circle around the camera. Using the two C# scripts at the bottom of this post you can do the same in just about any Unity project so long as you assign the proper variables and create the scripts necessary to interact with the player. An example of these scripts in action can be found at: Adventure Game Test.

Code

CameraRelativeMovement.cs

using UnityEngine;
using System.Collections;

public class CameraRelativeMovement : MonoBehaviour
{
    public Transform targetCamera;
    public Transform lookAtTarget;
    public Transform watchTarget;        
    public float forwardDirection;
    public float sideDirection;
    public float maxSpeed = 10.0f;        

    private CharacterMovement movement;
    private Transform myTransform;

    // Use this for initialization
    void Awake()
    {
        myTransform = transform;
        movement = GetComponent<CharacterMovement>();
    }

    // Update is called once per frame
    void Update()
    {
        Vector2 input = new Vector2(sideDirection, forwardDirection);
        float speedScale = input.magnitude;

        if (speedScale > 1.0f)
        {
            speedScale = 1.0f;
        }

        Vector3 moveRequest = GetMovementRequest(input);

        if (lookAtTarget != null)
        {
             Vector3 direction = lookAtTarget.position - transform.position;
             direction.y = 0.0f;
             movement.RequestRotateTowards(direction.normalized);
        }
        else
        {
             movement.RequestRotateTowards(moveRequest.normalized);
        }

        if (watchTarget != null)
        {
            movement.RequestWatch(watchTarget.position);
        }
        else
        {
            movement.RequestWatch();
        }

        movement.RequestMovement(moveRequest, speedScale * maxSpeed);
    }

    private Vector3 GetMovementRequest(Vector2 input)
    {
        Vector3 forward = myTransform.position - targetCamera.position;
        Vector3 right = Vector3.Cross(myTransform.up, forward);
        Vector3 moveRequest = input.y * forward + input.x * right;
        moveRequest.y = 0;
        return moveRequest;
    }
}

CameraMovement.cs

using UnityEngine;
using System.Collections;
public class CameraMovement : MonoBehaviour
{
    public float movementDamping = 5.0f;
    public float rotationDamping = 5.0f;

    private Transform myTransform;

    // Use this for initialization
    void Awake()
    {
        myTransform = transform;
    }

    public void SpringToTarget(Transform target, float preferredDistance, float preferredHeight)
    {
        float distance = Vector2.Distance(new Vector2(target.position.x, target.position.z),
                                          new Vector2(myTransform.position.x, myTransform.position.z));
        Vector3 moveDirection = target.position - myTransform.position;
        moveDirection.y = 0.0f;
        moveDirection = moveDirection.normalized * (distance - preferredDistance) + myTransform.position;
        moveDirection.y = target.position.y + preferredHeight;
        MoveToPosition(target.position, moveDirection);
    }

    public void SpringToTargetWithConstantOffset(Transform target, float preferredDistance, float preferredHeight)
    {
        float distance = Vector2.Distance(new Vector2(target.position.x, target.position.z),
                                          new Vector2(myTransform.position.x, myTransform.position.z));
        float z = Mathf.Sin(myTransform.rotation.y) * distance;
        float x = Mathf.Cos(myTransform.rotation.y) * distance;

        Vector3 moveDirection = new Vector3(x, 0, z);
        moveDirection.y = 0.0f;
        moveDirection = target.position - moveDirection.normalized * preferredDistance;
        moveDirection.y = target.position.y + preferredHeight;
        MoveToPosition(target.position, moveDirection);
    }

    // returns true if camera is pretty much behind the target
    public bool MoveBehindTarget(Transform target, float preferredDistance, float preferredHeight)
    {
        Vector3 moveDirection = target.forward;
        moveDirection.y = 0;
        moveDirection = moveDirection.normalized * -preferredDistance + target.position;
        moveDirection.y += preferredHeight;
        MoveToPosition(target.position, moveDirection);
        return (myTransform.position - moveDirection).magnitude < 0.5f;
    }

    public void RotateAroundPoint(Vector3 target, float rotation)
    {
        Vector3 forward = myTransform.position - target;
        Vector3 right = Vector3.Cross(myTransform.up, forward);
        float distance = Vector3.Distance(myTransform.position, target);

        Vector3 targetPosition = forward + right * rotation;
        targetPosition = targetPosition.normalized * distance;
        targetPosition.y = myTransform.position.y;
        targetPosition.x += target.x;
        targetPosition.z += target.z;
        MoveToPosition(target, targetPosition);
    }

    public void LookAtTarget(Vector3 direction)
    {
        transform.rotation = Quaternion.Slerp(myTransform.rotation, Quaternion.LookRotation(direction), rotationDamping * Time.deltaTime);
    }

    private void MoveToPosition(Vector3 lookAtTarget, Vector3 targetPosition)
    {
        Vector3 direction = (targetPosition - lookAtTarget).normalized;
        float distance = Vector3.Distance(lookAtTarget, targetPosition);

        RaycastHit hit;
        if (Physics.Raycast(lookAtTarget, direction, out hit, distance) &&
            (hit.collider.CompareTag("Wall") || hit.collider.CompareTag("Door")))
        {
            myTransform.position = Vector3.Lerp(myTransform.position, hit.point, movementDamping * Time.deltaTime);
        }
        else
        {
            myTransform.position = Vector3.Lerp(myTransform.position, targetPosition, movementDamping * Time.deltaTime);
        }
    }
}
Advertisements

Adventure Game Test

Play!

by: Ben Johnson

Description

This is an attempt to create a simple adventure game that works similarly to the 3D Legend of Zelda games. In this adventure you start off in a prison with a single NPC who allows you to leave, you then later find two more NPCs with a simple quest, and finally you battle your way past a guard and the prison boss. This game features several camera systems including a standard chase camera, a targeting camera for combat, and a first person camera to line up jumps and get a better view of the world. In this game all models are made of simple geometry to avoid any of the quirks with animation and allowing me to focus on recreating the basic game and camera system of The Legend of Zelda.

Controls

  • W and S – Move Character Vertically
  • A and D – Rotate Character Left and Right
  • Mouse/Left Control – Attack
  • Space – Action (Talk, Roll, Open Door)
  • Q – Use Targeting System
  • I and K – Look Up or Down (enables first person look camera until player hits Q to cancel)

Images

This slideshow requires JavaScript.

Power Pong

Play!

by: Ben Johnson

Description

As a beginning game designer it seems that creating a simple game of Pong is required as a right of passage. In this version of Pong you will battle against a simple AI opponent who will return any shot it can. To help you in your fight against this nefarious AI you can use various power ups that you collect by hitting the ball at them. Powers include the Grow box which widens your paddle, Tea Time which gives stops the ball and allows you to quick move in front of it in emergencies, and the dreaded Orange Shower which fills the screen with distracting oranges. Please note that there is no end to this game, you simply play until you have had enough.

Controls

  • W and S: Moves the paddle up and down respectively.
  • Q: Activate power up.

Images

This slideshow requires JavaScript.