Pythonに足を生やす

趣味や勉強のアウトプット等

【怖くない】Vimmerへの一歩: 移動編

こんにちは。
Vimmerへの一歩」はVim = 仕方なく使うもの・使いにくいエディタと現在進行系で思っている私がVimmerを目指すための連載シリーズです。
Vimを使いつつこれは便利だな、覚えるべきだなと思ったコマンドを機能ごとに記していきたいと思います。

対象読者は、

  • Vimはできれば使いたくない…と思っている方
  • インサートモードとノーマルモードの違いを知っている方

となります。インサートモードとノーマルモードの違いに関してはVimでは文字を入力できるモードとコマンド等を待ち受けるモードの2種類があるんだな、くらいの理解で大丈夫です。
Vimに苦手意識を持っている方と一緒に成長していければ幸いです。
(これも便利だよ!というコマンド等あればコメント等でご指摘いただけると嬉しいです)

さて、初回のテーマは移動編です。
せっかくVimを使っているのにインサートモード内で矢印キー、というのは私も含めVim初心者にありがちなことです。 しかしながら、Vimには素晴らしい移動機能がたくさん存在します。
せっかくなので便利な移動コマンド達を使いこなして、ファイル内を縦横無尽に駆け巡りましょう。

素早くカーソルを移動させすぎて、ウィンドウがついてこなくなった場合は zz とzを2回押すことで、カーソルが中心となるように画面がスクロールされます。
カーソルがトップとなるようにするには zt と押下してください。

目次

基本操作

矢印キー的な操作達です。
縦移動では j , k を多様しますが、h , l での横移動は効率が悪いことの方が多い印象です。
5k 等とすると数字分操作を繰り返せます。

コマンド 操作 備考
j 上へ とりあえず使う
k 下へ とりあえず使う
h 左へ なるべく使わない
l 右へ なるべく使わない

行末・行頭へ移動

k, jで縦移動した後に、行頭・行末へ移動したいなら以下のコマンドを使いましょう。

コマンド 操作 備考
0 行頭へ 行頭へ行きたいときに
$ 行末へ ;をつけ忘れたときなどにどうぞ

単語単位での移動

k, jで縦移動した後に、単語単位で移動するならこちらを使いましょう。 カーソル上の単語を削除できる, :diw コマンド等と併用するととても便利です。

コマンド 操作 備考
w 次の単語の先頭へ
b 現在の単語の先頭へ
前の単語の先頭へ
現在地が単語の先頭なら前の単語へ
e 現在の単語の末尾へ 単語の最後に文字を挿入するときに便利

検索した単語への移動

コマンド 操作 備考
\hoge ファイル先頭からhoge(任意の単語)を検索して移動 n で次の単語へ, N で前の単語へ
?hoge ファイル先頭からhoge(任意の単語)を検索して移動 n で次の単語へ, N で前の単語へ

行移動

コマンド 操作 備考
nG n行目に移動 nには任意の数字を入れます

ファイルの先頭・末尾へ移動

コマンド 操作 備考
gg ファイルの先頭へ ライブラリのインポート文を書き足すとき等
G ファイルの末尾へ ファイルの中間あたりを編集した後に戻るときに

おまけ

まだまだある便利なコマンド達。

コマンド 操作 備考
% 対応する括弧へ移動 ネストが深くてわかりにくいとき等

参考

qiita.com

eng-entrance.com

qiita.com

Fire HD (タブレット) × AirPlayでMac Book Airのトリプルディスプレイ環境を手軽に構築!

こんにちは!アウトプットをサボりすぎて、ブログ記事をほとんど書かないまま大学生活が終わろうとしている中の人です。先日のアマゾンプライムデーのセールでモバイルディスプレイ用にFire HD 10(Amazonタブレット)を購入したところ、副次的にMac Book Airのトリプルディスプレイ環境を構築できて感動したのでその方法をシェアしていきたいと思います!

f:id:will_optd:20190718125551j:plain

目次

環境 / 必要なもの

Mac Book Air early 2015
・Fire HD 10 (2017年モデル?)
タブレットスタンド or タブレット固定アーム

タブレットのほうはAirReceiverがダウンロードできれば何でもいいはずです。

前提

既にMac Book Airデュアルディスプレイ環境を保持していること。
(もしデュアルディスプレイ環境がない場合でもFire HDを持ち運び可能なサブモニターとして利用できます。)

構築方法

構築方法は至ってシンプル!

①AirReceiverというアプリをダウンロード可能なタブレットを用意する
②用意したタブレットに前述のアプリをダウンロードし、(初期設定でも動作したが、セキュリティ等お好みで)任意の設定をする
タブレットMac Book Air を同じWi-Fi環境に接続する
Mac Book AirのAirPlayの接続先に用意したタブレットを選択

これだけで簡単にMac Book Airのトリプルディスプレイ環境が構築できます。

今回の嬉しいポイント

この方法の最も大きなメリットはUSB接続を利用する場合と比較してより速く、簡単にトリプルディスプレイ環境を構築可能な点にあります。そもそも、Mac Book Air(early 2015)モデルは映像出力用のポートがthunder boltの一つしか存在しません。そのため、きちんとトリプルディスプレイ環境を構築しようとするとUSBコンバータを用意し、その上で専用のドライバをインストールする必要がありました。*1その点今回の手法はめちゃくちゃシンプルで、さらにコストも抑えられます。(USBコンバータ結構高い…)

また、外出時はモバイルサブディスプレイとして持ち運び可能なのも魅力的ですね!
ただもちろんタブレットサイズなので、大きな画面でトリプルディスプレイ環境を利用したい方はUSBコンバータなどを利用する方法をとることをおすすめします。

おわりに

予てからディスプレイは増やしたいと思っていたものの、Mac Book Airだとどうも結構面倒くさいらしい… ということで諦めていたのですが、今回思わぬところでトリプルディスプレイ環境が実現してめっちゃ嬉しいです!プライムデーが終わってしまったので少し機を逃してしまった感はありますが、今回の記事が同じような悩みを持つ方の助けになれば幸いです。

蛇足(費用について)

今回かかった費用は、

・Fire HD 10: 10000円くらい(定価15000円くらい)
タブレットアーム: 1000円くらい
・AirReceiver: 300円くらい

の合計約12000円でした。プライムデーは終わってしまいましたがサイズを妥協すればFire HD 7がセールで大体3500円、また100均でタブレットスタンドも用意できると思いますのでもっと安価にトリプルディスプレイ化もできちゃいます。

次のビッグセールは年末っぽい?のでぜひぜひ皆さんも試してみてくださいね!

Unityでリフティング!【ボールを跳ねさせる編】

youtu.be

やりたいこと

今回の最終的な目的はボールを自由自在に跳ねさせる(板で…)です。その第一回として、まず上の動画のようにUnityでボールを跳ねさせます。ボールを跳ねさせるだけならUnityの画面上で完結できちゃうので今回は短めです。

手順

ボールを落とす

板とボールを画面上に用意してもらったところから下の画像を参考に手順を説明していきます。まず、画像には写ってないのですがBall(Sphere)オブジェクトのインスペクタ画面の一番下のAdd ComponentからRigidbodyを追加してUse Gravityにチェックが入っていることを確認します。これだけでボールに重力が働いて画面を動かしてあげるとボールが落ちます。

ボールを跳ねさせる

このままだとボールを落としても跳ねてくれないので、画像の②からAssetsにPhysic Materialを追加します。ここで、③の部分でBouncinessをデフォルトの0から(1までの)好きな値に変えて④のようにマテリアルをボールにドラッグアンドドロップして貼り付けるとボールは跳ねるようになります(Bouncinessは反発係数と同義なので1に近いほどよく跳ねる)。

ボールをずっと跳ねさせる

今回はリフティングのためにボールを跳ねさせ続けたいのですが、たとえ反発係数を1に設定してもこれだけではだんだん跳ねる高さは低くなっていって最後には止まってしまいます。そこでボールを跳ねさせるために最後に変更するのが同じく③の部分のBounce Combineでこれは2つの物体が衝突したときにどのように反発係数を決定するかということを調整する項目でデフォルトはAverageとなっています。これをMaximumに設定すると2つの物体の中で反発係数の大きい方の反発係数が適用されるので、止まらずに跳ねるようになります。

f:id:will_optd:20180820200824p:plain

結果と次回やること

結果は一番上の動画の通りでポーンポーンとキレイに跳ねてくれるようになりました。次回は、板を動かしてボールを自由自在に操れるようにしてみたいと思います。

【Kotlin】xmlを使わずにViewを表みたいに配置したい!【Android Studio】

f:id:will_optd:20180814005000p:plain

今回やりたいこと

 唐突に大学生のための時間割アプリを作りたくなったので、まずは上の画像みたいにView(今回はボタン)を等間隔かつ画面一杯にn×m個配置することを試みてみました。2×2の4個くらいであればLayout Editorから手で4つ配置してあげてxmlファイルをじいくってもいいのですが今回みたいに数が多くなると(約50個)少し面倒なので、Kotlinで繰り返し処理をなんだかんだやってみたのが上の画像の結果です。ただ、実は後述の諸事情のせいで縦の大きさをうまい具合に調整できなかったので今回は妥協して高さのほうにも画面の横幅を利用しました。

手順

 今回は以下の手順で実装しました。

①いくつViewを配置するのか決める(nとmを決める)
②View1つ1つに対応する座標を生成して配列にする(2×2なら[(1,1), (1,2), (2,1), (2,2)]みたいな感じ)
③座標に対応する空の配列を作成(n×mの多次元配列)
④②の座標の配列で繰り返し処理を実行して③の配列1つ1つにView生成して(位置とか大きさも決めて)代入していく

コード

class MainActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        val constraintLayout = findViewById(R.id.constraintLayout) as ConstraintLayout
        
        // 画面の大きさを取得
        val wm = getWindowManager()
        val disp = wm.getDefaultDisplay()
        val p = Point()
        disp.getSize(p)
        val width = p.x
        val height = p.x
        // いくつViewを配置するかを決める
        val colnum = 7
        val rownum = 7
        // 座標を入れるための空のListとViewを入れるための空の多次元配列を作成
        val grids = mutableListOf<Pair<Int, Int>>()
        val buttons = Array(rownum, { arrayOfNulls<Button>(colnum)})

        // ボタンひとつひとつの幅と高さを決める
        val buttonWidth = width/colnum
        val buttonHeight = height/rownum
        val buttonLayoutParams = LinearLayout.LayoutParams(
                buttonWidth,  buttonHeight
        )
        // 座標を生成して上で作った配列に代入
        for (i in 1..rownum) {
            for (j in 1..colnum){
                grids.add(Pair<Int, Int>(i, j))
            }
        }
        // ボタンを生成して配置
        for (i in grids){
            // 座標に対応する部分にボタンを生成して代入(下二行)
            var target = buttons[i.first - 1][i.second - 1]
            target = Button(this)
            target.text = "BUTTON"
            target.layoutParams = buttonLayoutParams
            // ボタンの位置を決める
            var posx = (buttonWidth * (i.second - 1)).toFloat()
            var posy = (buttonHeight * (i.first - 1)).toFloat()
            // ボタンの位置を設定
            target.setX(posx)
            target.setY(posy)
            // ボタンを配置する
            constraintLayout.addView(target)
        }
    }

反省点

 まず、Viewを画面いっぱいに表示したかったのにOnCreateの中では親Viewの大きさが取得できない都合上、うまく大きさを調整できなかったのが悔やまれます。それというのも、上の青いバー部分を含んだ画面の大きさを取得してそれを下にボタンの大きさを決めているため、画面サイズを単純に割って配置するViewのサイズを決めてしまうと下にはみ出てしまうのです。調べてみるとonCreateのタイミングじゃなくonWindowFocusChange?のタイミングであればボタンを配置した親ビューの大きさも取得できるみたいなのでまずはそこを改善していきたいと思います。

今後やりたいこととか

 xmlじゃなくてコードのほうでViewを生成するとクリック時の挙動をどこで記述したらいいか今のとこさっぱりわからないのでそこを調べてクリック時に何らかの処理を行うプログラムを書いてみようと思います。それと、そもそもLayout Editorかxlmで似たようなことができればもっと楽になるのでそういった方法があれば是非ご教授いただけると幸いです。

2018/11/8 追記

大きさの調整はこんな感じで上手くいきました。setContentView(R.layout.activity_main)をonCreate内に書いて、前回の中身の部分はonWindowFocusChanged内へ。そしてコンテンツ領域のサイズはconstraintLayoutの横幅と縦幅からcl.getWidth()とcl.getHeight()で。

f:id:will_optd:20181109001033p:plain

import android.support.v7.app.AppCompatActivity
import android.os.Bundle
import android.support.constraint.ConstraintLayout
import android.widget.Button
import android.widget.LinearLayout

class MainActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
    }

    override fun onWindowFocusChanged(hasFocus: Boolean) {
        super.onWindowFocusChanged(hasFocus)
        val cl = findViewById(R.id.constraintLayout) as ConstraintLayout
        val width = cl.getWidth()
        val height = cl.getHeight()

        val colnum = 5
        val rownum = 5
        val grids = mutableListOf<Pair<Int, Int>>()
        val buttons = Array(rownum, { arrayOfNulls<Button>(colnum)})

        val buttonWidth = width/colnum
        val buttonHeight = height/rownum
        val buttonLayoutParams = LinearLayout.LayoutParams(
                buttonWidth,  buttonHeight
        )

        for (i in 1..rownum) {
            for (j in 1..colnum){
                grids.add(Pair<Int, Int>(i, j))
            }
        }

        for (i in grids) {
            var target = Button(this)
            buttons[i.first - 1][i.second - 1] = target
            target.text = "BUTTON"
            target.layoutParams = buttonLayoutParams
            var posx = (buttonWidth * (i.second - 1)).toFloat()
            var posy = (buttonHeight * (i.first - 1)).toFloat()
            target.setX(posx)
            target.setY(posy)
            cl.addView(target)
        }
        buttons[0][0]?.text = "ボタン"
    }
}

後はボタン同士の余白をなくしたい…

Unityで衝突判定【Trigger】

プレイヤーが他のオブジェクトにあたった時にコンソールにメッセージを表示させようと思った時にちょっと詰まったので自分用のメモです。Unityは独学で勉強し始めたばかりなので間違っている点などありましたらご指摘いただけると幸いです。

今回やりたいこと

f:id:will_optd:20180812173457p:plain
 上の画像が今回動かしていくシーンです。青い球の下にあるキューブが動かしていくプレイヤーで、左右矢印キーで壁と垂直方向にのみ動くようになっています。キューブの左右の壁がプレイヤーとの衝突判定をさせたいオブジェクトです。今回の目的は、単純にプレイヤーが左右の壁に触れたらコンソールにメッセージを表示するという挙動の実装です。上の2つの球は今回はまったく関係ありませんが、消すのが面倒だったので無視してください笑

トリガーと当たり判定

 Unityで衝突判定をするには似て非なる2種類があるそうで、それがトリガーと当たり判定です。この2つの違いは単純で、衝突判定時に物理的動作(反射等?)を伴うのが当たり判定、物理動作なしにただ他の処理の引き金となるものがトリガーということで、それぞれ用途別に使い分ける必要があり、さらに必要な条件、使う関数が異なります。今回はトリガーのほうを選択して実装していきます。

準備

 今回特に注意する条件は3つで、1つ目は衝突の主体どちらか一方がRigidbodyのComponentを持つこと、2つ目は両方のオブジェクトがColliderのComponentを持つことです。Rigidbodyはオブジェクトに物理的特性を与える要素、Colliderはそのオブジェクトのもつ領域を定義する要素で、衝突判定を行うときにその領域同士が触れ合うと判定が起こります。つまり、Collider要素を持たないオブジェクトは、衝突判定の観点から見ればそこに存在しないのと同じということになります。これら2つの条件は当たり判定を行うときにも必要になってくる条件です。最後の条件はTriggerで判定を行うのに必要な条件でオブジェクトのis Triggerにチェックを入れておくことです。is Triggerが外れている場合オブジェクト同士の物理的接触が起こる可能性があります。

スクリプト

 以下のC#スクリプトをプレイヤーオブジェクトに紐付ければ衝突判定の実装が完成です。プレイモードで再生してプレイヤーを左右に動かし、左右の壁に当たると"Hit! (Rightwall or Leftwall)"のメッセージがコンソールに表示されます。今回使用した関数はOnTriggerEnterでこれはオブジェクトが衝突したときにカッコ内の処理を実行するような関数で、衝突相手が引数として渡されています。トリガー型の衝突判定を実装する関数としては他にも衝突している間処理を実行し続けるOnTriggerStay、離れたときに処理が実行されるOnTriggerExitがあります。ここでは、衝突対象によって表示されるメッセージを変えるために衝突対象オブジェクトからother.nameでオブジェクトの名前を取得してHit!の文字列と連結しています。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class PlayerScript : MonoBehaviour {
        // この部分で衝突判定と衝突時の動作を記述
	 void OnTriggerEnter(Collider other){
        	Debug.Log("Hit! " + other.name);
        }
        // ここまで
	// Use this for initialization
	void Start () {
	}
	
	// Update is called once per frame
	void Update () {
        // キー入力で左右に動くプログラム
        if(Input.GetKey(KeyCode.RightArrow)){
        	transform.position += new Vector3(3.0f, 0.0f, 0.0f) * Time.deltaTime;
        }
        if(Input.GetKey(KeyCode.LeftArrow)){
        	transform.position -= new Vector3(3.0f, 0.0f, 0.0f) * Time.deltaTime;
        }
	}
}

結果

f:id:will_optd:20180812181047p:plainf:id:will_optd:20180812181050p:plain
 きちんと衝突時にコンソールにメッセージを表示させることができました。次回は、当たり判定の実装に挑戦してみたいと思います。

追記

youtu.be

コードの該当箇所を、下のように変更してis Triggerのチェックを外したら当たり判定型の衝突判定を実装することができました。動画には入っていませんがもちろんコンソールにはメッセージが表示されています。

void OnCollisionEnter(Collision other){
    Debug.Log("Hit! " + other.gameObject.name) ;
    // Collisionはname変数を直接は持たないためgameObject変数の持つname変数を取得して表示
}