Panel użytkownika
Nazwa użytkownika:
Hasło:
Nie masz jeszcze konta?

[Unity C#] Kamera zza pleców gracza

Ostatnio zmodyfikowano 2024-09-03 19:43
Autor Wiadomość
tBane
Temat założony przez niniejszego użytkownika
[Unity C#] Kamera zza pleców gracza
» 2024-09-01 22:16:39
Witam. Uczę się Unity i zastanawiam się jak w wygodny sposób napisać kamerę śledzącą zza pleców gracza

PlayerController
C/C++
using System.Collections;
using System.Collections.Generic;
using Unity.VisualScripting;
using UnityEngine;


public class PlayerController
: MonoBehaviour
{
   
   
public Rigidbody rb;
   
public Animator anim;
   
private Vector3 movement;
   
private float speed = 5.0f;
   
// how define animations ?
    // public anim_idle
    // public anim_walk
   
    // Start is called before the first frame update
   
void Start()
   
{
       
rb = GetComponent < Rigidbody >();
       
anim = GetComponent < Animator >();
       
anim.Play( "idle" );
       
anim.speed = speed;
   
}
   
   
   
// Update is called once per frame
   
void Update()
   
{
       
float rotate = Input.GetAxis( "Horizontal" );
       
float move = Input.GetAxis( "Vertical" );
       
       
movement = transform.forward * move;
       
       
if( movement != Vector3.zero )
           
 anim.Play( "walk" );
       
else
           
 anim.Play( "idle" );
       
       
transform.Rotate( 0, rotate, 0 );
       
   
}
   
   
private void FixedUpdate()
   
{
       
       
rb.MovePosition( rb.position + movement * Time.fixedDeltaTime );
   
}
}

CameraController
C/C++
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class CameraController
: MonoBehaviour
{
   
   
public GameObject player;
   
// Start is called before the first frame update
   
void Start()
   
{
       
//rb = GetComponent<Rigidbody>();
   
}
   
   
// Update is called once per frame
   
void Update()
   
{
       
    }
   
   
private void FixedUpdate()
   
{
       
       
Vector3 position;
       
position.x = player.transform.position.x;
       
position.y = player.transform.position.y + 1.5f;
       
position.z = player.transform.position.z - 2.0f;
       
       
GetComponent < Transform >().transform.position = position;
       
   
}
}
P-181541
tBane
Temat założony przez niniejszego użytkownika
» 2024-09-01 22:22:37
C/C++
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class CameraController
: MonoBehaviour
{
   
   
public GameObject player;
   
public Vector3 offset;
   
   
// Start is called before the first frame update
   
void Start()
   
{
       
Vector3 position;
       
position.x = player.transform.position.x;
       
position.y = player.transform.position.y + 1.5f;
       
position.z = player.transform.position.z - 2.0f;
       
       
offset = position - player.transform.position;
   
}
   
   
// Update is called once per frame
   
void Update()
   
{
       
    }
   
   
private void FixedUpdate()
   
{
       
transform.position = player.transform.position + player.transform.rotation * offset;
       
transform.LookAt( player.transform );
       
   
}
}
P-181542
tBane
Temat założony przez niniejszego użytkownika
» 2024-09-03 17:21:09
A jakbym chciał sterować kamerą/obrotem gracza za pomocą myszki? napisałem już częściowo kod ale znalazłem Bug'a - gdy obracamy graczem i jednocześnie poruszamy się do przody, to wtedy postać źle się przemieszcza.

C/C++
using System.Collections;
using System.Collections.Generic;
using Unity.VisualScripting;
using UnityEngine;


public class PlayerController
: MonoBehaviour
{
   
   
public Rigidbody rb;
   
public Animator anim;
   
public Camera camera;
   
   
   
private Vector3 movement;
   
private float speed = 5.0f;
   
private float animSpeed = 5.0f;
   
private float mouseSensitivity = 1000.0f;
   
private float cameraPitch = 0.0f;
   
   
// how define animations ?
    // public anim_idle
    // public anim_walk
   
    // Start is called before the first frame update
   
void Start()
   
{
       
rb = GetComponent < Rigidbody >();
       
anim = GetComponent < Animator >();
       
anim.Play( "idle" );
       
anim.speed = animSpeed;
   
}
   
   
   
// Update is called once per frame
   
void Update()
   
{
       
// ROTATE
       
        // Pobieranie ruchu myszy
       
float mouseX = Input.GetAxis( "Mouse X" ) * mouseSensitivity * Time.deltaTime;
       
float mouseY = Input.GetAxis( "Mouse Y" ) * mouseSensitivity * Time.deltaTime;
       
       
// Obracanie gracza w poziomie
       
transform.Rotate( Vector3.up * mouseX );
       
       
// Obracanie kamery w pionie
       
cameraPitch -= mouseY;
       
cameraPitch = Mathf.Clamp( cameraPitch, - 90.0f, 90.0f ); // Ograniczenie kąta obrotu, aby uniknąć nadmiernego obracania
       
       
camera.transform.localEulerAngles = Vector3.right * cameraPitch;
       
camera.transform.LookAt( transform.position + Vector3.up ); // + Vector3.up aby patrzyła na środek gracza (głowę)
       
       
        // MOVE
       
float move = Input.GetAxis( "Vertical" ) * speed;
       
movement = transform.forward * move;
       
       
if( movement != Vector3.zero )
           
 anim.Play( "walk" );
       
else
           
 anim.Play( "idle" );
       
       
   
}
   
   
private void FixedUpdate()
   
{
       
       
rb.MovePosition( rb.position + movement * Time.fixedDeltaTime );
   
}
}
P-181543
DejaVu
» 2024-09-03 17:43:01
ChatGPT 4o:

W Twoim kodzie problem polega na tym, że ruch gracza jest zależny od kierunku obrotu kamery, a nie od rzeczywistego kierunku gracza. W wyniku tego, podczas obracania się myszką i jednoczesnego ruchu do przodu, postać może poruszać się w nieoczekiwanym kierunku.

Aby to naprawić, musisz oddzielić rotację kamery od ruchu gracza, a ruch gracza powinien być zależny od kierunku, w którym gracz patrzy, a nie od globalnych współrzędnych.

### Poprawiony kod

Wprowadźmy kilka zmian w kodzie, aby rozwiązać ten problem:

1. **Zmiana kierunku ruchu**: Ruch gracza powinien być zależny od rotacji gracza, a nie od globalnego `transform.forward`.

2. **Oddzielenie rotacji kamery i gracza**: Kamera powinna być dzieckiem gracza i poruszać się z nim, ale jej rotacja w osi Y powinna być zależna tylko od myszy.

3. **Aktualizacja animacji**: Upewnij się, że animacja zmienia się tylko wtedy, gdy gracz rzeczywiście się porusza.

Oto zaktualizowany kod:


using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class PlayerController : MonoBehaviour
{
    public Rigidbody rb;
    public Animator anim;
    public Camera playerCamera;

    private Vector3 movement;
    private float speed = 5.0f;
    private float animSpeed = 5.0f;
    private float mouseSensitivity = 1000.0f;
    private float cameraPitch = 0.0f;

    void Start()
    {
        rb = GetComponent<Rigidbody>();
        anim = GetComponent<Animator>();
        anim.Play("idle");
        anim.speed = animSpeed;
    }

    void Update()
    {
        // ROTATE

        // Pobieranie ruchu myszy
        float mouseX = Input.GetAxis("Mouse X") * mouseSensitivity * Time.deltaTime;
        float mouseY = Input.GetAxis("Mouse Y") * mouseSensitivity * Time.deltaTime;

        // Obracanie gracza w poziomie
        transform.Rotate(Vector3.up * mouseX);

        // Obracanie kamery w pionie
        cameraPitch -= mouseY;
        cameraPitch = Mathf.Clamp(cameraPitch, -90.0f, 90.0f);

        playerCamera.transform.localEulerAngles = Vector3.right * cameraPitch;

        // MOVE
        float moveZ = Input.GetAxis("Vertical");
        float moveX = Input.GetAxis("Horizontal");

        movement = (transform.forward * moveZ + transform.right * moveX).normalized * speed;

        if (movement.magnitude > 0.1f)
        {
            anim.Play("walk");
        }
        else
        {
            anim.Play("idle");
        }
    }

    private void FixedUpdate()
    {
        rb.MovePosition(rb.position + movement * Time.fixedDeltaTime);
    }
}

### Co zostało zmienione:

1. **Ruch gracza**: W zmiennej `movement` ruch gracza jest teraz zależny od jego lokalnego kierunku (`transform.forward` i `transform.right`), co oznacza, że gracz porusza się w kierunku, w którym jest obrócony.

2. **Rotacja kamery**: Rotacja kamery w osi Y jest kontrolowana oddzielnie za pomocą zmiennej `cameraPitch`, aby umożliwić swobodny obrót w pionie.

3. **Animacja**: Warunek sprawdzający ruch gracza został zmieniony, aby używać `magnitude` zmiennej `movement` do ustalenia, czy gracz się porusza, czy nie.

Te zmiany powinny rozwiązać problem z poruszaniem się gracza w nieodpowiednich kierunkach podczas obracania kamery i ruchu do przodu.
P-181544
tBane
Temat założony przez niniejszego użytkownika
» 2024-09-03 17:55:56
Nie działa :-/
P-181545
DejaVu
» 2024-09-03 17:56:42
a co nie działa? ChatGPT 4o na podstawie Twojego 'precyzyjnego' opisu usterki:

Przepraszam za kłopot. Skoro zmodyfikowany kod nie działa jak oczekiwano, spróbujmy dokładniej przeanalizować problem i poprawić kod. Możliwe, że występują inne błędy, które wymagają naprawy.

### Możliwe przyczyny problemu

1. **Ruch i animacja**: Ruch może nie działać prawidłowo z powodu nieodpowiedniego przeliczania ruchu w `Update` i jego aplikacji w `FixedUpdate`.
2. **Kamera i obrót gracza**: Rotacja kamery i gracza może się nakładać lub powodować inne nieoczekiwane zachowanie, szczególnie jeśli kamera jest dzieckiem gracza.
3. **Fizyka Rigidbody**: Kiedy używasz `Rigidbody`, ważne jest, aby używać metod fizyki w `FixedUpdate`, a metody nie związane z fizyką w `Update`.

### Poprawiony kod

Poniżej jest kolejna wersja kodu, w której dodałem kilka poprawek:

- **Ruch i obrót**: Używamy `Rigidbody` do obsługi ruchu i obrotu gracza, co zapewnia lepsze połączenie z fizyką Unity.
- **Animacje**: Animacje są aktualizowane na podstawie prędkości gracza, a nie tylko wejścia z klawiatury.
- **Kamera**: Kamera obraca się niezależnie od gracza w osi Y, co eliminuje problemy z nałożeniem rotacji.

Spróbuj poniższego kodu:


using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class PlayerController : MonoBehaviour
{
    public Rigidbody rb;
    public Animator anim;
    public Camera playerCamera;

    private Vector3 movement;
    private float speed = 5.0f;
    private float animSpeed = 5.0f;
    private float mouseSensitivity = 1000.0f;
    private float cameraPitch = 0.0f;

    void Start()
    {
        rb = GetComponent<Rigidbody>();
        anim = GetComponent<Animator>();
        anim.speed = animSpeed;
    }

    void Update()
    {
        // Obracanie gracza w poziomie
        float mouseX = Input.GetAxis("Mouse X") * mouseSensitivity * Time.deltaTime;
        transform.Rotate(Vector3.up * mouseX);

        // Obracanie kamery w pionie
        float mouseY = Input.GetAxis("Mouse Y") * mouseSensitivity * Time.deltaTime;
        cameraPitch -= mouseY;
        cameraPitch = Mathf.Clamp(cameraPitch, -90.0f, 90.0f);

        playerCamera.transform.localEulerAngles = Vector3.right * cameraPitch;

        // Ruch gracza
        float moveZ = Input.GetAxis("Vertical");
        float moveX = Input.GetAxis("Horizontal");

        Vector3 direction = transform.forward * moveZ + transform.right * moveX;
        movement = direction.normalized * speed;

        // Aktualizacja animacji
        if (movement.magnitude > 0.1f)
        {
            anim.Play("walk");
        }
        else
        {
            anim.Play("idle");
        }
    }

    private void FixedUpdate()
    {
        // Przemieszczenie gracza
        rb.MovePosition(rb.position + movement * Time.fixedDeltaTime);
    }
}

### Co zmieniono:

1. **Ruch gracza**: Ruch jest teraz przeliczany w `Update` na podstawie wejść `Vertical` i `Horizontal`, a następnie aplikowany w `FixedUpdate` przy użyciu `Rigidbody.MovePosition`.
2. **Rotacja kamery**: Rotacja kamery jest teraz oddzielona od obrotu gracza. Gracz obraca się w osi Y (lewo-prawo) na podstawie ruchu myszy, a kamera obraca się w osi X (góra-dół) niezależnie.
3. **Animacje**: Animacje są odtwarzane na podstawie prędkości ruchu gracza, co zapewnia płynniejsze przełączanie między animacjami.

### Dodatkowe uwagi

- Upewnij się, że w hierarchii Unity kamera jest prawidłowo przypisana do zmiennej `playerCamera` w inspektorze.
- Upewnij się, że animacje „walk” i „idle” są prawidłowo zaimplementowane i dostępne w animatorze.
- Jeżeli problem nadal występuje, warto sprawdzić, czy nie ma innych skryptów wpływających na obiekt gracza lub jego fizykę.

Jeśli masz dodatkowe pytania lub potrzebujesz dalszej pomocy, daj znać!
P-181546
tBane
Temat założony przez niniejszego użytkownika
» 2024-09-03 18:03:57
Też nie działa. Kamera dziwnie pracuje.
P-181547
DejaVu
» 2024-09-03 18:04:52
ChatGPT 4o po moich pytaniach:

Masz rację, w Unity można zrobić sterowanie kamerą zza pleców gracza (tzw. **Third-Person Camera**) w bardziej standardowy i efektywny sposób, korzystając z wbudowanych funkcji i komponentów Unity. Zastosowanie podejścia opartego na najlepszych praktykach oraz narzędziach dostarczanych przez Unity może uprościć implementację, zmniejszyć ilość kodu i zapewnić bardziej płynne i naturalne sterowanie.

### Standardowe podejście do kamery zza pleców gracza w Unity

#### 1. Używanie komponentu `Cinemachine`

Unity dostarcza potężny pakiet o nazwie **Cinemachine**, który umożliwia łatwe tworzenie i kontrolowanie kamer w grze. Cinemachine oferuje gotowe rozwiązania do implementacji kamer trzeciej osoby bez potrzeby pisania skomplikowanego kodu. Cinemachine obsługuje płynne przejścia między kamerami, śledzenie gracza, a także różne efekty, takie jak tłumienie drgań czy automatyczne ustawianie kadru.

**Jak używać Cinemachine dla kamery zza pleców gracza:**

1. **Zainstaluj Cinemachine:**
   - Przejdź do `Window > Package Manager`.
   - Wybierz **Unity Registry** z listy rozwijanej.
   - Znajdź i zainstaluj pakiet **Cinemachine**.

2. **Utwórz nową kamerę Cinemachine:**
   - W menu `GameObject > Cinemachine` wybierz **Create FreeLook Camera**.
   - Cinemachine automatycznie utworzy nową kamerę oraz niezbędne obiekty.

3. **Podłącz kamerę do gracza:**
   - Ustaw gracza jako **Follow** oraz **Look At** obiekt w komponencie Cinemachine FreeLook Camera.

4. **Dostosuj parametry kamery:**
   - Użyj inspektora, aby dostosować prędkość obrotu, czułość oraz inne parametry kamery do swoich potrzeb. Cinemachine pozwala na intuicyjne dostosowanie orbit kamery oraz różnych zachowań.

Po skonfigurowaniu Cinemachine, ruch kamery będzie automatycznie zarządzany przez komponent, co uprości kod i zmniejszy liczbę ręcznych operacji.

#### 2. Używanie wbudowanych funkcji Unity

Jeśli chcesz zrobić to ręcznie, bez Cinemachine, możesz nadal uprościć kod za pomocą wbudowanych funkcji i komponentów Unity:

- **Transform.RotateAround**: Można użyć tej funkcji, aby obrócić kamerę wokół gracza na podstawie ruchu myszy.
- **SmoothDamp**: Użyj tej funkcji, aby uzyskać płynne przejścia i ruchy kamery.

Poniżej znajduje się przykładowy kod, który ilustruje uproszczone podejście do obsługi kamery trzeciej osoby bez Cinemachine:


using UnityEngine;

public class ThirdPersonCamera : MonoBehaviour
{
    public Transform player; // Obiekt gracza
    public Vector3 offset;   // Offset kamery względem gracza
    public float sensitivity = 5.0f; // Czułość myszy
    public float smoothing = 2.0f;   // Wygładzenie ruchu kamery

    private Vector3 velocity = Vector3.zero;

    void Start()
    {
        offset = transform.position - player.position; // Ustawienie początkowego offsetu
    }

    void LateUpdate()
    {
        // Pobranie wartości ruchu myszy
        float mouseHorizontal = Input.GetAxis("Mouse X") * sensitivity;
        float mouseVertical = -Input.GetAxis("Mouse Y") * sensitivity;

        // Obrót kamery wokół gracza na podstawie ruchu myszy
        offset = Quaternion.AngleAxis(mouseHorizontal, Vector3.up) * offset;
        offset = Quaternion.AngleAxis(mouseVertical, transform.right) * offset;

        // Docelowa pozycja kamery
        Vector3 targetPosition = player.position + offset;

        // Płynne przejście do nowej pozycji kamery
        transform.position = Vector3.SmoothDamp(transform.position, targetPosition, ref velocity, smoothing);

        // Kamera zawsze skierowana na gracza
        transform.LookAt(player.position);
    }
}

#### Kluczowe elementy tego podejścia:

- **Offset**: Przechowuje początkową odległość kamery od gracza.
- **SmoothDamp**: Używane do uzyskania płynnego ruchu kamery, który nie jest zbyt gwałtowny.
- **RotateAround**: Można użyć zamiast `Quaternion.AngleAxis` do obrotu kamery wokół gracza.
- **LateUpdate**: Jest używane do aktualizacji pozycji kamery po tym, jak wszystkie inne aktualizacje w grze zostały wykonane, co zapewnia, że kamera podąża za grą w sposób płynny.

### Podsumowanie

- **Cinemachine** jest zalecane, jeśli chcesz uzyskać więcej kontroli i funkcji bez pisania zbyt dużej ilości kodu. Jest to nowoczesne rozwiązanie rekomendowane przez Unity.
- **Ręczne podejście** jest bardziej elastyczne, ale wymaga więcej kodu i staranności, aby działało płynnie i niezawodnie. Można użyć uproszczonych metod jak `Transform.RotateAround` i `SmoothDamp`, aby zmniejszyć skomplikowanie kodu.

Oba podejścia są poprawne, ale pierwsze (z użyciem Cinemachine) jest bardziej zbliżone do współczesnych standardów Unity i często zalecane dla nowych projektów.
P-181548
« 1 » 2
  Strona 1 z 2 Następna strona