Skip to content

Instantly share code, notes, and snippets.

@G4rryS1ngh
Created March 3, 2020 10:55
Show Gist options
  • Select an option

  • Save G4rryS1ngh/2c564d66b196c2c72bbf2dadbe7c2811 to your computer and use it in GitHub Desktop.

Select an option

Save G4rryS1ngh/2c564d66b196c2c72bbf2dadbe7c2811 to your computer and use it in GitHub Desktop.
農業ゲームのデモ( ˘ω˘ )
# include <Siv3D.hpp> // OpenSiv3D v0.4.2
RectF GetRectFrom2Pts(Vec2 _p1, Vec2 _p2)
{
Vec2 size(Abs(_p1.x - _p2.x), Abs(_p1.y - _p2.y));
if (_p1.x < _p2.x)
{
if (_p1.y < _p2.y)
return RectF(Arg::topLeft = _p1, size);
else
return RectF(Arg::bottomLeft = _p1, size);
}
else
{
if (_p1.y < _p2.y)
return RectF(Arg::topRight = _p1, size);
else
return RectF(Arg::bottomRight = _p1, size);
}
}
struct Crop
{
String name;
String emoji;
double cost;
Texture texture;
MultiPolygon polygon;
size_t id;
static size_t Num;
Crop(String _emoji, double _cost, String _name)
: name(_name)
, emoji(_emoji)
, cost(_cost)
, texture(Emoji(_emoji), TextureDesc::Mipped)
, polygon(Emoji::CreateImage(_emoji).alphaToPolygonsCentered().simplified(10).scale(0.4 / Emoji::ImageSize.x))
, id(Num++)
{}
};
size_t Crop::Num = 0;
struct MenuIcon
{
String str;
Texture texture;
RoundRect frame;
Optional<Crop> crop;
Font font = Font(30, Typeface::Bold);
MenuIcon(String _str, Texture _texture, RoundRect _frame)
: str(_str), texture(_texture), frame(_frame) {}
MenuIcon(Crop _sakumotsu, RoundRect _frame)
: str(_sakumotsu.name + U"を植える"), texture(_sakumotsu.texture), crop(_sakumotsu), frame(_frame) {}
void draw(bool _isSelected) const
{
frame.drawShadow(Vec2(3, 4), 5).draw(AlphaF(0.3)).drawFrame();
if (_isSelected)
frame.drawShadow(Vec2(0, 0), 10, 3, ColorF(1, 1, 0, 0.5));
texture.resized(frame.h * 0.9).drawAt(frame.center());
if (frame.mouseOver())
font(str).draw(Arg::leftCenter = frame.rect.rightCenter(), Palette::Snow).draw(AlphaF(0.1));
}
bool operator == (const MenuIcon& right) const { return str == right.str; }
};
struct Menu
{
RectF region;
Array<MenuIcon> icons;
MenuIcon mode;
double scroll = 0;
double max_scroll = 0;
Menu(const Array<MenuIcon>& _icons)
: region(0, 0, 90, Scene::Height())
, icons(_icons)
, mode(_icons.front())
, max_scroll(Max(0.0, icons.back().frame.rect.br().y + 20 - Scene::Height()))
{}
void control()
{
scroll = Clamp(scroll + Mouse::Wheel() * 30, 0.0, max_scroll);
Transformer2D t(Mat3x2::Translate(0, -scroll), true);
for (const MenuIcon& icon : icons)
{
if (icon.frame.leftClicked())
mode = icon;
}
}
void draw() const
{
region.draw(AlphaF(0.2));
Transformer2D t(Mat3x2::Translate(0, -scroll), true);
icons.each([&](const MenuIcon& i) { i.draw(mode == i); });
}
};
struct Farmland
{
RectF rect;
Optional<Crop> crop;
double growth = 0;
double amount = 0;
Farmland(RectF _rect) : rect(_rect) {}
bool hasRipen() const { return crop && growth > crop->cost; }
void reset()
{
crop.reset();
growth = 0;
}
void draw() const
{
rect.draw(AlphaF(0.2 + 0.1 * rect.mouseOver() * Periodic::Triangle0_1(1.0s)))
.drawFrame(3.0);
if (crop)
{
const double s = 80;
double growth_rate = growth / crop->cost;
Circle(rect.center(), s / 2).drawArc(0, 2_pi * growth_rate, 10, 0, Palette::Green);
if (growth_rate >= 1.0)
Circle(rect.center(), s / 2).drawShadow(Vec2(0, 0), Periodic::Jump0_1(1s) * 10 + 10, 15, ColorF(1, 1, 0, 0.5));
crop->texture.resized(s * 0.9).drawAt(rect.center());
}
}
};
struct FarmlandsManager
{
Array<Farmland> farmlands;
Optional<Vec2> begin;
Optional<RectF> temp_farmland;
Optional<Farmland> control(MenuIcon _mode)
{
if (_mode.str == U"収穫")
{
for (Farmland& farmland : farmlands)
{
if (farmland.hasRipen() && farmland.rect.leftClicked())
{
Farmland result = farmland;
farmland.reset();
return result;
}
}
}
else if (_mode.str == U"耕す")
{
if (MouseL.down())
{
begin = Cursor::PosF();
}
else if (!MouseL.pressed())
{
if (MouseL.up() && begin)
{
RectF rect = GetRectFrom2Pts(begin.value(), Cursor::PosF());
const double threshold = 50;
if (rect.w >= threshold && rect.h >= threshold)
{
// 他の農地と被っていなければ追加
if (farmlands.none([&rect](const Farmland& f) { return f.rect.intersects(rect); }))
farmlands << Farmland(rect);
}
}
begin.reset();
temp_farmland.reset();
}
if (begin)
temp_farmland = GetRectFrom2Pts(*begin, Cursor::PosF());
}
else if (_mode.str == U"農地を消去")
{
farmlands.remove_if([](const Farmland& f) { return f.rect.leftClicked(); });
}
else
{
for (Farmland& farmland : farmlands)
{
// 作物を植える
if (!farmland.crop && _mode.crop && farmland.rect.leftClicked())
{
farmland.crop = *_mode.crop;
farmland.amount = Random(100, 200);
}
}
}
return Optional<Farmland>();
}
void update()
{
for (Farmland& farmland : farmlands)
{
// 作物の成長
if (farmland.crop)
farmland.growth += Scene::DeltaTime() * 20;
}
}
void draw() const
{
farmlands.each([](const Farmland& f) { f.draw(); });
if (temp_farmland)
temp_farmland->draw(ColorF(.6, .3, .1, .5)).drawFrame(3.0);
}
};
struct Basket
{
P2World world;
P2Body frame;
Texture texture;
Array<P2Body> bodies;
HashTable<P2BodyID, size_t> table;
Basket(const Array<Crop>& _crops)
: texture(Emoji(U"🗑"))
{
const LineString frame_shape = { Vec2(-1.1, -1.2), Vec2(-0.7, 1), Vec2(0.7, 1), Vec2(1.1, -1.2) };
frame = world.createStaticLineString(Vec2(0, 0), frame_shape);
}
void addCrop(Crop _crop)
{
bodies << world.createPolygons(RandomVec2(Circle(0, -2, 0.8)), _crop.polygon);
table.emplace(bodies.back().id(), _crop.id);
}
void update()
{
world.update();
}
void draw(const Array<Crop>& _crops) const
{
Transformer2D t(Mat3x2::Translate(-Vec2(1, 1)).scaled(80).translated(Scene::Size() - Vec2(20, 20)));
texture.resized(3.2).drawAt(0, -0.2, AlphaF(0.5));
frame.drawFrame(5.0, Palette::Skyblue);
for (const P2Body& body : bodies)
{
_crops[table.at(body.id())].texture.resized(0.4 * 1.2).rotated(body.getAngle()).drawAt(body.getPos());
}
}
};
void Main()
{
const Array<Crop> crops =
{
Crop(U"🍅", 120, U"トマト"),
Crop(U"🍆", 150, U"ナス"),
Crop(U"🥔", 140, U"ジャガイモ"),
Crop(U"🥕", 100, U"ニンジン"),
Crop(U"🌽", 90, U"トウモロコシ"),
Crop(U"🥒", 60, U"キュウリ"),
Crop(U"🌶", 130, U"トウガラシ"),
Crop(U"🌿", 110, U"ハーブ"),
Crop(U"🥜", 180, U"ラッカセイ"),
};
Array<MenuIcon> icons;
RoundRect frame(Vec2(20, 20), Vec2(50, 50), 5);
icons << MenuIcon{ U"収穫", Texture(Emoji(U"👋")), frame };
icons << MenuIcon{ U"耕す", Texture(Emoji(U"⛏")), frame.moveBy(0, 60) };
icons << MenuIcon{ U"農地を消去", Texture(Emoji(U"❌")), frame.moveBy(0, 60) };
crops.each([&](const Crop& s) { icons << MenuIcon{ s, frame.moveBy(0, 60) }; });
Menu menu(icons);
FarmlandsManager farms;
Basket basket(crops);
Camera2D camera;
Camera2DParameters key_only;
key_only.wheelScaleFactor = 1.0;
key_only.grabSpeedFactor = 0.0;
while (System::Update())
{
/** 操作 **/
camera.setParameters(menu.region.mouseOver() ? key_only : Camera2DParameters::Default());
camera.update();
if (menu.region.mouseOver())
{
menu.control();
}
else if(Scene::Rect().intersects(Cursor::PosRaw()))
{
auto t = camera.createTransformer();
Optional<Farmland> result = farms.control(menu.mode);
if (result)
basket.addCrop(result->crop.value());
}
/** 更新 **/
farms.update();
basket.update();
/** 描画 **/
{
auto t = camera.createTransformer();
farms.draw();
}
basket.draw(crops);
menu.draw();
if (!menu.region.mouseOver())
{
menu.mode.texture.resized(30).draw(Cursor::Pos(), AlphaF(0.8));
camera.draw(Palette::Orange);
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment