Add NegrBagrJaromirJagr minigame
This commit is contained in:
315
Assets/TimingWheelShooter.cs
Normal file
315
Assets/TimingWheelShooter.cs
Normal file
@@ -0,0 +1,315 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Video;
|
||||
|
||||
public class TimingWheelShooter : MonoBehaviour, ITask
|
||||
{
|
||||
[Header("Task Info")]
|
||||
[SerializeField] private string taskID = "RING_SHOOTER_01";
|
||||
[SerializeField] private string taskName = "Break the Ring";
|
||||
[SerializeField] private TaskType taskType = TaskType.Task;
|
||||
[SerializeField] private Vector2 taskLocation = Vector2.zero;
|
||||
|
||||
public string TaskID => taskID;
|
||||
public TaskType TaskType => taskType;
|
||||
public string TaskName => taskName;
|
||||
public (double, double) TaskLocation => (taskLocation.x, taskLocation.y);
|
||||
public bool IsCompleted { get; private set; }
|
||||
|
||||
[Header("Wheel")]
|
||||
public Transform rotatingWheel;
|
||||
public float defaultAngle = 90f;
|
||||
public float sweepAngle = 90f;
|
||||
public float wheelSpeed = 120f;
|
||||
|
||||
[Header("Projectile")]
|
||||
public ProjectileBehaviour potatoPrefab;
|
||||
public Transform projectileSpawn;
|
||||
public Transform aimPoint;
|
||||
public GlassRingController ring;
|
||||
public float baseLaunchSpeed = 12f;
|
||||
|
||||
[Header("Audio")]
|
||||
public AudioSource audioSource;
|
||||
public AudioClip startClip;
|
||||
[Range(0f, 1f)] public float startVolume = 1f;
|
||||
public AudioClip winClip;
|
||||
[Range(0f, 1f)] public float winVolume = 1f;
|
||||
|
||||
[Header("Finish Video")]
|
||||
public VideoPlayer videoPlayer;
|
||||
public VideoClip finishVideo;
|
||||
public AudioClip finishVideoAudio;
|
||||
[Range(0f, 1f)] public float finishVideoAudioVolume = 1f;
|
||||
public Camera targetCamera;
|
||||
|
||||
[Header("State")]
|
||||
public bool autoRestartAfterShot = true;
|
||||
public float restartDelay = 0.75f;
|
||||
|
||||
private bool isRunning = true;
|
||||
private bool finishSequenceStarted = false;
|
||||
private float currentAngle;
|
||||
private float direction = 1f;
|
||||
private Action<ITask> onCompletedCallback;
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
if (audioSource == null)
|
||||
audioSource = GetComponent<AudioSource>();
|
||||
|
||||
if (audioSource == null)
|
||||
audioSource = gameObject.AddComponent<AudioSource>();
|
||||
|
||||
if (videoPlayer == null)
|
||||
videoPlayer = GetComponent<VideoPlayer>();
|
||||
|
||||
if (videoPlayer == null)
|
||||
videoPlayer = gameObject.AddComponent<VideoPlayer>();
|
||||
|
||||
if (targetCamera == null)
|
||||
targetCamera = Camera.main;
|
||||
|
||||
// Video setup
|
||||
videoPlayer.playOnAwake = false;
|
||||
videoPlayer.waitForFirstFrame = true;
|
||||
videoPlayer.skipOnDrop = true;
|
||||
videoPlayer.isLooping = false;
|
||||
videoPlayer.audioOutputMode = VideoAudioOutputMode.None;
|
||||
videoPlayer.renderMode = VideoRenderMode.CameraNearPlane;
|
||||
|
||||
if (targetCamera != null)
|
||||
videoPlayer.targetCamera = targetCamera;
|
||||
}
|
||||
|
||||
private void Start()
|
||||
{
|
||||
currentAngle = defaultAngle;
|
||||
SetWheelAngle(currentAngle);
|
||||
|
||||
PlayStartSound();
|
||||
}
|
||||
|
||||
private void Update()
|
||||
{
|
||||
if (IsCompleted || finishSequenceStarted) return;
|
||||
|
||||
if (isRunning)
|
||||
UpdateWheelMotion();
|
||||
|
||||
if (Input.GetMouseButtonDown(0))
|
||||
StopAndShoot();
|
||||
|
||||
if (Input.touchCount > 0 && Input.GetTouch(0).phase == TouchPhase.Began)
|
||||
StopAndShoot();
|
||||
}
|
||||
|
||||
private void UpdateWheelMotion()
|
||||
{
|
||||
float halfRange = sweepAngle * 0.5f;
|
||||
float minAngle = defaultAngle - halfRange;
|
||||
float maxAngle = defaultAngle + halfRange;
|
||||
|
||||
currentAngle += direction * wheelSpeed * Time.deltaTime;
|
||||
|
||||
if (currentAngle >= maxAngle)
|
||||
{
|
||||
currentAngle = maxAngle;
|
||||
direction = -1f;
|
||||
}
|
||||
else if (currentAngle <= minAngle)
|
||||
{
|
||||
currentAngle = minAngle;
|
||||
direction = 1f;
|
||||
}
|
||||
|
||||
SetWheelAngle(currentAngle);
|
||||
}
|
||||
|
||||
private void SetWheelAngle(float angle)
|
||||
{
|
||||
if (rotatingWheel == null) return;
|
||||
|
||||
Vector3 e = rotatingWheel.localEulerAngles;
|
||||
e.y = angle; // your current setup uses Y
|
||||
rotatingWheel.localEulerAngles = e;
|
||||
}
|
||||
|
||||
private float EvaluateMultiplier(float angle)
|
||||
{
|
||||
float halfRange = sweepAngle * 0.5f;
|
||||
float offset = Mathf.Abs(angle - defaultAngle);
|
||||
|
||||
float zone5 = halfRange / 2.5f;
|
||||
float zone2 = halfRange / 1.5f;
|
||||
|
||||
if (offset <= zone5) return 5f;
|
||||
if (offset <= zone2) return 2f;
|
||||
return 1f;
|
||||
}
|
||||
|
||||
public void StopAndShoot()
|
||||
{
|
||||
if (!isRunning || IsCompleted || finishSequenceStarted) return;
|
||||
|
||||
isRunning = false;
|
||||
|
||||
float multiplier = EvaluateMultiplier(currentAngle);
|
||||
Shoot(multiplier);
|
||||
|
||||
Debug.Log($"Wheel stopped at {currentAngle:F1}°, multiplier = {multiplier}x");
|
||||
|
||||
if (autoRestartAfterShot)
|
||||
Invoke(nameof(RestartWheel), restartDelay);
|
||||
}
|
||||
|
||||
private void Shoot(float multiplier)
|
||||
{
|
||||
if (potatoPrefab == null || projectileSpawn == null || aimPoint == null)
|
||||
return;
|
||||
|
||||
Vector3 dir = (aimPoint.position - projectileSpawn.position).normalized;
|
||||
float speed = baseLaunchSpeed * multiplier;
|
||||
|
||||
ProjectileBehaviour p = Instantiate(
|
||||
potatoPrefab,
|
||||
projectileSpawn.position,
|
||||
Quaternion.LookRotation(dir, Vector3.up)
|
||||
);
|
||||
|
||||
p.baseDamage *= multiplier;
|
||||
p.breakImpulse *= multiplier;
|
||||
p.Launch(ring, dir * speed, 1f);
|
||||
}
|
||||
|
||||
private void RestartWheel()
|
||||
{
|
||||
if (!IsCompleted && !finishSequenceStarted)
|
||||
isRunning = true;
|
||||
}
|
||||
|
||||
public void NotifyButtonHit(ProjectileBehaviour projectile)
|
||||
{
|
||||
if (IsCompleted || finishSequenceStarted) return;
|
||||
|
||||
Debug.Log("Diamond hit. Starting finish sequence.");
|
||||
StartCoroutine(PlayFinishSequenceThenComplete());
|
||||
}
|
||||
|
||||
private IEnumerator PlayFinishSequenceThenComplete()
|
||||
{
|
||||
finishSequenceStarted = true;
|
||||
isRunning = false;
|
||||
CancelInvoke();
|
||||
|
||||
if (ring != null)
|
||||
ring.enabled = false;
|
||||
|
||||
if (finishVideo == null)
|
||||
{
|
||||
if (audioSource != null && winClip != null)
|
||||
audioSource.PlayOneShot(winClip, winVolume);
|
||||
|
||||
Complete();
|
||||
yield break;
|
||||
}
|
||||
|
||||
videoPlayer.Stop();
|
||||
videoPlayer.clip = finishVideo;
|
||||
videoPlayer.renderMode = VideoRenderMode.CameraNearPlane;
|
||||
|
||||
if (targetCamera == null)
|
||||
targetCamera = Camera.main;
|
||||
|
||||
if (targetCamera != null)
|
||||
videoPlayer.targetCamera = targetCamera;
|
||||
|
||||
bool finished = false;
|
||||
void OnVideoFinished(VideoPlayer vp) => finished = true;
|
||||
|
||||
videoPlayer.loopPointReached += OnVideoFinished;
|
||||
|
||||
videoPlayer.Prepare();
|
||||
while (!videoPlayer.isPrepared)
|
||||
yield return null;
|
||||
|
||||
videoPlayer.Play();
|
||||
|
||||
if (audioSource != null && finishVideoAudio != null)
|
||||
{
|
||||
audioSource.clip = finishVideoAudio;
|
||||
audioSource.volume = finishVideoAudioVolume;
|
||||
audioSource.Play();
|
||||
}
|
||||
else if (audioSource != null && winClip != null)
|
||||
{
|
||||
audioSource.PlayOneShot(winClip, winVolume);
|
||||
}
|
||||
|
||||
while (!finished)
|
||||
yield return null;
|
||||
|
||||
videoPlayer.loopPointReached -= OnVideoFinished;
|
||||
videoPlayer.Stop();
|
||||
|
||||
Complete();
|
||||
}
|
||||
|
||||
public void Initialize(Action<ITask> onCompleted)
|
||||
{
|
||||
onCompletedCallback = onCompleted;
|
||||
IsCompleted = false;
|
||||
finishSequenceStarted = false;
|
||||
isRunning = true;
|
||||
direction = 1f;
|
||||
currentAngle = defaultAngle;
|
||||
SetWheelAngle(currentAngle);
|
||||
|
||||
CancelInvoke();
|
||||
|
||||
if (ring != null)
|
||||
ring.enabled = true;
|
||||
|
||||
if (audioSource != null)
|
||||
audioSource.Stop();
|
||||
|
||||
if (videoPlayer != null)
|
||||
videoPlayer.Stop();
|
||||
|
||||
PlayStartSound();
|
||||
}
|
||||
|
||||
public void ExitTask(Action<ITask> onExit)
|
||||
{
|
||||
isRunning = false;
|
||||
finishSequenceStarted = false;
|
||||
CancelInvoke();
|
||||
|
||||
if (audioSource != null)
|
||||
audioSource.Stop();
|
||||
|
||||
if (videoPlayer != null)
|
||||
videoPlayer.Stop();
|
||||
|
||||
onExit?.Invoke(this);
|
||||
}
|
||||
|
||||
public void Complete()
|
||||
{
|
||||
if (IsCompleted) return;
|
||||
|
||||
IsCompleted = true;
|
||||
isRunning = false;
|
||||
finishSequenceStarted = false;
|
||||
CancelInvoke();
|
||||
|
||||
onCompletedCallback?.Invoke(this);
|
||||
}
|
||||
|
||||
private void PlayStartSound()
|
||||
{
|
||||
if (audioSource != null && startClip != null)
|
||||
audioSource.PlayOneShot(startClip, startVolume);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user