TAKOYAKING’s blog 一覧

TAKOYAKING’s blog

たこ焼き系

Rust: ターボフィッシュ コロンコロン::<>

意味

型を具体的に明示するときに使用します。
呼び方はターボフィッシュ(turbofish)。

左辺に型を書くのか、それともターボフィッシュで書くのが良いか?

左辺に型を書くべきかそれともターボフィッシュを使うのかどちらが良いか?


Type Annotation in Binding vs Turbofish · Issue #90 · rust-dev-tools/fmt-rfcs · GitHub

let query_result = users.load::<User>(&db_connection);
// VS
let users_result: QueryResult<Vec<User>> = user.load(&db_connection);

上と下では上の方が修正しやすいので個人的には良い

確かに、下の例だと全部型を書かないといけないので面倒です。

他の意見では

場合による。collectを使う場合は左辺に明示するのが好み。

もあり、確かに左辺に書いた方が便利な時もあるみたいです。

なぜ必要か

Rustのturbofishを理解する | κeenのHappy Hacκing Blog
ここに書いてありました。
記法がかぶるかららしいです。
小なりと大なりの記法と区別がつかない時があるみたいです。

びっくりした記法

Rustのturbofishを理解する | κeenのHappy Hacκing Blog

let v = Vec::<u32>::new();

ここの例から用いると、vecの初期化で使用するときはこのような記法になりますが、最初これを使用する場面に出会したときに、コロンがいっぱいすぎて、コードを書いていて、正しい記法なのか不安になりました。

感想

ターボフィッシュってなんか響きが良い!

Unity: 着地した時の判定 (2D)

着地したときの判定をどうするかの備忘録。

環境

Unity 2D

OnCollisionEnter2DとOnCollisionExit2D (ちょっと微妙)

  • OnCollisionEnter2D
  • OnCollisionExit2D

を使って、判定してみようと思いました。
基本コンセプトはイベントが呼ばれたときに、Physics2D.OverlapAreaを実行して、自身の下側と地面が衝突していれば着地判定できるので、これでいいかなと思ったのですが、OnCollisionExit2Dの時ではExitされるGameObjectはまだExitされていないので衝突判定で衝突ありと判定されてしまうので、除かないといけません。

全対象をチェックする
Physics2D.OverlapAreaAllを使って、そこからExitされるCollisionを除いてチェックすればOkです。

ただちょっと面倒だなと思ったので微妙かなと思いました。

あとなんでいちいちExitの時にチェックするかというと、地面のブロックが2つ合ってキャラクターが2つのブロックの間の上に立っている場合に、片方のブロックが無くなっても、もう片方のブロックが存在しているので、チェックしないと片方のブロックの上に着地しているのに、着地していない判定になってしまうからです。


調べてみた

初心者がUnity2Dでアクションゲームを作るチュートリアル その3 【接地判定編】 | Go-Nextブログ
この記事がわかりやすくて、Physics2D.OverlapAreaを使って、FixedUpdateで常にチェックしているというコードでした。

こっちの方がシンプルで良いかなと思いました。

感想

FixedUpdateとOnCollision系イベントだと負荷はどのくらい違うかとか気になるところでしたが、とりあえず、プロトタイプの完成を優先したいので、シンプルな方を選択したいです。

Rust: 匿名ライフタイム

structにライフタイム付けたらimpl側でもライフタイムが必要です。
その時のライフタイムの記述は匿名ライフタイムとして記述できるようです。(Rust 2018)

現象

struct SysConfig<'a> {
    dir: String,
    extension: String,
    blacklist: &'a Vec<String>,
}

impl SysConfig {
    fn parse(&self) {

    }
}

上記のようなコードを書くとimpl側でもライフタイムの指定が必要なので、以下のようなエラーがでます。

struct SysConfig<'a>
implicit elided lifetime not allowed here

help: indicate the anonymous lifetime: `<'_>`

解決方法

impl SysConfig<'_> {
    fn parse(&self) {

    }
}

エラ〜メッセージの通り記述してあげれば、直ります。
以下に匿名ライフタイムの記述がありました。(Anonymous Lifetime)
'_, the anonymous lifetime - The Edition Guide

ここによると推測可能なのでライフタイムは_(アンダースコア)で記述できると書いてあります。

もし、明示的に書く場合は以下のような記述になります。

impl<'a> SysConfig<'a> {
    fn parse(&self) {

    }
}

(2個書かないといけない・・・)

感想

ライフタイムの記述を簡略できるイメージで良い?

Unity: Unity 2D Animationでシーンでボーン(骨)の表示・非表示

Unity 2D AnimationでAnimationを作っていた時に、なぜかボーン(骨)が表示されないことがあって、焦りました。

f:id:TAKOYAKING:20200414001039p:plain

あれ?さっきまで骨があったはずなのになくなって結構焦りました。

https://forum.unity.com/threads/2d-sprite-editor-bones-arent-visible-in-scene.681337/
ここにGizmosをOnにすれば表示されると書いてありました。

上の方にあるGizmosをOnにすると表示されました。
f:id:TAKOYAKING:20200414001216p:plain

そういえば昨日Gizmosを切り替えて遊んでいたのを忘れていました!

Unity:オブジェクトのパスが変わった時にアニメーションのパスを一括変更する

アニメーションをすでに設定している時に対象のオブジェクトのパス構造を変えたい時に、アニメーションファイルも同じようにパス構造の変更を反映して欲しい時の解決策です。

現象

アニメーションが設定されている対象のオブジェクトのパス構造を以下のように変更しました。(1階層深くなった)
変更前:
f:id:TAKOYAKING:20200413215152p:plain

変更後:
f:id:TAKOYAKING:20200413215159p:plain

Animation タブ:
f:id:TAKOYAKING:20200413215326p:plain
「Missing!」 で黄色く表示され、黄色くなってしまい、アニメーションが動かなくなってしまいます。

解決

いちいち手動で一つ一つ再設定するのも面倒なので、直接アニメーションファイルを修正します。
[filename].animになっているファイルをテキストファイルで開きます。
次に path: を検索していき、正しいパス名に修正していきます。

写真のサンプル例だと階層が深くなったので、以下のような感じで修正していくことになります。
bone_arm_L -> barb/bone_arm_L
f:id:TAKOYAKING:20200413220731p:plain

感想

動いてよかった!
ただ、boneの階層が変わっただけなので、うまく修正できたけど、他のパターンでもちゃんと修正できるかはわかりません。

git rebase インタラクティブ 途中終了 (git rebase -i)

git rebase -i

インタラクティブモードになった時に、何も変更させずにキャンセルしたい時、どうするのかいつも忘れてしまうので、メモ。

間違い

:q

はrebaseが行われてしまいます。

Rust: use std::io::prelude::*;

Rustでファイル操作をするときにpreludeとuseするのが気になったので、備忘録として残します。

std::io::prelude

std::io::prelude - Rust
よく使用されるioのtraitをimportしてくれる便利なもの

コード

以下のコードはファイルを読み込んでprintする

use std::fs;
use std::path::Path;
use std::io;
use std::io::prelude::*;
use std::io::BufReader;

fn main() {
    cat().unwrap_or_else(|why| panic!(why));
}

fn cat() -> io::Result<()> {
    let path_name = "takoyaki.txt";
    let path = &Path::new(path_name);
    let f = fs::File::open(path)?;
    
    for result in BufReader::new(f).lines() {
        let l = result?;
        println!("{}", l);
    }
    Ok(())
}

これなら問題なく動きます。

もしuse std::io::prelude::*;を記述しなければ以下のようなエラーになる

error[E0599]: no method named `lines` found for struct `std::io::BufReader<std::fs::File>` in the current scope
  --> src/main.rs:17:42
   |
17 |     for (i, result) in BufReader::new(f).lines().enumerate() {
   |                                          ^^^^^ method not found in `std::io::BufReader<std::fs::File>`
   |
   = help: items from traits can only be used if the trait is in scope
help: the following trait is implemented but not in scope; perhaps add a `use` for it:
   |
1  | use std::io::BufRead;
   |

回避方法は以下の2つのうちのどちらかを記述すればOkです。

  • use std::io::prelude::*;
  • use std::io::BufRead;

読み方

プレリュード?