Skip to content

Instantly share code, notes, and snippets.

@azaika
Created September 22, 2020 14:02
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save azaika/0166f727a527c0923a27eebf37b465b1 to your computer and use it in GitHub Desktop.
Save azaika/0166f727a527c0923a27eebf37b465b1 to your computer and use it in GitHub Desktop.
#include <Siv3D.hpp>
void Main() {
Graphics::SetTargetFrameRateHz(60);
Window::SetTitle(U"五月祭 TSGLIVE 5! day-1 ライブゲームプログラミング");
Scene::SetBackground(Palette::Lightblue);
Window::Resize({ 500, 800 });
constexpr double timeDelta = 1 / 60.0;
constexpr double mag = 1 / 20.0;
Camera2D camera(Vec2::Zero(), 1/mag, Camera2DParameters::NoControl());
P2World world(9.8);
P2Body ceiling = world.createStaticRect(Vec2{ 0.0, 10.0 }, SizeF{ 25, 1.5 });
Array<P2Body> wall = {
world.createStaticRect(
Vec2{-(Window::ClientWidth() - 1.5) / 2 * mag, 0.0 },
SizeF{ 1.5, 100 }
),
world.createStaticRect(
Vec2{ (Window::ClientWidth() - 1.5) / 2.0 * mag, 0.0 },
SizeF{ 1.5, 100 }
)
};
const Polygon arrow({
{ 0.0, 1.0 },
{ 0.3, 0.7 },
{ 0.1, 0.8 },
{ 0.0, 0.0 },
{-0.1, 0.8 },
{-0.3, 0.7 },
});
double outer = 0.75;
Array<P2Body> playerBodies;
for (auto i : step(8))
playerBodies << world.createCircle(
Circular(outer / Sin(Math::Pi / 8), i * Math::TwoPi / 8),
outer
);
Array<P2PivotJoint> playerPivots;
auto resetPivots = [&](Vec2 center) {
for (auto i : step(playerBodies.size()))
playerPivots << world.createPivotJoint(
playerBodies[i],
playerBodies[(i + 1) % playerBodies.size()],
center + Circular(
outer / Tan(Math::Pi / playerBodies.size()),
(i + 0.5) * Math::TwoPi / playerBodies.size()
)
).setLimits(-40.0_deg, 40.0_deg).setLimitEnabled(true);
};
resetPivots(Vec2::Zero());
Optional<Vec2> grabOrigin;
Font scoreFont(60);
Font highScoreFont(30);
double highScore = 0.0;
Optional<double> hitInterval = none;
Array<P2Body> objects;
std::unordered_set<int> objectIds;
bool isGameover = false;
while (System::Update()) {
Cursor::RequestStyle(CursorStyle::Hand);
camera.update();
const Vec2 playerCenter = playerBodies.reduce(
[](auto&& acc, auto&& body) {
return acc + body.getPos();
}, Vec2::Zero()
) / static_cast<double>(playerBodies.size());
if (!hitInterval) {
for (auto&& [pair, col] : world.getCollisions()) {
if (objectIds.contains(pair.a) || objectIds.contains(pair.b)) {
playerPivots.clear();
if (playerBodies.size() <= 3) {
for (auto&& [i, b] : IndexedRef(playerBodies))
b.applyLinearImpulse(Circular(5.0, Random(Math::TwoPi)));
isGameover = true;
break;
}
playerBodies.pop_back();
for (auto&& [i, b] : IndexedRef(playerBodies))
b.setPos(playerCenter + Circular(outer / Sin(Math::Pi / playerBodies.size()), i * Math::TwoPi / playerBodies.size()));
resetPivots(playerCenter);
hitInterval = 0.0;
break;
}
}
}
else {
*hitInterval += 1.0;
if (*hitInterval >= 200)
hitInterval = none;
}
const Vec2 rawCursor = Cursor::PosRaw();
const double gazeY = Min(0.0, playerCenter.y);
if (!isGameover) {
camera.setTargetCenter({ 0.0, gazeY });
wall[0].setPos({ -11.75, gazeY });
wall[1].setPos({ 11.75, gazeY });
if (MouseL.down())
grabOrigin = rawCursor;
if (grabOrigin && MouseL.up()) {
for (auto&& body : playerBodies)
body.applyLinearImpulse((*grabOrigin - rawCursor) / 5.0);
grabOrigin = none;
}
highScore = Max(highScore, -gazeY);
}
constexpr double interval = 10.0;
const Quad tekiQuad({ 1.5, 0.0 }, { 0.0, 1.5 }, { -1.5, 0.0 }, { 0.0, -1.5 });
while (highScore + 5 * interval >= static_cast<double>(objects.size()) * interval) {
objects << world.createStaticQuad(
{
Random(-9.0, 9.0),
-static_cast<double>(objects.size() + 1) * interval
},
tekiQuad
);
objectIds.insert(objects.back().id());
}
world.update();
// 描画
{
const auto transformer = camera.createTransformer();
ceiling.draw();
wall.each([](auto&& w) { w.draw(); });
objects.each([](auto&& o) { o.draw(); });
playerBodies.each([&](auto&& b) { b.draw(hitInterval ? Palette::Blue.lerp(Palette::Red, *hitInterval / 250) : Palette::Red); });
}
if (isGameover) {
Rect(Window::ClientSize()).draw(ColorF(Palette::Black, 0.5));
scoreFont(U"ハイスコア").drawAt(Window::ClientCenter().moveBy(0, -30));
scoreFont(U"{:.1f}m"_fmt(highScore)).drawAt(Window::ClientCenter().moveBy(0, 30));
continue;
}
if (grabOrigin && MouseL.pressed()) {
Vec2 v = rawCursor - *grabOrigin;
auto _ = Transformer2D(
Mat3x2::Rotate(-v.getAngle({ 0.0, -1.0 }))
* Mat3x2::Scale(v.length())
* Mat3x2::Translate(*grabOrigin)
);
arrow.draw();
}
scoreFont(U"{:.1f}m"_fmt(Max(0.0, -gazeY))).drawAt({ Window::ClientWidth() / 2, 50 }, Palette::Black);
highScoreFont(U"ハイスコア: {:.1f}m"_fmt(highScore)).drawAt({ Window::ClientWidth() / 2, 100 }, Palette::Black);
}
playerPivots.clear();
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment