Skip to content

Commit

Permalink
Merge pull request #2951 from mapeditor/wip/scroll-factor
Browse files Browse the repository at this point in the history
Added support for a parallax scroll factor per layer
  • Loading branch information
bjorn authored Dec 15, 2020
2 parents 250486a + cfe6f74 commit 7d6b7e4
Show file tree
Hide file tree
Showing 50 changed files with 569 additions and 129 deletions.
36 changes: 33 additions & 3 deletions docs/manual/layers.rst
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,10 @@ foreground or background graphics. The order of the layers determines
the rendering order of your content.

Layers can be hidden, made only partially visible and can be locked. Layers
also have an offset, which can be used to position them independently of each
other, for example to fake depth. Finally their contents can be tinted by
multiplying with a custom :ref:`tint color <tint-color>`.
also have an offset and a :ref:`parallax scrolling factor <parallax-factor>`,
which can be used to position them independently of each other, for example to
fake depth. Finally their contents can be tinted by multiplying with a custom
:ref:`tint color <tint-color>`.

.. figure:: images/layers/lock-visibility-toggle.png
:alt: Layers View
Expand Down Expand Up @@ -125,6 +126,35 @@ Layers can be easily dragged in and out of groups with the mouse. The
Raise Layer / Lower Layer actions also allow moving layers in and out of
groups.

.. raw:: html

<div class="new">New in Tiled 1.5</div>

.. _parallax-factor:

Parallax Scrolling Factor
-------------------------

The parallax scrolling factor determines the amount by which the layer moves in
relation to the camera.

By default its value is 1, which means its position on the screen changes at
the same rate as the position of the camera (in opposite direction). A lower
value makes it move slower, simulating a layer that is further away, whereas
a higher value makes it move faster, simulating a layer positioned in between
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.

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
determined by multiplying the parallax scrolling factor by the scrolling
factors of all parent layers.

.. raw:: html

<div class="new">New in Tiled 1.4</div>
Expand Down
4 changes: 3 additions & 1 deletion docs/reference/json-map-format.rst
Original file line number Diff line number Diff line change
Expand Up @@ -94,10 +94,12 @@ Layer
offsetx, double, "Horizontal layer offset in pixels (default: 0)"
offsety, double, "Vertical layer offset in pixels (default: 0)"
opacity, double, "Value between 0 and 1"
parallaxx, double, "Horizontal :ref:`parallax factor <parallax-factor>` for this layer (default: 1). (since Tiled 1.5)"
parallaxy, double, "Vertical :ref:`parallax factor <parallax-factor>` for this layer (default: 1). (since Tiled 1.5)"
properties, array, "Array of :ref:`Properties <json-property>`"
startx, int, "X coordinate where layer content starts (for infinite maps)"
starty, int, "Y coordinate where layer content starts (for infinite maps)"
tintcolor, string, "Hex-formatted color (#RRGGBB or #AARRGGBB) that is multiplied with any graphics drawn by this layer or any child layers (optional)."
tintcolor, string, "Hex-formatted :ref:`tint color <tint-color>` (#RRGGBB or #AARRGGBB) that is multiplied with any graphics drawn by this layer or any child layers (optional)."
transparentcolor, string, "Hex-formatted color (#RRGGBB) (optional). ``imagelayer`` only."
type, string, "``tilelayer``, ``objectgroup``, ``imagelayer`` or ``group``"
visible, bool, "Whether layer is shown or hidden in editor"
Expand Down
3 changes: 2 additions & 1 deletion docs/reference/scripting.rst
Original file line number Diff line number Diff line change
Expand Up @@ -920,7 +920,8 @@ Properties
**visible** : bool, Whether the layer is visible (affects child layer visibility for group layers).
**locked** : bool, Whether the layer is locked (affects whether child layers are locked for group layers).
**offset** : :ref:`script-point`, Offset in pixels that is applied when this layer is rendered.
**map** : :ref:`script-map`, Map that this layer is part of (or ``null`` in case of a standalone layer).
**parallaxFactor** : :ref:`script-point`, The parallax factor of the layer (since Tiled 1.5).
**map** : :ref:`script-map` |ro|, Map that this layer is part of (or ``null`` in case of a standalone layer).
**selected** : bool, Whether the layer is selected.
**isTileLayer** : bool |ro|, Whether this layer is a :ref:`script-tilelayer`.
**isObjectLayer** : bool |ro|, Whether this layer is an :ref:`script-objectgroup`.
Expand Down
4 changes: 3 additions & 1 deletion docs/reference/tmx-map-format.rst
Original file line number Diff line number Diff line change
Expand Up @@ -380,11 +380,13 @@ tiles.
- **height:** The height of the layer in tiles. Always the same as the map height for fixed-size maps.
- **opacity:** The opacity of the layer as a value from 0 to 1. Defaults to 1.
- **visible:** Whether the layer is shown (1) or hidden (0). Defaults to 1.
- **tintcolor:** A color that is multiplied with any tiles drawn by this layer in ``#AARRGGBB`` or ``#RRGGBB`` format (optional).
- **tintcolor:** A :ref:`tint color <tint-color>` that is multiplied with any tiles drawn by this layer in ``#AARRGGBB`` or ``#RRGGBB`` format (optional).
- **offsetx:** Horizontal offset for this layer in pixels. Defaults to 0.
(since 0.14)
- **offsety:** Vertical offset for this layer in pixels. Defaults to 0.
(since 0.14)
- **parallaxx:** Horizontal :ref:`parallax factor <parallax-factor>` for this layer. Defaults to 1. (since 1.5)
- **parallaxy:** Vertical :ref:`parallax factor <parallax-factor>` for this layer. Defaults to 1. (since 1.5)

Can contain at most one: :ref:`tmx-properties`, :ref:`tmx-data`

Expand Down
29 changes: 17 additions & 12 deletions src/libtiled/layer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -45,18 +45,12 @@ static QColor multiplyColors(QColor color1, QColor color2)
color1.alphaF() * color2.alphaF());
}

Layer::Layer(TypeFlag type, const QString &name, int x, int y) :
Object(LayerType),
mName(name),
mId(0),
mLayerType(type),
mX(x),
mY(y),
mOpacity(1.0),
mVisible(true),
mMap(nullptr),
mParentLayer(nullptr),
mLocked(false)
Layer::Layer(TypeFlag type, const QString &name, int x, int y)
: Object(LayerType)
, mName(name)
, mLayerType(type)
, mX(x)
, mY(y)
{
}

Expand Down Expand Up @@ -190,6 +184,17 @@ QPointF Layer::totalOffset() const
return offset;
}

QPointF Layer::effectiveParallaxFactor() const
{
auto factor = mParallaxFactor;
const Layer *layer = this;
while ((layer = layer->parentLayer())) {
factor.rx() *= layer->parallaxFactor().rx();
factor.ry() *= layer->parallaxFactor().ry();
}
return factor;
}

/**
* Returns whether this layer can be merged down onto the layer below.
*/
Expand Down
38 changes: 29 additions & 9 deletions src/libtiled/layer.h
Original file line number Diff line number Diff line change
Expand Up @@ -184,9 +184,12 @@ class TILEDSHARED_EXPORT Layer : public Object

void setOffset(const QPointF &offset);
QPointF offset() const;

QPointF totalOffset() const;

void setParallaxFactor(const QPointF &factor);
QPointF parallaxFactor() const;
QPointF effectiveParallaxFactor() const;

bool canMergeDown() const;

virtual bool isEmpty() const = 0;
Expand Down Expand Up @@ -252,17 +255,18 @@ class TILEDSHARED_EXPORT Layer : public Object
Layer *initializeClone(Layer *clone) const;

QString mName;
int mId;
int mId = 0;
TypeFlag mLayerType;
int mX;
int mY;
int mX = 0;
int mY = 0;
QPointF mOffset;
qreal mOpacity;
QPointF mParallaxFactor = { 1.0, 1.0 };
qreal mOpacity = 1.0;
QColor mTintColor;
bool mVisible;
Map *mMap;
GroupLayer *mParentLayer;
bool mLocked;
bool mVisible = true;
Map *mMap = nullptr;
GroupLayer *mParentLayer = nullptr;
bool mLocked = false;

friend class Map;
friend class GroupLayer;
Expand All @@ -285,6 +289,22 @@ inline QPointF Layer::offset() const
return mOffset;
}

/**
* Sets the parallax factor of this layer.
*/
inline void Layer::setParallaxFactor(const QPointF &factor)
{
mParallaxFactor = factor;
}

/**
* Returns the parallax factor of this layer.
*/
inline QPointF Layer::parallaxFactor() const
{
return mParallaxFactor;
}


/**
* An iterator for iterating over the layers of a map, in the order in which
Expand Down
10 changes: 10 additions & 0 deletions src/libtiled/mapreader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -867,6 +867,16 @@ static void readLayerAttributes(Layer &layer,
atts.value(QLatin1String("offsety")).toDouble());

layer.setOffset(offset);

QPointF parallaxFactor(1.0, 1.0);
const qreal factorX = atts.value(QLatin1String("parallaxx")).toDouble(&ok);
if (ok)
parallaxFactor.setX(factorX);
const qreal factorY = atts.value(QLatin1String("parallaxy")).toDouble(&ok);
if (ok)
parallaxFactor.setY(factorY);

layer.setParallaxFactor(parallaxFactor);
}

std::unique_ptr<TileLayer> MapReaderPrivate::readTileLayer()
Expand Down
6 changes: 6 additions & 0 deletions src/libtiled/maptovariantconverter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -742,6 +742,12 @@ void MapToVariantConverter::addLayerAttributes(QVariantMap &layerVariant,
layerVariant[QStringLiteral("offsety")] = offset.y();
}

const QPointF parallaxFactor = layer.parallaxFactor();
if (parallaxFactor.x() != 1.0)
layerVariant[QStringLiteral("parallaxx")] = parallaxFactor.x();
if (parallaxFactor.y() != 1.0)
layerVariant[QStringLiteral("parallaxy")] = parallaxFactor.y();

if (layer.tintColor().isValid())
layerVariant[QStringLiteral("tintcolor")] = colorToString(layer.tintColor());

Expand Down
6 changes: 6 additions & 0 deletions src/libtiled/mapwriter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -714,6 +714,12 @@ void MapWriterPrivate::writeLayerAttributes(QXmlStreamWriter &w,
w.writeAttribute(QStringLiteral("offsetx"), QString::number(offset.x()));
w.writeAttribute(QStringLiteral("offsety"), QString::number(offset.y()));
}

const QPointF parallaxFactor = layer.parallaxFactor();
if (parallaxFactor.x() != 1.0)
w.writeAttribute(QStringLiteral("parallaxx"), QString::number(parallaxFactor.x()));
if (parallaxFactor.y() != 1.0)
w.writeAttribute(QStringLiteral("parallaxy"), QString::number(parallaxFactor.y()));
}

void MapWriterPrivate::writeObjectGroup(QXmlStreamWriter &w,
Expand Down
11 changes: 11 additions & 0 deletions src/libtiled/varianttomapconverter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -567,6 +567,17 @@ std::unique_ptr<Layer> VariantToMapConverter::toLayer(const QVariant &variant)
const QPointF offset(variantMap[QStringLiteral("offsetx")].toDouble(),
variantMap[QStringLiteral("offsety")].toDouble());
layer->setOffset(offset);

bool ok;
QPointF parallaxFactor(1.0, 1.0);
const qreal factorX = variantMap[QStringLiteral("parallaxx")].toDouble(&ok);
if (ok)
parallaxFactor.setX(factorX);
const qreal factorY = variantMap[QStringLiteral("parallaxy")].toDouble(&ok);
if (ok)
parallaxFactor.setY(factorY);

layer->setParallaxFactor(parallaxFactor);
}

return layer;
Expand Down
2 changes: 1 addition & 1 deletion src/tiled/abstractobjecttool.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,7 @@ void AbstractObjectTool::mouseMoved(const QPointF &pos,
// Take into account the offset of the current layer
QPointF offsetPos = pos;
if (Layer *layer = currentLayer())
offsetPos -= layer->totalOffset();
offsetPos -= mapScene()->absolutePositionForLayer(*layer);

const QPoint pixelPos = offsetPos.toPoint();

Expand Down
16 changes: 12 additions & 4 deletions src/tiled/abstracttiletool.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -83,8 +83,9 @@ void AbstractTileTool::mouseMoved(const QPointF &pos, Qt::KeyboardModifiers)
// Take into account the offset of the current layer
QPointF offsetPos = pos;
if (Layer *layer = currentLayer()) {
offsetPos -= layer->totalOffset();
mBrushItem->setLayerOffset(layer->totalOffset());
QPointF layerOffset = mapScene()->absolutePositionForLayer(*layer);
offsetPos -= layerOffset;
mBrushItem->setLayerOffset(layerOffset);
}

const MapRenderer *renderer = mapDocument()->renderer();
Expand All @@ -108,7 +109,9 @@ void AbstractTileTool::mouseMoved(const QPointF &pos, Qt::KeyboardModifiers)
void AbstractTileTool::mousePressed(QGraphicsSceneMouseEvent *event)
{
if (event->button() == Qt::RightButton && event->modifiers() & Qt::ControlModifier) {
const QPoint pos = tilePosition();
const QPointF mousePos = event->pos();
const MapRenderer *renderer = mapDocument()->renderer();

QList<Layer*> layers;

const bool append = event->modifiers() & Qt::ShiftModifier;
Expand All @@ -123,7 +126,12 @@ void AbstractTileTool::mousePressed(QGraphicsSceneMouseEvent *event)
if (tileLayer->isHidden())
continue;

if (!tileLayer->cellAt(pos - tileLayer->position()).isEmpty()) {
const QPointF layerOffset = mapScene()->absolutePositionForLayer(*tileLayer);
const QPointF tilePosF = renderer->screenToTileCoords(mousePos - layerOffset);
const QPoint tilePos = QPoint(qFloor(tilePosF.x()),
qFloor(tilePosF.y()));

if (!tileLayer->cellAt(tilePos - tileLayer->position()).isEmpty()) {
if (!layers.contains(tileLayer))
layers.append(tileLayer);
else if (append)
Expand Down
2 changes: 1 addition & 1 deletion src/tiled/abstractworldtool.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -176,7 +176,7 @@ void AbstractWorldTool::mouseMoved(const QPointF &pos,
// Take into account the offset of the current layer
QPointF offsetPos = pos;
if (Layer *layer = currentLayer())
offsetPos -= layer->totalOffset();
offsetPos -= mapScene()->absolutePositionForLayer(*layer);

const QPoint pixelPos = offsetPos.toPoint();
const QPointF tilePosF = mapDocument()->renderer()->screenToTileCoords(offsetPos);
Expand Down
4 changes: 3 additions & 1 deletion src/tiled/changeevents.h
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,9 @@ class LayerChangeEvent : public ChangeEvent
VisibleProperty = 1 << 2,
LockedProperty = 1 << 3,
OffsetProperty = 1 << 4,
TintColorProperty = 1 << 5,
ParallaxFactorProperty = 1 << 5,
TintColorProperty = 1 << 6,
PositionProperties = OffsetProperty | ParallaxFactorProperty,
AllProperties = 0xFF
};

Expand Down
21 changes: 21 additions & 0 deletions src/tiled/changelayer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,27 @@ void SetLayerOffset::setOffset(const QPointF &offset)
}


SetLayerParallaxFactor::SetLayerParallaxFactor(Document *document,
Layer *layer,
const QPointF &parallaxFactor,
QUndoCommand *parent)
: QUndoCommand(parent)
, mDocument(document)
, mLayer(layer)
, mOldParallaxFactor(layer->parallaxFactor())
, mNewParallaxFactor(parallaxFactor)
{
setText(QCoreApplication::translate("Undo Commands",
"Change Layer Parallax Factor"));
}

void SetLayerParallaxFactor::setParallaxFactor(const QPointF &parallaxFactor)
{
mLayer->setParallaxFactor(parallaxFactor);
emit mDocument->changed(LayerChangeEvent(mLayer, LayerChangeEvent::ParallaxFactorProperty));
}


SetTileLayerSize::SetTileLayerSize(Document *document,
TileLayer *tileLayer,
QSize size,
Expand Down
25 changes: 25 additions & 0 deletions src/tiled/changelayer.h
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,31 @@ class SetLayerOffset : public QUndoCommand
QPointF mNewOffset;
};

/**
* Used for changing the layer parallax factor.
*/
class SetLayerParallaxFactor : public QUndoCommand
{
public:
SetLayerParallaxFactor(Document *document,
Layer *layer,
const QPointF &parallaxFactor,
QUndoCommand *parent = nullptr);

void undo() override { setParallaxFactor(mOldParallaxFactor); }
void redo() override { setParallaxFactor(mNewParallaxFactor); }

int id() const override { return Cmd_ChangeLayerOffset; }

private:
void setParallaxFactor(const QPointF &parallaxFactor);

Document *mDocument;
Layer *mLayer;
QPointF mOldParallaxFactor;
QPointF mNewParallaxFactor;
};

/**
* Used for changing the tile layer size.
*
Expand Down
Loading

0 comments on commit 7d6b7e4

Please sign in to comment.