mirror of
https://github.com/libretro/scummvm.git
synced 2025-05-13 09:36:21 +00:00
STARK: Add a movement type allowing an item to follow a path
This commit is contained in:
parent
c733a5ab59
commit
b048c4ae86
130
engines/stark/movement/followpath.cpp
Normal file
130
engines/stark/movement/followpath.cpp
Normal file
@ -0,0 +1,130 @@
|
||||
/* ResidualVM - A 3D game interpreter
|
||||
*
|
||||
* ResidualVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the AUTHORS
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "engines/stark/movement/followpath.h"
|
||||
|
||||
#include "engines/stark/services/global.h"
|
||||
#include "engines/stark/services/services.h"
|
||||
|
||||
#include "engines/stark/resources/anim.h"
|
||||
#include "engines/stark/resources/floor.h"
|
||||
#include "engines/stark/resources/item.h"
|
||||
|
||||
namespace Stark {
|
||||
|
||||
FollowPath::FollowPath(Resources::ItemVisual *item) :
|
||||
Movement(item),
|
||||
_path(nullptr),
|
||||
_speed(0.0),
|
||||
_position(0.0),
|
||||
_previouslyEnabled(true) {
|
||||
}
|
||||
|
||||
FollowPath::~FollowPath() {
|
||||
}
|
||||
|
||||
void FollowPath::start() {
|
||||
Movement::start();
|
||||
|
||||
changeItemAnim();
|
||||
|
||||
_previouslyEnabled = _item->isEnabled();
|
||||
_item->setEnabled(true);
|
||||
}
|
||||
|
||||
void FollowPath::stop() {
|
||||
Movement::stop();
|
||||
|
||||
_item->setEnabled(_previouslyEnabled);
|
||||
}
|
||||
|
||||
void FollowPath::onGameLoop() {
|
||||
// Compute the new position on the path
|
||||
_position += _speed * StarkGlobal->getMillisecondsPerGameloop();
|
||||
|
||||
// Find the current path edge, and position on the path edge
|
||||
uint currentEdge = 0;
|
||||
float positionInEdge = _position;
|
||||
for (uint i = 0; i < _path->getEdgeCount(); i++) {
|
||||
float edgeLength = _path->getWeightedEdgeLength(i);
|
||||
if (positionInEdge < edgeLength) {
|
||||
break; // Found the current path edge
|
||||
}
|
||||
|
||||
positionInEdge -= edgeLength;
|
||||
currentEdge++;
|
||||
}
|
||||
|
||||
// Check if we went beyond the path's end
|
||||
if (currentEdge >= _path->getEdgeCount()) {
|
||||
stop();
|
||||
return;
|
||||
}
|
||||
|
||||
// Get the new position for the item
|
||||
Math::Vector3d newPosition = _path->getWeightedPositionInEdge(currentEdge, positionInEdge);
|
||||
|
||||
// Update the item's properties in the scene
|
||||
if (is3D()) {
|
||||
Resources::FloorPositionedItem *item3D = Resources::Object::cast<Resources::FloorPositionedItem>(_item);
|
||||
Resources::Floor *floor = StarkGlobal->getCurrent()->getFloor();
|
||||
|
||||
int32 floorFaceIndex = floor->findFaceContainingPoint(newPosition);
|
||||
if (floorFaceIndex >= 0) {
|
||||
item3D->setFloorFaceIndex(floorFaceIndex);
|
||||
} else {
|
||||
item3D->overrideSortKey(_path->getSortKey());
|
||||
}
|
||||
|
||||
item3D->setPosition3D(newPosition);
|
||||
|
||||
Math::Vector3d direction = _path->getEdgeDirection(currentEdge);
|
||||
item3D->setDirection(computeAngleBetweenVectorsXYPlane(direction, Math::Vector3d(1.0, 0.0, 0.0)));
|
||||
} else {
|
||||
Common::Point position2D = Common::Point(newPosition.x(), newPosition.y());
|
||||
_item->setPosition2D(position2D);
|
||||
}
|
||||
|
||||
changeItemAnim();
|
||||
}
|
||||
|
||||
void FollowPath::changeItemAnim() {
|
||||
if (_ended) {
|
||||
_item->setAnimKind(Resources::Anim::kActorUsageIdle);
|
||||
} else {
|
||||
_item->setAnimKind(Resources::Anim::kActorUsageWalk);
|
||||
}
|
||||
}
|
||||
|
||||
void FollowPath::setPath(Resources::Path *path) {
|
||||
_path = path;
|
||||
}
|
||||
|
||||
void FollowPath::setSpeed(float speed) {
|
||||
_speed = speed;
|
||||
}
|
||||
|
||||
bool FollowPath::is3D() const {
|
||||
return _path->getSubType() == Resources::Path::kPath3D;
|
||||
}
|
||||
|
||||
} // End of namespace Stark
|
65
engines/stark/movement/followpath.h
Normal file
65
engines/stark/movement/followpath.h
Normal file
@ -0,0 +1,65 @@
|
||||
/* ResidualVM - A 3D game interpreter
|
||||
*
|
||||
* ResidualVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the AUTHORS
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef STARK_MOVEMENT_FOLLOW_PATH_H
|
||||
#define STARK_MOVEMENT_FOLLOW_PATH_H
|
||||
|
||||
#include <engines/stark/resources/path.h>
|
||||
#include "engines/stark/movement/movement.h"
|
||||
|
||||
namespace Stark {
|
||||
|
||||
/**
|
||||
* Make an item follow pre-computed path
|
||||
*
|
||||
* Works for 2D and 3D items, with respectively 2D and 3D paths
|
||||
*/
|
||||
class FollowPath : public Movement {
|
||||
public:
|
||||
FollowPath(Resources::ItemVisual *item);
|
||||
virtual ~FollowPath();
|
||||
|
||||
// Movement API
|
||||
void start() override;
|
||||
void onGameLoop() override;
|
||||
void stop() override;
|
||||
|
||||
/** Set the path to follow */
|
||||
void setPath(Stark::Resources::Path *path);
|
||||
|
||||
/** Set the movement speed on the path */
|
||||
void setSpeed(float speed);
|
||||
|
||||
private:
|
||||
void changeItemAnim();
|
||||
bool is3D() const;
|
||||
|
||||
Resources::Path *_path;
|
||||
float _speed;
|
||||
|
||||
float _position;
|
||||
bool _previouslyEnabled;
|
||||
};
|
||||
|
||||
} // End of namespace Stark
|
||||
|
||||
#endif // STARK_MOVEMENT_FOLLOW_PATH_H
|
@ -26,6 +26,7 @@
|
||||
|
||||
#include "engines/stark/formats/xrc.h"
|
||||
|
||||
#include "engines/stark/movement/followpath.h"
|
||||
#include "engines/stark/movement/turn.h"
|
||||
#include "engines/stark/movement/walk.h"
|
||||
|
||||
@ -44,6 +45,7 @@
|
||||
#include "engines/stark/resources/layer.h"
|
||||
#include "engines/stark/resources/light.h"
|
||||
#include "engines/stark/resources/location.h"
|
||||
#include "engines/stark/resources/path.h"
|
||||
#include "engines/stark/resources/pattable.h"
|
||||
#include "engines/stark/resources/script.h"
|
||||
#include "engines/stark/resources/scroll.h"
|
||||
@ -108,6 +110,9 @@ Command *Command::execute(uint32 callMode, Script *script) {
|
||||
return opItem3DPlaceOn(_arguments[1].referenceValue, _arguments[2].referenceValue);
|
||||
case kItem3DWalkTo:
|
||||
return opItem3DWalkTo(script, _arguments[1].referenceValue, _arguments[2].referenceValue, _arguments[3].intValue);
|
||||
case kItem3DFollowPath:
|
||||
case kItem2DFollowPath:
|
||||
return opItemFollowPath(script, _arguments[1].referenceValue, _arguments[2].referenceValue, _arguments[3].intValue, _arguments[4].intValue);
|
||||
case kItemLookAt:
|
||||
return opItemLookAt(script, _arguments[1].referenceValue, _arguments[2].referenceValue, _arguments[3].intValue, _arguments[4].intValue);
|
||||
case kItemEnable:
|
||||
@ -430,6 +435,26 @@ Command *Command::opItem3DWalkTo(Script *script, const ResourceReference &itemRe
|
||||
}
|
||||
}
|
||||
|
||||
Command *Command::opItemFollowPath(Script *script, ResourceReference itemRef, ResourceReference pathRef, uint32 speed, uint32 suspend) {
|
||||
ItemVisual *item = itemRef.resolve<ItemVisual>();
|
||||
Path *path = pathRef.resolve<Path>();
|
||||
|
||||
FollowPath *follow = new FollowPath(item);
|
||||
follow->setPath(path);
|
||||
follow->setSpeed(speed / 100.0);
|
||||
follow->start();
|
||||
|
||||
item->setMovement(follow);
|
||||
|
||||
if (suspend) {
|
||||
script->suspend(item);
|
||||
item->setMovementSuspendedScript(script);
|
||||
return this; // Stay on the same command while suspended
|
||||
} else {
|
||||
return nextCommand();
|
||||
}
|
||||
}
|
||||
|
||||
Command *Command::opItemLookAt(Script *script, const ResourceReference &itemRef, const ResourceReference &objRef, bool suspend, int32 unknown) {
|
||||
FloorPositionedItem *item = itemRef.resolve<FloorPositionedItem>();
|
||||
Math::Vector3d currentPosition = item->getPosition3D();
|
||||
|
@ -83,9 +83,10 @@ public:
|
||||
|
||||
kItem3DPlaceOn = 81,
|
||||
kItem3DWalkTo = 82,
|
||||
|
||||
kItem3DFollowPath = 83,
|
||||
kItemLookAt = 84,
|
||||
|
||||
kItem2DFollowPath = 86,
|
||||
kItemEnable = 87,
|
||||
kItemSetActivity = 88,
|
||||
kItemSelectInInventory = 89,
|
||||
@ -205,6 +206,7 @@ protected:
|
||||
Command *opInventoryOpen(bool open);
|
||||
Command *opItem3DPlaceOn(const ResourceReference &itemRef, const ResourceReference &targetRef);
|
||||
Command *opItem3DWalkTo(Script *script, const ResourceReference &itemRef, const ResourceReference &targetRef, bool suspend);
|
||||
Command *opItemFollowPath(Script *script, ResourceReference itemRef, ResourceReference pathRef, uint32 speed, uint32 suspend);
|
||||
Command *opItemLookAt(Script *script, const ResourceReference &itemRef, const ResourceReference &objRef, bool suspend, int32 unknown);
|
||||
Command *opItemEnable(const ResourceReference &itemRef, int32 enable);
|
||||
Command *opItemSetActivity(const ResourceReference &itemRef, int32 unknown1, int32 unknown2);
|
||||
|
@ -89,7 +89,7 @@ void Item::onGameLoop() {
|
||||
if (_enabled && _movement) {
|
||||
_movement->onGameLoop();
|
||||
|
||||
if (_movement->hasEnded()) {
|
||||
if (_movement && _movement->hasEnded()) {
|
||||
setMovement(nullptr);
|
||||
}
|
||||
}
|
||||
@ -333,6 +333,10 @@ void ItemVisual::resetActionAnim() {
|
||||
}
|
||||
}
|
||||
|
||||
void ItemVisual::setPosition2D(const Common::Point &position) {
|
||||
warning("ItemVisual::setPosition2D is not implemented for this item type: %d (%s)", _subType, _name.c_str());
|
||||
}
|
||||
|
||||
ItemTemplate::~ItemTemplate() {
|
||||
}
|
||||
|
||||
@ -594,7 +598,9 @@ FloorPositionedItem::~FloorPositionedItem() {
|
||||
FloorPositionedItem::FloorPositionedItem(Object *parent, byte subType, uint16 index, const Common::String &name) :
|
||||
ItemVisual(parent, subType, index, name),
|
||||
_direction3D(0.0),
|
||||
_floorFaceIndex(-1) {
|
||||
_floorFaceIndex(-1),
|
||||
_sortKeyOverride(false),
|
||||
_sortKeyOverridenValue(0.0) {
|
||||
}
|
||||
|
||||
Math::Vector3d FloorPositionedItem::getPosition3D() const {
|
||||
@ -611,6 +617,7 @@ int32 FloorPositionedItem::getFloorFaceIndex() const {
|
||||
|
||||
void FloorPositionedItem::setFloorFaceIndex(int32 faceIndex) {
|
||||
_floorFaceIndex = faceIndex;
|
||||
_sortKeyOverride = false;
|
||||
}
|
||||
|
||||
void FloorPositionedItem::placeOnBookmark(Bookmark *target) {
|
||||
@ -654,7 +661,16 @@ void FloorPositionedItem::setDirection(const Math::Angle &direction) {
|
||||
_direction3D = direction.getDegrees(0.0);
|
||||
}
|
||||
|
||||
void FloorPositionedItem::overrideSortKey(float sortKey) {
|
||||
_sortKeyOverride = true;
|
||||
_sortKeyOverridenValue = sortKey;
|
||||
}
|
||||
|
||||
float FloorPositionedItem::getSortKey() const {
|
||||
if (_sortKeyOverride) {
|
||||
return _sortKeyOverridenValue;
|
||||
}
|
||||
|
||||
Floor *floor = StarkGlobal->getCurrent()->getFloor();
|
||||
|
||||
if (_floorFaceIndex == -1) {
|
||||
@ -705,6 +721,10 @@ Gfx::RenderEntry *FloorPositionedImageItem::getRenderEntry(const Common::Point &
|
||||
return _renderEntry;
|
||||
}
|
||||
|
||||
void FloorPositionedImageItem::setPosition2D(const Common::Point &position) {
|
||||
_position = position;
|
||||
}
|
||||
|
||||
void FloorPositionedImageItem::printData() {
|
||||
FloorPositionedItem::printData();
|
||||
|
||||
@ -744,6 +764,10 @@ Gfx::RenderEntry *ImageItem::getRenderEntry(const Common::Point &positionOffset)
|
||||
return _renderEntry;
|
||||
}
|
||||
|
||||
void ImageItem::setPosition2D(const Common::Point &position) {
|
||||
_position = position;
|
||||
}
|
||||
|
||||
void ImageItem::printData() {
|
||||
ItemVisual::printData();
|
||||
|
||||
|
@ -151,6 +151,13 @@ public:
|
||||
ItemVisual *getSceneInstance() override;
|
||||
void setAnimHierarchy(AnimHierarchy *animHierarchy) override;
|
||||
|
||||
/**
|
||||
* Change the item's 2D position.
|
||||
*
|
||||
* Only applies to 2D items
|
||||
*/
|
||||
virtual void setPosition2D(const Common::Point &position);
|
||||
|
||||
/** Get the hotspot index for an item relative position */
|
||||
int getHotspotIndexForPoint(const Common::Point &point);
|
||||
|
||||
@ -345,10 +352,20 @@ public:
|
||||
/** Obtain the sort value for the item, used to compute the draw order */
|
||||
float getSortKey() const;
|
||||
|
||||
/**
|
||||
* Don't rely on the floor face to compute the sort key, use the provided value instead.
|
||||
*
|
||||
* This can be used to handle cases where the item is not over the floor.
|
||||
*/
|
||||
void overrideSortKey(float sortKey);
|
||||
|
||||
protected:
|
||||
int32 _floorFaceIndex;
|
||||
Math::Vector3d _position3D;
|
||||
float _direction3D;
|
||||
|
||||
bool _sortKeyOverride;
|
||||
float _sortKeyOverridenValue;
|
||||
};
|
||||
|
||||
/**
|
||||
@ -367,6 +384,9 @@ public:
|
||||
// Item API
|
||||
Gfx::RenderEntry *getRenderEntry(const Common::Point &positionOffset) override;
|
||||
|
||||
// ItemVisual API
|
||||
void setPosition2D(const Common::Point &position) override;
|
||||
|
||||
protected:
|
||||
void printData() override;
|
||||
|
||||
@ -438,6 +458,9 @@ public:
|
||||
// Item API
|
||||
Gfx::RenderEntry *getRenderEntry(const Common::Point &positionOffset) override;
|
||||
|
||||
// ItemVisual API
|
||||
void setPosition2D(const Common::Point &position) override;
|
||||
|
||||
protected:
|
||||
void printData() override;
|
||||
|
||||
|
@ -54,6 +54,46 @@ void Path::printData() {
|
||||
debug("field_30: %d", _field_30);
|
||||
}
|
||||
|
||||
float Path::getEdgeLength(uint edgeIndex) const {
|
||||
Math::Vector3d edgeStart = getVertexPosition(edgeIndex);
|
||||
Math::Vector3d edgeEnd = getVertexPosition(edgeIndex + 1);
|
||||
|
||||
return edgeStart.getDistanceTo(edgeEnd);
|
||||
}
|
||||
|
||||
float Path::getWeightedEdgeLength(uint edgeIndex) const {
|
||||
float length = getEdgeLength(edgeIndex);
|
||||
float startWeight = getVertexWeight(edgeIndex);
|
||||
float endWeight = getVertexWeight(edgeIndex + 1);
|
||||
|
||||
return 2000.0 * length / (startWeight + endWeight);
|
||||
}
|
||||
|
||||
Math::Vector3d Path::getWeightedPositionInEdge(uint edgeIndex, float positionInEdge) {
|
||||
float edgeLength = getEdgeLength(edgeIndex);
|
||||
float weightedEdgeLength = getWeightedEdgeLength(edgeIndex);
|
||||
|
||||
float startWeight = getVertexWeight(edgeIndex);
|
||||
float endWeight = getVertexWeight(edgeIndex + 1);
|
||||
|
||||
float weightedEdgePosition = ((endWeight - startWeight) / (2 * weightedEdgeLength) * positionInEdge + startWeight) * 0.001
|
||||
* positionInEdge / edgeLength;
|
||||
|
||||
Math::Vector3d edgeStart = getVertexPosition(edgeIndex);
|
||||
Math::Vector3d edgeEnd = getVertexPosition(edgeIndex + 1);
|
||||
|
||||
return edgeEnd * weightedEdgePosition + edgeStart * (1.0 - weightedEdgePosition);
|
||||
}
|
||||
|
||||
float Path::getSortKey() const {
|
||||
return 0;
|
||||
}
|
||||
|
||||
Math::Vector3d Path::getEdgeDirection(uint edgeIndex) const {
|
||||
return Math::Vector3d();
|
||||
}
|
||||
|
||||
|
||||
Path2D::Path2D(Object *parent, byte subType, uint16 index, const Common::String &name) :
|
||||
Path(parent, subType, index, name) {
|
||||
}
|
||||
@ -61,13 +101,13 @@ Path2D::Path2D(Object *parent, byte subType, uint16 index, const Common::String
|
||||
void Path2D::readData(Formats::XRCReadStream *stream) {
|
||||
Path::readData(stream);
|
||||
|
||||
uint32 stepCount = stream->readUint32LE();
|
||||
for (uint i = 0; i < stepCount; i++) {
|
||||
Step step;
|
||||
step.weight = stream->readFloat();
|
||||
step.position = stream->readPoint();
|
||||
uint32 vertexCount = stream->readUint32LE();
|
||||
for (uint i = 0; i < vertexCount; i++) {
|
||||
Vertex vertex;
|
||||
vertex.weight = stream->readFloat();
|
||||
vertex.position = stream->readPoint();
|
||||
|
||||
_steps.push_back(step);
|
||||
_vertices.push_back(vertex);
|
||||
}
|
||||
|
||||
stream->readUint32LE(); // Unused in the original
|
||||
@ -76,15 +116,28 @@ void Path2D::readData(Formats::XRCReadStream *stream) {
|
||||
void Path2D::printData() {
|
||||
Path::printData();
|
||||
|
||||
for (uint i = 0; i < _steps.size(); i++) {
|
||||
debug("step[%d]: (x %d, y %d), weight: %f", i,
|
||||
_steps[i].position.x, _steps[i].position.y, _steps[i].weight);
|
||||
for (uint i = 0; i < _vertices.size(); i++) {
|
||||
debug("vertex[%d]: (x %d, y %d), weight: %f", i,
|
||||
_vertices[i].position.x, _vertices[i].position.y, _vertices[i].weight);
|
||||
}
|
||||
}
|
||||
|
||||
Path2D::~Path2D() {
|
||||
}
|
||||
|
||||
uint Path2D::getEdgeCount() const {
|
||||
return _vertices.size() - 1;
|
||||
}
|
||||
|
||||
Math::Vector3d Path2D::getVertexPosition(uint vertexIndex) const {
|
||||
Common::Point point = _vertices[vertexIndex].position;
|
||||
return Math::Vector3d(point.x, point.y, 0.0);
|
||||
}
|
||||
|
||||
float Path2D::getVertexWeight(uint vertexIndex) const {
|
||||
return _vertices[vertexIndex].weight;
|
||||
}
|
||||
|
||||
Path3D::Path3D(Object *parent, byte subType, uint16 index, const Common::String &name) :
|
||||
Path(parent, subType, index, name),
|
||||
_sortKey(0) {
|
||||
@ -93,13 +146,13 @@ Path3D::Path3D(Object *parent, byte subType, uint16 index, const Common::String
|
||||
void Path3D::readData(Formats::XRCReadStream *stream) {
|
||||
Path::readData(stream);
|
||||
|
||||
uint32 stepCount = stream->readUint32LE();
|
||||
for (uint i = 0; i < stepCount; i++) {
|
||||
Step step;
|
||||
step.weight = stream->readFloat();
|
||||
step.position = stream->readVector3();
|
||||
uint32 vertexCount = stream->readUint32LE();
|
||||
for (uint i = 0; i < vertexCount; i++) {
|
||||
Vertex vertex;
|
||||
vertex.weight = stream->readFloat();
|
||||
vertex.position = stream->readVector3();
|
||||
|
||||
_steps.push_back(step);
|
||||
_vertices.push_back(vertex);
|
||||
}
|
||||
|
||||
_sortKey = stream->readFloat();
|
||||
@ -108,9 +161,9 @@ void Path3D::readData(Formats::XRCReadStream *stream) {
|
||||
void Path3D::printData() {
|
||||
Path::printData();
|
||||
|
||||
for (uint i = 0; i < _steps.size(); i++) {
|
||||
debug("step[%d]: (x %f, y %f, z %f), weight: %f", i,
|
||||
_steps[i].position.x(), _steps[i].position.y(), _steps[i].position.z(), _steps[i].weight);
|
||||
for (uint i = 0; i < _vertices.size(); i++) {
|
||||
debug("vertex[%d]: (x %f, y %f, z %f), weight: %f", i,
|
||||
_vertices[i].position.x(), _vertices[i].position.y(), _vertices[i].position.z(), _vertices[i].weight);
|
||||
}
|
||||
|
||||
debug("sortKey: %f", _sortKey);
|
||||
@ -119,5 +172,27 @@ void Path3D::printData() {
|
||||
Path3D::~Path3D() {
|
||||
}
|
||||
|
||||
uint Path3D::getEdgeCount() const {
|
||||
return _vertices.size() - 1;
|
||||
}
|
||||
|
||||
Math::Vector3d Path3D::getVertexPosition(uint vertexIndex) const {
|
||||
return _vertices[vertexIndex].position;
|
||||
}
|
||||
|
||||
float Path3D::getVertexWeight(uint vertexIndex) const {
|
||||
return _vertices[vertexIndex].weight;
|
||||
}
|
||||
|
||||
float Path3D::getSortKey() const {
|
||||
return _sortKey;
|
||||
}
|
||||
|
||||
Math::Vector3d Path3D::getEdgeDirection(uint edgeIndex) const {
|
||||
Math::Vector3d direction = getVertexPosition(edgeIndex) - getVertexPosition(edgeIndex + 1);
|
||||
direction.normalize();
|
||||
return direction;
|
||||
}
|
||||
|
||||
} // End of namespace Resources
|
||||
} // End of namespace Stark
|
||||
|
@ -37,6 +37,12 @@ class XRCReadStream;
|
||||
|
||||
namespace Resources {
|
||||
|
||||
/**
|
||||
* A path can be followed by an item in a location
|
||||
*
|
||||
* Path are made of a list of vertices. Two consecutive vertices delimit an edge.
|
||||
* Each vertex has a weight. A higher weight means a higher movement speed.
|
||||
*/
|
||||
class Path : public Object {
|
||||
public:
|
||||
static const Type::ResourceType TYPE = Type::kPath;
|
||||
@ -55,18 +61,44 @@ public:
|
||||
// Resource API
|
||||
virtual void readData(Formats::XRCReadStream *stream) override;
|
||||
|
||||
/** Get the edge count in the path */
|
||||
virtual uint getEdgeCount() const = 0;
|
||||
|
||||
/**
|
||||
* Get a unit vector pointing in the direction of an edge
|
||||
*
|
||||
* Only valid for 3D paths
|
||||
*/
|
||||
virtual Math::Vector3d getEdgeDirection(uint edgeIndex) const;
|
||||
|
||||
/** Get the sort key to be used by the item following the path */
|
||||
virtual float getSortKey() const;
|
||||
|
||||
/** Get an edge's length */
|
||||
float getWeightedEdgeLength(uint edgeIndex) const;
|
||||
|
||||
/** Get the scene position from a position in an edge */
|
||||
Math::Vector3d getWeightedPositionInEdge(uint edgeIndex, float positionInEdge);
|
||||
|
||||
protected:
|
||||
void printData() override;
|
||||
float getEdgeLength(uint edgeIndex) const;
|
||||
virtual float getVertexWeight(uint vertexIndex) const = 0;
|
||||
virtual Math::Vector3d getVertexPosition(uint vertexIndex) const = 0;
|
||||
|
||||
uint32 _field_30;
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* A 2D path for 2D items
|
||||
*/
|
||||
class Path2D : public Path {
|
||||
public:
|
||||
Path2D(Object *parent, byte subType, uint16 index, const Common::String &name);
|
||||
virtual ~Path2D();
|
||||
|
||||
struct Step {
|
||||
struct Vertex {
|
||||
float weight;
|
||||
Common::Point position;
|
||||
};
|
||||
@ -74,19 +106,29 @@ public:
|
||||
// Resource API
|
||||
virtual void readData(Formats::XRCReadStream *stream) override;
|
||||
|
||||
// Path API
|
||||
uint getEdgeCount() const override;
|
||||
|
||||
protected:
|
||||
float getVertexWeight(uint vertexIndex) const override;
|
||||
Math::Vector3d getVertexPosition(uint vertexIndex) const override;
|
||||
|
||||
private:
|
||||
// Resource API
|
||||
void printData();
|
||||
void printData() override;
|
||||
|
||||
Common::Array<Step> _steps;
|
||||
Common::Array<Vertex> _vertices;
|
||||
};
|
||||
|
||||
/**
|
||||
* A 3D path for 3D items
|
||||
*/
|
||||
class Path3D : public Path {
|
||||
public:
|
||||
Path3D(Object *parent, byte subType, uint16 index, const Common::String &name);
|
||||
virtual ~Path3D();
|
||||
|
||||
struct Step {
|
||||
struct Vertex {
|
||||
float weight;
|
||||
Math::Vector3d position;
|
||||
};
|
||||
@ -94,11 +136,20 @@ public:
|
||||
// Resource API
|
||||
virtual void readData(Formats::XRCReadStream *stream) override;
|
||||
|
||||
// Path API
|
||||
uint getEdgeCount() const override;
|
||||
float getSortKey() const override;
|
||||
Math::Vector3d getEdgeDirection(uint edgeIndex) const override;
|
||||
|
||||
protected:
|
||||
float getVertexWeight(uint vertexIndex) const override;
|
||||
Math::Vector3d getVertexPosition(uint vertexIndex) const override;
|
||||
|
||||
private:
|
||||
// Resource API
|
||||
void printData();
|
||||
void printData() override;
|
||||
|
||||
Common::Array<Step> _steps;
|
||||
Common::Array<Vertex> _vertices;
|
||||
float _sortKey;
|
||||
};
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user