Im using Unity and have asked this on there forums however have not had any replies. Ive found this example from a plugin where I am trying to use the kinect to rotate an object using my right hand to rotate it right and the left to rotate left. I have managed to get the object to do this apart from it stops at each side of the object, but cant work out what part of the code is doing this.
Thanks
using UnityEngine;
using System.Collections;
using System;
public class GestureListener : MonoBehaviour, KinectGestures.GestureListenerInterface
{
// GUI Text to display the gesture messages.
public GUIText GestureInfo;
private bool raiselefthand;
private bool raiserighthand;
public bool IsSwipeLeft()
{
if(raiserighthand)
{
raiserighthand = false;
return true;
}
return false;
}
public bool IsSwipeRight()
{
if(raiselefthand)
{
raiselefthand = false;
return true;
}
return false;
}
public void UserDetected(uint userId, int userIndex)
{
// detect these user specific gestures
KinectManager manager = KinectManager.Instance;
manager.DetectGesture(userId, KinectGestures.Gestures.RaiseLeftHand);
manager.DetectGesture(userId, KinectGestures.Gestures.RaiseRightHand);
if(GestureInfo != null)
{
GestureInfo.GetComponent<GUIText>().text = "Swipe left or right to change the slides.";
}
}
public void UserLost(uint userId, int userIndex)
{
if(GestureInfo != null)
{
GestureInfo.GetComponent<GUIText>().text = string.Empty;
}
}
public void GestureInProgress(uint userId, int userIndex, KinectGestures.Gestures gesture,
float progress, KinectWrapper.NuiSkeletonPositionIndex joint, Vector3 screenPos)
{
// don't do anything here
}
public bool GestureCompleted (uint userId, int userIndex, KinectGestures.Gestures gesture,
KinectWrapper.NuiSkeletonPositionIndex joint, Vector3 screenPos)
{
string sGestureText = gesture + " detected";
if(GestureInfo != null)
{
GestureInfo.GetComponent<GUIText>().text = sGestureText;
}
if(gesture == KinectGestures.Gestures.RaiseRightHand)
raiserighthand = true;
else if(gesture == KinectGestures.Gestures.RaiseLeftHand)
raiselefthand = true;
return true;
}
public bool GestureCancelled (uint userId, int userIndex, KinectGestures.Gestures gesture,
KinectWrapper.NuiSkeletonPositionIndex joint)
{
// don't do anything here, just reset the gesture state
return true;
}
}
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
public class PresentationScript : MonoBehaviour
{
public bool slideChangeWithGestures = true;
public bool slideChangeWithKeys = true;
public float spinSpeed = 5;
public bool autoChangeAlfterDelay = false;
public float slideChangeAfterDelay = 10;
public List<Texture> slideTextures;
public List<GameObject> horizontalSides;
// if the presentation cube is behind the user (true) or in front of the user (false)
public bool isBehindUser = false;
private int maxSides = 0;
private int maxTextures = 0;
private int side = 0;
private int tex = 0;
private bool isSpinning = false;
private float slideWaitUntil;
private Quaternion targetRotation;
private GestureListener gestureListener;
void Start()
{
// hide mouse cursor
Cursor.visible = false;
// calculate max slides and textures
maxSides = horizontalSides.Count;
maxTextures = slideTextures.Count;
// delay the first slide
slideWaitUntil = Time.realtimeSinceStartup + slideChangeAfterDelay;
targetRotation = transform.rotation;
isSpinning = false;
tex = 0;
side = 0;
if(horizontalSides[side] && horizontalSides[side].GetComponent<Renderer>())
{
horizontalSides[side].GetComponent<Renderer>().material.mainTexture = slideTextures[tex];
}
// get the gestures listener
gestureListener = Camera.main.GetComponent<GestureListener>();
}
void Update()
{
// dont run Update() if there is no user
KinectManager kinectManager = KinectManager.Instance;
if(autoChangeAlfterDelay && (!kinectManager || !kinectManager.IsInitialized() || !kinectManager.IsUserDetected()))
return;
if(!isSpinning)
{
if(slideChangeWithKeys)
{
if(Input.GetKeyDown(KeyCode.PageDown))
RotateToNext();
else if(Input.GetKeyDown(KeyCode.PageUp))
RotateToPrevious();
}
if(slideChangeWithGestures && gestureListener)
{
if(gestureListener.IsSwipeLeft())
RotateToNext();
else if(gestureListener.IsSwipeRight())
RotateToPrevious();
}
// check for automatic slide-change after a given delay time
if(autoChangeAlfterDelay && Time.realtimeSinceStartup >= slideWaitUntil)
{
RotateToNext();
}
}
else
{
// spin the presentation
transform.rotation = Quaternion.Slerp(transform.rotation, targetRotation, spinSpeed * Time.deltaTime);
// check if transform reaches the target rotation. If yes - stop spinning
float deltaTargetX = Mathf.Abs(targetRotation.eulerAngles.x - transform.rotation.eulerAngles.x);
float deltaTargetY = Mathf.Abs(targetRotation.eulerAngles.y - transform.rotation.eulerAngles.y);
if(deltaTargetX < 1f && deltaTargetY < 1f)
{
// delay the slide
slideWaitUntil = Time.realtimeSinceStartup + slideChangeAfterDelay;
isSpinning = false;
}
}
}
private void RotateToNext()
{
// set the next texture slide
tex = (tex + 1) % maxTextures;
if(!isBehindUser)
{
side = (side + 1) % maxSides;
}
else
{
if(side <= 0)
side = maxSides - 1;
else
side -= 1;
}
if(horizontalSides[side] && horizontalSides[side].GetComponent<Renderer>())
{
horizontalSides[side].GetComponent<Renderer>().material.mainTexture = slideTextures[tex];
}
// rotate the presentation
float yawRotation = !isBehindUser ? 360f / maxSides : -360f / maxSides;
Vector3 rotateDegrees = new Vector3(0f, yawRotation, 0f);
targetRotation *= Quaternion.Euler(rotateDegrees);
isSpinning = true;
}
private void RotateToPrevious()
{
// set the previous texture slide
if(tex <= 0)
tex = maxTextures - 1;
else
tex -= 1;
if(!isBehindUser)
{
if(side <= 0)
side = maxSides - 1;
else
side -= 1;
}
else
{
side = (side + 1) % maxSides;
}
if(horizontalSides[side] && horizontalSides[side].GetComponent<Renderer>())
{
horizontalSides[side].GetComponent<Renderer>().material.mainTexture = slideTextures[tex];
}
// rotate the presentation
float yawRotation = !isBehindUser ? -360f / maxSides : 360f / maxSides;
Vector3 rotateDegrees = new Vector3(0f, yawRotation, 0f);
targetRotation *= Quaternion.Euler(rotateDegrees);
isSpinning = true;
}
}
I have managed to get the object to do this apart from it stops at each side of the object, but cant work out what part of the code is doing this.
I understand you ask for help finding which parts are involved in the rotation.
As such, I looked through the scripts and noticed 2 sections in the PresentationScript.
This part in the Update() method. Based on the code and the comments that are part of it.
// spin the presentation
transform.rotation = Quaternion.Slerp(transform.rotation, targetRotation, spinSpeed * Time.deltaTime);
// check if transform reaches the target rotation. If yes - stop spinning
float deltaTargetX = Mathf.Abs(targetRotation.eulerAngles.x - transform.rotation.eulerAngles.x);
float deltaTargetY = Mathf.Abs(targetRotation.eulerAngles.y - transform.rotation.eulerAngles.y);
if(deltaTargetX < 1f && deltaTargetY < 1f)
{
// delay the slide
slideWaitUntil = Time.realtimeSinceStartup + slideChangeAfterDelay;
isSpinning = false;
}
This line in the Start() method is also involved.
targetRotation = transform.rotation;
A transform controls the position, scaling and as is relevant for this case, also the rotation of an object.
Related
So decided to give game dev a try, picked up unity,Now I decided to create a simple ping pong game.
My game has Bat.cs class, ball.cs, and GameHandler.cs.
The GameHandler.cs initializes the batRight, batLeft, ball using the Bat.cs, Ball.cs class and prefabs, it also keeps track of if someone scores then starts a serve by stopping the rally:
public class GameHandler : MonoBehaviour
{
public Bat bat;
public Ball ball;
public Score score;
public static Vector2 bottomLeft;
public static Vector2 topRight;
public static bool rallyOn = false;
public static bool isServingLeft = true;
public static bool isServingRight = false;
public static bool isTwoPlayers = true;
static Bat batRight;
static Bat batLeft;
public static Ball ball1;
static Score scoreLeft;
static Score scoreRight;
// Start is called before the first frame update
void Start()
{
//Convert screens pixels coordinate into games coordinate
bottomLeft = Camera.main.ScreenToWorldPoint(new Vector2(0, 0));
topRight = Camera.main.ScreenToWorldPoint(new Vector2(Screen.width, Screen.height));
ball1 = Instantiate(ball) as Ball;
//Debug.Log("GameHandler.Start");
batRight = Instantiate(bat) as Bat;
batRight.Init(true);
batLeft = Instantiate(bat) as Bat;
batLeft.Init(false);
ball1.transform.position = new Vector3(batLeft.transform.position.x + ball1.getRadius() * 2, batLeft.transform.position.y);
//Instatiate scores
scoreLeft = Instantiate(score, new Vector2(-2, -4), Quaternion.identity) as Score;
scoreRight = Instantiate(score, new Vector2(2, -4), Quaternion.identity) as Score;
}
private void Update()
{
if (isServingLeft)
{
ball1.transform.position = new Vector3(batLeft.transform.position.x + ball1.getRadius() * 2, batLeft.transform.position.y);
if (Input.GetKey(KeyCode.LeftControl))
{
rallyOn = true;
isServingLeft = false;
}
}
if (isServingRight)
{
ball1.transform.position = new Vector3(batRight.transform.position.x - ball1.getRadius() * 2, batRight.transform.position.y);
if (isTwoPlayers && Input.GetKey(KeyCode.RightControl))
{
rallyOn = true;
isServingRight = false;
}
else
{
StartCoroutine(batRight.serveAi());
if (GameHandler.rallyOn)
{
StopCoroutine(batRight.serveAi());
}
}
}
}
public static void increaseScoreByOne(bool isRight)
{
rallyOn = false;
if (isRight)
{
scoreRight.increaseScore();
isServingRight = true;
}
else
{
scoreLeft.increaseScore();
isServingLeft = true;
}
}
}
The ball.cs listens to the static GameHandler.rallyOn and starts moving the ball accordingly, it also changes direction of the ball if it hits a vertical wall or the bat:
public class Ball : MonoBehaviour
{
[SerializeField]
float speed;
float radius;
public Vector2 direction;
public Vector3 ballPosition;
// Start is called before the first frame update
void Start()
{
direction = Vector2.one.normalized; // direction is (1, 1) normalized
//Debug.Log("direction * speed * Time.deltaTime:" + direction * speed * Time.deltaTime);
radius = transform.localScale.x / 2;
}
// Update is called once per frame
void Update()
{
ballPosition = transform.position;
if (GameHandler.rallyOn)
{
startRally();
}
}
void startRally()
{
transform.Translate(direction * speed * Time.deltaTime);
Debug.Log("direction * speed * Time.deltaTime:" + direction * speed * Time.deltaTime);
if ((transform.position.y + radius) > GameHandler.topRight.y && direction.y > 0)
{
direction.y = -direction.y;
}
if ((transform.position.y + radius) < GameHandler.bottomLeft.y && direction.y < 0)
{
direction.y = -direction.y;
}
if ((transform.position.x + radius) > GameHandler.topRight.x && direction.x > 0)
{
// Left player scores
GameHandler.increaseScoreByOne(false);
//For no, just freeza the script
// Time.timeScale = 0;
//enabled = false;
}
if ((transform.position.x - radius) < GameHandler.bottomLeft.x && direction.x < 0)
{
// right player scores
GameHandler.increaseScoreByOne(true);
}
}
void OnTriggerEnter2D(Collider2D collision)
{
if(collision.tag == "Bat")
{
if (collision.GetComponent<Bat>().isRight && direction.x > 0)
{
direction.x = -direction.x;
}
if (!collision.GetComponent<Bat>().isRight && direction.x < 0)
{
direction.x = -direction.x;
}
}
}
public float getRadius()
{
return radius;
}
}
The bat.cs initiazes the two paddles, and either listens to user input if its 2 players or listens to player and use AI if it is player vs CPU.:
public class Bat : MonoBehaviour
{
float height;
[SerializeField] // this make this appear on editor without making this field public
float speed;
string input;
public bool isRight;
string PLAYER1_INPUT = "PaddleLeft";
string PLAYER2_INPUT = "PaddleRight";
// Start is called before the first frame update
void Start()
{
height = transform.localScale.y;
}
// Update is called once per frame
void Update()
{
if (GameHandler.isTwoPlayers)
{
if (isRight)
{
movePaddleonUserInput(PLAYER2_INPUT);
}
else
{
movePaddleonUserInput(PLAYER1_INPUT);
}
}
else
{
if (isRight)
{
movePaddleAi();
}
else
{
movePaddleonUserInput(PLAYER1_INPUT);
}
}
}
void movePaddleAi()
{
if (isRight && GameHandler.ball1.direction.x > 0 && GameHandler.ball1.ballPosition.x > 0)
{
//transform.Translate(direction * speed * Time.deltaTime);
if ((transform.position.y) > GameHandler.ball1.ballPosition.y && GameHandler.ball1.direction.y < 0)
{
transform.Translate(GameHandler.ball1.direction * speed * Time.deltaTime * Vector2.up);
}
if ((transform.position.y) < GameHandler.ball1.ballPosition.y && GameHandler.ball1.direction.y > 0)
{
transform.Translate(GameHandler.ball1.direction * speed * Time.deltaTime * Vector2.up);
}
}
}
void movePaddleonUserInput(string input)
{
// move = (-1 -> 1) * speed * timeDelta(this keep move framerate independent)
float move = Input.GetAxis(input) * speed * Time.deltaTime;
//Debug.Log((transform.position.y + height / 2) + " > "+ GameHandler.topRight.y+ "&&" + move +" > 0");
//Restrict paddle movement to to the screen
// (top edge of paddle > Screen top and we are moving up)
if ((transform.position.y + height / 2) > GameHandler.topRight.y && move > 0)
{
move = 0;
}
// (bottom edge of paddle < Screen top and we are moving down)
if ((transform.position.y - height / 2) < GameHandler.bottomLeft.y && move < 0)
{
move = 0;
}
transform.Translate(move * Vector2.up);
}
public void Init(bool isRightPaddle)
{
isRight = isRightPaddle;
Vector2 pos;
if (isRightPaddle)
{
isRight = isRightPaddle;
pos = new Vector2(GameHandler.topRight.x, 0);
// offset since center is the anchor
pos -= Vector2.right * transform.localScale.x;
input = "PaddleRight";
}
else
{
pos = new Vector2(GameHandler.bottomLeft.x, 0);
// offset since center is the anchor
pos += Vector2.right * transform.localScale.x;
input = "PaddleLeft";
}
transform.name = input;
transform.position = pos;
}
public IEnumerator serveAi()
{
yield return new WaitForSecondsRealtime (2f);
GameHandler.rallyOn = true;
GameHandler.isServingRight = false;
}
}
Now I also have score.cs and mainMenu scene , but no need to include that for this question, What I am struggling with now is the AI not stopping after it scores a point, I want the AI paddle to stop for a few seconds before it serves.
As you can see in the code, I added a yield return new WaitForSecondsRealtime(2f);
public IEnumerator serveAi()
{
yield return new WaitForSecondsRealtime (2f);
GameHandler.rallyOn = true;
GameHandler.isServingRight = false;
}
But this only cause the paddle to wait for the first time it scores , and then if it scores again in quick interval, it doesn't wait at all.
Not sure what I doing wrong here, thanks for your time.
The more plausible explanation to me would be that GameHandler.rallyOn and isServing* aren't all being reset to the correct values to prevent the serve from occurring before the coroutine even begins, or another check is needed somewhere to prevent a serve from occurring if all of the correct booleans aren't set. Try placing appropriate breakpoints and stepping through in a debugger.
You'd probably be better off using WaitForSeconds rather than WaitForSecondsRealtime, by the way, at least if there's a chance you might want to allow the game to be paused in the future.
Realized that the coroutine is called multiple times even before its finished due do it being called from update function in GameHandler.cs. Needed a way to check if the co-routine is already running and not start a new one from update if so, used the Game.isServing variable to do so:
public IEnumerator serveAi()
{
GameHandler.isServingRight = false; // coroutine started , no need to start new one
yield return new WaitForSecondsRealtime (2f);
GameHandler.rallyOn = true;
}
And my update in GameHandler is already checking for that variable before starting the coroutine:
private void Update()
{
if (isServingLeft)
{
ball1.transform.position = new Vector3(batLeft.transform.position.x + ball1.getRadius() * 2, batLeft.transform.position.y);
if (Input.GetKey(KeyCode.LeftControl))
{
rallyOn = true;
isServingLeft = false;
}
}
if (isServingRight)
{
ball1.transform.position = new Vector3(batRight.transform.position.x - ball1.getRadius() * 2, batRight.transform.position.y);
if (isTwoPlayers && Input.GetKey(KeyCode.RightControl))
{
rallyOn = true;
isServingRight = false;
}
else
{
StartCoroutine(batRight.serveAi());
}
}
}
I am writing a C# script on Unity 3D.
I'm working on pathfinding now.
The path has been found correctly in the Array List and the Object can move according to the path with a constant speed.
Then, I want to improvise, where when the path found is a straight line, the object will increase its speed. Meanwhile, when the path turns the object will reduce its speed again.
Here, I don't know how to group between straight and turning paths in an arrayList.
Thankyou for helping me :)
This is the code :
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
public abstract class Unit : MonoBehaviour
{
#region public variables
public GameObject Astar;
public bool drawGizmos = false;
protected float gravity = 9.8f;
public Transform target;
public Transform NPC;
public Vector3 lastTargetPosition;
public float movementSpeed;
public float rotationSpeed = 85;
protected float distanceToPath = 1;
public Vector2 currentPosition = new Vector2(0, 0);
protected int spacesMoved = 0;
// Default action times to 5 second interval
protected float period = 1f;
protected float nextActionTime = 1f;
protected bool isSafeToUpdatePath = false;
protected int pathFoundCount = 0;
protected bool isMoving = false;
protected bool isTargetReached = false;
#endregion
#region member variables
public Vector3[] m_path;
protected int m_targetIndex;
protected CharacterController m_characterController;
private Node lastNodePosition;
private List<Node> lastPositionNeighbors;
private Vector3 m_lastKnownPosition;
private Quaternion m_lookAtRotation;
private GridSystem m_grid;
private Coroutine lastRoutine = null;
private bool preventExtraNodeUpdate = false;
public Stopwatch timer;
#endregion
public virtual void Awake()
{
timer = new Stopwatch();
if (Astar != null)
m_grid = Astar.GetComponent<GridSystem>();
}
public virtual void Start()
{
m_characterController = GetComponent<CharacterController>();
timer.Reset();
timer.Start();
PathRequestManager.RequestPath(transform.position, target.position, OnPathFound);
lastTargetPosition = target.position;
UnityEngine.Debug.Log("NPC Position : " + transform.position);
UnityEngine.Debug.Log("Target Position : " + target.position);
}
public virtual void Update()
{
if (Time.time > nextActionTime) //update path setiap 1f
{
nextActionTime += period;
isSafeToUpdatePath = true;
}
else
{
isSafeToUpdatePath = false;
}
//If we don't check !isMoving the AI may get stuck waiting to update the grid for nextActionTime.
if (target.position != lastTargetPosition)
{
isMoving = true;
UpdateNodePosition();
UpdatePath();
UpdateRotation();
}
lastTargetPosition = target.position;
}
public void UpdatePath()
{
lastNodePosition.walkable = Walkable.Passable;
PathRequestManager.RequestPath(transform.position, target.position, OnPathFound);
}
public virtual void OnPathFound(Vector3[] newPath, bool pathSuccessful)
{
if (pathSuccessful)
{
pathFoundCount++;
m_path = newPath;
m_targetIndex = 0;
// Stop coroutine if it is already running.
if (lastRoutine != null)
StopCoroutine(lastRoutine);
lastRoutine = StartCoroutine(FollowPath());
}
}
public float time;
public virtual IEnumerator FollowPath()
{
Vector3 currentPath = m_path[0];
while (true)
{
if (Vector3.Distance(transform.position, currentPath) < distanceToPath)
{
m_targetIndex++;
// If we are done with path.
if (m_targetIndex >= m_path.Length)
{
timer.Stop();
UnityEngine.Debug.Log("Time Move : " + timer.ElapsedMilliseconds);
isMoving = false;
yield break;
}
currentPath = m_path[m_targetIndex];
}
float Distance = Vector3.Distance(NPC.transform.position, target.transform.position);
UnityEngine.Debug.Log("Distance : " + Distance);
// Occurs each frame
//move follow path
UpdatePosition(currentPath);
yield return null;
}
}
public virtual void UpdatePosition(Vector3 destination)
{
Node node = m_grid.NodeFromWorldPoint(transform.position);
Vector3 direction = destination - transform.position;
movementSpeed = 1;
transform.Translate(direction.normalized * movementSpeed * Time.deltaTime, Space.World);
UnityEngine.Debug.Log("Speed NPC : " + movementSpeed);
}
public virtual void UpdateRotation()
{
m_lastKnownPosition = target.transform.position;
m_lookAtRotation = Quaternion.LookRotation(m_lastKnownPosition - transform.position);
if (transform.rotation != m_lookAtRotation)
transform.rotation = Quaternion.RotateTowards(transform.rotation, m_lookAtRotation, rotationSpeed * Time.deltaTime);
}
public void UpdateNodePosition()
{
Node node = m_grid.NodeFromWorldPoint(transform.position);
if (isMoving == false)
{
lastPositionNeighbors = m_grid.GetNeighbours(node);
foreach (Node n in lastPositionNeighbors)
{
if (n.walkable != Walkable.Impassable)
n.walkable = Walkable.Blocked;
}
node.walkable = Walkable.Blocked;
lastNodePosition = node;
currentPosition = new Vector2(node.gridX, node.gridY);
return;
}
if (lastNodePosition != null && isMoving)
{
preventExtraNodeUpdate = false;
lastPositionNeighbors = m_grid.GetNeighbours(node);
lastNodePosition.walkable = Walkable.Passable;
if (lastPositionNeighbors != null)
foreach (Node n in lastPositionNeighbors)
{
if (n.walkable != Walkable.Impassable)
n.walkable = Walkable.Passable;
}
if (!node.Equals(lastNodePosition))
spacesMoved++;
}
else
{
node.walkable = Walkable.Blocked;
lastNodePosition = node;
currentPosition = new Vector2(node.gridX, node.gridY);
}
}
public void OnDrawGizmos()
{
if (!drawGizmos)
return;
if (m_path != null)
{
for (int i = m_targetIndex; i < m_path.Length; i++)
{
Gizmos.color = Color.black;
Gizmos.DrawCube(m_path[i], Vector3.one);
}
}
}
}
This screenshot after running
Okay. It looks to me like all that you have to do in order to determine if you are on a curved path is to check if the next step you are going to take is directly in front of the player. You can do this in your UpdatePosition function. Just check if the direction you are about to move in has the same x or z position. Assuming that y is up and all points on your grid have the same y position. In the case that you are moving horizontally, x will stay the same, and in the case that you are moving vertically, z will stay the same. Or vice versa.
public virtual void UpdatePosition(Vector3 destination)
{
Node node = m_grid.NodeFromWorldPoint(transform.position);
Vector3 direction = destination - transform.position;
if(destination.x == transform.position.x || destination.z == transform.position.z)
{
//Direction is staying the same
movementSpeed = 1f;
}else{
movementSpeed = 0.5f;
}
transform.Translate(direction.normalized * movementSpeed * Time.deltaTime, Space.World);
UnityEngine.Debug.Log("Speed NPC : " + movementSpeed);
}
You should be able to customize the movement speed however you want from there. IF you're having issues still after this, try printing out the (x,y,z) components of the destination and the transform and see where they are similar when the path is straight and what changes when the path is curved. The code above assumes the y never changes.
Now I'm using the F key to make it scale up or down.
But I want to add another method for example AutoScaling that when calling it in Update it will scale up first once finished scaling up it will scale down and then up again and so no nonstop.
The Scaling script :
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Scaling : UnityEngine.MonoBehaviour
{
public GameObject objectToScale;
public GameObject lookAtTarget;
public float duration = 1f;
public Vector3 minSize;
public Vector3 maxSize;
public bool scaleUp = false;
public Coroutine scaleCoroutine;
public bool scalingHasFinished = false;
public void Inits()
{
scalingHasFinished = false;
objectToScale.transform.localScale = minSize;
}
public IEnumerator scaleOverTime(GameObject targetObj, Vector3 toScale, float duration, Camera objectToScaleCamera)
{
float counter = 0;
Vector3 startScaleSize = targetObj.transform.localScale;
while (counter < duration)
{
counter += Time.deltaTime;
targetObj.transform.localScale = Vector3.Lerp(startScaleSize, toScale, counter / duration);
if (scaleUp)
{
var lookPos = lookAtTarget.transform.position - objectToScale.transform.position;
lookPos.y = 0;
var rotation = Quaternion.LookRotation(lookPos);
objectToScale.transform.rotation = Quaternion.Slerp(objectToScale.transform.rotation, rotation, counter / duration);
}
else
{
var lookPos = lookAtTarget.transform.position - objectToScale.transform.position;
lookPos.y = 0;
var rotation = Quaternion.LookRotation(objectToScaleCamera.transform.forward);//SwitchCameras.GetCurrentCamera().transform.forward);//Camera.main.transform.forward);
objectToScale.transform.rotation = Quaternion.Slerp(objectToScale.transform.rotation, rotation, counter / duration);
}
yield return null;
}
scalingHasFinished = true;
}
public IEnumerator scaleOverTime(GameObject targetObj, Vector3 toScale, float duration, float rotationSpeed)
{
float counter = 0;
Vector3 startScaleSize = targetObj.transform.localScale;
while (counter < duration)
{
counter += Time.deltaTime;
targetObj.transform.localScale = Vector3.Lerp(startScaleSize, toScale, counter / duration);
targetObj.transform.Rotate(Vector3.up * rotationSpeed * Time.deltaTime, Space.Self);
yield return null;
}
}
}
And the script that use the scaling :
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class ObjectsManipulation : UnityEngine.MonoBehaviour
{
//Camera
public Camera playerCamera;
//Scaling
private bool canScale = true;
private Scaling scaling;
//Lights
public DimLights dimlights;
private Coroutine lightCoroutine;
//Colors
private Colors colors;
//Rotating
private bool stopRotation = false;
private Rotating rotating;
private void Start()
{
scaling = GetComponent<Scaling>();
scaling.Inits();
colors = GetComponent<Colors>();
colors.Start();
rotating = GetComponent<Rotating>();
}
// Use this for initialization
void Update()
{
if (playerCamera != null)
{
//Scaling
if (Input.GetKeyDown(KeyCode.F) && canScale == true)
{
Scaling();
}
}
//Rotate
if (Input.GetKey(KeyCode.R) && !scaling.scaleUp)
{
rotating.x += Time.deltaTime * rotating.rotationSpeed;
scaling.objectToScale.transform.localRotation = Quaternion.Euler(0, 0, rotating.x);
rotating.keyPressed = true;
}
if (Input.GetKeyUp(KeyCode.R))
{
rotating.keyPressed = false;
}
if (!rotating.keyPressed && !scaling.scaleUp && rotating.rotateBack == false
&& DetectInteractable.detected == false)
{
scaling.objectToScale.transform.rotation = Quaternion.LookRotation(playerCamera.transform.forward);
}
if (DetectInteractable.detected == true && !scaling.scaleUp && stopRotation == false)
{
rotating.x += Time.deltaTime * rotating.rotationSpeed;
scaling.objectToScale.transform.localRotation = Quaternion.Euler(0, 0, rotating.x);
}
}
public void Scaling()
{
//Flip the scale direction when F key is pressed
scaling.scaleUp = !scaling.scaleUp;
//Stop old coroutine
if (scaling.scaleCoroutine != null)
StopCoroutine(scaling.scaleCoroutine);
if (lightCoroutine != null)
StopCoroutine(lightCoroutine);
//Scale up
if (scaling.scaleUp)
{
//Start new coroutine and scale up within 5 seconds and return the coroutine reference
rotating.rotateBack = false;
scaling.scaleCoroutine = StartCoroutine(scaling.scaleOverTime(scaling.objectToScale, scaling.maxSize, scaling.duration, playerCamera));
if (dimlights.lightsOnOff == false)
lightCoroutine = StartCoroutine(dimlights.dimLightOverTime(1, scaling.duration));
}
//Scale Down
else
{
//Start new coroutine and scale up within 5 seconds and return the coroutine reference
rotating.rotateBack = true;
scaling.scaleCoroutine = StartCoroutine(scaling.scaleOverTime(scaling.objectToScale, scaling.minSize, scaling.duration, playerCamera));
if (dimlights.lightsOnOff == false)
lightCoroutine = StartCoroutine(dimlights.dimLightOverTime(0, scaling.duration)); ;
}
}
}
And in third script I want to call a method that will be in the ObjectsManipulation script maybe the same method Scaling maybe he will get a bool and if the bool is true make it scaling up/down automatic if it's not true make it use a key.
This is the script for testing the Scaling :
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class ScalingTest : MonoBehaviour
{
ObjectsManipulation om;
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
void Update()
{
om.Scaling();
}
}
For example in the Update maybe to do : om.Scaling(false); for using the F key and om.Scaling(true); for automatic.
Update of what I have tried :
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using UnityEditor;
using UnityEngine;
public class ConversationTrigger : MonoBehaviour
{
public List<Conversation> conversations = new List<Conversation>();
[HideInInspector]
public int dialogueIndex;
[HideInInspector]
public int conversationIndex;
private bool triggered = false;
private bool activateButton = false;
private DialogueManager dialoguemanager;
private bool startDialogue = false;
private void Start()
{
dialogueIndex = 0;
dialoguemanager = FindObjectOfType<DialogueManager>();
}
public IEnumerator PlayConversation(int index)
{
this.conversationIndex = index;
if (conversations.Count > 0 &&
conversations[index].Dialogues.Count > 0)
{
for (int i = 0; i < conversations[index].Dialogues.Count; i++)
{
if (triggered == false)
{
if (dialoguemanager != null)
{
dialoguemanager.StartDialogue(conversations[index].Dialogues[i]);
}
while (DialogueManager.dialogueEnded == false)
{
yield return null;
}
}
}
}
}
public void SaveConversations()
{
string jsonTransform = JsonHelper.ToJson(conversations.ToArray(), true);
File.WriteAllText(#"d:\json.txt", jsonTransform);
}
public void LoadConversations()
{
string jsonTransform = File.ReadAllText(#"d:\json.txt");
conversations.Clear();
conversations.AddRange(JsonHelper.FromJson<Conversation>(jsonTransform));
}
}
And using it like this :
StartCoroutine(conversationTrigger.PlayConversation(0));
Where conversationTrigger is public ConversationTrigger conversationTrigger;
But it's not working good at all. It's starting the conversation index 0 but then play only the first dialogue sentences twice and then never continue to the next dialogue there are two dialogues in this case. And then it stop.
It should play all the dialogues of the current conversation.
Something in the PlayConversation method is wrong.
I'm sorry to say your post is long and contains many redundant codes, so I haven't carefully read it, this is a simple reference about making a zoom animation by script.
float minScale; // Minimum scale value
float maxScale; // Maximum scale value
Transform target; // Target to scale
void Update()
{
float scale = Mathf.PingPong(Time.time, maxScale - minScale) + minScale;
target.localScale = new Vector3(scale, scale, scale);
}
CurrentlyGrounded Should flip to true and false. Instead, visual studio is reporting that it "Doesn't exist in the current context". How do I force this variable to exist EVERYWHERE in the script?
Making it public did absolutely nothing.
The problem occurs in the private void GroundCheck() method on Line 267.
using System;
using UnityEngine;
using UnityStandardAssets.CrossPlatformInput;
namespace UnityStandardAssets.Characters.FirstPerson
{
[RequireComponent(typeof (Rigidbody))]
[RequireComponent(typeof (CapsuleCollider))]
public class RigidbodyFirstPersonController : MonoBehaviour
{
[Serializable]
public class MovementSettings
{
public float ForwardSpeed = 8.0f; // Speed when walking forward
public float BackwardSpeed = 4.0f; // Speed when walking backwards
public float StrafeSpeed = 4.0f; // Speed when walking sideways
public float AirForwardSpeed = 8.0f; // Speed when flying forward
public float AirBackwardSpeed = 4.0f; // Speed when flying backwards
public float AirStrafeSpeed = 4.0f; // Speed when flying sideways
public bool CurrentlyGrounded = true;
public float RunMultiplier = 2.0f; // Speed when sprinting
public KeyCode RunKey = KeyCode.LeftShift;
public float JumpForce = 30f;
public AnimationCurve SlopeCurveModifier = new AnimationCurve(new Keyframe(-90.0f, 1.0f), new Keyframe(0.0f, 1.0f), new Keyframe(90.0f, 0.0f));
[HideInInspector] public float CurrentTargetSpeed = 8f;
#if !MOBILE_INPUT
private bool m_Running;
#endif
public void UpdateDesiredTargetSpeed(Vector2 input)
{
if (input == Vector2.zero) return;
if (input.x > 0 || input.x < 0 && CurrentlyGrounded == true)
{
//strafe
CurrentTargetSpeed = StrafeSpeed;
}
else if (input.x > 0 || input.x < 0 && CurrentlyGrounded == false)
{
//strafe
CurrentTargetSpeed = AirStrafeSpeed;
}
if (input.y < 0 && CurrentlyGrounded == true)
{
//backwards
CurrentTargetSpeed = BackwardSpeed;
}
else if (input.y < 0 && CurrentlyGrounded == false)
{
//backwards
CurrentTargetSpeed = AirBackwardSpeed;
}
if (input.y > 0 && CurrentlyGrounded == true)
{
//forwards
//handled last as if strafing and moving forward at the same time forwards speed should take precedence
CurrentTargetSpeed = ForwardSpeed;
}
else if (input.y > 0 && CurrentlyGrounded == false)
{
//forwards
//handled last as if strafing and moving forward at the same time forwards speed should take precedence
CurrentTargetSpeed = AirForwardSpeed;
}
#if !MOBILE_INPUT
if (Input.GetKey(RunKey))
{
CurrentTargetSpeed *= RunMultiplier;
m_Running = true;
}
else
{
m_Running = false;
}
#endif
}
#if !MOBILE_INPUT
public bool Running
{
get { return m_Running; }
}
#endif
}
[Serializable]
public class AdvancedSettings
{
public float groundCheckDistance = 0.01f; // distance for checking if the controller is grounded ( 0.01f seems to work best for this )
public float stickToGroundHelperDistance = 0.5f; // stops the character
public float slowDownRate = 20f; // rate at which the controller comes to a stop when there is no input
public bool airControl; // can the user control the direction that is being moved in the air
[Tooltip("set it to 0.1 or more if you get stuck in wall")]
public float shellOffset; //reduce the radius by that ratio to avoid getting stuck in wall (a value of 0.1f is nice)
}
public Camera cam;
public MovementSettings movementSettings = new MovementSettings();
public MouseLook mouseLook = new MouseLook();
public AdvancedSettings advancedSettings = new AdvancedSettings();
private Rigidbody m_RigidBody;
private CapsuleCollider m_Capsule;
private float m_YRotation;
private Vector3 m_GroundContactNormal;
private bool m_Jump, m_PreviouslyGrounded, m_Jumping, m_IsGrounded;
public Vector3 Velocity
{
get { return m_RigidBody.velocity; }
}
public bool Grounded
{
get { return m_IsGrounded; }
}
public bool Jumping
{
get { return m_Jumping; }
}
public bool Running
{
get
{
#if !MOBILE_INPUT
return movementSettings.Running;
#else
return false;
#endif
}
}
private void Start()
{
m_RigidBody = GetComponent<Rigidbody>();
m_Capsule = GetComponent<CapsuleCollider>();
mouseLook.Init (transform, cam.transform);
}
private void Update()
{
RotateView();
if (CrossPlatformInputManager.GetButtonDown("Jump") && !m_Jump)
{
m_Jump = true;
}
}
private void FixedUpdate()
{
GroundCheck();
Vector2 input = GetInput();
if ((Mathf.Abs(input.x) > float.Epsilon || Mathf.Abs(input.y) > float.Epsilon) && (advancedSettings.airControl || m_IsGrounded))
{
// always move along the camera forward as it is the direction that it being aimed at
Vector3 desiredMove = cam.transform.forward*input.y + cam.transform.right*input.x;
desiredMove = Vector3.ProjectOnPlane(desiredMove, m_GroundContactNormal).normalized;
desiredMove.x = desiredMove.x*movementSettings.CurrentTargetSpeed;
desiredMove.z = desiredMove.z*movementSettings.CurrentTargetSpeed;
desiredMove.y = desiredMove.y*movementSettings.CurrentTargetSpeed;
if (m_RigidBody.velocity.sqrMagnitude <
(movementSettings.CurrentTargetSpeed*movementSettings.CurrentTargetSpeed))
{
m_RigidBody.AddForce(desiredMove*SlopeMultiplier(), ForceMode.Impulse);
}
}
if (m_IsGrounded)
{
m_RigidBody.drag = 5f;
if (m_Jump)
{
m_RigidBody.drag = 0f;
m_RigidBody.velocity = new Vector3(m_RigidBody.velocity.x, 0f, m_RigidBody.velocity.z);
m_RigidBody.AddForce(new Vector3(0f, movementSettings.JumpForce, 0f), ForceMode.Impulse);
m_Jumping = true;
}
if (!m_Jumping && Mathf.Abs(input.x) < float.Epsilon && Mathf.Abs(input.y) < float.Epsilon && m_RigidBody.velocity.magnitude < 1f)
{
m_RigidBody.Sleep();
}
}
else
{
m_RigidBody.drag = 0f;
if (m_PreviouslyGrounded && !m_Jumping)
{
StickToGroundHelper();
}
}
m_Jump = false;
}
private float SlopeMultiplier()
{
float angle = Vector3.Angle(m_GroundContactNormal, Vector3.up);
return movementSettings.SlopeCurveModifier.Evaluate(angle);
}
private void StickToGroundHelper()
{
RaycastHit hitInfo;
if (Physics.SphereCast(transform.position, m_Capsule.radius * (1.0f - advancedSettings.shellOffset), Vector3.down, out hitInfo,
((m_Capsule.height/2f) - m_Capsule.radius) +
advancedSettings.stickToGroundHelperDistance, Physics.AllLayers, QueryTriggerInteraction.Ignore))
{
if (Mathf.Abs(Vector3.Angle(hitInfo.normal, Vector3.up)) < 85f)
{
m_RigidBody.velocity = Vector3.ProjectOnPlane(m_RigidBody.velocity, hitInfo.normal);
}
}
}
private Vector2 GetInput()
{
Vector2 input = new Vector2
{
x = CrossPlatformInputManager.GetAxis("Horizontal"),
y = CrossPlatformInputManager.GetAxis("Vertical")
};
movementSettings.UpdateDesiredTargetSpeed(input);
return input;
}
private void RotateView()
{
//avoids the mouse looking if the game is effectively paused
if (Mathf.Abs(Time.timeScale) < float.Epsilon) return;
// get the rotation before it's changed
float oldYRotation = transform.eulerAngles.y;
mouseLook.LookRotation (transform, cam.transform);
if (m_IsGrounded || advancedSettings.airControl)
{
// Rotate the rigidbody velocity to match the new direction that the character is looking
Quaternion velRotation = Quaternion.AngleAxis(transform.eulerAngles.y - oldYRotation, Vector3.up);
m_RigidBody.velocity = velRotation*m_RigidBody.velocity;
}
}
/// sphere cast down just beyond the bottom of the capsule to see if the capsule is colliding round the bottom
private void GroundCheck()
{
m_PreviouslyGrounded = m_IsGrounded;
RaycastHit hitInfo;
if (Physics.SphereCast(transform.position, m_Capsule.radius * (1.0f - advancedSettings.shellOffset), Vector3.down, out hitInfo,
((m_Capsule.height/2f) - m_Capsule.radius) + advancedSettings.groundCheckDistance, Physics.AllLayers, QueryTriggerInteraction.Ignore))
{
m_IsGrounded = true;
CurrentlyGrounded = true;
m_GroundContactNormal = hitInfo.normal;
}
else
{
m_IsGrounded = false;
CurrentlyGrounded = false;
m_GroundContactNormal = Vector3.up;
}
if (!m_PreviouslyGrounded && m_IsGrounded && m_Jumping)
{
m_Jumping = false;
}
}
}
}
What should be happening is that it's seen and changes as expected.
Instead, it's reported as nonexisting in the current context.
Don't listen to people who want to make everything static just to access stuff "more easily".
This actually might cause a lot of trouble as soon as you have more than exactly one instances of that class (e.g. if there are two players, or an AI uses the same component).
Another bad side effect is that you won't be able anymore to configure it via the Inspector e.g. for debugging or to give it the desired start value.
What you want to use instead is
moventSettings.CurrentlyGrounded
to access the value of your MovementSettings instance.
Just the same way you did it e.g. in
movementSettings.Running
You can assign it to a global variable.
public static class Globals
{
public static String value = "Sample Value"; // Modifiable
public static readonly String CODE_PREFIX = "TEST-"; // Unmodifiable
}
You can then retrieve the defined values anywhere in your code
String code = Globals.CODE_PREFIX + value.ToString();
The question says it all, I have a Coroutine that I am using to create some spinning animation. The problem is that it suddenly stops randomly (at different times). I don't know what might be causing this as it works most of the times (8 times out of 10) on PC. I also built the game and tried it on an android phone but it only works (3 times out of 10). Any idea what might be causing this?
This is my Script:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class SpinWheelScript : MonoBehaviour {
public CanvasGroup spinWheelCanvas;
public GameObject[] rewards;
public GameObject[] pointerDir;
public GameObject[] ringDir;
public GameObject pointer;
public GameObject ring;
private Quaternion pointerTargetRotation;
private Quaternion ringTargetRotation;
private bool spinIsEnabled = false;
private bool isSpinning = false;
private bool lastSpin = false;
private bool animationIsEnabled = false;
private float time;
private float pSpeed;
private float rSpeed;
private float pointerRotateFloat;
private float ringRotateFloat;
private int rewardEnabler = 0;
private int randomReward;
private int pRandomDir;
private int rRandomDir;
private int plastRandomDir = 0;
private int rlastRandomDir = 0;
private void Update()
{
if (spinIsEnabled == false)
{
// Do Nothing
}
else if (spinIsEnabled == true && isSpinning == false)
{
// Select reward
if (rewardEnabler == 0)
{
RewardSelector();
rewardEnabler = 1;
}
StartCoroutine(Spin());
}
if (lastSpin == true)
{
Debug.Log(randomReward);
pointerRotateFloat = ((360 - (randomReward * 60)) - 30);
ringRotateFloat = ((360 - (randomReward * 60)) - 30);
if (pointerRotateFloat > ringRotateFloat)
{
pSpeed = (pointerRotateFloat);
rSpeed = (pointerRotateFloat / ringRotateFloat) * (ringRotateFloat);
}
else
{
rSpeed = (ringRotateFloat);
pSpeed = (ringRotateFloat / pointerRotateFloat) * (pointerRotateFloat);
}
Quaternion pointerTargetRotation = Quaternion.Euler(new Vector3(0, 0, pointerRotateFloat));
pointer.transform.rotation = Quaternion.RotateTowards(pointer.transform.rotation, pointerTargetRotation, pSpeed * Time.deltaTime);
Quaternion ringTargetRotation = Quaternion.Euler(new Vector3(0, 0, ringRotateFloat));
ring.transform.rotation = Quaternion.RotateTowards(ring.transform.rotation, ringTargetRotation, rSpeed * Time.deltaTime);
if ((pointer.transform.rotation == pointerTargetRotation) && (ring.transform.rotation == ringTargetRotation))
{
lastSpin = false;
isSpinning = false;
spinIsEnabled = false;
animationIsEnabled = true;
}
}
}
IEnumerator Spin()
{
isSpinning = true;
pSpeed = 0;
rSpeed = 0;
time = 0;
while (time < 15)
{
pRandomDir = PointerRandomDirection(); // Function to pick a random number.
rRandomDir = RingRandomDirection(); // Function to pick a random number.
for (;;)
{
pointerRotateFloat = (((pRandomDir + 1) * 60) - 30) - pointer.transform.rotation.z;
ringRotateFloat = (((rRandomDir + 1) * 60) - 30) - ring.transform.rotation.z;
if (pointerRotateFloat > ringRotateFloat)
{
pSpeed = (pointerRotateFloat);
rSpeed = (pointerRotateFloat / ringRotateFloat) * (ringRotateFloat);
}
else
{
rSpeed = (ringRotateFloat);
pSpeed = (ringRotateFloat / pointerRotateFloat) * (pointerRotateFloat);
}
pointerTargetRotation = Quaternion.Euler(new Vector3(0, 0, pointerRotateFloat));
pointer.transform.rotation = Quaternion.RotateTowards(pointer.transform.rotation, pointerTargetRotation, pSpeed * Time.deltaTime);
ringTargetRotation = Quaternion.Euler(new Vector3(0, 0, ringRotateFloat));
ring.transform.rotation = Quaternion.RotateTowards(ring.transform.rotation, ringTargetRotation, rSpeed * Time.deltaTime);
Debug.Log("Before the if");
if ((pointer.transform.rotation == pointerTargetRotation) && (ring.transform.rotation == ringTargetRotation))
break;
yield return null;
}
time++;
}
lastSpin = true;
}
private int RewardSelector()
{
randomReward = Random.Range(0, rewards.Length);
return randomReward;
}
private int PointerRandomDirection()
{
int pRandomDir = plastRandomDir;
if (pointerDir.Length <= 1)
return 0;
while (pRandomDir == plastRandomDir)
{
pRandomDir = Random.Range(0, pointerDir.Length);
}
plastRandomDir = pRandomDir;
return pRandomDir;
}
private int RingRandomDirection()
{
int rRandomDir = rlastRandomDir;
if (ringDir.Length <= 1)
return 0;
while (rRandomDir == rlastRandomDir)
{
rRandomDir = Random.Range(0, ringDir.Length);
}
rlastRandomDir = rRandomDir;
return rRandomDir;
}
public void OnSpinButtonClick()
{
if(spinIsEnabled == false && isSpinning == false)
spinIsEnabled = true;
spinWheelCanvas.interactable = false;
}
}
Thanks in advance.
If you don't find the answer using your existing solution, here is an alternative solution you might appreciate, which arguably is more simple.
A simpler way to achieve the spinning effect and stopping at random angles:
Make 2 animations (In the Animation/Animator windows), a 0-180 degree animation and a 180-360 degree animation, then have them transition between each other.
Making just one 0-360 animation will most likely look buggy, hence I advise to make it in 2 parts.
You can then decide the speed of this animation by adjusting the animation speed and Animator parameters (which control what animations are playing) through code.
To have the spinning wheel stop at random angles you could have a float value in the animator called "Speed", the higher the speed the longer time it takes to stop the animation, hence random stopping angles are achieved.
When the speed hits 0, set the animation speed to 0 as well, that should stop the animation at the designated angle.
Feel free to ask questions if you don't understand what I mean.