夏までにiPhone アプリつくってみっか!

趣味でiPhone/Androidアプリを開発し、日々勉強した事を書いています。オープンワールド系レースゲームをUnityで開発中です。

Unity 5でMCLAのようなオープンワールドレーシングゲームを作ってみたい

ミッドナイトクラブ ロサンゼルス(MCLA)というレースゲームをご存知ですか?

2009年発売と結構古いゲームなのですが、つい先日Xbox 360用を購入したところすっかりハマってしまい、ゲーム開発の方がおろそかになってしまいました。

上のリンクはPS3版ですが、このComplete Editionというやつのダウンロード版です。
拡張マップなどのダウンロードコンテンツが入っていてお得なのですが、ローカライズされていないので英語が苦手な人は要注意です。登場人物がチンピラ英語を話すので英語が苦手でない人でも聞き取るのが大変かも知れません。私は無理でした。

MCLAについて簡単に説明すると、「時間、天気が変化するLAの街を自分の好きなように走り回り、気が向いたら街のチンピラレーサーにレースを挑んで金を巻き上げる」というオープンワールドレーシングゲームなのですが、時間や天気の変化を反映したグラフィックが結構リアルなので「LAに住んでる感」が味わえます。

TravelShooting JPの次はUnity 5で3Dゲームを作ろうかと考えていたので、とりあえず、こういうオープンワールドなレースゲームを作ってみようと思います。

実は以前Unityを使って適当にボウリングゲームを作り始めたものの勉強不足のためすぐに挫折した事があります。
tf.hateblo.jp

今回は挫折しないようにゲーム制作に手を出す前に公式チュートリアルRoll-a-BallSpace ShooterSurvival Shooter2D Roguelikeを終わらせ、UnityとC#をある程度理解した状態で再挑戦します。

3Dのモデリングをする能力は持っていないので、オープンワールドな街は無料で公開されているZenrinのJapanese Otaku Cityをありがたく使わせて頂くことにします。
車はとりあえずUnityに標準で入っているものを使い、秋葉原の街の中に配置します。
そのままでも動くのですが、ハンドリングがクイックすぎるので速度に応じたステアリングの切れ角の制御やタッチパネルからの入力の処理などをiCarUserControl.csスクリプトに追加しました。

using System;
using UnityEngine;

//using UnityStandardAssets.CrossPlatformInput;

namespace UnityStandardAssets.Vehicles.Car
{
	[RequireComponent (typeof(CarController))]
	public class CarUserControl : MonoBehaviour
	{
		private CarController m_Car;

		private Vector2 touchOrigin = Vector2.zero;
		private float currentSteer = 0f;
		private float currentThrottle = 0f;
		// the car controller we want to use


		private void Awake ()
		{
			// get the car controller
			m_Car = GetComponent<CarController> ();
		}


		private void FixedUpdate ()
		{
			// pass the input to the car!
//			float h = CrossPlatformInputManager.GetAxis ("Horizontal");
//			float v = CrossPlatformInputManager.GetAxis ("Vertical");
//			float handbrake = CrossPlatformInputManager.GetAxis ("Jump");
			const float maxX = 30f;
			const float maxY = 50f;
			const float steerSensitivity = 0.5f;
			const float throttleSensitivity = 0.1f;
			const float steerMinCenter = 0.01f;
			const float throttleMinCenter = 0.01f;
			const float mobileSpeedFactor = 0.3f;
			const float deskTopSpeedFactor = 0.05f;
			float targetSteer = 0f;
			float targetThrottle = 0f;
#if UNITY_STANDALONE || UNITY_WEBPLAYER || UNITY_EDITOR
			float speedFactor = (m_Car.CurrentSpeed + 1) * deskTopSpeedFactor; // +1はゼロの割り算にならないように
			targetSteer = Input.GetAxis("Horizontal") / speedFactor;
			targetThrottle = Input.GetAxis("Vertical");
#elif UNITY_IOS || UNITY_ANDROID || UNITY_WP8 || UNITY_IPHONE
			float speedFactor = (m_Car.CurrentSpeed + 1) * mobileSpeedFactor;
			float maxSteer = maxX * speedFactor;
			if (Input.touchCount > 0) {
				Touch mytouch = Input.touches [0];
				if (mytouch.phase == TouchPhase.Began) {
					touchOrigin = mytouch.position;
				} else if (mytouch.phase == TouchPhase.Moved || mytouch.phase == TouchPhase.Stationary) {
					Vector2 touchDiff = mytouch.position - touchOrigin;
					targetSteer = (Mathf.Clamp (touchDiff.x, -maxSteer, maxSteer) / maxSteer);
					targetThrottle = Mathf.Clamp (touchDiff.y, -maxY, maxY) / maxY;
				}
			}
#endif
			currentSteer = Mathf.Lerp (currentSteer, targetSteer, steerSensitivity);
			currentThrottle = Mathf.Lerp (currentThrottle, targetThrottle, throttleSensitivity);
			if (targetSteer == 0f && currentSteer <= steerMinCenter) {
				currentSteer = 0f;
			}
			if (targetThrottle == 0f && currentThrottle <= throttleMinCenter) {
				currentThrottle = 0f;
			}
				
			m_Car.Move (currentSteer, currentThrottle, currentThrottle, 0f);

		}
	}
}

完成したのがこちら。

まだ敵車はいませんが、歩道橋に登ってジャンプしたり一人でもそこそこ遊べます。
UnityのアセットにはAIで走る車も用意されているようなので、次はこれを使って敵車を走らせてみたいと思います。