アナログCPU:5108843109

ゲームと音楽とプログラミング(酒と女とロックンロールのノリで)

('ω') < イザユケエンジニャー

SQX #5:碧照ノ樹海/小さな果樹林 その2

プレイ3日目。

まず、碧照ノ樹海のB2も地図のほとんどが埋まったので、小さな果樹林のFOE、狂乱の角鹿に挑戦。
戦闘前の写真を撮り忘れましたが、21ターンでなんとか撃破しました。
f:id:honey8823:20180805212329j:plain:w400
TPが足りない…

鹿のドロップ素材からハーフアーマー系の装備ができました。
ハーフアーマー系はリーパー専用なので(あとは3人がフルアーマー系、1人が非アーマー系)
もちろんこうなる。
f:id:honey8823:20180805213043j:plain:w300

これで小さな果樹林を制覇したので、気持ちよく碧照ノ樹海へ戻ります。

続きを読む

SQX #1:世界樹の迷宮Xはじめました(前編)

8月2日、待ちに待ったSQX発売日でした。

今回はセブンネットで購入、店舗特典はネイピアさん(姉)のクリアファイル。
f:id:honey8823:20180803140530j:plain:w400

ちなみにクリアファイル裏側はこんな感じ。
f:id:honey8823:20180803140642j:plain:w300

カードリッジ。
f:id:honey8823:20180803140626j:plain:w400

3DSのソフト起動前タイトル部分。
f:id:honey8823:20180803140743j:plain:w400

起動すると一度この画面で何分も動かなかったのですが、
再起動してみると一瞬でした。
f:id:honey8823:20180803140834j:plain:w400

続きを読む

ツールチップを自前で実装

したのでメモっておく。

つーかはてなブログCSSもJSも記事内で書けるのかスゲー。
ということで実装サンプルも置いておく。

↓実装サンプルここから
================================
ここにマウスを乗せるとピョッと出てくる
================================
↑実装サンプルここまで

ツールチップは結構いろいろな方法で実現できるようですが(末尾の参考文献を参照のこと)
今回は以下のような感じに落ち着きました。

<HTML>

<span class="tooltip-event" data-tooltip="ピョッと出てくるやつの中身">
  ここにマウスを乗せるとピョッと出てくる
</span>

特に変わったところはなし。
spanでなく他のタグ(divでもaでもテーブルでも)に入れ替えてもOK。
ツールチップの中身は改行入っててもOK。
ものによるけどタグもOK。
逆に言えば、タグを文字列として出したい場合はエスケープが必要になる。

CSS

.tooltip-body {
  background: #666;
  color: #fff;
  width: 400px;
  padding: 10px;
  position: absolute;
  text-align: left;
  z-index: 0;
  display: none;
}

ツールチップ部分の見た目。
基本的に好きに変えられる。
周りのコンテンツに合わせて、z-indexは調整する必要あり。
また、フェードインに使うのでデフォルトは「display: none;」にしておく。

jQuery

$(".tooltip-event").hover(
    function(e) {
        var text = $(this).attr("data-tooltip");

        if (text != ""){
            var spantag = $("<span></span>", {id:"activetooltip", "class": "tooltip-body"});
            spantag.html(text.replace(/\r\n|\r|\n/g, "<br>"));
            $("body")[0].appendChild(spantag[0]);
            $("#activetooltip").css(
                {
                    'top' : $(document).scrollTop()  + e.clientY + 10,
                    'left': $(document).scrollLeft() + e.clientX + 10,
                }
            );
            setTimeout(function(){
                $("#activetooltip").animate({opacity: 'show'}, {duration: 200, easing: 'swing'});
            }, 300);
        }
    },
    function() {
        $("#activetooltip").remove();
    }
);

本体。
「tooltip-event」クラスを持つ要素にマウスが乗っかると動く。

以下に抜粋したところが、乗っかったときの処理。

// ツールチップの中身に入る文字列を抜き出してくる
var text = $(this).attr("data-tooltip");

// 抜き出した文字列が空でないときだけツールチップを出す
if (text != ""){
    // ツールチップ本体となるspanタグを生成
    var spantag = $("<span></span>", {id:"activetooltip", "class": "tooltip-body"});
    
    // spanタグに、改行コードをbrタグに変換した文字列を突っ込む
    spantag.html(text.replace(/\r\n|\r|\n/g, "<br>"));
    
    // bodyタグの末尾に加える
    $("body")[0].appendChild(spantag[0]);
    
    // 表示位置を調整する(スクロール位置+マウス位置+右と下に10px)
    $("#activetooltip").css(
        {
            'top' : $(document).scrollTop()  + e.clientY + 10,
            'left': $(document).scrollLeft() + e.clientX + 10,
        }
    );
    
    // 300ミリ秒後に、200ミリ秒かけてフェードイン
    setTimeout(function(){
        $("#activetooltip").animate({opacity: 'show'}, {duration: 200, easing: 'swing'});
    }, 300);
}

抜粋するほどでもない気はしますが、
マウスが外れたときの処理がこちら。

// activetooltipというIDの要素を削除
$("#activetooltip").remove();

参考文献

setIntervalの挙動で勘違いしていたこと

setIntervalを単なる時間区切りループ的なものと認識していたらつまづいた話。(初心者丸出し)
※コードはjQueryで書いています

以下のコード、
「start」→「roop:0」→…「roop:4」→「end」
と動くのかと思ったら、
「start」→「end」→「roop:0」→…「roop:4」
だった。

$(function(){
    console.log("start");

    var i = 0;
    var timer = setInterval(function(){
        console.log("roop:" + i);
        i ++;
        if (i >= 5){
            clearInterval(timer);
        }
    }, 500);

    console.log("end");
});

setIntervalはざっくり言うと「インターバルタイマーをセットする処理」。
タイマーをセットするだけのおしごとなので、
セットし終わったらその実行がどうとか関係なく次の処理に移ります。
うーんなるほど…。
ループ的に使いたければ、clearIntervalしている部分にその後実行したい処理を書く必要があるわけですね。

$(function(){
    console.log("start");

    var i = 0;
    var timer = setInterval(function(){
        console.log("roop:" + i);
        i ++;
        if (i >= 5){
           console.log("end");
            clearInterval(timer);
        }
    }, 500);
});

参考文献
setIntervalとsetTimeoutを調べた結果余分なことになった - 三等兵

新しいウインドウを開き、そこに値を送信する

まずは結論

<HTML:親ウインドウ>

<a href="#" onclick="pushValue();">ウインドウを開いて値を送信する</a>

<HTML:子ウインドウ>

<input type="hidden" id="testid" value="">

jQuery

var obj; // 開いたウインドウを扱うためのオブジェクト変数
function pushValue(){
    // ウインドウオブジェクトが存在しない場合・閉じられている場合は新たに開く
    if (!obj || obj.closed){
        // ウインドウを開く(/childwindow.htmlを、横500px×縦500pxで)
        obj = window.open("/childwindow.html", "child", "width=500, height=500");
        
        // 書き換えたい要素が存在すれば(=書き換え部分が読み込まれれば)書き換えを行う
        // 500ミリ秒ごとにリトライ
        var timer = setInterval(function(){
            if ($("#testid", obj.document) != undefined){
                sendValue();
                clearInterval(timer);
            }
        }, 500);
    }
    // ウインドウが既に開かれている場合は要素の書き換えを行う
    else{
        sendValue();
    }
}
function sendValue(){
    $("#testid", obj.document).val("testvalue");
}

と、こんな感じでの実装となりました。
以下はjQuery部分のメイキング。

ウインドウを開く部分

「window.open(開くHTMLのパス, 名前, スタイル)」で
別ウインドウを開くことができます。

jQuery

function pushValue(){
    window.open("/childwindow.html", "child", "width=500, height=500");
}

まずはこれで開くことを確認。
ちなみに、名前(上記の例では「child」)を消すと、
リンクを押すたび新しく別のウインドウが開くようになります。

とりあえずこれだけで特に問題なく開きますが、
この後このウインドウを操作することになるので、
オブジェクト変数に入れるようにしておきます。

jQuery

var obj;
function pushValue(){
    obj = window.open("/childwindow.html", "", "width=500, height=500");
}

ウインドウオブジェクト用の変数「obj」を用意しました。

これでウインドウを開ける部分はOK。

値を送る部分

※ローカルでは動かない可能性があるので、
 どこかのサーバーで試す必要があるかもしれません
 (といってもxampp環境はOKでした)

まず、子ウインドウで値を送るには以下のようにすればOK…らしい。

$(obj.document).find('#testid').val('testvalue');

が、window.openの直後に追加してみても動かない。

とりあえず分割して試してみようと、一旦
リンクも関数も「子ウインドウを開く」と「値を送る」の操作に分けてみると動いた。

しばらく考えてから気付いた。
window.openした後、さらに子ウインドウの読み込みが終わってから送らないとダメか…。

とりあえず、試しに「window.openの3秒後に値を送信」とすれば動いた。

jQuery

var obj;
function pushValue(){
    obj = window.open("/childwindow.html", "child", "width=500, height=500");
    setTimeout(function(){
        $(obj.document).find('#testid').val('testvalue');
    },3000);
}

でも読み込みは一瞬で終わるかもしれないし3秒で間に合わないかもしれない。
ので、
「#testidが存在するかどうかを定期的にチェックし、存在すれば送信」
という処理にしてみた。

jQuery

var obj;
function pushValue(){
    obj = window.open("/childwindow.html", "child", "width=500, height=500");
    var timer = setInterval(function(){
        if ($("#testid", obj.document) != undefined){
            $("#testid", obj.document).val('testvalue');
            clearInterval(timer);
        }
    }, 500);
}

必要に応じて整える

ウインドウが既に開かれているかどうかを判定し
開いていなければこれまで書いてきた一連の流れを行い、
開いていればすぐ値を書き換え(つまり後から親ウインドウで操作)…としたかったので、
さっきのかたまりを丸ごとif文で分けた。

タイムアウトとかのロジックを入れた方がいいケースもあるかも。

jQuery

var obj;
function pushValue(){
    if (!obj || obj.closed){
        obj = window.open("/childwindow.html", "child", "width=500, height=500");
        var timer = setInterval(function(){
            if ($("#testid", obj.document) != undefined){
                sendValue();
                clearInterval(timer);
            }
        }, 500);
    }
    else{
        sendValue();
    }
}
function sendValue(){
    $("#testid", obj.document).val("testvalue");
}

JS/jQueryを使って、動的に生成したURLへ遷移させる

3種類考えたので全部書いとく。
「動的に生成したURL」ってタイトルだけどその生成部分は重要じゃないので普通に固定値で書いてる。

location.hrefを使う方法

<HTML>

<a href="#" onclick="redirect();">ダミーリンク</a>

jQuery

function redirect(){
    location.href = "http://example.com";
}

簡単。
でもこれを使いたくないパターンがあったので別解を作った。

aタグを書き換える方法

<HTML>

<a href="#" onclick="redirect();" id="linktag">ダミーリンク</a>

jQuery

function redirect(){
    $("#linktag").attr("href", "http://example.com");
}

この方法ならほかの属性も変更できる。
target="_blank"したりとか。

ただ、aタグの書き換えは行われるけどその後クリックした扱いにならないことがあったので、
その場合は例えば以下のようなのを追加しました。

$("#linktag").attr("onclick", "");
$("#linktag")[0].click();

「.click()」で強制的にクリックさせるけど、
その時にonclickが再発動しないように空にしておく…という感じ。

location.hrefも既存タグ変更もやりたくないケースもあるかもしれないので
さらに別解を作った。

新しいaタグをこっそり作ってそっちを押したことにする方法

<HTML>

<a href="#" onclick="redirect();">ダミーリンク</a>

jQuery

function redirect(){
    var virtuallink = $("<a></a>", {href: "http://example.com", id: "virtuallink"});
    virtuallink.text(" ");
    $("body")[0].appendChild(virtuallink[0]);
    $("#virtuallink")[0].click();
}

要するに

<a href="http://example.com" id="virtuallink">

というタグをbodyの一番最後にくっつけて、それにクリックイベントを起こす方法です。

あんまりかっこよくないので、
生成したオブジェクトそのものに対してclickできないかと試したけど動作せず。
jQueryの最後の行を「 virtuallink[0].click(); 」としても動くのに、
 その前の「 $("body")[0].appendChild(virtuallink[0]); 」を削除すると動かない)

zipファイルを生成する

PHPでzipファイルを作る機会があったのでメモ。

関数化したので次からこれ使おう。

<?

/*
 * makeZip
 *
 * @param files    zipに詰めたいファイル情報の配列
 *                 ただし、ファイル情報は
 *                   array('file_path' => "ファイルパス", 'zip_file_name' => "zip内でのファイル名")
 *                 という配列で表す
 * @param zip_path zipのパス
 * @return 正常ならtrue、失敗したらfalse
 */
function makeZip($files, $zip_path, $mode = 0755)
{
    // 既にファイルが存在する場合は削除
    if (file_exists($zip_path))
    {
        @unlink($zip_path);
    }

    // ZipArchiveはPHP5.2以降なら標準で使用可能
    $zip = new ZipArchive();

    // オープンできなければエラー終了
    if ($res = $zip->open($zip_path, ZipArchive::CREATE) !== true)
    {
        return false;
    }

    // 渡されたファイルを順番にzipに詰める
    foreach ($files as $file)
    {
        // 詰めるのに失敗したらエラー終了
        if ($zip->addFile($file['file_path'], $file['zip_file_name']) == false)
        {
            $zip->close();
            @unlink($zip_path);
            return false;
        }
    }

    // クローズしてパーミッション変更
    $zip->close();
    chmod($zip_path, $mode);

    // 正常終了
    return true;
}

呼び出し部分の例

<?

$file_list = array();

$file_list[] = array(
    'zip_file_name' => "test01.jpg",
    'file_path'     => "./files/test01.jpg",
);
$file_list[] = array(
    'zip_file_name' => "test02.jpg",
    'file_path'     => "./files/test02.jpg",
);

$this->makeZip($file_list, "./zip/test.zip");