Як обмежити рух натискання на область?


11

Прошу вибачення за дещо загальну назву. Я дійсно не маю особливих уявлень щодо того, як досягти того, що я намагаюся зробити, що ускладнює навіть дослідження можливого рішення.

Я намагаюся реалізувати різновиди маркера шляху (можливо, є найбільш підходяще ім'я для цього, але це найкраще, що я міг придумати).

Перед гравцем буде розміщений маркер доріжки, який визначатиме, як рухатиметься гравець, як тільки він закінчить планувати свою чергу. Гравець може клацнути та перетягнути маркер до обраної вами позиції, але маркер можна переміщувати лише в межах визначеної робочої зони (сірий біт).

Діаграма маркера шляху

Тому я зараз застряг з двома проблемами:

Перш за все, як саме я повинен визначити цю працездатну область? Я можу собі уявити, може, два вектори, у яких гравець є відправною точкою для формування працездатного кута, і, можливо, ці дві дуги можуть виникнути з кіл, у яких є центр, де знаходиться гравець, але я точно не знаю, як це все поставити разом.

По-друге, після того, як я визначив область, де маркер може бути розміщений, як я можу примусити, що маркер повинен залишатися лише в цій області? Наприклад, якщо гравець клацає і перетягує маркер навколо, він може вільно переміщатися в межах робочої зони, але не повинен залишати межі області. Так, наприклад, якщо гравець почне перетягувати маркер вгору, він рухатиметься вгору, поки не потрапить у кінець робочої області (перша діаграма внизу), але якщо після цього гравець почне тягнути набік, маркер повинен слідувати за перетягуванням, поки нерухомий в межах області (друга діаграма нижче).

Перша діаграма: рух вгору Друга схема: Після перетягування

Я сподіваюся, що це було не надто заплутано. Дякую, хлопці.

Редагувати: Якщо це має значення, я використовую C ++ з SDM Marmalade.


Я думаю, що термін, який ви шукаєте, - це "крапка", і чи можете ви математично визначити сіру область? Вирішення вашої проблеми, мабуть, буде набагато простішим, якщо воно є.
Джон Макдональд

Арентові точки, пов'язані з наведенням маршрутів і подібні? Крім того, математичне визначення сірої зони є однією з моїх проблем: PI думаю, що я міг би розібратися щось на зразок прямокутника чи навіть кола, але такої форми, з двома дугами для сторін та двома іншими сторонами під кутом ... Це трохи над головою.
Вексиль

Вам також потрібно буде вказати, якою мовою та / або набором інструментів ви користуєтесь, оскільки рішення в першу чергу залежать від платформи.
Raceimaztion

Дійсно? Я вважав, що алгоритмічне рішення чи навіть псевдокод допоможуть. Я все-таки відредагую питання, про всяк випадок.
Вексиль

Визначте фігуру в полярних координатах (максимальний кут від кута символів та min / max відстань від символу). Потім лише оновіть точку до місця, де знаходиться миша, якщо миша знаходиться в цих межах. Якщо вона перевищує будь-яку з цих крайнощів, прив'яжіть її до максимально можливого значення. Почніть оновлення, натиснувши всередині області, і зупиніться, коли миша буде відпущена.
ClassicThunder

Відповіді:


8

Ви можете визначити працездатну область, як ту, що знаходиться у вашому запитанні, з трьома значеннями:

float innerRadius;
float outerRadius;
float maxAngle;

Ці значення будуть базуватися на центральній точці, яка може бути або не бути позицією гравця. Форма оброблюваної ділянки залежить від того, де ви розмістите цю точку.

введіть тут опис зображення

У прикладі вище центральної позиції лежить певна відстань (скажімо, 50 одиниць) позаду гравця. Це можна легко обчислити як:

float offset = -50;
Vector2 centerPosition = playerPosition + offset * playerForward;

Щоб обмежити позицію маркера на цій оброблюваній області, спочатку перемістіть маркер так, як зазвичай. Потім підтвердіть відстань між центральною точкою та маркером:

Vector2 direction = markerPosition - centerPosition;
float distance = direction.Length();
direction.Normalize();
markerPosition = centerPosition + direction * clamp(distance, innerRadius, outerRadius);

Нарешті, підтвердіть кут маркера до заданого діапазону. Для цього я буду використовувати псевдокод:

- Find angle between vector C->M and vector playerForward
- If abs(angle) <= maxAngle Then do nothing
- Else If angle > 0 Then rotate M around C by maxAngle-angle
- Else If angle < 0 Then rotate M around C by -maxAngle-angle

Погляньте навколо, як обертати точку навколо іншого. Це можна зробити або за допомогою тригонометрії, або матриці перетворення.

Ви також можете взяти до уваги розмір маркера та зробити радіус та кут трохи меншими, щоб компенсувати.

Редагувати: По-другому, це може здатися більш природним, якщо спочатку перевірити кут, а потім відстань, тому спробуйте обидві альтернативи!


Чудове рішення! Я натрапив на щось, що включало два кола та трикутник, але ваше рішенняг витончено спрощує це. Щодо перевірки кута, я подумав про щось уздовж лінії мати нормалізований вектор, який стояв на maxAngle (та інший на -maxAngle) від гравця вперед, який можна було б помножити на довжину C-> M, якщо це було меж , кутовий. Я припускаю, що ваше рішення обертання M навколо C було б менш затратним, чи не так?
Вексіл

@Vexille Добре, що обертання передбачає операцію cosта sinоперацію, тому я не впевнений. Але для обчислення цих двох векторів вам також потрібно їх обертати, хоча це потрібно робити лише тоді, коли вектор прямого зміниться. Все одно не має великого значення, виберіть той, який ви віддаєте перевагу.
Девід Гувейя

10

Я думав, як можна вирішити проблему, якщо форма була неправильною, і її не можна було визначити математично. Попередження: це брудне рішення, не для слабкого серця.

1. Займіть вашу область:

введіть тут опис зображення

2. І перетворіть його в однотонну растрову карту:

введіть тут опис зображення і назвіть його scale_0

3. Клоніруйте растрову карту і зменшіть її до 50%:

введіть тут опис зображення і назвіть його масштабом_1

4. І так далі, поки не буде растрова карта менше 4 пікселів у ширину / висоту:

введіть тут опис зображення введіть тут опис зображення введіть тут опис зображення введіть тут опис зображення введіть тут опис зображення масштаб: 2, 3, 4, 5, 6

5. Тепер ми маємо нашу область як однотонні растрові зображення різної роздільної здатності: введіть тут опис зображення

6. Візьміть останнє зображення (тут "scale_6") і повторіть усі пікселі.

  • x = Math.pow ( 2, scale_level );переведіть координати кожного пікселя в координатні екрани: де scale_level - це число, яке ми додали після "scale_". Ми також могли б назвати це рівнем квадрового дерева, хоча ми не дуже працюємо з квадровим деревом. Зробіть те ж саме з у.
  • перевірте, чи піксель у перекладеному x & y є чорним. Якщо ні, то це не частина форми, і вам слід просто continueперейти до наступного кроку петлі
  • перевірте, чи піксель ближче до курсору миші, ніж попередньо перевірений піксель - якщо так, збережіть координати пікселя - використовуйте координати перед перекладом, тобто координати всередині растрової карти.
  • в кінці циклу помножте ці координати на 2: x *= 2; y*=2;перевести їх на координати в наступному зображенні (попередня шкала)

7. Зробіть попереднє зображення (тут "scale_5"), але не переглядайте всі пікселі; почати з x = збережений_x і закінчити x = збережений_x + 2, те саме, що і y. Тобто, відтепер ви переймете лише 4 пікселі для кожного рівня! Решта - як у с. 6.

8. Зробіть перше зображення (найбільше = одне з найбільшою роздільною здатністю), знову переведіть на 4 пікселі, і ви нарешті отримаєте піксель, найближчий до курсору миші:

введіть тут опис зображення

введіть тут опис зображення

введіть тут опис зображення

9. Однак я трактую "М" як точку тут. Якщо ви хочете, щоб це було цілком відповідне коло, вам потрібно спочатку скоротити (зменшити) форму circle.radiusпікселями.

Я подумав, що додам, що цей алгоритм буде працювати лише в тому випадку, якщо ви будете використовувати не однотонні, а зображення в градаціях сірого, і піксель розглядаєте як "повний", якщо він не білий, а як "порожній", якщо він абсолютно білий ... АБО якщо ваш розмір алгоритм кожного разу змінює кожну групу з 4 пікселів на 1 чорний піксель, коли хоча б один із цих 4 пікселів не був білим.


2
+1 для відповіді на фігури, які складно (якщо не неможливо) виразити математично.
Cypher

Вау, дуже цікаво. +1 теж: D
Вексиль

Я реалізував це в реальному проекті, і, можу сказати, виникли деякі проблеми. В основному вам потрібно скласти список комірок сітки, де ви берете найближчу клітинку сітки з назвою closest, і перевірте відстань до найбільшої точки в closest- назвемо відстань furthest_dist. Тепер вам потрібно видалити зі списку всі клітинки, які мають найближчу точку далі, furthest_distі вийти на рівень глибше. Тож замість чогось подібного: i.imgur.com/4UuFo.png Це приблизно так: i.imgur.com/dyTT3.png
Маркус фон Броаді
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.