Gaming Life

一日24時間、ゲームは10時間

Riderでコンストラクタを挿入する手順

引数なしコンストラクタを生成する

ctorと入力すると、引数のないコンストラクタが自動で生成されます

public class SampleClass1
{
    public SampleClass1()
    {
        
    }
}

すべてのフィールドを初期化するコンストラクタを生成する

ctorfと入力すると、すべてのフィールドを初期化するコンストラクタを自動で生成します。

public class SampleClass2
{
    private int _x;
    private readonly int _y;
    private int _z;

    public SampleClass2(int x, int y, int z)
    {
        _x = x;
        _y = y;
        _z = z;
    }
}

すべてのプロパティを初期化するコンストラクタを生成する

ctorpと入力すると、すべてのプロパティを初期化するコンストラクタを自動で生成します。

public class SampleClass3
{
    private int X { get; set; }
    private int Y { get; }
    private int Z { get; set; }

    public SampleClass3(int x, int y, int z)
    {
        X = x;
        Y = y;
        Z = z;
    }
}

すべてのプロパティとフィールドを初期化するコンストラクタを生成する

ctorfpと入力すると、すべてのプロパティとフィールドを初期化するコンストラクタを自動で生成します。

public class sampleclass4
{
    private int a;
    private int b { get; }
    private int c { get; set; }
    private readonly int d;

    public sampleclass4(int a, int d, int b, int c)
    {
        a = a;
        d = d;
        b = b;
        c = c;
    }
}

2023年読んで面白かった本

ブログでは、お久しぶりです。

身近な方には報告したが、今年7月に転職して今は都内でスマホゲームを作っている。

今年から、読んだ本をscrapboxに記録するようになった。ここに沢山の本を記録していこうというモチベで、様々なジャンルの本が読めたと思う。 ただ1年を振り返ってみると、転職した影響か、今後のキャリアで悩むことが多く、救い(?)を求めて実用書(自己啓発本)の類いの本を読む時間が多かったように感じる。

scrapbox.io

※ここに記録した本をすべて読みきっているわけではない。また、マンガは記録をつけていない。

仕事納めも無事終え、ふと、せっかく読んだ本を記録したんだから、振り返って面白かった本を紹介してみたいと思い立ち。今回は、2023年読んだ本の中から特に面白かった14冊をピックアップして紹介する。

小説

アルジャーノンに花束を』ダニエル キイス

言わずと知れた名SF小説。何がきっかけで読むことにしたかは覚えていない。

32歳になっても幼児のような知能しか持たない主人公が、ある手術により超知能を得るというSF。重度の発達障害を持つ主人公が書く手記の形で進む物語は、はっきり言って読みにくい。私は最初の100ページ程度を読み切るのに1週間以上かかった。しかし、物語が進めば、最初の読みにくい文章にも愛着がわいてしまう。多くの読者に長く愛されているのにも納得の傑作だった。

『本と鍵の季節』米澤穂信

氷菓シリーズの原作小説を書いた米澤先生の著書。図書委員会仲間の男子高校生コンビが主役の青春図書室ミステリー。ホームズ役である松倉詩門のキャラクターがとても魅力的。〈図書委員〉シリーズとして、『栞と嘘の季節』という続編も出ておりこちらも大変良かった。

かがみの孤城辻村深月

文句なし今年のベスト小説。

引きこもりの少女が、突如鏡の中に現れた不思議な世界で、同年代の少年少女と出逢う物語。ジャンルとしては、ファンタジー系ミステリーと呼べばよいか。心理描写が秀逸、もっと言うと真に迫りすぎており、読んでいて胃が痛くなった。

ちなみに本作は全編オーディオブック化しており、主役を演じるのが花守ゆみりさん。彼女のラジオで「この収録は本当に良かった!」と話していたのをきっかけに小説を読み、どっぷりハマり、オーディオブックも買った。しかしオーディオブックは未だすべて聞けていない。花守さんの圧巻の演技に、心が揺さぶられすぎてしまうんだ……2024年中には聞き終えたい。

『傲慢と善良』辻村深月

続けて、同じ辻村作品から『傲慢と善良』をピックアップ。累計部数67万刷と、非常に売れているらしい。

消えた婚約者を探すため、男が彼女の過去に向き合う物語。辻村先生はどうしてこんなに人の価値観や感情、内面を描くのがうまいのか……それでいて読みやすい。

好き好き大好き超愛してる。舞城王太郎

ある男女の愛を綴った物語。合間合間に挟まった短編(掌編)小説も非常に良かった。読み終わった後知ったのだが、エヴァの元ネタという噂は本当なんだろうか。

癖のある文体で、好みははっきり分かれる作品だと思う。舞城王太郎作品の中では最も読みやすいという話らしいのだが……『煙か土か食い物』を持ってるので、今度読んでみようと思う。

『ロード・エルメロイII世の冒険 2 彷徨海の魔人(上)』三田誠

TYPE-MOON好きで活字好きなら読んどけ。

技術書

『達人プログラマー ―熟達に向けたあなたの旅― 第2版』 David Thomas, Andrew Hunt

良いプログラマになるための心構えや実践的なアプローチが多数解説されている。世に出回っているプログラミング技法の基礎はほぼすべて本書から学べるのではなかろうか。おそらく来年も何度も見返すだろう。バイブルとしてとっておきたい一冊。

『闘うプログラマー[新装版] ビル・ゲイツの野望を担った男達』G パスカル ザカリー

Windows NTを完成させた、当時のマイクロソフトの出来事を、関係者インタビューを元にまとめた本。狂気が世界を動かすんだな……

マンガ

『かげきしょうじょ!』斉木久美子

アニメ『かげきしょうじょ!』のOP曲「星のオーケストラ」にハマったことがきっかけで、全巻購入した。宝塚歌劇団をモデルにしたであろう紅華歌劇団予科生である2人の少女の青春物語。なお、アニメはまだ見てない。サブ主人公のCVが花守ゆみりなので、見ねば。

『バックヤード ジャンク ユニバース』加藤拓弐

年の瀬にやってきた大傑作。作者の「癖」をこれでもかと詰め込んだ短編マンガ集。[エルフロイド森聖国物語]がとても好き。

BORUTO 20巻』 岸本斉史, 池本幹雄

すいません。BORUTOのことなめてました。大ヒット作品の設定だけ引き継いだ駄作だとばかり思い込んでいたのですが、この巻はちゃんと面白い。いやNARUTOガチ勢視点では、不満はあるのだろうけど。今後単行本で追いかけていこうと思う。

実用書

『ロギング仕事術: 課題に気づく、タスクが片づく、成果が上がる』倉下忠憲

scrapboxユーザーならおなじみ倉下忠憲さんの著書。私はもともとメモ魔ではあったが、この本を読みよりメモ魔ぶりが加速した。実際、本書に仕事の進め方が大いに影響を受けているので、ピックアップ。

『書く習慣』いしかわゆき

マチュア物書きへの救いの書。続けられるかわからんが、来年はブログをもっと更新していこうかな。

その他

悠木碧のつくりかた』悠木碧

声優「悠木碧」のファーストエッセイ集。声優オタ必読だと思ってるくらいには面白かった。  

 

   

2023年の面白かった本はこんなところ。

振り返ってみると、技術書全然読めてないな……読みかけだったり、ネット記事で済ませがちなので、来年は月1冊くらいは技術書を読もうかな。

C/C++から始めた人の、C#のref/out/in修飾子の用途

概要

ref: 引数を参照で渡し、値の書き換えと、関数内で参照先の書き換えの両方を許可したい時に使う

out: 関数の引数に計算結果を返したい時に使う

in: 引数を参照で渡し、値の書き換えのみ許可したい時に使う

前提知識:C#における値型と参照型の違いについて

C/C++からプログラムを始めた私にとって、C#の最初のつまづきポイントがここだった。C#プログラミングにおいて、値型と参照型を意識することは非常に重要である。

値型と参照型の違いは単純で、「その型の値を直接保持するか否か」である。以下に簡単な例を示す。

// C#ではstruct(構造体)は値型である
public struct T
{
    public int a, b, c;
    public T(int _a, int _b, int _c) { a = _a; b = _b; c = _c; }
    public override string ToString() { return $"{a}, {b}, {c}"; }
}

// C#ではclassは参照型である
public class U
{
    public int a, b, c;
    public U(int _a, int _b, int _c) { a = _a; b = _b; c = _c; }
    public override string ToString() { return $"{a}, {b}, {c}"; }
}

// 値型の変数を=で代入した時の挙動を見る
T a1 = new T(1, 1, 1);
T a2 = a1;
T a3 = a2;
a1.a = 2;
Console.WriteLine($"a1: {a1}");
Console.WriteLine($"a2: {a2}");
Console.WriteLine($"a3: {a3}");

Console.WriteLine("=======================");

// 参照型の変数を=で代入した時の挙動を見る
U b1 = new U(1, 1, 1);
U b2 = b1;
U b3 = b2;
b1.a = 2;
Console.WriteLine($"b1: {b1}");
Console.WriteLine($"b2: {b2}");
Console.WriteLine($"b3: {b3}");

出力結果

a1: 2, 1, 1
a2: 1, 1, 1
a3: 1, 1, 1
=======================
b1: 2, 1, 1
b2: 2, 1, 1
b3: 2, 1, 1

値型の変数は、値そのもの(今回の例でいうと int a, b, cの3つのint型の値)を保持する。そのため、 = を使って代入した時、値すべてをコピーして代入先に格納するという挙動になる。

一方参照型の変数は、値の実体がどこにあるかを示す参照情報だけを持ち、実体は別の場所(ヒープ)に用意する。そのため、 = を使って代入すると参照情報だけをコピーするので、上記コードでの変数 b1, b2, b3 は同じ値の実体を指していることになる。

値型と参照型について、詳しくは以下のWebサイトを見てほしい。

ufcpp.net

techblog.kayac.com

関数の引数は値渡し

C#で引数付きの関数を呼び出す時、関数には値そのものが渡される。これを一般に値渡しと呼ぶ。

では、値型と参照型で「値渡し」した時の挙動がどう変わってくるか見てみる。

void ModifyValueStruct(T t)
{
    t.a = 10; // 値型引数の値を関数内で書き換える
}

void ModifyValueClass(U u)
{
    u.a = 10; // 参照型引数の値を関数内で書き換える
}

T t = new T(1, 1, 1);
U u = new U(1, 1, 1);
ModifyValueStruct(t);
ModifyValueClass(u);
Console.WriteLine($"T t: {t}");
Console.WriteLine($"U u: {u}");

出力結果

T t: 1, 1, 1
U u: 10, 1, 1

値型の変数を関数に値渡しすると、「値そのもの」がコピーされ関数に引き渡される。つまり、関数呼び出し側の変数 t と、関数内の変数 t は別モノ。関数内でいくら値型引数の値を書き換えても、関数呼び出し元には、その変更は伝わらない。

一方参照型の変数を関数に値渡しすると、「値の参照情報」だけがコピーされ、関数に引き渡される。つまり、関数呼び出し側の変数 u と 関数内の変数 u は同じ値を指している。したがって、関数内で参照型引数の値を書き換えると、関数呼び出し元の変数が指す値も書き換わる。

ref/out/inを使った参照渡し

ref/out/in修飾子は、「関数の引数を参照渡し」したい時に使われる。

ref/out/inを使いたいときは、関数宣言側と、引数引数の型名の前にrefなどの修飾子をつければよい。

void RefFunc(ref int i) { /* ... */ } // 型名の前にref修飾子をつける

// ...

int num;
RefFunc(ref num); // 呼び出すときにもref修飾子をつける(注:inはつけなくてもよい)

ref/out/in修飾子はすべて「引数の参照渡し」を実現するためのキーワードだが、それぞれ細かく挙動が変わってくる。以下にその違いをまとめた表を載せた。

キーワード 引数として渡す前に初期化が必要か メソッド内で参照先の値の書き換えが可能か 呼び出し時の修飾子付与
ref 必須 可能 必須
out 不要 必須 必須
in 必須 不可 任意

値型を参照渡しする例

void Func(T t)
{
    t.a = 2; // 値渡しされた値型を関数内で書き換えても呼び出し元には伝わらない
}
void Func2(T t)
{
    t = new T(2, 2, 2); // 値渡しされた値型のインスタンス差し替えは呼び出し元に伝わらない
}
void RefFunc(ref T t)
{
    t.a = 2; // ref引数の値を書き換えると呼び出し元にも伝わる
}
void RefFunc2(ref T t)
{
    t = new T(2, 2, 2); // 引数が指すインスタンスを書き換えることも出来る
}

void OutFunc(out T t)
{
    t = new T(3, 3, 3); // out引数は関数内で必ず初期化しなければならない
}

void InFunc(in T t)
{
    // t.a = 2; // in引数の値を書き換えることはできない
}

T t;

t = new T(1, 1, 1);
Func(t);
Console.WriteLine($"Func() -> {t}");

t = new T(1, 1, 1);
Func2(t);
Console.WriteLine($"Func2() -> {t}");

t = new T(1, 1, 1);
RefFunc(ref t);
Console.WriteLine($"RefFunc() -> {t}");

t = new T(1, 1, 1);
RefFunc2(ref t);
Console.WriteLine($"RefFunc2() -> {t}");

t = new T(1, 1, 1);
OutFunc(out t);
Console.WriteLine($"OutFunc() -> {t}");

t = new T(1, 1, 1);
InFunc(in t);
Console.WriteLine($"InFunc() -> {t}");

出力結果

Func() -> 1, 1, 1
Func2() -> 1, 1, 1
RefFunc() -> 2, 1, 1
RefFunc2() -> 2, 2, 2
OutFunc() -> 3, 3, 3
InFunc() -> 1, 1, 1

参照型を参照渡しする例

void Func(U u)
{
    u.a = 2; // 値渡しされた参照型引数の値を書き換えると、呼び出し元に伝わる
}
void Func2(U u)
{
    u = new U(2, 2, 2); // 値渡しされた参照型引数の指す先を変えても、呼び出し元には伝わらない
}
void RefFunc(ref U u)
{
    u.a = 2; // 値を書き換えると呼び出し元にも伝わる
}
void RefFunc2(ref U u)
{
    u = new U(2, 2, 2); // 引数が指すインスタンスを書き換えることも出来る
}

void OutFunc(out U u)
{
    u = new U(3, 3, 3); // ouu引数は関数内で必ず初期化しなければならない
}

void InFunc(in U u)
{
    // u.a = 2; // in引数の値を書き換えることはできない
}

U u;

u = new U(1, 1, 1);
Func(u);
Console.WriteLine($"Func() -> {u}");

u = new U(1, 1, 1);
Func2(u);
Console.WriteLine($"Func2() -> {u}");

u = new U(1, 1, 1);
RefFunc(ref u);
Console.WriteLine($"RefFunc() -> {u}");

u = new U(1, 1, 1);
RefFunc2(ref u);
Console.WriteLine($"RefFunc2() -> {u}");

u = new U(1, 1, 1);
OutFunc(out u);
Console.WriteLine($"OutFunc() -> {u}");

u = new U(1, 1, 1);
InFunc(in u);
Console.WriteLine($"InFunc() -> {u}");

出力結果

Func() -> 2, 1, 1
Func2() -> 1, 1, 1
RefFunc() -> 2, 1, 1
RefFunc2() -> 2, 2, 2
OutFunc() -> 3, 3, 3
InFunc() -> 1, 1, 1

ref/out/inの使い道

refは、既に値が入っている変数を書き換える時に使う。

気をつけたいのは、参照型の引数を書き換えたいからという理由でrefをつける必要はないこと。参照型の値渡しで値の書き換えは可能なので、その用途でrefをつける必要はない。

参照型引数にrefをつけるのは、「引数が指す先を変えたい(新しいインスタンスを指すようにしたい)」ときのみ。.NET APIでは、 Array.Resize() で参照型引数にref修飾子を使っている。

outは、関数の返り値を複数持たせたいような時に使うことが多い印象。C++では「非constポインタ渡し」で実現する処理。ただしrefとは異なり、関数内で新たに初期化されるので、まだ宣言しかしていない変数を渡すべき。

ちなみに、下のように変数宣言をoutによる参照渡しと同時にこなすこともできる(outを使うときはこの書き方が安全だと思う)。

bool isValid = Calclate(out int num);

inは、inを使わければならない特別なプログラムがあるわけではない。

inの用途はズバリ「値型引数のコピーコスト削減」。

値型を値渡しする時、その値のコピーが作られる。この値が4Byteのint程度ならコピーにかかるコストは無視できるほど小さい(だろう)。しかし、もし巨大な値型(struct)を値渡ししたら巨大なコピーが作られてしまい、その分コピーに必要な時間もメモリも増えてしまう。こういう時にinは使われる。C++でいうところの「&を使ったconst参照渡し」に相当すると考えて良い。

が、コピーに無視できないほどのコストがかかる巨大な値型(struct)を作るべきではないということは忘れてはならない(そうしないとならない特別な事情って何かあるんでしょうか。知ってる方がいたら教えていください)。

まとめ

C/C++からプログラムを始めた人にとって、C#の値型と参照型の違いは必ず抑えておきたい。それを理解した上で、ref/out/inを使いたい。

UnityのHDRPでSNNフィルタを実装する

最近UnityのHDRPを使って色々と実験をしている。今回はその実験中に作ったSNNフィルタポストプロセスの実装メモ。今回実装にはGtihubで公開されている「HDRP-Custom-Passes」に付属するシーンを使用した。

github.com

f:id:ai_gaminglife:20210429151643p:plain

環境

Unity 2020.3.1f1 Personal

High Definition RP ver.10.3.2

SNNフィルタとは

SNNフィルタ(Symmetric Nearest Neighbor Filter)は、画像を油彩画のような見た目に変化させるフィルタである。中のアルゴリズムについては、既にわかりやすく説明されているサイトがあるので、ここでは省略する。

sites.google.com

実装

PostProcessを管理するC#クラスを作成する

Create > Rendering > C# Post Process Volume からPostProcessを管理するC#クラスを作成する。ここでは「SNNFilter.cs」と名付けた。

SNNFilterクラスの中身は以下の通り。

using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.Rendering.HighDefinition;
using System;

[Serializable, VolumeComponentMenu("Post-processing/Custom/SNNFilter")]
public sealed class SNNFilter : CustomPostProcessVolumeComponent, IPostProcessComponent
{
    [Tooltip("Controls the intensity of the effect.")]
    public ClampedFloatParameter intensity = new ClampedFloatParameter(0f, 0f, 1f);
    public FloatParameter sampleCountFactor = new FloatParameter(2f);
    Material m_Material;

    public bool IsActive() => m_Material != null && intensity.value > 0f;

    // Do not forget to add this post process in the Custom Post Process Orders list (Project Settings > HDRP Default Settings).
    public override CustomPostProcessInjectionPoint injectionPoint => CustomPostProcessInjectionPoint.AfterPostProcess;

    const string kShaderName = "Hidden/Shader/SNNFilter";

    public override void Setup()
    {
        if (Shader.Find(kShaderName) != null)
            m_Material = new Material(Shader.Find(kShaderName));
        else
            Debug.LogError($"Unable to find shader '{kShaderName}'. Post Process Volume SNNFilter is unable to load.");
    }

    public override void Render(CommandBuffer cmd, HDCamera camera, RTHandle source, RTHandle destination)
    {
        if (m_Material == null)
            return;

        m_Material.SetFloat("_Intensity", intensity.value);
        m_Material.SetFloat("_SampleCountFactor", sampleCountFactor.value);

        m_Material.SetTexture("_InputTexture", source);
        HDUtils.DrawFullScreen(cmd, m_Material, destination);
    }

    public override void Cleanup()
    {
        CoreUtils.Destroy(m_Material);
    }
}

SNNFilterシェーダを作成する

Create > Shader > HDRP > PostProcess でポストプロセス用のシェーダを作成できる。ファイル名はSNNFilterとする。この時シェーダ名は先程作成したC#クラス中の kShaderName と完全に一致させる必要がある。

シェーダの中身は以下の通り。

Shader "Hidden/Shader/SNNFilter"
{
    HLSLINCLUDE

    #pragma target 4.5
    #pragma only_renderers d3d11 playstation xboxone vulkan metal switch

    #include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Common.hlsl"
    #include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Color.hlsl"
    #include "Packages/com.unity.render-pipelines.high-definition/Runtime/ShaderLibrary/ShaderVariables.hlsl"
    #include "Packages/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/FXAA.hlsl"
    #include "Packages/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/RTUpscale.hlsl"

    struct Attributes
    {
        uint vertexID : SV_VertexID;
        UNITY_VERTEX_INPUT_INSTANCE_ID
    };

    struct Varyings
    {
        float4 positionCS : SV_POSITION;
        float2 texcoord   : TEXCOORD0;
        UNITY_VERTEX_OUTPUT_STEREO
    };

    Varyings Vert(Attributes input)
    {
        Varyings output;
        UNITY_SETUP_INSTANCE_ID(input);
        UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(output);
        output.positionCS = GetFullScreenTriangleVertexPosition(input.vertexID);
        output.texcoord = GetFullScreenTriangleTexCoord(input.vertexID);
        return output;
    }

    // List of properties to control your post process effect
    float _Intensity;
    float _SampleCountFactor;
    TEXTURE2D_X(_InputTexture);

    float4 GetOffsetPixel(float2 offset, float2 coord) {
        float2 invScreenSize = 1.0 / _ScreenSize;
        float4 result = LOAD_TEXTURE2D_X(_InputTexture, (coord + invScreenSize * offset) * _ScreenSize.xy);
        return result;
    }

    float4 GetSNN(float4 centerColor, Varyings input, float2 offset) {
        float4 col0 = GetOffsetPixel(offset, input.texcoord);
        float4 col1 = GetOffsetPixel(-offset, input.texcoord);
        float3 d0 = col0.rgb - centerColor.rgb;
        float3 d1 = col1.rgb - centerColor.rgb;

        return dot(d0, d0) < dot(d1, d1) ? col0 : col1;
    }

    float4 CustomPostProcess(Varyings input) : SV_Target
    {
        UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(input);

        float4 centerColor = LOAD_TEXTURE2D_X(_InputTexture, input.texcoord * _ScreenSize.xy);

        int count = 0;
        float4 resultColor = (0, 0, 0, 1);
        for (int x = -_SampleCountFactor; x <= _SampleCountFactor; ++x) {
            for (int y = -_SampleCountFactor; y <= _SampleCountFactor; ++y) {
                if (x == 0 && y <= 0) {
                    continue;
                }
                resultColor += GetSNN(centerColor, input, float2(x, y));
                count++;
            }
        }
        resultColor /= count;

        return resultColor;
    }

    ENDHLSL

    SubShader
    {
        Pass
        {
            Name "SNNFIlter"

            ZWrite Off
            ZTest Always
            Blend Off
            Cull Off

            HLSLPROGRAM
                #pragma fragment CustomPostProcess
                #pragma vertex Vert
            ENDHLSL
        }
    }
    Fallback Off
}

作成したポストプロセスをHDRPに登録する

Edit > ProjectSettings > HDRP Default Settings からHDRPの詳細な設定を決められる。今回は、 After Post Process に先程作成したSNNFilterを登録する。

f:id:ai_gaminglife:20210429151720p:plain

ポストプロセスをシーンに追加する

Hierarchyから、 Volume > Global Volume と選択して、シーンにGlobal Volumeを追加する。Global Volumeはポストプロセスを設定すると、シーン全体にそのポストプロセスを適用することができる。

Global Volume中のVolumeコンポーネントのProfileのNewを押して、Profileを新規作成する。

続けて Add Override を選択する。ここまで適切に設定していれば、ここで「SNNFilter」を追加できる。Intensityを0より大きい値に設定するとポストプロセスが適用される。

f:id:ai_gaminglife:20210429151730p:plain

SNNFilterの例

Sample Count Factor = 2の時

f:id:ai_gaminglife:20210429151738p:plain

Sample Count Factor = 10の時

f:id:ai_gaminglife:20210429151748p:plain

Sample Count Factor = 20の時

f:id:ai_gaminglife:20210429151759p:plain

参考資料

Custom Post Process | High Definition RP | 10.2.2

DirectXの話 第111回 - もんしょの巣穴

alelievr/HDRP-Custom-Passes: A bunch of custom passes made for HDRP

WindowsでMacのようにキーボードショートカット一発で呼び出せる辞書アプリ「RapidDict」を買った

f:id:ai_gaminglife:20210228204514p:plain

学生時代、研究室で支給されたmacを使っていた時期がある。その時よく使っていたmacの機能で、Windowsにもほしいなあと思ったのが「spotlightで起動できる辞書検索」機能だ。

spotlightとはmacに標準に搭載されているランチャーアプリのことで、これを使ってショートカット一つで起動し、アプリの起動やファイル検索などを容易に呼び出すことができる。このspotlightには辞書.appが組み込まれており、調べたい単語を入れると、その辞書ページに一発で飛ぶことができる。この機能のお陰で、大学時代海外の論文を読むときに簡単に英単語を調べられて、助かったのを覚えている。

inforati.jp

Windowsにも「Wox」などmacのSpotlightに相当するサードパーティ製アプリは存在する。私の場合、Microsoftが開発しているユーティリティアプリ「PowerToys」にバンドルされている「PowerToys Run」を使っている。

github.com

ただ、これらのランチャーアプリには辞書が組み込まれていない。また、ショートカット一つで起動できるような出来の良いWindows用辞書アプリもないため、macを研究室に返還して自宅のWindowsで英単語を調べるときは、仕方なくブラウザを立ち上げてWeblio辞書を使っていた。

で、最近になってショートカット一つで起動できるWindows向け辞書アプリを見つけた。それが、RapidDictだ。

yomogisoftware.biz

RapidDictはアプリ自体は無料だが、辞書データ(英辞郎)を入手するのに980円支払う必要がある。一応無料の辞書データもあるようだが、かなり貧弱なため、基本RapidDictを使うなら980円を払うべき。

RapidDictを使ってみて、正直アプリ自体の出来はあまり良くないと感じた。購入した辞書データをインストールする際何度かアプリがダウンすることもあったし、検索速度も決して早いとはいえない。

ただショートカット一つで起動できる英語辞書というだけで、その出来の悪さに目をつぶって使い続けたくなる魅力がある。Windowsで英単語を検索するためだけにわざわざブラウザを起動するのに嫌気が差している人は、是非RapidDictを試してみてほしい。

……PowerToys Runに辞書機能入らないかなあ……

(遅すぎる)今年の目標 2021年版

遅すぎますが今年の目標を簡単に書いておこうと思う。

ブログ毎月更新継続

こんな急ぎ書いたようなのが丸見えな記事でも、3年以上続いているブログの毎月更新は、今年も継続したい。その中で、1、2記事は、10数時間かけた大作の記事が書きたい

今年こそ一人Advent Calender完走

すっかりなかったことになっている去年の一人アドベントカレンダー。あれは直前に思いつきでカレンダーを作って、即興で記事を書いていたところがあるので仕方ないところがある。

今年は、まだまだ時間があるので、記事のストックをためて、12月に一人アドベントカレンダーが完走できるようにしたい。(そしてその最終日に、この記事を踏まえた今年の振り返り記事を書きたい)

就活記事のリメイク

昔書いた就活記事のリメイクを書く。これは今絶賛書いているところで、来月中に公開する目処が経っているので、乞うご期待ということでお待ち下さい。

月2冊は技術書を読む

去年は本を4冊買ったら1冊買うみたいなスタイルで、完読したという本があまり多くなかった。最近本棚を買い替えたこともあり読書のモチベが高いので、まずは積んでいる本の消化から優先して、最低月2冊ペースで本を読みたい。

二ヶ月に1個はGithubに何かしらの小さいプロジェクトを公開する

最近OpenSiv3Dを使って2048ゲームのクローンを作成した(これについては後でまた詳しくブログに詳細を書くと思います)。この規模でいいので、小さいプロジェクトを最低でも二ヶ月に一個は開発して、それをGithub及びブログで公開していきたい。

新しい言語を一つ覚える

今の所考えているのはjavascript + HTML5。web系の知識が空っぽなので、Github pagesにポートフォリオとなるサイトが作れる程度にはなにか作りたいなーと。

まとめ

以上。今年もフルリモート勤務が続くと思われるので、この目標が達成できるだけの時間は取れると思う。今年は無理に大きいことをやろうとせず、将来の肥やしになるような、小さい事をコツコツと、をテーマにエンジニアライフを送りたいと思います。

windowsのリモートデスクトップで複数画面を使う&画面上部の接続バーを消す方法

本記事はai_9684_dctソロ Advent Calendar 2020 10日目の記事です。

Windowsリモートデスクトップ接続」に関する機能の紹介。

コロナ禍の中、4月の入社以来、数回の出社を除いてリモートワークが続いている。弊社の場合、自宅にある会社から貸与されたPCから会社のネットワークにVPN接続し、windows標準の「リモートデスクトップ接続」か、「Chromeリモートデスクトップ」で会社のPCにつないでリモートで作業するというスタイルを取っている。

私は学生時代もたまに使っていて、使い慣れていたということもあり、半年以上「Chromeリモートデスクトップ」を使用していた。しかしながら「Chromeリモートデスクトップ」は1画面でしか作業できない事が非常に不満だった。

そんなことをMTG中にぼやいたら、先輩から「windowsリモートデスクトップなら複数画面使えるよ!」というアドバイスを貰った。マジか、と調べてみたら確かにあった。

f:id:ai_gaminglife:20201210215105p:plain

リモートデスクトップ接続の接続前の設定画面で、「リモートセッションで全てのモニターを使用する」というオプションを有効にすると、例えばリモート接続元のPCが2画面使っていれば、2画面まるごと使ってリモートデスクトップの画面を使う事が出来た。なぜこの機能にもっと早く気づかなかったんだ……

更に、windows標準のリモートデスクトップ接続の大きな不満の一つだった、画面上部に常に表示される↓この接続バーも消せることが分かった。

f:id:ai_gaminglife:20201210215138p:plain

同じ設定画面で、「全画面表示の使用時に接続バーを表示する」という設定のチェックを外せば、接続バーが最初以外一切表示されなくなる。なお、接続バーを使わなくても、「[Ctrl] + [Alt] + [Pause]」キーを同時押しすれば、全画面表示が解除される。

というわけで、リモートワークの不満の一つだった「画面の狭さ」という課題がクリアされ、リモート作業中にかかるストレスを大きく減らすことができましたとさ。まあ、夕方6時頃になると回線が重くなって、入力の遅延が我慢できないほど目立つようになるのは変わらないのだが。10Gビット回線引こうかなあ……