Веб-сайт самохостера Lotigara

summaryrefslogtreecommitdiff
path: root/source/game/StarAnimation.cpp
blob: d8d62dc76550f6463aa66834d75180915d69d65d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
#include "StarAnimation.hpp"
#include "StarJsonExtra.hpp"
#include "StarRandom.hpp"
#include "StarRoot.hpp"
#include "StarAssets.hpp"
#include "StarGameTypes.hpp"
#include "StarLexicalCast.hpp"

namespace Star {

Animation::Animation(Json config, String const& directory) {
  m_directory = directory;
  if (m_directory.empty()) {
    if (config.isType(Json::Type::String))
      m_directory = AssetPath::directory(config.toString());
    else
      m_directory = "/";
  }
  if (config.isNull())
    config = JsonObject();

  config = Root::singleton().assets()->fetchJson(config);

  m_mode = AnimationModeNames.getLeft(config.getString("mode", "endAndDisappear"));
  m_base = config.getString("frames", "");
  // If the base image has no index tag, then assume that the frame is appended
  // to the end.
  m_appendFrame = !m_base.contains("<index>");
  m_frameNumber = config.getInt("frameNumber", 1);
  m_animationCycle = config.getFloat("animationCycle", 1.0);
  m_animationTime = m_animationCycle * config.getFloat("loops", 1.0);
  m_angle = config.getFloat("angle", 0.0f);
  m_offset = jsonToVec2F(config.get("offset", JsonArray{0.0f, 0.0f}));
  m_centered = config.getBool("centered", true);
  m_processing = config.getString("processing", "");
  m_color = config.opt("color").apply(jsonToColor).value(Color::White);
  m_variantOffset = Random::randInt(config.getInt("variants", 1) - 1) * m_frameNumber;

  reset();
}

void Animation::setAngle(float angle) {
  m_angle = angle;
}

void Animation::setProcessing(DirectivesGroup processing) {
  m_processing = std::move(processing);
}

void Animation::setColor(Color color) {
  m_color = color;
}

void Animation::setTag(String tagName, String tagValue) {
  m_tagValues[std::move(tagName)] = std::move(tagValue);
}

void Animation::clearTags() {
  m_tagValues.clear();
}

Drawable Animation::drawable(float pixelSize) const {
  if (m_base.empty() || m_frame < 0)
    return Drawable();

  // Replace <index> with the frame index, if it is not found then add
  // :<index> to the end
  String baseFrame = AssetPath::relativeTo(m_directory, m_base).replaceTags(m_tagValues);
  if (m_appendFrame)
    baseFrame += ":" + toString(m_frame);

  Drawable drawable = Drawable::makeImage(std::move(baseFrame), pixelSize, m_centered, m_offset);
  drawable.imagePart().addDirectivesGroup(m_processing, true);
  drawable.rotate(m_angle);
  drawable.color = m_color;
  return drawable;
}

void Animation::update(float dt) {
  if (m_completed)
    return;

  float time_within_cycle = fmod(m_animationTimer, m_animationCycle);
  float time_per_frame = m_animationCycle / m_frameNumber;
  float frame_number = time_within_cycle / time_per_frame;
  m_frame = m_variantOffset + clamp<int>(frame_number, 0, m_frameNumber - 1);
  m_animationTimer += dt;

  if (m_mode == Animation::LoopForever) {
    // to prevent floating point jitter and seizing after a very long time
    m_animationTimer = fmod(m_animationTimer, m_animationCycle);
  } else if (m_animationTimer >= m_timeToLive) {
    if (m_mode == Animation::EndAndDisappear)
      m_frame = -1;
    m_completed = true;
  }

  m_tagValues["index"] = toString(m_frame);
}

bool Animation::isComplete() const {
  return m_completed;
}

void Animation::reset() {
  m_frame = 0;
  m_animationTimer = 0;
  m_timeToLive = m_animationTime;
  m_completed = false;
  m_tagValues["index"] = "0";
}

EnumMap<Animation::AnimationMode> Animation::AnimationModeNames = {{Animation::AnimationMode::Stop, "Stop"},
    {Animation::AnimationMode::EndAndDisappear, "EndAndDisappear"},
    {Animation::AnimationMode::LoopForever, "LoopForever"}};
}