Пятница, 26 Апреля 2024, 05:57

Приветствую Вас Гость

[ Новые сообщения · Игроделы · Правила · Поиск ]
  • Страница 1 из 2
  • 1
  • 2
  • »
Форум игроделов » Движки для разработки игр и сложные системы разработки » Unity » Каким образом перемещать персонажа по неровной поверхности?
Каким образом перемещать персонажа по неровной поверхности?
ChazДата: Суббота, 18 Января 2014, 17:03 | Сообщение # 1
частый гость
Сейчас нет на сайте
Привет. Такая беда. Если перемещать персонажа при помощи CharacterController.Move, то значение CharacterController.isGrounded меняется каждый раз, когда я иду по ровной поверхности. Оно будет false, если я подпрыгну, и будет true, если я стою на земле, но когда я иду, то оно меняется из false в true и обратно много раз подряд. Если использовать Translate для передвижения персонажа, то значение isGrounded стабильно, то есть, если на земле, то true, если в воздухе, то false, если двигаюсь по земле, то true, но если я пытаюсь забратся на горбик или ввойти в стену, то я прохожу сквозь меш, а CharacterController.Move позволяет подниматся на горку и останавливатся, если переоснаж двигается в стену. Подскажите же, как сделать, чтобы персонаж и на горку поднимался и при ходьбе по земле значение isGrounded было true?
Вот скрипт, может я неверно двигаю персонажа методом Move?
Код

using System;
using System.Timers;
using UnityEngine;
using System.Collections;

public class Move : MonoBehaviour
{

     public float speed;
     public float fallSpeed = 1;

     private Transform camera, player;

     private Transform myTrans;
     private Vector3 direction;
     private CharacterController controller;
     private Vector3 rotVect;
     private float Yjump;

         // Use this for initialization
         void Start ()
         {
             direction = Vector3.zero;
             speed = speed == 0 ? 10:speed;
             camera = GameObject.FindGameObjectWithTag("Camera").transform;
             player = GameObject.FindGameObjectWithTag("Player").transform;
             myTrans = transform;
             controller = this.gameObject.GetComponent<CharacterController>();
         }
          
         // Update is called once per frame
         void Update ()
         {
             direction = Vector3.zero;

             if (Input.GetKey(KeyCode.W))
             {
                 direction += camera.forward;
                 direction.y = 0;
             }

         if (Input.GetKey(KeyCode.S))
         {
             direction += -camera.forward;
             direction.y = 0;
         }

         if (Input.GetKey(KeyCode.D))
         {
             direction += camera.right;
             direction.y = 0;  
         }

         if (Input.GetKey(KeyCode.A))
         {
             direction += -camera.right;
             direction.y = 0;
         }

             if (Input.GetKey(KeyCode.W) || Input.GetKey(KeyCode.S) || Input.GetKey(KeyCode.A) || Input.GetKey(KeyCode.D))
             {
                 myTrans.forward = direction.normalized;
                 //controller.Move(direction.normalized*speed*Time.deltaTime);
             myTrans.Translate(direction.normalized * speed * Time.deltaTime);
             }
         Debug.Log(controller.isGrounded);
         }

     void FixedUpdate()
     {
         if (Input.GetKeyDown(KeyCode.Space))
         {
             if (controller.isGrounded)
                 Yjump = 1f;
         }

         if (Yjump != 0 || Yjump>0)
         {    
             controller.Move(myTrans.up*Yjump);
             Yjump -= Time.deltaTime;
             if (Yjump < 0)
                 Yjump = 0;
         }

         if (!controller.isGrounded)
         {
             fallSpeed += 0.5f;
             controller.Move(Vector3.down * Time.deltaTime * fallSpeed);
             if (controller.isGrounded)
             {
                 Yjump = 0;
                 fallSpeed = 1;
             }
         }      
     }
}
  
ЛевшаДата: Суббота, 18 Января 2014, 17:15 | Сообщение # 2
почти ветеран
Сейчас нет на сайте
Столкнувшись когда то с аналогичной проблемой я просто повесил на персонажа еще один мелкий сфераКолайдер - триггер в ногах.
Работает надежно. smile


X.cor.R (Prologue)
ChazДата: Суббота, 18 Января 2014, 17:36 | Сообщение # 3
частый гость
Сейчас нет на сайте
Левша, а я думал пускать луч из ног, и проверять дистанцию до точки столкновения, это норм или лучше сфера колайдер?
ЛевшаДата: Суббота, 18 Января 2014, 18:26 | Сообщение # 4
почти ветеран
Сейчас нет на сайте
Цитата Chaz ()
пускать луч из ног, и проверять дистанцию до точки столкновения

Тоже можно, но рейкаст в Update наверно понакладнее будет...


X.cor.R (Prologue)
ChazДата: Суббота, 18 Января 2014, 18:36 | Сообщение # 5
частый гость
Сейчас нет на сайте
слушайте, глюк какой-то. Нацепил на персонажа сферический коллайдер, поставил галочку напротив is trigger. Далее назначил земле тег Ground и написал такой код
Код
using System;
using System.Timers;
using UnityEngine;
using System.Collections;

public class Move : MonoBehaviour
{

      public float speed;
      public float fallSpeed = 1;
      public bool isGrounded = false;

      private Transform camera, player, mesh;
      private SphereCollider sphereCollider;
      private Transform myTrans;
      private Vector3 direction;
      private CharacterController controller;
      private Vector3 rotVect;
      private float Yjump;
        

   // Use this for initialization
   void Start ()
   {
       direction = Vector3.zero;
       speed = speed == 0 ? 10:speed;
       camera = GameObject.FindGameObjectWithTag("Camera").transform;
       player = GameObject.FindGameObjectWithTag("Player").transform;
          mesh = GameObject.FindGameObjectWithTag("Mesh").transform;
       sphereCollider = gameObject.GetComponent<SphereCollider>();
       myTrans = transform;
       controller = this.gameObject.GetComponent<CharacterController>();
   }
     
   // Update is called once per frame
   void Update ()
   {
       direction = Vector3.zero;

       if (Input.GetKey(KeyCode.W))
       {
           direction += camera.forward;
           direction.y = 0;
       }

          if (Input.GetKey(KeyCode.S))
          {
              direction += -camera.forward;
              direction.y = 0;
          }

          if (Input.GetKey(KeyCode.D))
          {
              direction += camera.right;
              direction.y = 0;   
          }

          if (Input.GetKey(KeyCode.A))
          {
              direction += -camera.right;
              direction.y = 0;
          }

       if (Input.GetKey(KeyCode.W) || Input.GetKey(KeyCode.S) || Input.GetKey(KeyCode.A) || Input.GetKey(KeyCode.D))
       {
           mesh.forward = direction.normalized;
           controller.Move(direction.normalized*speed*Time.deltaTime);
             // myTrans.Translate(direction.normalized * speed * Time.deltaTime);
       }
          Debug.Log(controller.isGrounded);
   }

      void FixedUpdate()
      {
          if (Input.GetKeyDown(KeyCode.Space))
          {
              if (isGrounded)//controller.isGrounded)
                  Yjump = 1f;
          }

          if (Yjump != 0 || Yjump>0)
          {     
              controller.Move(myTrans.up*Yjump);
              Yjump -= Time.deltaTime;
              if (Yjump < 0)
                  Yjump = 0;
          }

          if (!isGrounded)
          {
              fallSpeed += 0.5f;
              controller.Move(Vector3.down * Time.deltaTime * fallSpeed);
          }
      }

      void OnTriggerEnter(Collider other)
      {
          if (other.tag == "Ground")
          {
              isGrounded = true;
                  Yjump = 0;
                  fallSpeed = 0;
              Debug.Log("grounded from enter");
          }
      }

      void OnTriggerExit(Collider other)
      {
          if (other.tag == "Ground")
          {
              isGrounded = false;
              Debug.Log("ungrounded!");
          }
      }

      void OnTriggerStay(Collider other)
      {
          if (other.tag == "Ground")
          {
              isGrounded = true;
              Debug.Log("grounded from stay");
          }
      }
}

Пока хожу по ровной земле и по пологим горбикам - все нормально работает. Но когда я поднимаюсь на горбик и пытаюсь сойти с обрыва, то я остаюсь в воздухе, хожу по воздуху и триггер
Код
void OnTriggerStay(Collider other)
      {
          if (other.tag == "Ground")
          {
              isGrounded = true;
              Debug.Log("grounded from stay");
          }
      }
постоянно срабатыват, хотя я не стою на земле, че это за глюк такой???


Сообщение отредактировал Chaz - Суббота, 18 Января 2014, 18:40
ЛевшаДата: Суббота, 18 Января 2014, 19:44 | Сообщение # 6
почти ветеран
Сейчас нет на сайте
Используй другую bool переменную для контроля, оставь этот isGrounded в покое. smile
Вот такая примерно конструкция:



X.cor.R (Prologue)

Сообщение отредактировал Левша - Суббота, 18 Января 2014, 19:47
ChazДата: Суббота, 18 Января 2014, 19:53 | Сообщение # 7
частый гость
Сейчас нет на сайте
Левша, так я так и делаю, isGrounded это моя переменная, а не от CharacterController'а
ЛевшаДата: Суббота, 18 Января 2014, 19:55 | Сообщение # 8
почти ветеран
Сейчас нет на сайте
Цитата
Debug.Log(controller.isGrounded);


X.cor.R (Prologue)
ChazДата: Суббота, 18 Января 2014, 20:01 | Сообщение # 9
частый гость
Сейчас нет на сайте
Цитата Левша ()
Цитата
Debug.Log(controller.isGrounded);

да вы не это не обращайте внимания, это оно просто осталось в дебаг логе
вы сюда смотрите
Код
void FixedUpdate()  
       {  
           if (Input.GetKeyDown(KeyCode.Space))  
           {  
               if (isGrounded)//controller.isGrounded)  
                   Yjump = 1f;  
           }  

           if (Yjump != 0 || Yjump>0)  
           {      
               controller.Move(myTrans.up*Yjump);  
               Yjump -= Time.deltaTime;  
               if (Yjump < 0)  
                   Yjump = 0;  
           }  

           if (!isGrounded)  
           {  
               fallSpeed += 0.5f;  
               controller.Move(Vector3.down * Time.deltaTime * fallSpeed);  
           }  
       }  

       void OnTriggerEnter(Collider other)  
       {  
           if (other.tag == "Ground")  
           {  
               isGrounded = true;  
                   Yjump = 0;  
                   fallSpeed = 0;  
               Debug.Log("grounded from enter");  
           }  
       }  

       void OnTriggerExit(Collider other)  
       {  
           if (other.tag == "Ground")  
           {  
               isGrounded = false;  
               Debug.Log("ungrounded!");  
           }  
       }  

       void OnTriggerStay(Collider other)  
       {  
           if (other.tag == "Ground")  
           {  
               isGrounded = true;  
               Debug.Log("grounded from stay");  
           }  
       }  
}
ЛевшаДата: Суббота, 18 Января 2014, 20:24 | Сообщение # 10
почти ветеран
Сейчас нет на сайте
И все таки смени имя переменной.
OnTriggerEnter - не нужен.

Код

var ground : boolean = true;

function OnTriggerStay (hit : Collider) {
      if (hit.tag == "Floor")  ground = true;
}   
function OnTriggerExit (hit : Collider) {
      if (hit.tag == "Floor")  ground = false;
}


X.cor.R (Prologue)

Сообщение отредактировал Левша - Суббота, 18 Января 2014, 20:26
ChazДата: Суббота, 18 Января 2014, 20:34 | Сообщение # 11
частый гость
Сейчас нет на сайте
Левша, та же фигня
ЛевшаДата: Суббота, 18 Января 2014, 21:25 | Сообщение # 12
почти ветеран
Сейчас нет на сайте
Цитата Chaz ()
то я остаюсь в воздухе, хожу по воздуху

А гравитация ? Она все время должна работать, не зависимо на земле ты или в воздухе.


X.cor.R (Prologue)
ChazДата: Суббота, 18 Января 2014, 21:30 | Сообщение # 13
частый гость
Сейчас нет на сайте
Левша, хм, а у меня работает только если в воздухе, окей, сделаю, чтобы всегда работала хД надеюсь, это никак не отразится на перемещении. И это, а как мне тогда ускорение гравитации сделать? у меня просто такое условие - если перс в воздухе, то двигаем его вниз, и увеличиваем скорость падения, а когда на земле, то значение скорости обнуляется и он не падает вниз.
ЛевшаДата: Суббота, 18 Января 2014, 21:51 | Сообщение # 14
почти ветеран
Сейчас нет на сайте
Цитата Chaz ()
у меня просто такое условие - если перс в воздухе, то двигаем его вниз, и увеличиваем скорость падения, а когда на земле, то значение скорости обнуляется и он не падает вниз.

Ну это же в реале не так, я понимаю что это симуляция, но лучше придерживатся реальной модели поведения.
Меньше будет побочных, неучтенных проявлений.
А по факту - у тебя видимо не срабатывает выход из триггера...
Попробуй навесить на землю риджБодю с галочкой на IsKinematic.


X.cor.R (Prologue)

Сообщение отредактировал Левша - Суббота, 18 Января 2014, 22:06
ChazДата: Воскресенье, 19 Января 2014, 04:24 | Сообщение # 15
частый гость
Сейчас нет на сайте
Левша, риджидБадя и так уже висела, и с IsKinematic триггеры как-раз не детектятся, но я убрал IsKinematic и просто зафризил риджидБадю, и тогда триггеры детектятся, но проблема все же осталась, я позже видюшку запишу и покажу вам, увидите насколько это все абсурдно, когда с одной части обрыва персонаж падает, а с другой нет =(
ЛевшаДата: Воскресенье, 19 Января 2014, 04:57 | Сообщение # 16
почти ветеран
Сейчас нет на сайте
Цитата Chaz ()
с IsKinematic триггеры как-раз не детектятся

С чего это ? о_О
У меня детектятся...


X.cor.R (Prologue)
ChazДата: Воскресенье, 19 Января 2014, 15:53 | Сообщение # 17
частый гость
Сейчас нет на сайте
Левша, ой! у меня тоже детектиться, но как-то плохо, триггер на вход и на нахождение чего-то в триггере не работает сразу, нужно поколотить персонажа, и тогда тока все срабатывает, и то криво работает. Вот я видюшку записал, значение True и False в консоли, относятся к CharacterController.isGrounded, а остальные штуки относятся к искусственной переменной isGrounded. Как вы и говорили, триггер на выход не срабатывает, а триггер на нахождение внутри работает даже если сферка очень далеко от земли.
ВИДЮШКА
allodsДата: Воскресенье, 19 Января 2014, 17:02 | Сообщение # 18
почти ветеран
Сейчас нет на сайте
по мне так рейкст надо, один рейкаст с перса не просадит вам фпс
ChazДата: Понедельник, 20 Января 2014, 14:43 | Сообщение # 19
частый гость
Сейчас нет на сайте
allods, ну я еще могу использовать и треггеры и переменную от CharacterController'a. Триггер работает, когда персонаж на земле, а CharacterController.isGrounded хорошо работает, когда перс в воздухе
upd: фигню я сморозил, тогда буду дожидатся ответа Левши или запилю рейкастом.
upd2: сделал постоянную гравитацию, ну и ясный пень, теперь работает все чотко, но все рарвно интересно, почему же триггер на выходе не срабатывает

Добавлено (20.01.2014, 14:43)
---------------------------------------------
Значит сделал постоянную гравитацию + рейкаст. Но вот же проблема, лучик тоненький, а персонаж толстенький, и вот на этом скриншоте

если основыватся на данных полученных из рейкаста - персонаж в воздухе, хотя на самом деле он стоит на очень крутой горке. У меня движение пока что так сделано, что персонажем можно двигать и в воздухе, поэтому я могу спустится с этой горки, но в реале же мы не можем управлять направлением полета, если прыгнем вперед, например, и тогда, значит, если персонаж не на земле, то он не может двигатся ,и если он повиснет на таком крутом склоне, как на скриншоте, то он там застрянет на всю жизнь.

Сообщение отредактировал Chaz - Воскресенье, 19 Января 2014, 23:52
set16Дата: Понедельник, 20 Января 2014, 14:59 | Сообщение # 20
постоянный участник
Сейчас нет на сайте
Вот скрипт не дает лазать по горам и не позволяет рулить в прыжке smile
Код

using UnityEngine;
using System.Collections;
   
[RequireComponent (typeof (CharacterController))]
public class ChrContP: MonoBehaviour {
   
     public float walkSpeed = 6.0f;
  public float rotspeed = 20f;
     public float runSpeed = 11.0f;
     public bool limitDiagonalSpeed = true;
     public bool toggleRun = false;
     public float jumpSpeed = 8.0f;
     public float gravity = 20.0f;
     public float fallingDamageThreshold = 10.0f;
     public bool slideWhenOverSlopeLimit = false;
     public bool slideOnTaggedObjects = false;
     public float slideSpeed = 12.0f;
     public bool airControl = false;
     public float antiBumpFactor = .75f;
     public int antiBunnyHopFactor = 1;
     private Vector3 moveDirection = Vector3.zero;
     private bool grounded = false;
     private CharacterController controller;
     private Transform myTransform;
     private float speed;
     private RaycastHit hit;
     private float fallStartLevel;
     private bool falling;
     private float slideLimit;
     private float rayDistance;
     private Vector3 contactPoint;
     private bool playerControl = false;
     private int jumpTimer;
   
     void Start() {
         controller = GetComponent<CharacterController>();
         myTransform = transform;
         speed = walkSpeed;
         rayDistance = controller.height * .5f + controller.radius;
         slideLimit = controller.slopeLimit - .1f;
         jumpTimer = antiBunnyHopFactor;
     }
   
     void FixedUpdate() {
         float inputX = Input.GetAxis("Horizontal");
         float inputY = Input.GetAxis("Vertical");
         float inputModifyFactor = (inputX != 0.0f && inputY != 0.0f && limitDiagonalSpeed)? .7071f : 1.0f;
   
         if (grounded) {
             bool sliding = false;
             if (Physics.Raycast(myTransform.position, -Vector3.up, out hit, rayDistance)) {
                 if (Vector3.Angle(hit.normal, Vector3.up) > slideLimit)
                     sliding = true;
             }
             else {
                 Physics.Raycast(contactPoint + Vector3.up, -Vector3.up, out hit);
                 if (Vector3.Angle(hit.normal, Vector3.up) > slideLimit)
                     sliding = true;
             }
   
             if (falling) {
                 falling = false;
                 if (myTransform.position.y < fallStartLevel - fallingDamageThreshold)
                     FallingDamageAlert (fallStartLevel - myTransform.position.y);
             }
   
             if (!toggleRun)
                 speed = Input.GetButton("Run")? runSpeed : walkSpeed;
   
             if ( (sliding && slideWhenOverSlopeLimit) || (slideOnTaggedObjects && hit.collider.tag == "Slide") ) {
                 Vector3 hitNormal = hit.normal;
                 moveDirection = new Vector3(hitNormal.x, -hitNormal.y, hitNormal.z);
                 Vector3.OrthoNormalize (ref hitNormal, ref moveDirection);
                 moveDirection *= slideSpeed;
                 playerControl = false;
             }
             else {
                 moveDirection = new Vector3(0, -antiBumpFactor, inputY * inputModifyFactor);//inputX * inputModifyFactor
                 moveDirection = myTransform.TransformDirection(moveDirection) * speed;
                 playerControl = true;
             }
   
             if (!Input.GetButton("Jump"))
                 jumpTimer++;
             else if (jumpTimer >= antiBunnyHopFactor) {
                 moveDirection.y = jumpSpeed;
                 jumpTimer = 0;
             }
         }
         else {
             if (!falling) {
                 falling = true;
                 fallStartLevel = myTransform.position.y;
             }
   
             if (airControl && playerControl) {
                 moveDirection.z = inputY * speed * inputModifyFactor;
                 moveDirection = myTransform.TransformDirection(moveDirection);
             }
         }
   
         moveDirection.y -= gravity * Time.deltaTime;
    transform.Rotate(0,inputX * rotspeed * Time.deltaTime,0);
         grounded = (controller.Move(moveDirection * Time.deltaTime) & CollisionFlags.Below) != 0;
     }
   
     void Update () {
         if (toggleRun && grounded && Input.GetButtonDown("Run"))
             speed = (speed == walkSpeed? runSpeed : walkSpeed);
     }
   
     void OnControllerColliderHit (ControllerColliderHit hit) {
         contactPoint = hit.point;
     }
   
     void FallingDamageAlert (float fallDistance) {
         print ("Ouch! Fell " + fallDistance + " units!");    
     }
}


=>The darkness of distant lands [3D]<=
Форум игроделов » Движки для разработки игр и сложные системы разработки » Unity » Каким образом перемещать персонажа по неровной поверхности?
  • Страница 1 из 2
  • 1
  • 2
  • »
Поиск:

Все права сохранены. GcUp.ru © 2008-2024 Рейтинг