Cafe capybara TECH-BLOG

PHPな会社でゴリゴリしてるあかいいぬの技術ブログです

Shoot Many Robots 2012/04/12のアップデート内容訳

基本的に内輪向けな感じ

  • Unicode文字を含んだWindowsのプロフィール名を持っている場合の信頼性の向上
  • 接続者が終了確認ダイアログを出している間にホストが終了するとクラッシュするバグの修正
  • マルチプレイ中にホストが垂直同期(Vertical sync)を切り替えた時にクラッシュするバグの修正
  • Souvenir Tam O'Shanterのbrogue継続時間の減少(?)
  • smrconfig.iniファイルがゲーム起動時にすぐ書き込まれるようになるので、手動でセッティングを変更することが出来る
  • smrconfig.iniにグラフィックオプションを追加し、低スペックマシンを使っている場合はそれらをオフにすることが出来る
    • Anti-aliasing(輪郭のギザギザを低減する処理)
    • Fog(遠くを霧がかかったようにする処理)
    • Outline rendering(輪郭を黒くする処理)
    • Global illumination(光源関連の処理)
    • Shadow filtering(影の品質向上)

メンバーに、オプションの設定が反映されないという人がいたので、今回のアップデートでそれが修正されたかもしれませんね。

他にも色々と修正してほしい所はポツポツありますので、このままどんどん修正を行なっていってほしいものです。

Shoot Many Robots プレイ感想

Shoot Many Robots(通称SMR)で検索していらっしゃってる方が幾分かいるようなので、せっかくなのでプレイの感想を載せてみたいと思います。

現在の所はステージ3まで(全部で13ステージくらいあるはず)プレイして、レベルは21あたり(MAX50)です。

Steamの紹介文も更新されているので、訳も更新しないとダメかなあ。

Ustreamアーカイブ

Ustreamの方にプレイ開始から3時間ほどをアーカイブで残しています。長いので飛ばし飛ばし雰囲気を感じ取って頂ければとおもいます。

概要

シンプルな横スクロールのシューティングゲーム。以前ハンゲームに「ガンストライク」というものがありましたが、まさにそんな感じ。

メジャーなものでは「メタルスラッグ」が当てはまるとおもいます。

RVで武器の準備や他のプレイヤーとの接続を行なって、それからステージに降り立つ流れです。シンプルでとても楽。

爽快感がある

f:id:expert88:20120410231638j:plain
実際の戦闘ですが、たくさんのロボットをガンガンぶっ壊していくのは結構爽快です。

※ただ、人数が少ないと敵の数も減ってしまって、爽快感というと四人以外では中々感じられないかもしれません。

アイテムが豊富

f:id:expert88:20120410232116j:plain
装備できる5種類各々に60~80個程度のアイテムがあります。

メインウェポンは、低レベル帯ではSMG、リボルバー、AR、スナイパー、火炎放射器、ショットガンのようにジャンル分けされていて、レベルが上がるごとにそれぞれのより強いものがアンロックされるようです。

それぞれのジャンルに得意不得意があるので、個性が出ます。

防具系(ギア)はかなり独特な風貌のものが多く、宇宙飛行士になったり変態(!)になったりすることが出来ます。
(実用性を考えると、選択肢は中々減ってしまいますが...)

やりこみ要素がある

各装備、レベル上限の50Lvで装備出来るアイテムが10個前後あります。もちろん購入価格も非常に高いので、繰り返しプレイしてコレクションしていくのも楽しいでしょう。

敵を倒すのが楽しい

f:id:expert88:20120410232547j:plain
たくさんの種類の敵は、それぞれ独特のAIと倒し方を持っていて、注意すべき攻撃や攻撃の避け方など、常に注意して戦場を見ていないとすぐにやられてしまいます。

特に防御力を増加させる装備はそれほど多くなく、レベルが上がっても受けるダメージ量があまり変わらないのでゴリ押しが難しくなっています。

ステージ3までの感想として、ボスはあまり強くありませんが、時々出る中ボスが中々怖かったりします。


もちろん問題点もあります。でも、どれもアップデートによって解決しそうな気もします。

クロスヘアが見づらい

f:id:expert88:20120410230718j:plain
マウスで狙っている位置を示すクロスヘアですが、赤一色なので結構な確率で見失います。

せめて白、出来れば複数の色を使って見やすいクロスへアに変えたいものです。

スライディングの方向がクロスヘアの位置で決まる

f:id:expert88:20120410230949j:plain
Sキーでスライドが出来るアイテムがいくつかあるのですが、スライディングの方向が「クロスヘアが画面の左右どちら側にあるか」で決まります。

一見わかりやすいように見えますが、例えば右に移動しながら(Dキーを押しながら)左側の敵に攻撃しつつスライディングをすると、急に左に戻ってしまって混乱することがあります。

また、左の敵を倒して右にスライディングで移動しようと思っても、クロスヘアは左側にあるので左に戻ってしまうことも。

移動している方向にスライディング出来ればこのような操作ミスはなくなるのですが...。

通信が若干不安定になる

プレイ中、特に敵の数がとても多くなった時、中ボス級の敵を倒してアイテムがたくさん出た時などで、他のキャラクターの動きが止まったりします。

回線自体そこまでいいものを使っていない場合、それがどの場所でも起こるので、かなりプレイに影響が出るレベルです。

WiMAXやe-mobileなどの無線の回線を使ってプレイしようと思っている方は注意を。

日本語化について

日本語化のキーワードでいらっしゃっている方もおるらしいですが、申し訳ない。ここでは全く日本語化に関しての情報はありません。

軽くファイル構成を見た感じ、独自形式ですべてのファイルが圧縮されているみたいなので、簡単には日本語化は難しそうです。

公式での日本語化というのも、おそらくないでしょう。独立系のゲームですから。


とにかく、最終ステージのクリアまではガンガン楽しく進められそうです。$20ゲームとしてはオススメ!

Shoot Many Robots日本語訳

Steamで4月7日に発売予定となっている「Shoot Many Robots」という横スクロールシューティングゲームについて、Steam紹介ページの日本語訳をしてみることにしました。

Steamでの販売ページはこちら→ Pre-purchase Shoot Many Robots on Steam

元の文章、ムービー、スクリーンショットなどもページにあるので、ぜひご一読を。

概要

この4人協力撃って走ってなアクションシューティングは、すげえ数で襲ってくる悪いロボット達を武器で一斉掃射する、シューター御用達のゲームだ。

プレイヤー達は、銃、弾薬、そしてビールをボロボロのRVに積み込んでロボット達の大破壊を待つ、山男のP. Walter Tugnutを操作するのだ(Pはピクルスの略だぜ)。

遠くにある捨てられた工場からそのロボット達が生み出された時、Walterはロボット潰しにワクワクしながらRVから降りる。ロボットの大群を潰しまくって、人間性が失われないことを願うばかりだ。

Steam限定予約購入

予約購入でゲーム内アイテムのWalter用「ゴードン・フリーマンの服」(着ているとゲーム内にPortalのタレットが出るんだ)、そしてTeam Frotress 2のMedicかPyro用の「スクラップパック」を手に入れよう!

主な特徴

撃って走って

古典的な2.5D横スクロールシューティングを、現代のゲームデザインに再活性化させた。

4人協力

ロボットの軍隊をやっつけるため、四人までオンラインで協力しあうことが出来る。

キャラクターカスタマイズ

プレイスタイルに合わせて、数えきれないほどの組み合わせでクレイジーなアイテムを装備することが出来る。プレイヤーはロボット殺戮でレベルアップし、キャラクタの能力を向上させたり、新しいミッションや装備をアンロックしたり出来る。

多数のミッション

ロボットのテリトリーを押し進んでいくミッション...章の終わりにボスとの戦闘があるサバイバルなミッション...ロボットの大群に打ち勝つだけの息の詰まりそうなレベル。もちろんチャレンジャーのために、三つの難易度でプレイヤーを痛めつける。

多様な戦闘

戦闘には2つの武器を持ち込める...だが、これは難しい選択となるだろう。リボルバー、ロケットランチャー、アサルトライフル、火炎放射器、サブマシンガン、そしてショットガン。どれも使いたくなるようなものばかりだが、さらに冷凍光線、石像ランチャー、そしてロボットの爆発系ロボットのおとりになる猫バズーカもある。近接攻撃は、プレイヤーはロボットをノックバックさせつつダメージを与えるパンチが可能だ(そしてやらないといけない)。ロボットから放たれたロケットもタイミングが合えばパンチ出来る、もちろん奴らの顔面目掛けて飛んでいくぞ。

個性的なロボット

たくさんのロボット...小さなチェーンソーを装備した小型ヘリから、燃える巨大な豚野郎まで...全て独特の特徴、AI、独特の殺し方、さらに難易度が上がればより獰猛になって現れる。


...自分で翻訳してて、下手だなあと思う。英語は英語のまま理解するのが一番です...。

ワンダーランドと羊の歌 歌わせて頂きました

ニコ動歌ってみた新曲。こちらにも投稿することにしました。

是非聞いて、罵ってやってください。

このハチさんの曲、ワンダーランドと羊の歌は、2010年7月と結構昔のものなんですが、投稿当初からずっと好きで聞き続けている曲です。

ハチさんが出すものはどれも好きなのですが、この曲は南方研究所さんのオリジナルPVもあり、その雰囲気と曲調がものすごく好きなのです。

実際色々歌ってみてはいるのですが、この曲は歌いやすい音域なので、投稿するレベルまで歌うことが出来ました。

一年前の一人カラオケ全盛期なら実はかなり広い音域があったのですが、半年ほど全く声を出さない時期を作ってしまって、今はもう高音が全然ダメダメです。

尊敬する灯油さんの歌う曲やその歌い方は昔は真似出来たのに、今は全然でなくて...。

ちなみに動画のタイトルは灯油さんリスペクトな形式です。


次は何を歌おうか...今まで家で録っていましたが、これから学校に行くようになれば防音設備のある小練習室が使えるようになるので、多分そちらで収録することになるかと思います。いやあ楽しみだ。

家だと最大声量で歌えないので、もっと激しい曲が録れたらいいなあと思っています。

FPSゲームの作り方 3.銃を撃つ

キャラクターも出てきたところで今回は、シューティングの肝である、「銃を撃つ」というアクションを実装します。

まだゲーム性(勝ったり負けたりがある)は出てきませんが、FPSっぽくはなります!

銃弾を実装する

左クリックをすると、視点の中心から向いている方向に銃弾が発射されるという流れです。

まず最初に、銃弾のクラスを実装します。

	/// <summary>
	/// 銃弾を表すクラス
	/// </summary>
	public class Bullet
	{
		/// <summary>
		/// 銃弾の速度
		/// </summary>
		public static readonly float Speed = 10f;

		/// <summary>
		/// 発射位置
		/// </summary>
		public Vector3 BasePosition
		{ get; private set; }

		/// <summary>
		/// 発射方向
		/// </summary>
		public Vector3 Direction
		{ get; private set; }

		/// <summary>
		/// 発射したキャラクタ
		/// </summary>
		public Character Shooter
		{ get; private set; }

		private float _distance;
		private float _distance_prev;

		public Bullet(Vector3 basePosition, Vector3 direction, Character shooter)
		{
			BasePosition = basePosition;
			Direction = direction;
			Shooter = shooter;
		}

		/// <summary>
		/// 銃弾の場所を更新する。
		/// trueを返した場合、その銃弾は削除される。
		/// </summary>
		public bool Update(GameTime gameTime)
		{
			_distance_prev = _distance;
			_distance += Speed;

			return _distance > 10000;
		}
		public void Draw(GraphicsDevice device)
		{
			var vertices = new VertexPositionColor[] {
					new VertexPositionColor(BasePosition + Direction * _distance_prev, Color.Yellow),
					new VertexPositionColor(BasePosition + Direction * _distance, Color.Yellow)
			};
			device.DrawUserPrimitives<VertexPositionColor>(
				PrimitiveType.LineList, vertices, 0, 1);
		}
	}

これ単体は1つの銃弾を表します。

敵の銃弾も自分の銃弾も、同じこのクラスを使います。

shooterというのは、誰が撃ったかを表すもので、これを使ってダメージの有無を判断します。

さらに、この銃弾を管理するクラスを1つ用意します。

	/// <summary>
	/// 銃弾を管理するクラス
	/// </summary>
	public class BulletManager : DrawableGameComponent
	{
		private Camera _camera;
		private BasicEffect _basicEffect;
		private List<Bullet> _bulletList;

		public BulletManager(Game game, Camera camera)
			:base(game)
		{
			_camera = camera;
			_bulletList = new List<Bullet>();

			// ゲームのコンポーネントに登録する
			game.Components.Add(this);
			game.Services.AddService(typeof(BulletManager), this);
		}

		public override void Initialize()
		{
			base.Initialize();

			// ゲームコンポーネント内でGraphicsDeviceを使用する際はbase.Initialize()の後で
			_basicEffect = new BasicEffect(GraphicsDevice);
			_basicEffect.VertexColorEnabled = true;
		}

		/// <summary>
		/// 銃弾を発射する
		/// </summary>
		public void Shoot(Vector3 basePosition, Vector3 direction, Character shooter)
		{
			_bulletList.Add(new Bullet(basePosition, direction, shooter));
		}

		public override void Update(GameTime gameTime)
		{
			for (int i = 0; i < _bulletList.Count; i++)
			{
				// trueなら削除する
				if (_bulletList[i].Update(gameTime))
				{
					_bulletList.RemoveAt(i);
					i--;
				}
			}

			base.Update(gameTime);
		}

		public override void Draw(GameTime gameTime)
		{
			_basicEffect.View = _camera.View;
			_basicEffect.Projection = _camera.Projection;
			_basicEffect.CurrentTechnique.Passes[0].Apply();

			foreach (var b in _bulletList)
			{
				b.Draw(GraphicsDevice);
			}

			base.Update(gameTime);
		}
	}

今回は「DrawableGameComponent」というXNAの機能を使いました。

この抽象クラスを継承すると、メインクラス(Gameクラス)と同じメソッドの動きをし、ゲームのコンポーネントとして登録することで、自動でUpdate、Drawなどおこなってくれます。
(正確には、Gameクラスのbase.Update(),base.Draw()などの部分で行われています)

銃弾を発射する際はShootメソッドを呼び出すだけですね。

Character抽象クラスがこのBulletManagerを保持するようにちょっといじります。

		/// <summary>
		/// 銃弾管理クラス
		/// </summary>
		protected BulletManager BulletManager
		{ get; set; }

		public Character(Model modelData, BulletManager bulletManager)
		{
			ModelData = modelData;
			BulletManager = bulletManager;
			Diffuse = Color.White;
		}

コンストラクタの部分に変数の宣言と、引数からの代入を加えました。

		public MyCharacter(Model modelData, BulletManager bulletManager)
			: base(modelData, bulletManager)

		public EnemyCharacter(Model modelData, BulletManager bulletManager, Random r)
			: base(modelData, bulletManager)

MyCharacterとEnemyCharacterの宣言部分もこのように書き加えます。

さらにMyCharacterのUpdateメソッドに銃を撃つ処理を加えます。

		public override void Update(GameTime gameTime)
		{
			// 左クリックしてたら弾を撃つ
			if (Mouse.GetState().LeftButton == ButtonState.Pressed)
			{
				Vector3 dir = Vector3.TransformNormal(Vector3.Forward,
					Matrix.CreateFromYawPitchRoll(Yaw, Pitch, 0));
				BulletManager.Shoot(Position, dir, this);
			}
		}

BulletManagerをメインのクラスに追加します。

	public class Game1 : Microsoft.Xna.Framework.Game
	{
		// ~中略~

		BulletManager _bulletManager;

		public Game1()
		{
			graphics = new GraphicsDeviceManager(this);
			Content.RootDirectory = "Content";
		}

		protected override void Initialize()
		{
			// エフェクトの作成
			_basicEffect = new BasicEffect(GraphicsDevice);
			_basicEffect.VertexColorEnabled = true;
			_basicEffect.TextureEnabled = false;
			_basicEffect.LightingEnabled = false;

			// 地面のポリゴン作成
			_ground = new VertexPositionColor[] {
				new VertexPositionColor(new Vector3(-512, -10, -512), Color.White),
				new VertexPositionColor(new Vector3( 512, -10, -512), Color.Red),
				new VertexPositionColor(new Vector3(-512, -10,  512), Color.Green),
				new VertexPositionColor(new Vector3( 512, -10,  512), Color.Blue),
			};

			// カメラ操作クラス一覧を作成
			_cameraOperator = new List<CanOperateCamera>();

			// カメラを作成して射影行列を設定
			_camera = new Camera(Matrix.CreatePerspectiveFieldOfView(
				MathHelper.PiOver2, GraphicsDevice.Viewport.AspectRatio, 1, 10000),
				GraphicsDevice.Viewport);
			// フリーカメラをカメラ操作クラス一覧に追加
			_cameraOperator.Add(new FreeCamera());

			// 銃弾管理クラスを作成
			_bulletManager = new BulletManager(this, _camera);

			// キャラクター一覧を作成
			_characters = new List<Character>();

			base.Initialize();
		}

		protected override void LoadContent()
		{
			// 自キャラクラスを作成
			MyCharacter myChar = new MyCharacter(Content.Load<Model>("CharCube"), _bulletManager);
			_cameraOperator.Add(myChar);
			_characters.Add(myChar);

			// 敵を10体キャラクター一覧に追加
			Random r = new Random();
			for (int i = 0; i < 10; i++)
				_characters.Add(new EnemyCharacter(Content.Load<Model>("CharCube"), _bulletManager, r));
		}

初期化を全てLoadContentメソッド内で行なっていましたが、ちゃんとInitializeとLoadContentに分けました。

LoadContentではContentを利用するものを、Initializeではそれ以外を初期化するためにあります。

Initializeメソッド内でContentを使おうとすると、エラーが起きます(base.Initialize()後ならいいですが...)。

現時点でこんな感じになりました。

あれ...なんかレーザービーム(CV.柳生比呂士)みたいになってますね。弾速が遅いのもありますが、とにかく絶えず銃弾が出ているのでこんなことになっているようです。

間隔を空けて撃つ

ある程度間隔を空けて撃つようにしましょう。これはMyCharacterをいじるだけで出来ます。

		private readonly float _shootInterval = 80;
		private float _shootIntervalNow;

		public MyCharacter(Model modelData, BulletManager bulletManager)
			: base(modelData, bulletManager)
		{
			Diffuse = Color.Blue;
		}

		public override void Update(GameTime gameTime)
		{
			// 左クリックしてたら弾を撃つ
			if (Mouse.GetState().LeftButton == ButtonState.Pressed)
			{
				_shootIntervalNow += (float)gameTime.ElapsedGameTime.TotalMilliseconds;

				if (_shootIntervalNow > _shootInterval)
				{
					Vector3 dir = Vector3.TransformNormal(Vector3.Forward,
						Matrix.CreateFromYawPitchRoll(Yaw, Pitch, 0));
					BulletManager.Shoot(Position, dir, this);
					_shootIntervalNow = 0;
				}
			}
			else _shootIntervalNow = 1000;
		}

float _shootIntervalNowという変数を用意して、クリックしている間だけ、フレーム分の経過時間を追加します。

ある程度まで時間が経過したら実際に発射し、数値を0に戻す。これを繰り返すだけです。

左クリックしていない間は数値を大きくしておきます。これで一発目がクリックした瞬間に撃たれるようになります。

だいぶ銃っぽくなってきました。

第四回では、ついに「当たり判定」と戦ってみたいと思います。

自分の撃った弾が敵に当たると、敵を倒せる。これだけでもうゲームですね。