123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159 |
- //***********************************************************
- // Filename: TargetManager.cs
- // Author: Niclas
- // Last changes: 08 August 2018
- // Content: This file generates new targets with several parameters
- //***********************************************************
- using System.Collections;
- using System.Collections.Generic;
- using UnityEngine;
- /// <summary>
- /// This class is responsible for generating new targets with various constrains on button press and tracking the experiment progress
- /// </summary>
- public class TargetManager : MonoBehaviour, IButton {
- // true if the experiment is ongoing
- public bool isExpActive = false;
- // Area in which new targets can be generated
- private GameObject area;
- // Bounds of the area
- private Bounds areaBounds;
- // The number of targets that will be spawned in this experiment
- public int numberOfTargets = 0;
- // Prefab used to generate a new target
- public GameObject targetPrefab;
- // The gameobject of prefab instance which is already placed in the scene
- public GameObject lastTarget;
- // Constrains for generating the next target
- // The maximum rotation of the direction of targets in either way
- public float maxAngle = 10;
- // minimum and maximum distance of the next target to the current one
- public float minDistance = 1;
- public float maxDistance = 3;
- // The maximum y rotation of the next target
- public float maxTargetRotation = 360;
- // Directional Vector from which the direction in which the next target spawns will be calculated
- private Vector3 dirOfNextPos = Vector3.right;
- // 0 for starting target, >0 for "true" targets; doubles as target count
- private int currentTargetId = 0;
- // Use this for initialization
- void Start() {
- // Set base Target which only used to calculate the postion of the first "real" Target
- if (lastTarget == null) {
- lastTarget = new GameObject();
- }
- area = GameObject.FindGameObjectWithTag("ExpPlane");
- areaBounds = area.GetComponent<MeshFilter>().mesh.bounds;
- }
- // Update is called once per frame
- void Update() {
- // Debug Listener for KeyPress
- if (Input.GetKeyDown(KeyCode.Space)) {
- OnButtonUp();
- }
- }
- /// <summary>
- /// Spawns Target at desired position and rotation as child of area
- /// </summary>
- private void SpawnTarget() {
- currentTargetId++;
- GameObject target = Instantiate(targetPrefab);
- target.transform.SetParent(area.transform, false);
- target.transform.localPosition = RandomRestrictedPosition();
- target.transform.rotation = RandomYRotation();
- target.GetComponent<TestTarget>().id = currentTargetId;
- lastTarget = target;
- // Fire event that a new target has been spawned
- TargetSpawnedEvent tse = new TargetSpawnedEvent();
- tse.targetId = currentTargetId;
- tse.targetTransform = target.transform;
- tse.FireEvent();
- }
- /// <summary>
- /// Generates a random rotation with nullvector as base, is separate to allow possible restrictions in rotation
- /// </summary>
- /// <returns>Returns a Quaternion containing a random rotation within constrains</returns>
- private Quaternion RandomYRotation() {
- Vector3 euler = Vector3.zero;
- euler.y = Random.Range((-maxTargetRotation / 2) - 90, (maxTargetRotation / 2) - 90);
- return Quaternion.Euler(euler);
- }
- /// <summary>
- /// Returns a randomly selected position in the area and calls for a check if it is valid
- /// </summary>
- /// <returns>Returns a within constrains random and valid position</returns>
- private Vector3 RandomRestrictedPosition() {
- Vector3 nextPos = lastTarget.transform.localPosition;
- float rot = Random.Range(-maxAngle, maxAngle);
- Vector3 moveTarget = Quaternion.AngleAxis(rot, Vector3.up) * dirOfNextPos;
- // TODO: improve so it rotates based on lastTarget rotation
- moveTarget = moveTarget.normalized * Random.Range(minDistance, maxDistance);
- nextPos += moveTarget;
- nextPos.y = 0;
- return ValidatePosition(nextPos);
- }
- /// <summary>
- /// Checks if next Position is in the areas bounds and set it inside if needed
- /// </summary>
- /// <param name="position">The position that should be checked if it lies within constrains</param>
- /// <returns>Returns the position with, if necessary, corrections</returns>
- private Vector3 ValidatePosition(Vector3 position) {
- if (!areaBounds.Contains(position)) {
- Debug.Log("OutOfBounds! ClosestPos: " + areaBounds.ClosestPoint(position));
- position = areaBounds.ClosestPoint(position) + ((areaBounds.ClosestPoint(position) - position).normalized * maxDistance);
- dirOfNextPos = dirOfNextPos * -1;
- }
- return position;
- }
- /// <summary>
- /// Called when the corresponding button on the controller this script is put into, is released
- /// </summary>
- public void OnButtonUp() {
- if (isExpActive) {
- Destroy(lastTarget);
- if (currentTargetId == numberOfTargets) {
- isExpActive = false;
- ExperimentEndEvent eee = new ExperimentEndEvent();
- eee.FireEvent();
- } else {
- SpawnTarget();
- }
- }
- }
- // unused; necessary to match signature
- public void OnButtonDown(GameObject controllerObject, int controllerIdentificator) {
- }
- }
|