SDL_Rect frameRect(int frame = -1) const { | SDL_Rect frameRect(int frame = -1) const { | ||||
if (frame == -1) frame = frame_; | if (frame == -1) frame = frame_; | ||||
return SDL_Rect{ 0, frame_height_ * frame, surface_->w, frame_height_ }; | |||||
return SDL_Rect{ 0, frameHeight_ * frame, surface_->w, frameHeight_ }; | |||||
} | } | ||||
std::unique_ptr<SDL_Surface, void (*)(SDL_Surface *)> surface_{nullptr, &SDL_FreeSurface}; | std::unique_ptr<SDL_Surface, void (*)(SDL_Surface *)> surface_{nullptr, &SDL_FreeSurface}; | ||||
std::unique_ptr<SDL_Texture, void (*)(SDL_Texture *)> texture_{nullptr, &SDL_DestroyTexture}; | std::unique_ptr<SDL_Texture, void (*)(SDL_Texture *)> texture_{nullptr, &SDL_DestroyTexture}; | ||||
int frame_height_; | |||||
int num_frames_; | |||||
int frameHeight_; | |||||
int numFrames_; | |||||
std::string name_; | std::string name_; | ||||
int frame_ = 0; | int frame_ = 0; | ||||
private: | private: | ||||
float switch_interval_ = 1; | |||||
float switch_timer_ = switch_interval_; | |||||
float switchInterval_ = 1; | |||||
float switchTimer_ = switchInterval_; | |||||
}; | }; | ||||
class ResourceManager { | class ResourceManager { |
class World { | class World { | ||||
public: | public: | ||||
World(Game *game, unsigned long rand_seed); | |||||
World(Game *game, unsigned long randSeed); | |||||
void addMod(ModWrapper &&mod); | void addMod(ModWrapper &&mod); | ||||
void setWorldGen(std::string gen); | void setWorldGen(std::string gen); |
PLACEHOLDER_RED, PLACEHOLDER_GREEN, PLACEHOLDER_BLUE)); | PLACEHOLDER_RED, PLACEHOLDER_GREEN, PLACEHOLDER_BLUE)); | ||||
} | } | ||||
frame_height_ = 32; | |||||
frameHeight_ = 32; | |||||
// Load TOML if it exists | // Load TOML if it exists | ||||
errno = ENOENT; // I don't know if ifstream is guaranteed to set errno | errno = ENOENT; // I don't know if ifstream is guaranteed to set errno | ||||
cpptoml::parser parser(tomlfile); | cpptoml::parser parser(tomlfile); | ||||
try { | try { | ||||
auto toml = parser.parse(); | auto toml = parser.parse(); | ||||
frame_height_ = toml->get_as<int>("height").value_or(frame_height_); | |||||
frameHeight_ = toml->get_as<int>("height").value_or(frameHeight_); | |||||
} catch (cpptoml::parse_exception &exc) { | } catch (cpptoml::parse_exception &exc) { | ||||
warn << "Failed to parse toml file " << assetpath << ".toml: " | warn << "Failed to parse toml file " << assetpath << ".toml: " | ||||
<< exc.what(); | << exc.what(); | ||||
abort(); | abort(); | ||||
} | } | ||||
num_frames_ = surface_->h / frame_height_; | |||||
numFrames_ = surface_->h / frameHeight_; | |||||
name_ = id; | name_ = id; | ||||
} | } | ||||
abort(); | abort(); | ||||
} | } | ||||
frame_height_ = h; | |||||
num_frames_ = 1; | |||||
frameHeight_ = h; | |||||
numFrames_ = 1; | |||||
name_ = name; | name_ = name; | ||||
} | } | ||||
void ImageResource::tick(float dt) { | void ImageResource::tick(float dt) { | ||||
switch_timer_ -= dt; | |||||
if (switch_timer_ <= 0) { | |||||
switch_timer_ += switch_interval_; | |||||
switchTimer_ -= dt; | |||||
if (switchTimer_ <= 0) { | |||||
switchTimer_ += switchInterval_; | |||||
frame_ += 1; | frame_ += 1; | ||||
if (frame_ >= num_frames_) | |||||
if (frame_ >= numFrames_) | |||||
frame_ = 0; | frame_ = 0; | ||||
} | } | ||||
} | } |
} | } | ||||
} | } | ||||
World::World(Game *game, unsigned long rand_seed): | |||||
game_(game), random_(rand_seed), resources_(game->win_) { | |||||
World::World(Game *game, unsigned long randSeed): | |||||
game_(game), random_(randSeed), resources_(game->win_) { | |||||
std::unique_ptr<Tile> invalidTile = Tile::createInvalid(resources_); | std::unique_ptr<Tile> invalidTile = Tile::createInvalid(resources_); | ||||
tilesMap_[invalidTile->name] = 0; | tilesMap_[invalidTile->name] = 0; |
-> std::optional<Entity *> { | -> std::optional<Entity *> { | ||||
// Filter out things which don't have bodies | // Filter out things which don't have bodies | ||||
auto *has_body = dynamic_cast<BodyTrait::HasBody *>(ent.get()); | |||||
if (has_body == nullptr) | |||||
auto *hasBody = dynamic_cast<BodyTrait::HasBody *>(ent.get()); | |||||
if (hasBody == nullptr) | |||||
return std::nullopt; | return std::nullopt; | ||||
// Filter out things which are too far away from 'center' | // Filter out things which are too far away from 'center' | ||||
auto &body = has_body->getBody(); | |||||
auto &body = hasBody->getBody(); | |||||
auto bounds = body.getBounds(); | auto bounds = body.getBounds(); | ||||
Vec2 entcenter = bounds.pos + (bounds.size / 2); | Vec2 entcenter = bounds.pos + (bounds.size / 2); | ||||
auto dist = (entcenter - center).length(); | auto dist = (entcenter - center).length(); |
Swan::ItemStack s2(&item1, 40); | Swan::ItemStack s2(&item1, 40); | ||||
s2 = s1.insert(s2); | s2 = s1.insert(s2); | ||||
expecteq(s1.count(), item1.maxStack_); | |||||
expecteq(s2.count(), 80 - item1.maxStack_); | |||||
expecteq(s1.count(), item1.maxStack); | |||||
expecteq(s2.count(), 80 - item1.maxStack); | |||||
} | } | ||||
test("Insert respects max_stack_") { | |||||
test("Insert respects maxStack") { | |||||
MockItem item1({ .name = "item1", .image = "no", .maxStack = 20 }); | MockItem item1({ .name = "item1", .image = "no", .maxStack = 20 }); | ||||
Swan::ItemStack s1(&item1, 15); | Swan::ItemStack s1(&item1, 15); |
for (int x = 12; x < 20; ++x) { | for (int x = 12; x < 20; ++x) { | ||||
set(x, 26); | set(x, 26); | ||||
} | } | ||||
nc.light_sources = { | |||||
nc.lightSources = { | |||||
{ { 20, 10 }, 20 }, | { { 20, 10 }, 20 }, | ||||
{ { 16, 30 }, 20 }, | { { 16, 30 }, 20 }, | ||||
{ { 5, 27 }, 20 }, | { { 5, 27 }, 20 }, |
while (tickAcc >= 1.0 / TICK_RATE) { | while (tickAcc >= 1.0 / TICK_RATE) { | ||||
ZoneScopedN("game tick"); | ZoneScopedN("game tick"); | ||||
tickAcc -= 1.0 / TICK_RATE; | tickAcc -= 1.0 / TICK_RATE; | ||||
RTClock tick_clock; | |||||
RTClock tickClock; | |||||
game.tick(1.0 / TICK_RATE); | game.tick(1.0 / TICK_RATE); | ||||
} | } | ||||