バックグラウンド対応のためMarketのModelView分離

This commit is contained in:
kimura 2021-10-05 13:40:38 +09:00
parent eb8d5cf151
commit 3a0ab744b5
8 changed files with 451 additions and 0 deletions

View File

@ -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);
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 72fc7821a0f8481495274ac394c7b620
timeCreated: 1633316259

View File

@ -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();
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: eee40f4ea08e42fab5bf3ea8810f972a
timeCreated: 1633065710

View File

@ -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);
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 772e0346311a433fb714573f207813d2
timeCreated: 1633323544

View File

@ -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);
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 2acf7c5ed16d4e3890013ca7519535d5
timeCreated: 1633320855