Hatena::Groupgamehell

ゲームプログラムめも日記 このページをアンテナに追加 RSSフィード

けんもほろろ  / オススメゲームプログラム本  / 作ったもの置き場  
ゲーム開発のデザパタまとめ  / めも日記まとめ  

2008-01-21

[]今日のキーワード追加 18:01 今日のキーワード追加 - ゲームプログラムめも日記 を含むブックマーク はてなブックマーク - 今日のキーワード追加 - ゲームプログラムめも日記 今日のキーワード追加 - ゲームプログラムめも日記 のブックマークコメント

今更ですが、

実例で学ぶゲームAIプログラミング

実例で学ぶゲームAIプログラミング

を買ったので、その内容をkenmoなりにまとめてみましたー。

masa_no_pagemasa_no_page2008/01/24 04:19会社から借りてる「ゲーム開発者のためのAI入門」てのうちにあるけど別物かな。
著・訳が違うから完全に別物なんだと思うけど、タイトルだけならまだしも珍ザルの絵まで似てるからウケルwww

masa_no_pagemasa_no_page2008/01/24 04:23あっ!
いつも書き込んでる知り合いのブログと素で間違えてて慣れ慣れしい書き込みしてしまいました^^;;;;
初めましての者です。つたないものですがどうぞよろしくm(_ _)m

kenmokenmo2008/01/24 12:45「ゲーム開発者のためのAI入門」は、AIの知識が幅広く紹介されているのに対して、
コチラの本は、ポイントを絞っていて、深い内容ではないかと思います。
……確かにあまりにもタイトル・絵が似てて、本屋で見つけたとき、「おや?」と思いましたが(w

こちらこそ、よろしくお願いしますー。

2007-12-20

[] ゲームのはこづめVol.6 19:26  ゲームのはこづめVol.6 - ゲームプログラムめも日記 を含むブックマーク はてなブックマーク -  ゲームのはこづめVol.6 - ゲームプログラムめも日記  ゲームのはこづめVol.6 - ゲームプログラムめも日記 のブックマークコメント

今年も出るみたいですよ、 ゲームのはこづめVol.6、、。

http://maglog.jp/alpha-secret-base/Article227598.html


kenmoは、

  • 菜月さん☆ブースト2
  • RECT WINDER ASCII
  • THE脱出004

で参戦しております。


まー、菜月さん☆ブースト2以外は微妙なゲームですが、、(´Д`;


せっかくなので、菜月さん☆ブースト2は体験版を置いておきました。

よかったらプレイしてみてくださいなー。

http://www5f.biglobe.ne.jp/~kenmo/dest/d/natsuki2_trial.zip

■操作方法

マウス操作で、

  • 左クリック:攻撃
  • 右クリック:移動

です。


EASY/NORMALまで遊べます。NORMALは、はこづめ版より少し難しくしてあります。


なんかね、、kenmoは全方位シューのつもりで作ったのに、誰にも理解されなかったよ!

やっぱり自機から弾が出ないとシューティングと言えないのだろうか、、。

ただ、マウスって、どうしてもアバウトな入力しかできないから、こういう操作体系にするのがいいのでは、などと模索しながら作りました。


そんなわけで、気に入ったら、はこづめ版をよろしくお願いしますo(. .)o HELLモードが超展開(wなので、、!


以上、宣伝でした。

[]誰のためのデザイン? 19:26 誰のためのデザイン? - ゲームプログラムめも日記 を含むブックマーク はてなブックマーク - 誰のためのデザイン? - ゲームプログラムめも日記 誰のためのデザイン? - ゲームプログラムめも日記 のブックマークコメント

宣伝だけじゃアレなので、最近読んだ本の話でも。

だいぶ古い(1990年発売)本ですが、今読んでもかなり役に立ちます。(ゲームづくりに)

 

要はインターフェースについて、認知心理学的な視点から色々書かれている本です。

 

今まで、ゲームをやってて、「これはインターフェースが悪い」という印象を持ったりしても、それを具体的な言葉にはなかなかできていなかったような気がします。

 

この本は、そういった曖昧に感じていたものを、理論的に言葉で説明できるための知識を与えてくれるものです。

 

悪いインターフェースはだいたい以下の4つに問題があるみたい。

  • 可視性
  • 対応付け
  • 概念モデル
  • フィードバック

可視性とは、その機能・操作をユーザが視認できるかどうか。対応付けとは、操作に対する結果がイメージできるものかどうか。概念モデルとは、機能・操作のフローをユーザがイメージ(モデリング)できるかどうか。フィードバックとは、操作(入力)対して、必要なフィードバックがちゃんと受けられるかどうか、ということみたいです。(たぶん

 

分厚い本ですが、まあ、簡単に目を通しておくだけでも、役に立つような気がします(kenmoも全部読めてないし(w

 

アフォーダンスとかの話もあって勉強になりますよー。

2007-09-28

アスキーコードマップエデ

[]アスキーコードマップエディタ 21:34 アスキーコードマップエディタ - ゲームプログラムめも日記 を含むブックマーク はてなブックマーク - アスキーコードマップエディタ - ゲームプログラムめも日記 アスキーコードマップエディタ - ゲームプログラムめも日記 のブックマークコメント

前々から作ってみようと思っていた、アスキーコードマップを作れるエディタを作ってみた。

いや、まあ、作ったと言っても、Platinumのプラグインですがー。

 

http://www5f.biglobe.ne.jp/~kenmo/dest/tool/ascii.zip

 

この中のDLLをPlatinumの「Plugins」に入れて、ascii形式の「書き出し」をすると、

例えば、こんな感じのテキストファイルが出力されます。

SIZE=400
WIDTH=20
HEIGHT=20
CHIP_WIDTH=32
CHIP_HEIGHT=32
LAYER_COUNT=1
BIT_COUNT=8

####################
#                  #
#                  #
#                  #
#   +              #
#  +++  B A        #
#   +              #
#                  #
#                  #
#      HELL        #
#      2000        #
#                  #
#                  #
#                  #
#                  #
#                  #
#                  #
#                  #
#                  #
####################

 

これで、Platinumを使って編集してもいいし、

テキストエディタを使って編集してもいい、ってなわけです。

追記

改行文字の書き込みがおかしかったのを修正。

// 改行文字書込み
bool WriteFileCRLF(HANDLE hFile)
{
	int val = 0x0D0A;
	DWORD dwWriteBytes;
	if (!WriteFile(hFile, &val, 2, &dwWriteBytes, NULL) || 
		dwWriteBytes != 2)
	{
		return false;
	}
	return true;
}

リトルエンディアンなので、こうですね。

	int val = 0x0A0D;

o_megao_mega2007/09/28 01:06@の不思議なダンジョン!

kenmokenmo2007/10/01 09:33@の冒険が、今、始まる……。

2007-09-27

当たり判定エディタ

[]当たり判定エディタ 12:27 当たり判定エディタ - ゲームプログラムめも日記 を含むブックマーク はてなブックマーク - 当たり判定エディタ - ゲームプログラムめも日記 当たり判定エディタ - ゲームプログラムめも日記 のブックマークコメント

なんか思いつきで、使う予定もないのに作ってみた。

http://www5f.biglobe.ne.jp/~kenmo/dest/tool/hiteditor.zip

 

使い方は、

  1. 画像読込」ボタンを押下
  2. ファイル選択ダイアログから、当たり判定を行う画像を選択
  3. 画像を左クリックして当たり判定をつける
  4. 複数付けたい場合、コンボボックスから別の番号を選択して、左クリックする
  5. 完成したら、「保存」ボタンを押下して、設定ファイルを保存する

です。

 

当たり判定の設定ファイルフォーマットはこんな感じ

[HEADER]
IMAGE=nya.bmp # 画像のパス
WIDTH=128     # 幅
HEIGHT=128    # 高さ
[DATA]
DATA1=1,68,7,50,42
DATA2=1,24,66,48,45
DATA3=0,0,0,0,0
DATA4=0,0,0,0,0
DATA5=0,0,0,0,0
DATA6=0,0,0,0,0
DATA7=0,0,0,0,0
DATA8=0,0,0,0,0

基本はINIファイル形式です。

 

ヘッダ部は、画像パスと幅と高さです。

データ部は、当たり判定のカンマ区切りのCSVデータで、

  1. 使用可否フラグ(0:未使用 1:使用する)
  2. 左上X座標
  3. 左上Y座標
  4. 高さ

という順番で並んでおります。

 

 

これを作った後で気がついたのですが、

Platinumのようなマップエディタでも、

当たり判定エディタとして使えるのではないかと。

 

たとえば、こんな感じで、

f:id:kenmo:20070927122200p:image

キャラ画像を再背面に置いて、

レイヤーで当たり判定チップを置いていけば、複雑な当たり判定ができてしまいます。

 

ただ、当たり判定をしない部分に、「何もないよ」という情報を持つので、

少しだけ冗長なデータ構造となりますが。

 

kenmoの作ったエディタとの違いは、

ベクタ画像ラスタ画像の違いのようなものですね。

2007-09-20

[]INIファイル読み込みクラス 11:40 INIファイル読み込みクラス - ゲームプログラムめも日記 を含むブックマーク はてなブックマーク - INIファイル読み込みクラス - ゲームプログラムめも日記 INIファイル読み込みクラス - ゲームプログラムめも日記 のブックマークコメント

ふと思い立って、INIファイルの読み込みクラスを作ってみた。

private import std.ctype;
private import std.file;
private import std.string;

/**
 * INIファイル読み込みクラス
 */
class INILoader
{
private:
	char[][char[]] _data; // データ(キーと値)
public:
	this() {}
	/**
	 * INIファイル読み込み
	 * @param filepath ファイルパス
	 */
	void load(char[] filepath)
	{
		auto file = cast(char[])read(filepath);
		foreach(i, b; split(file, "\n"))
		{
			int idx = find(b, '#');       // コメント文字を検索
			if(idx >= 0) b = b[0..idx];   // コメントを除去
			b = strip(b);
			if(b.length == 0) continue;
			if(find(b, '=') < 0) throw new Error(format("INILoader.load(): invalid syntax -> '%s'(%d)", filepath, i+1));
			
			char[][] tmp = split(b, "="); // キーと値で分割
			if(tmp.length < 2) continue;
			char[] key = strip(tmp[0]);
			char[] val = strip(tmp[1]);
			_data[key] = val;
		}
		_data.rehash;
	}
	char[] get(char[] key)        { checkKey(key);         return _data[key];             } // 文字列で取得
	int    getint(char[] key)     { char[] val = get(key); return checkInt(key, val);     } // 整数で取得
	float  getfloat(char[] key)   { char[] val = get(key); return checkFloat(key, val);   } // 浮動小数で取得
	bool   getboolean(char[] key) { char[] val = get(key); return checkBoolean(key, val); } // 真偽で取得
	void dump()
	{
		printf("{\n");
		foreach(k; _data.keys)
		{
			printf("  \"%.*s\" : \"%.*s\",\n", k, _data[k]);
		}
		printf("}\n");
	}
private:
	void checkKey(char[] key)
	{
		if(key in _data) return;
		throw new Error(format("INILoader.checkKey(): not exist key ... '%s'", key));
	}
	int checkInt(char[] key, char[] val)
	{
		foreach(c; val)
		{
			if(!isdigit(c)) throw new Error(format("INILoader.checkInt(): not digit value ... '%s' -> '%s'", key, val));
		}
		return atoi(val);
	}
	float checkFloat(char[] key, char[] val)
	{
		foreach(c; val)
		{
			if(!isdigit(c) && c != '.') throw new Error(format("INILoader.checkFloat(): not digit value ... '%s' -> '%s'", key, val));
		}
		return atof(val);
	}
	bool checkBoolean(char[] key, char[] val)
	{
		switch(val)
		{
		case "1", "yes", "true",  "on":  return true;
		case "0", "no",  "false", "off": return false;
		default: throw new Error(format("INILoader.checkBoolean(): not boolean value ... '%s' -> '%s'", key, val));
		}
	}
}

やっていることは、たいしたことではないです。

例えば、こんなINIファイルを、、

# 自機
PLAYER_DAMAGE_SPEED = 8.0  # ダメージ時に吹き飛ばされる移動量
PLAYER_DECAY_SPEED  = 0.97 # 移動の減衰量
PLAYER_DAMAGE_TIMER = 120  # ダメージ時間(2sec)
PLAYER_COUNT_TIMER  = 40   # 体当たりでの打ち返し演出タイマ

キー=値

という書式をハッシュテーブルに突っ込むだけです。

「#」以降はコメントとして扱います。

(※セクションは使えません)

 

読み込むINIファイルを「game.ini」とすると、使い方はこんな感じ。

/**
 * システム定数管理
 */
class GH
{
public
	// プレイヤー
	static float PLAYER_DAMAGE_SPEED; // ダメージ時に吹き飛ばされる移動量
	static float PLAYER_DECAY_SPEED;  // 移動の減衰量
	static int   PLAYER_DAMAGE_TIMER; // ダメージタイマ
	static int   PLAYER_COUNT_TIMER;  // 体当たりでの打ち返し演出タイマ
	static void load()
	{
		scope ini = new INILoader();
		ini.load("game.ini");
		PLAYER_DAMAGE_SPEED = ini.getfloat("PLAYER_DAMAGE_SPEED");
		PLAYER_DECAY_SPEED  = ini.getfloat("PLAYER_DECAY_SPEED");
		PLAYER_DAMAGE_TIMER = ini.getint("PLAYER_DAMAGE_TIMER");
		PLAYER_COUNT_TIMER  = ini.getint("PLAYER_COUNT_TIMER");
	}
}

ゲーム起動(開始)時に、設定を読みにいって、staticに全部入れてしまうわけです。

で、この定数(正確には違うけど)を参照して、パラメータを決定するようにします。

 

 

まあ、この仕組み自体はたいしたことではないのですが、

ゲームって、パラメータの調整で、面白さが大きく変わってしまうことが良くあります。

 

そういうときに、コンパイルなしで設定ファイルをちょこちょこいじるだけで、

パラメータを調整できると、

 

「もうすこし反動を大きくしてみるかな、、」

とか、簡単に確認できますし、

「これで面白くなるかどうかわかんないけど、この値を大きくしてみよう!」

適当にやってみたら、意外に面白い動きになってしまった!!

 

なんて嬉しい効果があったります。

 

 

ということで、INIファイルゲームの設定ファイルとして使うと、

組み込みも簡単だし、調整も楽だよ!

という話でした。

[]INIファイル読み込みクラス17:50 INIファイル読み込みクラス2 - ゲームプログラムめも日記 を含むブックマーク はてなブックマーク - INIファイル読み込みクラス2 - ゲームプログラムめも日記 INIファイル読み込みクラス2 - ゲームプログラムめも日記 のブックマークコメント

Outputもできると汎用部品になりそう

ということで作ってみた。

 

private import std.ctype;
private import std.file;
private import std.string;

/**
 * INIファイル読み込みクラス
 */
class ConfigParser
{
private:
	int            _index;    // 現在のデータ番号
	char[][]       _indices;  // データ番号
	char[][char[]] _data;     // データ(キーと値)
	char[]         _filepath; // ファイルパス
public:
	this() {}
	void init()
	{
		// 初期化
		_index          = 0;
		_indices.length = 0;
		_data           = null;
		//foreach(k; _data) _data.remove(k);
	}
	void load(char[] filepath)
	{
		init();
		_filepath = filepath.dup; // ファイル名コピー
		// 読み込み
		auto file = cast(char[])read(filepath);
		// データを入れる
		foreach(b; split(file, "\n"))
		{
			int idx = find(b, '#');       // コメント文字を検索
			if(idx >= 0) b = b[0..idx];   // コメントを除去
			char[][] tmp = split(b, "="); // キーと値で分割
			if(tmp is null)    continue;
			if(tmp.length < 2) continue;
			char[] key = strip(tmp[0]);
			char[] val = strip(tmp[1]);
			set(key, val);
		}
		_data.rehash;
	}
	char[] get(char[] key)        { checkKey(key);         return _data[key];             } // 文字列で取得
	int    getint(char[] key)     { char[] val = get(key); return checkInt(key, val);     } // 整数で取得
	float  getfloat(char[] key)   { char[] val = get(key); return checkFloat(key, val);   } // 浮動小数で取得
	bool   getboolean(char[] key) { char[] val = get(key); return checkBoolean(key, val); } // 真偽で取得
	// 文字列の追加
	void   set(char[] key, char[] val)
	{
		if(!(key in _data))
		{
			_index++;
			_indices ~= key;
		}
		_data[key] = val;
	}

	void   set(char[] key, int    val) { set(key, std.string.toString(val)); } // 整数の追加
	void   set(char[] key, float  val) { set(key, std.string.toString(val)); } // 浮動小数の追加
	void   set(char[] key, bool   val) { set(key, std.string.toString(val)); } // 真偽の追加
	void write(char[] filepath=null)
	{
		if(filepath is null) filepath = _filepath;
		std.file.write(filepath, "");
		foreach(k; _indices)
		{
			append(filepath, format("%s = %s\n", k, _data[k]));
		}
	}
	void dump()
	{
		printf("{\n");
		foreach(k; _data.keys)
		{
			printf("  \"%.*s\" : \"%.*s\",\n", k, _data[k]);
		}
		printf("}\n");
	}
private:
	void checkKey(char[] key)
	{
		if(key in _data) return;
		throw new Error(format("ConfigParser.checkKey(): not exist key ... '%s'", key));
	}
	int checkInt(char[] key, char[] val)
	{
		foreach(c; val)
		{
			if(!isdigit(c)) throw new Error(format("not digit value ... '%s' -> '%s'", key, val));
		}
		return atoi(val);
	}
	float checkFloat(char[] key, char[] val)
	{
		foreach(c; val)
		{
			if(!isdigit(c) && c != '.') throw new Error(format("not digit value ... '%s' -> '%s'", key, val));
		}
		return atof(val);
	}
	bool checkBoolean(char[] key, char[] val)
	{
		switch(val)
		{
		case "1", "yes", "true",  "on":  return true;
		case "0", "no",  "false", "off": return false;
		default: throw new Error(format("not boolean value ... '%s' -> '%s'", key, val));
		}
	}
}

 

使い方はこんな感じ。

void main()
{
	// オブジェクト生成
	ConfigParser cfg = new ConfigParser();
	// 読み込み
	cfg.load("setting.ini");
	// デバッグ出力
	cfg.dump();
	// "TIMER_SHOT"の値の取得
	printf("%.*s\n", cfg.get("TIMER_SHOT"));
	// キー"hoge"、値"piyo"を追加・更新
	cfg.set("hoge", "piyo");
	// INIファイルに出力
	cfg.write();
}

インデックス用の配列を持って、

記述した順番で、出力するようにしてみました。

 

まあ、

  • インデントが崩れる
  • コメントが全部消える

という欠点はありますがー。

 

コメントを残すのは難しいですねー。

 

あと、set()は、値の更新・追加になります。

 

参考

PythonのConfigParser

http://www.python.jp/doc/2.4/lib/RawConfigParser-objects.html

追記

連想配列初期化が間違っていたので修正しました。

	//foreach(k; _data) _data.remove(k);
	_data           = null;

Dだと、nullを入れるのが、連想配列初期化する方法みたい。

o_megao_mega2007/09/20 12:17これでも十分便利だけど、Outputもできると汎用部品になりそう。といってみるテスト。
iniファイルのコメントを残しつつ出力できるとよさげー

wang-zhiwang-zhi2007/09/20 12:31ASCのときは何も考えずにcsv形式のデータをばっこんばっこん読み書きしてたんだけどキー定義のファイルのほうがいいね。

kenmokenmo2007/09/20 18:05>キー定義のファイルのほうがいいね
今回のは、「定数」を外出しするという目的なので、INI形式だと楽なんですよねー。
キャラのデータベースのような表形式のデータの場合は、CSVの方が扱いやすいし、
より複雑なデータを扱うなら、XMLかYAMLでしょうね。