2015-11-25 5 views
17

Non lavoro con le tessere ma i cubi sono disegnati con sf :: Vertex. Ogni cubo ha 6 lati con 4 punti ciascuno. enter image description here2D isometrico - SFML - Formule giuste, intervallo di coordinate errato

Quindi devo solo cubes[numCube].sides()[numSide].... per selezionare un lato.

mi crea cubi 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); 
     } 
    } 

In cube.cpp genero lati, poi, in sides.cpp, i CALCUL coordinate ciascuno punti simili:

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. .... 

Point 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); 
} 

il mio problema provengono dalla funzione che uso per rilevare clic:

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

La funzione (non perdete tempo con i commenti):

cerco di ottenere l'entrata di un cubo nel mio cubo di vettore, senza 'per il ciclo'. Perché? usare meno CPU quando clicco.

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

L'I-J e entryNumber sono OK. Voglio dire, per esempio, per il cubo 0, ho I = 0; J = 0; ecc ... Funziona.

Non capisco il motivo per cui la coordinata gamma è come la parte rossa (non preciso al 100%, non sono un genio della vernice ha ha) in questa immagine:

enter image description here

Ma io dovrebbe ottenere quello (2a foto - la parte rossa è dove clicco):

Ma dopo pochi controlli, l'IJ e la voce che ho ottenuto sono corrispondenti. Questo è così strano.

enter image description here

EDIT2: offset e strato numero attuato. Problema lasciato: intervallo di coordinate errato.

Solo nel caso, questa è la 'funzione' gestione degli eventi:

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: ho aggiornato il mio codice per permettermi di disegnare solo il lato negativo del cubo, così posso fare questo (l'erba): enter image description here

L'intervallo di coordinate (il quadrato isometrico rosso mostrato prima nelle schermate) cambia leggermente quando inserisco un quadrato piatto (verde). Non so perché, preferisco precisarlo, per ogni evenienza.

risposta

5

è necessario memorizzare la "altezza" di ogni elemento dal piano piastrelle al fine di distinguere quale cubo sono effettivamente di selezione (la più vicina all'osservatore):

enter image description here

coordinate dello schermo stesso, ma piastrelle diverse.

Non mi è chiaro come hai modellato il tuo mondo, quindi ti darò un algoritmo parziale per verificare quale faccia di quale cubo è quello cliccato. Per favore, adattalo al tuo codice attuale e alle classi che hai scritto per farlo funzionare.

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

Modifica

suggerisco di provare un altro modo.

Considerare lo schermo come diviso non per le tessere quadrangolari ma per i triangoli già rappresentati. Ogni tessera 2D del tuo modello sarà formata da due di quei triangoli e quindi da tutti i lati dei cubi che vuoi disegnare. Per ogni cubo non disegnare e nemmeno creare i lati posteriori, quelli non saranno mai disegnati.

Si può provare a implementare una sorta di algoritmo di buffer z specializzato archiviando per ciascuno dei triangoli che si devono disegnare sullo schermo l'indice del lato che è più vicino all'osservatore. Le coordinate del vertice di tutti i triangoli sono calcolate (una volta) con il codice che hai già.

  (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) 

Si stanno creando i cubi strato per strato, suppongo, ogni livello abbia un'altezza diversa rispetto al piano di base. Crea ogni lato del cubo usando le coordinate calcolate in precedenza. Per ogni faccia (solo il 3 che indica l'osservatore) considera ciascuno dei suoi 2 triangoli. È possibile determinare facilmente se è visibile o meno se si procede in ordine, quindi è sufficiente aggiornare l'ID memorizzato nel triangolo corrispondente.

Una volta terminata questa fase, dovrai disegnare ogni triangolo una volta che hai già lasciato cadere quelli nascosti. Per determinare la trasformazione inversa dalle coordinate dello schermo agli indici di celle, devi solo calcolare quale triangolo viene colpito e quindi cercare quale ID corrisponde a quello. Quindi trasforma indietro x, y in I, J (hai già queste equazioni) e scegli il triangolo a sinistra se x < (J-I)/cubesize quello giusto altrimenti.

+0

Ho già impostato "altezza", in tutto il mio codice, "altezza" è il numero del livello. Tutto ciò di cui ho bisogno è di correggere il calcolo I/J. – Madz

+0

Grazie per la tua risposta, sfortunatamente, non so se è dovuto alla mia mancanza di abilità o codifica in inglese (matematica?), Ma non sono sicuro di capirlo. Ho capito la parte in cui avrei dovuto abbandonare la faccia che non verrà visualizzata, ma cos'è un nodo? – Madz

+0

@Madz dal tuo codice, crei ogni cubo calcolando le coordinate x, y dei suoi vertici dalle due parti I e J. Quindi ogni coppia di indie (I, J) definisce un cubo. Nei tuoi disegni (e miniere) ogni vertice di ogni triangolo o tessera quadrangolare corrisponde a un paio di pezzi (I, J). La matematica che stai facendo è trasformare quei valori in coordinate dello schermo e all'indietro. –

Problemi correlati