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

Przyciąganie obiektów przez teren w Unity

VPS Starter Arubacloud
0 głosów
488 wizyt
pytanie zadane 28 sierpnia 2017 w C# przez Strzechoniusz Nowicjusz (120 p.)
Witam.

Podobny temat był już poruszany, ale wydaje mi się, że potrzebuję czegoś innego. A mianowicie: stworzyłem grę 3D typu RPG. Mam tam teren, obiekty wrogów i obiekty gracza. Wrogowie pojawiają się w losowych miejscach na planszy i poruszają się w stronę gracza. Wrogowie nie latają, nie skaczą, w zamyśle w ogóle nie powinni odrywać się od ziemi. I tutaj się pojawia problem. W skryptach wrogów zaimplementowałem instrukcję, która metodą raycastingu wykrywa gracza lub innego wroga i jeśli takowego wykryje - wróg dalej się nie porusza. Jednak to nie rozwiązuje do końca problemu: jeśli pojawia się dużo wrogów i wszystkie idą do gracza -  pierwszy ładnie się zatrzymuje przed graczem, drugi czasem też, ale częściej jednak korzystając z pędu przesuwa stojącego przed nim wroga minimalnie w stronę gracza i zatrzymuje się i tak dalej. Jeśli w pierwszego wroga uderzy trzech czy czterech następnych ten prawie wchodzi w gracza (w zamyśle zatrzymuje się w odległości 3 jednostki od gracza). I to właściwie nie jest jakieś strasznie złe. Prawdziwym problemem jest to, że jeśli wróg jest dosyć niski, czasem tak jest "wpychany" w gracza, że gracz wchodzi na niego. To psuje efekt. Podobnie dzieje się z samymi wrogami. Jeśli jest cała gromada krasnali, tworzą się z nich małe wieżyczki. Próbowałem już wielu rzeczy żeby to wyeliminować, nic nie działało dostatecznie dobrze. No i wpadł mi do głowy kolejny pomysł, ale nie wiem jak go zrealizować. Chciałbym żeby obiekt gracza i obiekty wrogów były jakby przyczepione do terenu. Chciałbym stworzyc tak silne przyciąganie obiektów przez teraz, żeby mogły poruszać się po terenie (teren jest górzysty, wiele wzniesień, czyli obiekty przesuwają się we wszystkich trzech osiach), ale żadna siła nie jest w stanie ich od tego terenu oderwać w górę. Czy można zrobić coś takiego? Lub może macie inne pomysły które rozwiążą ten problem. Dołączam elementy skryptu, wybaczcie, ale piszę strasznie "brudne" skrypty. Dziękuję za pomoc.

 

using UnityEngine;
using System.Collections;

public class EnemyAIv5 : MonoBehaviour {
   
    public float walkSpeed = 5.0f;
  
    public float runSpeed = 10.0f;
   
    public float attackDistance = 3.0f;
   
    private Transform mojObiekt;
    private Transform gracz;
    private bool patrzNaGracza = false;
    private Vector3 pozycjaGraczaXYZ;
    public float zasiegWzroku = 30f;
    public float zasiegPrzygotowaniaAtaku = 10f;
  
    private bool gladkiObrot = true;
    private float predkoscObrotu = 6.0f;
    

    RaycastHit hit;

    public bool cosFront=false;

   
    public enum stan{s_idzie, s_biegnie, s_walczy, s_nic, s_spawn};

    

   

 

  
    
    void Start () {
        mojObiekt = transform;
        GetComponent<Rigidbody> ().freezeRotation = true;

        if(GameObject.FindWithTag ("Player"))gracz = GameObject.FindWithTag ("Player").transform;

    }

  
    void Update () {

        if(gracz)pozycjaGraczaXYZ = new Vector3 (gracz.position.x, mojObiekt.position.y, gracz.position.z);
        

float dist = Vector3.Distance (mojObiekt.position, gracz.position);

       

        if (dist >= 100) {
            Destroy (gameObject);

        }

        if (HP > 0) {
            if (aktualnyStan != stan.s_spawn) {

                cosFront = false;
                if (Physics.Raycast (transform.position, transform.forward, out hit, (float)(gameObject.GetComponent<BoxCollider>().size.z))) {
                    if (hit.collider.tag == "Enemy") {
                        cosFront = true;
                    }
                }

                if (dist <= zasiegWzroku && dist > zasiegPrzygotowaniaAtaku) {
                    if (!atakuje) {
                        float predkoscRuchu = walkSpeed;
                        
                     
                        if (!cosFront) {
                            mojObiekt.position = Vector3.MoveTowards (mojObiekt.position, pozycjaGraczaXYZ, predkoscRuchu * Time.deltaTime);
                            gameObject.GetComponent<Rigidbody> ().constraints = RigidbodyConstraints.None;
                            GetComponent<Rigidbody> ().freezeRotation = true;

                        } else {
                            gameObject.GetComponent<Rigidbody> ().constraints = RigidbodyConstraints.FreezePosition;
                        }
                       
                     

                    }
                   

                } else if (dist <= zasiegPrzygotowaniaAtaku && dist > attackDistance) {
                    if (!atakuje) {
                        float predkoscRuchu = runSpeed;
                       
                        if (!cosFront) {
                            mojObiekt.position = Vector3.MoveTowards (mojObiekt.position, pozycjaGraczaXYZ, predkoscRuchu * Time.deltaTime);
                            gameObject.GetComponent<Rigidbody> ().constraints = RigidbodyConstraints.None;
                            GetComponent<Rigidbody> ().freezeRotation = true;

                        } else {
                            gameObject.GetComponent<Rigidbody> ().constraints = RigidbodyConstraints.FreezeAll;
                        }
                      
                }
            }
        }            
    }
}
 

 

Z kodu usunąłem niepotrzebne elementy, zakładamy, że nie brakuje żadnych nawiasów czy czegoś takiego.
komentarz 29 sierpnia 2017 przez Bartosz Dokurno Użytkownik (980 p.)

Kod dajemy do bloczka code! 

Takiego o, łatwiej to czytać

 

1 odpowiedź

0 głosów
odpowiedź 29 sierpnia 2017 przez piotrsz109 Stary wyjadacz (13,730 p.)

Dodaj dla gracza i wroga collidery i użyj CharacterController. Poza tym powinieneś użyć do tego NavMeshAgent. Kod:

using UnityEngine;
using UnityEngine.Navigation;

public class EnemyAI : MonoBehaviour {
public float zasiegWzroku;
public Transform player;
private NavMeshAgent agent;

void Start(){
player = GameObject.FindGameObjectWithTag("Player").transform;
agent = player.GetComponent<NavMeshAgent>();
}

void Update(){
if(Vector3.Distance(transform.position, player.position) < zasiegWzroku){
agent.SetDestination(player.position);
}
}
}

W NavMeshAgent możesz ustawić odległość w jakiej ma się wróg zatrzymać a także szybkość chodenia. Życie oraz atak sam dopisz.

Podobne pytania

0 głosów
3 odpowiedzi 1,045 wizyt
pytanie zadane 22 listopada 2016 w OpenGL, Unity przez Tom_Ja Dyskutant (7,970 p.)
0 głosów
1 odpowiedź 195 wizyt
0 głosów
0 odpowiedzi 342 wizyt
pytanie zadane 29 lipca 2016 w C# przez natrov Gaduła (3,970 p.)

92,455 zapytań

141,263 odpowiedzi

319,099 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!

...