【テクテクライフ】平和の滝

なぜここが札幌の名所なんだろう。

この場所が結構やばくて、

これを見れば分かるだろうか。

札幌の中心部からかなり離れているのである。

行き方は、地下鉄東西線発寒南駅から、平和の滝入り口行きのバスに乗る。

そこから20分ぐらい歩く。

かなり田舎である。

漬いた。

駐車場から急な階段を降りていけば滝がある。

これだけだった。

うーん、なんでこんな所が名所なんだろう?🤔🤔🤔

登山道があって、ここから手稲山に抜けることができるみたい。

もうちょっと季節が進めば紅葉がきれいなんだろうなぁ。

ちょっと時期が早すぎたか。

プロジェクトセカイを始めた。

初音ミクなどのボーカロイド曲を題材としたリズムゲームで、

こういうゲームを見ると、どうしてもガルパと比べてしまう、バンドリーマーがおりまして。

ストーリーは主にユニット毎に用意されているのですが、

なかなか内容が重たくて。

初音ミクを初めとしたバーチャルシンガーがどのように関与してメンバーの関係をどうこうしていくのかが、見所です。

ガルパと比較してしまう、理由としては、

基本的なシステムがガルパをベースにしていること。

勿論オリジナル要素もあるのですが、

たぶん、今後リリースされるリズムゲームは、ガルパのシステムがベースになっていくんじゃ無いかと。

で、オイラのゲームの状況ですが、

初回ガチャで見事に一歌を引き当てることができ、さらに溜めた石でレンを引き当てました。

ちょっとラッキー。

まずは、ライブをこなしつつレベルを上げて、サイドストーリーとエリアアイテムを買いそろえていく、というのがメインになると思います。

そして、上級者はいきなりハードから始める方が多いと思いますが(ハードをフルコンすると、無料石がもらえる)

ただ、ガルパの経験からすると、後で必ずコインが不足します。

素材は揃っているのに。

なので、オイラはEasyからフルコンしていって、コインを貯めることを忘れずにプレイしています。

でもまぁ、これでもコインは不足する(と思う)んですけどね。

あとはイベントとかの報酬でキャラを獲得して、☆3の頭数を増やすことですかね。

それができれば序盤は戦えるはず。

ちなみに、どのくらいのレベルまで対応出来るかというと、レベル26、27でクリアできる、という腕前です。

多分難易度マスターは無理(今のところは)

そう考えると、ガルパってまだまだぬるま湯なんだなぁって思いました。

テクテクライフがリリースされました。

このゲームは、ちょっと昔にサービス終了したテクテクテクテクの後継アプリゲームです。

町中を歩いて、通ったエリアに色を塗っていく、というゲームで、

テクテクテクテクではそれにRPG的な要素も含まれていて、フィールドの敵と戦ってレベルを上げてボスを倒していく、という内容だったのですが、

今回、テクテクライフになって、そう言ったバトル要素は全て排除されました。

純粋に地図を塗っていくゲームになっています。

むしろ、こっちのほうが良かったかもしれない。

ボスが強すぎて、勝てなくて、ランクが頭打ちになってしまうという状況に陥っていたので。

その一方で、目的を持って地図を埋めていくという楽しみが増えています。

タイムスタンプラリーという機能が追加されていまして、

目的地近くに行くとチェックすることができて、コンプリートするとなにかご褒美がもらえるかもしれません。

札幌では、東豊線スタンプラリーと札幌名所スタンプラリーが用意されています。

時間があるときにいかがでしょうか。

また、今回新たに追加された便利な機能として、

バックグラウンドでもGPS信号をトレースして予約塗りすることができます。

有料ですが。

時間制と月更新のサブスク方式があるのですが、出歩くことが多い人は明らかにサブスクを利用した方がお得です。

そして、この機能を利用すると、ドラクエウォークと同時プレイができます。

最近、毎日とにかく歩きまくる、というのを実践していまして、

ドラクエウォークもやっと上級職に転職できまして、

これでさらにお出かけの楽しみが増えるというものです。

ほんと最近歩きまくってるな・・・

【ぼっち】餃子×酒×肴 大衆酒場036(ゼロサンロク)

久しぶりの新店舗開拓。

いや、GoToイート利用したかったけど、1人で予約取れる店少ないのよ。

もっとぼっちに優しい世界になってほしい。

看板メニューは餃子。

タレは各種揃っておりますが、餃子自体に味が付いているので、まずは何もつけずにそのまま頂いて、残りは自分のお好きなように調合して頂くと良いと思います。

この餃子が本当に美味しくて、ビールが進む!

旬の鰹のたたきも頂きました。

いやー旨かった!

比較的早い時間からオープンしているのも嬉しいですね。

15:00開始はギリギリディナータイムなので。

今回は非常に満足でした。

【北海道大戦】じゃんけんアイコンをクラス化

じゃんけんアイコンを使いやすい様にクラス化させます。

    class BattleIcon
    {
        public enum Icon
        {
            Gu,
            Choki,
            Par
        }

        public enum Position
        {
            Attack,
            Deffence
        }

        private asd.TextureObject2D _image = null;
        private Icon _icon;
        private Position _position;
        private int _x;
        private int _y;
        private int width = 80;
        private int height = 80;

        public BattleIcon(Icon icon, Position pos)
        {
            _icon = icon;
            _position = pos;
            _image = new asd.TextureObject2D();
            if (pos == Position.Attack)
            {
                _y = 500;
                switch (icon)
                {
                    case Icon.Gu:
                        _x = 300;
                        _image.Texture = Singleton.ImageGu;
                        break;
                    case Icon.Choki:
                        _x = 450;
                        _image.Texture = Singleton.ImageChoki;
                        break;
                    case Icon.Par:
                        _x = 600;
                        _image.Texture = Singleton.ImagePar;
                        break;
                }
                _image.Position = new asd.Vector2DF(_x, _y);
            }
            else
            {
                _y = 250;
                switch (icon)
                {
                    case Icon.Gu:
                        _x = 300;
                        _image.Texture = Singleton.ImageGu;
                        break;
                    case Icon.Choki:
                        _x = 450;
                        _image.Texture = Singleton.ImageChoki;
                        break;
                    case Icon.Par:
                        _x = 600;
                        _image.Texture = Singleton.ImagePar;
                        break;
                }
                _image.Position = new asd.Vector2DF(_x, _y);
            }
        }

        public void AddLayer(asd.Layer2D layer)
        {
            layer.AddObject(_image);
        }

        public void Show()
        {
            switch (_icon)
            {
                case Icon.Gu:
                    _image.Texture = Singleton.ImageGu;
                    break;
                case Icon.Choki:
                    _image.Texture = Singleton.ImageChoki;
                    break;
                case Icon.Par:
                    _image.Texture = Singleton.ImagePar;
                    break;
            }
        }

        public void Hide()
        {
            _image.Texture = null;
        }

        public void OnMouse(asd.Vector2DF pos)
        {
            if (IsOnMouse(pos))
            {
                switch (_icon)
                {
                    case Icon.Gu:
                        _image.Texture = Singleton.ImageGu2;
                        break;
                    case Icon.Choki:
                        _image.Texture = Singleton.ImageChoki2;
                        break;
                    case Icon.Par:
                        _image.Texture = Singleton.ImagePar2;
                        break;
                }
            }
            else
            {
                switch (_icon)
                {
                    case Icon.Gu:
                        _image.Texture = Singleton.ImageGu;
                        break;
                    case Icon.Choki:
                        _image.Texture = Singleton.ImageChoki;
                        break;
                    case Icon.Par:
                        _image.Texture = Singleton.ImagePar;
                        break;
                }
            }
        }

        public bool IsOnMouse(asd.Vector2DF pos)
        {
            if (pos.X > _x && pos.X < width + _x
                && pos.Y > _y && pos.Y < height + _y)
            {
                return true;
            }
            else
            {
                return false;
            }
        }
    }

とりあえず、使いそうなメソッドをいくつか実装しました。

    class BattleScene : asd.Scene
    {
        protected override void OnUpdated()
        {
            asd.Vector2DF pos = asd.Engine.Mouse.Position;

            switch (_status)
            {
                case GameStatus.SelectDeffenceAction:
                    cycleProcessSelectDeffenceAction(pos);
                    break;
                case GameStatus.SelectAttackAction:
                    break;
                case GameStatus.ShowActionResult:
                    break;
            }
            if (asd.Engine.Mouse.LeftButton.ButtonState == asd.ButtonState.Push)
            {
                switch (_status)
                {
                    case GameStatus.SelectDeffenceAction:
                        break;
                    case GameStatus.SelectAttackAction:
                        break;
                    case GameStatus.ShowActionResult:
                        break;
                }
            }
        }

        private void cycleProcessSelectDeffenceAction(asd.Vector2DF pos)
        {
            _image_gu_deffence.OnMouse(pos);
            _image_choki_deffence.OnMouse(pos);
            _image_par_deffence.OnMouse(pos);
        }

とりあえず、こんなところか。

マウスカーソルを合わせることで色を変えるようにしました。

うん、今日もがんばった。

Pixel5とPixel4a(5G)が発表されましたね。

思ったより早かったね。

販売開始は10月15日、価格はPixel4(5G)が60,500円、Pixel5が74,800円です。

Pixel4a(5G)で何が変わったか

まず、当然のことながら、プロセッサーが5G対応のSnapdragon 765Gになりました。

あとは、背面に広角カメラがついて2眼になっています。

Pixel5で何が変わったか

プロセッサーはPixel4a(5G)と同じSnapdragon 765Gですね。

Pixel4にあったMotion Senseが無くなった模様です。

そのおかげで、Pixel4よりも安くなりました。

このシリーズ、毎回なにかしら尖った機能が搭載されているのですが、

おそらく、今回はバッテリーシェアがそれに当たると思います。

Pixel5から他の端末に無線で充電できる機能です。

そのためか、Pixel4の弱点だったバッテリー容量も大幅に強化されています。

iPhoneより先に5Gに対応したことで大きくアドバンテージを取ったことになりますが、

そうなると、次の新型iPhoneの発表も期待されますね。

まぁ、オイラはPixel4a買ったばかりだから。

【ラズパイ】リモートでカメラのプレビュー表示

いや、今回は結構ハマった。

これが半日頑張った成果だ。

まずはラズパイ側。

import base64
import cv2
import json
import os
import sys
import urllib.parse
import time
import threading

from http.server import BaseHTTPRequestHandler
from http.server import HTTPServer
from http import HTTPStatus

PORT = 8000

cap = cv2.VideoCapture(0)

def __main__():
    thread = threading.Thread(target=httpServe)
    thread.start()
    
    try:
        while cap.isOpened():
            time.sleep(1)
    except KeyboardInterrupt:
        return

def httpServe():
    handler = StubHttpRequestHandler
    httpd = HTTPServer(('',PORT),handler)
    httpd.serve_forever()

class StubHttpRequestHandler(BaseHTTPRequestHandler):
    server_version = "HTTP Stub/0.1"

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)

    def do_GET(self):
        enc = sys.getfilesystemencoding()

        _, img = cap.read()
        resized_img = cv2.resize(img, (480, 320))
        _, encoded_img = cv2.imencode('.jpg', resized_img, [int(cv2.IMWRITE_JPEG_QUALITY), 30])
        dst_base64 = base64.b64encode(encoded_img).decode('utf-8')

        data = {
            'image': 'data:image/jpg;base64,' + dst_base64
        }

        encoded = json.dumps(data).encode()

        self.send_response(HTTPStatus.OK)
        self.send_header("Content-type", "text/html; charset=%s" % enc)
        self.send_header("Access-Control-Allow-Origin", "null")
        self.send_header("Content-Length", str(len(encoded)))
        self.end_headers()

        self.wfile.write(encoded)     

__main__()

そしてクライアント側。

<!DOCTYPE html>
<html>
<head>
  <title>My first Vue app</title>
  <script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
  <script src="vue.min.js"></script>
  <script src="jquery-3.5.1.slim.min.js"></script>
</head>
<body>
  <div id="app">
      <image id="camera" src="" />
  </div>

  <script>
    var app = new Vue({
      el: '#app',
      data: {
        timer: null,
      },
      created: function() {
        self = this;
        this.timer = setInterval(function() {self.onLoad()}, 50)
      },
      methods: {
        onLoad: function() {
            axios.get('http://pi4.local:8000').then(function(response){
                $("#camera").attr('src', response.data.image);
            }).catch(function(error){
            });
        }
      }
    })
  </script>
</body>
</html>

まず、サーバ側の説明。

今回は、すでに使った実績のある、HTTPで通信を行います。

もっと下位層のプロトコルを使うと、もっと効率よくデータの送信ができるのですが、その分、扱いも難しくなります。

HTTPはTCP/UDPよりも、データのやりとりが多くなるので、少しモッサリ感がありますが、扱いが簡単になります。

実際、今回はブラウザで表示させているので!

カメラで撮影し、それを画像に落とすところまでは今まで通りですが、

今回はHTTPで送信するために、Base64に変換し、Jsonに載せて送信します。

Base64の頭にある「data:image/jpg;base64」というのは、このデータはJpegですよ、ということを示す文字列で、これがないと、受け手側は何のデータか判断できません。

「Access-Control-Allow-Origin」はCORS対策です。

例えばクロームなのでは、同じドメインでなければ画像が開けない、という制約がありまして、それを判断しているのが、リクエストヘッダーのOriginと、レスポンスヘッダーのAccess-Control-Allow-Origin。

この二つの値が一致しないと画像はエラーで表示されなくなります。(ただしブラウザによる)

今回はChrome側のOriginがnullだったので、それに合わせました。

FireFoxとかだったらまた話が変わってくるかもしれない。

続いて、クライアント側。

サクッと作成するために、Vue.jsを使用しました。

使用しているライブラリはaxios、jQueryです。

Laravelと同じような構成にしました。

画面には<div id=”app”>と<image id=”camera”>のみです。

やっていることは単純で、画面が作成されたらcreatedメソッドが実行されて、onLoad()を周期的にコールするようにしています。

50という数字を小さくすればヌルヌルになりますし(ただしラズパイ側の負荷が大きくなる)、大きくすればカクカクになります。

今回はラズパイにクーラーつけているから大丈夫だけど、ラズパイZeroでこの負荷はやばいと思う。

そして、レスポンスの中のBase64をimageのsrcに入れれば画像が表示されます。

これを早いサイクルで実行・画像更新することで、動画のように見せることが出来ます。

今回はWebカメラみたいに仕上がりましたが、HTTPが使えるならばクライアントは何だってできます!

openGLって今更やる必要があるのかって思った。

openTKでハマってしまったのを前に記事で書いたのですが、

本気でやるなら書籍を買うしかないと思って探しては見た物の、あまりピンとこないというか、アレだったので、

そんなときに見つけたのがこのページ。

細かい所は上のページを読んで貰うとして、

結論から言うと、

openGLの理論を学ぶとするのはいいけれど、

単に3Dアプリを作りたいと言うだけならば、既存のプラットフォームを使った方が早い。

例えばUnityとか。

openGLで悩むより、Unityの勉強を始めた方がいい。

そういえば、Unityの書籍を使った勉強、途中で止まっていたけど、

再開してみるかな。

【ダイエット支援】もっと具体的な設計をしなくちゃいけなくて

たぶん、前回の記事の内容だけではコーディングはまだできなくって、

もっと具体的に動作の仕組みを考えなくちゃいけないと思いまして。

UIの動き

  • 文字を入力すると、データベースから入力候補を取得し、表示する
  • 入力した内容が入力候補と一致すると、その栄養素値が自動で入力される
  • 入力を空にすると、入力候補も空にする

テキスト窓に入力したかどうかはVue.jsではv-on:changeで処理を起動することができるみたいなので、これを使用します。

データベース

基本的には入力済みの食品・栄養素の情報(テンプレート)からデータを抽出して候補がある物から選択するという形にしたいと思います。

ただ、そう言った食品や栄養素の情報を全部用意するのは大変なので、ユーザーが入力した情報を記憶しておいて(ヒストリ)、管理者が正式データとして登録する、という仕組みにしたいと思います。

なので、管理者画面が必要になりますね。

データベースはテンプレートとヒストリの二つ用意しておきたいと思います。

ここらへん、本当はもっと詰めなくちゃいけない所ですが、今回はあとでどうにでもできるように、リスクが少ない方法を選択したいと思います。

あとでデータベース構成を変えるとなるとコードの修正も大変なので。

なので、今後の作業はこんな感じです。

  • データベースの構築
  • テンプレートからデータを入力する処理
  • ユーザーが入力したデータをヒストリに保存する処理
  • 管理者がヒストリからテンプレートに移す処理

よし、これでいきましょう。

【COCOS2D-X】タッチ処理を使用する。

さて、今回はタッチ処理を試してみたいと思います。

タッチ処理はスマホ専用の処理なので、Windowsでは動かないので、スマホで動作確認します。

で、タッチした座標を画面に表示させたいと思います。

    auto listener1 = EventListenerTouchOneByOne::create();
    listener1->onTouchBegan = [this](Touch* touch, Event* event)->bool
    {
        auto str = String();
        str.appendWithFormat("Touch (%f %f)", touch->getLocation().x, touch->getLocation().y);
        label->setString(str.getCString());
        return true;
    };
    _eventDispatcher->addEventListenerWithSceneGraphPriority(listener1, this);

タッチ処理はイベントリスナーを使用するのですが、

EventListenerTouchOneByOneとEventListenerTouchAllAtOnceがあるのですが、前者はシングルタッチ、後者はマルチタッチのようです。

使用するハンドラ名が若干違うようです。

今回はシングルタッチを使用します。

で、今回初めてC++のラムダ式を使ったのですが、

[]はキャプチャといって、ラムダ式内に持っていく変数を指定するみたいなんですよね。

座標を表示するラベルなんですが、

ローカルにLabelオブジェクトを定義して[&label]って書いてもエラーで動かなかったので、

今回はサンプルコードに従って、labelはprivate変数に定義し、キャプチャには[this]とします。

こうすることでprivateのlabelオブジェクトを使用することができました。

あとは、引数touchからx,y座標をラベルに表示させる。

スマホだからか、画像のクリッピング処理がWindowsとは動きが違ってたんですよね。

ちょっとここは要調査ですわ。

もしかしたら、Windows用とスマホ用に画像を2種類用意しないといけないかもしれん。

自分、ぼっちですが何か?