Copy collision properties when selecting metatiles from the map area

This commit is contained in:
Marcus Huderle 2020-02-02 16:25:37 -06:00
parent 7a84ca872c
commit cfaf23aa3e
3 changed files with 90 additions and 12 deletions

View file

@ -1,8 +1,10 @@
#ifndef METATILESELECTOR_H #ifndef METATILESELECTOR_H
#define METATILESELECTOR_H #define METATILESELECTOR_H
#include <QPair>
#include "selectablepixmapitem.h" #include "selectablepixmapitem.h"
#include "tileset.h" #include "tileset.h"
#include "maplayout.h"
class MetatileSelector: public SelectablePixmapItem { class MetatileSelector: public SelectablePixmapItem {
Q_OBJECT Q_OBJECT
@ -13,15 +15,18 @@ public:
this->primaryTileset = primaryTileset; this->primaryTileset = primaryTileset;
this->secondaryTileset = secondaryTileset; this->secondaryTileset = secondaryTileset;
this->selectedMetatiles = new QList<uint16_t>(); this->selectedMetatiles = new QList<uint16_t>();
this->selectedCollisions = new QList<QPair<uint16_t, uint16_t>>();
this->externalSelectedMetatiles = new QList<uint16_t>(); this->externalSelectedMetatiles = new QList<uint16_t>();
setAcceptHoverEvents(true); setAcceptHoverEvents(true);
} }
QPoint getSelectionDimensions(); QPoint getSelectionDimensions();
void draw(); void draw();
void select(uint16_t metatile); void select(uint16_t metatile);
void selectFromMap(uint16_t metatileId, uint16_t collision, uint16_t elevation);
void setTilesets(Tileset*, Tileset*); void setTilesets(Tileset*, Tileset*);
QList<uint16_t>* getSelectedMetatiles(); QList<uint16_t>* getSelectedMetatiles();
void setExternalSelection(int, int, QList<uint16_t>*); QList<QPair<uint16_t, uint16_t>>* getSelectedCollisions();
void setExternalSelection(int, int, QList<uint16_t>, QList<QPair<uint16_t, uint16_t>>);
QPoint getMetatileIdCoordsOnWidget(uint16_t); QPoint getMetatileIdCoordsOnWidget(uint16_t);
protected: protected:
void mousePressEvent(QGraphicsSceneMouseEvent*); void mousePressEvent(QGraphicsSceneMouseEvent*);
@ -35,6 +40,7 @@ private:
Tileset *primaryTileset; Tileset *primaryTileset;
Tileset *secondaryTileset; Tileset *secondaryTileset;
QList<uint16_t> *selectedMetatiles; QList<uint16_t> *selectedMetatiles;
QList<QPair<uint16_t, uint16_t>> *selectedCollisions;
int externalSelectionWidth; int externalSelectionWidth;
int externalSelectionHeight; int externalSelectionHeight;
QList<uint16_t> *externalSelectedMetatiles; QList<uint16_t> *externalSelectedMetatiles;

View file

@ -72,6 +72,7 @@ void MapPixmapItem::shift(QGraphicsSceneMouseEvent *event) {
void MapPixmapItem::paintNormal(int x, int y) { void MapPixmapItem::paintNormal(int x, int y) {
QPoint selectionDimensions = this->metatileSelector->getSelectionDimensions(); QPoint selectionDimensions = this->metatileSelector->getSelectionDimensions();
QList<uint16_t> *selectedMetatiles = this->metatileSelector->getSelectedMetatiles(); QList<uint16_t> *selectedMetatiles = this->metatileSelector->getSelectedMetatiles();
QList<QPair<uint16_t, uint16_t>> *selectedCollisions = this->metatileSelector->getSelectedCollisions();
// Snap the selected position to the top-left of the block boundary. // Snap the selected position to the top-left of the block boundary.
// This allows painting via dragging the mouse to tile the painted region. // This allows painting via dragging the mouse to tile the painted region.
@ -89,7 +90,12 @@ void MapPixmapItem::paintNormal(int x, int y) {
int actualY = j + y; int actualY = j + y;
Block *block = map->getBlock(actualX, actualY); Block *block = map->getBlock(actualX, actualY);
if (block) { if (block) {
block->tile = selectedMetatiles->at(j * selectionDimensions.x() + i); int index = j * selectionDimensions.x() + i;
block->tile = selectedMetatiles->at(index);
if (selectedCollisions && selectedCollisions->length() == selectedMetatiles->length()) {
block->collision = selectedCollisions->at(index).first;
block->elevation = selectedCollisions->at(index).second;
}
map->_setBlock(actualX, actualY, *block); map->_setBlock(actualX, actualY, *block);
} }
} }
@ -122,12 +128,21 @@ QList<int> MapPixmapItem::smartPathTable = QList<int>({
void MapPixmapItem::paintSmartPath(int x, int y) { void MapPixmapItem::paintSmartPath(int x, int y) {
QPoint selectionDimensions = this->metatileSelector->getSelectionDimensions(); QPoint selectionDimensions = this->metatileSelector->getSelectionDimensions();
QList<uint16_t> *selectedMetatiles = this->metatileSelector->getSelectedMetatiles(); QList<uint16_t> *selectedMetatiles = this->metatileSelector->getSelectedMetatiles();
QList<QPair<uint16_t, uint16_t>> *selectedCollisions = this->metatileSelector->getSelectedCollisions();
// Smart path should never be enabled without a 3x3 block selection. // Smart path should never be enabled without a 3x3 block selection.
if (selectionDimensions.x() != 3 || selectionDimensions.y() != 3) return; if (selectionDimensions.x() != 3 || selectionDimensions.y() != 3) return;
// Shift to the middle tile of the smart path selection. // Shift to the middle tile of the smart path selection.
uint16_t openTile = selectedMetatiles->at(4); uint16_t openTile = selectedMetatiles->at(4);
uint16_t openTileCollision = 0;
uint16_t openTileElevation = 0;
bool setCollisions = false;
if (selectedCollisions && selectedCollisions->length() == selectedMetatiles->length()) {
openTileCollision = selectedCollisions->at(4).first;
openTileElevation = selectedCollisions->at(4).second;
setCollisions = true;
}
// Fill the region with the open tile. // Fill the region with the open tile.
for (int i = 0; i <= 1; i++) for (int i = 0; i <= 1; i++)
@ -140,6 +155,10 @@ void MapPixmapItem::paintSmartPath(int x, int y) {
Block *block = map->getBlock(actualX, actualY); Block *block = map->getBlock(actualX, actualY);
if (block) { if (block) {
block->tile = openTile; block->tile = openTile;
if (setCollisions) {
block->collision = openTileCollision;
block->elevation = openTileElevation;
}
map->_setBlock(actualX, actualY, *block); map->_setBlock(actualX, actualY, *block);
} }
} }
@ -180,6 +199,10 @@ void MapPixmapItem::paintSmartPath(int x, int y) {
id += 8; id += 8;
block->tile = selectedMetatiles->at(smartPathTable[id]); block->tile = selectedMetatiles->at(smartPathTable[id]);
if (setCollisions) {
block->collision = selectedCollisions->at(smartPathTable[id]).first;
block->elevation = selectedCollisions->at(smartPathTable[id]).second;
}
map->_setBlock(actualX, actualY, *block); map->_setBlock(actualX, actualY, *block);
} }
} }
@ -200,8 +223,8 @@ void MapPixmapItem::updateMetatileSelection(QGraphicsSceneMouseEvent *event) {
selection_origin = QPoint(x, y); selection_origin = QPoint(x, y);
selection.clear(); selection.clear();
selection.append(QPoint(x, y)); selection.append(QPoint(x, y));
uint16_t metatileId = map->getBlock(x, y)->tile; Block *block = map->getBlock(x, y);
this->metatileSelector->select(metatileId); this->metatileSelector->selectFromMap(block->tile, block->collision, block->elevation);
} else if (event->type() == QEvent::GraphicsSceneMouseMove) { } else if (event->type() == QEvent::GraphicsSceneMouseMove) {
QPoint pos = QPoint(x, y); QPoint pos = QPoint(x, y);
int x1 = selection_origin.x(); int x1 = selection_origin.x();
@ -218,11 +241,17 @@ void MapPixmapItem::updateMetatileSelection(QGraphicsSceneMouseEvent *event) {
} }
QList<uint16_t> metatiles; QList<uint16_t> metatiles;
QList<QPair<uint16_t, uint16_t>> collisions;
for (QPoint point : selection) { for (QPoint point : selection) {
metatiles.append(map->getBlock(point.x(), point.y())->tile); int x = point.x();
int y = point.y();
metatiles.append(map->getBlock(x, y)->tile);
int blockIndex = y * map->getWidth() + x;
Block block = map->layout->blockdata->blocks->at(blockIndex);
collisions.append(QPair<uint16_t, uint16_t>(block.collision, block.elevation));
} }
this->metatileSelector->setExternalSelection(x2 - x1 + 1, y2 - y1 + 1, &metatiles); this->metatileSelector->setExternalSelection(x2 - x1 + 1, y2 - y1 + 1, metatiles, collisions);
} }
} }
@ -263,6 +292,8 @@ void MapPixmapItem::magicFill(QGraphicsSceneMouseEvent *event) {
if (block) { if (block) {
QList<uint16_t> *selectedMetatiles = this->metatileSelector->getSelectedMetatiles(); QList<uint16_t> *selectedMetatiles = this->metatileSelector->getSelectedMetatiles();
QList<QPair<uint16_t, uint16_t>> *selectedCollisions = this->metatileSelector->getSelectedCollisions();
bool setCollisions = selectedCollisions && selectedCollisions->length() == selectedMetatiles->length();
QPoint selectionDimensions = this->metatileSelector->getSelectionDimensions(); QPoint selectionDimensions = this->metatileSelector->getSelectionDimensions();
uint16_t tile = block->tile; uint16_t tile = block->tile;
@ -276,7 +307,12 @@ void MapPixmapItem::magicFill(QGraphicsSceneMouseEvent *event) {
int j = yDiff % selectionDimensions.y(); int j = yDiff % selectionDimensions.y();
if (i < 0) i = selectionDimensions.x() + i; if (i < 0) i = selectionDimensions.x() + i;
if (j < 0) j = selectionDimensions.y() + j; if (j < 0) j = selectionDimensions.y() + j;
block->tile = selectedMetatiles->at(j * selectionDimensions.x() + i); int index = j * selectionDimensions.x() + i;
block->tile = selectedMetatiles->at(index);
if (setCollisions) {
block->collision = selectedCollisions->at(index).first;
block->elevation = selectedCollisions->at(index).second;
}
map->_setBlock(x, y, *block); map->_setBlock(x, y, *block);
} }
} }
@ -291,6 +327,8 @@ void MapPixmapItem::magicFill(QGraphicsSceneMouseEvent *event) {
void MapPixmapItem::_floodFill(int initialX, int initialY) { void MapPixmapItem::_floodFill(int initialX, int initialY) {
QPoint selectionDimensions = this->metatileSelector->getSelectionDimensions(); QPoint selectionDimensions = this->metatileSelector->getSelectionDimensions();
QList<uint16_t> *selectedMetatiles = this->metatileSelector->getSelectedMetatiles(); QList<uint16_t> *selectedMetatiles = this->metatileSelector->getSelectedMetatiles();
QList<QPair<uint16_t, uint16_t>> *selectedCollisions = this->metatileSelector->getSelectedCollisions();
bool setCollisions = selectedCollisions && selectedCollisions->length() == selectedMetatiles->length();
int numMetatiles = map->getWidth() * map->getHeight(); int numMetatiles = map->getWidth() * map->getHeight();
bool *visited = new bool[numMetatiles]; bool *visited = new bool[numMetatiles];
@ -316,10 +354,15 @@ void MapPixmapItem::_floodFill(int initialX, int initialY) {
int j = yDiff % selectionDimensions.y(); int j = yDiff % selectionDimensions.y();
if (i < 0) i = selectionDimensions.x() + i; if (i < 0) i = selectionDimensions.x() + i;
if (j < 0) j = selectionDimensions.y() + j; if (j < 0) j = selectionDimensions.y() + j;
uint16_t tile = selectedMetatiles->at(j * selectionDimensions.x() + i); int index = j * selectionDimensions.x() + i;
uint16_t tile = selectedMetatiles->at(index);
uint16_t old_tile = block->tile; uint16_t old_tile = block->tile;
if (selectedMetatiles->count() != 1 || old_tile != tile) { if (selectedMetatiles->count() != 1 || old_tile != tile) {
block->tile = tile; block->tile = tile;
if (setCollisions) {
block->collision = selectedCollisions->at(index).first;
block->elevation = selectedCollisions->at(index).second;
}
map->_setBlock(x, y, *block); map->_setBlock(x, y, *block);
} }
if (!visited[x + 1 + y * map->getWidth()] && (block = map->getBlock(x + 1, y)) && block->tile == old_tile) { if (!visited[x + 1 + y * map->getWidth()] && (block = map->getBlock(x + 1, y)) && block->tile == old_tile) {
@ -346,12 +389,21 @@ void MapPixmapItem::_floodFill(int initialX, int initialY) {
void MapPixmapItem::_floodFillSmartPath(int initialX, int initialY) { void MapPixmapItem::_floodFillSmartPath(int initialX, int initialY) {
QPoint selectionDimensions = this->metatileSelector->getSelectionDimensions(); QPoint selectionDimensions = this->metatileSelector->getSelectionDimensions();
QList<uint16_t> *selectedMetatiles = this->metatileSelector->getSelectedMetatiles(); QList<uint16_t> *selectedMetatiles = this->metatileSelector->getSelectedMetatiles();
QList<QPair<uint16_t, uint16_t>> *selectedCollisions = this->metatileSelector->getSelectedCollisions();
// Smart path should never be enabled without a 3x3 block selection. // Smart path should never be enabled without a 3x3 block selection.
if (selectionDimensions.x() != 3 || selectionDimensions.y() != 3) return; if (selectionDimensions.x() != 3 || selectionDimensions.y() != 3) return;
// Shift to the middle tile of the smart path selection. // Shift to the middle tile of the smart path selection.
uint16_t openTile = selectedMetatiles->at(4); uint16_t openTile = selectedMetatiles->at(4);
uint16_t openTileCollision = 0;
uint16_t openTileElevation = 0;
bool setCollisions = false;
if (selectedCollisions && selectedCollisions->length() == selectedMetatiles->length()) {
openTileCollision = selectedCollisions->at(4).first;
openTileElevation = selectedCollisions->at(4).second;
setCollisions = true;
}
// Flood fill the region with the open tile. // Flood fill the region with the open tile.
QList<QPoint> todo; QList<QPoint> todo;
@ -372,6 +424,10 @@ void MapPixmapItem::_floodFillSmartPath(int initialX, int initialY) {
} }
block->tile = openTile; block->tile = openTile;
if (setCollisions) {
block->collision = openTileCollision;
block->elevation = openTileElevation;
}
map->_setBlock(x, y, *block); map->_setBlock(x, y, *block);
if ((block = map->getBlock(x + 1, y)) && block->tile == old_tile) { if ((block = map->getBlock(x + 1, y)) && block->tile == old_tile) {
todo.append(QPoint(x + 1, y)); todo.append(QPoint(x + 1, y));
@ -423,6 +479,10 @@ void MapPixmapItem::_floodFillSmartPath(int initialX, int initialY) {
id += 8; id += 8;
block->tile = selectedMetatiles->at(smartPathTable[id]); block->tile = selectedMetatiles->at(smartPathTable[id]);
if (setCollisions) {
block->collision = selectedCollisions->at(smartPathTable[id]).first;
block->elevation = selectedCollisions->at(smartPathTable[id]).second;
}
map->_setBlock(x, y, *block); map->_setBlock(x, y, *block);
// Visit neighbors if they are smart-path tiles, and don't revisit any. // Visit neighbors if they are smart-path tiles, and don't revisit any.
@ -453,7 +513,7 @@ void MapPixmapItem::pick(QGraphicsSceneMouseEvent *event) {
int y = static_cast<int>(pos.y()) / 16; int y = static_cast<int>(pos.y()) / 16;
Block *block = map->getBlock(x, y); Block *block = map->getBlock(x, y);
if (block) { if (block) {
this->metatileSelector->select(block->tile); this->metatileSelector->selectFromMap(block->tile, block->collision, block->elevation);
} }
} }

View file

@ -53,6 +53,11 @@ void MetatileSelector::select(uint16_t metatileId) {
emit selectedMetatilesChanged(); emit selectedMetatilesChanged();
} }
void MetatileSelector::selectFromMap(uint16_t metatileId, uint16_t collision, uint16_t elevation) {
this->select(metatileId);
this->selectedCollisions->append(QPair<uint16_t, uint16_t>(collision, elevation));
}
void MetatileSelector::setTilesets(Tileset *primaryTileset, Tileset *secondaryTileset) { void MetatileSelector::setTilesets(Tileset *primaryTileset, Tileset *secondaryTileset) {
this->primaryTileset = primaryTileset; this->primaryTileset = primaryTileset;
this->secondaryTileset = secondaryTileset; this->secondaryTileset = secondaryTileset;
@ -67,13 +72,19 @@ QList<uint16_t>* MetatileSelector::getSelectedMetatiles() {
} }
} }
void MetatileSelector::setExternalSelection(int width, int height, QList<uint16_t> *metatiles) { QList<QPair<uint16_t, uint16_t>>* MetatileSelector::getSelectedCollisions() {
return this->selectedCollisions;
}
void MetatileSelector::setExternalSelection(int width, int height, QList<uint16_t> metatiles, QList<QPair<uint16_t, uint16_t>> collisions) {
this->externalSelection = true; this->externalSelection = true;
this->externalSelectionWidth = width; this->externalSelectionWidth = width;
this->externalSelectionHeight = height; this->externalSelectionHeight = height;
this->externalSelectedMetatiles->clear(); this->externalSelectedMetatiles->clear();
for (int i = 0; i < metatiles->length(); i++) { this->selectedCollisions->clear();
this->externalSelectedMetatiles->append(metatiles->at(i)); for (int i = 0; i < metatiles.length(); i++) {
this->externalSelectedMetatiles->append(metatiles.at(i));
this->selectedCollisions->append(collisions.at(i));
} }
this->draw(); this->draw();
@ -115,6 +126,7 @@ void MetatileSelector::hoverLeaveEvent(QGraphicsSceneHoverEvent*) {
void MetatileSelector::updateSelectedMetatiles() { void MetatileSelector::updateSelectedMetatiles() {
this->externalSelection = false; this->externalSelection = false;
this->selectedMetatiles->clear(); this->selectedMetatiles->clear();
this->selectedCollisions->clear();
QPoint origin = this->getSelectionStart(); QPoint origin = this->getSelectionStart();
QPoint dimensions = this->getSelectionDimensions(); QPoint dimensions = this->getSelectionDimensions();
for (int j = 0; j < dimensions.y(); j++) { for (int j = 0; j < dimensions.y(); j++) {