Поетапна ізометрична карта: Обчисліть координати карти для точки на екрані


12

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

Ось зображення, яке показує мою систему координат:

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

Як перетворити точку на екрані в цю систему координат?



Я не бачу, як це корисно в будь-якому випадку. Я думаю, ти не зовсім зрозумів, що я маю на увазі.
Кріс

Це робить трансформацію, навпаки, тому вам потрібно змінити її.
Маркус фон Броаді

Відповіді:


23

По-перше, ось код. Далі буде пояснення:

/*
 * tw, th contain the tile width and height.
 *
 * hitTest contains a single channel taken from a tile-shaped hit-test
 * image. Data was extracted with getImageData()
 */

worldToTilePos = function(x, y) {

    var eventilex = Math.floor(x%tw);
    var eventiley = Math.floor(y%th);

    if (hitTest[eventilex + eventiley * tw] !== 255) {
        /* On even tile */

        return {
            x: Math.floor((x + tw) / tw) - 1,
            y: 2 * (Math.floor((y + th) / th) - 1)
        };
    } else {
        /* On odd tile */

        return {
            x: Math.floor((x + tw / 2) / tw) - 1,
            y: 2 * (Math.floor((y + th / 2) / th)) - 1
        };
    }
};

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

Пояснення

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

Хитрість полягає в тому, щоб переглядати карту не як одну шарувату сітку, а як дві сітки, накладені одна на одну. Є сітка непарних рядків і сітка парних рядків, але давайте назвемо їх червоно-зеленими, щоб ми могли створити гарну діаграму ...

Дві сітки, червона та зелена

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

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

Два регіони-кандидати

Тепер вибрати, який із двох регіонів є правильним. Завжди буде рівно одна відповідь.

Звідси ми могли б зробити кілька простіших арифметичних і проробити відстань у квадраті від нашої вибіркової точки до кожної центральної точки двох областей. Хто буде найближчим, буде нашою відповіддю.

Однак існує альтернативний спосіб. Для кожного тестового регіону ми робимо вибірку растрової карти, яка відповідає точній формі нашої плитки. Ми відбираємо його в точці, переведеній на локальні координати для цієї єдиної плитки. Для нашого прикладу це виглядало б приблизно так:

Точкові зразки

Ліворуч перевіряємо зелену область і отримуємо хіт (Чорний піксель). Праворуч ми перевіряємо червону область і отримуємо промах (Білий піксель). Другий тест, звичайно, є зайвим, оскільки завжди буде точно те чи інше, ніколи і те і інше.

Тоді ми приходимо до висновку, що ми потрапили в непарну плитку на рівні 1,1. Ця координата повинна бути простою для відображення вихідних координат плитки, використовуючи різні перетворення для непарних і парних рядків.

Цей метод також дозволяє мати прості властивості на піксель у растрових (іх) тестових пікселях. Напр. Білий - це плитка, чорний - хіт, синій - вода, червоний - твердий.


2
Це приголомшливо³!
HumanCatfood

Фантастична і добре пояснена відповідь - тепер просто потрібно втілити її в код. Оскільки оригінальний плакат не надав жодної інформації про код за ним або про мову, окрім тегів у Javascript, я кажу відповідь A *
Tom 'Blue' Piddock

1

Я думаю, що у вас є проблема з вашим координатним простором. Координати, які ви дали плитці, насправді не є ізометричною проекцією. Ви повинні думати xAxis як діагоналі вниз вправо, а yAxis як діагоналі вниз вліво (або якогось варіанту цього)

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

Матриця перетворень, яку ви шукаєте, - одна з цих осей x та y. Це фактично те саме, що робити наступний розрахунок.

screenOffsetXY = screenPointXY - tileOriginXY;
tileX = dot(screenOffsetXY, xAxis) / tileWidth;
tileY = dot(screenOffsetXY, yAxis) / tileWidth;

Редагувати: Я просто натрапив на подібне запитання (але з системою координат, про яку я говорив), і хтось тут дав набагато більш ретельну відповідь:

Як перетворити координати миші в ізометричні індекси?


0

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

function mouseTwoGridPosition(e){

var mousex = e.pageX; //mouse position x
var mouseY = e.pageY;  //mouse position y
var canvas_width = 1000; //pixels
var offset_left = 100; //offset of canvas to window in pixels
var offset_top = 150; //offset of canvas to window in pixels

var isotile = 64; //if iso tile is 64 by 64

//get mouse position relative to canvas rather than window
var x = mousex - canvas_width/2 - offset_left;
var y = mousey - offset_top;


//convert to isometric grid
var tx = Math.round( (x + y * 2) / isotile) - 1;
var ty = Math.round((y * 2 - x) / isotile) - 1;

 //because your grid starts at 0/0 not 1/1 we subtract 1 
 // this is optional based on what grid number you want to start at



   return [tx,ty];
}

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


Це не занадто просто? Я хочу, щоб він ідеально відповідав формі ізо плитки. Ви просто перевіряєте прямокутну область, якщо я правильно це розумію.
Кріс

що ви маєте на увазі під формою ізотилу ... наприклад, скажіть, що ваша миша знаходиться в діамантових межах 0: 1, повернення буде 0: 1, поки ваша миша не покине цю межу. Якщо ваші плитки відрізняються за розміром - тоді мій метод не буде працювати. Надана функція - це те, що я використовую, і це добре працює для мене.
Дейв

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

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

Ви впевнені, що використовуєте ту саму систему координат, що і я? Це все ще повністю вимкнено.
Кріс

0

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

    hWidth = this.tileset.tileSize.width / 2;
    hHeight = this.tileset.tileSize.height / 2;

    pX = point.x - halfWidth;
    pY = point.y - halfHeight;

    x = Math.floor((pX + (pY - hHeight) * 2) / this.tileset.tileSize.width);
    y = Math.floor((pY - (pX - hWidth) * 0.5) / this.tileset.tileSize.height);

    tx = Math.floor((x - y) / 2) + 1 + this.camera.x;
    ty = y + x + 2 + this.camera.y;
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.