Staggered Isometric Map: Tính toán tọa độ bản đồ cho điểm trên màn hình


11

Tôi biết đã có rất nhiều tài nguyên về vấn đề này, nhưng tôi chưa tìm thấy tài nguyên nào phù hợp với hệ tọa độ của mình và tôi gặp khó khăn lớn khi điều chỉnh bất kỳ giải pháp nào theo nhu cầu của mình. Điều tôi học được là cách tốt nhất để làm điều này là sử dụng ma trận biến đổi. Thực hiện điều đó không có vấn đề gì, nhưng tôi không biết mình phải biến đổi không gian tọa độ theo cách nào.

Đây là một hình ảnh cho thấy hệ tọa độ của tôi:

enter image description here

Làm cách nào để chuyển đổi một điểm trên màn hình sang hệ tọa độ này?



Tôi không thể thấy điều này hữu ích theo bất kỳ cách nào. Tôi nghĩ bạn không hiểu ý tôi là gì.
Chris

Nó thực hiện chuyển đổi, chỉ là cách khác, vì vậy bạn cần đảo ngược nó.
Markus von Broady

Câu trả lời:


23

Đầu tiên, đây là mã. Một lời giải thích sẽ theo sau:

/*
 * 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
        };
    }
};

Lưu ý rằng mã này sẽ không hoạt động ngoài hộp cho bản đồ được hiển thị trong câu hỏi của bạn. Điều này là do bạn có các ô lẻ lẻ lệch sang trái, trong khi đó các ô lẻ thường được bù ở bên phải (Như trường hợp trong trình chỉnh sửa bản đồ lát gạch ). Bạn sẽ có thể dễ dàng khắc phục điều này bằng cách điều chỉnh giá trị x được trả về trong trường hợp gạch lẻ.

Giải trình

Đây có vẻ là một phương pháp mạnh mẽ hơn một chút để hoàn thành nhiệm vụ này, nhưng ít nhất nó có lợi thế là pixel hoàn hảo và linh hoạt hơn một chút.

Bí quyết là trong việc xem bản đồ không phải là một lưới so le, mà là hai lưới chồng lên nhau. Có lưới hàng lẻ và lưới hàng chẵn, nhưng thay vào đó, hãy gọi chúng là màu đỏ và màu xanh lá cây để chúng ta có thể tạo một sơ đồ đẹp ...

Hai lưới, đỏ và xanh

Lưu ý bên phải hình ảnh đó Tôi đã đánh dấu một điểm bằng một chấm màu tím. Đây là điểm ví dụ chúng tôi sẽ cố gắng tìm trong không gian gạch ban đầu của chúng tôi.

Điều cần chú ý về bất kỳ điểm nào trên thế giới là nó sẽ luôn nằm ở hai khu vực chính xác - một màu đỏ và một màu xanh lá cây (Trừ khi nó ở một cạnh, nhưng dù sao bạn cũng sẽ bị kẹp trong ranh giới cạnh lởm chởm). Hãy tìm những vùng đó ...

Hai khu vực ứng cử viên

Bây giờ để chọn cái nào trong hai vùng là đúng. Sẽ luôn có một câu trả lời chính xác.

Từ đây, chúng tôi có thể thực hiện một số số học đơn giản hơn và tính ra khoảng cách bình phương từ điểm mẫu của chúng tôi đến từng điểm trung tâm của hai vùng. Bất cứ điều gì gần nhất sẽ là câu trả lời của chúng tôi.

Có một cách khác tuy nhiên. Đối với mỗi khu vực thử nghiệm, chúng tôi lấy mẫu một bitmap phù hợp với hình dạng chính xác của các ô của chúng tôi. Chúng tôi lấy mẫu tại một điểm được dịch thành tọa độ cục bộ cho ô đơn đó. Ví dụ của chúng tôi, nó sẽ trông giống như thế này:

Mẫu điểm

Một bên trái, chúng tôi kiểm tra vùng màu xanh lá cây và nhận được một điểm nhấn (pixel đen). Ở bên phải, chúng tôi kiểm tra vùng màu đỏ và bỏ lỡ (pixel trắng). Thử nghiệm thứ hai tất nhiên là dư thừa vì nó sẽ luôn luôn chính xác cái này hay cái kia, không bao giờ cả hai.

Sau đó chúng tôi đi đến kết luận rằng chúng tôi có một điểm nhấn trong ô lẻ ở mức 1,1. Tọa độ này phải đơn giản để ánh xạ tới tọa độ ô ban đầu bằng cách sử dụng một phép biến đổi khác nhau cho các hàng lẻ và chẵn.

Phương pháp này cũng cho phép bạn có các thuộc tính mỗi pixel đơn giản trên (các) bitmap thử nghiệm pixel. Ví dụ: màu trắng là gạch ngói, màu đen là một hit, màu xanh là nước, màu đỏ là rắn.


2
Điều này thật tuyệt vời!
HumanCatfood

Câu trả lời tuyệt vời và được giải thích tốt - bây giờ chỉ cần thực hiện nó thành mã. Vì người đăng ban đầu không cung cấp bất kỳ thông tin nào về mã đằng sau nó hoặc ngôn ngữ khác ngoài thẻ trong Javascript, tôi nói câu trả lời A *
Tom 'Blue' Piddock 15/03/13

1

Tôi nghĩ vấn đề bạn gặp phải là với không gian phối hợp của bạn. Các tọa độ bạn đã cung cấp cho các ô không thực sự là một phép chiếu đẳng cự - Bạn cần nghĩ về xAxis là đi chéo xuống bên phải và yAxis như đi chéo xuống bên trái (hoặc một số biến thể của điều đó)

ngay bây giờ nếu bạn di chuyển dọc theo trục tọa độ được minh họa, bạn sẽ di chuyển theo hướng chéo trong "không gian gạch" để hình vuông kết thúc như kim cương (và mọi thứ sẽ phức tạp hơn)

Ma trận biến đổi mà bạn đang tìm kiếm được xây dựng từ các trục x và y đó. Nó có hiệu quả tương tự như làm phép tính sau.

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

Chỉnh sửa: Tôi vừa gặp một câu hỏi tương tự (nhưng với hệ thống tọa độ mà tôi đang nói đến) và ai đó đã đưa ra một câu trả lời kỹ lưỡng hơn nhiều ở đây:

Làm thế nào để chuyển đổi tọa độ chuột thành chỉ số đẳng cự?


0

Về cơ bản bạn muốn có được vị trí của chuột trong cửa sổ bằng cách sử dụng trình nghe sự kiện, bạn cần loại bỏ phần bù của vị trí canvas trong cửa sổ khỏi vị trí chuột, do đó vị trí chuột sẽ liên quan đến canvas.

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];
}

Tôi sẽ giả sử bạn biết cách thực hiện nghe sự kiện trên canvas 'cho mousemove, nếu không bạn có thể muốn tìm hiểu thêm JS trước khi bạn xem xét thiết kế trò chơi isometric: D


Đây không phải là một chút quá đơn giản? Tôi muốn nó phù hợp với hình thức của gạch iso một cách hoàn hảo. Bạn chỉ đang kiểm tra một khu vực hình chữ nhật nếu tôi hiểu điều này một cách chính xác.
Chris

Ý của bạn là "hình thức" của đồng vị ... ví dụ như con chuột của bạn nằm trong giới hạn hình kim cương là 0: 1, tỷ lệ hoàn trả sẽ là 0: 1 cho đến khi chuột của bạn rời khỏi ranh giới đó. Nếu gạch của bạn thay đổi kích thước - thì phương pháp của tôi sẽ không hoạt động. Các chức năng được cung cấp là những gì tôi sử dụng và nó hoạt động tốt cho tôi.
Dave

Chỉ cần tự hỏi, bởi vì tất cả các giải pháp khác là cách phức tạp hơn. Gạch có cùng kích thước của khóa học vì vậy tôi sẽ kiểm tra điều này.
Chris

Cũng tinker với nó đảm bảo bạn có được độ lệch chính xác của canvas bên trái và trên cùng - và chiều rộng của canvas, khi bạn làm toán sẽ hoạt động tốt (cũng là chiều rộng kích thước đồng vị).
Dave

Bạn có chắc là bạn đang sử dụng cùng một hệ tọa độ như tôi không? Nó vẫn hoàn toàn tắt.
Chris

0

Tôi đã giải quyết điều này bằng cách thay đổi không gian tọa độ. Bây giờ nó bắt đầu mà không có phần bù ở hàng đầu tiên và tôi đã tìm thấy một ví dụ hoạt động mà tôi có thể điều chỉnh một chút.

    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;
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.