すだちキャンパス

すだちキャンパス

やってみたこと、学んだことなどのメモ。

unity1weekに参加しました(5回目)

こんにちは。unity1weekに参加したので、感想などです。

作ったもの

こちら↓です。回転させて、花粉(黄色い丸)を上手く真ん中の四角だけに入れるゲームです。
unityroom.com

f:id:sweetgohan:20210302133405p:plain

制作過程

イデア出し(3日)

今回は「おしゃれっぽいゲームを作る」ことを最優先にしようと考えていたので、ゲームのアイデア出しに一番時間をかけました。とはいえ、前回まではいつも半日くらいで思いついたものを作っていたので、今までが時間をかけなさすぎだったのかもしれません。
具体的には、おしゃれになりそうなゲームの案をまず書き出して、条件に合わないものをボツにしていきました。やはり、

  • ゲーム部分がサクッと実装できて
  • ある程度ゲーム性があって
  • おしゃれ

という条件を全て満たすものを考えるのは難しかったです。

ゲーム部分作成(1日)

ここはほぼ詰まらずに作成できました。

  • パーティクルに衝突判定を付ける
  • キーで回転操作を可能にする
  • ゲームの終了判定とリザルト画面の表示

くらいしか作っていませんしね。

デザインにちょっとこだわる(1日)

まず、おしゃれなフォントを探してお借りしました。文字がおしゃれになるだけで、全体の雰囲気もグッとおしゃれになる気がします。

次に、ポストエフェクトを付けました。
今まで何回も挫折していましたが、こちらのサイトを参考にすると上手くいきました。
ちなみに、以前もこのサイトを真似てみて失敗したことがあったのですが、原因が分かりました。
Main Cameraに追加したPost Process LayerのLayerをMain Cameraのレイヤーと合わせることが重要なようです!!

最後に、UIをおしゃれにしました。今まではSetActiveでOn/Off切り替えしていただけだったので唐突感がありましたが、シームレスに表示できるようにしました。
例えば、"Game Over"はalpha値を変化させることでスッと表示させています。Resultパネルも、横に広がるように表示させることで開いた感じを出しています。
ちなみに、パネルの大きさを変化させるやり方はこちらを参考にしました。

音を付ける

仕上げに音を付けました。が、音を探して付ける時間が1時間くらいしか取れず、全く時間が足りませんでした。
本当はもっとやわらかい、ぽわんとした音を付けたかったのですが・・・限られた時間では探すのが難しかったです。

反省と感想

今回は「おしゃれなゲームを作る」という目標があったので、それは概ね達成できたかなと思います。今までできなかったポストエフェクトをかけられるようになったり、UIにも多少こだわることができました。また、土日が作業できないという事が分かっていたので金曜日に予約投稿しておくことができたことも個人的には良かった点かなと思っています。

逆に反省点としては、アイデア出しに3日もかけた割に斬新さの無い平凡なゲームになってしまったかなという点が少し残念でした。また、DoTweenなどを上手く使えればもっと手軽におしゃれなUI表現ができそうですし、モーショングラフィックスなども取り入れてみたいです。

おしゃれにするコツも少しは分かったので、次回はゲーム性にももう少しこだわったおしゃれなゲームを作りたいと思います。


(評価期間終了後)
f:id:sweetgohan:20210315165920p:plain
けっこう全体的に低めの評価でした・・・ゲーム作り難しい。
「操作性」に関しては、回転スピードが遅かったのが原因かな?と思いました。スピードを変えられるようにした方がより面白かったかもです。

画像を分割する方法(Androidアプリ・Kotlin)

こんにちは。
最近KotlinをAndroidアプリ開発のために初めて触ったのですが、そこで詰まったことを簡単にまとめておきます。

やりたい事

画像のように、用意しておいた画像を分割して表示させることです。
Kotlinで画像の分割

表示している画像はこちらからお借りしています。

Bitmapで画像を表示させる

まず調べたところ、画像の操作はBitmapという形式に変換してから行う様でしたのでBitmap形式に変換して表示させてみました。

はじめに、表示させたい画像を用意します。そしてその画像をコピーし、app > res > drawable にペーストします。この時にダイアログが出ますが、OKで大丈夫です。
次に、"activity_main.xml"に移動します。そしてImage Viewをドラッグ&ドロップして表示画面に置きます。この時にエラーが出ると思うのですが、画像のボタンをクリックすれば解消されます。

最後に"MainActivity.kt"に移動してコードを書きます。

package com.example.[アプリ名]

import android.graphics.Bitmap
import android.graphics.BitmapFactory
import android.graphics.Color
import android.os.Bundle
import android.widget.ImageView
import androidx.appcompat.app.AppCompatActivity


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

        var imageview = findViewById<ImageView>(R.id.imageView)

        //画像名が"book.png"なら"R.drawable.book"とします
        var bmpImage : Bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.[拡張子無しの画像名])

        imageview.setImageBitmap(bmpImage)
    }
}

ここで1つ注意点があります。それは、「画像のデータサイズが大きすぎるとアプリが落ちる」ということです。
試しに1000KBほどある画像をBitmapとして読み込んで表示しようとすると、画像のようなエラーが出ます。
画像のサイズが大きすぎる場合のエラー

下の方に、
"java.lang.RuntimeException: Canvas: trying to draw too large(167417432bytes) bitmap."
と出ているのが分かると思います。
ちなみに、私はしばらく一番下の"Failed to start monitoring emulator-5554"というエラーにばかり注目していたので解決するのに時間がかかってしまいました。エミュレータの問題ではなく画像のサイズの問題でした・・・。

また調べたところ、ライブラリを使うと大きい画像も表示できるようです。

画像を分割する処理

次に、画像を分割する処理についてです。

Bitmap.createBitmap(元のBitmap画像, x座標, y座標, width, height)

のように書くと、指定した(x,y)座標から指定した幅と高さで切り出して新しいBitmap画像を作成してくれます。
これを利用すると、次のように書けます。(AppCompatActivity()の中の、"setContentView(R.layout.activity_main)"の後から書いています。また、予めImageViewを2つ用意してあります。)

        var imageview = findViewById<ImageView>(R.id.imageView01)
        var imageview2 = findViewById<ImageView>(R.id.imageView02)
        var bmpImage : Bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.book)
        val imageHeight:Int = bmpImage.height
        val imageWidth:Int = bmpImage.width
        val newWidth:Int = imageWidth / 2
        val newHeight:Int = imageHeight
        var x:Int = 0
        var y:Int = 0
        val list = arrayOf(0,1)
        val imageList:MutableList<Bitmap> = mutableListOf()


        for(num in list){
            imageList.add(Bitmap.createBitmap(bmpImage, x, y, newWidth, imageHeight))
            x += newWidth
        }

        imageview.setImageBitmap(imageList[0])
        imageview2.setImageBitmap(imageList[1])

mutableListという可変のListを作成してその中に格納しています。ちなみに、原因は分かりませんがarrayだとアプリが落ちてしまい上手くいきませんでした。

おまけ 画像をスマホ内の写真から選ぶ

こちらの通りにするとできました。
具体的には、onActivityResult()の中身の画像を表示している部分を、上の節で書いたコードに書き換えています。

こんな感じで動きます↓
f:id:sweetgohan:20210123115551g:plain

unity1weekに参加しました(4回目)

こんにちは。年末~年始に開催されていたunity1weekに参加したので、感想などのメモです。

作ったもの

こちらです↓。目を閉じている間だけ透明になれるので、それを上手く利用して見つからないように脱出するゲームです。
unityroom.com

今回はアイコンも作ってみました。
TOUMEI脱出のアイコン

制作過程

ゲーム内容の決定

まず、今回はゲーム内容を単純化して見た目などに力を入れようと思いました。
お題が「あける」だったので、目を開けたり閉じたりするゲームにしようと決めました。そして、イライラ棒的なゲームだと実装も楽だなということでゲームの内容がほぼ決まりました。

UIの作成

特に新しいことや難しいことはしていません。
・目を開ける/閉じるボタン
・透明薬のゲージ
・ゴールまでのタイム測定
をまず作りました。

プレイヤーと障害物の作成

まずプレイヤーを操作するスクリプトを作成しました。視点(見る方向)を操作可能にするか迷いましたが、少し時間がかかりそうなのとあえて下があまり見えないほうが厳しくて面白いかなと思い、位置のみ操作可能にしました。
次に、目を開けた状態で特定の範囲に入ると失敗になる判定部分を作成しました。これは普通にMeshを非表示にした物体を置いて衝突判定をとっています。センサーだけは目を閉じていてもアウト判定にしたかったので、プレイヤーの上空とセンサーの上空に物体を配置して、それらがぶつかると失敗判定にしました。

音の大きさを距離に応じて変化させる

目を閉じた状態では音で判断できるようにしようと思い作成しました。
これはとても簡単にできて、Audio Sourseの設定で"3D Sound"にするだけです!(参考: Unityで距離に伴って音量を変える方法 | STYLY )
ですが音を出すものが3つもあるので、最終的にはけっこううるさい感じになってしまいました。これはちょっと反省点です。

センサーをかっこよくしたい(できなかった)

完成物ではセンサーはただの赤い壁ですが、本当はここをもっとかっこよくしたかったのです。
シェーダーを使って(特にGLSLを移植して)いい感じにしたいと思い色々調べたのですが、結局時間内には作れませんでした。
ですが後日、その方法が分かったので↓次回はもっとかっこよくしたいと思います。
kabos.hatenablog.jp

完成

なんと、今回初めて締め切りまでに作り終えて予約投稿することができました!
そのおかげで、評価期間が始まってすぐに他の方のゲームを遊べたのでけっこう楽しかったです。他の人のゲームを遊ぶほど自分のゲームも遊んでもらいやすくなりますし。
期限を守れるとこういう良いことがあるのですね・・・

反省と感想

今回は予約投稿できたという点がかなり頑張ったと思える点でした。
ゲーム部分を簡単にすることで見た目に凝ろうと思ったのですが、結果的に見た目に凝る時間はあまり無くちょうど完成という形になったので、次回こそはもう少し見た目に凝りたいと思います。
また、センサー部分でシェーダーを上手く使えなかったことも反省点ですし、本当はポストエフェクトも付けたかったのでそれができなかったことも反省点です。

ですが、「みんなの評価」の「斬新さ」で初めて3超えの評価をいただくことができました!

いつも2~3弱がデフォだったのでけっこう嬉しいです。

次回はお題にもよりますが、対戦ゲームや協力ゲームを制作してみたいです。

最後に、今回のunity1weekで一番感動したゲームを貼らせていただこうと思います。
unityroom.com
こちら↑のゲームなのですが、デザインが良すぎる・・・!開始画面もそうですし、音や鳥と背景の色が変化していくところとかがとても素敵で感動しました。
こんな風におしゃれなゲームを作れるようになりたいなあ・・・。

ClusterGAMEJAM 2020 in WINTERに参加しました

こんにちは。
先日、初めてClusterのワールドを作成しました↓。
kabos.hatenablog.jp

それからしばらくしてCluster Game Jamなるイベントがあることを知り、さらに参加するだけで色々(Tシャツとエナジードリンクとグミ)がもらえるということを知ってしまい・・・これは参加するしかない!ということで参加してみました。
結果としてはものすごく悲惨なことになったのですが、いい経験になったと思います。というわけで自分のまとめも兼ねて簡単に感想などを書いておきたいと思います。

作ったワールド

こちら↓です。
cluster.mu
ちなみに、現時点でトランポリン以外まともに動きません・・・直そうと思って直せていない。。

次は巨大なクレーンゲームのあるワールドを作ってみたいな~♪と思っていたので、とりあえずそれを作ることに。お題の「溢れるエナジー」には雰囲気とかで近づければいいかな、と考えていました。

f:id:sweetgohan:20201231224559p:plain
サムネ用

スケジュール

ゲームジャムは、金曜日の20時から日曜日の20時までというスケジュールだったのですが、ちょうど色々な予定と重なってしまっていたため、私が参加できたのは土曜日の午後~夜と日曜日の午後だけでした。
正直かなり甘くみていたので、まあ半日でクレーンゲームの仕組みを作って半日でステージと雰囲気を作ったらいいかなと考えていました。が、後になってから考えると、活動可能時間の半分は予備タイムとしておくべきでした・・・。結局、クレーンゲームの仕組みを作るのに3/4日ほど費やしてしまい、ステージ作成~アップロードが超ギリギリになってしまいました。
厳格な締切があるイベントに参加するのはたぶん初めてだったので、本当にいい経験になったと思います。

動かなかったクレーンゲーム

締め切りが20時だったので、19:30くらいに終わらせてアップロードしようとしたのですが、なんとエラーが出てアップロードできません!
Unityではエラーなく動いてるのになぜ・・・と思いながら見てみると、
itemの子にitemは配置できない
Itemの子にItemは配置できません!?

これはかなり致命的な事件です。クレーンの動きをどのように作っていたかというと、本体と爪を親子にしておくことでボタンを押した時に爪が追従して動き、さらに設定しておいたアニメーションで爪が動くという感じです。

つまり根幹の仕組みが壊れたということですね・・・アップロード時だけじゃなくてシーンの再生時にもエラー出してほしかった(泣)ローカルで動かす分にはなんら問題もなかったので・・・

教訓: 必ず余裕をもってアップロードすること

ということで、時間制限のあるゲームジャムに参加する時は余裕を持って制作することが一番大事だという教訓を得ました。
また余談ですが、調べたところリッチな表現にはシェーダー(とポストエフェクト)が一番役に立つようです。もっと勉強しようっと。

UnityにGLSL(サーフェスシェーダー)を書く方法

こんにちは。
今回は個人的にずっとわからなかったことが解決したので、そのメモとして書いておきます。

UnityにGLSLで書いたフラグメントシェーダーを移植したい

基本的な書き方

Unityのサーフェスシェーダーにおいて、uv座標は次のように書くと取得できます。

sampler2D _MainTex;
struct Input
        {
            float2 uv_MainTex;
        };
void surf (Input IN, inout SurfaceOutputStandard o)
        {
            //uv取得
	    fixed2 uv = IN.uv_MainTex;
            fixed4 col = fixed4(1, 0, 0, 1);

            //色を出力
            o.Albedo = col;
        }

つまり、簡単な対応表(?)を作ると次のようになります。
gl_FragCoord.xy ⇔ IN.uv_MainTex
gl_FragColor ⇔ o.Albedo
vec2など ⇔ fixed2など
time ⇔ _Time

関数や変数の読み替え

こちら↓の記事にとてもわかりやすくまとまっていました。
qiita.com
qiita.com
ありがたい限りです。

作ったもの

今回は、矢印っぽい動くシェーダーを作ってみました。

Shader "Custom/testShader"
{
    Properties
    {
        _Color ("Color", Color) = (1,1,1,1)
        _MainTex ("Albedo (RGB)", 2D) = "white" {}
        _Glossiness ("Smoothness", Range(0,1)) = 0.5
        _Metallic ("Metallic", Range(0,1)) = 0.0
    }
    SubShader
    {
        Tags { "RenderType"="Opaque" }
        LOD 200

        CGPROGRAM
        #pragma surface surf Standard fullforwardshadows
        #pragma target 3.0

        sampler2D _MainTex;

        struct Input
        {
            float2 uv_MainTex;
        };


        void surf (Input IN, inout SurfaceOutputStandard o)
        {
			fixed2 uv = IN.uv_MainTex;
			fixed4 col = fixed4(1, 0, 0, 1);

			col = fixed4(1,1,0, 1);
			uv -= 0.5;
			uv.x += _Time*8.0;
			float k = 2*(uv.x - length(uv.y));
			k = frac(k);
		
			o.Albedo = col * k + fixed4(1,0,0.5,1)*(1-k);
        }
        ENDCG
    }
    FallBack "Diffuse"
}

こんな感じになります。
f:id:sweetgohan:20201230230545g:plain

参考

基本的なやり方がわかったので、以下の記事を参考にすればもっと色々な表現に挑戦できそうです・・・!
tips.hecomi.com
nn-hokuson.hatenablog.com
coinbaby8.com

船舶免許を取得しました(実技1回落ち)

こんにちは。
去年の12月に船舶免許(2級小型船舶操縦士免許)を取得したので、それについての記録です。
2級小型船舶操縦士免許

ちなみに、船舶免許の実技試験は99%落ちないと言われているのですが、
落ちました。
そんな貴重な(?)体験談です。

結論

「船舶免許 落ちた」などで検索してこの記事にたどりついてくれた方がいらっしゃるかもしれないので、先に結論を書いておきます。
車の運転経験が無く、運動神経が良くはなく、講師との相性が悪いと、落ちることもあります!!
というか、そうでなくても普通に船の運転は難しいので落ちることはあります!!
もし、実技で落ちてしまっても、あまり落ち込まないでくださいね!!!いつかは受かりますよ!!!!!

取得した理由

さて、記事に戻ります。
まず取得した理由ですがズバリ、「身分証明書が欲しかったから」です。
自動車の免許は持っていないし、学生証では公的な身分証にならない事が多いので、顔写真住所付きの身分証が欲しくて取得しました。
あとは単純に船舶免許ってかっこよくない?という理由もあります。

事前準備(ほぼ何もしなかった)

そんな軽い気持ちで思い立ち、とりあえず調べて家から一番近い免許センターに申し込みました。
自習して試験を受けるコース(少し安い)と、講習を受けて試験を受けるコース(少し高い)の2つがあったのですが、自信がなかったので少し高い方へ申し込みました。ちなみに、高いコースは試験に落ちても無料で再試を受けられる(主に筆記が想定されていました)というサービスもウリでした。これが後で役に立つとは・・・。

申し込んでからしばらくすると、受講票が送られてきました。教材は当日配布との事だったので、特に事前学習はできず。
不安だったので一応船舶免許を取得された方のブログを流し読みしたり、YouTubeで船舶免許 実技 で検索して動画を見たりしていましたが、ほぼ何もしていないに等しかったです。ちなみに、調べていると釣りが趣味の人などが取得される傾向があるようでした(そりゃそうか)。
あとこちらのサイト↓に、船舶免許取得の流れがとてもわかりやすくまとまっていて参考になりました。
ez-net.jp

講習の様子

筆記(2日間)

筆記は、講習を聞いていれば問題なく受かるといった感じでした。
教科書と問題集が配られて、先生が重要な部分のみ解説+重要な問題をチェックという流れで進むので、講習を聞いて休み時間に言われた問題を復習しておけば受かります。
f:id:sweetgohan:20210107234543j:plain f:id:sweetgohan:20210107234609j:plain
↑こんな感じです。

また、講習が朝9時から夕方5時までで少し長いなと思っていたのですが、実際は1時間授業→10分休憩のサイクルで進んだのでとても楽でした。
2日目の夕方に70分程の試験があり、全員が受け終わり次第採点されて合格発表でした。
ここは問題なく合格しましたし、同じ講習を受けていた他の人たち(たしか8人くらい)も全員合格されていました。

実技(1日・1回目)

そして問題の実技です。私の場合は、
8:30 集合
~10:30頃 座学+ロープワークの講習
~12:00 船の点検の講習、発進の仕方などの説明
~13:00 お昼休み
~16:00 水上で運転講習
16:00頃~ 試験
といった流れでした。
これを見ると、たった数時間の講習で船を運転できるようになるのか?と思いませんか?私は無理でした。しかもマンツーマンでなく生徒2人に対し先生1人だったので、実際に自分が練習できた時間は2時間弱くらいだったと思います。

ロープワークと点検は覚えるだけだったので簡単でしたが、運転が難しいのなんの・・・
まず、波があって揺れるので、真っ直ぐ進めないのです!
困っている私に先生が説明してくれるのですが、感覚的なことしか言ってくれず具体的にどうしたらいいのかが全く分かりません。尋ねようとしたら「(教え方に)不満があるのか?」と言われてしまい聞けないし・・・。
しかも、基本的に先生が言った通りに操作するんですが、その時に間違ったことをすると私が気付く前に先生に「こうですよ!」と言われて先に訂正されてしまうんですよね。このスタイルがどうも私には合わず。。間違ってる事を教えてくれるのはありがたいんですが、自分で考える(というか思い出す)時間をくれないと定着しないし・・・。

とまあこんな感じでその後の講習も進み、ついに試験の時間になりました。
ちなみに講習で習う項目は次の通りです。

  • ロープワーク: 試験に出る結び方を7個(巻き結び、もやい結び、いかり結び、ひとえ、ふたえつなぎ、本結び、クリート止め)覚えます。
  • 点検: 点検する項目がまあまああるので、それらを覚えます。
  • 暖機運転: 発進する前にエンジンを温めます。
  • 微速で発進: 周りを確認して発進します。
  • 滑走状態: しばらくしたら回転数(スピード)を上げて船を滑走状態にします。
  • 変針: 船の方向転換です。
  • 避航操船: 船のイラストを出されるので、座学で習った通りに運転します(向かいから船が来たら右に避けるなど)。
  • 方位測定: 方位磁石で建物などの方位を読み取ります。
  • 人命救助: 先生が投げておいたブイに近づき、拾います。
  • 連続旋回(蛇行): 目印のブイが3つ並んでいるので、その間を蛇行します。
  • 着岸: 桟橋に近づいて船を停め、ロープで係留します。
  • 後進離岸: ロープを解らんし、バックで桟橋から離れます。

試験が始まると、順番に「○○をして下さい。」と言われるのでこなしていく、といった感じです。
また、教えてくれる先生と試験官は別の人です。これもけっこうなトラップ(?)でした。
先程書いたように、私が間違えると先生が先に手を出して修正していたので、(あと実技は落ちないって聞いてたし、)試験の時も間違えたり困っていたりしたら手助けしてくれるものだと思いこんでいたのです。
しかしそんな事は一切ありませんでした。むしろ厳しめの試験官だったらしく、結果は惨敗。後日もう一度来ることになりました・・・。まあ優しめの人でも落ちていたのでは?と思うほどひどいものでしたが。
試験の様子は次の項を御覧下さい。

実際に落ちた人の実技試験の様子(これよりマシだったら多分受かります!)

どんな運転をすると落ちるかを書いておきます。これよりマシだったら受かると思います、たぶん。
まず、ロープワーク~方位測定は特に問題なく完了しました。大きく失敗したのは、人命救助・連続旋回(蛇行)・着岸・後進離岸の4つです。

  • 人命救助: 上で書いたように、先生が予め投げたブイに接近して拾うのですが、これが超難しいです。拾えなかった場合も「やり直します」と言ってUターンすればリトライできるのですが、私は3回チャレンジして全て失敗しました。3回で終了したのは、試験官に「もういいです。次行きましょう。」と言われたためです・・・。また(少なくとも私の試験を担当した試験官の場合は)、人命救助で2回以上失敗したらほぼ不合格だそうです。
  • 連続旋回(蛇行): そもそも上手く直進できていない人が旋回なんてできるわけありません。ブイに近づきすぎてぶつかりそうになったりしていました
  • (右舷)着岸: 桟橋にぶつかった上、上手く停止できずに桟橋の端っこまで流されました。下手すぎる・・・。直進できないと一番キツいのは着岸だと思います。
  • 離岸: ここまで失敗続きでかなりパニックになっていたので、ただいきなり桟橋横でハンドルも切らずにバックする人になっていました。


そして不合格となり、泣きながら帰りました。

落ちてから再試まで

まず、実技は落ちないと聞いていたためにショックが大きすぎたので、しばらく忘れて過ごしました。また、年末で予定が立て込んでいた事と、同じ先生に教わりたくなかったため、補修+再試験を10日後に予約しました。
そして一週間くらいでメンタルが回復してきたので、その頃からロープワークの復習と実技の教科書の読み込みをしておきました。特に、着岸・離岸のハンドル操作があまり分かっていなかったので、教科書を読んで初めて理解しました。さらに、YouTubeで着岸・離岸の動画を見てイメージトレーニングもしていました↓。
youtu.be

これだけ対策しても不安はかなり大きく、補修&再試当日は暗澹たる気持ちで会場へ向かいました。

実技(半日・2回目)

2回目は最初に点検とロープワークを軽く復習して、あとはひたすら運転の練習という流れでした。先生がOKと感じたら再試験を受けて受かったら終了、落ちたらもう一度練習してまた試験です。朝9時から補修が始まって、多分お昼頃には再試験できるだろうと言われた事で少しホッとしました。なぜなら、もしまた落ちても今日もう一度受けられるからです。2回チャンスがあるのは大きい・・・!
しかも今回の先生の教え方はかなり分かりやすく、練習している内に真っ直ぐに運転できるようになってきました。今まではハンドルを回しすぎていたのが、コツを掴んで波に合わせて適度に回せるようになったようです。

直進できるようになったので、人命救助、連続旋回、着岸、離岸と練習していき、どれもだいぶマシになってきました。
補修の先生は、一旦最後まで見守ってから「ここがこうだったので、こう失敗していました。あそこはもっとこうしましょう。」のように教えてくれる人で私に合っていたので、より上達も早かったように思います。講師ガチャ大事・・・

そして11:30頃には先生のOKが出たので、いよいよ再試験です。
再びロープワークから始まり、暖機運転~方位測定までは問題なくできました。そして人命救助も、1回失敗してしまいましたが2回目は成功しました!
連続旋回も、緊張で少し大回り・急旋回になりましたがそこそこ成功。着岸も、少し行き過ぎましたが成功。
離岸だけ、着岸で行き過ぎた影響で横に停泊していた船にぶつかりかけましたがなんとか成功。
そしてついに、合格しました!!!

正直に言うと、けっこう合格点ギリギリだったそうです。まあでも合格は合格なので、本当に嬉しかったです。

終わりに

とても大変でしたが、なんとか取得することができて本当に良かったです。
調べても「運転が下手すぎて船舶免許の実技試験に落ちた」という人はなかなかいないので、なんらかの参考になるのではないでしょうか。
それではまた。

あけましておめでとうございます~VR年賀状~

あけましておめでとうございます。
毎年AR年賀状を作っていたのですが、マーカーARだとURL単体で完結できないため見てもらいにくいという欠点があります。そこで今年はWebVR年賀状を作りました。
マーカーレスARにチャレンジするかどうかも悩んだのですが、インタラクティブにしたかったという点が1つ、そして31日に作り始めたのでサクッとできそうな方に傾いたというのが1つです。

作ったもの

早速ですが、作った年賀状はこちら↓です。おみくじが引けます。
happynewyear2o21.netlify.app
f:id:sweetgohan:20201231214432p:plain

お借りした背景画像のリンクはこちら。3Dモデルのクレジットはサイト内に記載してみました。

制作メモ

3Dモデル

3Dモデルは全てGLTF形式のものを使用しています。
牛と鳥居のモデルはPolyからお借りしたのですが、6月にサービス終了してしまうんですね・・・。残念です。
ちなみにおみくじの箱だけ自作(というほどでもないですが)しました。

クリックしたら反応する箱

クリックしたらなにかアクションが起こるというものは以前作ったことがあった↓ので、それを参考にしました。
kabos.hatenablog.jp

おみくじの表示

おみくじはWebVRの画面にオーバーラップして表示されるようにしています。これは、a-sceneの上にdivを置いておき、それの表示/非表示を切り替えることで実現できます。
つまり、HTMLを次のように書きます。

<head>
<!--  色々 >
<style>
    #omikuzi {
      height:100%;
      width:100%;
      background: rgba(255,255,255,0.5);
      position: fixed;
      top: 0;
      left: 0;
      z-index: 9999;
      opacity: 0;
      visibility: hidden;
    }
</style>
</head>

<body>
  <div id="omikuzi"><p>おみくじ</p></div>
  <a-scene>
   <!-- おみくじの箱とカメラを置く>
   <a-entity
     id="omikuzibox"
     gltf-model="#box"
     click-omikuzi></a-entity>
    <a-camera id="cameraBody" look-controls="reverseMouseDrag: true; reverseTouchDrag: true;" wasd-controls>
       <a-entity cursor="rayOrigin: mouse"></a-entity>
    </a-camera>
  </a-scene>
</body>

そして、JavaScriptで次のように書くと、箱をクリック時におみくじを表示することができます。

AFRAME.registerComponent('click-omikuzi', {
  init: function () {
    this.el.addEventListener(_click, function (event) {
      rand = Math.floor( Math.random() * 7) ;
      omikuziImage.src = images[rand];
      //display omikuzi
      omikuziWindow.style.opacity = 1;
      omikuziWindow.style.visibility = "visible";
    });
  }
});


それでは、今年もよろしくお願いします!