Tutorial de sus în jos pentru controlerul jucătorului pentru Unity

Mulți oameni sunt familiarizați cu genuri de jocuri precum FPS (First-Person Shooter) și RTS (Real-Time Strategy), dar există și multe jocuri care nu se încadrează într-o singură categorie specifică. Un astfel de joc este Top-Down Shooter.

Top-Down Shooter este un joc în care jucătorul este controlat dintr-o perspectivă de sus.

Exemple de împușcători de sus în jos sunt Hotline Miami, Hotline Miami 2, Original Grand Theft Auto etc.

Vampire Survivors 2

Pentru a crea un controler de caractere de sus în jos în Unity, urmați pașii de mai jos.

Pasul 1: Creați scripturile

Pentru acest tutorial, vom avea nevoie de un singur script.

  • Creați un nou script, denumiți-l SC_TopDownController, eliminați totul din el și inserați codul de mai jos în interiorul acestuia:

SC_TopDownController.cs

using UnityEngine;

[RequireComponent(typeof(Rigidbody))]
[RequireComponent(typeof(CapsuleCollider))]

public class SC_TopDownController : MonoBehaviour
{
    //Player Camera variables
    public enum CameraDirection { x, z }
    public CameraDirection cameraDirection = CameraDirection.x;
    public float cameraHeight = 20f;
    public float cameraDistance = 7f;
    public Camera playerCamera;
    public GameObject targetIndicatorPrefab;
    //Player Controller variables
    public float speed = 5.0f;
    public float gravity = 14.0f;
    public float maxVelocityChange = 10.0f;
    public bool canJump = true;
    public float jumpHeight = 2.0f;
    //Private variables
    bool grounded = false;
    Rigidbody r;
    GameObject targetObject;
    //Mouse cursor Camera offset effect
    Vector2 playerPosOnScreen;
    Vector2 cursorPosition;
    Vector2 offsetVector;
    //Plane that represents imaginary floor that will be used to calculate Aim target position
    Plane surfacePlane = new Plane();

    void Awake()
    {
        r = GetComponent<Rigidbody>();
        r.freezeRotation = true;
        r.useGravity = false;

        //Instantiate aim target prefab
        if (targetIndicatorPrefab)
        {
            targetObject = Instantiate(targetIndicatorPrefab, Vector3.zero, Quaternion.identity) as GameObject;
        }

        //Hide the cursor
        Cursor.visible = false;
    }

    void FixedUpdate()
    {
        //Setup camera offset
        Vector3 cameraOffset = Vector3.zero;
        if (cameraDirection == CameraDirection.x)
        {
            cameraOffset = new Vector3(cameraDistance, cameraHeight, 0);
        }
        else if (cameraDirection == CameraDirection.z)
        {
            cameraOffset = new Vector3(0, cameraHeight, cameraDistance);
        }

        if (grounded)
        {
            Vector3 targetVelocity = Vector3.zero;
            // Calculate how fast we should be moving
            if (cameraDirection == CameraDirection.x)
            {
                targetVelocity = new Vector3(Input.GetAxis("Vertical") * (cameraDistance >= 0 ? -1 : 1), 0, Input.GetAxis("Horizontal") * (cameraDistance >= 0 ? 1 : -1));
            }
            else if (cameraDirection == CameraDirection.z)
            {
                targetVelocity = new Vector3(Input.GetAxis("Horizontal") * (cameraDistance >= 0 ? -1 : 1), 0, Input.GetAxis("Vertical") * (cameraDistance >= 0 ? -1 : 1));
            }
            targetVelocity *= speed;

            // Apply a force that attempts to reach our target velocity
            Vector3 velocity = r.velocity;
            Vector3 velocityChange = (targetVelocity - velocity);
            velocityChange.x = Mathf.Clamp(velocityChange.x, -maxVelocityChange, maxVelocityChange);
            velocityChange.z = Mathf.Clamp(velocityChange.z, -maxVelocityChange, maxVelocityChange);
            velocityChange.y = 0;
            r.AddForce(velocityChange, ForceMode.VelocityChange);

            // Jump
            if (canJump && Input.GetButton("Jump"))
            {
                r.velocity = new Vector3(velocity.x, CalculateJumpVerticalSpeed(), velocity.z);
            }
        }

        // We apply gravity manually for more tuning control
        r.AddForce(new Vector3(0, -gravity * r.mass, 0));

        grounded = false;

        //Mouse cursor offset effect
        playerPosOnScreen = playerCamera.WorldToViewportPoint(transform.position);
        cursorPosition = playerCamera.ScreenToViewportPoint(Input.mousePosition);
        offsetVector = cursorPosition - playerPosOnScreen;

        //Camera follow
        playerCamera.transform.position = Vector3.Lerp(playerCamera.transform.position, transform.position + cameraOffset, Time.deltaTime * 7.4f);
        playerCamera.transform.LookAt(transform.position + new Vector3(-offsetVector.y * 2, 0, offsetVector.x * 2));

        //Aim target position and rotation
        targetObject.transform.position = GetAimTargetPos();
        targetObject.transform.LookAt(new Vector3(transform.position.x, targetObject.transform.position.y, transform.position.z));

        //Player rotation
        transform.LookAt(new Vector3(targetObject.transform.position.x, transform.position.y, targetObject.transform.position.z));
    }

    Vector3 GetAimTargetPos()
    {
        //Update surface plane
        surfacePlane.SetNormalAndPosition(Vector3.up, transform.position);

        //Create a ray from the Mouse click position
        Ray ray = playerCamera.ScreenPointToRay(Input.mousePosition);

        //Initialise the enter variable
        float enter = 0.0f;

        if (surfacePlane.Raycast(ray, out enter))
        {
            //Get the point that is clicked
            Vector3 hitPoint = ray.GetPoint(enter);

            //Move your cube GameObject to the point where you clicked
            return hitPoint;
        }

        //No raycast hit, hide the aim target by moving it far away
        return new Vector3(-5000, -5000, -5000);
    }

    void OnCollisionStay()
    {
        grounded = true;
    }

    float CalculateJumpVerticalSpeed()
    {
        // From the jump height and gravity we deduce the upwards speed 
        // for the character to reach at the apex.
        return Mathf.Sqrt(2 * jumpHeight * gravity);
    }
}

Pasul 2: Creați Shader-ul

Acest tutorial necesită, de asemenea, un shader personalizat, care este necesar pentru a face ținta Aim să suprapună restul obiectelor (întotdeauna deasupra).

  • Faceți clic dreapta pe vizualizarea Proiect -> Creare -> Shader -> Standart Surface Shader
  • Denumiți shaderul "Cursor"

  • Deschideți shaderul, eliminați tot ce este în interior, apoi lipiți codul de mai jos:

Cursor.shader

Shader "Custom/FX/Cursor" {
	Properties {
		_MainTex ("Base", 2D) = "white" {}
	}
	
	CGINCLUDE

		#include "UnityCG.cginc"

		sampler2D _MainTex;
		
		half4 _MainTex_ST;
						
		struct v2f {
			half4 pos : SV_POSITION;
			half2 uv : TEXCOORD0;
		};

		v2f vert(appdata_full v) {
			v2f o;
			
			o.pos = UnityObjectToClipPos (v.vertex);	
			o.uv.xy = TRANSFORM_TEX(v.texcoord, _MainTex);
					
			return o; 
		}
		
		fixed4 frag( v2f i ) : COLOR {	
			return tex2D (_MainTex, i.uv.xy);
		}
	
	ENDCG
	
	SubShader {
		Tags { "RenderType" = "Transparent" "Queue" = "Transparent+100"}
		Cull Off
		Lighting Off
		ZWrite Off
		ZTest Always
		Fog { Mode Off }
		Blend SrcAlpha OneMinusSrcAlpha
		
	Pass {
	
		CGPROGRAM
		
		#pragma vertex vert
		#pragma fragment frag
		#pragma fragmentoption ARB_precision_hint_fastest 
		
		ENDCG
		 
		}
				
	} 
	FallBack Off
}

Pasul 3: Configurați controlerul de caractere de sus în jos

Să instalăm un controler de caractere de sus în jos:

  • Creați un nou GameObject și apelați-l "Player"
  • Creați un nou Cub și scalați-l (În cazul meu, scara este (1, 2, 1))
  • Creați un al doilea cub, scalați-l mult mai mic și mutați-l într-o zonă superioară (Acesta este pur și simplu pentru a ști în ce direcție se uită jucătorul)
  • Mutați ambele cuburi în interiorul obiectului "Player" și eliminați componentele BoxCollider

Acum, înainte de a merge mai departe, să creăm prefabricatul țintă Aim:

  • Creați un nou GameObject și apelați-l "AimTarget"
  • Creați un nou Quad (GameObject -> 3D Object -> Quad) și mutați-l în interiorul obiectului "AimTarget"
  • Atribuiți textura de mai jos unui Quad și schimbați Material Shader la 'Custom/FX/Cursor'

cruce punct roșu

  • Salvați "AimTarget" în Prefab și eliminați-l din Scenă

Înapoi la instanța Player:

  • Atașați scriptul SC_TopDownController la obiectul "Player" (veți observa că a adăugat câteva componente suplimentare, cum ar fi Rigidbody și CapsuleCollider)
  • Scalați CapsuleCollider până când se potrivește cu modelul jucătorului (în cazul meu, Înălțimea este setată la 2 și Centrul este setat la (0, 1, 0)

  • Și, în sfârșit, atribuiți variabilele "Player Camera" și "Target Indicator Prefab" în SC_TopDownController

Instanța Player este acum gata, haideți să o testăm:

Sharp Coder Video player

Totul funcționează conform așteptărilor.

Articole sugerate
Crearea mișcării jucătorilor în Unity
Player 3D și 2D Wall Jump Tutorial pentru Unity
Tutorial lanternă pentru Unity
Tutorial 3D Worm Controller pentru Unity
Cum să adăugați suport pentru platforma în mișcare la controlerul de caractere în Unity
Adăugarea suportului pentru salt dublu la un controler de caractere 2D platformer în Unity
Controler de jucător RTS și MOBA pentru Unity