Webアプリ習作#9
ツイート機能の仮実装について
Laravelの枠組みで動かす前にまずは簡易的な仮実装で動作を確認する
abraham/twitteroauthのインストール
TwitterのAPIを操作できるライブラリ プロジェクトディレクトリにて以下を実行
composer require abraham/twitteroauth
終わったらcomposer.jsonを開き、requireセクションにabraham/twitteroauthが追加されていることを確認
アクセストークンをメモ
ツイートを実行するTwitterOAuthにはアクセストークンが必要 本来ならLaravel Socialiteから取得できるユーザー情報を参照するところだが、仮実装なので直打ちする app\Http\Controllers\TwitterAuthController.phpを修正
public function callback() { $providerUser = Socialite::driver('Twitter')->user(); dd($providerUser); // これを一時的に追加.(後で削除)
http://localhost:8000/auth/twitter
にアクセスしてログイン情報を確認してtokenとtokenSecretの値をメモしておく
終わったらTwitterAuthController.phpの修正を戻す
ツイートする仮画面を作成
resources/views/test.blade.phpを作成 TwitterOAuthのコンストラクタの引数には先ほどメモしたtoken,tokenSecretの文字列を記載する ※token,tokenSecretの文字列は取り扱いに注意(公開厳禁)
<?php use Abraham\TwitterOAuth\TwitterOAuth; function testTweet(){ $twitter = new TwitterOAuth( env('TWITTER_CLIENT_ID'), env('TWITTER_CLIENT_SECRET'), "メモしたtokenの文字列", "メモしたtokenSecretの文字列" ); $twitter->post("statuses/update", [ "status" => 'テストツイートです' ]); } if (isset($_GET['testtweet'])) { testTweet(); } ?> <!DOCTYPE html> <html lang="ja"> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"> <title> test </title> </head> <body> <a href='index.php?testtweet=true'>テストツイートをする</a> </body> </html>
ルーティングの編集
routes/web.phpを以下のように修正
Route::get('/', function () { //return view('welcome'); // これを削除. return view('test'); // これを追加. });
確認
http://localhost:8000
にアクセスして"テストツイートをする"というリンクをクリック
ログインしたTwitterアカウントを確認してテストツイートが追加されていることを確認
オンラインサロンに参加してみた
知見を広めるためにはもっと人とつながる機会を増やさないとと思っていましたが、新型コロナが一向に収束しない状況で勉強会などに参加することに二の足を踏んでいた中でオンラインサロンに思い当たり、試してみることにしました。
みんサロでプログラマ・エンジニア向けのサロンを探してみたところ、堤修一さんという方が主催するオンラインサロンを発見。
エンジニアと人生コミュニティの口コミと評判|みんなのオンラインサロン
31歳でプログラマになり株式会社カヤック社員を経てサンフランシスコの企業で働いていたという経歴の持ち主で、Youtubeには下記の動画を始めとして、エンジニアが発信することの大事さを説く動画をいくつかアップされています。
【エンジニアのための発信講座】#1 発信をはじめよう - YouTube
主催するサロンには現在200人以上が参加しているとのこと。 このコミュニティから良い刺激を受けられそうだと感じたので入会を申し込むことに。 プランは月額1000円と1500円があったが、違いがよくわからなかったのでとりあえず1000円のプランを選択。 みんサロのページから[このサロンに参加する]を選択すると、CAMPFIRE community内のページ
にリダイレクトされたのでそこでアカウントを作成して申し込み。 すぐにSlackの招待メールが届きました。 Slackは今まで仕事でしか使ってこなかったので、プライベート用のアカウントを新規作成した上で参加。 まずは自己紹介をとのことなので、自己紹介チャンネルに短い文章とこのブログのURLを添えて投稿してみることに。
キャラクターの命令実行処理について(2)
複数のステート間の移行
前記事ではユニットに与えられた命令を処理するために、複数のステートを適宜切り替える必要があることを説明しました。 この一連のステート間の移行をどう管理すべきでしょうか?
キュー(FIFO)で管理する
命令を入力したときに必要なステートをキューに格納することで管理する方法です。 例:攻撃コマンドを実行した場合、移動ステート・攻撃ステートの順にキューに格納します。 最初に格納されたものから処理されるので移動ステート・攻撃ステートの順に処理されます。 また、キューが空になったら待機ステートが設定されるようにしておきます。
スタック(LIFO)で管理する
命令を入力したときに必要なステートをスタックに格納することで管理する方法です。 例:攻撃コマンドを実行した場合、攻撃ステート、移動ステートの順にスタックに格納します。 最後に格納されたものから処理されるので移動ステート・攻撃ステートの順に処理されます。 また、スタックの底には待機ステートが常に格納されるようにしておきます。
何が違うのか
両者にはそれぞれ異なるメリットがあります。 キュー管理型のメリットは複数命令の順次実行に対応できる点です。 作業ユニットに複数の作業を順に実行させたい場合(PCゲームであればCtrl+クリックなどで入力させる)、キューに移動ステート、作業ステート、移動ステート、作業ステート・・・の順に格納することで実現できます。 運営や管理に主眼を置いたストラテジーゲーム向けの仕様だと思います。 一方スタック管理型のメリットは割り込み命令に対応できる点です。 戦闘ユニットが目標に向かう途中で敵の迎撃を受けた場合、スタックに新たに攻撃ステートを積むことで敵ユニットへの攻撃を開始、敵ユニットを壊滅させたらそのまま元の目標への移動を再開、という流れをプレイヤーの追加入力なしに実現できます。 こちらは戦闘や戦略に主眼を置いたストラテジーゲーム向けの仕様になります。
複合型
ユニットデータにキューとスタックの両方を持たせることも可能です。 命令が複数入力された場合最初の命令だけスタックに、以降の命令はキューに格納しておき、スタックの命令が終了したら(=待機ステートになったら)キューから次の命令を取り出してスタックに積むという形になります。 このようにすれば両者の利点が利用できますが、実際のところここまで実装しているゲームはあまり見かけません。 複雑なルールにするとプレイヤーにも理解しづらく混乱を招くのかもしれません。 ゲームの仕様に応じてキュー管理型かスタック管理型かを選ぶのがよいと思います。
キャラクターの命令実行処理について(1)
キャラクターに与えられた命令を実行させるには
ゲーム内のキャラクターに何らかの行動をさせるために必要な処理はゲームジャンルによって大きく異なります。 アクションゲームであればプレイヤーの入力に応じた動作を即時反映させるだけなのでシンプルですが、そのようなゲームばかりではありません。 この記事ではストラテジーゲームなどに多く見られるような、 「プレイヤーがキャラクターに命令を入力し、キャラクターはその命令に応じた行動を自動で実行する」という一連の処理を実装する上での基本的な考え方を説明します。
用語について
この記事では各キャラクターのことをユニットと呼びます。 プレイヤーキャラ(PC)も非プレイヤーキャラ(NPC)も同じユニットとして扱うことで処理を共通化します。 また、ユニットが何の命令を実行中かを示す状態をステートと呼びます。 各ユニットがそれぞれステートを持ち、毎フレームの処理によってユニットがそのステートに応じた行動を実行します。 PCはプレイヤーによって、 NPCはゲームのアルゴリズムによって命令を与えられることになりますが、 NPCの命令アルゴリズムについてはゲームの仕様に大きく左右されるので記事としてはフォローしません。
待機ステートについて
待機ステートは最も基本的ステートです。 何も命令が与えられていないユニットはこのステートになります。 また、何らかの命令が与えられたユニットも命令に応じた行動が終了したらこのステートに戻ります。 毎フレームの処理ではユニットは何もせずに終了します。
移動ステートについて
ユニットに移動命令が与えられると移動ステートに移行します。 移動ステートは目標を持っており、命令として与えられた目標が格納されます。特定の地点や建造物や他のユニットが目標になり得ます。 毎フレームの処理ではまずユニットが目標に到着しているかどうかを判定します。 到着していなければユニットの移動力に応じて座標移動をさせ、 到着していれば移動ステートを終了して待機ステートに移行します。
移動ステートの経路探索について
ユニットが存在するのが何も障害物のない均一な世界であれば、目標に向けてただ直線移動させればいいのですが、そのようなゲームを作る機会は多くないでしょう。 障害のあるワールド上でユニットを移動させるためには経路探索処理を実装しなければなりません。 経路探索について詳しく知りたければ、A*(エースター)アルゴリズムについて調べるといいと思います。 ユニットの目標が動くオブジェクト(他のユニットなど)の場合、経路探索は適宜更新をしなければなりませんが、 毎フレーム探索すると処理不可が大きいので数フレーム置きに間引いた方がよいと思います。 目標が動かない場合(地点や建造物など)は経路探索は命令入力直後の一回だけで済みます。 いずれの場合も探索した経路は移動ステートから参照できる形で保持させます。
その他の行動ステート
ここからはゲームの仕様次第なのですが、 例えば軍事ユニットであれば敵ユニットに攻撃する、敵の建造物を破壊するなどの命令が、 作業ユニットであれば採掘地点で資源を得る、建造物を建てる等の命令が必要になるはずです。 それぞれの命令に対応した行動ステートを実装します。 攻撃命令であれば攻撃ステートを実装し、このステートには目標として敵ユニットを持たせるようにします。 破壊命令であれば破壊ステートを実装し、このステートには目標をとして敵建造物を持たせるようにします。 毎フレーム処理ではまず各行動が終わったかどうかを判定します。 攻撃ステートの場合目標ユニットが壊滅したかどうか、破壊ステートで場合目標ユニットが破壊されたかどうかです。 終わっていればそのステートを終了して待機ステートに移行します。 終わっていなければ各ステートに応じた行動を実行させます。
ステートの移行について
これらの命令を入力した際にユニットが既に各目標に隣接していればよいですが、 そうでなければユニットを目標の場所に移動させてから各行動を実行させます。 命令を与えられたユニットはまず移動ステートが設定されることで目標への移動を開始し、目標に到達したら対応した行動ステートに移行します。 こうすることでプレイヤーが移動→各行動という命令を適宜入力することなく、一度の命令入力でユニットに一連の行動をさせることができます。
次の記事ではこの流れを実装するための考え方を説明します。
Webアプリ習作#8
前記事に引き続き主にこちらを参考にしました。 Laravel Socialiteを使ってTwitterアカウントでログイン機能 - Crieit
モデルのディレクトリ構成の変更
Laravelのプロジェクト作成時にUserモデルのファイル(User.php)がapp直下に自動生成されるが、app/Modelsディレクトリを作成しその下に移動させる それに伴いUser.phpの中身も変更
namespace App; ↓ namespace App\Models;
また、プロジェクトディレクトリ以下を検索して
App\User
と書かれている箇所を
App\Models\User
に置換する 具体的には以下の三か所 app\Http\Controllers\Auth\RegisterController.php
use App\User; ↓ use App\Models\User;
config\auth.php
'providers' => [ 'users' => [ 'driver' => 'eloquent', 'model' => App\User::class, ], ↓ 'providers' => [ 'users' => [ 'driver' => 'eloquent', 'model' => App\Models\User::class, ],
database\factories\UserFactory.php
use App\User; ↓ use App\Models\User;
social_usersに対応するモデル作成
プロジェクトディレクトリで以下コマンドを実行
php artisan make:model Models/SocialUser
app\ModelsにSocialUser.phpが生成されたことを確認 app\Models\User.phpに以下のメソッドを追加してSocialUserモデルと連携
public function socialUsers() { return $this->hasMany(SocialUser::class); }
app\Models\SocialUser.phpの方にも以下を追加
class SocialUser extends Model { public function user() { return $this->belongsTo(User::class); } }
これでusersとsocial_usersが連携される
callbackメソッドの実装
app\Http\Controllers\TwitterAuthController.phpに以下のuseキーワードの記述を追加
// ここからを追加. use App\Models\User; use App\Models\SocialUser; use Auth; use DB; // ここまでを追加. use Illuminate\Http\Request; use Socialite;
同じくapp\Http\Controllers\TwitterAuthController.phpのcallbackメソッドを修正
public function callback() { $providerUser = Socialite::driver('Twitter')->user(); // 既存ユーザーか. $socialUser = SocialUser::where('provider_user_id', $providerUser->id)->first(); if ($socialUser) { // 既存ユーザーならログインしてトップページへ. Auth::login($socialUser->user, true); return redirect('/'); } // 新しいユーザーを作成. $user = new User(); $user->unique_id = $providerUser->nickname; $user->name = $providerUser->name; $user->avatar = $providerUser->user['profile_image_url_https']; $user->bio = $providerUser->user['description']; $socialUser = new SocialUser(); $socialUser->provider_user_id = $providerUser->id; DB::transaction(function () use ($user, $socialUser) { $user->save(); $user->socialUsers()->save($socialUser); }); // 作成したユーザーでログイン. Auth::login($user, true); return redirect('/'); }
アクセス確認
ローカルサーバを起動してログインURLにアクセス
http://localhost:8000/auth/twitter
Twitterのアプリケーション認証画面を介してLaravelのホーム画面へ移行することを確認
DBを確認
psqlを起動してDBに接続
\c twiapp_db
テーブル一覧を表示してユーザー情報が一人分生成されていることを確認
select * from users; select * from social_users;
再度ログイン確認
もう一度ログインURLにアクセスして正常にログインできることを確認 その後DBにアクセスしてデータが複数生成されていないことも確認
Webアプリ習作#7
前々記事に引き続き主にこちらを参考にしました。 Laravel Socialiteを使ってTwitterアカウントでログイン機能 - Crieit
DBの方針
ユーザー情報はLaravelにデフォルトで用意されているusersテーブル(マイグレーション済み)の他にsocial_usersテーブルを新規に作成し、この2つで管理する social_usersには連携するSNS(今回のケースではTwitter)固有の情報が格納されusersデータ一つにつき複数個(連携するSNSの数ぶん)紐づけられる つまりusersとsocial_usersは一対多の関係にある(ただし、今のところTwiiterとしか連携しないので実質一対一の関係)
Doctrine DBALのインストール
DBの既存のカラムを修正するchangeメソッドの実行に必要なライブラリ プロジェクトディレクトリ上で下記を実行
composer require doctrine/dbal
social_usersテーブルの作成
プロジェクトディレクトリ上で以下を実行
php artisan make:migration create_social_users --create social_users
database/migrations下に[日付]_create_social_users.phpというファイルが生成されるので下記のように修正
public function up() { Schema::create('social_users', function (Blueprint $table) { $table->bigIncrements('id'); $table->bigInteger('user_id')->unsigned()->index();// この行を追加. $table->string('provider_user_id')->index();// この行を追加. $table->timestamps(); $table->foreign('user_id')->references('id')->on('users')->onDelete('cascade');// この行を追加. }); }
上記のprovider_user_id
が連携SNS(Twitter)のユニークIDに相当する
usersテーブルの拡張
usersテーブルを生成するマイグレーションファイルは'2014_10_12_000000_create_users_table.php'(Laravelプロジェクト作成時に自動生成済み)だが、これとは別にusersテーブルを修正するマイグレーションファイルを作成する --createオプションの代わりに--tableオプションを指定する
php artisan make:migration add_social_columns_to_users --table users
[日付]_add_social_columns_to_users.phpというファイルが生成されるので編集
public function up() { Schema::table('users', function (Blueprint $table) { // ここからを追加. $table->string('unique_id')->after('id'); $table->string('avatar')->after('password'); $table->text('bio')->after('avatar'); $table->string('email')->nullable()->change(); $table->string('password')->nullable()->change(); // ここまでを追加. }); } public function down() { Schema::table('users', function (Blueprint $table) { // ここからを追加. $table->string('password')->change(); $table->string('email')->change(); $table->dropColumn('bio'); $table->dropColumn('avatar'); $table->dropColumn('unique_id'); // ここまでを追加. }); }
マイグレーションを実行
php artisan migrate
※エラー発生※
LogicException : Laravel v6 is only compatible with doctrine/dbal 2, in order to use this feature you must require the package "doctrine/dbal:^2.6".
Doctrine DBALがLarvel 6に対して新し過ぎるので、プロジェクトディレクトリのcomposer.jsonを開いてdoctrine/dbalの項目を以下のように修正
"doctrine/dbal": "^2.6",
更新して再度マイグレーション
composer update php artisan migrate
DBの確認
psqlを起動して追加されたことを確認する DBに接続
\c twiapp_db
テーブル一覧を確認
\dt
social_usersが追加されていることを確認 テーブルの中身を確認
\d social_users \d users
Webアプリ習作#6
アプリ機能の大枠を決定
Twitter APIのElevated Access申請にあたってアプリの機能を簡単に説明する必要がある 習作目的のシンプルなものという方針から以下のように決定
- 自分のTwitterアカウントにログインして固定のメッセージをツイートする
- アプリによって生成されたツイートは一覧で表示される
- Twitterのデータ分析は特にしない
- 使用するTwitterの機能はツイートのみ、リツイート・いいね・フォロー・DM機能は使用しない
言語の壁
各項目は英語で入力する必要がある DeepL翻訳:世界一高精度な翻訳ツール
Elevated Access申請
https://developer.twitter.com/en/portal/dashboardにアクセス ProjectsのProject 1(ESSENTIAL)を選択 Apply for Elevatedを選択
(1)Basic infoを入力
What's your name? What country are you based in?
には入力済み
What's your current coding skill level?
にSome Experienceを入力
Want updates? (optional)
チェックしない Nextを選択
(2)Intended Useを入力
In English, please describe how you plan to use Twitter data and/or APIs. The more detailed the response, the easier it is to review and approve. [訳]Twitterのデータおよび/またはAPIをどのように利用する予定か、英語で記入してください。より詳細な回答があればあるほど、審査や承認が容易になります。
上記の方針に基づいて入力
Are you planning to analyze Twitter data? [訳]Twitterのデータを分析する予定はありますか?
Noを選択
Will your App use Tweet, Retweet, Like, Follow, or Direct Message functionality? [訳]ツイート、リツイート、いいね、フォロー、ダイレクトメッセージの機能を使いますか?
Yesを選択
Please describe your planned use of these features. [訳]これらの機能の予定使用について教えてください。
上記の方針に基づいて入力
Do you plan to display Tweets or aggregate data about Twitter content outside Twitter? [訳]Twitterのコンテンツに関するツイートや集計データをTwitterの外部で表示する予定はありますか?
Yesを選択
Please describe how and where Tweets and/or data about Twitter content will be displayed outside of Twitter. [訳]Twitterのコンテンツに関するツイートやデータが、Twitter以外でどのように、どこに表示されるかを説明してください。
上記の方針に基づいて入力
Will your product, service, or analysis make Twitter content or derived information available to a government entity? [訳]あなたの製品、サービス、分析によって、Twitterのコンテンツや派生する情報を政府機関が利用できるようになりますか?
Noを選択
(3)Review画面で入力項目を確認
確認したらNext
(4)Termsを確認
確認した旨をチェックしてSubmit ※申請待ち期間が発生することなく登録後に即座に申請が終了した(通知メールなども特になし)
動作確認
申請終了したらローカルサーバを起動し
http://localhost:8000/auth/twitter
にアクセス
Twitterのアプリケーション認証画面にリダイレクト→アプリに戻りログインしたユーザー情報が表示されることを確認