18

我不使用瓷砖,而是使用 sf::Vertex 绘制的立方体。每个立方体有 6 个面,每个面有 4 个点。 在此处输入图像描述

所以我只需要cubes[numCube].sides()[numSide]....选择一边。

我创建立方体 layer.cpp :

for(int J = 0; J < mapSize; J++)
    {
        for(int I = 0; I < mapSize; I++)
        {
            x = (J - I) * (cubeSize/2);
            y = (J + I) * (cubeSize/4);

            c = new cube(cubeSize, x, y, z, I, J);
            cs.push_back(*c);
        }
    }

在 cube.cpp 中我创建边,然后,在 side.cpp 中,我计算每个点的坐标,如下所示:

switch(typeSide)
{
    case 0://DOWN_SIDE
        light = 1;

        tmp_x = x + (size/2);
        tmp_y = y + (size/2);
        p0 = new point(tmp_x, tmp_y, tmp_z);

        tmp_x = x + size;
        tmp_y = y + (3 * (size/4));
        p1 = new point(tmp_x, tmp_y, tmp_z);

        tmp_x = x + (size/2);
        tmp_y = y + size;
        p2 = new point(tmp_x, tmp_y, tmp_z);

        tmp_x = x;
        tmp_y = y + (3 * (size/4));
        p3 = new point(tmp_x, tmp_y, tmp_z);
        break;

    case 1://BACK_LEFT_SIDE

//ETC. ....

点.cpp:

/*
 * point.cpp
 *
 *  Created on: 21 nov. 2015
 *      Author: user
 */

#include "point.h"

point::point(float tx, float ty, float tz)
{
    coords* dummyVar = new coords(tx, ty, tz);
    coordinates = dummyVar;
}

std::vector<float> point::position()//Use : myPoint.getPosition[0] //get the x
{
    std::vector<float> dummyVar;

    dummyVar.push_back(coordinates->getX());
    dummyVar.push_back(coordinates->getY() - coordinates->getZ());

    return dummyVar;
}

void point::move(float tx, float ty, float tz)
{
    coordinates->setX(tx);
    coordinates->setY(ty);
    coordinates->setZ(tz);
}

我的问题来自我用来检测点击的功能:

if (event.type == sf::Event::MouseMoved)
{
            currentSelectedCube = maps[currentMapID].getCubeIDAt(event.mouseMove.x, event.mouseMove.y, offsetLeft, offsetTop, enableOffset);
}

功能(不要理会评论):

我尝试在没有“for循环”的情况下在我的立方体向量中获取一个立方体的条目。为什么 ?单击时使用更少的CPU。

int map::getCubeIDAt(float x, float y, int offsetLeft, int offsetTop, bool enableOffset)//WIP ! //USED FOR CLICK DETECTION ON CUBES
    {
    //----------------------------------------------------------------//
        int unsigned entry = -1;

        int I = 0;
        int J = 0;
    //----------------------------------------------------------------//

        if(currentLayerId() > -1)//If there is any layers
        {
            //IF CHECK IN MAP BOUDING BOX + ROTATION TO GOT DIAMOND SHAPE AREA(LAYER + OFFSETS)----------------------------------
            //{

                if(!enableOffset)//With offsets disabled
                {
                    I = (y * 2 - x) / cubeSize;
                    J = (y * 2 + x) / cubeSize;
                }
                else //With offsets enabled
                {
                    I = (((y-offsetTop)+(currentLayerId()*(cubeSize/2))) * 2 - (x-offsetLeft)) / cubeSize;
                    J = (((y-offsetTop)+(currentLayerId()*(cubeSize/2)))  * 2 + (x-offsetLeft)) / cubeSize;
                }

                entry = I + J * size;

                if (entry < 0 || entry >= layers()[currentLayerId()].cubes().size())
                {
                    entry = -1;
                }
                else//DEBUG - DISPLAYING VALUES FOR TEST
                {
                    std::cout << "Entry n°" << entry << " - ";
                    std::cout << "[" << I << "; " << J << "]" << std::endl;
                }
            //}
            //END IF CHECK IN MAP BOUDING BOX + ROTATION TO GOT DIAMOND SHAPE AREA(LAYER + OFFSETS)----------------------------------
        }

        return entry;
    }

IJ 和 entryNumber 都可以。我的意思是,例如,对于立方体 0,我有 I = 0;J = 0; 等等......这是有效的。

我不明白为什么坐标范围像这张图片中的红色部分(100%不准确,我不是绘画天才哈哈):

在此处输入图像描述

但我应该得到那个(第二张图片 - 红色部分是我点击的地方):

但是经过几次检查,IJ和我得到的条目是对应的。这太奇怪了。

在此处输入图像描述

EDIT2: 实现了偏移和层数。 问题左:错误的坐标范围。

以防万一,这是处理事件的“函数”:

void GRAPHICS_HANDLER::listenEvents()
{
    while (window->pollEvent(event))
    {
        if (event.type == sf::Event::Closed)
        {
            window->close();
        }

        if(event.type == sf::Event::KeyPressed)
        {
            //DISPLAY/UNDISPLAY GRID -- DEBUG FUNCTION
            if(event.key.code == sf::Keyboard::Escape)
            {
                if(grid)
                    grid = false;
                else
                    grid = true;
            }

//-----------------------------------------------------------------------------------DEBUG---------------------------------------------------------------//
            if(event.key.code == sf::Keyboard::B)//ACTIVE BRUSHMODE -- NEED TO BLOCK IT WHEN ACCESS VIOLATION OF CUBES ARRAY(CRASH)
            {
                if(!brushMode)
                {
                    brushMode = true;
                    std::cout << "Brush mode enabled" << std::endl;
                }
                else
                {
                    brushMode = false;
                    std::cout << "Brush mode disabled" << std::endl;
                }
            }

            if(event.key.code == sf::Keyboard::L)//ADD_LAYER
            {
                addLayer(getCurrentMapID());
            }

            if(event.key.code == sf::Keyboard::M)//DELETE_LAYER
            {
                deleteLayer(currentMapID, maps[currentMapID].currentLayerId());
            }

            if(event.key.code == sf::Keyboard::S)//ADD_LAYER
            {
                std::cout << "Select a texture: ";
                std::cin >> currentSelectedTexture; std::cout << std::endl;
            }

            if(event.key.code == sf::Keyboard::Left)//Move in Layer
            {
                if(maps[currentMapID].currentLayerId() > 0)
                {
                    maps[currentMapID].setCurrentLayerID(maps[currentMapID].currentLayerId()-1);
                }
            }

            if(event.key.code == sf::Keyboard::Right)//Move in Layer
            {
                if(maps[currentMapID].currentLayerId() < maps[currentMapID].layers().size()-1)
                {
                    maps[currentMapID].setCurrentLayerID(maps[currentMapID].currentLayerId()+1);
                }
            }
//-----------------------------------------------------------------------------------DEBUG---------------------------------------------------------------//
        }

        if (event.type == sf::Event::MouseMoved)
        {
//--------------------------------------------------------------------------CURSOR-----------------------------------------------------------------------//
            currentSelectedCube = maps[currentMapID].getCubeIDAt(event.mouseMove.x, event.mouseMove.y, offsetLeft, offsetTop, enableOffset);
//--------------------------------------------------------------------------CURSOR-----------------------------------------------------------------------//
        }

        if (event.type == sf::Event::MouseButtonPressed)
        {
//--------------------------------------------------------------------------CURSOR-----------------------------------------------------------------------//
            currentSelectedCube = maps[currentMapID].getCubeIDAt(event.mouseButton.x, event.mouseButton.y, offsetLeft, offsetTop, enableOffset);
//--------------------------------------------------------------------------CURSOR-----------------------------------------------------------------------//
            if (event.mouseButton.button == sf::Mouse::Left)
            {
//--------------------------------------------------------------------------CUBE CLICK DETECTION--------------------------------------------------//
                if(maps.size() > 0 && maps[currentMapID].layers().size() > 0 && currentSelectedCube > -1)
                {
                    cubeClicked = true;
                }
            }

            if (event.mouseButton.button == sf::Mouse::Right)
            {
                if(maps.size() > 0 && maps[currentMapID].layers().size() > 0 && currentSelectedCube > -1)
                {
                    maps[currentMapID].layers()[maps[currentMapID].currentLayerId()].cubes()[currentSelectedCube].setTexture(1);
                }
            }
//--------------------------------------------------------------------------CUBE CLICK DETECTION--------------------------------------------------//
        }
    }
}

EDIT3:我更新了我的代码以允许我只绘制立方体的下侧,所以我可以这样做(草): 在此处输入图像描述

当我放置平面正方形(绿色)时,坐标范围(屏幕截图中之前显示的红色等距正方形)会发生一些变化。我不知道为什么,我更喜欢精确它,以防万一。

4

1 回答 1

6

您需要从瓦片平面存储每个元素的“高度”,以区分您实际选择的立方体(离观察者越近):

在此处输入图像描述

相同的屏幕坐标,但不同的图块。

我不清楚你是如何为你的世界建模的,所以我会给你一个部分算法来检查哪个立方体的哪个面是点击的。请根据您的实际代码和您为使其工作而编写的类进行调整。

// I'll let you to add the offsets for the screen coordinates
I = (y * 2 - x) / cubeSize;
J = (y * 2 + x) / cubeSize;
// find out if it is a left or right triangle
if ( x < (J - I) * (cubeSize/2) ) {
    // left triangle
    for ( k = max_n_layer; k > -1; --k ) {
        // you create the cubes nesting the I loop in the J loop, so to get the index of a cube,
        // assuming that you have created all the cubes (even the invisible ones, like it seems from your code)
        index = (J+1+k)*mapsize + I+1+k;

        // I don't really get how you define the existence or not of a face, but I guess something like this:
        if ( index < map.layer[k].cubes.size() 
            &&  map.layer[k].cubes[index].sides[top_side] != 0 ) { 
        // the face selected is the top side of cube[index] of layer k
            // you have to return index and k to select the right face, or simply a pointer to that face
            // if this makes any sense with how you have designed your model
            return &map.layer[k].cubes[index].sides[top_side];
        }
        // now check for the side
        index = (J+k)*mapsize + I+1+k;
        if ( index < map.layer[k].cubes.size() 
            && map.layer[k].cubes[index].sides[right_side] != 0 ) { 

            return &map.layer[k].cubes[index].sides[right_side];
        }
        index = (J+k)*mapsize + I+k;
        if ( index < map.layer[k].cubes.size() 
            && map.layer[k].cubes[index].sides[left_side] != 0 ) { 

            return &map.layer[k].cubes[index].sides[left_side];
        }
    }
} else {
    // right triangle
    for ( k = max_n_layer; k > -1; --k ) {

        index = (J+1+k)*mapsize + I+1+k;

        if ( index < map.layer[k].cubes.size() 
            &&  map.layer[k].cubes[index].sides[top_side] != 0 ) { 
            return &map.layer[k].cubes[index].sides[top_side];
        }

        index = (J+1+k)*mapsize + I+k;
        if ( index < map.layer[k].cubes.size() 
            && map.layer[k].cubes[index].sides[left_side] != 0 ) { 

            return &map.layer[k].cubes[index].sides[left_side];
        }
        index = (J+k)*mapsize + I+k;
        if ( index < map.layer[k].cubes.size() 
            && map.layer[k].cubes[index].sides[right_side] != 0 ) { 

            return &map.layer[k].cubes[index].sides[right_side];
        }
    }
}    
// well, no match found. As I said is up to you to decide how to do in this case
return nullptr;

编辑

我建议你尝试另一种方式。

考虑屏幕不是由四边形瓷砖而是由您已经描绘的三角形划分的。您的模型的每个 2D 瓦片都将由其中两个三角形组成,因此您要绘制立方体的所有边。对于每个立方体不绘制甚至创建背面,那些永远不会被绘制。

您可以尝试通过为必须在屏幕上绘制的每个三角形存储更靠近观察者的一侧的索引来实现一种专门的 z 缓冲区算法。使用您已有的代码(一次)计算所有三角形的顶点坐标。

            (I,J)              //For every node (I,J) you have a left and a right triangle
           .  *  .
(I+1,J) *  .  |  .  * (I,J+1)
              *
          (I+1,J+1)

我猜你正在逐层创建你的立方体,每一层在基本平面上都有不同的高度。使用之前计算的坐标创建立方体的每一面。对于每个面(仅指向观察者的 3 个面)考虑其 2 个三角形中的每一个。如果您按顺序进行,您可以轻松确定它是否可见,然后您只需更新存储在相应三角形中的 ID。

完成此步骤后,您必须绘制每个三角形一次,因为您已经删除了隐藏的三角形。要确定从屏幕坐标到单元格索引的逆变换,您只需计算击中哪个三角形,然后查找对应的 ID。所以将 x,y 转换回 I,J (你已经有了这些方程),x < (J-I)/cubesize否则选择左边的三角形。

于 2015-12-05T15:15:49.110 回答