Implemented weather

This commit is contained in:
Tiberiu Chibici 2016-12-10 17:42:51 +02:00
parent f6a02dc850
commit bb2ddf1374
18 changed files with 340 additions and 23 deletions

View File

@ -2,7 +2,6 @@
<launchConfiguration type="org.eclipse.ui.externaltools.ProgramBuilderLaunchConfigurationType">
<stringAttribute key="org.eclipse.debug.core.ATTR_REFRESH_SCOPE" value="${working_set:&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;&#10;&lt;resources&gt;&#10;&lt;item path=&quot;/Farmlands/build/Debug&quot; type=&quot;2&quot;/&gt;&#10;&lt;item path=&quot;/Farmlands/build/Release&quot; type=&quot;2&quot;/&gt;&#10;&lt;/resources&gt;}"/>
<booleanAttribute key="org.eclipse.debug.ui.ATTR_LAUNCH_IN_BACKGROUND" value="false"/>
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_BUILD_SCOPE" value="${working_set:&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;&#10;&lt;resources&gt;&#10;&lt;item path=&quot;/Farmlands/CMakeLists.txt&quot; type=&quot;1&quot;/&gt;&#10;&lt;/resources&gt;}"/>
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_LOCATION" value="/usr/bin/cmake"/>
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_RUN_BUILD_KINDS" value="full,incremental,"/>
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_TOOL_ARGUMENTS" value="-DCMAKE_BUILD_TYPE=${config_name:Farmlands} ../.."/>

View File

@ -21,7 +21,7 @@
</State>
</Sprite>
<SpriteRenderer />
<Plant needsWater="false" maxDaysWithoutWater="3">
<Plant needsWater="true" maxDaysWithoutWater="3">
<State len="1" />
<State len="1" />
<State len="2" />

View File

@ -7,6 +7,7 @@
<Transform />
<Camera scale="4" mainCamera="true" />
<GameTime />
<Weather />
</GameObject>
<!-- Background object -->

View File

@ -13,8 +13,10 @@
#include <model/Configuration.h>
#include <graphics/RenderContext.h>
#include <resources/ResourceManager.h>
#include <utils/Random.h>
#include <memory>
#include <random>
namespace farmlands {
@ -47,6 +49,9 @@ namespace farmlands {
float deltaTime;
// Misc
utils::Random random;
private:
static GameState s_current;
};

View File

@ -7,9 +7,11 @@ using namespace farmlands;
int main()
{
int ret = 0;
try
{
return controller::FarmlandsGame().run();
ret = controller::FarmlandsGame().run();
}
catch (utils::Exception& ex)
{
@ -22,4 +24,11 @@ int main()
std::cerr << "Panic: Caught unhandled exception!\n";
std::cerr << typeid(ex).name() << " : " << ex.what() << "\n";
}
if (ret != 0)
{
std::cerr << "Panic: Caught non-zero exit status!\n";
}
return ret;
}

View File

@ -35,7 +35,7 @@ MapLayer* MapLayer::clone()
Cell MapLayer::get(size_t row, size_t col) const
{
Assert(row < m_w && col < m_h, "Index out of bounds.");
Assert(row < m_h && col < m_w, "Index out of bounds.");
return m_cells[row * m_w + col];
}

View File

@ -6,7 +6,7 @@
*/
#include <GameState.h>
#include <components/GameTime.h>
#include <components/environment/GameTime.h>
#include <iostream>
@ -16,6 +16,7 @@
namespace farmlands {
namespace components {
namespace environment {
GameTime::~GameTime()
{
@ -51,5 +52,6 @@ void GameTime::onUpdateLogic()
}
}
} /* namespace components */
} /* namespace farmlands */

View File

@ -12,6 +12,7 @@
namespace farmlands {
namespace components {
namespace environment {
/**
* Maintains game time.
@ -27,6 +28,7 @@ namespace components {
virtual void onUpdateLogic() override;
};
}
} /* namespace components */
} /* namespace farmlands */

View File

@ -0,0 +1,122 @@
/*
* Weather.cpp
*
* Created on: Dec 10, 2016
* Author: tibi
*/
#include <GameState.h>
#include <assets/Ground.h>
#include <components/environment/Weather.h>
#include <components/plants/Plant.h>
#include <iostream>
namespace farmlands {
namespace components {
namespace environment {
Weather::Weather()
: today(WeatherType::Sunny),
tomorrow(WeatherType::Sunny),
m_map(nullptr),
m_grid(nullptr)
{
}
Weather::~Weather()
{
}
model::Component* Weather::clone()
{
Weather* clone = new Weather();
clone->today = today;
clone->tomorrow = tomorrow;
return clone;
}
void Weather::dump(unsigned level)
{
for (unsigned i = 0; i < level; i++)
std::cout<<" ";
std::cout << " .Component: Weather \n";
}
void Weather::onInitialize()
{
model::GameObject* root = &GameState::current().scene->root;
// Find background object
auto it = root->findByComponent<Map>();
Assert(it != root->childrenEnd(), "Can't find background game object.");
m_map = (*it)->component<Map>();
auto gridIt = root->findByComponent<basic::Grid>();
Assert(gridIt != root->childrenEnd(), "Can't find grid game object.");
m_grid = (*gridIt)->component<basic::Grid>();
}
void Weather::onUpdateLogic()
{
if (GameState::current().isMidnight)
{
today = tomorrow;
std::cout << "Today the weather is ";
if (today == WeatherType::Sunny)
std::cout << "sunny\n";
if (today == WeatherType::Cloudy)
std::cout << "cloudy\n";
if (today == WeatherType::Rainy)
std::cout << "rainy\n";
// Pick weather for next day
int r = GameState::current().random.getInt((int) WeatherType::_Count);
tomorrow = (WeatherType) r;
// Wet/dry soil tiles
updateSoilTiles();
updatePlants();
}
}
void Weather::updateSoilTiles()
{
bool rain = (today == WeatherType::Rainy);
Cell cellWet = assets::Ground::SoilWet;
Cell cellDry = assets::Ground::SoilDry;
for (size_t row = 0; row < m_map->height; row++)
for (size_t col = 0; col < m_map->width; col++)
{
Cell soil = m_map->layer(1).get(row, col);
if (assets::groundIsSoil(soil))
m_map->layer(1).set(row, col, (rain) ? cellWet : cellDry);
}
}
void Weather::updatePlants()
{
bool rain = (today == WeatherType::Rainy);
if (rain)
{
// Tell plants that they have been given water
for (size_t row = 0; row < m_map->height; row++)
for (size_t col = 0; col < m_map->width; col++)
{
model::GameObject* obj = m_grid->get(col, row);
plants::Plant* plant = (obj != nullptr) ? obj->component<plants::Plant>() : nullptr;
if (plant)
plant->onWatered();
}
}
}
} /* namespace environment */
} /* namespace components */
} /* namespace farmlands */

View File

@ -0,0 +1,53 @@
/*
* Weather.h
*
* Created on: Dec 10, 2016
* Author: tibi
*/
#ifndef COMPONENTS_ENVIRONMENT_WEATHER_H_
#define COMPONENTS_ENVIRONMENT_WEATHER_H_
#include <components/basic/Grid.h>
#include <components/Map.h>
#include <model/Component.h>
namespace farmlands {
namespace components {
namespace environment {
enum class WeatherType
{
Sunny,
Cloudy,
Rainy,
_Count
};
class Weather: public model::Component
{
public:
Weather();
virtual ~Weather();
virtual model::Component* clone() override;
virtual void dump(unsigned level) override;
virtual void onInitialize() override;
virtual void onUpdateLogic() override;
WeatherType today, tomorrow;
private:
void updateSoilTiles();
void updatePlants();
Map* m_map;
basic::Grid* m_grid;
};
} /* namespace environment */
} /* namespace components */
} /* namespace farmlands */
#endif /* COMPONENTS_ENVIRONMENT_WEATHER_H_ */

View File

@ -8,6 +8,7 @@
#include <GameState.h>
#include <assets/Ground.h>
#include <components/items/WateringCan.h>
#include <components/plants/Plant.h>
#include <math/GameMath.h>
#include <utils/Assert.h>
@ -54,8 +55,11 @@ void WateringCan::onInitialize()
// Find background object
auto it = root->findByComponent<Map>();
Assert(it != root->childrenEnd(), "Can't find background game object.");
m_map = (*it)->component<Map>();
auto gridIt = root->findByComponent<basic::Grid>();
Assert(gridIt != root->childrenEnd(), "Can't find grid game object.");
m_grid = (*gridIt)->component<basic::Grid>();
}
void WateringCan::performAction(float x, float y, model::Direction d)
@ -73,23 +77,35 @@ void WateringCan::performAction(float x, float y, model::Direction d)
Cell backCell = m_map->layer(0).get(row, col);
Cell soilCell = m_map->layer(1).get(row, col);
// If there is water, fill can
if (backCell == Ground::Water)
{
amountLeft = capacity;
std::cout << "Filled can: " << amountLeft << "\n";
}
model::GameObject* obj = m_grid->get(col, row);
plants::Plant* plant = (obj != nullptr) ? obj->component<plants::Plant>() : nullptr;
// If there is dry soil, wet it
// Fill can
if (backCell == Ground::Water)
fillCan();
// Wet dry soil
if (groundIsDrySoil(soilCell) && amountLeft > 0)
{
m_map->layer(1)[row][col] = Ground::SoilWet;
--amountLeft;
// Set wet soil
m_map->layer(1)[row][col] = Ground::SoilWet;
// If there is a plant, tell it we watered it
if (plant != nullptr)
plant->onWatered();
std::cout << "Watering can: " << amountLeft << "\n";
}
}
void WateringCan::fillCan()
{
amountLeft = capacity;
std::cout << "Filled can: " << amountLeft << "\n";
}
} /* namespace items */
} /* namespace components */
} /* namespace farmlands */

View File

@ -8,6 +8,7 @@
#ifndef COMPONENTS_ITEMS_WATERINGCAN_H_
#define COMPONENTS_ITEMS_WATERINGCAN_H_
#include <components/basic/Grid.h>
#include <components/items/IPlayerAction.h>
#include <components/Map.h>
#include <model/Component.h>
@ -30,12 +31,15 @@ namespace items {
virtual void performAction(float x, float y, model::Direction d) override;
void fillCan();
public:
uint32_t capacity;
uint32_t amountLeft;
private:
Map* m_map;
basic::Grid* m_grid;
};
} /* namespace items */

View File

@ -65,7 +65,10 @@ void Plant::onUpdateLogic()
// At midnight, the plant grows
if (GameState::current().isMidnight)
{
stateDays++;
// Plant only grows when wet
if (!needsWater || daysWithoutWater == 0)
stateDays++;
daysWithoutWater++;
// Exceeded plant's survival time without water
@ -94,6 +97,7 @@ void Plant::onWatered()
void Plant::die()
{
// TODO: implement plant death
std::cout << "Oh, no. Plant is dead\n";
}
} /* namespace plants */

View File

@ -243,16 +243,46 @@ components::DebugController* parse<components::DebugController> (boost::property
}
template <>
components::GameTime* parse<components::GameTime> (boost::property_tree::ptree& root)
components::environment::GameTime* parse<components::environment::GameTime> (boost::property_tree::ptree& root)
{
// Ensure we are on the correct node (property tree seems to add root of its own)
if (root.front().first == "GameTime")
root = root.front().second;
components::GameTime* gameTime = new components::GameTime();
components::environment::GameTime* gameTime = new components::environment::GameTime();
return gameTime;
}
components::environment::WeatherType parseWeatherType(std::string weatherType)
{
boost::to_lower(weatherType);
components::environment::WeatherType type = components::environment::WeatherType::Sunny;
if (weatherType == "cloudy")
type = components::environment::WeatherType::Cloudy;
if (weatherType == "rainy")
type = components::environment::WeatherType::Rainy;
return type;
}
template <>
components::environment::Weather* parse<components::environment::Weather> (boost::property_tree::ptree& root)
{
// Ensure we are on the correct node (property tree seems to add root of its own)
if (root.front().first == "Weather")
root = root.front().second;
components::environment::Weather* weather = new components::environment::Weather();
std::string today = root.get<std::string>("<xmlattr>.today", "Sunny");
weather->today = parseWeatherType(today);
std::string tomorrow = root.get<std::string>("<xmlattr>.tomorrow", "Sunny");
weather->tomorrow = parseWeatherType(tomorrow);
return weather;
}
template <>
components::items::Axe* parse<components::items::Axe> (boost::property_tree::ptree& root)
{
@ -522,8 +552,12 @@ model::GameObject* parse<model::GameObject> (boost::property_tree::ptree& root)
else if (child.first == "DebugController")
gameObj->addComponent(parse<components::DebugController>(child.second));
// Environment
else if (child.first == "GameTime")
gameObj->addComponent(parse<components::GameTime>(child.second));
gameObj->addComponent(parse<components::environment::GameTime>(child.second));
else if (child.first == "Weather")
gameObj->addComponent(parse<components::environment::Weather>(child.second));
else if (child.first == "Map")
gameObj->addComponent(parse<components::Map>(child.second));

View File

@ -13,7 +13,8 @@
#include <components/basic/Sprite.h>
#include <components/basic/Transform.h>
#include <components/DebugController.h>
#include <components/GameTime.h>
#include <components/environment/GameTime.h>
#include <components/environment/Weather.h>
#include <components/items/Axe.h>
#include <components/items/Giftable.h>
#include <components/items/Hoe.h>
@ -66,7 +67,10 @@ namespace storage {
components::DebugController* parse<components::DebugController> (boost::property_tree::ptree& root);
template <>
components::GameTime* parse<components::GameTime> (boost::property_tree::ptree& root);
components::environment::GameTime* parse<components::environment::GameTime> (boost::property_tree::ptree& root);
template <>
components::environment::Weather* parse<components::environment::Weather> (boost::property_tree::ptree& root);
template <>
components::items::Axe* parse<components::items::Axe> (boost::property_tree::ptree& root);

View File

@ -18,10 +18,10 @@ namespace utils {
void _AssertInternal(bool condition, const std::string& msg, const std::string& lineText, const std::string& file, int line);
void _AssertInternalLog(bool condition, const std::string& msg, const std::string& lineText, const std::string& file, int line);
#ifdef BUILD_DEBUG
#define Assert(condition, message) farmlands::utils::_AssertInternal(condition, message, #condition, __FILE__, __LINE__)
#else
#ifdef NDEBUG
#define Assert(condition, message) farmlands::utils::_AssertInternalLog(condition, message, #condition, __FILE__, __LINE__)
#else
#define Assert(condition, message) farmlands::utils::_AssertInternal(condition, message, #condition, __FILE__, __LINE__)
#endif
} /* namespace utils */

32
src/utils/Random.cpp Normal file
View File

@ -0,0 +1,32 @@
/*
* Random.cpp
*
* Created on: Dec 10, 2016
* Author: tibi
*/
#include <utils/Random.h>
namespace farmlands {
namespace utils {
float Random::getFloat()
{
std::uniform_real_distribution<float> distrib;
return distrib(m_engine);
}
int Random::getInt(int min, int max)
{
std::uniform_int_distribution<int> distrib(min, max);
return distrib(m_engine);
}
int Random::getInt(int max)
{
std::uniform_real_distribution<float> distrib(0, max);
return distrib(m_engine);
}
} /* namespace utils */
} /* namespace farmlands */

30
src/utils/Random.h Normal file
View File

@ -0,0 +1,30 @@
/*
* Random.h
*
* Created on: Dec 10, 2016
* Author: tibi
*/
#ifndef UTILS_RANDOM_H_
#define UTILS_RANDOM_H_
#include <random>
namespace farmlands {
namespace utils {
class Random
{
public:
float getFloat();
int getInt(int min, int max);
int getInt(int max);
private:
std::mt19937 m_engine;
};
} /* namespace utils */
} /* namespace farmlands */
#endif /* UTILS_RANDOM_H_ */