ショッピングモールとかを歩いていると「niko and …」をよく見る
もしあなたがC++erなら、すぐに気が付いたかもしれない。
あ、これC++のコードだって
int main() { auto f = [](auto... niko) constexpr { return (niko and ...); }; static_assert(f(true, true, true)); }
まとめ
fold expression はいいぞ
ショッピングモールとかを歩いていると「niko and …」をよく見る
もしあなたがC++erなら、すぐに気が付いたかもしれない。
あ、これC++のコードだって
int main() { auto f = [](auto... niko) constexpr { return (niko and ...); }; static_assert(f(true, true, true)); }
fold expression はいいぞ
ゲームは1日1時間ってことば聞いたことありますか?
僕は何度かあります。
これ一般的には最大1時間って意味で使われてると思ってるんですけど
アウトプットばっかしててインプットの時間がちゃんと確保できてないという事を少し気になっていたので
むしろ 最低1時間 はやったほうがいいと考えて
ゲームは1日1時間するようにしました。(最低なので2,3時間やってもOK)
※強制感もちすぎるのも辛いので、まぁ無理だった日は、次の日2時間やればOKみたいなノリで縛られすぎないルールにしました。
※音ゲーは既に遊ぶ習慣ができているので、この時間に含めないことにしました。
もともと好きなゲームが出たときは勝手にやるんですけど(カービィとか)、
RPGみたいな重い腰をあげないと進まないゲームを起動する気力が落ちがちなので、
このあたりを遊ぶ時間を意識的に確保しようという狙いもありました。
今年の4月から始めたのですが以下のゲームを遊べました。
現在プレイ中
今後の予定スタック
特にゼノブレイドシリーズは興味はありつつも手が出せてなかった作品だったのですが めちゃくちゃハマった
ストーリーが大好きでした。
今後のシリーズにも期待したいですね
(他の過去のゼノシリーズまで遡って遊ぶ気力は出ず)
↑こういうのをやってみてた 方針的には以下のようなことをしていた
ちなみに小難しいことはしておらず
— マホウ@アクションゲーム作る (@tyanmahou) 2022年7月15日
シンプルな実装でやってみてた。
①反転した状態のテクスチャをあらかじめ作っておく
②投影するマスクテクスチャのようなものを用意する
③シェーダーでがっちゃんこする
おわり pic.twitter.com/jBScjmhO1J
ソースコードが欲しい人もいると思うが ちょっと汚いので割愛
2D 横スクロール視点の場合は、作りも変わると思う
ポケモンのルビサファくらいのグラフィック表現って今に思うと、いろいろすごいな
完全に2Dドット絵なんだが、なんか影とか反射とか
どうなってんだろう?
随時更新するかも
float screen(float dest, float src) { return 1 - (1 - dest) * (1 - src); } float4 screen(float4 dest, float4 src) { float4 color; color.r = screen(dest.r, src.r); color.g = screen(dest.g, src.g); color.b = screen(dest.b, src.b); color.a = 1.0; return color; }
float overlay(float dest, float src) { return dest < 0.5 ? 2.0 * dest * src : 1.0 - 2.0 * (1 - dest) * (1 - src); } float4 overlay(float4 dest, float4 src) { float4 color; color.r = overlay(dest.r, src.r); color.g = overlay(dest.g, src.g); color.b = overlay(dest.b, src.b); color.a = 1.0; return color; }
float softlight(float dest, float src) { return src < 0.5 ? 2.0 * dest * src + dest * dest * (1.0 - 2.0 * src) : 2.0 * dest * (1 - src) + sqrt(dest) * (2 * src - 1.0); } float4 softlight(float4 dest, float4 src) { float4 color; color.r = softlight(dest.r, src.r); color.g = softlight(dest.g, src.g); color.b = softlight(dest.b, src.b); color.a = 1.0; return color; }
or
float softlight(float dest, float src) { return src < 0.5 ? pow(dest, 2.0 * (1.0- src)) :pow(dest, 1.0 / (2.0 * src)); } float4 softlight(float4 dest, float4 src) { float4 color; color.r = softlight(dest.r, src.r); color.g = softlight(dest.g, src.g); color.b = softlight(dest.b, src.b); color.a = 1.0; return color; }
float hardLight(float dest, float src) { return src < 0.5 ? dest * src * 2.0: 1 - 2 * (1 - dest) * (1 - src); } float4 hardLight(float4 dest, float4 src) { float4 color; color.r = hardLight(dest.r, src.r); color.g = hardLight(dest.g, src.g); color.b = hardLight(dest.b, src.b); color.a = 1.0; return color; }
float colorBurn(float dest, float src) { return src <= 0 ? 0 : 1 - (1 - dest) / src; } float4 colorBurn(float4 dest, float4 src) { float4 color; color.r = colorBurn(dest.r, src.r); color.g = colorBurn(dest.g, src.g); color.b = colorBurn(dest.b, src.b); color.a = 1; return color; }
float colorDodge(float dest, float src) { return src >= 1 ? 1 : dest / (1 - src); } float4 colorDodge(float4 dest, float4 src) { float4 color; color.r = colorDodge(dest.r, src.r); color.g = colorDodge(dest.g, src.g); color.b = colorDodge(dest.b, src.b); color.a = 1; return color; }
float vividLight(float dest, float src) { return src < 0.5 ? colorBurn(dest, 2 * src) : colorDodge(dest, 2 * (src - 0.5)); } float4 vividLight(float4 dest, float4 src) { float4 color; color.r = vividLight(dest.r, src.r); color.g = vividLight(dest.g, src.g); color.b = vividLight(dest.b, src.b); color.a = 1.0; return color; }
Python3 & OpenCV で画像処理を学ぶ[5] 〜 AfterEffects/Photoshopにある描画モードを実装する - Optie研
コードベースのマイグレーションみたいなものを作りました。
以下に
がありますが、これのprefixの数字をidとして、カレントバージョンから最新バージョンまで全部実行する仕組みです
1_Test.cpp
#include"Migration.hpp" #include <iostream> namespace { MIGRATION(Test) { void up() const override { std::cout << "Up Test" << std::endl; } void down() const override { std::cout << "Down Test" << std::endl; } }_; }
2_Hoge.cpp
#include"Migration.hpp" #include <iostream> namespace { MIGRATION(Hoge) { void up() const override { std::cout << "Up Hoge" << std::endl; } void down() const override { std::cout << "Down Hoge" << std::endl; } }_; }
呼び出し
main.cpp
int main() { using Migration::MigrationHundler; int current = 0; std::cin >> current; std::cout << "Latest: " << current << std::endl; std::cout << "-- Migration Up --" << std::endl; current = MigrationHundler::Up(current); std::cout << "Latest: " << current << std::endl; std::cout << "-- Migration Down --" << std::endl; current = MigrationHundler::Down(current); std::cout << "Latest: " << current << std::endl; std::cout << "-- Migration Down --" << std::endl; current = MigrationHundler::Down(current); std::cout << "Latest: " << current << std::endl; }
出力
Latest: -1 -- Migration Up -- Up Test Up Hoge Latest: 2 -- Migration Down -- Down Hoge Latest: 1 -- Migration Down -- Down Test Latest: -1
Migration.hpp
#pragma once #include <vector> #include <algorithm> #include <unordered_map> #include <optional> namespace Migration { struct IMigration { public: virtual ~IMigration() = default; virtual void up() const = 0; virtual void down() const = 0; }; template<int Id> struct Migration; class MigrationHundler { public: template<int Id> static void Regist(IMigration* migration) { m_migrations[Id] = migration; } static IMigration* Get(int version) { return m_migrations[version]; } static int Up(int currentVersion) { int nextVersion = -1; std::vector<int> updateVersions; for (auto&& m : m_migrations) { if (m.first > currentVersion) { updateVersions.push_back(m.first); if(nextVersion < m.first) { nextVersion = m.first; } } } std::ranges::sort(updateVersions); for(int v : updateVersions) { m_migrations[v]->up(); } return nextVersion == -1 ? currentVersion : nextVersion; } static int Down(int currentVersion) { if(m_migrations.find(currentVersion) != m_migrations.end()){ m_migrations[currentVersion]->down(); } int nextVersion = -1; for (auto&& m : m_migrations) { if (m.first < currentVersion) { if(nextVersion < m.first) { nextVersion = m.first; } } } return nextVersion; } private: MigrationHundler() = default; MigrationHundler(const MigrationHundler& other) = delete; void operator=(const MigrationHundler& other) = delete; private: inline static std::unordered_map<int, IMigration*> m_migrations; }; template<int Id> struct Migration : public IMigration { public: Migration() { MigrationHundler::Regist<Id>(this); } }; namespace detail { consteval int versionId(const char* path) { // filename取得 const char* filename = path; while (*path) { if (*path++ == '\\') { filename = path; } } // バージョン値取得 const char* str = filename; int value = 0; while (char c = *str) { if (c <= '9' && c >= '0') { value = (c - '0') + value * 10; } else { break; } ++str; } return value; } } } #define MIGRATION(name) struct name : ::Migration::Migration<::Migration::detail::versionId(__FILE__)>
ファイル名からprefixのidへの変換はdetail::versionId
でします。
これをMIGRATION
マクロに隠蔽することでよしなに紐づけてます。
Hundlerへの登録はインスタンス生成時にthisポインタを渡しますので、各実装をしたら一つどこかにインスタンスが必要です。
例では_
の変数名で無名名前空間に生成しています
実際にはカレントバージョンをどこかに永続化する必要があるので何度も更新が走らないようにtxtなりdbなり自由に保存しておきましょう。
メタクラスについて勉強してみた。
class とか structっていうキーワードを使う箇所をユーザー定義したものに変えて
my_class Hoge{};
みたいに使います。
んで、 何ができるかというと
例えばC++ではstructはデフォルトpublic, classはprivateっていう話がありますが、
そーゆーデフォルト時のルールを決めることができたり、違反したらコンパイルエラーにできたりする。
メンバ変数は指定しなければprivateになる。すべてprivateじゃなければコンパイルエラー!みたいな
例だとinterface メタクラスを例に上げていた
$class interface { // デストラクタ定義 ~interface() noexcept { } constexpr { // メンバ変数はもったらコンパイルエラー compiler.require($interface.variables().empty(), "interfaces may not contain data"); for (auto f : $interface.functions()) { // コピー、ムーブはコンパイルエラー compiler.require(!f.is_copy() && !f.is_move(), "interfaces may not copy or move; consider a" " virtual clone() instead"); // アクセス指定子いないならpublicにする if (!f.has_access()) f.make_public(); // public以外があったらコンパイルエラー compiler.require(f.is_public(), "interface functions must be public"); // 純粋仮想関数とする f.make_pure_virtual(); } } };
interface IHoge
{
void hoge();
};
が
class IHoge { public: virtual ~IHoge() = 0; virtual void hoge() = 0; };
みたいになるという感じですかね
未来の話なのでどうなることかわからんが、面白そうだった
https://www.fluentcpp.com/2017/08/04/metaclasses-cpp-summary/