Skip to content

Commit

Permalink
Added parallax origin property to the map (#3209)
Browse files Browse the repository at this point in the history
Closes #3043

Co-authored-by: Thorbjørn Lindeijer <bjorn@lindeijer.nl>
  • Loading branch information
krukai and bjorn committed Dec 17, 2021
1 parent 65df8f0 commit b1450db
Show file tree
Hide file tree
Showing 19 changed files with 148 additions and 17 deletions.
35 changes: 20 additions & 15 deletions docs/manual/layers.rst
Original file line number Diff line number Diff line change
Expand Up @@ -151,8 +151,8 @@ the screen and the camera.
A value of 0 makes the layer not move at all, which can be useful to include
some pieces of your ingame UI or to mark its general viewport boundaries.

Negative values make the layer move in opposite direction, though this is rarely
useful.
Negative values make the layer move in opposite direction, though this is
rarely useful.

When the parallax scrolling factor is set on a group layer, it applies to all
its child layers. The effective parallax scrolling factor of a layer is
Expand All @@ -163,25 +163,30 @@ Parallax Reference Point
~~~~~~~~~~~~~~~~~~~~~~~~

To match not only the scrolling speed but also the positioning of layers, we
need to use the same points of reference. In Tiled these are the origin of the
map (the top-left of its bounding box) and the center of the view. The distance
between these two points is multiplied by the parallax factor, to determine the
need to use the same points of reference. In Tiled these are the parallax
origin and the center of the view. The parallax origin is stored per map and
defaults to (0,0), which is the top-left of the maps bounding box. The distance
between these two points is multiplied by the parallax factor to determine the
final position on the screen for each layer. For example:

* If the map's origin is in the center of the view, the distance is (0,0) and
none of the parallax factors have any effect.
* If the parallax origin is in the center of the view, the distance is (0,0)
and none of the parallax factors have any effect. The layers are rendered
where they would have been, if parallax was disabled.

* When the map is scrolled left by 10 pixels, the distance is -10, so a layer
with a parallax factor of 0.5 will be positioned ``0.5 * -10 = -5`` pixels from
the center of the view.
* Now, when the map is scrolled right by 10 pixels, the distance between the
parallax origin and the center of the view is 10. So a layer with a parallax
factor of 0.7 will have moved just ``0.7 * 10 = 7`` pixels.

Quite often, a viewport transform is used to scroll the entire map. In this
case, one may need to adjust the position of each layer to take its parallax
factor into account. For this, we take the map position that is located in the
center of the view, and multiply this by ``(1 - parallaxFactor)`` to get the layer
position. When the position in the center is 10, the layers will have normally
moved 10 pixels to the left (-10), but by positioning the layer at ``(10 * (1 - 0.5)) = 5``, we're
making sure that it only moves 5 pixels to the left.
factor into account. Instead of multiplying the distance with the parallax
factor directly, we now multiply by ``1 - parallaxFactor`` to get the layer
position. For example:

* When the camera moves right by 10 pixels, the layer will have moved 10
pixels to the left (-10), so by positioning the layer at
``10 * (1 - 0.7) = 3``, we're making sure that it only moves 7 pixels to
the left.

.. raw:: html

Expand Down
3 changes: 3 additions & 0 deletions docs/reference/json-map-format.rst
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ Map
nextlayerid, int, "Auto-increments for each layer"
nextobjectid, int, "Auto-increments for each placed object"
orientation, string, "``orthogonal``, ``isometric``, ``staggered`` or ``hexagonal``"
parallaxoriginx, double, "X coordinate of the parallax origin in pixels (since 1.8, default: 0)"
parallaxoriginy, double, "Y coordinate of the parallax origin in pixels (since 1.8, default: 0)"
properties, array, "Array of :ref:`Properties <json-property>`"
renderorder, string, "``right-down`` (the default), ``right-up``, ``left-down`` or ``left-up`` (currently only supported for orthogonal maps)"
staggeraxis, string, "``x`` or ``y`` (staggered / hexagonal maps only)"
Expand Down Expand Up @@ -755,6 +757,7 @@ Changelog
Tiled 1.8
~~~~~~~~~

* Added ``parallaxoriginx`` and ``parallaxoriginy`` properties to :ref:`json-map`.
* Added ``repeatx`` and ``repeaty`` properties to :ref:`json-layer` (applies
only to image layers at the moment).

Expand Down
2 changes: 2 additions & 0 deletions docs/reference/tmx-changelog.rst
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ Below are described the changes/additions that were made to the
Tiled 1.8
---------

- Added ``parallaxoriginx`` and ``parallaxoriginy`` attributes to the :ref:`tmx-map`
element.
- Added ``repeatx`` and ``repeaty`` attributes to the :ref:`tmx-imagelayer`
element.

Expand Down
4 changes: 4 additions & 0 deletions docs/reference/tmx-map-format.rst
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,10 @@ in what changed between Tiled versions.
- **staggerindex:** For staggered and hexagonal maps, determines whether
the "even" or "odd" indexes along the staggered axis are shifted.
(since 0.11)
- **parallaxoriginx:** X coordinate of the parallax origin in pixels
(defaults to 0). (since 1.8)
- **parallaxoriginy:** Y coordinate of the parallax origin in pixels
(defaults to 0). (since 1.8)
- **backgroundcolor:** The background color of the map. (optional, may
include alpha value since 0.15 in the form ``#AARRGGBB``. Defaults to
fully transparent.)
Expand Down
5 changes: 5 additions & 0 deletions docs/scripting-doc/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1750,6 +1750,11 @@ declare class TileMap extends Asset {
*/
staggerAxis : typeof TileMap.StaggerX | typeof TileMap.StaggerY

/**
* The parallax origin used for reference when applying the respective parallax factor.
*/
parallaxOrigin : point

/**
* General map orientation
*/
Expand Down
15 changes: 15 additions & 0 deletions src/libtiled/map.h
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ class TILEDSHARED_EXPORT Map : public Object
HexSideLengthProperty,
StaggerAxisProperty,
StaggerIndexProperty,
ParallaxOriginProperty,
OrientationProperty,
RenderOrderProperty,
BackgroundColorProperty,
Expand Down Expand Up @@ -159,6 +160,7 @@ class TILEDSHARED_EXPORT Map : public Object
int hexSideLength = 0;
StaggerAxis staggerAxis = StaggerY;
StaggerIndex staggerIndex = StaggerOdd;
QPointF parallaxOrigin;
QColor backgroundColor;
};

Expand Down Expand Up @@ -223,6 +225,9 @@ class TILEDSHARED_EXPORT Map : public Object
void setStaggerIndex(StaggerIndex staggerIndex);
void invertStaggerIndex();

QPointF parallaxOrigin() const;
void setParallaxOrigin(const QPointF &parallaxOrigin);

QMargins drawMargins() const;
void invalidateDrawMargins();

Expand Down Expand Up @@ -493,6 +498,16 @@ inline void Map::invertStaggerIndex()
mParameters.staggerIndex = static_cast<StaggerIndex>(!mParameters.staggerIndex);
}

inline QPointF Map::parallaxOrigin() const
{
return mParameters.parallaxOrigin;
}

inline void Map::setParallaxOrigin(const QPointF &parallaxOrigin)
{
mParameters.parallaxOrigin = parallaxOrigin;
}

inline void Map::invalidateDrawMargins()
{
mDrawMarginsDirty = true;
Expand Down
9 changes: 9 additions & 0 deletions src/libtiled/mapreader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -270,6 +270,15 @@ std::unique_ptr<Map> MapReaderPrivate::readMap()
mapParameters.staggerAxis = staggerAxisFromString(staggerAxis);
mapParameters.staggerIndex = staggerIndexFromString(staggerIndex);

bool ok;
const qreal parallaxOriginX = atts.value(QLatin1String("parallaxoriginx")).toDouble(&ok);
if (ok)
mapParameters.parallaxOrigin.setX(parallaxOriginX);

const qreal parallaxOriginY = atts.value(QLatin1String("parallaxoriginy")).toDouble(&ok);
if (ok)
mapParameters.parallaxOrigin.setY(parallaxOriginY);

const QString backgroundColor = atts.value(QLatin1String("backgroundcolor")).toString();
if (QColor::isValidColor(backgroundColor))
mapParameters.backgroundColor = QColor(backgroundColor);
Expand Down
5 changes: 5 additions & 0 deletions src/libtiled/maptovariantconverter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,11 @@ QVariant MapToVariantConverter::toVariant(const Map &map, const QDir &mapDir)
mapVariant[QStringLiteral("staggerindex")] = staggerIndexToString(map.staggerIndex());
}

if (!map.parallaxOrigin().isNull()) {
mapVariant[QStringLiteral("parallaxoriginx")] = map.parallaxOrigin().x();
mapVariant[QStringLiteral("parallaxoriginy")] = map.parallaxOrigin().y();
}

const QColor bgColor = map.backgroundColor();
if (bgColor.isValid())
mapVariant[QStringLiteral("backgroundcolor")] = colorToString(bgColor);
Expand Down
5 changes: 5 additions & 0 deletions src/libtiled/mapwriter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -221,6 +221,11 @@ void MapWriterPrivate::writeMap(QXmlStreamWriter &w, const Map &map)
staggerIndexToString(map.staggerIndex()));
}

if (!map.parallaxOrigin().isNull()) {
w.writeAttribute(QStringLiteral("parallaxoriginx"), QString::number(map.parallaxOrigin().x()));
w.writeAttribute(QStringLiteral("parallaxoriginy"), QString::number(map.parallaxOrigin().y()));
}

if (map.backgroundColor().isValid()) {
w.writeAttribute(QStringLiteral("backgroundcolor"),
colorToString(map.backgroundColor()));
Expand Down
9 changes: 8 additions & 1 deletion src/libtiled/varianttomapconverter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,14 @@ std::unique_ptr<Map> VariantToMapConverter::toMap(const QVariant &variant,
mapParameters.staggerAxis = staggerAxisFromString(staggerAxis);
mapParameters.staggerIndex = staggerIndexFromString(staggerIndex);

bool ok;
const qreal parallaxOriginX = variantMap[QStringLiteral("parallaxoriginx")].toDouble(&ok);
if (ok)
mapParameters.parallaxOrigin.setX( parallaxOriginX);
const qreal parallaxOriginY = variantMap[QStringLiteral("parallaxoriginy")].toDouble(&ok);
if (ok)
mapParameters.parallaxOrigin.setY(parallaxOriginY);

const QString bgColor = variantMap[QStringLiteral("backgroundcolor")].toString();
if (QColor::isValidColor(bgColor))
mapParameters.backgroundColor = QColor(bgColor);
Expand Down Expand Up @@ -121,7 +129,6 @@ std::unique_ptr<Map> VariantToMapConverter::toMap(const QVariant &variant,
tileset->loadImage();
}

bool ok;
const int compressionLevel = variantMap[QStringLiteral("compressionlevel")].toInt(&ok);
if (ok)
map->setCompressionLevel(compressionLevel);
Expand Down
7 changes: 7 additions & 0 deletions src/plugins/lua/luaplugin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -233,6 +233,13 @@ void LuaWriter::writeMap(const Map *map)
staggerIndexToString(map->staggerIndex()));
}

if (!map->parallaxOrigin().isNull()) {
mWriter.writeStartTable("parallaxorigin");
mWriter.writeKeyAndValue("x", map->parallaxOrigin().x());
mWriter.writeKeyAndValue("y", map->parallaxOrigin().y());
mWriter.writeEndTable();
}

const QColor &backgroundColor = map->backgroundColor();
if (backgroundColor.isValid())
writeColor("backgroundcolor", backgroundColor);
Expand Down
16 changes: 16 additions & 0 deletions src/tiled/changemapproperty.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,16 @@ ChangeMapProperty::ChangeMapProperty(MapDocument *mapDocument,
{
}

ChangeMapProperty::ChangeMapProperty(MapDocument *mapDocument,
const QPointF &parallaxOrigin)
: QUndoCommand(QCoreApplication::translate("Undo Commands",
"Change Parallax Origin"))
, mMapDocument(mapDocument)
, mProperty(Map::ParallaxOriginProperty)
, mParallaxOrigin(parallaxOrigin)
{
}

ChangeMapProperty::ChangeMapProperty(MapDocument *mapDocument,
Map::Orientation orientation)
: QUndoCommand(QCoreApplication::translate("Undo Commands",
Expand Down Expand Up @@ -190,6 +200,12 @@ void ChangeMapProperty::swap()
mStaggerIndex = staggerIndex;
break;
}
case Map::ParallaxOriginProperty: {
const QPointF parallaxOrigin = map->parallaxOrigin();
map->setParallaxOrigin(mParallaxOrigin);
mParallaxOrigin = parallaxOrigin;
break;
}
case Map::RenderOrderProperty: {
const Map::RenderOrder renderOrder = map->renderOrder();
map->setRenderOrder(mRenderOrder);
Expand Down
9 changes: 9 additions & 0 deletions src/tiled/changemapproperty.h
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,14 @@ class ChangeMapProperty : public QUndoCommand
*/
ChangeMapProperty(MapDocument *mapDocument, Map::StaggerIndex staggerIndex);

/**
* Constructs a command that changes the parallax origin.
*
* @param mapDocument the map document of the map
* @param parallaxOrigin the new parallax origin
*/
ChangeMapProperty(MapDocument *mapDocument, const QPointF &parallaxOrigin);

/**
* Constructs a command that changes the map orientation.
*
Expand Down Expand Up @@ -112,6 +120,7 @@ class ChangeMapProperty : public QUndoCommand
int mIntValue;
Map::StaggerAxis mStaggerAxis;
Map::StaggerIndex mStaggerIndex;
QPointF mParallaxOrigin;
Map::Orientation mOrientation;
Map::RenderOrder mRenderOrder;
Map::LayerDataFormat mLayerDataFormat;
Expand Down
8 changes: 8 additions & 0 deletions src/tiled/editablemap.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -530,6 +530,14 @@ void EditableMap::setStaggerIndex(StaggerIndex value)
map()->setStaggerIndex(static_cast<Map::StaggerIndex>(value));
}

void EditableMap::setParallaxOrigin(const QPointF &parallaxOrigin)
{
if (auto doc = mapDocument())
push(new ChangeMapProperty(doc, parallaxOrigin));
else if (!checkReadOnly())
map()->setParallaxOrigin(parallaxOrigin);
}

void EditableMap::setOrientation(Orientation value)
{
if (auto doc = mapDocument()) {
Expand Down
8 changes: 8 additions & 0 deletions src/tiled/editablemap.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ class EditableMap : public EditableAsset
Q_PROPERTY(int hexSideLength READ hexSideLength WRITE setHexSideLength)
Q_PROPERTY(StaggerAxis staggerAxis READ staggerAxis WRITE setStaggerAxis)
Q_PROPERTY(StaggerIndex staggerIndex READ staggerIndex WRITE setStaggerIndex)
Q_PROPERTY(QPointF parallaxOrigin READ parallaxOrigin WRITE setParallaxOrigin)
Q_PROPERTY(Orientation orientation READ orientation WRITE setOrientation)
Q_PROPERTY(RenderOrder renderOrder READ renderOrder WRITE setRenderOrder)
Q_PROPERTY(QColor backgroundColor READ backgroundColor WRITE setBackgroundColor)
Expand Down Expand Up @@ -120,6 +121,7 @@ class EditableMap : public EditableAsset
int hexSideLength() const;
StaggerAxis staggerAxis() const;
StaggerIndex staggerIndex() const;
QPointF parallaxOrigin() const;
Orientation orientation() const;
RenderOrder renderOrder() const;
QColor backgroundColor() const;
Expand Down Expand Up @@ -179,6 +181,7 @@ class EditableMap : public EditableAsset
void setHexSideLength(int value);
void setStaggerAxis(StaggerAxis value);
void setStaggerIndex(StaggerIndex value);
void setParallaxOrigin(const QPointF &parallaxOrigin);
void setOrientation(Orientation value);
void setRenderOrder(RenderOrder value);
void setBackgroundColor(const QColor &value);
Expand Down Expand Up @@ -266,6 +269,11 @@ inline EditableMap::StaggerIndex EditableMap::staggerIndex() const
return static_cast<StaggerIndex>(map()->staggerIndex());
}

inline QPointF EditableMap::parallaxOrigin() const
{
return map()->parallaxOrigin();
}

inline EditableMap::Orientation EditableMap::orientation() const
{
return static_cast<Orientation>(map()->orientation());
Expand Down
16 changes: 15 additions & 1 deletion src/tiled/mapscene.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,8 @@ void MapScene::setMapDocument(MapDocument *mapDocument)
mMapDocument = mapDocument;

if (mMapDocument) {
connect(mMapDocument, &MapDocument::changed,
this, &MapScene::changeEvent);
connect(mMapDocument, &MapDocument::mapChanged,
this, &MapScene::mapChanged);
connect(mMapDocument, &MapDocument::tilesetTilePositioningChanged,
Expand Down Expand Up @@ -232,7 +234,7 @@ QPointF MapScene::parallaxOffset(const Layer &layer) const
return {};

const QPointF parallaxFactor = layer.effectiveParallaxFactor();
const QPointF viewCenter = mViewRect.center();
const QPointF viewCenter = mViewRect.center() - mapDocument()->map()->parallaxOrigin();
return QPointF((1.0 - parallaxFactor.x()) * viewCenter.x(),
(1.0 - parallaxFactor.y()) * viewCenter.y());
}
Expand Down Expand Up @@ -358,6 +360,18 @@ MapItem *MapScene::takeOrCreateMapItem(const MapDocumentPtr &mapDocument, MapIte
return mapItem;
}

void MapScene::changeEvent(const ChangeEvent &change)
{
switch (change.type) {
case ChangeEvent::MapChanged:
if (static_cast<const MapChangeEvent&>(change).property == Map::ParallaxOriginProperty)
emit parallaxParametersChanged();
break;
default:
break;
}
}

/**
* Updates the possibly changed background color.
*/
Expand Down
1 change: 1 addition & 0 deletions src/tiled/mapscene.h
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,7 @@ class MapScene : public QGraphicsScene
private:
void refreshScene();

void changeEvent(const ChangeEvent &change);
void mapChanged();
void repaintTileset(Tileset *tileset);

Expand Down
Loading

0 comments on commit b1450db

Please sign in to comment.