614 lines
20 KiB
C#
614 lines
20 KiB
C#
using asap.core;
|
||
using GameCore;
|
||
using PaintCore;
|
||
using PaintIn3D;
|
||
using System.Collections;
|
||
using System.Collections.Generic;
|
||
using UnityEngine;
|
||
using Unity.Mathematics;
|
||
using asap.core.common;
|
||
using CW.Common;
|
||
using UniRx;
|
||
|
||
namespace game
|
||
{
|
||
public class WashingGamePainting : WashingGameBase
|
||
{
|
||
[Tooltip("绘制用笔刷,主要用于喷洗泡沫等")]
|
||
public CwPaintSphere m_PaintSphere;
|
||
|
||
[Tooltip("绘制用纹理,主要用于喷洗泡沫等")]
|
||
public CwPaintableMeshTexture m_PaintTexture;
|
||
|
||
[Tooltip("玩家停止喷涂/清理后,持续播放动画时间")]
|
||
[SerializeField] private float m_ToolPlayingEffectTimeAfterStoppedPainting = 0.1f;
|
||
|
||
[Tooltip("飞溅动画预制体")]
|
||
[SerializeField]
|
||
private SplashAnimation m_SplashPrefab = null;
|
||
|
||
[Tooltip("飞溅特效延迟播放时间")]
|
||
[SerializeField]
|
||
private float m_SplashDelayTime = 0.2f;
|
||
|
||
[Tooltip("飞溅特特效显示时间")]
|
||
[SerializeField]
|
||
private float m_SplashDisplayTime = 0.1f;
|
||
|
||
[Tooltip("喷涂省略的比例,范围:0.0 - 1.0")]
|
||
[SerializeField] private float m_OmitPercentage = 0.1f;
|
||
|
||
IObjectPoolService m_ObjectPoolService;
|
||
|
||
#region 工具功能
|
||
private float m_Timer = 0f;
|
||
#endregion
|
||
|
||
#region 特效相关
|
||
private IObjectPool m_ObjectPool = null;
|
||
private IEnumerator CreateSplashClone(EventWashingCleanerFollowPositionData data)
|
||
{
|
||
yield return new WaitForSeconds(m_SplashDelayTime);
|
||
|
||
SplashAnimation clone = GetObjectPoolService().SpawnObject<SplashAnimation>();
|
||
clone.transform.position = data.position;
|
||
clone.transform.up = data.normal;
|
||
|
||
clone.SetTimer(m_SplashDisplayTime);
|
||
}
|
||
|
||
private IObjectPoolService GetObjectPoolService()
|
||
{
|
||
if (m_ObjectPoolService != null) return m_ObjectPoolService;
|
||
|
||
m_ObjectPoolService = GContext.container.Resolve<IObjectPoolService>();
|
||
m_ObjectPoolService.CreatePool<SplashAnimation>(m_SplashPrefab, 8, 32);
|
||
|
||
return m_ObjectPoolService;
|
||
}
|
||
|
||
private void DestroyObjectPool()
|
||
{
|
||
if (m_ObjectPoolService == null) return;
|
||
m_ObjectPoolService.DestroyPool<SplashAnimation>();
|
||
}
|
||
#endregion
|
||
|
||
#region 页面功能
|
||
protected EventWashingPanel panel;
|
||
protected virtual void InitPanel()
|
||
{
|
||
panel.ResetBrushChannelCounterData();
|
||
|
||
panel.SetDataManager(m_DataManager);
|
||
|
||
if (m_DataManager.WashingData.IsAllGameOver == true)
|
||
{
|
||
panel.ShowForAllGameOver();
|
||
// 设置关闭按钮
|
||
panel.SetBtnCloseClickListener(OnBtnCloseClickListener);
|
||
return;
|
||
}
|
||
|
||
panel.StopCountingFill();
|
||
|
||
panel.ShowForPainting();
|
||
|
||
// 设置预览按钮
|
||
panel.SetBtnPreviewClickListener(null);
|
||
|
||
// 设置关闭按钮
|
||
panel.SetBtnCloseClickListener(OnBtnCloseClickListener);
|
||
|
||
// 设置左右箭头
|
||
panel.SetBtnArrayClickListener(OnBtnLeftClick, OnBtnRightClick);
|
||
|
||
m_IsGuiding = panel.InitGuidance();
|
||
if (m_IsGuiding == true)
|
||
{
|
||
StopInputOperation();
|
||
}
|
||
else
|
||
{
|
||
ResumeInputOperation();
|
||
}
|
||
}
|
||
|
||
private void OnBtnLeftClick()
|
||
{
|
||
// 向左移动机位
|
||
FishingYachtAct.Publish<EventWashingCameraMoveData>(new EventWashingCameraMoveData(EventWashingCameraMoveDirection.Backward));
|
||
|
||
}
|
||
private void OnBtnRightClick()
|
||
{
|
||
// 向右移动机位
|
||
FishingYachtAct.Publish<EventWashingCameraMoveData>(new EventWashingCameraMoveData(EventWashingCameraMoveDirection.Forward));
|
||
}
|
||
|
||
private void OnBtnCloseClickListener()
|
||
{
|
||
//SaveRenderTexture(m_PaintTexture.Current, Application.dataPath + "/../SavedScreen.png");
|
||
//return;
|
||
// 关闭当前Act
|
||
GContext.Publish(new UnloadActToNextAct());
|
||
}
|
||
|
||
private float m_PowerConsumptionTime = 0.4f;
|
||
private float m_PowerConsumptionCD = 0f;
|
||
private void HideElectricityConsumption()
|
||
{
|
||
if (m_PowerConsumptionCD > 0f) return;
|
||
panel.SetElectricityConsumptionVisible(false);
|
||
}
|
||
|
||
private void ShowElectricityConsumption()
|
||
{
|
||
m_PowerConsumptionCD = m_PowerConsumptionTime;
|
||
panel.SetElectricityConsumptionVisible(true);
|
||
}
|
||
#endregion
|
||
|
||
#region 船本体相关
|
||
protected void InitShipMaterial()
|
||
{
|
||
//if (m_ShipMaterials == null || m_ShipRenderer == null) return;
|
||
//m_ShipRenderer.sharedMaterials = m_ShipMaterials;
|
||
}
|
||
#endregion
|
||
|
||
#region 长时间不操作检测
|
||
private bool m_IsDetectedAsInOperation = false;
|
||
#endregion
|
||
|
||
#region Paint in 3D 相关
|
||
private void SaveRenderTexture(RenderTexture renderTexture, string file)
|
||
{
|
||
RenderTexture.active = renderTexture;
|
||
Texture2D texture = new Texture2D(renderTexture.width, renderTexture.height, TextureFormat.ARGB32, false, false);
|
||
texture.ReadPixels(new Rect(0, 0, renderTexture.width, renderTexture.height), 0, 0);
|
||
texture.Apply();
|
||
|
||
byte[] bytes = texture.EncodeToPNG();
|
||
UnityEngine.Object.Destroy(texture);
|
||
|
||
System.IO.File.WriteAllBytes(file, bytes);
|
||
Debug.Log("write to File over");
|
||
//UnityEditor.AssetDatabase.Refresh(); //自动刷新资源
|
||
}
|
||
/// <summary>
|
||
/// 设置CwPaintSphere混合模式为AdditiveSoft
|
||
/// </summary>
|
||
public void ChangePaintSphereBlendModeToAdditiveSoft()
|
||
{
|
||
if (m_PaintSphere == null) return;
|
||
m_PaintSphere.enabled = true;
|
||
m_PaintSphere.gameObject.SetActive(true);
|
||
m_PaintSphere.BlendMode = CwBlendMode.AdditiveSoft(Vector4.one);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 设置CwPaintSphere混合模式为SubtractiveSoft
|
||
/// </summary>
|
||
public void ChangePaintSphereBlendModeToSubtractiveSoft()
|
||
{
|
||
if (m_PaintSphere == null) return;
|
||
m_PaintSphere.enabled = true;
|
||
m_PaintSphere.gameObject.SetActive(true);
|
||
m_PaintSphere.BlendMode = CwBlendMode.SubtractiveSoft(Vector4.one);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 清空绘制用纹理
|
||
/// </summary>
|
||
public void ClearPaintTexture()
|
||
{
|
||
if (m_PaintTexture == null) return;
|
||
m_PaintTexture.Clear();
|
||
}
|
||
|
||
public void SetPaintTextureColor(Color color, bool isReplace = false)
|
||
{
|
||
if (m_PaintTexture == null) return;
|
||
m_PaintTexture.Color = color;
|
||
|
||
if (isReplace == true) m_PaintTexture.Replace();
|
||
|
||
BHitScreenBase.SetTargetTransform(m_PaintTexture.transform);
|
||
}
|
||
private void StopPainting(bool isInOperation = true)
|
||
{
|
||
if (m_PaintSphere == null) return;
|
||
//m_PaintSphere.gameObject.SetActive(false);
|
||
if (m_Tool != null)
|
||
{
|
||
m_Tool.NotAuthorizedAnimation();
|
||
}
|
||
BHitScreen bHitScreen = m_PaintSphere.transform.transform.GetComponent<BHitScreen>();
|
||
if (bHitScreen != null)
|
||
{
|
||
bHitScreen.NotAuthorizedDrawing();
|
||
}
|
||
|
||
m_IsDetectedAsInOperation = isInOperation;
|
||
}
|
||
private void ResumePainting()
|
||
{
|
||
if (m_PaintSphere == null) return;
|
||
if (m_Tool != null)
|
||
{
|
||
m_Tool.AuthorizedAnimation();
|
||
}
|
||
BHitScreen bHitScreen = m_PaintSphere.transform.GetComponent<BHitScreen>();
|
||
if (bHitScreen != null && HaveEnergy())
|
||
{
|
||
bHitScreen.AuthorizedDrawing();
|
||
}
|
||
|
||
m_IsDetectedAsInOperation = false;
|
||
}
|
||
|
||
private void StopInputOperation()
|
||
{
|
||
var pointers = m_PaintSphere.transform.GetComponents<CwPointer>();
|
||
if (pointers != null)
|
||
{
|
||
foreach (var pointer in pointers)
|
||
{
|
||
pointer.enabled = false;
|
||
}
|
||
}
|
||
}
|
||
private void ResumeInputOperation()
|
||
{
|
||
var pointers = m_PaintSphere.transform.GetComponents<CwPointer>();
|
||
if (pointers != null)
|
||
{
|
||
foreach (var pointer in pointers)
|
||
{
|
||
pointer.enabled = true;
|
||
}
|
||
}
|
||
}
|
||
#endregion
|
||
|
||
#region 事件
|
||
private void InitEvent()
|
||
{
|
||
this.Subscribe<EventWashingGestureFollowPositionData>(SetGestureFollowPosition);
|
||
this.Subscribe<EventWashingConclusionData>(StartConclusion);
|
||
this.Subscribe<EventWashingStepOverData>(StepOver);
|
||
this.Subscribe<EventWashingCleanerFollowPositionData>(SetCleanerFollowPosition);
|
||
|
||
this.Subscribe<EventWashingCameraMoveData>(EventCameraForwardListener); // 摄像机移动处理
|
||
|
||
this.Subscribe<EventWashingCameraStopData>(EventWashingCameraStopListener);
|
||
this.Subscribe<EventWashingMonitoringFoamProgressData>(EventMonitoringFoamProgressListener);
|
||
|
||
this.Subscribe<EventWashingAllGameOverData>(AllGameOver);
|
||
this.Subscribe<EventWashingTokenUpdateData>(UpdateBatteryInfo);
|
||
|
||
GContext.OnEvent<AddIndexEvent>().Subscribe(GuideListener).AddTo(this.disposables);
|
||
}
|
||
|
||
private void GuideListener(AddIndexEvent addIndexEvent)
|
||
{
|
||
if (addIndexEvent.CompleteGuide == true && panel != null)
|
||
{
|
||
panel.CompleteGuidance();
|
||
m_IsGuiding = false;
|
||
ResumeInputOperation();
|
||
}
|
||
}
|
||
|
||
private bool m_IsUpdateBatteryInfo = true;
|
||
private void UpdateBatteryInfo(EventWashingTokenUpdateData data)
|
||
{
|
||
if (panel != null && m_IsUpdateBatteryInfo == true)
|
||
{
|
||
panel.SetBatteryInfo();
|
||
}
|
||
}
|
||
|
||
private void AllGameOver(EventWashingAllGameOverData data)
|
||
{
|
||
if (panel != null)
|
||
{
|
||
panel.ShowForAllGameOver();
|
||
}
|
||
}
|
||
|
||
private void EventMonitoringFoamProgressListener(EventWashingMonitoringFoamProgressData data)
|
||
{
|
||
if (m_DataManager != null)
|
||
{
|
||
m_DataManager.WashingData.Percent = data.progress;
|
||
|
||
m_DataManager.WashingData.OmitPercent = m_OmitPercentage;
|
||
}
|
||
}
|
||
private void EventCameraForwardListener(EventWashingCameraMoveData data)
|
||
{
|
||
if (m_CameraMoveController != null)
|
||
{
|
||
if (data.direction == EventWashingCameraMoveDirection.Forward)
|
||
{
|
||
m_CameraMoveController.ForwardToNextRest();
|
||
}
|
||
else if (data.direction == EventWashingCameraMoveDirection.Backward)
|
||
{
|
||
m_CameraMoveController.BackwardToNextRest();
|
||
}
|
||
StopPainting();
|
||
}
|
||
}
|
||
private void EventWashingCameraStopListener(EventWashingCameraStopData data)
|
||
{
|
||
ResumePainting();
|
||
}
|
||
private void SetGestureFollowPosition(EventWashingGestureFollowPositionData data)
|
||
{
|
||
if (data.isFollowing)
|
||
{
|
||
ShowElectricityConsumption();
|
||
//Vector3 worldPosition = Vector3.zero;
|
||
RectTransformUtility.ScreenPointToWorldPointInRectangle(
|
||
panel.gestureFollow.transform.GetComponent<RectTransform>(),
|
||
data.position,
|
||
UIManager.Instance.UICanvas.worldCamera,
|
||
out Vector3 worldPosition);
|
||
panel.SetGestureFollowPosition(worldPosition);
|
||
}
|
||
else
|
||
{
|
||
HideElectricityConsumption();
|
||
}
|
||
}
|
||
private void SetCleanerFollowPosition(EventWashingCleanerFollowPositionData data)
|
||
{
|
||
if (!IsGameOver() && (HaveEnergy() || ConsumeTokens(1)))
|
||
{
|
||
ResumePainting();
|
||
}
|
||
else
|
||
{
|
||
// 停止游戏
|
||
StopPainting(false);
|
||
}
|
||
|
||
if (m_Tool != null)
|
||
{
|
||
((ToolForFollowerAndNormalPosition)m_Tool).Follow(data.position, data.normal);
|
||
m_Tool.StartExecuting();
|
||
m_Timer = m_ToolPlayingEffectTimeAfterStoppedPainting;
|
||
|
||
if (m_SplashPrefab != null && m_Tool.IsAuthorizedAnimation)
|
||
{
|
||
StartCoroutine(CreateSplashClone(data));
|
||
}
|
||
}
|
||
}
|
||
protected virtual void StartConclusion(EventWashingConclusionData data)
|
||
{
|
||
if (m_DataManager != null)
|
||
{
|
||
m_DataManager.WashingData.IsOver = true;
|
||
m_DataManager.SyncData();
|
||
}
|
||
panel.StopCountingFill();
|
||
panel.StartConclusion();
|
||
}
|
||
private void StepOver(EventWashingStepOverData data)
|
||
{
|
||
m_IsUpdateBatteryInfo = false;
|
||
GameOver();
|
||
FishingYachtAct.Publish<EventWashingGameOverData>(new EventWashingGameOverData());
|
||
}
|
||
#endregion
|
||
|
||
#region 代币相关
|
||
protected void UpdateToken(float deltaTime)
|
||
{
|
||
if (m_DataManager == null || m_DataManager.WashingData == null) return;
|
||
float step = 1f / m_DataManager.WashingData.StepEnergyConsume;
|
||
|
||
float tmpProgress = 1f - m_DataManager.WashingData.OmitPercent;
|
||
|
||
float realProgress = m_DataManager.WashingData.Percent / tmpProgress;
|
||
if (realProgress > 1) realProgress = 1;
|
||
|
||
float nextEnergy = 1f - math.frac(realProgress / step);
|
||
|
||
if (m_DataManager.WashingData.Energy < nextEnergy) m_DataManager.WashingData.Energy = 0f;
|
||
|
||
if (m_DataManager.WashingData.Energy > 0) m_DataManager.WashingData.Energy = nextEnergy;
|
||
|
||
if (m_DataManager.WashingData.Energy < 0) m_DataManager.WashingData.Energy = 0;
|
||
}
|
||
|
||
protected bool IsUpdateTokenOver()
|
||
{
|
||
if (m_DataManager == null || m_DataManager.WashingData == null) return true;
|
||
|
||
float step = 1f / m_DataManager.WashingData.StepEnergyConsume;
|
||
|
||
float tmpProgress = 1f - m_DataManager.WashingData.OmitPercent;
|
||
|
||
float realProgress = m_DataManager.WashingData.Percent / tmpProgress;
|
||
if (realProgress > 1) realProgress = 1;
|
||
|
||
int belongStep = (int)math.floor(realProgress / step) + 1;
|
||
|
||
if (belongStep > m_DataManager.WashingData.StepEnergyConsume) m_DataManager.WashingData.IsOver = true;
|
||
|
||
if (belongStep > m_DataManager.WashingData.ConsumedToken) return true;
|
||
|
||
return false;
|
||
}
|
||
|
||
protected override UpdateOperationSet GetUpdateOperationSet()
|
||
{
|
||
if (m_DataManager == null) return null;
|
||
UpdateOperationSet updateOperationSet = new UpdateOperationSet();
|
||
updateOperationSet.Update = UpdateToken;
|
||
updateOperationSet.IsUpdateOver = IsUpdateTokenOver;
|
||
updateOperationSet.Callback = ConsumeTokens;
|
||
return updateOperationSet;
|
||
}
|
||
#endregion
|
||
|
||
#region 数据处理
|
||
protected Color m_PainterColor = Color.white;
|
||
private void SyncGameData()
|
||
{
|
||
if (m_DataManager == null || m_DataManager.WashingData == null) return;
|
||
if (m_PaintTexture == null) return;
|
||
if (m_PaintSphere == null) return;
|
||
|
||
if (m_PaintTexture.SaveLoad == PaintCore.CwPaintableTexture.SaveLoadType.Automatic && string.IsNullOrEmpty(m_PaintTexture.SaveName) == false)
|
||
{
|
||
m_DataManager.WashingData.AddLocalDataKey(m_GameName, m_PaintTexture.SaveName);
|
||
|
||
if (m_DataManager.WashingData.Percent <= 0) return;
|
||
|
||
bool isExists = CwCommon.SaveExists(m_PaintTexture.SaveName);
|
||
if (isExists == false)
|
||
{
|
||
int total = (int)(m_PaintTexture.Width * m_PaintTexture.Height * m_DataManager.WashingData.Percent);
|
||
int index = 0;
|
||
Texture2D texture = new Texture2D(m_PaintTexture.Width, m_PaintTexture.Height, TextureFormat.ARGB32, false, false);
|
||
for (int i = 0; i < texture.width; i++)
|
||
{
|
||
for (int j = 0; j < texture.height; j++)
|
||
{
|
||
if (index < total) texture.SetPixel(i, j, m_PainterColor);
|
||
else texture.SetPixel(i, j, m_PaintTexture.Color);
|
||
++index;
|
||
}
|
||
}
|
||
texture.Apply();
|
||
|
||
var data = texture.EncodeToPNG();
|
||
|
||
CwHelper.Destroy(texture);
|
||
|
||
CwCommon.SaveBytes(m_PaintTexture.SaveName, data);
|
||
}
|
||
}
|
||
}
|
||
protected override void SetEnergyEnough()
|
||
{
|
||
base.SetEnergyEnough();
|
||
if (panel != null) panel.SetEnergyEnough();
|
||
}
|
||
protected override void SetEnergyShortage()
|
||
{
|
||
base.SetEnergyShortage();
|
||
if (panel != null) panel.SetEnergyShortage();
|
||
}
|
||
#endregion
|
||
|
||
#region 生命周期
|
||
public async override void EnterGame()
|
||
{
|
||
base.EnterGame();
|
||
|
||
m_IsUpdateBatteryInfo = true;
|
||
|
||
BrushChannelCounterFill.OmitPercentage = this.m_OmitPercentage;
|
||
|
||
StopPainting(false);
|
||
|
||
// 打开页面(UI)
|
||
GameObject pannelObj = await UIManager.Instance.ShowUI(UITypes.EventWashingPanel);
|
||
if (pannelObj == null) return;
|
||
panel = pannelObj.transform.GetComponent<EventWashingPanel>();
|
||
|
||
InitPanel();
|
||
InitEvent();
|
||
|
||
AfterEnterGame();
|
||
}
|
||
|
||
protected override void ResumeGame()
|
||
{
|
||
base.ResumeGame();
|
||
ResumePainting();
|
||
}
|
||
|
||
protected override void PauseGame()
|
||
{
|
||
base.PauseGame();
|
||
StopPainting(false);
|
||
}
|
||
|
||
public override void Fresh(EventWashingDataManager dataManager)
|
||
{
|
||
base.Fresh(dataManager);
|
||
|
||
m_IsGuiding = true;
|
||
StopInputOperation();
|
||
|
||
if (dataManager == null || dataManager.WashingData == null) return;
|
||
//if (m_PaintTexture != null) m_PaintTexture.DefaultFillRatio = dataManager.WashingData.Percent;
|
||
}
|
||
|
||
public override void SyncData()
|
||
{
|
||
SyncGameData();
|
||
base.SyncData();
|
||
}
|
||
|
||
protected override void OnEnable()
|
||
{
|
||
base.OnEnable();
|
||
GetObjectPoolService();
|
||
}
|
||
|
||
protected override void OnDisable()
|
||
{
|
||
base.OnDisable();
|
||
DestroyObjectPool();
|
||
}
|
||
|
||
protected override void Update()
|
||
{
|
||
base.Update();
|
||
|
||
m_Timer -= Time.deltaTime;
|
||
if (m_Timer <= 0)
|
||
{
|
||
m_Timer = 0f;
|
||
if (m_Tool != null) m_Tool.StopExecuting();
|
||
}
|
||
|
||
if (m_IsDetectedAsInOperation == true)
|
||
{
|
||
if (panel != null)
|
||
{
|
||
panel.ContinuousOperation();
|
||
}
|
||
}
|
||
|
||
m_PowerConsumptionCD -= Time.deltaTime;
|
||
if (m_PowerConsumptionCD <= 0)
|
||
{
|
||
m_PowerConsumptionCD = 0;
|
||
}
|
||
}
|
||
|
||
public override void GameOver()
|
||
{
|
||
base.GameOver();
|
||
if (panel != null) panel.StopCountingFill();
|
||
StopPainting();
|
||
// 关闭笔刷填充进度
|
||
if (panel != null)
|
||
{
|
||
panel.ResetBrushChannelCounterFillAndInverse(true, false);
|
||
}
|
||
}
|
||
#endregion
|
||
}
|
||
}
|