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/formats/xrc.h"
|
||||||
|
|
||||||
|
#include "engines/stark/movement/followpath.h"
|
||||||
#include "engines/stark/movement/turn.h"
|
#include "engines/stark/movement/turn.h"
|
||||||
#include "engines/stark/movement/walk.h"
|
#include "engines/stark/movement/walk.h"
|
||||||
|
|
||||||
@ -44,6 +45,7 @@
|
|||||||
#include "engines/stark/resources/layer.h"
|
#include "engines/stark/resources/layer.h"
|
||||||
#include "engines/stark/resources/light.h"
|
#include "engines/stark/resources/light.h"
|
||||||
#include "engines/stark/resources/location.h"
|
#include "engines/stark/resources/location.h"
|
||||||
|
#include "engines/stark/resources/path.h"
|
||||||
#include "engines/stark/resources/pattable.h"
|
#include "engines/stark/resources/pattable.h"
|
||||||
#include "engines/stark/resources/script.h"
|
#include "engines/stark/resources/script.h"
|
||||||
#include "engines/stark/resources/scroll.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);
|
return opItem3DPlaceOn(_arguments[1].referenceValue, _arguments[2].referenceValue);
|
||||||
case kItem3DWalkTo:
|
case kItem3DWalkTo:
|
||||||
return opItem3DWalkTo(script, _arguments[1].referenceValue, _arguments[2].referenceValue, _arguments[3].intValue);
|
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:
|
case kItemLookAt:
|
||||||
return opItemLookAt(script, _arguments[1].referenceValue, _arguments[2].referenceValue, _arguments[3].intValue, _arguments[4].intValue);
|
return opItemLookAt(script, _arguments[1].referenceValue, _arguments[2].referenceValue, _arguments[3].intValue, _arguments[4].intValue);
|
||||||
case kItemEnable:
|
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) {
|
Command *Command::opItemLookAt(Script *script, const ResourceReference &itemRef, const ResourceReference &objRef, bool suspend, int32 unknown) {
|
||||||
FloorPositionedItem *item = itemRef.resolve<FloorPositionedItem>();
|
FloorPositionedItem *item = itemRef.resolve<FloorPositionedItem>();
|
||||||
Math::Vector3d currentPosition = item->getPosition3D();
|
Math::Vector3d currentPosition = item->getPosition3D();
|
||||||
|
@ -83,9 +83,10 @@ public:
|
|||||||
|
|
||||||
kItem3DPlaceOn = 81,
|
kItem3DPlaceOn = 81,
|
||||||
kItem3DWalkTo = 82,
|
kItem3DWalkTo = 82,
|
||||||
|
kItem3DFollowPath = 83,
|
||||||
kItemLookAt = 84,
|
kItemLookAt = 84,
|
||||||
|
|
||||||
|
kItem2DFollowPath = 86,
|
||||||
kItemEnable = 87,
|
kItemEnable = 87,
|
||||||
kItemSetActivity = 88,
|
kItemSetActivity = 88,
|
||||||
kItemSelectInInventory = 89,
|
kItemSelectInInventory = 89,
|
||||||
@ -205,6 +206,7 @@ protected:
|
|||||||
Command *opInventoryOpen(bool open);
|
Command *opInventoryOpen(bool open);
|
||||||
Command *opItem3DPlaceOn(const ResourceReference &itemRef, const ResourceReference &targetRef);
|
Command *opItem3DPlaceOn(const ResourceReference &itemRef, const ResourceReference &targetRef);
|
||||||
Command *opItem3DWalkTo(Script *script, const ResourceReference &itemRef, const ResourceReference &targetRef, bool suspend);
|
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 *opItemLookAt(Script *script, const ResourceReference &itemRef, const ResourceReference &objRef, bool suspend, int32 unknown);
|
||||||
Command *opItemEnable(const ResourceReference &itemRef, int32 enable);
|
Command *opItemEnable(const ResourceReference &itemRef, int32 enable);
|
||||||
Command *opItemSetActivity(const ResourceReference &itemRef, int32 unknown1, int32 unknown2);
|
Command *opItemSetActivity(const ResourceReference &itemRef, int32 unknown1, int32 unknown2);
|
||||||
|
@ -89,7 +89,7 @@ void Item::onGameLoop() {
|
|||||||
if (_enabled && _movement) {
|
if (_enabled && _movement) {
|
||||||
_movement->onGameLoop();
|
_movement->onGameLoop();
|
||||||
|
|
||||||
if (_movement->hasEnded()) {
|
if (_movement && _movement->hasEnded()) {
|
||||||
setMovement(nullptr);
|
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() {
|
ItemTemplate::~ItemTemplate() {
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -594,7 +598,9 @@ FloorPositionedItem::~FloorPositionedItem() {
|
|||||||
FloorPositionedItem::FloorPositionedItem(Object *parent, byte subType, uint16 index, const Common::String &name) :
|
FloorPositionedItem::FloorPositionedItem(Object *parent, byte subType, uint16 index, const Common::String &name) :
|
||||||
ItemVisual(parent, subType, index, name),
|
ItemVisual(parent, subType, index, name),
|
||||||
_direction3D(0.0),
|
_direction3D(0.0),
|
||||||
_floorFaceIndex(-1) {
|
_floorFaceIndex(-1),
|
||||||
|
_sortKeyOverride(false),
|
||||||
|
_sortKeyOverridenValue(0.0) {
|
||||||
}
|
}
|
||||||
|
|
||||||
Math::Vector3d FloorPositionedItem::getPosition3D() const {
|
Math::Vector3d FloorPositionedItem::getPosition3D() const {
|
||||||
@ -611,6 +617,7 @@ int32 FloorPositionedItem::getFloorFaceIndex() const {
|
|||||||
|
|
||||||
void FloorPositionedItem::setFloorFaceIndex(int32 faceIndex) {
|
void FloorPositionedItem::setFloorFaceIndex(int32 faceIndex) {
|
||||||
_floorFaceIndex = faceIndex;
|
_floorFaceIndex = faceIndex;
|
||||||
|
_sortKeyOverride = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void FloorPositionedItem::placeOnBookmark(Bookmark *target) {
|
void FloorPositionedItem::placeOnBookmark(Bookmark *target) {
|
||||||
@ -654,7 +661,16 @@ void FloorPositionedItem::setDirection(const Math::Angle &direction) {
|
|||||||
_direction3D = direction.getDegrees(0.0);
|
_direction3D = direction.getDegrees(0.0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void FloorPositionedItem::overrideSortKey(float sortKey) {
|
||||||
|
_sortKeyOverride = true;
|
||||||
|
_sortKeyOverridenValue = sortKey;
|
||||||
|
}
|
||||||
|
|
||||||
float FloorPositionedItem::getSortKey() const {
|
float FloorPositionedItem::getSortKey() const {
|
||||||
|
if (_sortKeyOverride) {
|
||||||
|
return _sortKeyOverridenValue;
|
||||||
|
}
|
||||||
|
|
||||||
Floor *floor = StarkGlobal->getCurrent()->getFloor();
|
Floor *floor = StarkGlobal->getCurrent()->getFloor();
|
||||||
|
|
||||||
if (_floorFaceIndex == -1) {
|
if (_floorFaceIndex == -1) {
|
||||||
@ -705,6 +721,10 @@ Gfx::RenderEntry *FloorPositionedImageItem::getRenderEntry(const Common::Point &
|
|||||||
return _renderEntry;
|
return _renderEntry;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void FloorPositionedImageItem::setPosition2D(const Common::Point &position) {
|
||||||
|
_position = position;
|
||||||
|
}
|
||||||
|
|
||||||
void FloorPositionedImageItem::printData() {
|
void FloorPositionedImageItem::printData() {
|
||||||
FloorPositionedItem::printData();
|
FloorPositionedItem::printData();
|
||||||
|
|
||||||
@ -744,6 +764,10 @@ Gfx::RenderEntry *ImageItem::getRenderEntry(const Common::Point &positionOffset)
|
|||||||
return _renderEntry;
|
return _renderEntry;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ImageItem::setPosition2D(const Common::Point &position) {
|
||||||
|
_position = position;
|
||||||
|
}
|
||||||
|
|
||||||
void ImageItem::printData() {
|
void ImageItem::printData() {
|
||||||
ItemVisual::printData();
|
ItemVisual::printData();
|
||||||
|
|
||||||
|
@ -151,6 +151,13 @@ public:
|
|||||||
ItemVisual *getSceneInstance() override;
|
ItemVisual *getSceneInstance() override;
|
||||||
void setAnimHierarchy(AnimHierarchy *animHierarchy) 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 */
|
/** Get the hotspot index for an item relative position */
|
||||||
int getHotspotIndexForPoint(const Common::Point &point);
|
int getHotspotIndexForPoint(const Common::Point &point);
|
||||||
|
|
||||||
@ -345,10 +352,20 @@ public:
|
|||||||
/** Obtain the sort value for the item, used to compute the draw order */
|
/** Obtain the sort value for the item, used to compute the draw order */
|
||||||
float getSortKey() const;
|
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:
|
protected:
|
||||||
int32 _floorFaceIndex;
|
int32 _floorFaceIndex;
|
||||||
Math::Vector3d _position3D;
|
Math::Vector3d _position3D;
|
||||||
float _direction3D;
|
float _direction3D;
|
||||||
|
|
||||||
|
bool _sortKeyOverride;
|
||||||
|
float _sortKeyOverridenValue;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -367,6 +384,9 @@ public:
|
|||||||
// Item API
|
// Item API
|
||||||
Gfx::RenderEntry *getRenderEntry(const Common::Point &positionOffset) override;
|
Gfx::RenderEntry *getRenderEntry(const Common::Point &positionOffset) override;
|
||||||
|
|
||||||
|
// ItemVisual API
|
||||||
|
void setPosition2D(const Common::Point &position) override;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void printData() override;
|
void printData() override;
|
||||||
|
|
||||||
@ -438,6 +458,9 @@ public:
|
|||||||
// Item API
|
// Item API
|
||||||
Gfx::RenderEntry *getRenderEntry(const Common::Point &positionOffset) override;
|
Gfx::RenderEntry *getRenderEntry(const Common::Point &positionOffset) override;
|
||||||
|
|
||||||
|
// ItemVisual API
|
||||||
|
void setPosition2D(const Common::Point &position) override;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void printData() override;
|
void printData() override;
|
||||||
|
|
||||||
|
@ -54,6 +54,46 @@ void Path::printData() {
|
|||||||
debug("field_30: %d", _field_30);
|
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) :
|
Path2D::Path2D(Object *parent, byte subType, uint16 index, const Common::String &name) :
|
||||||
Path(parent, subType, index, 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) {
|
void Path2D::readData(Formats::XRCReadStream *stream) {
|
||||||
Path::readData(stream);
|
Path::readData(stream);
|
||||||
|
|
||||||
uint32 stepCount = stream->readUint32LE();
|
uint32 vertexCount = stream->readUint32LE();
|
||||||
for (uint i = 0; i < stepCount; i++) {
|
for (uint i = 0; i < vertexCount; i++) {
|
||||||
Step step;
|
Vertex vertex;
|
||||||
step.weight = stream->readFloat();
|
vertex.weight = stream->readFloat();
|
||||||
step.position = stream->readPoint();
|
vertex.position = stream->readPoint();
|
||||||
|
|
||||||
_steps.push_back(step);
|
_vertices.push_back(vertex);
|
||||||
}
|
}
|
||||||
|
|
||||||
stream->readUint32LE(); // Unused in the original
|
stream->readUint32LE(); // Unused in the original
|
||||||
@ -76,15 +116,28 @@ void Path2D::readData(Formats::XRCReadStream *stream) {
|
|||||||
void Path2D::printData() {
|
void Path2D::printData() {
|
||||||
Path::printData();
|
Path::printData();
|
||||||
|
|
||||||
for (uint i = 0; i < _steps.size(); i++) {
|
for (uint i = 0; i < _vertices.size(); i++) {
|
||||||
debug("step[%d]: (x %d, y %d), weight: %f", i,
|
debug("vertex[%d]: (x %d, y %d), weight: %f", i,
|
||||||
_steps[i].position.x, _steps[i].position.y, _steps[i].weight);
|
_vertices[i].position.x, _vertices[i].position.y, _vertices[i].weight);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Path2D::~Path2D() {
|
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) :
|
Path3D::Path3D(Object *parent, byte subType, uint16 index, const Common::String &name) :
|
||||||
Path(parent, subType, index, name),
|
Path(parent, subType, index, name),
|
||||||
_sortKey(0) {
|
_sortKey(0) {
|
||||||
@ -93,13 +146,13 @@ Path3D::Path3D(Object *parent, byte subType, uint16 index, const Common::String
|
|||||||
void Path3D::readData(Formats::XRCReadStream *stream) {
|
void Path3D::readData(Formats::XRCReadStream *stream) {
|
||||||
Path::readData(stream);
|
Path::readData(stream);
|
||||||
|
|
||||||
uint32 stepCount = stream->readUint32LE();
|
uint32 vertexCount = stream->readUint32LE();
|
||||||
for (uint i = 0; i < stepCount; i++) {
|
for (uint i = 0; i < vertexCount; i++) {
|
||||||
Step step;
|
Vertex vertex;
|
||||||
step.weight = stream->readFloat();
|
vertex.weight = stream->readFloat();
|
||||||
step.position = stream->readVector3();
|
vertex.position = stream->readVector3();
|
||||||
|
|
||||||
_steps.push_back(step);
|
_vertices.push_back(vertex);
|
||||||
}
|
}
|
||||||
|
|
||||||
_sortKey = stream->readFloat();
|
_sortKey = stream->readFloat();
|
||||||
@ -108,9 +161,9 @@ void Path3D::readData(Formats::XRCReadStream *stream) {
|
|||||||
void Path3D::printData() {
|
void Path3D::printData() {
|
||||||
Path::printData();
|
Path::printData();
|
||||||
|
|
||||||
for (uint i = 0; i < _steps.size(); i++) {
|
for (uint i = 0; i < _vertices.size(); i++) {
|
||||||
debug("step[%d]: (x %f, y %f, z %f), weight: %f", i,
|
debug("vertex[%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);
|
_vertices[i].position.x(), _vertices[i].position.y(), _vertices[i].position.z(), _vertices[i].weight);
|
||||||
}
|
}
|
||||||
|
|
||||||
debug("sortKey: %f", _sortKey);
|
debug("sortKey: %f", _sortKey);
|
||||||
@ -119,5 +172,27 @@ void Path3D::printData() {
|
|||||||
Path3D::~Path3D() {
|
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 Resources
|
||||||
} // End of namespace Stark
|
} // End of namespace Stark
|
||||||
|
@ -37,6 +37,12 @@ class XRCReadStream;
|
|||||||
|
|
||||||
namespace Resources {
|
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 {
|
class Path : public Object {
|
||||||
public:
|
public:
|
||||||
static const Type::ResourceType TYPE = Type::kPath;
|
static const Type::ResourceType TYPE = Type::kPath;
|
||||||
@ -55,18 +61,44 @@ public:
|
|||||||
// Resource API
|
// Resource API
|
||||||
virtual void readData(Formats::XRCReadStream *stream) override;
|
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:
|
protected:
|
||||||
void printData() override;
|
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;
|
uint32 _field_30;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A 2D path for 2D items
|
||||||
|
*/
|
||||||
class Path2D : public Path {
|
class Path2D : public Path {
|
||||||
public:
|
public:
|
||||||
Path2D(Object *parent, byte subType, uint16 index, const Common::String &name);
|
Path2D(Object *parent, byte subType, uint16 index, const Common::String &name);
|
||||||
virtual ~Path2D();
|
virtual ~Path2D();
|
||||||
|
|
||||||
struct Step {
|
struct Vertex {
|
||||||
float weight;
|
float weight;
|
||||||
Common::Point position;
|
Common::Point position;
|
||||||
};
|
};
|
||||||
@ -74,19 +106,29 @@ public:
|
|||||||
// Resource API
|
// Resource API
|
||||||
virtual void readData(Formats::XRCReadStream *stream) override;
|
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:
|
private:
|
||||||
// Resource API
|
// 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 {
|
class Path3D : public Path {
|
||||||
public:
|
public:
|
||||||
Path3D(Object *parent, byte subType, uint16 index, const Common::String &name);
|
Path3D(Object *parent, byte subType, uint16 index, const Common::String &name);
|
||||||
virtual ~Path3D();
|
virtual ~Path3D();
|
||||||
|
|
||||||
struct Step {
|
struct Vertex {
|
||||||
float weight;
|
float weight;
|
||||||
Math::Vector3d position;
|
Math::Vector3d position;
|
||||||
};
|
};
|
||||||
@ -94,11 +136,20 @@ public:
|
|||||||
// Resource API
|
// Resource API
|
||||||
virtual void readData(Formats::XRCReadStream *stream) override;
|
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:
|
private:
|
||||||
// Resource API
|
// Resource API
|
||||||
void printData();
|
void printData() override;
|
||||||
|
|
||||||
Common::Array<Step> _steps;
|
Common::Array<Vertex> _vertices;
|
||||||
float _sortKey;
|
float _sortKey;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user