「XREA+」サービスを申し込んだ

全然更新していない本サイト「あまやどり - ゲーム作成講座 -」はXREAという無料レンタルサーバを使わせてもらっているのですが、ハイク用のBOTh:id:kalen_t)を1時間に1回動かすためにcronを使いたくなったので、勢いで有料サービスのXREA+に申し込んでしまいました。1週間無料期間がありますが、このまま有料サービスを使う予定。まともな有料レンタルサーバで最安値レベルの年4800円という価格設定は嬉しい。

XREA+を申し込んだことで、cronが使えるようになったほか、サイト上部の広告が消え、容量も50MBから一気に3GBになりました。今のところこの大容量の使い道は思い浮かばないけど。あと、ついでにドメインも取っちゃいました。全然更新しないサイトなのに後先考えておりません。バリュードメインのサポートは悪いという話もあってちょっと不安ですが、やはりお値段が魅力的なので……。

というわけで、あまやどりの新URLは http://www.amayado.net/ となります。旧URL( http://minus273.s27.xrea.com/ )は新URLに転送されるようです。

プログラミングの練習(Hit and Blow) #02 GameMain

ここ数日はRubyの面白さに目覚めていたので、久しぶりに書いていかにC++が面倒な言語かを思い知りました。特に関数の先行宣言。なんで同じことを2回書かなくちゃいけないのか……。その点、C++に似てるけど先行宣言を書かなくていいD言語は楽でした。でもそこがC++のかわいいところだと思って今日もがんばります。

前回書き忘れていましたが、Cの標準ライブラリをC++で使いたいときは

#include <stdio.h>
#include <stdlib.h>

ではなくて、

#include <cstdio>
#include <cstdlib>
using namespace std;

としてあげたほうがいいそうです。using namespaceしていることからもわかるとおり、後者はstd名前空間に包まれています。他の主なC標準ライブラリに対しても、頭にcを付けて最後の.hを削ったものが用意されています。ただ、なんでこうしたほうがいいのかが私には分かりません……。おそらく名前の衝突を防ぐためなのでしょうが、using namespaceしちゃったらその意味がないですよね。だからといってしないと面倒だし(よく使うのに毎回std::printfって書くのは面倒すぎる)。まあ、C++っぽくてかっこいいので、私は後者を使っています。実際は前者でも大した問題はなさそうなので好きなほうでいいと思いますが。(参考:C++マニアック,Hello world!,namespace,header

やっと本題です。前回gameMainという関数がありましたが、これは別ファイルに分けます。GameMain.hとGameMain.cppを作ります。で、以下がGameMain.cppの内容です。

#include "GameMain.h"

static void init();
static void run();
static void term();

static int x = 200;
static int y = 100;

void gameMain()
{
	init();
	run();
	term();
}

void init()
{
}

void run()
{
	DrawBox(x, y, x + 50, y + 50, 0xffffff, TRUE);
	WaitKey();	//何かキーが押されるまで待つ
}

void term()
{
}

まだ中身は空っぽです。最初の関数宣言と変数宣言の前にstaticが付いていますが、これはこれらの関数・変数はこのファイル内でしか使えないようにする指示です。実際、initとtermにstaticが無いと、AppMainの方のinitとtermと名前が衝突しているためコンパイルエラーが出ます。

注意してほしいのですが、C++ではstaticに複数の使い方がありまして、関数の外部では今回の意味になり、関数の内部では静的変数やクラスの静的関数を表すため、非常にややこしいです。というか前者はなぜstaticなんでしょうね。素直に考えればprivateの方が適切ですよね。

ただ、今Wikipediaを見たら

ただし、ファイルスコープを指定するのにstaticを用いるのはC++では推奨されず、無名名前空間を用いるべきとされている。

http://ja.wikipedia.org/wiki/%E4%BA%88%E7%B4%84%E8%AA%9E_(C%2B%2B)

と書いてありました。知りませんでした。でも面倒なのでこのままいきます。中途半端ですみませんが、今回は細かいことに悩みたくないので、新しい知識はなるべく使いたくないのです。

はてなハイクでReply先アイコンを置き換えて分かりやすくするGreasemonkey

(2009-03-17 16:00 追記)AutoPagerizeで継ぎ足されたページでも置き換えられるようになりました(version 1.1)。AutoPagerize」および「AutoPagerize for Haiku (patched ver)」で動作を確認しました。

これは何?

はてなハイクでReplyを投稿した時につくアイコンをProfileアイコンに置き換えて、Reply先を分かりやすくするGreasemonkeyスクリプトです。詳しくは少し下の「スクリーンショット」をご覧ください。ご利用になるにはGreasemonkeyをインストールしたFirefoxが必要です。

見よう見まねで初めて作ったGreasemonkeyスクリプトなので、変なところがあるやもしれません。

インストール

replace_reply_icon_by_profile_icon_for_Hatena_Haiku.user.js version 1.1 (2009-03-17)

上記リンクをクリックすればインストールが始まります。GreasemonkeyをインストールしたFirefoxが必要です。WindowsXPFirefox 3.0.7 にて動作確認しております。

スクリーンショット

百聞は一見に如かずということで、ある日のハイクのカミナギチャットを例にあげます。

id:ken_woodさん、id:co8co8さん、そしてid:kaminagiさん、勝手に例にあげてすみませんm(_ _)m

このGreasemonkeyをインストールすると、次のようにアイコンが置き換わり、誰にReplyしているのかが分かりやすくなります。


ハイクに時報を自動投稿するスクリプト

ハイクに時報を投稿するだけのごく簡単なbotが生まれました。h:id:kalen_tにて喋っています。今後喋ることのバリエーションを増やすかどうかは未定。

紹介を兼ねて、現状のソーススクリプトを掲載します。Ruby初心者が見よう見まねで書いたものなので、変なところがあるかもしれませんし、あまり詳しい説明も付けていませんが、ご了承ください。

誤投稿を防ぐため、コマンドラインオプションを付けて起動しない限り実際にはハイクに投稿しないようになっています。

#!/usr/local/bin/ruby -Ks

#※開発環境はWindows XPです。

=begin
■開発日誌
◆2009-03-13
kalen_t の投稿テストを経て、時報としてとりあえず動きそう。

◆2009-03-14
起動・終了時メッセージと時報を投稿。
メニューから制作者による告知を投稿することもできる。
不意な投稿を避けるため、実際にハイクに投稿するかどうかを
コマンドラインオプションで指定できる(無指定だと投稿しない)。
=end

require "kconv"
require 'net/http'
require 'uri'
require 'cgi'
Net::HTTP.version_1_2

username = '(はてなID)'  #はてなのIDを入れます。
password = '(パスワード)'  #投稿用メールアドレスを入れます。ハイクAPIを参照のこと。
bot_name = 'nanashino_bot'

#コマンドライン引数を見て、実際にハイクに投稿するかどうか決める
if ARGV[0] == "p" then
  post_flag = true
  puts "■★★★投稿モードで起動します。★★★"
else
  post_flag = false
  puts "■投稿しないモードで起動します。"
end

#ハイクに投稿する関数
def post_haiku(username, password, message, bot_name, reply_id, post_flag)
  #投稿プレビュー
  puts " ◆投稿プレビュー\n" + message + "\nsource: " + bot_name + "\n"
  if reply_id != nil then
    puts "reply_id: " + reply_id
  end

  #パラメータをURLエンコードする
  params = 'status=' + CGI.escape(message.toutf8)
  params += '&source=' + CGI.escape(bot_name.toutf8)
  if reply_id != nil then
    params += '&in_reply_to_status_id=' + CGI.escape(reply_id.toutf8)
  end

  puts " ◆投稿プレビュー(URLエンコード後)\n" + params + "\n"

  #BASIC認証してはてなハイクにPOST
  if post_flag then
    puts ' ◆投稿中……'
    req = Net::HTTP::Post.new("http://h.hatena.ne.jp/api/statuses/update.xml")
    req.basic_auth(username, password)
    Net::HTTP.start('h.hatena.ne.jp', 80) {|http|
      response = http.request(req, params)
      #puts response.body.tosjis
    }
    puts ' ◆投稿が完了しました'
  else
    puts " ◆投稿しないモードなのでスキップします。"
  end
end

#起動時刻を取得
startup_day = Time.now

#起動時にメッセージを投稿
puts '■起動メッセージを投稿します。'
message  = "おはようございます。\n時報投稿スクリプトの試運転を始めます。"
post_haiku(username, password, message, bot_name, nil, post_flag)

#毎時0分に時報を投稿するスレッドを作成
#(メインメニューの処理と並行して裏で動き続けます)
t = Thread.new do
  puts '■0分待ち中……。'
  day = Time.now
  hour_prev = day.hour
  while true
    sleep(1)
    day = Time.now
    #puts day
    if day.hour != hour_prev then
      puts '■0分になりました。投稿します。'
      message  = day.hour.to_s + '時になりました。'
      post_haiku(username, password, message, bot_name, nil, post_flag)
      hour_prev = day.hour
      puts '■0分待ち中……。'
    end
  end
end

#メインメニュー
puts "■コマンド待機に入ります。"
puts " hコマンドでメニューを表示します。"

while true
  print ">"
  input_str = STDIN.gets  #ただのgetsだとコマンドライン引数を拾ってしまうので

  case input_str.chomp
  when "h"
    puts '■メニュー'
    puts ' h: このメニューを表示'
    puts ' q: プログラムの終了'
    puts ' m: ハイクに制作者からの告知を投稿'

  when "q"
    puts '■プログラム終了メッセージを投稿します。'
    
    #稼働時間を取得
    day = Time.now
    run_day = (day - startup_day).divmod(24*60*60)
    run_hour = run_day[1].divmod(60*60)
    run_min = run_hour[1].divmod(60)

    run_time = ""
    if run_day[0] != 0 then
      run_time += run_days[0].to_s + ""
    end
    if run_hour[0] != 0 then
      run_time += run_hour[0].to_s + "時間"
    end
    if run_min[0] != 0 then
      run_time += run_min[0].to_s + ""
    end
    run_time += run_min[1].truncate.to_s + ""

    message  = "そろそろ落ちます。\n今回の稼働時間は" + run_time + "でした。-"
    message  += "ありがとうございましたー。"
    post_haiku(username, password, message, bot_name, nil, post_flag)

    puts '■プログラムを終了します。'
    break

  when "m"
    puts "■制作者からの告知メッセージを投稿します。"
    puts "■メッセージを入力してください。"
    puts " 「-」のみの行を入力すると入力を終了します。"
    input_mes = ""
    while true
      input = STDIN.gets.chomp
      if input == "-" then
        break
      end
      input_mes += input + "\n"
    end

    #制作者という単語が出てくるとbotっぽくなるので「ますっ」とか言ってごまかす
    post_mes = "制作者より投稿されたメッセージを読み上げますっ。\n \n"
    input_mes.each_line { |line|
      post_mes += ">" + line
    }

    puts " ◆告知メッセージプレビュー\n" + post_mes
    puts "■yコマンドで投稿、それ以外でキャンセルします。"
    if STDIN.gets.chomp == "y" then
      message  = post_mes
      post_haiku(username, password, message, bot_name, nil, post_flag)
    else
      puts "■投稿をキャンセルしました。"
    end

  else
    puts "■未定義のコマンド: " + input_str
  end
end

参考にさせていただいたページのメモ。

プログラミングの練習(Hit and Blow) #01 mainあたり

もうゲームを作りかけては手に負えなくなって放置するっていうループに飽き飽きしてきたので、再入門のつもりで簡単なプログラムを作ってみようと思います。自分以外の人には参考にならないかもしれませんが、いちおう作業記録をブログに載せていきます。

開発環境はVC2008EEとDXライブラリ。念のため補足すると、DXライブラリというのはDirectXのことではなくて、DirectXをラッピングしたライブラリのひとつです。C言語HSP並みに楽にDirectXを扱えるので初心者には重宝します。作るのはHit and Blowです。初心に帰りすぎですね。個人的にはHit and Blowと聞くと女神転生シリーズを思い出します。

早速VCでプロジェクトを作って、DXライブラリを使えるように準備します。ついでにプロジェクトの設定でコンパイラの警告レベルを4にするのも忘れません。

ところで今回はオブジェクト指向とやらは一切忘れて、C言語的な設計にしていこうと思います。というのも、今までC++で作ろうとしたプログラムは一気に複雑になって自分の手に負えなくなってしまっていたからです……。もうスマートさは捨てて、自分の身の丈に合ったコードを書いていこうかと。HSPを使っていたころは稚拙でも無理やりプログラムを完成させていたので、その気概を思い出していきたい。

早速プログラムを書いていきます。以下、書きながら思ったことをつらつらと書いていきます。コード片しか載せないので変数定義とかが無かったりしますがご了承ください。以下はAppMain.cppの内容です(mainがあるファイルは一番上に来てほしいので、Aで始まるこの名前にしています)。

//Debugビルド(コンソールが出る)の場合はこちらから
int main()
{
	init();
	gameMain();
	term();

	return EXIT_SUCCESS;
}

//Releaseビルドの場合はこちらから
int WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int)
{
	return main();
}

なぜかmainとWinMain両方あります。WinMainでは単にmainを呼び出しているだけなので、やることは実質同じです。この上で、プロジェクトのプロパティの[リンカ]→[システム]→[サブシステム]をDebugビルドでは「コンソール」に、Releaseビルドでは「Windows」にしておきます。こうすることにより、Debugビルドの時だけゲーム画面とは別におなじみのDOS窓が開きます! printfでいろいろ表示できるのでデバッグに便利。ちなみにこの方法はSelene 1.0系に付属のチュートリアルで知りました。まあTRACEマクロを使えばこんな面倒なことはしなくていいわけですが、単なる好みでDOS窓を選びました。

最初からやけに細かい小技ですが、これは講座とかではなく作業記録ですので、今後もこんな感じで続いていくものと思われます。ご了承ください。

あ、あと、WinMainの引数の変数名がないのは、「引数は関数の本体部で 1 度も参照されません。」っていうwarningを消すためです(参考:「引数が関数内で使用されないことを示す」「プログラムのエントリーポイント」)。ちなみに警告レベル3だとこの警告は出ません。

mainの中のinit、termは(主にDXライブラリの)初期化処理・終了処理です。gameMainの中に実際のゲームの処理を書いていく予定。mainはシンプルなほうがいいってよく聞くのでこんな感じにしました。

次はinitとtermの中身を。

void init()
{
	//デバッグビルドならデフォルトでデバッグモードをON
#ifdef _DEBUG
	bDebugMode = true;
#endif

	//Debugビルドなら常にウインドウモード、
	//Releaseビルドならフルスクリーンかウインドウか選べる
	bWindowMode = false;
	if (bDebugMode) {
		ChangeWindowMode(TRUE);
		bWindowMode = true;
	} else {
		if (MessageBox(NULL, "フルスクリーンモードにしますか?",
		    applicationTitle.c_str(), MB_YESNO) == IDNO)
		{
			ChangeWindowMode(TRUE);
			bWindowMode = true;
		}
	}

	//ウインドウタイトルを設定
	SetMainWindowText(applicationTitle.c_str());

	// DXライブラリ初期化処理
	if (DxLib_Init() == -1) exit(EXIT_FAILURE);
}

void term()
{
	// DXライブラリ使用の終了処理
	DxLib_End();
}

起動時にプレイヤーがフルスクリーンにするかどうか選べるようにしてたフリーゲームがあって、便利なので真似したのですが、どのゲームだったか忘れてしまいました。

こんな感じでだらだらと報告を書いていこうと思います。飽きっぽい私でも、さすがにHit and Blowくらいなら完成させられる、はず。

Myはてながリニューアルされてた

私は! ダイアリーに帰ってきたぞ! ……というわけで久しぶりの更新です。ここのところハイクばっかりやってたのでちょっと文体変わったかもしれませんが。

Myはてなをリニューアルしました - はてなダイアリー日記」で告知されているとおり、Myはてながリニューアルされました。重要なのはプロフィール機能が追加されたことです。私のはこちらになります↓

ナノさんのプロフィール - はてな

以前はものすごいシンプルなページだったのですが、突然豪華になってしまいました。こういうページがあったらいいなとは思っていたのですが、ここまでの変更を突然行っちゃうとは……。ユーザーの反発を買ってでも、一般の人たちに受けそうなサイトを目指したいということなのでしょうか。今思えば、はてブお気に入られが見られるようになったのは今日のための伏線だったのかもしれませんね。

とりあえず、自己紹介は従来からあるダイアリーのものと共通ということで、仕方がないのでそれっぽく書き換えました。でも現状ではこのページへ行く方法があんまりないですよね(ダイアリーのプロフィールページから行ける程度?)。そのうち各サービスからプロフィールへのリンクが整備されるのでしょうけど。あと、「「Myはてな」リニューアルの感想 - uncommunicatable (t298ra)」で指摘されているとおり、プライベートモードのブックマーカーのidが見えてしまっているという問題もありますね(まさかわざと?)。これからどうなることやら。