Created
March 3, 2020 10:55
-
-
Save G4rryS1ngh/2c564d66b196c2c72bbf2dadbe7c2811 to your computer and use it in GitHub Desktop.
農業ゲームのデモ( ˘ω˘ )
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| # 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