taki のすべての投稿

【ぼっち】いろはにほへと白石店

1人でもGoToイートが利用できることに重点を置いています。

居酒屋チェーン店ですが、LINEのクーポンを使えば、飲み放題が安くなります。

中トロの刺身が期間限定メニューで500円。

これでも刺身では一番安いです。

牛串。

間に挟まっているのはニンニクでした。

いや、美味しかった。

【COCOS2D-X】背景画像を設置。

画像はWeb検索して、見つけたフリー素材を使用しました。

で、これ多分、普通に表示するだけだと、画面からはみ出してしまうので。

これを上手く画面に収まるようにしたい。

見た感じ、画像の高さがはみ出ているので、高さの表示を画像に合うように拡大率を計算して、画像を縮小させたいと思います。

    auto sprite = Sprite::create("ID003_Western-Castle_noon.jpg");
    if (sprite == nullptr)
    {
        problemLoading("'ID003_Western-Castle_noon.jpg'");
    }
    else
    {
        // position the sprite on the center of the screen
        sprite->setPosition(Vec2(visibleSize.width/2 + origin.x, visibleSize.height/2 + origin.y));

        // add the sprite as a child to this layer
        this->addChild(sprite, 0);
    }
    auto scaleRate = visibleSize.height / sprite->getContentSize().height;
    sprite->setScale(scaleRate);

    auto str = String();
    str.appendWithFormat("width %f height %f", sprite->getContentSize().width, sprite->getContentSize().height);
    label->setString(str.getCString());

この画像の範囲をベースにして、画面を作っていきましょうか。

あ、画面をタップしたときにエフェクトかかるようにしたいなぁ。

次回やります。

【目の疲れ対策】部屋の中の明るさも重要だと言うこと

明るければ良いってもんじゃ無いんだね。

オイラが使用しているNEC製のLEDシーリングライトはリモコンで部屋の明るさを4段階に調整できるんです。

今までは、ずっと一番明るい状態で使用していたんですが、

こないだ、少し明るさを暗くしてパソコン作業をしていたところ、いつもより目の疲れが無かったんですよね。

それで、部屋の明るさをいろいろ試してみた結果、以下のことが分かりました。

  • パソコン部屋の窓はカーテン締め切り
  • 午前は一番くらい状態にする
  • 午後は少し明るいくらいにする
  • 夜はディスプレイを暖色にし、部屋も暗めにする

ディスプレイの画面を暖色にするには、f.luxというフリーソフトを使用しています。

https://justgetflux.com

これを常駐させて、起床時間や入眠時間を設定すれば、それに合わせて、例えば、寝る前の時間には暖色に変更する、といった設定ができるようになります。

あと、スマホの画面も、夜は暖色系にしてますし、夜は画面の明るさを暗めにしています。

そのようにしてからは、少し寝付きが良くなったような気がしています。

皆さんも生活スタイルに合わせて部屋の明るさを調節してみるのも良いかもしれないよ。

【クラフトピア】小麦無限栽培・収穫機構

まだ動作は不安定だけど、とりあえず機能したので。

画面では2×2のエリアに小麦畑を設置し、中央にスプリンクラーを設置します。

この状態で小麦を刈り取ると、自動的に水を撒いて、小麦が成長、再び刈り取ることができます。

この刈り取った小麦を、チェストにアブソーバーを取り付けると、アブソーバーが小麦を吸い込んでチェストに格納してくれます。

あとは自動で刈り取る機構ですが、回転のこぎりを使用します。

ただ、壁を取り付けないと、勝手に変な方向に進んでしまうため、壁で囲っておく必要があります。

今回は壁が破壊されないようにトタンの壁を使用しましたが、他の壁ではどうなんでしょうかね?

これが意外なほど機能して、小麦が生長したところから回転のこぎりが刈り取ってくれるんです。

隣で農地を作成し、他の作物を栽培しながら過ごしていると、小麦がいつの間にか溜まっている、という寸法です。

もしかしたらスプリンクラーの設置位置を増やしたり、位置を調整すれば、アブソーバーの位置を調整すれば、もっと広くできるかもしれません。

ただ、チェストを回収すると、アブソーバーが消えるの、なんとかしてくれませんか?

まぁアブソーバー自体がテスト中だからね・・・

もうちょっと研究してみます。

【テクテクライフ】さっぽろ羊ヶ丘展望台

歩いて行ける距離だと思ったので、歩いて行きました。

しんどかった。

みなさんはバスでの移動をオススメします。

バスで行く場合は地下鉄福住駅から直通のバスがあります。

クラーク像、けっこうかっこいいね。

放牧されていた羊。

近くに行くと思った以上に鼻息が荒いです。

フンフンいっているのが聞こえます。

レストランではジンギスカン食べ飲み放題ができます。

1人4100円。

比較的お手頃なお値段ではないでしょうか。

【ラズパイ】【カメラ】プレビュー画面をラズパイから取得・表示(修正)

この記事のソースが余りにも冗長すぎるので、書き換えました。

こんな感じです。

CONTENT_TYPE = {'.html': 'text/html; charset=utf-8', '.txt': 'text/plain; charset=utf-8', '.js': 'text/javascript', '.json': 'application/json',
        '.jpeg': 'image/jpeg', '.jpg': 'image/jpeg', '.png': 'image/png', '.gif': 'image/gif',
        '.css':'text/css'}



    def do_GET(self):
        parsed = urlparse(self.path)
        if parsed.path == '/Streaming':
            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)
        elif parsed.path.endswith('/'):
            self.send_response(HTTPStatus.OK)
            with open('index.html',mode='br') as f:
                data = f.read()
            self.send_header("Content-type", "text/html; charset=utf-8")
            self.end_headers()
            self.wfile.write(bytes(data))
        else:
            self.send_response(HTTPStatus.OK)
            filepath = '.' + parsed.path
            with open(filepath, mode='br') as f:
                data = f.read()
            self.send_header("Content-type", CONTENT_TYPE[pathlib.Path(filepath).suffix])
            self.end_headers()
            self.wfile.write(bytes(data))

まず、URLが”/”の場合はindex.htmlを返します。

そして、URLが”/Streaming”の場合はカメラの映像をbase64で返します。

それ以外の場合(今回で言うと、jsファイル達)、URLで指定されたファイル名と同じファイルを返します。

ただ、その場合、content-typeを正しいものにしないとブラウザが正しく動いてくれないので、ファイル拡張子に対応する適切なcontent-typeを設定するようにしています。

それを対応づけているのがCONTENT_TYPEです。

こうすることで、今後jsファイル以外のものにも対応出来ます。

一般的なHTTPサーバに比べれば不十分ですが、今回目指しているのはそれではないので、こんなもんで十分でしょう。

ソースはgitHubに公開しました。

https://github.com/takishita2nd/RemoteCamera

【プロジェクトセカイ】一応全曲プレイ一巡して思ったこと

自分は一歌推しです。

一応、今実装されている曲のEXまでの譜面を一通りプレイ終わりました。

今はほぼ毎日新曲が追加実装されているのですが。

ストーリーはなかなか精神えぐってきます。精神疾患者には少々辛い。

楽曲レベルは、ほぼガルパと同じ基準だと思って問題無いでしょう。

マスタークラスになると平気で難易度30以上が出てきますが、おそらくガルパの六兆年(レベル29)より難しいと思います。

クリアできる気がしません。

ライブのリトライ機能はなかなか神仕様ですね。

プレイ中にリトライすると、直接、曲の開始に戻ることができるだけでも嬉しいのですが、

ライブポイント(ブースト)はリザルト画面で消費されるので、リトライしてもリタイヤしてもポイントは減りません。

クリアできるまで何度でも挑戦できます。できるものなら。

ノーツのアイコンが横棒であるためか、他のリズムゲームより目が疲れる気がします。

スキンのカスタマイズとかできれば良いのですが。

老眼には少々きついかもしれません。

バーチャルライブもなかなか良いです。

満員で入れないときはブチ切れそうになりますが。

【北海道大戦】じゃんけんバトルを実装

実際にじゃんけんバトルを実装していきます。

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

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

        private void cycleProcessSelectDeffenceAction(asd.Vector2DF pos)
        {
            if(_player == Player.Deffence)
            {
                _image_gu_deffence.Show();
                _image_choki_deffence.Show();
                _image_par_deffence.Show();
                _image_gu_deffence.OnMouse(pos);
                _image_choki_deffence.OnMouse(pos);
                _image_par_deffence.OnMouse(pos);
            }
            else
            {
                var r = Singleton.Random;
                switch(r.Next(0, 3))
                {
                    case 0:
                        selectedDeffece = BattleIcon.Icon.Gu;
                        break;
                    case 1:
                        selectedDeffece = BattleIcon.Icon.Choki;
                        break;
                    case 2:
                        selectedDeffece = BattleIcon.Icon.Par;
                        break;
                }
                _status = GameStatus.SelectAttackAction;
            }
        }

        private void cycleProcessSelectAttackAction(asd.Vector2DF pos)
        {
            if (_player == Player.Attack)
            {
                _image_gu_attack.Show();
                _image_choki_attack.Show();
                _image_par_attack.Show();
                _image_gu_attack.OnMouse(pos);
                _image_choki_attack.OnMouse(pos);
                _image_par_attack.OnMouse(pos);
            }
            else
            {
                var r = Singleton.Random;
                switch (r.Next(0, 3))
                {
                    case 0:
                        selectedAttack = BattleIcon.Icon.Gu;
                        break;
                    case 1:
                        selectedAttack = BattleIcon.Icon.Choki;
                        break;
                    case 2:
                        selectedAttack = BattleIcon.Icon.Par;
                        break;
                }
                _status = GameStatus.ShowActionResult;
            }
        }

        private void cycleProcessShowActionResult(asd.Vector2DF pos)
        {
            _attackResult.SetIcon(selectedAttack);
            _attackResult.Show();
            _deffenceResult.SetIcon(selectedDeffece);
            _deffenceResult.Show();
        }

        private void onClickMouseSelectDeffenceAction(asd.Vector2DF pos)
        {
            if (_player == Player.Deffence)
            {
                if (_image_gu_deffence.IsOnMouse(pos))
                {
                    selectedDeffece = BattleIcon.Icon.Gu;
                }
                else if (_image_choki_deffence.IsOnMouse(pos))
                {
                    selectedDeffece = BattleIcon.Icon.Choki;
                }
                else if (_image_par_deffence.IsOnMouse(pos))
                {
                    selectedDeffece = BattleIcon.Icon.Par;
                }
                _image_gu_deffence.Hide();
                _image_choki_deffence.Hide();
                _image_par_deffence.Hide();
                _status = GameStatus.SelectAttackAction;
            }
        }

        private void onClickMouseSelectAttackAction(asd.Vector2DF pos)
        {
            if (_player == Player.Attack)
            {
                if (_image_gu_attack.IsOnMouse(pos))
                {
                    selectedAttack = BattleIcon.Icon.Gu;
                }
                else if (_image_choki_attack.IsOnMouse(pos))
                {
                    selectedAttack = BattleIcon.Icon.Choki;
                }
                else if (_image_par_attack.IsOnMouse(pos))
                {
                    selectedAttack = BattleIcon.Icon.Par;
                }
                _image_gu_attack.Hide();
                _image_choki_attack.Hide();
                _image_par_attack.Hide();
                _status = GameStatus.ShowActionResult;
            }
        }

        private void onClickMouseShowActionResult(asd.Vector2DF pos)
        {
            _attackResult.Hide();
            _deffenceResult.Hide();
            _status = GameStatus.SelectDeffenceAction;
        }

シーンの状態は、

  1. 防御側の選択
  2. 攻撃側の選択
  3. 結果の表示

の順で遷移していきます。

防御側選択状態では、プレイヤーが防御側ならば、じゃんけんアイコンを選択します。プレイヤーが攻撃側ならば、ランダムで相手が何を選択したかを決定します。

攻撃側選択状態は、防御側選択の逆で、プレイヤーが攻撃側ならば、じゃんけんアイコンを選択、プレイヤーが防御側ならば、ランダムで相手が何を選択したかを決定します。

そして最後に攻撃側と防御側が選択したアイコンを表示し、じゃんけんの結果を表示します。

まぁ、ここまでは表示をどうするかの処理が中心になります。

次回はじゃんけんの結果を処理する実装を行います。

【テクテクライフ】旭山記念公園と北海道神宮

思ったより難しくありませんでした。

地下鉄円山公園駅のバスターミナルから直通のバスが走ってました。

回収完了。

なかなか景色が良いです。

ちなみに、北海道神宮(円山公園内)もチェックポイントがあったので、ついでに回収しました。

リスがおりました。

【ラズパイ】【カメラ】プレビュー画面をラズパイから取得・表示

前回は、Webページをローカルで作成して、そこからブラウザに表示させていたのですが、

今回はWebページをラズパイに設置して、ブラウザからラズパイにアクセスすることによってプレビュー画面を表示させたいと思います。

動作はURLのパスによって変えます。

パスが”/”ならば、Webページを、”/Streaming”ならカメラの画像を返すようにします。

まず、Pythonのコードはこうなりました。

import base64
import cv2
import json
import os
import sys
import time
import threading

from http.server import BaseHTTPRequestHandler
from http.server import HTTPServer
from http import HTTPStatus
from urllib.parse import urlparse

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):
        parsed = urlparse(self.path)
        if parsed.path == '/Streaming':
            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)
        elif parsed.path == '/vue.min.js':
            self.send_response(HTTPStatus.OK)
            with open('vue.min.js',mode='br') as f:
                data = f.read()
            self.send_header("Content-type", "text/javascript")
            self.end_headers()
            self.wfile.write(bytes(data))
        elif parsed.path == '/jquery-3.5.1.slim.min.js':
            self.send_response(HTTPStatus.OK)
            with open('jquery-3.5.1.slim.min.js',mode='br') as f:
                data = f.read()
            self.send_header("Content-type", "text/javascript")
            self.end_headers()
            self.wfile.write(bytes(data))
        else:
            self.send_response(HTTPStatus.OK)
            with open('index.html',mode='br') as f:
                data = f.read()
            self.send_header("Content-type", "text/html; charset=utf-8")
            self.end_headers()
            self.wfile.write(bytes(data))

__main__()

無駄にでかくなった気がする。

というのも、使用しているjsファイルもラズパイからGETしようとブラウザが動くので、jsファイルを送るように作成しないといけないのです。

めんどくさいから、他のライブラリを使用することも考えないといかんなぁ。

続いて、html側。

こちらはそんなに難しくはない。

URLを変えるだけなので。

<!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/Streaming').then(function(response){
                $("#camera").attr('src', response.data.image);
            }).catch(function(error){
            });
        }
      }
    })
  </script>
</body>
</html>

これで動作しました。