How can I implement a 1st person camera view? - c#

I'm following this tutorial right now: https://unity3d.com/learn/tutorials/projects/roll-ball-tutorial/moving-camera?playlist=17141
I've managed to implement a 3rd person camera view button, but I'm having trouble figuring out how to do the same for a 1st person camera view. Below is a camera control script that I attached to the main camera:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class cameraControls : MonoBehaviour
{
public GameObject player;
private Vector3 offset;
public bool thirdPerson;
public bool firstPerson;
void OnGUI()
{
// 3rd person camera view
if (GUI.Button(new Rect(20, 50, 140, 40), "3rd Person Camera"))
{
thirdPerson = true;
}
// 1st person camera view
if (GUI.Button(new Rect(20, 110, 140, 40), "1st Person Camera"))
{
firstPerson = false;
}
}
// Start is called before the first frame update
void Start()
{
offset = transform.position - player.transform.position;
}
// Update is called once per frame
void Update()
{
if (thirdPerson == true)
{
transform.position = player.transform.position + offset;
}
}
}

Well, while it might be okay for such a small tutorial:
you should not use the GUI and OnGUI stuff for ingame UI. unity released in version 4.6 (years ago) a better UI system.
you could have 2 cameras, one for 3rd person one for 1st person. when pressing one of your buttons, you disable one camera and enable the other.
based on your edit:
you currently have 2 bool variables there, one for "firstPerson" one for "thirdPerson", thats redundant.
what do you do if both are true? or both are false? just have one variable e.g. "thirdPerson" true -> use 3rd person, false -> use 1st person.
also i see that you have decided to change the cameras position instead of using 2 cameras. this is also is a possible way to accomplish your goal

You can use a single camera and change its position based on which viewing angle should be active. Try to attatch two empty objects as children to your player object and add a reference to them in your script (your camera also needs to be a child of your player for this to work). Then drag & drop them from the hierarchy to the inspector and just switch between those positions like so:
public Transform firstPersonPosition;
public Transform thirdPersonPosition;
public Camera camera;
private void GoFirstPerson()
{
camera.transform.position = firstPersonPosition.position;
}
private void GoThirdPerson()
{
camera.transform.position = thirdPersonPosition.position;
}
You can basically use them as "waypoints" for your camera to jump to.
//Edit:
If you are having problems with understanding how your code affects your GameObjects during Play Mode just switch to Scene View during play and look at your objects and where they are in the scene. I bet your first person camera is somewhere in your player model because you set its position to your players position.

Related

Unity, how find my game object and move it

I'm totally newbie with Unity and C# and i try to do a 3D game.
I want to when i press "Qkey", the cube descends in height.
here is my code
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class ripcube : MonoBehaviour
{
// Start is called before the first frame update
bool isTeleported = false;
// Update is called once per frame
void Update()
{
if (Input.GetKey("a") && !isTeleported)
{
ripcube.transform.position = (-2, -2, -2) ;
}
}
}
And it gives me the error:
(19,13): error CS0120: An object reference is required for the non-static field, method, or property 'Component.transform'
I know than ripcube is my class, but what is my gameobject? i created my cube on the graphics interface..
Thanks for your help
You should go watch some basic videos on youtube on how unity gameobjects work but for now:
You can reference game objects from your code or find them as following:
public class ripcube: MonoBehaviour
{
GameObject myCubeObject;
float speed = 2f;
void Start()
{
myCubeObject = GameObject.Find("YourCubeNameInUnity");
}
void Update()
{
if(Input.GetKey(KeyCode.Q))
{
myCubeObject.transform.Translate(speed * Vector3.down * Time.deltaTime);
}
}
}
Thing you should notice here :
The GameObject is a Unity class that is the base for all the game objects in the scene,
you can find it by its name in the Hierarchy view.
After you find it you can access it in the Update() function and change its transform every frame.
Here I used Translate wich is an addition to the position every frame
you can also use myCubeObject.transform.position += speed * Vector3.down * Time.deltaTime
Be aware that im using a float speed variable that is the speed the cube will go in the desired direction (I used 2 for the value but it can be anything really).
The direction is specified by a vector (Vector3.down). You can change is as you please
Multiplying by Time.deltaTime makes the movement independant on FPS (Frames per second) wich is determined normally bt the machine the game is running on.
bro you can use
transform.position = new Vector3(-2, -2, -2);
instead of
transform.position = (-2, -2, -2) ;
and change
Input.GetKey("a")
to
Input.GetKey(KeyCode.Q)

Fading UI text from object Checksphere and interact

I'm trying to come up with a generic rule that I can add to any GameObject. Items like tables, chairs etc that once collided and interacted fade in the white text, then after a few seconds the text fades out.
Ideally I'd be able to offset the position of this text with a Vector3 so I can position it around my character
At the moment I have, some code but the CrossFade.Alpha doesn't seem to work. this might or might not be the best way to go about this, I'm open to new ideas
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class Qwerty : MonoBehaviour
{
public float Radius = 1f;
public Text TextToUse;
[SerializeField] private LayerMask playerMask;
private bool isInSphere;
// Start is called before the first frame update
void Start()
{
isInSphere = false;
}
// Update is called once per frame
void Update()
{
isInSphere = Physics.CheckSphere(transform.position, Radius, playerMask);
if (isInSphere && Input.GetKey(KeyCode.F) == true)
{
// Check if collision is detected and F is pressed
isInSphere = true;
Debug.Log("Hello");
//Fade in over 2 seconds
TextToUse.CrossFadeAlpha(1, 2f, false);
}
else if (!isInSphere && !Input.GetKey(KeyCode.F))
{
//Fade out on leave over 2 seconds
isInSphere = false;
TextToUse.CrossFadeAlpha(0, 2f, false);
}
}
}
Description
Tweens the alpha of the CanvasRenderer color associated with this Graphic.
Creates a fading effect on a Graphic with a CanvasRenderer attached. Choose an alpha level to fade to, and pick the speed of the fade to see a smooth fade over time. UI Images and Text are some of the elements that you are able to apply this effect to.
CrossFade.Alpha needs a canvas that has CanvasRenderer attached to work.

Function WorldToScreenPoint() not working as expected

I need little help with function WorldToScreenPoint(position), Could somebody guide me little bit ? I am using this function to display name of the city:
public class LabelsTest : MonoBehaviour
{
[SerializeField]
private Text nameLabel;
// Update is called once per frame
void Update()
{
Vector3 cameraPos = Camera.main.WorldToScreenPoint(transform.position);
nameLabel.transform.position = cameraPos;
}
}
But problem is that I see UI with text two times, one above the plane which is perfect:
but when I face away from the plane, I can see the label there, too.:
I don't know if I am doing something wrong or it just not working as it should.
Thanks for help.
You need to prevent the Text from rendering while it is behind the camera. Luckily, WorldToScreenPoint gives you a z component that tells you how far in front of the camera the point is. So, just set the Text to be enabled when z>0 and disabled when z<=0:
public class LabelsTest : MonoBehaviour
{
[SerializeField]
private Text nameLabel;
// Update is called once per frame
void Update()
{
Vector3 cameraPos = Camera.main.WorldToScreenPoint(transform.position);
nameLabel.transform.position = cameraPos;
nameLabel.enabled = cameraPos.z>0;
}
}
That's because your 'Plane' is culling the backface, meaning when the Plane is up at a certain point higher than the Camera's Y position it goes invisible.
Here's a GIF of the problem.
https://gyazo.com/d22c51951d1e8abd07a354af7f48ffef

VR Adding Locomotion: Walk

Using Unity2017.3.1f1 Personal (64 bit) to build a VR app for Android, using Cardboard VR SDK. The purpose of the app is to allow users visualize data in an immersive way.
Currently want to do something similar to the scene view where one can move forward by going where one's looking but with the Cardboard single button i'm just gonna give the ability to move forward.
Built a Canvas where user can select what type of locomotion he/she wants: teleport or walk.
The teleport works fine as you can see here.
When the user selects walk, the following error shows in the Console:
NullReferenceException: Object
reference not set to an instance of an
object
Player.TryWalk () (atAssets/Player.cs:44)
Player.Update () (at Assets/Player.cs:37)
My Player script:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public enum InputMode
{
NONE,
TELEPORT,
WALK
}
public class Player : MonoBehaviour {
public static Player instance; //Singleton design pattern: only one instance of the class appears
public InputMode activeMode = InputMode.NONE;
[SerializeField]
private float playerSpeed = 3.0f;
void Awake()
{
if(instance != null)
{
GameObject.Destroy(instance.gameObject);
}
instance = this;
}
// Use this for initialization
void Start () {
}
// Update is called once per frame
void Update ()
{
TryWalk();
}
public void TryWalk()
{
if(Input.GetMouseButton(0) && activeMode == InputMode.WALK)
{
Vector3 forward = Camera.main.transform.forward;
Vector3 newPosition = transform.position + forward * Time.deltaTime * playerSpeed;
transform.position = newPosition;
}
}
}
The Player script was added as component of Player:
When the button Walk is pressed, the Active Mode changes to WALK, as you can see in the next image.
Still, even though this happens, the user is not able to Walk.
What can I do to solve this?
Camera.main; was returning null.
In order to fix it, had to have the camera in my scene tagged MainCamera as you can see in the next image.
See it working here.

Unity3D - unable to respawn an object after it has been destroyed

I am having an issue respawning a prefab after it has been destroyed. I can't seem to get it to respawn back at its original start position after a second of being destroyed. I have created an empty game object and attached the SpawnTargets.cs script to it. I'm not sure of what the best methodology to approach this situation. Another object with a script attached to it does the actual destroy of the prefab. BulletCollisionHandler.cs works fine though. Thanks for any help. Code is below:
SpawnTargets.cs:
using UnityEngine;
using System.Collections;
public class SpawnTargets : MonoBehaviour
{
public GameObject targetCircle;
public GameObject targetSquare;
public GameObject targetStar;
private Vector3 circleSpawnPosition = new Vector3(0.0f, 1.227389f, -7.5f);
private Vector3 squareSpawnPosition = new Vector3(0.0f, 1.027975f, -7.993299f);
private Vector3 starSpawnPosition = new Vector3(0.0f, 1.8f, -7f);
// Use this for initialization
void Start ()
{
}
// Update is called once per frame
void Update ()
{
SpawnTarget ();
}
void SpawnTarget()
{
}
}
BulletCollisionHandler.cs:
using UnityEngine;
using System.Collections;
public class BulletCollisionHandler : MonoBehaviour
{
public GameObject targetCircle;
// Use this for initialization
void Start ()
{
Destroy (gameObject, 2);
}
// Update is called once per frame
void Update ()
{
}
void OnCollisionEnter(Collision other)
{
if(other.gameObject.name == "TargetSquare")
{
other.gameObject.rigidbody.isKinematic = false;
((TargetMovementHorizontal)other.gameObject.GetComponent<TargetMovementHorizontal>()).enabled = false;
Destroy (other.gameObject, 1);
Debug.Log("Hit square");
}
else if(other.gameObject.name == "TargetCircle")
{
other.gameObject.rigidbody.isKinematic = false;
((TargetMovementHorizontal)other.gameObject.GetComponent<TargetMovementHorizontal>()).enabled = false;
Destroy (other.gameObject, 1);
Debug.Log("Hit circle");
}
else if(other.gameObject.name == "TargetStar")
{
other.gameObject.rigidbody.isKinematic = false;
((TargetMovementHorizontal)other.gameObject.GetComponent<TargetMovementHorizontal>()).enabled = false;
((TargetMovementVertical)other.gameObject.GetComponent<TargetMovementVertical>()).enabled = false;
Destroy (other.gameObject, 1);
Debug.Log("Hit star");
}
}
}
You're not calling Instantiate() anywhere, so it's hard to see where the new object would come from in the code you've supplied.
In any case, it might be better not to use Destroy. If you want to immediately reset the object, why not simply recycle it back to the start position? It's a good idea to avoid instantiating and destroying lots of objects, it's better to hide/disable the ones your don't need and unhide/re-enable them.
Here's a tutorial on the general idea. The tutorial is about groups of objects but the same trick would work for recycling single objects too.
You are better of using gameObject.SetActive( true/false ); for activating / deactivating the gameObject instead of just using Destroy.
Then if you are using Destroy you have 3 options that comes to mind for getting it into the desire position before the Player sees it.
1) You enable the game object after disabling its Renderer component. Then you equalize the transform's position / rotation the one you need. After this you re-enable the Renderer component. It should be placed where you want it.
2) You Instantiate the gameObject, but first making sure the Renderer component is disabled on its Prefab, by default, so you can re-assign its Transform values then - re-enable the Renderer again.
3) You make an invisible gameObject (an Empty gameObject) and Instantiate the wanted gameObject, you then make the Empty to be the parent of the newly created gameObject.. Provided that the parent Empty is exactly where you want it to be, when you instantiate and reset the child's position it should jump off right on top the the Empty parent.
I'm not giving code since you haven't and I don't have no idea of which method you might end up liking more. In terms of performance the Enable/Disable are the best option.
And as theodox says Object Pooling is your best friend for things like bullets, although it might be applied to many other gameObjects that might work as 'collections of objects' on your game's logic. It's totally worth learning.

Categories

Resources