This should be an easy task, and I have googled it, but I can't figure out why any of the examples are working for me.
Basically, I want to place tiles on the ground in my first person game. I want the object I want to place on the ground to "float" in mid-air while choosing the perfect location for it. I can instantiate the object, make it a child of the player camera, but I'm unable to position it X units in front of the camera; it always ends up "on" the player;
public void StartPlacing ( Item item ) {
Object itemPrefab = Resources.Load( "Prefabs/" + item.prefabName );
GameObject itemObject = (GameObject)Instantiate( itemPrefab );
itemObject.transform.parent = playerCamera.transform;
// What to do here to place it in front of the camera? I've tried this:
itemObject.localPosition = new Vector3( 0, 0, 5 );
}
UPDATE: The camera is a child of the player (Character Controller), and the camera is in perspective mode.
You could use the forward vector of the object, something like this:
public GameObject frontObject;
public float distance;
void Update () {
frontObject.transform.position = Camera.main.transform.position + Camera.main.transform.forward * distance;
}
Thanks for all the useful suggestions, everyone! I came up with the following code which suits my needs:
using UnityEngine;
using System.Collections;
public class ConstructionController : MonoBehaviour {
private Camera playerCamera;
private GameObject itemObject;
private float distance = 3.0f;
// Use this for initialization
void Start () {
playerCamera = GetComponentInChildren<Camera>();
}
// Update is called once per frame
void Update () {
if ( itemObject != null ) {
itemObject.transform.position = playerCamera.transform.position + playerCamera.transform.forward * distance;
itemObject.transform.rotation = new Quaternion( 0.0f, playerCamera.transform.rotation.y, 0.0f, playerCamera.transform.rotation.w );
}
}
// Start constructing an item
public void StartConstructingItem ( Item item ) {
Object itemPrefab = Resources.Load( "Prefabs/" + item.prefabName );
itemObject = (GameObject)Instantiate( itemPrefab );
}
}
Related
I am trying to implement a way for the player to switch between a square and a circle. For this to work my player object has two colliders, one circle and one box. When switching between them I simply disable one collider and enable the other, and switch the current sprite. The issue arises when I switch from a circle to a square.
I want the square to be able to glide across the floor, whereas the circle is supposed to roll. In order to make the switch seamless I have to reorient the square to be aligned with the current velocity, and remove the angular velocity. This does seem to work, however there is a slight period of frames (or frame) where the square has the same rotation the circle had before switching. This seems odd to me since the new rotation and sprite is changed in the same part of the code. This is a video showcasing the issue.
If this is an issue resulting from the way the objects are rendered I can solve this another way. I would just like to understand why it happens.
Code snippet of the part that changes the properties from circle to square when switching:
else if (Input.GetKeyDown("2"))
{
// Update rotation of box to velocity:
float newAngleRadians = Mathf.Atan2(rb.velocity.y, rb.velocity.x);
float newAngleDegrees = newAngleRadians * 180 / Mathf.PI;
rb.rotation = newAngleDegrees;
rb.angularVelocity = 0;
Debug.Log(rb.rotation);
playerShape = Shape.SQUARE;
spriteRenderer.sprite = spriteArray[1];
circleCollider.enabled = false;
boxCollider.enabled = true;
updateShape = true;
}
Logging the angle of the rigidbody directly after setting it to newAngleDegrees shows that the rotation has been set correct, yet the issue persists.
And just in case it is needed, full code of the script:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class scr_StateMachine : MonoBehaviour
{
// Types of shapes:
public enum Shape { SQUARE, CIRCLE, TRIANGLE }
// Variables:
public Rigidbody2D rb;
public SpriteRenderer spriteRenderer;
public Sprite[] spriteArray;
public Shape playerShape;
public CircleCollider2D circleCollider;
public BoxCollider2D boxCollider;
private bool updateShape;
void Start()
{
playerShape = Shape.CIRCLE;
updateShape = true;
}
void Update()
{
// Get input for shape change:
if(Input.GetKeyDown("1"))
{
playerShape = Shape.CIRCLE;
spriteRenderer.sprite = spriteArray[0];
circleCollider.enabled = true;
boxCollider.enabled = false;
updateShape = true;
}
else if (Input.GetKeyDown("2"))
{
// Update rotation of box to velocity:
float newAngleRadians = Mathf.Atan2(rb.velocity.y, rb.velocity.x);
float newAngleDegrees = newAngleRadians * 180 / Mathf.PI;
rb.rotation = newAngleDegrees;
rb.angularVelocity = 0;
Debug.Log(rb.rotation);
playerShape = Shape.SQUARE;
spriteRenderer.sprite = spriteArray[1];
circleCollider.enabled = false;
boxCollider.enabled = true;
updateShape = true;
}
// Update movement script's shape:
if (updateShape)
{
GetComponent<scr_Movement>().shape = playerShape;
updateShape = false;
}
}
}
I think the issue is Rigidbody/Rigidbody2D physics are applied in fixed time steps (see FixedUpdate). Therefore yes, on a strong device it can definitely happen that you render some frames before the next FixedUpdate call kicks in and changes the Rigidbody/Rigidbody2D behavior.
I think what you could do is actually wait with the change for the next FixedUpdate call e.g. using a Coroutine and WaitForFixedUpdate like e.g.
public class scr_StateMachine : MonoBehaviour
{
// Types of shapes:
public enum Shape { SQUARE, CIRCLE, TRIANGLE }
// Variables:
public Rigidbody2D rb;
public SpriteRenderer spriteRenderer;
public Sprite[] spriteArray;
public Shape playerShape;
public CircleCollider2D circleCollider;
public BoxCollider2D boxCollider;
[SerializeField] private scr_Movement _scrMovement;
void Start()
{
if(!_scrMovement) _scrMovement = GetComponent<scr_Movement>();
ChangeShape(Shape.CIRCLE);
}
// Still get User Input in Update
void Update()
{
// Get input for shape change:
if(Input.GetKeyDown("1"))
{
ChangeShape(Shape.CIRCLE);
}
else if (Input.GetKeyDown("2"))
{
ChangeShape(Shape.SQUARE);
}
}
private void ChangeShape(Shape newShape)
{
// if the same shape comes in we already have -> nothing to do
if(newShape == playerShape) return;
// Stop any already running coroutine since we only want to handle the last input before the FixUpdate call
// https://docs.unity3d.com/ScriptReference/MonoBehaviour.StopAllCoroutines.html
StopAllCoroutines();
// Start a new coroutine for the new shape
// see https://docs.unity3d.com/ScriptReference/MonoBehaviour.StartCoroutine.html
StartCoroutine(ChangeShapeInNextFixedUpdate(newShape));
}
private IEnumerator ChangeShapeInNextFixedUpdate(Shape newShape)
{
// just in case again, if the same shape comes in we already have -> nothing to do
if(newShape == playerShape) yield break;
// Wait until the next FixedUpdate call
// see https://docs.unity3d.com/ScriptReference/WaitForFixedUpdate.html
yield return new WaitForFixedUpdate();
// Now do your required changes depending on the new shape
circleCollider.enabled = newShape == Shape.CIRCLE;
boxCollider.enabled = newShape == Shape.SQUARE;
switch(newShape)
{
case Shape.CIRCLE:
spriteRenderer.sprite = spriteArray[0];
break;
case Shape.SQUARE:
// Update rotation of box to velocity:
var newAngleRadians = Mathf.Atan2(rb.velocity.y, rb.velocity.x);
// see https://docs.unity3d.com/ScriptReference/Mathf.Rad2Deg.html
var newAngleDegrees = newAngleRadians * Mathf.Rad2Deg;
rb.rotation = newAngleDegrees;
rb.angularVelocity = 0;
Debug.Log(rb.rotation);
spriteRenderer.sprite = spriteArray[1];
break;
}
playerShape = newShape;
_scrMovement.shape = playerShape;
}
}
I want to assign a number to objects in Unity 3D and the number should appear on the object. Please, I need help on a code to do this. I have little knowledge of C#, but I have been learning aggressively these days. I will appreciate any help. Thanks. Below is a sample code I assign to each of the object.
public class NumberHolder : MonoBehaviour
{
int myNumber = 0;
UnityEngine.UI.Text myTextField;
void Awake()
{
myNumber = UnityEngine.Random.Range(0,100) + 1;
myTextField = GetComponent<UnityEngine.UI.Text>();
}
void Start()
{
if(myTextField != null)
{
myTextField.text = "" + myNumber;
}
}
}
Try the script below. It should contain some tidbits to direct you. A couple things to note: for this script, your object must have a collider (doesn't matter which kind: 2D or 3D). Also, this script displays the object's number only when the mouse is over the object. I could tailor it to always show the object, but I gotta make you work a little. Plus, I think in the long run this will work splendidly for you, as you can dissect it.
I will give you a hint. What's the secret to drawing text at the object's position?
You need to convert the object's world space coordinates, to screen space coordinates and then overlay your text.
Consider the following code blocks.
These methods determine if the mouseposition on screen is over the object:
private void OnMouseEnter()
{
isVis = true;
}
private void OnMouseExit()
{
isVis = false;
}
These lines draw the objects number at the mouse location:
Vector2 mospos = Input.mousePosition;
mospos.y = Screen.height - mospos.y;
if (isVis)
{
GUI.Box(new Rect(Input.mousePosition.x + 2, Screen.height -
Input.mousePosition.y + 2, 128, 72),"" + myNumber);
}
Full class below. Hope it helps!
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class LocalLabelingScript : MonoBehaviour {
Monster beast;
bool isVis = false;
int myNumber;
private void Awake()
{
myNumber = UnityEngine.Random.Range(0,100) + 1;
}
private void OnGUI()
{
Vector2 mospos = Input.mousePosition;
mospos.y = Screen.height - mospos.y;
if (isVis)
{
GUI.Box(new Rect(Input.mousePosition.x + 2, Screen.height -
Input.mousePosition.y + 2, 128, 72),"" + myNumber);
}
private void OnMouseEnter()
{
isVis = true;
}
private void OnMouseExit()
{
isVis = false;
}
}
I'm using the google cardboard SDK and i have a script attached to the child "Head" in the GvrMain prefab. There's also a Character controller connected and the vrCamera variable has been set to the "Head" object to this so that i can move the user based on the code which will follow.
The issue i'm having is that i want to move the character when the user tilts their head at an angle, all this works fine but the issue is that when the simpleMove function is called nothing is happening... I've logged to see if any of the variables upto the point are empty but none of them seem to be; just this function doesn't seem to be getting called. Code below.
public class VRLookWalk : MonoBehaviour {
public Transform vrCamera;
public float toggleAngle = 30.0f;
public float speed = 3.0f;
public bool moveForward;
private CharacterController myCC;
// Use this for initialization
void Start () {
myCC = GetComponent<CharacterController> ();
}
// Update is called once per frame
void Update () {
if (vrCamera.eulerAngles.x >= toggleAngle && vrCamera.eulerAngles.x < 90.0f)
{
moveForward = true;
} else {
moveForward = false;
}
if (moveForward)
{
Vector3 forward = vrCamera.TransformDirection (Vector3.forward);
myCC.SimpleMove (forward * speed);
}
}
}
i want a gameObject to add instanciatetd objects prom a prefab as his chiled.
so i wrote this code:
public class TgtGenerator : MonoBehaviour {
public SpriteRenderer spriteTgt;
public Sprite[] targets;public SpriteRenderer spriteTgt;
// Use this for initialization
void Start () {
}
// Update is called once per frame
void Update () {
generateRandTgt ();
}
void generateRandTgt(){
SpriteRenderer tgt = GameObject.Instantiate (spriteTgt, getRandPosition (), Quaternion.identity)as SpriteRenderer;
tgt.sprite = randSprite ();
}
Sprite randSprite(){
var length = targets.Length-1;
Debug.Log (Random.Range(0,length));
return targets[Random.Range(0,length)];
}
Vector3 getRandPosition(){
float xScale = gameObject.transform.localScale.x / 2;
float yScale = gameObject.transform.localScale.y / 2;
float x = Random.Range(-xScale,xScale);
float y = Random.Range(-yScale,yScale);
float z = 0;
return new Vector3 (x, y, z);
}
the instantiated object is getting his size from the prefab like i wanted to.
but the problem is it instanciated at the root node of the hirarchy so they are not placed inside of the gameobject coordinate like i wanted to.
when i am adding this line of code just after the instaciate line :
tgt.transform.parent = gameObject.transform;
it generated as a child like i wanted to but it gets huge and upside down.
how should i manage this?
Try Using This To Force Child To Have It's Own Scale After Being a Child:
var localScale = child.transform.localScale; // store original localScale value
child.transform.parent = parent;
child.transform.localScale = localScale; // force set
I am new in unity, i need to create a effect when my game is started:
When game is being started, game scene is dark
When game has already been started, game scene is light.
Please teach me how i can do it, Thanks so much.
1st you have to add Light on your scene from GameObject Menu in unity. If you need On Off that light just add the Javascript to your light. Lot of ways to do this Google it and easy to find.
var times : float;
function Start () {
light.intensity =0;
}
function Update () {
times += Time.deltaTime; // just I added time.
if (times > 5) // or Here you can use Press key events....
light.intensity =8;
}
Here's what I use. I create a pixel texture and use the GUI system to ensure it'll be drawn before everything in the scene. I actually use a display manager to control the order GUI elements are drawn to make sure the overlay is in front of other gui elements.
using UnityEngine;
using System.Collections;
public class Overlay : MonoBehaviour {
//----------------------------------------------------------------------------------------------------//
[SerializeField]
private Color screenColor = Color.black;
[SerializeField]
private float fadeSpeed = 0.5f;
//----------------------------------------------------------------------------------------------------//
static private Texture2D overlay;
static private bool fadeOverlay;
static private bool fadeOverlayIn;
//----------------------------------------------------------------------------------------------------//
public void Awake() {
//Setup the values for the fading overlay.
overlay = new Texture2D( 1, 1 );
overlay.SetPixel( 0, 0, screenColor );
overlay.Apply();
fadeOverlay = true;
fadeOverlayIn = false;
}
public void Update() {
if ( fadeOverlay ) {
if ( fadeOverlayIn ) {
screenColor.a += Time.deltaTime * fadeSpeed;
if ( screenColor.a >= 1 ) {
fadeOverlay = false;
}
} else {
screenColor.a -= Time.deltaTime * fadeSpeed;
if ( screenColor.a <= 0 ) {
fadeOverlay = false;
}
}
overlay.SetPixel( 0, 0, screenColor );
overlay.Apply();
}
}
public void OnGUI() {
if ( fadeOverlayIn || fadeOverlay ) {
GUI.DrawTexture( Camera.main.pixelRect, overlay );
}
}
static public void Toggle() {
fadeOverlay = true;
fadeOverlayIn = !fadeOverlayIn;
}
//----------------------------------------------------------------------------------------------------//
}