4人まで参加してマルチプレイ出来ます。一人でもタイムアタックで遊べます。AI車は8台で3台が早いです。コースから落下したら戻ります。ほかの人がいる時抜けてもゲームは維持されます。
Photon Unity Network(PUN2)にアップデートしました。今回photon transform viewとphoton transform view classicをオブジェクトで使い分けました。free素材を使いました。
ゲーム説明
PC用:キーボードの カーソルキー「→」、「←」で左右にハンドルを切ります。 カーソルキー「↑」、「z」でアクセル「↓」、「x」でブレーキです。
スマホ用:タッチするとバーチャルパッドが表示されます。離すと消えて真っすぐになります。バーチャルパッドで左右にハンドルを切り、アクセルとブレーキはボタンで操作します。






①Asset StoreからPhoton Unity Networking Freeをimportします。
②unity standard assetsをimportします。standard assetsにあるUtilityを使います。
③Photon接続Script
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class NetworkManager : MonoBehaviour {
private float timeUP;
public GUIStyle style;
void Awake () {
// Server接続
PhotonNetwork.ConnectUsingSettings("v0.1");
}
// Lobby参加OK時
void OnJoinedLobby() {
// ランダムにRoom参加
PhotonNetwork.JoinRandomRoom();
}
// Room参加NG時
void OnPhotonRandomJoinFailed() {
// 名前なしRoom作成
PhotonNetwork.CreateRoom(null);
}
// Room参加OK時
void OnJoinedRoom() {
if (PhotonNetwork.countOfPlayers < 2) {
//プレイヤーをインスタンス化
Vector3 spawnPosition = new Vector3 (-53f, 0.5f, -11f); //生成位置
PhotonNetwork.Instantiate ("Player", spawnPosition, Quaternion.identity, 0);
Vector3 enemyPosition = new Vector3 (-53f, 0.5f, -5f); //生成位置
PhotonNetwork.InstantiateSceneObject ("Enemy", enemyPosition, Quaternion.identity, 0, null);
Vector3 enemy3Position = new Vector3 (-55.5f, 0.5f, -5f); //生成位置
PhotonNetwork.InstantiateSceneObject ("Enemy2", enemy3Position, Quaternion.identity, 0, null);
Vector3 enemy4Position = new Vector3 (-53f, 0.5f, -7f); //生成位置
PhotonNetwork.InstantiateSceneObject ("Enemy3", enemy4Position, Quaternion.identity, 0, null);
Vector3 enemy2Position = new Vector3 (-55.5f, 0.5f, -7f); //生成位置
PhotonNetwork.InstantiateSceneObject ("Enemy4", enemy2Position, Quaternion.identity, 0, null);
Vector3 enemy5Position = new Vector3 (-53f, 0.5f, -9f); //生成位置
PhotonNetwork.InstantiateSceneObject ("Enemy5", enemy5Position, Quaternion.identity, 0, null);
Vector3 enemy6Position = new Vector3 (-55.5f, 0.5f, -9f); //生成位置
PhotonNetwork.InstantiateSceneObject ("Enemy6", enemy6Position, Quaternion.identity, 0, null);
}
if (PhotonNetwork.countOfPlayers == 2) {
Vector3 spawnPosition = new Vector3 (-55.5f, 0.5f, -11f); //生成位置
PhotonNetwork.Instantiate ("Player", spawnPosition, Quaternion.identity, 0);
}
if (PhotonNetwork.countOfPlayers == 3) {
Vector3 spawnPosition = new Vector3 (-53f, 0.5f, -13f); //生成位置
PhotonNetwork.Instantiate ("Player", spawnPosition, Quaternion.identity, 0);
}
if (PhotonNetwork.countOfPlayers == 4) {
Vector3 spawnPosition = new Vector3 (-55.5f, 0.5f, -13f); //生成位置
PhotonNetwork.Instantiate ("Player", spawnPosition, Quaternion.identity, 0);
}
if (PhotonNetwork.countOfPlayers > 4) {
PhotonNetwork.Disconnect ();
}
}
// GUI表示
void OnGUI() {
// Photon接続状態
GUILayout.Label(PhotonNetwork.connectionStateDetailed.ToString());
timeUP += Time.deltaTime;
if (timeUP < 10f) {
GUILayout.Label ("count of players " + PhotonNetwork.countOfPlayers.ToString (),style);
}
}
}
AI車はPhotonNetwork.InstantiateSceneObjectでシーンにインスタンス化するので、接続しているプレーヤーがいる限り存在します。PhotonNetwork.countOfPlayersでプレーヤーの数によって座標を変更しているのは、同じ場所にインスタンス化するのを防止するためです。
④自車
Tagの名前をPlayerにします。Box Collider、Rigidbody、Audio Source、Photon View(Script)、Photon Transform View(Script)、そして下記のPlayermove(Script)をアタッチします。自車はProjectのResourcesにドラッグ&ドロップしてプレハブ化してHierarchyから削除します。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Playermove : Photon.MonoBehaviour {
private float baseDistance = 3f;
private float baseCameraHeight = 2f;
private float chaseDamper = 3f; // カメラの追跡スピード
Transform cam;
private float accel = 0;
AudioSource sound1;
AudioSource sound2;
AudioSource sound3;
// Use this for initialization
void Start () {
if (photonView.isMine) {
cam = GameObject.FindGameObjectWithTag ("MainCamera").transform;
//AudioSourceコンポーネントを取得し、変数に格納
AudioSource[] audioSources = GetComponents<AudioSource> ();
sound1 = audioSources [0];
sound2 = audioSources [1];
sound3 = audioSources [2];
}
}
// Update is called once per frame
void Update () {
if (photonView.isMine) {
if (Input.GetKey (KeyCode.DownArrow) || Input.GetKey (KeyCode.X)) {
if (accel > -0.7f) {
accel = accel - 0.03f;
}
}
if (Input.GetKey (KeyCode.UpArrow) || Input.GetKey (KeyCode.Z)) {
if (accel < 12.8f) {
accel = accel + 0.3f;
}
}
if (Input.GetKey (KeyCode.RightArrow)) {
transform.Rotate (0, 80 * Time.deltaTime, 0);
}
if (Input.GetKey (KeyCode.LeftArrow)) {
transform.Rotate (0, -80 * Time.deltaTime, 0);
}
accel = accel * 0.98f;
transform.position += transform.forward * Time.deltaTime * accel;
// カメラの位置を設定
var desiredPos = transform.position - transform.forward * baseDistance + Vector3.up * baseCameraHeight;
cam.position = Vector3.Lerp (cam.position, desiredPos, Time.deltaTime * chaseDamper);
// カメラの向きを設定
cam.LookAt (transform);
if (accel > 12.5f && sound3.isPlaying == false) {
sound3.Play ();
sound2.Stop ();
sound1.Stop ();
} else if (accel > 9.5f && accel <= 12.5f && sound2.isPlaying == false) {
sound2.Play ();
sound3.Stop ();
sound1.Stop ();
} else if (accel > 0.5f && accel <= 9.5f && sound1.isPlaying == false) {
sound1.Play ();
sound3.Stop ();
sound2.Stop ();
} else if (accel < 0.5f) {
sound1.Stop ();
sound3.Stop ();
sound2.Stop ();
}
}
}
}
⑤AI車のコースをつくる。
HierarchyでCreate Emptyをつくる。名前はWaypointsとします。そこにstandard assetsのUtilityにあるWaypointCircuitというスクリプトを持ってきます。WaypointsのInspectorを見て、WaypointCircuitコンポーネントのAssign using all child objectsをクリックし、子オブジェクトを元にルートを作成します。
⑥AI車
Box Collider、Rigidbody、Standard AssetsにあるWaypoint Progress Tracker(Script)、Photon View(Script)、Photon Transform View(Script)、そして下記のWaypoint1(Script)をアタッチします。InspectorでWaypoint Progress Tracker(Script)のTargetにHierarchyにあるオブジェクトWaypointsをドラッグ&ドロップします。AI車は動きを調整して出来上がってからプレハブ化します。動作確認したらProjectのResourcesにドラッグ&ドロップしてプレハブ化してHierarchyから削除します。プレハブ化すると、Waypoint Progress Tracker(Script)のTargetが空になるので、続けてWaypoint Progress Tracker(Script)そのものを修正します。
using System.Collections;
using UnityStandardAssets.Utility;
using UnityEngine;
[RequireComponent(typeof(WaypointProgressTracker))]
public class Waypoint1 : MonoBehaviour {
private WaypointProgressTracker tracker = null;
float speed = 12.8f;
void Start()
{
tracker = GetComponent<WaypointProgressTracker>();
}
void Update()
{
Vector3 targetPosition = tracker.progressPoint.position + tracker.progressPoint.direction;
transform.position = Vector3.MoveTowards( transform.position, targetPosition, speed * Time.deltaTime);
transform.LookAt (targetPosition);
Vector3 fwd = transform.TransformDirection(Vector3.forward);
if (Physics.Raycast (transform.position, fwd, 5)) {
speed = 8f;
} else {
speed = 12.8f;
}
}
}
⑦Waypoint Progress Tracker(Script)の修正。
プレハブ化すると、Waypoint Progress Tracker(Script)のTargetは空になります。インスタンス化していないためだと思われます。インスタンス化してから、HierarchyにあるオブジェクトWaypointsを読み込むよう修正します。Waypointsのタグをwaypointにします。
using System;
using UnityEngine;
namespace UnityStandardAssets.Utility
{
public class WaypointProgressTracker : MonoBehaviour
{
// This script can be used with any object that is supposed to follow a
// route marked out by waypoints.
// This script manages the amount to look ahead along the route,
// and keeps track of progress and laps.
private WaypointCircuit circuit;//<--- [SerializeField]の代わりに変数の宣言をしてvoid Start()で代入。
[SerializeField] private float lookAheadForTargetOffset = 5;
// The offset ahead along the route that the we will aim for
[SerializeField] private float lookAheadForTargetFactor = .1f;
// A multiplier adding distance ahead along the route to aim for, based on current speed
[SerializeField] private float lookAheadForSpeedOffset = 10;
// The offset ahead only the route for speed adjustments (applied as the rotation of the waypoint target transform)
[SerializeField] private float lookAheadForSpeedFactor = .2f;
// A multiplier adding distance ahead along the route for speed adjustments
[SerializeField] private ProgressStyle progressStyle = ProgressStyle.SmoothAlongRoute;
// whether to update the position smoothly along the route (good for curved paths) or just when we reach each waypoint.
[SerializeField] private float pointToPointThreshold = 4;
// proximity to waypoint which must be reached to switch target to next waypoint : only used in PointToPoint mode.
public enum ProgressStyle
{
SmoothAlongRoute,
PointToPoint,
}
// these are public, readable by other objects - i.e. for an AI to know where to head!
public WaypointCircuit.RoutePoint targetPoint { get; private set; }
public WaypointCircuit.RoutePoint speedPoint { get; private set; }
public WaypointCircuit.RoutePoint progressPoint { get; private set; }
public Transform target;
private float progressDistance; // The progress round the route, used in smooth mode.
private int progressNum; // the current waypoint number, used in point-to-point mode.
private Vector3 lastPosition; // Used to calculate current speed (since we may not have a rigidbody component)
private float speed; // current speed of this object (calculated from delta since last frame)
// setup script properties
private void Start()
{
circuit = GameObject.FindWithTag ("waypoint").GetComponent<WaypointCircuit> ();//<---waypointを代入。
// You can manually create a transform and assign it to this component *and* the AI,
// then this component will update it, and the AI can read it.
if (target == null)
{
target = new GameObject(name + " Waypoint Target").transform;
}
Reset();
}
~~~~~~~~~~~~~
コメント