気ままなタンス*プログラミングなどのノートブック

プログラミングやRPGツクール、DTM等について、学んだことや備忘録をアウトプットとして残し、情報を必要としている誰かにとって「かゆいところに手が届く」ツールでありたいという願いを込めつつ、記事を書きます。

【読書メモ】“内向型”のための雑談術 自分にムリせずラクに話せる51のルール

昔からずっと、雑談がうまくできない。 友人同士や職場の同僚同士なら、まだそれでも良かった。

しかし、最近はよくお客さん先に訪問するようになったため、 この「雑談できない事象」が自分自身の「問題」に変わった。

タイトルやレビューや確認していたのだが、 「内向型」のための雑談というあまり読んだことがない(個人的に)ようなタイトルであり、 自分の求めるものに合致していると感じて、購入を決めた。

“内向型”のための雑談術―自分にムリせずラクに話せる51のルール

ラインを引いたところ、印象に残った部分をメモする

読書メモ

雑談の悩み

  • 初対面の人と何をしゃべっていいのかわからないために、なかなか打ち解けられない
  • だれかと一緒にいると、沈黙をやぶる言葉が出てこなくて、いつも重苦しい空気になる
  • 大勢の人が集まるパーティや飲み会の席などでたいてい孤立してしまう

雑談は大切

  • 意味のないふざけた会話や人を笑わせるバカな話が、人と接する場面では大切な役割を果たす
  • 最初の雑談ができなければ、本当にいいたいことが伝えられない
  • 近づきすぎても、遠すぎても人付き合いはうまくいかない。その役割を果たしているのが「雑談」
  • 「小さな雑談」さえうまく使えれば、不思議と会話全体がうまくまわる

雑談の役割

楽しい話をすることでも、笑いをとることでもない
雑談のネタは、何も笑えるものでなく、身近なところに取り上げるだけで十分

雑談の目的

常に、雑談の目的を意識すべき。

  • 苦痛な状態からの回避
  • 場の空気を温める(相手の心を開きたい)
  • 好印象を残す(信頼を得ることで「次」につなげたい)

雑談の勘違い

  • 笑い話で盛り上げなければならない
  • たくさんしゃべらなければならない
    • 自分では喋らずに相手に喋ってもらう方が、雑談としての効果が高い
    • 「聞く雑談」に徹することでうまく切る抜けることができる
  • 豊富な話題をもっていなければならない
  • 普通の会話テクニックは内向型人間には使えない(そのとおり)
    • 感情を素直に表現する、明るい表情でからだ全体を使っておおげさにうなづく、自分から率先して会話に入る・・・等々、無理がある。

内向型人間の強み

  • 喋りが苦手である
    • 聞き役に徹することができる
  • 相手の気持ちに敏感である
    • 相手に迷惑がかかりそうになると、すぐにやめてしまう
  • しゃべる言葉を厳選している

感想等

「雑談の悩み」で記載した内容は、そのまま自分の悩みと言える。 こうったタイプの人間がどのように雑談に関する力を身につけていけば良いのか、そもそも身につけることができるのか、 様々な疑問が浮かんできており、本の内容がどう進むのか楽しみである。

【Django】Formの使い方について復習(2016/06/11)

数か月ぶりにDjango(バージョンは1.9)を書いていたけど、色々と忘れてしまっていた。 復習のためメモしておく。

Formの定義

from django import forms

class AnyForm(forms.ModelForm):
    
    class Meta:
        model = AnyModel
        fields = ('any_id', 'any_name')

Formの利用

  • モデルのPK(any_id)がビューに渡された場合は、既存データの更新処理として動く
  • それ以外は新規作成を行う
#-----------------------------------------------------
# views.py
#-----------------------------------------------------
from django.shortcuts import get_object_or_404, render
from django.core.urlresolvers import reverse_lazy

from .forms import AnyForm
def do_any_action(request, any_id):
    # 更新・登録
    if request.method == "POST":
        any_form = AnyForm(request.POST)
        if any_form.is_valid():
            if any_id:
                any_obj = get_object_or_404(AnyModel, pk=any_id)
                any_obj.any_name = any_form.cleaned_data["any_name"]

            else:
                # ModelFormはモデルインスタンスを返す(commit=Falseの場合、DBには保存しない)
                any_obj = any_form.save(commit=False)


            # any_objに作成・更新で共通の処理
            
            
            # 保存
            any_obj.save()
            return redirect(reverse_lazy('pj:result'))
        else:
            return render(request, 'pj/any.html', dict(any_id=any_id, form=any_form)

    # 更新・登録画面への遷移        
    else: 
        any_form = AnyForm()
        return render(request, 'pj/any.html', dict(any_id=any_id, form=any_form))


#-----------------------------------------------------
# urls.py
#-----------------------------------------------------
from django.conf.urls import url
from django.views.generic import TemplateView
from . import views

name = "pj"
urlpatterns = [
   url(r'^mod_any_action/(P<any_id>\d+)/$', views.do_any_action, name="mod_any_action"),
   url(r'^cre_any_action/$', views.do_any_action, name="cre_any_action"),
   url(r'^result$', TemplateView.as_view(template_name="result.html")),
]           

テンプレート

<!-- any.html -->

<!doctype html>
<html>
<head>
  <title>any</title>
</head>
<body>
  {% if any_id %}
  <form action="{% url 'pj:mod_any_action' any_id %}" method="post">
  {% else %}
  <form action="{% url 'pj:cre_any_action' %} method="post">
  {% endif %}
    {{ form.any_name }}
    {% csrf_token%}
  </form>
</body>
</html>

雑感

あまりに久々すぎて、しょぼいミスが目立ってしまった。 ModelFormではない普通のFormを定義していて、そのフィールドにカンマをつけるというミスをしていることに気づかずに 「意図した動作をしない」と悩んでしまった。

定期的にコードを書く機会を作るべきだと感じた。

【JavaScript】webpack + babelの環境メモ

webpackとbabelでES6の自動コンパイル環境を準備したのでメモを残す。

コンパイルに必要なライブラリ

ライブラリ インストールコマンド 備考
babel-cli npm install -g babel-cli グローバルインストール
babel-preset-es2015 npm install --save-dev babel-preset-es2015
babel-polyfill npm install --save-dev babel-polyfill polyfillの意味:古いブラウザであってもモダンブラウザと同様の機能を提供する方法

webpackのライブラリ

ライブラリ インストールコマンド 備考
webpack npm install -g webpack グローバルインストール
style-loader npm install --save-dev style-loader
css-loader npm install --save-dev css-loader
babel-loader npm install --save-dev babel-loader

ついでにjQueryをインストール

ライブラリ インストールコマンド 備考
jquery npm install jquery

webpack.config.jsの作成

  • エントリーは/src/entry.jsとする
  • コンパイル後の出力先ディレクトリは/dist/bundle.jsとする
  • コンパイル前のjsファイルを確認(devtool)
  • babel-loader、style-loader、css-loaderを指定する
module.exports = {
    entry: "/src/entry.js",
    output: {
        path: __dirname + "/dist,
        filename: "bundle.js"
    },
    devtool: "inline-source-map",
    module: {
        loaders: [
            { "test": /\.js$/, exclude: /node_modules/, loader: "babel-loader"},
            { "test": /\.css$/, loader: "style-loader!css-loader"}
        ]
    }
}

style.cssを作成

body {
  background: blue;
}

src/entry.jsを作成

// entry.js
require("./style.css");
let $ = require('jquery');
// import $ from 'jquery' // これは動かなかった。。

let v = [1, 2, 3];
v.forEach(x => console.log(x));

htmlより、dist/bundle.jsを読み込み

<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<script src="dist/bundle.js"></script>

</body>
</html>

自動コンパイルをするため、--watchオプションをつける。

$ webpack --watch

通常のビルドはこちら

$ webpack

実行コマンド一覧

$ npm init -y

# ライブラリインストール
$ npm install -g babel-cli
$ npm install --save-dev babel-preset-es2015
$ npm install --save-dev babel-polyfill
$ npm install -g webpack
$ npm install --save-dev style-loader
$ npm install --save-dev css-loader
$ npm install --save-dev babel-loader

# webpack.config.jsを作成(上記、「webpack.config.jsの作成」の内容を記述し保存
$ touch ./webpack.config.js


# ファイルの監視(自動コンパイル)を実行
$ webpack --watch


参考にさせていただいた記事

qiita.com

library and externals

mae.chab.in

d.hatena.ne.jp

所感

個人的にWebフレームワークDjango(https://www.djangoproject.com/)を使っており、 DJangoテンプレートからbundle.jsを読み込み、動かすところまでできた。

あとは、ES6を使って、実際にアプリを書いてみる。

npmについては、ほぼほぼ初心者といって良い状態。 Gruntとwebpackを使ってみて、個人的にはwebpackの方がシンプルで使いやすいように思った。

【雑記】なにがやりたいか聞かれて即答できなかった話

なにがやりたいか

懇親会で上司や先輩と飲んでいた時、質問された。

「よく家でコーディングやってるみたいだけど、やりたいことは何?」

その質問を受けて、少々困惑した。 なぜならば、自分自身では何がやりたいのか、明確にできているつもりだったが、 客観的に見ると、明確に意識できていないことに気づかされたからだ。

根底にある考え

基本的にはプラグインの開発やフリーゲームの作成を行い、 「人の役に立つことをしたい、人を楽しんでもらいたい」という想いの元に動いている。

仕事でも他の人から「これ作って」「これやって」と言われたら、 その人のことを優先的に考えて行動している。*1

(どうやったら使いやすいか常に考えたり、はやく使わせてあげたいと考える)

しかし、人の役に立つことをしたいというのは、 先輩からしたら、曖昧な考えであったようで、今振り返ると確かにその指摘も妥当だと感じる。

指摘を受けて振り返る

なんとなくではあったが、 自分から主体的にモノを考え、何かに取り組むことができておらず、悩み続けていた。

何かを作ろうとしても、 「既存のサービスがあるから作っても無駄」「1から作るにも、数式が入ってくると、膨大な時間がかかりそう」 こんな理由で反射的・無意識的に断念していることがわかった。

新しいプログラミング言語を学ぶにしても、そこからどんなものを生み出すか見当がつかない状況。 (仕事で新言語での開発等に携わっていれば、ノウハウ蓄積の観点で違ったものになったのかもしれない)

本当に先輩が聞きたかったことは何か

会話にズレがあったようにも感じる。

先輩としては、BtoBか、BtoCかという、金銭の絡む話の中で「やりたいこと」が聞きたかった様子。

しかし、現在の自分としては報酬等、かかわりのない部分で動いている(が、やりたいことは明確に言えない)*2

今後なにをしていくべきか

未完成の状態にあるものを挙げてみる(何度も書いている気がする)

  • ツクールMVゲーム
  • ツクールVX aceゲーム
  • プラグイン(RecollectionMode)の機能追加

最近はツクールMVも影響で、JavaScriptを学ぶことが多い。 (ツクールMVJavaScript、Node.jsやES2015)

クライアント側で完結するものだけではなくWebアプリも作りたい(主にDjango。だけどネタがない)

少し整理すると、「むしろやりたいけど、詰まってる」ことが多い? やりたいことが多すぎて、結局取り組めていない状況にも見える。

軌道に乗ればほぼほぼ解決しそう。

*1:もちろん自分の仕事が忙しいときは少々ずれることはある

*2:というよりも、今は言えないだけで作りたいものがでてきたら当然それが最優先になるので、一時的なものだとも思う

【RecoGene】使い方について(ツクールMV回想モードプラグイン用ツール)

RPGツクールMVの回想モード導入プラグイン用のツール「RecoGene」を作りました。

α版:RecoGene - RecollectionMode.jsジェネレータ

f:id:rinne_grid2_1:20160511211307j:plain

RecoGeneとは?

RPGツクールMVの回想モード導入プラグインRecollectionMode.js」の設定生成ツールです。 Web画面上でCG設定に関する情報を入力し、設定済みのプラグインをダウンロードできます。 さらに、既存のRecollectionMode.js(バージョン1.1.2以降)ファイルから、設定を読み込み、編集することも可能です

主な機能

注意事項

α版ということもあり、不具合が含まれている可能性があります。 必ずプラグインのバックアップを実施いただきますようお願いします。

使い方

1.「回想用のCG設定」タブを開き、CG設定を入力します。

f:id:rinne_grid2_1:20160511204209j:plain

2.(必要に応じて)「回想モードのウィンドウ設定」タブを開き、回想モードのウィンドウ関係の設定を行います

f:id:rinne_grid2_1:20160511205019j:plain

3.(必要に応じて)「回想モードのBGM設定」タブを開き、BGMに関する設定を行います。

f:id:rinne_grid2_1:20160511205212j:plain

4.(必要に応じて)「その他設定」タブを開き、セーブ共有や一時マップの設定を行います。

f:id:rinne_grid2_1:20160511205347j:plain

5.下記画像の赤枠「プラグイン保存」ボタンを押下します

f:id:rinne_grid2_1:20160511205347j:plain

6.以下のようなダイアログが出てくるので、赤枠「クリップボードに保存」ボタンを押下します

f:id:rinne_grid2_1:20160511205555j:plain

7.任意のファイルを作成し、クリップボードの内容を貼り付けます。

8.ツクールMVにプラグインを登録します。

9.ツクールMVを起動し、プラグイン内容が反映されていることを確認します

f:id:rinne_grid2_1:20160511210702j:plain

設定のアップロード

  • RecollectionMode.jsのバージョン1.1.2以降を利用している場合、設定を読み込むことができます

1.「設定をアップロード」ボタンを押下し、プラグインファイルを選択します

f:id:rinne_grid2_1:20160511210932j:plain

2.プラグイン内容が読み込まれたことを確認します

f:id:rinne_grid2_1:20160511211307j:plain

作成について

普段JavaScriptjsonを記述しない方にとっては、 直接プラグイン設定を変更することに対して少々抵抗感があるのではないかと考え、GUIツールを作成しました。

少しでもお役に立てれば幸いです。

不具合等ありましたら、こちらの記事のコメント欄に投稿をお願いします。

【RPGツクールMV】セーブ・ロード系のメソッドメモ

セーブ・ロード時に利用するメソッドやゲーム変数の変化等、 必要になり調査したのでメモ。

loadFromLocalFile(ローカル実行時のセーブファイル読み込み)

// rpg_managers.js 610行目
StorageManager.loadFromLocalFile = function(savefileId) {
    var data = null;
    var fs = require('fs');
    var filePath = this.localFilePath(savefileId);
    if (fs.existsSync(filePath)) {
        data = fs.readFileSync(filePath, { encoding: 'utf8' });
    }
    return LZString.decompressFromBase64(data);
};
  • this.localFilePathは、以下のような条件でパスを返す
    • savefileIdが0より小さい場合:"config.rpgsave"を返す
    • savefileIdが0と同じ場合:"global.rpgsave"を返す
    • savefileIdが1以上の場合:"file%1.rpgsave".format(savefileId)を返す

loadFromWebStorage(ブラウザ実行時のセーブファイル読み込み)

// rpg_managers.js 639行目
StorageManager.loadFromWebStorage = function(savefileId) {
    var key = this.webStorageKey(savefileId);
    var data = localStorage.getItem(key);
    return LZString.decompressFromBase64(data);
};
  • this.webStorageKeyは以下のような条件でキー名を返す
    • savefileIdが0より小さい場合:"RPG Config"
    • savefileIdが0と同じ場合:"RPG Global"
    • savefileIdが1以上の場合:"RPG File%1".format(savefileId);

saveToLocalFile(ローカル実行時のセーブファイル書き込み)

// rpg_managers.js 599行目
StorageManager.saveToLocalFile = function(savefileId, json) {
    var data = LZString.compressToBase64(json);
    var fs = require('fs');
    var dirPath = this.localFileDirectoryPath();
    var filePath = this.localFilePath(savefileId);
    if (!fs.existsSync(dirPath)) {
        fs.mkdirSync(dirPath);
    }
    fs.writeFileSync(filePath, data);
};
  • 引数で受け取ったjsonをBase64にエンコード

saveToWebStorage(ブラウザ実行時のセーブファイル書き込み)

// rpg_managers.js 633行目
StorageManager.saveToWebStorage = function(savefileId, json) {
    var key = this.webStorageKey(savefileId);
    var data = LZString.compressToBase64(json);
    localStorage.setItem(key, data);
};

ローカルか、ブラウザ実行かの判定

// rpg_managers.js 595行目
StorageManager.isLocalMode = function() {
    return Utils.isNwjs();
};

セーブ(ローカル、ブラウザ)の判定

// rpg_managers.js 563行目
StorageManager.save = function(savefileId, json) {
    if (this.isLocalMode()) {
        this.saveToLocalFile(savefileId, json);
    } else {
        this.saveToWebStorage(savefileId, json);
    }
};

セーブの呼び出し

// rpg_managers.js 362行目
DataManager.saveGameWithoutRescue = function(savefileId) {
    var json = JsonEx.stringify(this.makeSaveContents());
    if (json.length >= 200000) {
        console.warn('Save data too big!');
    }
    StorageManager.save(savefileId, json);
    this._lastAccessedId = savefileId;
    var globalInfo = this.loadGlobalInfo() || [];
    globalInfo[savefileId] = this.makeSavefileInfo();
    this.saveGlobalInfo(globalInfo);
    return true;
};
  • this.makeSaveContentsで、ゲーム変数($gameSystem等)をオブジェクトに格納
// rpg_managers.js 422行目
DataManager.makeSaveContents = function() {
    // A save data does not contain $gameTemp, $gameMessage, and $gameTroop.
    var contents = {};
    contents.system       = $gameSystem;
    contents.screen       = $gameScreen;
    contents.timer        = $gameTimer;
    contents.switches     = $gameSwitches;
    contents.variables    = $gameVariables;
    contents.selfSwitches = $gameSelfSwitches;
    contents.actors       = $gameActors;
    contents.party        = $gameParty;
    contents.map          = $gameMap;
    contents.player       = $gamePlayer;
    return contents;
};
  • ゲーム変数を格納したオブジェクトをjsonに変換し、563行目のsaveメソッドに渡す
  • makeSavefileInfoメソッドで、セーブ画面に表示するキャラクターやプレイ時間等の情報をオブジェクトにセットする
// game_managers.js 411行目
DataManager.makeSavefileInfo = function() {
    var info = {};
    info.globalId   = this._globalId;
    info.title      = $dataSystem.gameTitle;
    info.characters = $gameParty.charactersForSavefile();
    info.faces      = $gameParty.facesForSavefile();
    info.playtime   = $gameSystem.playtimeText();
    info.timestamp  = Date.now();
    return info;
};

ロード(ローカル、ブラウザ)の判定

StorageManager.load = function(savefileId) {
    if (this.isLocalMode()) {
        return this.loadFromLocalFile(savefileId);
    } else {
        return this.loadFromWebStorage(savefileId);
    }
};

ロードの呼び出し

DataManager.loadGameWithoutRescue = function(savefileId) {
    var globalInfo = this.loadGlobalInfo();
    if (this.isThisGameFile(savefileId)) {
        var json = StorageManager.load(savefileId);
        this.createGameObjects();
        this.extractSaveContents(JsonEx.parse(json));
        this._lastAccessedId = savefileId;
        return true;
    } else {
        return false;
    }
};
  • StorageManager.loadで、セーブファイルから文字列(Base64からデコード済み)を取得
  • this.createGameObjectsで、Game_XXXXオブジェクトを生成
// game_managers.js 194行目
DataManager.createGameObjects = function() {
    $gameTemp          = new Game_Temp();
    $gameSystem        = new Game_System();
    $gameScreen        = new Game_Screen();
    $gameTimer         = new Game_Timer();
    $gameMessage       = new Game_Message();
    $gameSwitches      = new Game_Switches();
    $gameVariables     = new Game_Variables();
    $gameSelfSwitches  = new Game_SelfSwitches();
    $gameActors        = new Game_Actors();
    $gameParty         = new Game_Party();
    $gameTroop         = new Game_Troop();
    $gameMap           = new Game_Map();
    $gamePlayer        = new Game_Player();
};
  • セーブファイルの文字列を、jsonパースし、ゲーム変数($gameSystem等)に格納
// game_managers.js 438行目
DataManager.extractSaveContents = function(contents) {
    $gameSystem        = contents.system;
    $gameScreen        = contents.screen;
    $gameTimer         = contents.timer;
    $gameSwitches      = contents.switches;
    $gameVariables     = contents.variables;
    $gameSelfSwitches  = contents.selfSwitches;
    $gameActors        = contents.actors;
    $gameParty         = contents.party;
    $gameMap           = contents.map;
    $gamePlayer        = contents.player;
};

【Django】1.9チュートリアル実施メモ

Django1.9のチュートリアルの日本語訳版が公開されていたので、 改めて実施することにした。

今まで実施したチュートリアル(1.4)との違いや復習としてのメモを記載する。

今回はチュートリアル1-3までの内容に関するメモ。

さぁ始めましょう。 | Django documentation | Django

apps.pyについて

AppConfigクラスを継承したクラスを記載する

from django.apps import AppConfig
class PollsConfig(AppConfig):
    name = 'polls'

INSTALLED_APPSには、上記Configを指定する

INSTALLED_APPS = [
    'polls.apps.PollsConfig',
]
  • ここは、1.7より前まではアプリ名を指定していた。

マイグレーション

マイグレーションファイルの作成

python manage.py makemigrations polls

マイグレーションのSQL確認

python manage.py sqlmigrate polls 0001

マイグレーションの確認

python manage.py check

マイグレーションの適用

python manage.py migrate

manage.pyについて

  • manage.pyでは、DJANGO_SETTINGS_MODULEの環境変数を設定している
  • DJANGO_SETTINGS_MODULE環境変数はDjangoに対して、設定ファイルへのimportパスを渡す際に利用される
  • django-admin.py startprojectで作成した時点で、'projectname.settings'が指定されている

timezoneについて

  • よく使う
    • django.utils.timezone
    • datetime
  • 個人的に忘れがち
from django.utils import timezone
import datetime

time = timezone.now()

# 7日前
delta = datetime.timedelta(days=-7)

before_week = time + delta

モデルの属性について

属性 + __yearで年指定

from django.utils import timezone
current_year = timezone.now().year
Question.objects.get(pub_date__year=current_year)

外部キーを張った属性のセット

q = Question.objects.get(pk=1)
# Choiceには、Questionへの外部キーが張られている
q.choice_set.all()

# 外部キー側のオブジェクトを作成
q.choice_set.create(choice_text='hoge', votes=0)

adminサイト

  • フォームは、モデルから自動的に生成される
  • モデルのフィールド型によって、適切なHTML入力ウィジェットが対応している
  • 各フィールドには、Django管理サイトでデータを表示する方法が定義されている

DjangoのURLについて

  • URLパターンは、URLをシンプルに一般化したものである
  • Djangoでは、URLとビューをひもづけるため、URLconfを利用する

urlpatterns

  • プロジェクトフォルダ内のurls.py
from django.conf.urls import url, include

urlpatterns = [
    url(r'polls/', include('polls.urls')),
]

  • アプリケーションのurls.py
from django.conf.urls import url
from . import views

urlpatterns = [
    urls(r'^(?P<object_id>[0-9]+)/resources/$', views.resource, name='resource' ),
]

ビューについて

  • ビューには二つの役割がある
    • リクエストされたコンテンツを含むHttpResponseオブジェクトを返す
    • Http404のような例外の送出

Djangoテンプレートについて

  • アプリケーションフォルダ内に、templatesフォルダを作成する *【Memo:】 (今までDjangoで作ったアプリは、プロジェクトの直下に作成していた気がする
  • DjangoTemplatesの設定ファイルについて、APP_DIRSオプションがTrueに設定されていることにより、INSTALLED_APPSのそれぞれのサブディレクトリにおけるtemplatesフォルダを検索する。
  • アプリケーションが複数ある場合は、URLconfに名前空間を追加する
from django.conf.urls import url
from . import views

name = 'polls'
urlpatterns = [
    urls(r'^(?P<object_id>[0-9]+)/resources/$', views.resource, name='resource' ),
]

チュートリアルのドキュメント

はじめての Django アプリ作成、その 1 | Django documentation | Django

はじめての Django アプリ作成、その2 | Django documentation | Django

はじめての Django アプリ作成、その 3 | Django documentation | Django