Почему персонаж застревает?

Общие вопросы о Unity3D

Почему персонаж застревает?

Сообщение EIvanov 06 апр 2023, 14:54

Простой пример. Игрок - Player, на котором есть бокс коллайдер 2д. У игрока есть вложенный объект Ground check (пустой - стандартный способ проверки земли).
Земля - Ground. Также есть бокс коллайдер 2д.

Когда игрок доходит до края земли - от застревает. Аналогично и с другого края.
На игрока и землю поместил материал с friction = 0. Не помогло.
По земле ходит - прыгает прекрасно, только доходит до края - застревает. Так происходит на любой "земле" - делал копии объектов.
Убирал стены - дело не в них, застревает именно в земле.

https://youtu.be/pPFL7-xSlGs



Изображение
Изображение
Изображение

Код передвижения игрока

Синтаксис:
Используется csharp
void FixedUpdate()
{
isGrounded = Physics2D.OverlapCircle(groundCheck.position, checkRadius, whatIsGround);

// Передвижение игрока.
float movement = Input.GetAxis("Horizontal");


// Передвижение и прыжок возможны только когда игрок на земле (отключаем управление в полете).
if (isGrounded==true)
{      
// Передвижение.
if (isJumping==false)
{
transform.position += new Vector3(movement, 0, 0) * speed * Time.deltaTime;
if (movement < 0) sr.flipX = true;
if (movement > 0) sr.flipX = false;
}
// Прыжок с накоплением высоты прыжка, в зависимости от длительности удержания пробела.
if (isJumping==true)
{      
currentJumpHeight+=jumpHeightIncrement;
if (currentJumpHeight>=maxJumpHeight) jumpNow=true;
}
}
}



// Сразу останавливаем игрока после приземления на землю (объект с тегом Ground).
// Без этого кода игрок будет некоторое время двигаться по инерции.
void OnCollisionEnter2D(Collision2D collision)
{
if (collision.gameObject.tag == "Ground")
{
rb.velocity = Vector2.zero;
}
}
EIvanov
UNIт
 
Сообщения: 103
Зарегистрирован: 05 июл 2021, 17:23

Re: Почему персонаж застревает?

Сообщение Alkos26Rus 06 апр 2023, 15:26

Physics2D.OverlapBox вместо Physics2D.OverlapCircle
Аватара пользователя
Alkos26Rus
Адепт
 
Сообщения: 1642
Зарегистрирован: 26 ноя 2020, 17:52
Откуда: Москва

Re: Почему персонаж застревает?

Сообщение EIvanov 06 апр 2023, 21:10

//
Последний раз редактировалось EIvanov 06 апр 2023, 21:47, всего редактировалось 1 раз.
EIvanov
UNIт
 
Сообщения: 103
Зарегистрирован: 05 июл 2021, 17:23

Re: Почему персонаж застревает?

Сообщение 1max1 06 апр 2023, 21:24

Синтаксис:
Используется csharp
transform.position +=

Вот так двигать рб не надо, это бэд практис. Ты во время прыжка тупо врезаешься внутрь стены и он начинает думать что он на земле.
Аватара пользователя
1max1
Адепт
 
Сообщения: 5505
Зарегистрирован: 28 июн 2017, 10:51

Re: Почему персонаж застревает?

Сообщение EIvanov 06 апр 2023, 22:07

Перепишу ответ выше т.к. есть дополнения.

Alkos26Rus спасибо за ответ. Сделал как вы сказали
Синтаксис:
Используется csharp
Vector2 boxSize = new Vector2(1f, 0.1f); // размеры box для проверки
isGrounded = Physics2D.OverlapBox(groundCheck.position, boxSize, 0f, whatIsGround);


Теперь игрок почти не застревает на краях стены.
То есть раньше всегда застревал ровно на этом месте
Изображение

Теперь 1 раз на 50 попыток застревает тут
Изображение
Буквально за долю секунды до того, как должен упасть, касаясь самым кончиком земли..и застревает. Очень редко, но бывает (

1max1
https://youtu.be/abd3LeUIo9c

Изменил код
Синтаксис:
Используется csharp
//transform.position += new Vector3(movement, 0, 0) * speed * Time.deltaTime;
transform.Translate(new Vector2(movement * speed * Time.deltaTime, 0));

Глюк не ушел. Я могу просто прилипнуть к стенке-земле, зажав стрелку вправо и висеть сколь угодно долго.
EIvanov
UNIт
 
Сообщения: 103
Зарегистрирован: 05 июл 2021, 17:23

Re: Почему персонаж застревает?

Сообщение 1max1 06 апр 2023, 23:07

//transform.position += new Vector3(movement, 0, 0) * speed * Time.deltaTime;
transform.Translate(new Vector2(movement * speed * Time.deltaTime, 0));

Это одно и тоже, лол :D Используй rb.velocity.
Аватара пользователя
1max1
Адепт
 
Сообщения: 5505
Зарегистрирован: 28 июн 2017, 10:51

Re: Почему персонаж застревает?

Сообщение Tolking 06 апр 2023, 23:18

Ну так твой OverlapBox земли касается? Значит земля... Жмешь в право? Ну ок, трансформ "плотнее" прижимается к земле справа... Мог бы и вообще насквозь пройти, при таком подходе...

форма колайдера должна быть сферой или капсулой, с одной точкой касания снизу, и по каcанию этой точки проверяют землю. И двигать нужно не трансформ, а ригридбоди...
Ковчег построил любитель, профессионалы построили Титаник.
Аватара пользователя
Tolking
Адепт
 
Сообщения: 2716
Зарегистрирован: 08 июн 2009, 18:22
Откуда: Тула

Re: Почему персонаж застревает?

Сообщение 1max1 07 апр 2023, 02:51

Я бы для проверки земли сделал бы триггерный коллайдер снизу на милиписечку уже по ширине чем игрок. Типа если игрок 2 юнита, то коллайдер для чека земли будет 1.999, ну и двигать не трансформом ясень пень, это же с пеленок рассказывают))
Аватара пользователя
1max1
Адепт
 
Сообщения: 5505
Зарегистрирован: 28 июн 2017, 10:51

Re: Почему персонаж застревает?

Сообщение EIvanov 07 апр 2023, 05:02

1max1, Tolking
Про коллайдер кажется понял. Действительно у меня в коде отключается управление, если игрок в воздухе. Это объясняет все глюки - коллайдер просто переставал касаться земли.

Это одно и тоже, лол :D Используй rb.velocity.

ну и двигать не трансформом ясень пень

У меня корректно работает только transform. Наверно, в моем коде есть ряд условий, которые, конфликтуют с velocity.
Вот 3 варианта передвижения.

Синтаксис:
Используется csharp
// Корректно работает.
transform.Translate(new Vector2(horizontalInput * speed * Time.deltaTime, 0));
if (Mathf.Sign(horizontalInput) == -1) sr.flipX = true;
if (Mathf.Sign(horizontalInput) == 1) sr.flipX = false;

// Требует массу и остановку импульса.
Vector2 movement = new Vector2(horizontalInput, 0f) * speed;
rb.AddForce(movement, ForceMode2D.Impulse);


// Не работает прыжок. Странно.
Vector3 movement = new Vector2(horizontalInput, 0f) * speed;
rb.velocity = movement;

// Прыжок - этот код выполняется, но при использовании velocity  игрок не прыгает. А при transform или Impulse - прыгает.

void Jump(JumpType jumpType)
{

// Выполняем прыжок только если стоим на земле
if (isGrounded)
{
Debug.Log("Прыжок!");     // В консоли вижу Прыжок! Всё работает.
// Вычисляем начальную скорость для достижения заданной высоты прыжка
float initialVelocity = Mathf.Sqrt(2 * currentJumpHeight * Physics2D.gravity.magnitude);

// Прыжок по вертикали.
if (jumpType == JumpType.Vertical)
{
initialVelocity = Mathf.Sqrt(2 * currentJumpHeight * Physics2D.gravity.magnitude); // Вычисляем начальную скорость для вертикального прыжка
rb.velocity = Vector2.up * initialVelocity; // Задаем вертикальную скорость объекту
}
}
}



 
EIvanov
UNIт
 
Сообщения: 103
Зарегистрирован: 05 июл 2021, 17:23

Re: Почему персонаж застревает?

Сообщение EIvanov 07 апр 2023, 05:50

Tolking
форма колайдера должна быть сферой или капсулой

Хорошая идея. Сделал, но возникает проблема с отображением радиуса круга.
При его изменении в редакторе, новый радиус отображается только если закрыть и заново открыть проект. (
EIvanov
UNIт
 
Сообщения: 103
Зарегистрирован: 05 июл 2021, 17:23

Re: Почему персонаж застревает?

Сообщение 1max1 07 апр 2023, 11:44

Синтаксис:
Используется csharp
Vector3 movement = new Vector2(horizontalInput, rb.velocity.y) * speed;
rb.velocity = movement;

Не забывай сохранять Y скорость и будет ок.
Аватара пользователя
1max1
Адепт
 
Сообщения: 5505
Зарегистрирован: 28 июн 2017, 10:51

Re: Почему персонаж застревает?

Сообщение EIvanov 08 апр 2023, 06:24

1max1
Не забывай сохранять Y скорость и будет ок.

Игрок улетает вверх со скоростью ракеты. 0_0

https://youtu.be/EECXONzoofE


Код
Синтаксис:
Используется csharp
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class PlayerController_6 : MonoBehaviour
{

public float playerSpeed = 6f; // Скорость.
public float jumpForce = 7f; // Сила прыжка.


public Transform groundCheck;
public LayerMask whatIsGround;
public float checkRadius = 0.1f; // Радиус проверки земли.
private bool isGrounded; // Поле - флаг приземления.


Rigidbody2D rb;


void Start()
{
rb = GetComponent<Rigidbody2D>();
}



void FixedUpdate()
{
float horizontalInput = Input.GetAxis("Horizontal");
float verticalInput = Input.GetAxis("Vertical");
isGrounded = Physics2D.OverlapCircle(groundCheck.position, checkRadius, whatIsGround);

Vector3 movement = new Vector2(horizontalInput, rb.velocity.y) * playerSpeed;
rb.velocity = movement;

Debug.Log("rb.velocity.y="+rb.velocity.y);
}


void Update()
{
if (Input.GetKeyDown(KeyCode.Space) && isGrounded == true) {Jump(); Debug.Log("Прыжок");}
}

// Прыжок.
public void Jump()
{
rb.velocity = Vector2.up * jumpForce;
}



void OnCollisionEnter2D(Collision2D collision)
{
// Игровая механика - сразу останавливаем игрока после приземления на землю (объект с тегом Ground).
if (collision.gameObject.tag == "Ground")
{
rb.velocity = Vector2.zero;
}
}



}
 
EIvanov
UNIт
 
Сообщения: 103
Зарегистрирован: 05 июл 2021, 17:23

Re: Почему персонаж застревает?

Сообщение Alkos26Rus 08 апр 2023, 11:45

Так наверно
Синтаксис:
Используется csharp
Vector3 movement = new Vector2(horizontalInput * playerSpeed, rb.velocity.y);
Аватара пользователя
Alkos26Rus
Адепт
 
Сообщения: 1642
Зарегистрирован: 26 ноя 2020, 17:52
Откуда: Москва

Re: Почему персонаж застревает?

Сообщение EIvanov 08 апр 2023, 23:32

Alkos26Rus
Так наверно Vector3 movement = new Vector2(horizontalInput * playerSpeed, rb.velocity.y);

Спасибо работает.
Когда был только horizontalInput множитель playerSpeed был за скобками. Добавил rb.velocity.y, а множитель перенести забыл (
EIvanov
UNIт
 
Сообщения: 103
Зарегистрирован: 05 июл 2021, 17:23


Вернуться в Общие вопросы

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 15