Item Drop Improvements

This commit is contained in:
Kae 2023-08-18 13:06:07 +10:00
parent 90267c6105
commit c11d20894b
5 changed files with 73 additions and 13 deletions

View File

@ -0,0 +1,8 @@
{
"directives" : "",
"pickupDistance" : 0.5,
"afterTakenLife" : 2.5,
"overheadTime" : 0.5,
"overheadApproach" : 2000,
"overheadRandomizedDistance" : 0.25
}

Binary file not shown.

View File

@ -7,6 +7,7 @@
#include "StarEntityRendering.hpp"
#include "StarWorld.hpp"
#include "StarDataStreamExtra.hpp"
#include "StarPlayer.hpp"
namespace Star {
@ -179,13 +180,25 @@ RectF ItemDrop::collisionArea() const {
void ItemDrop::update(float dt, uint64_t) {
if (isMaster()) {
if (m_owningEntity.get() != NullEntityId) {
auto owningEntity = world()->entity(m_owningEntity.get());
if (owningEntity) {
if (auto owningEntity = world()->entity(m_owningEntity.get())) {
Vec2F position = m_movementController.position();
Vec2F diff = world()->geometry().diff(owningEntity->position(), position);
bool overhead = m_dropAge.elapsedTime() < m_overheadTime;
Vec2F targetPosition = owningEntity->position();
if (overhead) {
targetPosition += m_overheadOffset;
auto rect = owningEntity->collisionArea();
if (!rect.isNull())
targetPosition[1] += rect.yMax() + 1.5;
else
targetPosition[1] += 1.5f;
}
Vec2F diff = world()->geometry().diff(targetPosition, position);
float magnitude = diff.magnitude();
m_movementController.approachVelocity(diff.normalized() * m_config.getFloat("velocity"), m_config.getFloat("velocityApproach"));
if (magnitude < m_config.getFloat("pickupDistance"))
Vec2F velocity = diff.normalized() * m_velocity * min(1.0f, magnitude);
if (auto playerEntity = as<Player>(owningEntity))
velocity += playerEntity->velocity();
m_movementController.approachVelocity(velocity, overhead ? m_overheadApproach : m_velocityApproach);
if (!overhead && magnitude < m_pickupDistance)
m_mode.set(Mode::Dead);
} else {
@ -199,12 +212,12 @@ void ItemDrop::update(float dt, uint64_t) {
m_movementController.applyParameters(parameters);
} else {
// Rarely, check for other drops near us and combine with them if possible.
if (canTake() && m_mode.get() == Mode::Available && Random::randf() < m_config.getFloat("combineChance")) {
world()->findEntity(RectF::withCenter(position(), Vec2F::filled(m_config.getFloat("combineRadius"))), [&](EntityPtr const& entity) {
if (canTake() && m_mode.get() == Mode::Available && Random::randf() < m_combineChance) {
world()->findEntity(RectF::withCenter(position(), Vec2F::filled(m_combineRadius)), [&](EntityPtr const& entity) {
if (auto closeDrop = as<ItemDrop>(entity)) {
// Make sure not to try to merge with ourselves here.
if (closeDrop.get() != this && closeDrop->canTake()
&& vmag(position() - closeDrop->position()) < m_config.getFloat("combineRadius")) {
&& vmag(position() - closeDrop->position()) < m_combineRadius) {
if (m_item->couldStack(closeDrop->item()) == closeDrop->item()->count()) {
m_item->stackWith(closeDrop->take());
m_dropAge.setElapsedTime(min(m_dropAge.elapsedTime(), closeDrop->m_dropAge.elapsedTime()));
@ -240,10 +253,10 @@ void ItemDrop::update(float dt, uint64_t) {
m_mode.set(Mode::Available);
if (!m_eternal && m_mode.get() == Mode::Available && m_dropAge.elapsedTime() > m_item->timeToLive())
m_mode.set(Mode::Dead);
if (m_mode.get() == Mode::Taken && m_dropAge.elapsedTime() > m_config.getFloat("afterTakenLife"))
if (m_mode.get() == Mode::Taken && m_dropAge.elapsedTime() > m_afterTakenLife)
m_mode.set(Mode::Dead);
if (m_mode.get() <= Mode::Available && m_ageItemsTimer.elapsedTime() > m_config.getDouble("ageItemsEvery", 10)) {
if (m_mode.get() <= Mode::Available && m_ageItemsTimer.elapsedTime() > m_ageItemsEvery) {
Root::singleton().itemDatabase()->ageItem(m_item, m_ageItemsTimer.elapsedTime());
m_itemDescriptor.set(m_item->descriptor());
updateCollisionPoly();
@ -261,9 +274,20 @@ bool ItemDrop::shouldDestroy() const {
}
void ItemDrop::render(RenderCallback* renderCallback) {
for (auto& drawable : m_item->dropDrawables()) {
drawable.translate(position());
renderCallback->addDrawable(move(drawable), RenderLayerItemDrop);
if (!m_drawables) {
m_drawables = m_item->dropDrawables();
if (Directives dropDirectives = m_config.getString("directives", "")) {
for (auto& drawable : *m_drawables) {
if (drawable.isImage())
drawable.imagePart().addDirectives(dropDirectives, true);
}
}
}
EntityRenderLayer renderLayer = m_mode.get() == Mode::Taken ? RenderLayerForegroundTile : RenderLayerItemDrop;
Vec2F dropPosition = position();
for (auto& drawable : *m_drawables) {
drawable.position = dropPosition;
renderCallback->addDrawable(drawable, renderLayer);
}
}
@ -339,6 +363,18 @@ ItemDrop::ItemDrop() {
m_netGroup.addNetElement(&m_movementController);
m_netGroup.addNetElement(&m_itemDescriptor);
m_afterTakenLife = m_config.getFloat("afterTakenLife");
m_overheadTime = m_config.getFloat("overheadTime");
m_pickupDistance = m_config.getFloat("pickupDistance");
m_velocity = m_config.getFloat("velocity");
m_velocityApproach = m_config.getFloat("velocityApproach");
m_overheadApproach = m_config.getFloat("overheadApproach");
m_overheadOffset = Vec2F(m_config.getFloat("overheadRandomizedDistance"), 0).rotate(Constants::pi * 2.0 * Random::randf());
m_combineChance = m_config.getFloat("combineChance");
m_combineRadius = m_config.getFloat("combineRadius");
m_ageItemsEvery = m_config.getDouble("ageItemsEvery", 10);
m_eternal = false;
}

View File

@ -6,6 +6,7 @@
#include "StarItemDescriptor.hpp"
#include "StarGameTimers.hpp"
#include "StarEntity.hpp"
#include "StarDrawable.hpp"
namespace Star {
@ -96,6 +97,17 @@ private:
Json m_config;
ItemPtr m_item;
RectF m_boundBox;
float m_afterTakenLife;
float m_overheadTime;
float m_pickupDistance;
float m_velocity;
float m_velocityApproach;
float m_overheadApproach;
Vec2F m_overheadOffset;
float m_combineChance;
float m_combineRadius;
double m_ageItemsEvery;
NetElementTopGroup m_netGroup;
NetElementEnum<Mode> m_mode;
@ -108,6 +120,8 @@ private:
EpochTimer m_dropAge;
GameTimer m_intangibleTimer;
EpochTimer m_ageItemsTimer;
Maybe<List<Drawable>> m_drawables;
};
}

View File

@ -1150,6 +1150,8 @@ ItemPtr Player::pickupItems(ItemPtr const& items) {
if (items->pickupSound().size()) {
m_effectsAnimator->setSoundPool("pickup", {items->pickupSound()});
float pitch = 1.f - ((float)items->count() / (float)items->maxStack()) * 0.5f;
m_effectsAnimator->setSoundPitchMultiplier("pickup", clamp(pitch * Random::randf(0.9f, 1.1f), 0.f, 2.f));
m_effectsAnimator->playSound("pickup");
}
auto itemDb = Root::singleton().itemDatabase();