Siv3D Advent Calendar 2023 の20日目の記事です。
はじめに
#つぶやきProcessing をご存じでしょうか?
#つぶやきProcessing とはProcessingやp5.jsを使い、1ポスト(280字)に収まるプログラムで、どこまでアートを表現できるかに挑戦するものです。とにかく短いコードで様々なものを作ります。
これに倣い、今回はSiv3Dでショートコーディングを行います。
ルール
-
Main.cpp
のみで動作する。 - 執筆時点での最新バージョン(v0.6.13)で動作する。
- #つぶやきSiv3D のハッシュタグも含めて280字以内に収まっている。
1. pong
短縮前
#include <Siv3D.hpp>
void Main() {
const int32 radius = 4, barWidth = 80;
Point pos{ Scene::Center() }, velocity{ 6, 6 };
while (System::Update()) {
const int32 mouseX = Cursor::Pos().x;
if (not InRange(pos.x, 2 * radius, Scene::Width() - 2 * radius)) {
velocity.x *= -1;
}
if (InRange(pos.x, mouseX, mouseX + barWidth) && not InRange(pos.y, 2 * radius, Scene::Height() - 2 * radius)) {
velocity.y *= -1;
}
if (not InRange(pos.y, -radius, Scene::Height() + radius)) {
pos = std::move(Scene::Center());
}
pos += velocity;
Rect{ mouseX, 0, barWidth, radius }.draw();
Rect{ mouseX, Scene::Height() - radius, barWidth, radius }.draw();
Circle{ pos, 2 * radius }.draw();
}
}
短縮後
#include<Siv3D.hpp>
void Main(){
int x=400,y=300,u=6,v=6,z;
while(System::Update()){
z=Cursor::Pos().x;
v=(x<8||x>792)?-v:v;
u=(x>z&&x<z+80&&(y<8||y>592))?-u:u;
if(y<-4||y>604)x=400,y=300;
Rect{z,0,80,4}.draw();
Rect{z,596,80,4}.draw();
Circle{x+=v,y+=u,8}.draw();
}
}
短縮のポイント
- 空白を最低限にする
- 省略できる部分は省略します。
- 変数を1文字にする
-
x
やy
にすると文字数が大幅に減ります。
-
-
int32
やdouble
をint
やauto
にする- 文字数は減ります。万能ではないです。
- 三項演算子に置き換える
- 無理やりぶち込みます。
参考
2. 花畑
短縮前
#include <Siv3D.hpp>
void Main() {
const int32 radius = 96, area = 40;
const Texture t{ U"🥀"_emoji }, u{ U"🌷"_emoji };
while(System::Update()) {
const auto& mouse{ Cursor::Pos() };
Circle{ mouse, radius }.drawFrame(3.0, Palette::Yellow);
for (const auto& p : step({ 21, 16 })) {
const auto& v{ mouse.distanceFrom(area * p) < radius ? t : u };
v.scaled(0.3).drawAt(area * p);
}
}
}
短縮後
#include<Siv3D.hpp>
void Main(){
for(Texture t{U"🥀"_emoji},u{U"🌷"_emoji};System::Update();){
Vec2 m=Cursor::Pos();
Circle{m,96}.drawFrame(3,{255,255,0});
for(auto p:step({21,16})){
(m.distanceFrom(40*p)<96?t:u).scaled(.3).drawAt(40*p);
}
}
}
短縮のポイント
- whileループをforループに置き換える
- 変数の宣言と
System::Update()
を1行にまとめます。
- 変数の宣言と
- 小数の表記を省略する
-
0.1
は.1
、1.0
は1.
にします。
-
-
Color
型を工夫する-
Palette
は便利ですが、今回はRGB値を使用して文字数を節約しています。
-
3. 模様
短縮前
#include <Siv3D.hpp>
void Main() {
while (System::Update()) {
const double t = Scene::Time();
for (const auto& [x, y] : step({ 74, 56 })) {
const Vec2 v{ x, y }, u{ Math::Acos(Math::Sin(y / 5.0 + t)), Math::Acos(Math::Cos(x / 5.0 + t)) };
Circle{ 11.0 * v, 3.0 * (Math::Sin((40 * u).length() / 10.0 + t) + 2.0) }.draw(HSV{ 64, 0.5 });
}
}
}
短縮後
#include<Siv3D.hpp>
void Main(){
for(double t=0;System::Update();t+=0.01){
for(const auto& [x,y]:step({74,56})){
const Vec2 v{x,y},u{Acos(Sin(y/5.0+t)),Acos(Cos(x/5.0+t))};
Circle{11.0*v,3.0*(Sin((40*u).length()/10.0+t)+2.0)}.draw(HSV{64,0.5});
}
}
}
短縮のポイント
もともとのコードが短かったのであまり変えていません。const
や小数点も省略せず書いています。
- 名前空間を省略する
- 今回は
Math::
を省略しています。あまり省略したくはありませんが、これだけで随分変わるので今回はできる限り省略します。
- 今回は
-
Scene::Time()
を自分で定義する- 少し短くなります。
4. 弾幕
マウスカーソルが被弾すると背景がフラッシュします。
短縮前
#include <Siv3D.hpp>
void Main() {
const double radius = 5.0;
double backgroundColor = 0.0;
while (System::Update()) {
Scene::SetBackground(ColorF{ backgroundColor });
backgroundColor = Max(backgroundColor - 0.1, 0.0);
const double t = Scene::Time() / 2.0;
for (const auto i : step(360)) {
const double d = static_cast<double>(i);
const double r = Scene::Size().length() / 2.0 * Math::Sin(d + t);
const Vec2 v{ Math::Cos(d / 4.0), Math::Sin(d / 4.0) };
const Vec2 pos{ (r * v).rotated(d + t / 9.0) + Scene::Center() };
Circle{ pos, radius }.draw();
if (pos.distanceFrom(Cursor::Pos()) < radius) {
backgroundColor = 1;
}
}
}
}
短縮後
#include<Siv3D.hpp>
void Main(){
for(float t=0,b=0,d;System::Update();t+=.01)
for(Rect{0,0,800}.draw(ColorF{b-=.1}),d=360;d--;){
Vec2 c{400,300},v{Cos(d/4),Sin(d/4)},p=(500*Sin(d+t)*v).rotated(d+t/9)+c;
Circle{p,5}.draw();
b=p.distanceFrom(Cursor::Pos())<5?1:b;
}
}
ハッシュタグ含めてギリギリでした...。
短縮のポイント
-
Scene::SetBackground()
をRect
で代用する- 少し減ります。
-
double
をfloat
にする- 1文字しか減りません。
- 代入しながら値を使用する
-
ColorF{b-=.1}
のように、代入と引数の指定を同時に行います。
-
- あらゆるものを無理やりfor文に詰め込む
- パワー
5. ゴースト
短縮前
※今回ははじめから短縮プログラムを書きました。
短縮後
#include<Siv3D.hpp>
void Main(){
Texture t{U"👻"_emoji};
for(float v=0,a,u;System::Update();v+=.5)
for(auto[i,j]:step({8,9})){
Vec2 c{400,300},p{Cos(u=(a=70*i+v)/90+.7*j),Sin(u)*(i%2*2-1)},q=int(a)%560*p;
t.resized(q.length()/5).scaled(Cos(5*u),1).drawAt(q+c);
}
}
短縮のポイント
- 二重ループをまとめる
- Siv3Dの
step()
で二重ループをまとめます。
- Siv3Dの
-
Vec2
などのSiv3D特有のクラスを有効活用する- メソッドがかなり便利なので有効活用します。
6. 機構
短縮前
※今回もはじめから短縮プログラムを書きました。
短縮後
#include<Siv3D.hpp>
#define C(x,y,r) Circle{x,y,r}.draw({0,0,0}).drawFrame(9)
void Main(){
for(float t=0,p=400,q,x,y;System::Update();t+=.03){C(p,125,70);Line{x=70*Cos(t)+p,y=125-70*Sin(t),p,q=y+300}.draw(15);C(x,y,30);RectF{p/2,q,p,p/4}.draw();C(p,q,30);}
}
短縮のポイント
- マクロを使用する
- マクロを使用すると予期しない挙動が起こりやすくなるので注意してください。
終わりに
Siv3Dでショートコーディングを試してみました。名前空間を省略したり型変換を明示しなかったりと、本来のSiv3Dのコーディングスタイルと異なってしまいますが、ほかにも工夫できそうです。
おまけ
#include <Siv3D.hpp>
void Main() {
for (Font f{ 36 }; System::Update();) {
for (auto [i, c] : Indexed(U"Siv3D Advent Calendar 2023")) {
f(c).draw(
i * 30 + 18,
Math::Tan(Scene::Time() - 29_deg * i) * 6 + 300,
HSV{ 14 * i }
);
}
}
}
今年も1年間Siv3Dには大変お世話になりました!ありがとうございました!