• Najnowsze pytania
  • Bez odpowiedzi
  • Zadaj pytanie
  • Kategorie
  • Tagi
  • Zdobyte punkty
  • Ekipa ninja
  • IRC
  • FAQ
  • Regulamin
  • Książki warte uwagi

C#, Unity 2D - AI - poruszanie horyzontalne za graczem, jeżeli jest w zasięgu

VPS Starter Arubacloud
0 głosów
642 wizyt
pytanie zadane 13 grudnia 2019 w C# przez Teslum_369 Gaduła (4,190 p.)

Witam,

Na wstępie chciałbym oznajmić, iż jestem bardzo początkującym programistą w C# / Unity 2D.

Tworzę moją pierwszą grę (edukacyjną), gdzie chcę użyć klasyczne elementy platformówki. Opieram się głównie na poradnikach angielsko języcznych i czasami po prostu używam cudzego kodu do wykonania jakiegoś elementu / akcji etc. Zawsze straram się jednak zrozumieć kod i sprawdzajam co dane linie kodu robią.

Chciałbym zapytać, jak sprawić, aby postać ruszała się horyzontalnie (tylko w lewo i prawo) za graczem, jeżeli jest w zasięgu, oraz gdy gracz opuści go, AI wraca na swoje miejsce. Nie ukrywam, iż posłużyłem się kodem z internetu, ponieważ na moim obecnym poziomie raczej nie dałbym napisać tego skryptu własnymi rękoma. Przedstawiam kod: (Podkreślam, nie jest moim własnym skryptem)

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

public class Enemy : MonoBehaviour
{
    public Transform player; // changed this to Transform
    public float detectRange = 10; // this gets multiplied by itself to compare to a sqr magnitude check (instead of distance)
    public bool inRange = false;
    public float moveSpeed = 2f; // you can adjust this, of course.
    Rigidbody2D rb;  // cached the reference, so you can avoid GetComponent calls in Update/FixedUpdate.

    void Awake()
    {
        rb = GetComponent<Rigidbody2D>();
        detectRange *= detectRange;
    }

    void Update()
    {
        // a little cheaper than 'distance'.. deleted the code to create a position from the player values.
        float distsqr = (player.position - transform.position).sqrMagnitude;

        if (distsqr <= detectRange)
        {
            inRange = true;
            // get a velocity based on the normalized direction, multiplied by move speed.
            Vector2 velocity = (player.transform.position - transform.position).normalized * moveSpeed;
            rb.velocity = velocity;
        }

    }

}

Zatem jeszcze raz zapytam, jak mógłbym dodać opcję poruszania się tylko w lewo i w prawo oraz po odejściu gracza po za zasięg, AI wraca do swojego "pierwotnego" miejsca?

Naprawdę dziękuję z góry za pomoc smiley.

1 odpowiedź

+2 głosów
odpowiedź 14 grudnia 2019 przez piotrsz109 Stary wyjadacz (13,730 p.)
wybrane 14 grudnia 2019 przez Teslum_369
 
Najlepsza
Aby postac poruszała się tylko w dwóch osiach, dla zmiennej velocity, musisz ustawić dla jednej z współrzędnych wartość 0.

Aby postać wracała, gdy postać nie jest w zasięgu w metodzie Update musisz dodać warunek, czy gracz nie jest w zasięgu. W ciele if'a piszesz kod podobny do zawierającego się w poprzednim warunku - tylko tam zawierasz pozycję początkową, którą np.: zapisujesz w zmiennej w metodzie start.

Pozdrawiam
komentarz 14 grudnia 2019 przez Teslum_369 Gaduła (4,190 p.)

Dzięki za odpowiedź! :)

Chodzenie horyzontalne działa doskonale. Miałem jednak trochę problem z implemetacją kodu dot.  "wracania" AI do pierwotnego miejsca. Kombinowałem, kombinowałem, aż niespodziewanie wymyśliłem inny sposób. Skoro i tak już AI followuje gracza to czemu by nie stworzyć obiektu w pierwotnym miejscu AI i później zmienić follow na ten obiekt? No właśnie, wszystko nawet spoko działa, tylko problem mam jeszcze taki, że jak już dotrze do swojego miejsca to AI się bardzo trzęsie. Jak mógłbym zatrzymać go w tej pozycji? Próbowałem zmienić prędkość ruchu na 0, ale nie działało tak jak trzeba :/ (może po prostu coś źle napisałem, nie wiem sad). Masz może jakiś pomysł jak sprawić by bot się nie trząsł po dotarciu do swojej pierwotnej pozycji?

Kodzik:

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

public class Enemy : MonoBehaviour
{
    public Transform player; // changed this to Transform
    public Transform obj; // changed this to Transform
    public float moveSpeed = 2f;
    public float detectRange = 2; // this gets multiplied by itself to compare to a sqr magnitude check (instead of distance)
    public bool inRange = false;
    Rigidbody2D rb;  // cached the reference, so you can avoid GetComponent calls in Update/FixedUpdate.
    Rigidbody2D rb_obj;  // cached the reference, so you can avoid GetComponent calls in Update/FixedUpdate.


    void Awake()
    {
        rb = GetComponent<Rigidbody2D>();
        rb_obj = GetComponent<Rigidbody2D>();

    }

  

    void Update()
    {
        // a little cheaper than 'distance'.. deleted the code to create a position from the player values.
        float distsqr = (player.position - transform.position).sqrMagnitude;

        if (distsqr <= detectRange)
        {
            inRange = true;
            // get a velocity based on the normalized direction, multiplied by move speed.
            Vector2 velocity = (player.transform.position - transform.position).normalized;
            velocity.y = 0;
            rb.velocity = velocity*2;

        }

        if (distsqr > detectRange && inRange == true)
        {
            inRange = true;
            Vector2 velocity = (obj.transform.position - transform.position).normalized;
            velocity.y = 0;
            rb_obj.velocity = velocity * 2;

            if(transform.position.x == 15f)
            {
                moveSpeed = 0f;
            }

        }
    }


}

Pozdrawiam :)

komentarz 14 grudnia 2019 przez piotrsz109 Stary wyjadacz (13,730 p.)
Możesz dopisać warunek, że jeśli odległość jest mniejsza równa np.: 0.5f to velocity = Vector3.zero
komentarz 14 grudnia 2019 przez Teslum_369 Gaduła (4,190 p.)

niestety nie działa :(

 if (distsqr > detectRange && inRange == true)
        {
            inRange = true;
            Vector2 velocity = (obj.transform.position - transform.position).normalized;
            velocity.y = 0;
            rb_obj.velocity = velocity * 2;

            if (distsqr <= 0.5f) velocity = Vector3.zero;

        }

Postać tak jakby wykonuje szybki ruch do przodu i do tyłu, nie wiem dlaczego :/

komentarz 14 grudnia 2019 przez piotrsz109 Stary wyjadacz (13,730 p.)

Resztę musisz napisać w else dla drugiego warunki.

 if (distsqr <= 0.5f) velocity = Vector3.zero;
else if (distsqr > detectRange && inRange == true)
       {
           inRange = true;
           Vector2 velocity = (obj.transform.position - transform.position).normalized;
           velocity.y = 0;
           rb_obj.velocity = velocity * 2;
       }

 

komentarz 14 grudnia 2019 przez Teslum_369 Gaduła (4,190 p.)
Wywala mi błąd (The name 'velocity' does not exist in the current context), próbowałem napisać rb.velocity ale to niczego nie zmienia (chociaz już się kod uruchamia).

PS. może to pomoże, może nie, ale jak AI z followuje postać to wszystko działa normalnie (postać się nie rusza ciągle w przód i w tył) lecz jak wraca do obiektu to już ma problem xD
komentarz 14 grudnia 2019 przez piotrsz109 Stary wyjadacz (13,730 p.)
musisz użyć rb_obj.velocity.

Przepraszam, nie spojrzałem
komentarz 14 grudnia 2019 przez Teslum_369 Gaduła (4,190 p.)
Niestety, nadal nic :(
komentarz 14 grudnia 2019 przez piotrsz109 Stary wyjadacz (13,730 p.)
if (distsqr <= 0.5f) rb_obj.velocity = Vector3.zero;
else if (distsqr > detectRange && inRange == true)
       {
           inRange = true;
           Vector2 velocity = (obj.transform.position - transform.position).normalized;
           velocity.y = 0;
           rb_obj.velocity = velocity * 2;
       }

Masz właśnie tak, i nie działa?

komentarz 14 grudnia 2019 przez Teslum_369 Gaduła (4,190 p.)
Mam właśnie tak, no niestety, postać robi brekdensa wciąż xd

Może to wynikać z właściwości obiektu? (Inspektor)
komentarz 14 grudnia 2019 przez piotrsz109 Stary wyjadacz (13,730 p.)
Może wystarczy zwiększyć odległość z 0.5f na np.: 1f
komentarz 14 grudnia 2019 przez Teslum_369 Gaduła (4,190 p.)
Zwiększałem co pół jednostki do 3f i nic. Zauwazyłem, iż postać się zatrzymuje przed graczem o te kilka jednostek (no, jeśli jest w zasięgu) no i wtedy (tak jak już pisałem) wszystko jest dobrze. Problem jest tylko gdy AI wraca do obiektu na pierwotnej pozycji. To wtedy robi szybki ruch w przód i w tył wielokrotnie.
komentarz 14 grudnia 2019 przez piotrsz109 Stary wyjadacz (13,730 p.)
Jesteś pewien, że gracz nie był w tamtym momencie w zasięgu?
komentarz 14 grudnia 2019 przez piotrsz109 Stary wyjadacz (13,730 p.)
Plus dołącz proszę cały kod ponownie, ze zmianami
komentarz 14 grudnia 2019 przez Teslum_369 Gaduła (4,190 p.)
Okej, dołącze Ci jeszcze plik, aby zwizualizować całą sytuację. Za kilka chwil udostępnie.
komentarz 14 grudnia 2019 przez Teslum_369 Gaduła (4,190 p.)

Mała dokumentacja: https://imgur.com/a/WFxd7c4

Kod:

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

public class Enemy : MonoBehaviour
{
    public Transform player; // changed this to Transform
    public Transform obj; // changed this to Transform
    public float moveSpeed = 2f;
    public float detectRange = 1; // this gets multiplied by itself to compare to a sqr magnitude check (instead of distance)
    public bool inRange = false;
    Rigidbody2D rb;  // cached the reference, so you can avoid GetComponent calls in Update/FixedUpdate.
    Rigidbody2D rb_obj;  // cached the reference, so you can avoid GetComponent calls in Update/FixedUpdate.


    void Awake()
    {
        rb = GetComponent<Rigidbody2D>();
        rb_obj = GetComponent<Rigidbody2D>();

    }

  

    void Update()
    {
        // a little cheaper than 'distance'.. deleted the code to create a position from the player values.
        float distsqr = (player.position - transform.position).sqrMagnitude;

        if (distsqr <= detectRange)
        {
            inRange = true;
            // get a velocity based on the normalized direction, multiplied by move speed.
            Vector2 velocity = (player.transform.position - transform.position).normalized;
            velocity.y = 0;
            rb.velocity = velocity*2;

        }

        if (distsqr <= 1f) rb_obj.velocity = Vector3.zero;
        else if (distsqr > detectRange && inRange == true)
        {
            inRange = true;
            Vector2 velocity = (obj.transform.position - transform.position).normalized;
            velocity.y = 0;
            rb_obj.velocity = velocity * 2;
        }
    }


}

 

komentarz 14 grudnia 2019 przez piotrsz109 Stary wyjadacz (13,730 p.)
 if (distsqr <= 1f) rb_obj.velocity = Vector3.zero;
else  if (distsqr <= detectRange)
        {
            inRange = true;
            // get a velocity based on the normalized direction, multiplied by move speed.
            Vector2 velocity = (player.transform.position - transform.position).normalized;
            velocity.y = 0;
            rb.velocity = velocity*2;
 
        }
        else if (distsqr > detectRange && inRange == true)
        {
            inRange = true;
            Vector2 velocity = (obj.transform.position - transform.position).normalized;
            velocity.y = 0;
            rb_obj.velocity = velocity * 2;
        }

Moim zdaniem, powinno działać

komentarz 14 grudnia 2019 przez Teslum_369 Gaduła (4,190 p.)
Hah, już działa! :D

Dzięki wielkie za pomoc :))))))

Podobne pytania

0 głosów
1 odpowiedź 495 wizyt
pytanie zadane 10 października 2020 w C# przez PanPrezes Obywatel (1,520 p.)
0 głosów
0 odpowiedzi 436 wizyt
pytanie zadane 1 grudnia 2019 w C# przez Filip Papros Nowicjusz (120 p.)
0 głosów
1 odpowiedź 278 wizyt
pytanie zadane 2 września 2021 w C# przez hydrogeniumoxygenium Nowicjusz (120 p.)

92,452 zapytań

141,262 odpowiedzi

319,085 komentarzy

61,854 pasjonatów

Motyw:

Akcja Pajacyk

Pajacyk od wielu lat dożywia dzieci. Pomóż klikając w zielony brzuszek na stronie. Dziękujemy! ♡

Oto polecana książka warta uwagi.
Pełną listę książek znajdziesz tutaj.

Akademia Sekuraka

Akademia Sekuraka 2024 zapewnia dostęp do minimum 15 szkoleń online z bezpieczeństwa IT oraz dostęp także do materiałów z edycji Sekurak Academy z roku 2023!

Przy zakupie możecie skorzystać z kodu: pasja-akademia - użyjcie go w koszyku, a uzyskacie rabat -30% na bilety w wersji "Standard"! Więcej informacji na temat akademii 2024 znajdziecie tutaj. Dziękujemy ekipie Sekuraka za taką fajną zniżkę dla wszystkich Pasjonatów!

Akademia Sekuraka

Niedawno wystartował dodruk tej świetnej, rozchwytywanej książki (około 940 stron). Mamy dla Was kod: pasja (wpiszcie go w koszyku), dzięki któremu otrzymujemy 10% zniżki - dziękujemy zaprzyjaźnionej ekipie Sekuraka za taki bonus dla Pasjonatów! Książka to pierwszy tom z serii o ITsec, który łagodnie wprowadzi w świat bezpieczeństwa IT każdą osobę - warto, polecamy!

...