Skip to content

Instantly share code, notes, and snippets.

@chobby
Last active April 23, 2016 12:16
Show Gist options
  • Save chobby/0f51f3580db5b11af0904c64430b4cb7 to your computer and use it in GitHub Desktop.
Save chobby/0f51f3580db5b11af0904c64430b4cb7 to your computer and use it in GitHub Desktop.
99 line? STG

SIMPLE STG

第 6 回 | テーマ「99 行でゲームを作る」 参加作品

作者

はむくん

遊び方

  • Zキーで弾を発射
  • 十字キーで移動
# include <Siv3D.hpp>
struct Object{
Vec2 pos, vel;
double value;
int num, hp, type;
bool isDestroyed;
};
void Main(){
Graphics::SetBackground(Palette::Black);
const Font font(30);
Stopwatch stopWatch(true);
const String stageData = L"003333001313001111001212002222004000000005";
std::array<Array<Object>,6> data;
Window::Resize(Size(480, 640));
const Vec2 windowSize = Window::Size();
Vec2 player{ windowSize.x / 2.0, windowSize.y * 0.9 };
size_t currentStageIndex, remainingLives, currentScore, sceneIndex = 0;
const Array<Color> colors{ ColorF(0.5), ColorF(0.7), Palette::Skyblue, Palette::Blue, Palette::Red, Palette::White};
const auto init = [&](){
stopWatch.restart();
remainingLives = 3;
currentStageIndex = currentScore = 0;
for (auto& objects : data)
objects.clear();
sceneIndex = 1;
};
const auto drawBullets = [&](const Array<Object>& objects, double radius){
for (auto& object : objects){
Circle(object.pos, radius).draw(colors[object.num * 2]);
Circle(object.pos, radius * 0.7).draw(colors[object.num * 2 + 1]);
}
};
const auto drawEnemies = [&](const Array<Object>& objects){
for (auto& object : objects)
Circle(object.pos, 20.0).drawFrame(3.0, 0.0, Palette::Red);
};
const auto drawEffect = [&](const Array<Object>& objects){
for (auto& object : objects)
RectF(100.0).setCenter(object.pos).draw(HSV(90.0, 0.5, Exp(- object.num * 0.1)).toColorF(Exp(-object.num * 0.1)));
};
const auto shoot = [&](Object& object, size_t bulletNum, const Vec2& direction, double range, int shootInterval, int longPeriod, int shortPeriod, double speed, double value, int num) {
if (object.num % longPeriod <= shortPeriod && object.num % shootInterval == 0)
for (size_t i = 0; i < bulletNum; ++i)
data[0].push_back(Object{ object.pos, direction.rotated(-range + 2.0 * range / static_cast<double>(bulletNum) / 2.0 + 2.0 * range / static_cast<double>(bulletNum) * i) * speed, value, num, 5, 0, false });
};
const auto updateEnemy = [&](Object& object) {
++object.num;
shoot(object, 1, (player - object.pos).normalized(), Pi, 5, 60, 30, 5.0, 0.0, 2);
shoot(object, (object.type != 1) ? 5 : 21, Vec2::Down.rotated((Pi / 4.0) * Sin(object.num * 0.1)), (object.type != 1) ? Pi / 4.0 : Pi, (object.type != 1) ? 20 : 5, 120, 60, 5.0, 0.0, 1);
};
const auto drawBackground = [&](const Array<Object>& objects){
for (auto& object : objects)
RectF(object.vel.length() *100.0).setCenter((object.pos - Window::Center()) * 1.2 + Window::Center() - player * (0.1)).draw(HSV(200, 0.5, 0.1 * Min(object.vel.length() / 1.0, 1.0)));
};
std::array<std::function<void(const Array<Object>&)>, 6> drawFunctions{ [&](const Array<Object>& objects) { drawBullets(objects, 8.0); }, drawEnemies, [&](const Array<Object>& objects) { drawBullets(objects, 15.0); }, drawEffect, [&](const Array<Object>& objects) {}, drawBackground };
std::array<std::function<void(Object&)>, 6> updateFunctions{ [](Object&) {} , updateEnemy, [](Object&) {},[&](Object& object) {object.isDestroyed = (60 < ++object.num);}, [](Object&) {}, [](Object&) {} };
Array<std::function<void()>> enemyFactories{ [&]() {data[1].push_back(Object{ Vec2(Random(0.0, windowSize.y), 0), Vec2::Down.rotated(Random(-Pi / 8.0, Pi / 8.0)) * Random(5.0, 20.0), 5.0, Random(0, 60), 5,0, false}); }, [&]() {data[1].push_back(Object{ Vec2(Random(0.0, windowSize.x), 0), Vec2::Down.rotated(Random(-Pi / 8.0, Pi / 8.0)) * 1.0, 0.0, Random(0, 60), 5,0, false}); }, [&]() {data[1].push_back(Object{ Vec2(windowSize.x * 0.5, 0), Vec2::Down * 10.0, 5.0, 0, 500,1, false }); } };
const auto generateEnemies = [&](int enemyFactoriesIndex, int num = 0){
for (int i = 0; i < num; ++i)
enemyFactories[enemyFactoriesIndex]();
};
Array<std::function<void()>> enemyAppearancePattern{ []() {} , [&]() {generateEnemies(0, Random(1, 5)); }, [&]() {generateEnemies(0,Random(5,15)); },[&]() {generateEnemies(1,3); },[&]() {generateEnemies(2,1); },[&]() {sceneIndex = 3; } };
const auto mainScene = [&](){
if (stopWatch.elapsed().count() / 3000 != currentStageIndex) {
currentStageIndex = stopWatch.elapsed().count() / 3000;
enemyAppearancePattern[Parse<int>(Format(stageData[currentStageIndex]))]();
}
Vec2 dir(Vec2(Input::KeyRight.pressed - Input::KeyLeft.pressed, Input::KeyDown.pressed - Input::KeyUp.pressed));
player += (!dir.isZero()) ? dir.setLength(Input::KeyZ.pressed ? 4.0 : 6.0) : Vec2::Zero;
player = Vec2(Clamp(player.x, 0.0, windowSize.x), Clamp(player.y, 0.0, windowSize.y));
for (size_t i = 0; i < (Input::KeyZ.pressed) * 3; ++i)
data[2].push_back(Object{ player, (Vec2::Up * 10.0 + Vec2::Left + Vec2::Right * i).normalized() * 30.0, 0.0, 0, 5,0, false });
if (System::FrameCount() % 10 == 0)
data[5].push_back(Object{ Vec2(Random(0.0, windowSize.x), 0.0), Vec2::Down * Random(0.0, 1.0), 0.0, 0, 5,0, false });
for (size_t i = 0; i < data.size(); ++i)
for (size_t j = 0; j < data[i].size(); ++j) {
data[i][j].vel += -data[i][j].vel * data[i][j].value / 60.0;
data[i][j].pos += data[i][j].vel;
updateFunctions[i](data[i][j]);
data[i][j].isDestroyed |= !Window::ClientRect().intersects(data[i][j].pos);
}
for (auto& bullet : data[2])
for (auto& enemy : data[1])
if ((enemy.pos - bullet.pos).length() < 20) {
bullet.isDestroyed = true;
if (--enemy.hp <= 0) {
enemy.isDestroyed = true;
currentScore += 100;
for (int i = 0; i < 20; ++i)
data[3].push_back(Object{ enemy.pos, RandomVec2(Circle(1.0)) * 30.0 + Vec2::Up * 10.0, 10.0, 0, 5,0, false });
}
}
for (auto& enemyBullet : data[0])
if ((enemyBullet.pos - player).length() < 5.0) {
for (int i = 0; i < 100; ++i)
data[3].push_back(Object{ player, RandomVec2(Circle(1.0)) * 50.0 + Vec2::Up * 10.0, 5.0, 0, 5,0, false });
player = Vec2(windowSize.x / 2.0, windowSize.y * 0.9);
for (auto& bullet : data[0])
bullet.isDestroyed = true;
sceneIndex = (--remainingLives <= 0) ? 2 : 1;
}
for (auto& objects : data)
Erase_if(objects, [&](const Object& object) {return object.isDestroyed; });
for (size_t i = 0; i < data.size(); ++i) {
const int j = data.size() - i - 1;
drawFunctions[j](data[j]);
}
Circle(player, 10.0).draw();
font(L"SCORE: ",currentScore, L" LIFE: ", remainingLives).draw();
};
const auto simpleScene = [&](const String& string, size_t currentScene, size_t nextScene){
font(string).drawCenter(windowSize / 2.0);
sceneIndex = (Input::AnyKeyClicked()) ? nextScene : currentScene;
};
Array<std::function<void()>> scenes{ [&]() {simpleScene(L"SIMPLE STG\n\nZ KEY: SHOOT\nARROW: MOVE", 0, 4); } ,mainScene,[&]() {simpleScene(Format(L"GAME OVER\nSCORE: ", currentScore), 2, 4); },[&]() {simpleScene(Format(L"GAME CLEAR!\nSCORE: ", currentScore), 3, 4); }, init };
while (System::Update())
scenes[sceneIndex]();
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment