Re: Кастомна фізика персонажа Unity3d
шось я взагалі заплутався, як тільки додав цю інерцію, так відразу все поламалось
Ви не увійшли. Будь ласка, увійдіть або зареєструйтесь.
Ласкаво просимо вас на україномовний форум з програмування, веб-дизайну, SEO та всього пов'язаного з інтернетом та комп'ютерами.
Будемо вдячні, якщо ви поділитись посиланням на Replace.org.ua на інших ресурсах.
Для того щоб створювати теми та надсилати повідомлення вам потрібно Зареєструватись.
Український форум програмістів → Розробка ігор → Кастомна фізика персонажа Unity3d
Сторінки Попередня 1 2 3 4 5 Наступна
Для відправлення відповіді ви повинні увійти або зареєструватися
шось я взагалі заплутався, як тільки додав цю інерцію, так відразу все поламалось
майбуть, таки доведеться заглянути до підручника з фізики
вирішив з нуля переписувати.
І от шось мені не подобається те, як я знаходжу напрямок руху.
using UnityEngine;
public class PlayerController : MonoBehaviour
{
public Rigidbody2D ball; //шарик
public CircleCollider2D circleCollider;
public float speed;
public LayerMask layerMask;
public bool grounded; // true, якщо на землі
private float realRadius;
private float rayLength; // довжина променю для пошуку землі під ногами
// Use this for initialization
void Start()
{
realRadius = circleCollider.radius * ball.transform.localScale.x;
rayLength = realRadius + (realRadius / 10); // довжина променю на 1/10 довша за радіус (промінь пускається з центру кулі)
}
// Update is called once per frame
void Update()
{
if (Input.GetKeyDown(KeyCode.RightArrow))
{
Move(Vector2.right);
}
if (Input.GetKeyDown(KeyCode.LeftArrow))
{
Move(Vector2.left);
}
}
void Move(Vector2 direction)
{
RaycastHit2D hit = Physics2D.Raycast(ball.position, -ball.transform.up, rayLength, layerMask); // пускаємо промінь вниз, відносно повороту кулі
Debug.DrawLine(ball.position, ball.position + ((-(Vector2)ball.transform.up) * rayLength), Color.blue, 10);
if (hit)
{
grounded = true; //якщо промінь вдарився об щось, то ми тіпа на землі
SetAngle(hit); //повертаємо персонажа відповідно до нахилу землі
float forwardRayLength = speed * Time.deltaTime; //знаходимо довжину променю, щоб знайти наступне положення
hit = Physics2D.Raycast(ball.position, ball.transform.right, forwardRayLength, layerMask); //пускаємо промінь з центру кулі в напрямку "право" відносно повороту кулі, на отриману раніше довжину
if (hit)//якщо промінь вдарився в щось
{
SetAngle(hit); //повертаємо відповідно до нахило того, об що ми вдарились
ball.position = GetNewPosition(hit); //встановлюємо нову позицію
}
else // якщо промінь не вдарився
{
Vector2 rayStartPoint = ball.position + forwardRayLength * (Vector2)ball.transform.right; //обраховуємо позицію з котрої будемо пускати промінь (ця позиція рівна тій точці, в котру ми пускали промінь раніше)
hit = Physics2D.Raycast(rayStartPoint, -ball.transform.up, rayLength, layerMask); //пускаємо промінь з обрахованої раніше точки вниз відносно повороту кулі
if (hit)//якщо промінь вдарився
{
SetAngle(hit); //встановлюємо поворот кулі відповідно до поверхні, об яку вдарився промінь
ball.position = GetNewPosition(hit); //встановлюємо нову позицію
}
else//якщо промінь не вдарився
{
grounded = false; //ми тіпа не на землі
ball.position = rayStartPoint;//встановлюємо позицію кулі в точку, з котрої пускали промінь раніше
}
}
}
else//якщо промінь не вдарився
{
grounded = false;//ми тіпа не на землі
}
}
Vector2 GetNewPosition(RaycastHit2D hit)
{
return hit.point + ((Vector2)ball.transform.up * realRadius); //обраховуємо позицію відповідно до точки вдаряння променя
}
void SetAngle(RaycastHit2D hit)
{
float angle = Vector2.Angle(hit.normal, Vector2.right); //обраховуємо кут між нормаллю поверхні в точці, в котрій промінь зіштовхнувся з нею та вектором (1;0)
angle -= 90f; //віднімаємо від отриманого раніше кута 90 градусів
ball.MoveRotation(angle); //повертаємо кулю на обрахований раніше кут
}
}
От ця фігня з кутами мене трохи бісить, хотілося б мінімізувати залежність напрямку руху від кутів.
гаразд, я віднайшов знову першу перешкоду, котра завадила мені при моїй першій спробі написати ту хвізику.
Проблема в кутах. Метод Vector2.Angle повертає менше значення кута між двома векторами, тобто коли кут стає більшим за 180, воно повертає не 190, наприклад, а 170, тому що починає рахувати кут з іншого боку.
надибав підходящу формулу, тепер знаходжу кут ось так
float AngleAtan2(Vector2 from, Vector2 to)
{
return Mathf.Rad2Deg * (Mathf.Atan2(to.y, to.x) - Mathf.Atan2(from.x, from.y));
}
повертає весь діапазон значень, при цьому непотрібно віднімати 90 градусів, воно відразу повертає потрібне значення.
Як бути з гравітейшн?
Якщо ви дивились кід, то при русі я там встановлюю або зкидаю булеву зміну grounded, котра каже нам, чи на землі ми, чи ні. Ну а потім я написав ось такий кід
if (!grounded)
{
RaycastHit2D hit = Physics2D.Raycast(ball.position, Vector2.down, rayLength + (gravityAcceleration * Time.deltaTime), layerMask);
if (hit)
{
ball.position = GetNewPosition(hit);
grounded = true;
}
else
{
ball.position += (Vector2.down * gravityAcceleration * Time.deltaTime);
}
}
ця перевірка викликається кожен кадр. Але ж самі розумієте, поки я не натисну на кнопку руху, доти перевірка на заземлення не відбудеться. А якщо під персонажем якась платформа зникне? Він же має падати до низу.
То це мені що, кожен кадр додатково пускати промінь для перевірки? Це взагалі нормально? Стільки променів за один кадр..
От і ще одна проблема.
Зараз гравітація перевіряється запуском променя рівно вниз з центру персонажа на відстань радіус персонажа+(радіус персонажа/10)+прискорення гравітації
І коли воно заїзджає на повернутий на 45 градусів квадратик, то в верхівці промень, котрий визначає наступну позицію, не дістає до землі, адже він пускається під кутом. І тоді grounded==false.
Починає працювати гравітація, котра запускає промень вниз, і не знаходить там землі, після чого воно спускається вниз.
Синій колір - промень, що встановлює нову позицію при русі
Червоний колір - промень гравітації
У мене таке враження, що FakiNyan винаходить до нютоновську фізику.
У мене таке враження, що FakiNyan винаходить до нютоновську фізику.
Тсс, не злякайте, ще кілька сторінок, і він зрозуміє, що ніякої кастомної фізики йому не треба, причому буде розуміти чому.
я тут подумав не розділяти рух і гравітацію, адже напрямок руху вже включає гравітацію.
Тобто треба до напрямку руху додавати напрямок гравітації.
щось я почав був писати і якось нічого не приходе в голову.
Ну от з'являється цей шарик над похилою поверхнею, і гравітація його тягне до низу. В якийсь момент частинка кульки торкається поверхні. Але ж якщо я буду пускати промінь з центру рівно до низу, то відбудеться знову та сама фігня, коли промінь не буде діставати до землі і буде постійно спускати кульку до низу.
Майбуть, треба працювати не з променями, а з фігуркою кулі? Типу перевіряти, чи торкнулась сама куля якоїсь поверхні.
я тут подумав, що в реалі воно ж так і маж бути. Кругляш не повинен просто висіти на похилій поверхні, воно має котитися до низу. А всіляки квадрати не повинні з'їзджати до низу, тому що у них більша площа дотику до поверхні, і сила тертя сильніша.
Тоді я хочу зробити, ніби мій кругляш обліпляний двохсторонньою клейкою стрічкою, і воно не має котитись до низу саме по собі.
пишу знову ,вже третю версію.
Тепер буду все робити потроху, і не намагатись відразу зробити круто.
тепер воно бігає по зовнішньому колу, чи не диво???
Коротше, щось я зробив таки. Тепер воно може зістрибувати з парапетів. Але не завжди так.
Ось, гляньте на картинку.
1. Додаємо до позиції персонажа вектор, нахил котрого дорівнює нахилу поверхні, помножений на швидкість.
2. З точки знайденної раніше пускаємо промінь вниз, відносно повороту персонажа (цей промінь зображений дівчачим кольором)
3. Якщо промінь не потрапляє в землю, або ще щось, то пускаємо промінь з центру персонажа рівно вниз (цей промінь зображений хлопчачим кольором). А якщо потрапляє, то встановлюємо персонажа в позицію нормаль поверхні в точці удару променя - радіус кулі.
4. Якщо хлопчачий промінь потрапляє в землю, то встановлюємо персонажа в позицію нормаль поверхні в точці удару променя - радіус кулі, а якщо ні, то рухаємось в останньому напрямку постійно змінюючи вектор руху на вектор гравітації, таким чином воно зіскакує з парапетів.
Ну і тут така проблема, що ось в тому місці, котре зображене на картинці, спочатку виконується 1, 2, 3 (з потраплянням променя в землю), після чого знову 1, 2, 3 (без потрапляння). Ну і воно скаче на одному місці, туди-сюди, туди-сюди.
Як то пофіксити?
я так розумію, в мене є лише два варіанта:
1. Кулька летить далі, типу відривається від землі, постійню змінюючи напрямок польоту в сторону землі.
2. Кулька рухається далі по поверхні.
Перший варіант наразі працює, лише коли ні дівчачий, ні хлопчачий промені не потрапляють в землю, тому реалізувати то буде просто.
Другий варіант не існує. Але єдине, що приходить на думку - пускати промень рівно вниз, з кінчика дівчачого променю.
Що думоєте?