バックグラウンド対応のためMarketのModelView分離
This commit is contained in:
parent
eb8d5cf151
commit
3a0ab744b5
|
|
@ -0,0 +1,129 @@
|
||||||
|
using System;
|
||||||
|
using UniRx;
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
public class CustomerAnimator : MonoBehaviour
|
||||||
|
{
|
||||||
|
public static readonly int WalkFront = Animator.StringToHash("WalkFront");
|
||||||
|
public static readonly int WalkSide = Animator.StringToHash("WalkSide");
|
||||||
|
public static readonly int WalkBack = Animator.StringToHash("WalkBack");
|
||||||
|
public static readonly int StayBack = Animator.StringToHash("StayBack");
|
||||||
|
public static readonly int WalkFrontEat = Animator.StringToHash("WalkFrontEat");
|
||||||
|
public static readonly int WalkSideEat = Animator.StringToHash("WalkSideEat");
|
||||||
|
|
||||||
|
private static readonly int Complain = Animator.StringToHash("ComplainTrigger");
|
||||||
|
|
||||||
|
[SerializeField] private Animator animator;
|
||||||
|
[SerializeField] private CustomerDirection customerDirection;
|
||||||
|
[SerializeField] private Animator orderAnimator;
|
||||||
|
[SerializeField] private GameObject tapReaction;
|
||||||
|
[SerializeField] private GameObject orderPopup;
|
||||||
|
[SerializeField] private Transform leftPopcornTarget;
|
||||||
|
[SerializeField] private Transform rightPopcornTarget;
|
||||||
|
[SerializeField] private Transform frontPopcornTarget;
|
||||||
|
[SerializeField] private Transform wantFlavorSpriteTarget;
|
||||||
|
[SerializeField] private SpriteRenderer leftPopcorn;
|
||||||
|
[SerializeField] private SpriteRenderer rightPopcorn;
|
||||||
|
[SerializeField] private SpriteRenderer frontPopcorn;
|
||||||
|
[SerializeField] private SpriteRenderer wantFlavorSprite;
|
||||||
|
[SerializeField] private Sprite defaultSprite;
|
||||||
|
[SerializeField] private Sprite caramelSprite;
|
||||||
|
|
||||||
|
private readonly ReactiveProperty<int> triggerName = new ReactiveProperty<int>();
|
||||||
|
|
||||||
|
private void Start()
|
||||||
|
{
|
||||||
|
triggerName.AddTo(this);
|
||||||
|
triggerName.Subscribe(x =>
|
||||||
|
{
|
||||||
|
animator.SetTrigger(x);
|
||||||
|
}).AddTo(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetTrigger(CustomerMovingType movingType)
|
||||||
|
{
|
||||||
|
switch (movingType)
|
||||||
|
{
|
||||||
|
case CustomerMovingType.WalkSide:
|
||||||
|
triggerName.Value = WalkSide;
|
||||||
|
break;
|
||||||
|
case CustomerMovingType.WalkSideEat:
|
||||||
|
triggerName.Value = WalkSideEat;
|
||||||
|
break;
|
||||||
|
case CustomerMovingType.WalkCenter:
|
||||||
|
triggerName.Value = WalkSide;
|
||||||
|
break;
|
||||||
|
case CustomerMovingType.StayBackOrder:
|
||||||
|
triggerName.Value = StayBack;
|
||||||
|
break;
|
||||||
|
case CustomerMovingType.StayBack:
|
||||||
|
triggerName.Value = StayBack;
|
||||||
|
break;
|
||||||
|
case CustomerMovingType.WalkBack:
|
||||||
|
triggerName.Value = WalkBack;
|
||||||
|
break;
|
||||||
|
case CustomerMovingType.WalkBackHalf:
|
||||||
|
triggerName.Value = WalkBack;
|
||||||
|
break;
|
||||||
|
case CustomerMovingType.WalkFront:
|
||||||
|
triggerName.Value = WalkFront;
|
||||||
|
break;
|
||||||
|
case CustomerMovingType.WalkFrontEat:
|
||||||
|
triggerName.Value = WalkFrontEat;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new ArgumentOutOfRangeException(nameof(movingType), movingType, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetSide(bool isDefaultSide)
|
||||||
|
{
|
||||||
|
if (isDefaultSide)
|
||||||
|
{
|
||||||
|
customerDirection.SetDefaultSide();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
customerDirection.SetFlipSide();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetWantFlavor(ProductStockData stockData)
|
||||||
|
{
|
||||||
|
// if (stockData.FlavorId == 2)
|
||||||
|
// {
|
||||||
|
// leftPopcorn.sprite = caramelSprite;
|
||||||
|
// rightPopcorn.sprite = caramelSprite;
|
||||||
|
// frontPopcorn.sprite = caramelSprite;
|
||||||
|
// wantFlavorSprite.sprite = caramelSprite;
|
||||||
|
// }
|
||||||
|
// else
|
||||||
|
// {
|
||||||
|
// leftPopcorn.sprite = defaultSprite;
|
||||||
|
// rightPopcorn.sprite = defaultSprite;
|
||||||
|
// frontPopcorn.sprite = defaultSprite;
|
||||||
|
// wantFlavorSprite.sprite = defaultSprite;
|
||||||
|
// }
|
||||||
|
orderPopup.SetActive(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ShowComplain()
|
||||||
|
{
|
||||||
|
orderAnimator.SetTrigger(Complain);
|
||||||
|
this.CallWaitForSeconds(1.5f, () =>
|
||||||
|
{
|
||||||
|
orderPopup.SetActive(false);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public void HideOrderPopup()
|
||||||
|
{
|
||||||
|
orderPopup.SetActive(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ShowTapReaction()
|
||||||
|
{
|
||||||
|
tapReaction.SetActive(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 72fc7821a0f8481495274ac394c7b620
|
||||||
|
timeCreated: 1633316259
|
||||||
|
|
@ -0,0 +1,18 @@
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
public class CustomerData : MonoBehaviour
|
||||||
|
{
|
||||||
|
[SerializeField] private List<CustomerAnimator> normalCustomerList;
|
||||||
|
[SerializeField] private List<CustomerAnimator> specialCustomerList;
|
||||||
|
|
||||||
|
public CustomerAnimator ChooseNormalPrefab()
|
||||||
|
{
|
||||||
|
return normalCustomerList.RandomChoose();
|
||||||
|
}
|
||||||
|
|
||||||
|
public CustomerAnimator ChooseSpecialPrefab()
|
||||||
|
{
|
||||||
|
return specialCustomerList.RandomChoose();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
fileFormatVersion: 2
|
||||||
|
guid: eee40f4ea08e42fab5bf3ea8810f972a
|
||||||
|
timeCreated: 1633065710
|
||||||
|
|
@ -0,0 +1,66 @@
|
||||||
|
using System;
|
||||||
|
using System.Linq;
|
||||||
|
using UniRx;
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
public class CustomerFlow : MonoBehaviour
|
||||||
|
{
|
||||||
|
private IObservable<bool> customerObservable;
|
||||||
|
private IObservable<bool> walkerObservable;
|
||||||
|
private IObservable<bool> adWalkerObservable;
|
||||||
|
private readonly Subject<Unit> adStartObservable = new Subject<Unit>();
|
||||||
|
private static readonly float checkHeartInterval = 1f;
|
||||||
|
// 歩行者の出現間隔
|
||||||
|
private static readonly float walkerInterval = 60f / 6;
|
||||||
|
|
||||||
|
public IObservable<bool> Flow => walkerObservable.Merge(customerObservable, adWalkerObservable);
|
||||||
|
|
||||||
|
private void Awake()
|
||||||
|
{
|
||||||
|
adStartObservable.AddTo(this);
|
||||||
|
|
||||||
|
var shopLevelList = SpreadsheetDataManager.Instance.GetBaseDataList<ShopLevelData>(Const.ShopLevelDataSheet);
|
||||||
|
// 10分間期待値を来客の間隔に変換
|
||||||
|
var intervalList = shopLevelList.Select(shopLevel => (heart: shopLevel.heart, interval: 60f * 10 / shopLevel.customer));
|
||||||
|
|
||||||
|
// 1秒間隔でハートを確認
|
||||||
|
var changeCustomerFlowObservable = Observable.Interval(TimeSpan.FromSeconds(checkHeartInterval))
|
||||||
|
.Select(_ => GameDataManager.GameData.Heart)
|
||||||
|
.DistinctUntilChanged()
|
||||||
|
.Select(heart => intervalList.Last(x => x.heart <= heart).interval);
|
||||||
|
|
||||||
|
// お客さん出現タイマー
|
||||||
|
customerObservable = changeCustomerFlowObservable
|
||||||
|
.DistinctUntilChanged()
|
||||||
|
.Do(x => Debug.Log($"changeInterval:{x}"))
|
||||||
|
.Select(customerInterval => Observable.Interval(TimeSpan.FromSeconds(customerInterval))
|
||||||
|
.Do(_ => Debug.Log($"customer:{GetHashCode()}"))
|
||||||
|
.Select(_ => true))
|
||||||
|
.Switch();
|
||||||
|
|
||||||
|
// 歩行者出現頻度、立ち止まり確率も設定(歩行者タイマー1分間に6人
|
||||||
|
walkerObservable = Observable.Interval(TimeSpan.FromSeconds(walkerInterval))
|
||||||
|
.Do(l => Debug.Log($"walker:{GetHashCode()}"))
|
||||||
|
.Select(x => false);
|
||||||
|
|
||||||
|
// 宣伝時、タップすると60秒だけ稼働するストリーム
|
||||||
|
adWalkerObservable = adStartObservable
|
||||||
|
.Delay(TimeSpan.FromSeconds(2f))
|
||||||
|
.Select(x => Observable.Interval(TimeSpan.FromSeconds(3f))
|
||||||
|
.Take(TimeSpan.FromSeconds(60f))
|
||||||
|
.Do(_ => Debug.Log($"adWalker:{GetHashCode()}"))
|
||||||
|
.Select(_ => false))
|
||||||
|
.Switch();
|
||||||
|
#if DEVELOPMENT_BUILD || UNITY_EDITOR
|
||||||
|
if (UsayaStorageManager.LoadOrDefault(UsayaStorageFilename.Settings_Data, "DebugManyWalker", false))
|
||||||
|
{
|
||||||
|
Observable.Timer(TimeSpan.FromSeconds(1f), TimeSpan.FromSeconds(70f)).Subscribe(_ => { adStartObservable.OnNext(default); }).AddTo(this);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
public void StartAdWalker()
|
||||||
|
{
|
||||||
|
adStartObservable.OnNext(Unit.Default);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 772e0346311a433fb714573f207813d2
|
||||||
|
timeCreated: 1633323544
|
||||||
|
|
@ -0,0 +1,226 @@
|
||||||
|
using System;
|
||||||
|
using System.Linq;
|
||||||
|
using TMPro;
|
||||||
|
using UniRx;
|
||||||
|
using UniRx.Triggers;
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
public class MarketManager : MonoBehaviour
|
||||||
|
{
|
||||||
|
[SerializeField] private GameObject closeSign;
|
||||||
|
[SerializeField] private ShopStockView stockView;
|
||||||
|
[SerializeField] private MarketCartView cartView;
|
||||||
|
[SerializeField] private BrotherBlueView blueView;
|
||||||
|
[SerializeField] private BrotherPinkView pinkView;
|
||||||
|
[SerializeField] private Transform coinPrefab;
|
||||||
|
[SerializeField] private Transform rootTransform;
|
||||||
|
private Market market;
|
||||||
|
|
||||||
|
private void Start()
|
||||||
|
{
|
||||||
|
var gameData = GameDataManager.GameData;
|
||||||
|
CoinManager.Instance.ChangeCoin(gameData.Coin);
|
||||||
|
HeartMeter.Instance.Initialize();
|
||||||
|
HeartMeter.Instance.SetHeart(gameData.Heart);
|
||||||
|
|
||||||
|
market = Market.Instance;
|
||||||
|
stockView.SetStock(gameData.StorageTanks);
|
||||||
|
var startStocks = market.DisplayFlavors
|
||||||
|
.Select((flavor, index) => (flavor, index))
|
||||||
|
.Where(data => market.ShuffledOrder.Contains(data.index))
|
||||||
|
.Select(data => (data.index, new ProductStockData
|
||||||
|
{
|
||||||
|
FlavorId = data.flavor,
|
||||||
|
Rarity = ProductRarity.Normal,
|
||||||
|
Stock = 1
|
||||||
|
}))
|
||||||
|
.ToList();
|
||||||
|
cartView.SetStock(startStocks, false);
|
||||||
|
pinkView.Initialize();
|
||||||
|
|
||||||
|
// Customerの各アニメーション設定
|
||||||
|
foreach (var controller in market.CustomerControllerList)
|
||||||
|
{
|
||||||
|
GenerateCustomer(controller);
|
||||||
|
}
|
||||||
|
market.CustomerControllerList.ObserveAdd().Subscribe(x =>
|
||||||
|
{
|
||||||
|
GenerateCustomer(x.Value);
|
||||||
|
}).AddTo(this);
|
||||||
|
|
||||||
|
// 販売
|
||||||
|
market.SellObservable.Subscribe(coin =>
|
||||||
|
{
|
||||||
|
// コイン獲得エフェクト
|
||||||
|
CoinEffect(coin);
|
||||||
|
CoinManager.Instance.AddCoinWithEffect(coin, () => { });
|
||||||
|
|
||||||
|
blueView.SellAction();
|
||||||
|
}).AddTo(this);
|
||||||
|
|
||||||
|
market.SellOrderSubject.Subscribe(x =>
|
||||||
|
{
|
||||||
|
// 販売アニメーション
|
||||||
|
foreach (var order in x.orders)
|
||||||
|
{
|
||||||
|
cartView.SellStock(order);
|
||||||
|
};
|
||||||
|
|
||||||
|
// 時間を開けて補充アニメーション
|
||||||
|
this.CallWaitForSeconds(1f, () =>
|
||||||
|
{
|
||||||
|
stockView.SetStock(gameData.StorageTanks);
|
||||||
|
if (gameData.ShopStock.Count == Market.ShopStockCount)
|
||||||
|
{
|
||||||
|
// 補充したフレーバーのスキンを設定
|
||||||
|
foreach (var order in x.orders)
|
||||||
|
{
|
||||||
|
cartView.Refill(order, market.DisplayFlavors[order]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (x.isReorder)
|
||||||
|
{
|
||||||
|
#if UNITY_EDITOR
|
||||||
|
Debug.Log($"bb setStockFlag {market.DisplayFlavors.Count} {market.ShuffledOrder.Count}");
|
||||||
|
#endif
|
||||||
|
// 陳列表示更新(陳列13=650ms,7=350ms)
|
||||||
|
var stocks = market.DisplayFlavors
|
||||||
|
.Select((flavor, index) => (flavor, index))
|
||||||
|
.Where(data => market.ShuffledOrder.Contains(data.index))
|
||||||
|
.Select(data => (data.index, new ProductStockData
|
||||||
|
{
|
||||||
|
FlavorId = data.flavor,
|
||||||
|
Rarity = ProductRarity.Normal,
|
||||||
|
Stock = 1
|
||||||
|
}))
|
||||||
|
.ToList();
|
||||||
|
cartView.SetStock(stocks, true);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}).AddTo(this);
|
||||||
|
|
||||||
|
// 開閉店
|
||||||
|
CompositeDisposable shopStateCompositeDisposable = new CompositeDisposable();
|
||||||
|
shopStateCompositeDisposable.AddTo(this);
|
||||||
|
market.CurrentShopState.Subscribe(state =>
|
||||||
|
{
|
||||||
|
shopStateCompositeDisposable.Clear();
|
||||||
|
switch (state)
|
||||||
|
{
|
||||||
|
case ShopState.Open:
|
||||||
|
pinkView.SetNormal();
|
||||||
|
closeSign.SetActive(false);
|
||||||
|
break;
|
||||||
|
case ShopState.Busy:
|
||||||
|
break;
|
||||||
|
case ShopState.Close:
|
||||||
|
if (market.CustomerList.Count(x => x.State.Value == CustomerState.Order) == 0)
|
||||||
|
{
|
||||||
|
pinkView.SetSleepy();
|
||||||
|
closeSign.SetActive(true);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// お客さんがいなくなったあと、閉店の看板を出す
|
||||||
|
Observable.CombineLatest(
|
||||||
|
market.CustomerList
|
||||||
|
.Select(x => x.State)
|
||||||
|
.Where(x => x.Value == CustomerState.Order))
|
||||||
|
.FirstOrDefault(states => states.Count(x => x == CustomerState.Order) == 0)
|
||||||
|
.Delay(TimeSpan.FromSeconds(2f))
|
||||||
|
.Subscribe(_ =>
|
||||||
|
{
|
||||||
|
pinkView.SetSleepy();
|
||||||
|
closeSign.SetActive(true);
|
||||||
|
}).AddTo(shopStateCompositeDisposable);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new ArgumentOutOfRangeException(nameof(state), state, null);
|
||||||
|
}
|
||||||
|
}).AddTo(this);
|
||||||
|
|
||||||
|
// お客さんが少なくなったら弟が走る
|
||||||
|
market.CustomerList.ObserveCountChanged(true).AsUnitObservable()
|
||||||
|
.Merge(Observable.Interval(TimeSpan.FromSeconds(1f)).AsUnitObservable())
|
||||||
|
.Where(_ => market.CurrentShopState.Value != ShopState.Close)
|
||||||
|
.Subscribe(_ =>
|
||||||
|
{
|
||||||
|
var count = market.CustomerList.Count(c => c.State.Value == CustomerState.Wait || c.State.Value == CustomerState.Order);
|
||||||
|
if (count < pinkView.FewerBorder)
|
||||||
|
{
|
||||||
|
pinkView.SetWalk();
|
||||||
|
}
|
||||||
|
}).AddTo(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void CoinEffect(int count)
|
||||||
|
{
|
||||||
|
var effect = Instantiate(coinPrefab, Vector3.zero, Quaternion.identity, rootTransform);
|
||||||
|
effect.GetComponentInChildren<TextMeshProUGUI>().text = count.ToString();
|
||||||
|
Destroy(effect.gameObject, 1f);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void GenerateCustomer(CustomerController controller)
|
||||||
|
{
|
||||||
|
var customerObject = new GameObject();
|
||||||
|
customerObject.transform.localPosition = controller.transform.localPosition;
|
||||||
|
// controllerが破棄のタイミングでこちらも破棄
|
||||||
|
controller.OnDestroyAsObservable().Subscribe(_ =>
|
||||||
|
{
|
||||||
|
Destroy(customerObject);
|
||||||
|
}).AddTo(customerObject);
|
||||||
|
// customer位置同期
|
||||||
|
this.UpdateAsObservable().Subscribe(_ =>
|
||||||
|
{
|
||||||
|
customerObject.transform.localPosition = controller.transform.localPosition;
|
||||||
|
}).AddTo(customerObject);
|
||||||
|
|
||||||
|
var customerAnimator = Instantiate(controller.CustomerPrefab, customerObject.transform);
|
||||||
|
controller.CurrentMovingType.Subscribe(x =>
|
||||||
|
{
|
||||||
|
customerAnimator.SetTrigger(x);
|
||||||
|
}).AddTo(customerAnimator);
|
||||||
|
controller.IsDefaultSide.Subscribe(x =>
|
||||||
|
{
|
||||||
|
customerAnimator.SetSide(x);
|
||||||
|
}).AddTo(customerAnimator);
|
||||||
|
controller.WantFlavor
|
||||||
|
.SkipLatestValueOnSubscribe()
|
||||||
|
.Subscribe(data =>
|
||||||
|
{
|
||||||
|
customerAnimator.SetWantFlavor(data);
|
||||||
|
}).AddTo(customerAnimator);
|
||||||
|
controller.IsComplain
|
||||||
|
.SkipLatestValueOnSubscribe()
|
||||||
|
.Subscribe(active =>
|
||||||
|
{
|
||||||
|
if (active)
|
||||||
|
{
|
||||||
|
customerAnimator.ShowComplain();
|
||||||
|
}
|
||||||
|
}).AddTo(customerAnimator);
|
||||||
|
controller.Purchased.Subscribe(_ =>
|
||||||
|
{
|
||||||
|
customerAnimator.HideOrderPopup();
|
||||||
|
var heartAnimation = customerAnimator.GetComponent<HeartAnimation>();
|
||||||
|
heartAnimation.GetHeart(HeartMeter.Instance.transform, () =>
|
||||||
|
{
|
||||||
|
HeartMeter.Instance.AddHeart(1);
|
||||||
|
});
|
||||||
|
}).AddTo(customerAnimator);
|
||||||
|
var eventTrigger = customerAnimator.gameObject.AddComponent<ObservableEventTrigger>();
|
||||||
|
eventTrigger.OnPointerClickAsObservable()
|
||||||
|
.TakeWhile(_ => market.CurrentShopState.Value != ShopState.Close)
|
||||||
|
.Take(1)
|
||||||
|
.Subscribe(_ =>
|
||||||
|
{
|
||||||
|
controller.Tapped();
|
||||||
|
customerAnimator.ShowTapReaction();
|
||||||
|
if (customerAnimator.TryGetComponent(typeof(Collider2D), out var target))
|
||||||
|
{
|
||||||
|
Destroy(target);
|
||||||
|
}
|
||||||
|
}).AddTo(customerAnimator);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 2acf7c5ed16d4e3890013ca7519535d5
|
||||||
|
timeCreated: 1633320855
|
||||||
Loading…
Reference in New Issue