I have recently downloaded a cabinet kitchen → https://www.cgtrader.com/3d-models/interior/kitchen/ca-5cd9388f-0be1-4cea-ab44-bc1b493f590f
So everything basically works fine, however, I've added a player controller and I want for each cupboard, that the player press E to open it. I'm having some serious difficulties with that though since every cupboard opens instead of only one and I don't know how to focus on only one at the time, maybe adding a box collider for when the player is close to a cupboard?
Plus, I've found two different types of keypressing :
→ Input.GetKeyDown(KeyCode.E) = which slightly opens every cupboard but not entirely
→ Input.GetKey("e") = which fully opens every cupboard but you have to keep pressing E and this is not what I want.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Door : MonoBehaviour {
public bool isopen;
public float speed;
[SerializeField]
float Open,Close;
private void Awake()
{
}
void Start () {
}
// Update is called once per frame
void Update () {
if (Input.GetKey("e"))
{
isopen = true;
Quaternion open = Quaternion.Euler(Open, 90, 90);
transform.localRotation = Quaternion.Slerp(transform.localRotation, open, Time.deltaTime * speed);
}
else
{
isopen = false;
Quaternion close = Quaternion.Euler(Close, 90, 90);
transform.localRotation = Quaternion.Slerp(transform.localRotation, close, Time.deltaTime * speed);
}
}
void PlayAnim()
{
print("hit");
if (isopen)
{
isopen = false;
}
else
{
isopen = true;
}
}
}
Here is my 'HIT' script :
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class hit : MonoBehaviour
{
// Use this for initialization
void Start()
{
}
// Update is called once per frame
void Update()
{
if (Input.GetKeyDown(KeyCode.E))
{
RaycastHit hit;
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
if (Physics.Raycast(ray, out hit, 100.0f))
{
hit.transform.SendMessage("PlayAnim");
}
}
}
}
However, the script works only for my drawers but not for my cupboard which are all slightly opened when E is pressed.
But when the player looks at a drawer, they press E and only the drawer they focused opens, same steps for closing it.
I've added the HIT script to my cupboards though...
So, I would like to be able to open a single cupboard when needed, and press E again to close it.
How am I supposed to do? Any directions?
Thank you very much guys.
This problem would best be solved by breaking it into parts: Selecting a cupboard with a key, making it open/close and running the animation.
If you are using a first person view, you could check which cupboard the player is looking at by casting a ray using Physics.Raycast() from the position of the camera at the direction it is looking at. If the resulting RaycastHit collided with a cupboard, this one will need to open. By the way, GetKeyDown() fires once on a single Update() when the key is pressed, GetKey() fires as long as the key is held. You want to only fire once and keep the animation running by itself from then, so use GetKeyDown(). You would probably not want to use a box collider for that, as the player could open a cabinet behind him, just by rubbing his back against it and pressing "e".
Then, in a different script attached to the cupboards, you have to have a function to open/close them. As soon as it is called, you check whether it is currently moving, and if not, start the animation.
The animation will need to rotate the door on every frame in Update() until it reached the target position. By saving how far it moved already and whether it is closing or opening in variables, this should be rather easy to achieve because you already managed to make them rotate in the right way.
It finally works! I have added the hit script and Physics.RayCast and edited the Door script. Now I have to figure out how to add the text canvas and makes it disappear when needed.
Thank you anyways!
Related
So I've got a script attached to a trigger below a double door which open upon the character entering the trigger and closing when the character leaves the trigger. With my first iteration of the code, the animations would reset upon me leaving the trigger before the opening animation was finished. I attempted modifying the code so that the opening animation would finish before the closing animation started when I left the trigger. This left me with the following code.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class TriggerDoorController : MonoBehaviour
{
[SerializeField] private Animator Door1;
[SerializeField] private Animator Door2;
private void OnTriggerEnter(Collider other) {
if (other.CompareTag("Player")){
if (!Door1.GetCurrentAnimatorStateInfo(0).IsName("DoorSlideOpen") && !Door1.GetCurrentAnimatorStateInfo(0).IsName("DoorSlideClose")) {
Door1.Play("DoorSlideOpen", 0, 0.0f);
Door2.Play("DoorSlideOpen2", 0, 0.0f);
}
}
}
private void OnTriggerExit(Collider other) {
if (other.CompareTag("Player")){
if (!Door1.GetCurrentAnimatorStateInfo(0).IsName("DoorSlideOpen") && !Door1.GetCurrentAnimatorStateInfo(0).IsName("DoorSlideClose")) {
Door1.Play("DoorSlideClose", 0, 0.0f);
Door2.Play("DoorSlideClose2", 0, 0.0f);
}
}
}
}
Now the door only opens when I enter the trigger, but doesn't close when I leave it. I tried searching online but can't really find much. Honestly, I don't really understand why it doesn't work. Could someone guide as to why it doesn't and to on how I could fix this? I'm also open to any other method if there's an easier one. Thanks.
I am working on a game, and till now, i have allowed a user to play the game by moving up and down using the up and down arrow keys on the computer keyboard.
But now i want to make the user be able to do that on a mobile phone by touching up or down, or maybe swiping up or down to move in the game.
I am using c# for this.
This is the current code assigned to the player object:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Player : MonoBehaviour
{
public float playerSpeed;
private Rigidbody2D rb;
private Vector2 playerDirection;
// Start is called before the first frame update
void Start()
{
rb = GetComponent<Rigidbody2D>();
}
// Update is called once per frame
void Update()
{
float directionY = Input.GetAxisRaw("Vertical");
playerDirection = new Vector2(0, directionY).normalized;
}
void FixedUpdate()
{
rb.velocity = new Vector2(0, playerDirection.y * playerSpeed);
}
}
What do i need to do to achieve this?
You should try to make buttons with trasparency
You have plenty of possibilities here !
But there might have better solutions than others ;)
You could make a UI representing up and down arrow that respond with wathever behaviour you'd like when pressed ORyou could dig a little the Input documentation, espacially what's relative to touches.
From there you can get touch position in screen space an make whatever you want with it !
The choice is lead by the type of game or application you're trying to make. Hope that helped ;)
I want to make a door which opens and closes by pressing a button ( "O" for open and "C" for close). Tried with this:
using System.Collections;
using UnityEngine;
public class DoorScript : MonoBehaviour {
public float speed;
public float angle;
public Vector3 direction;
// use this for initializaton
void start() {
angle = transform.eulerAngles.y;
}
// Update is called once per frame
void Update() {
if (Mathf.Round(transform.eulerAngles.y) != angle) {
//rotate our door
transform.Rotate(direction * speed);
}
if (Input.GetKeyDown(KeyCode.O)) {
angle = 90;
direction = Vector3.up;
}
if (Input.GetKeyDown(KeyCode.C)) {
angle = 0;
direction = -Vector3.up;
}
}
}
But it did not works how I want. I mean: You can be far away, if you press "O" the door will open anyway. How can I implement an action range? I mean, you will need to be a little bit closer to the door interact with it?
I also need to say that in the game will me aprox. 40 doors. I need for each other a custom script?
The code is in C#. I have a little bit of coding experience, but i can´t solve this.
Thanks
One way to do this is to use Colliders, RigidBodies and OnTrigger calls. Here is a manual page that outlines the usage.
https://docs.unity3d.com/ScriptReference/Collider.OnTriggerEnter.html
For your implementation, the door would have the Example script (call it something other than "Example") and the player would be the sphere (although you would create the player outside of this script). When the player is near a door, the door will know it by keeping track of the presence of the player through the OnTrigger calls. Then, when the key is pressed, the door will react if the user is nearby. Every door would have a script like this.
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.
I am looking for a code or script in C# or Java to make my cube tagged as a Player jump, in below script.
I have written some code and attached it to a button on canvas, but the problem is when I press and hold the button, it keeps jumping and makes an infinitly high jump.
Here is my script written in C#
using UnityEngine;
using System.Collections;
using UnityEngine.UI;
public class DownstateButton : Button
{
public void Update()
{
//A public function in the selectable class which button inherits from.
if(IsPressed())
{
WhilePressed();
}
}
public void WhilePressed()
{
var player =GameObject.FindWithTag("Player");
player.transform.Translate(0, 1, 0);
//It was for jump
}
}
Hook the PointerDown (called when the button is pressed down) and PointerUp (button has been let go again) events from the UIButton and weight the translation of the position with Time.deltaTime, and you should be good to go. (player.transform.Translate(0,1 * Time.deltaTime, 0), optionally multiply it with another factor for speed modulation.) References: http://unity3d.com/learn/tutorials/modules/beginner/ui/ui-events-and-event-triggers
EDIT: Yeah, some example code. First, I have an EventTrigger component on the button. I use this sothat I can hook the PointerDown and PointerUp events as described before. It looks like this in the inspector:
(Use the "Add New Event Type" button to redirect the event calls.)
Then, I have this script on the button. The code speaks for itself.
using UnityEngine;
using UnityEngine.EventSystems;
public class JumpButton : MonoBehaviour {
private bool shouldJump = false;
// Update is called once per frame
void Update () {
//Find the player
var player = GameObject.FindGameObjectWithTag("Player");
//No player? exit out.
if (player == null)
return;
//Is the jump button currently being pressed?
if (shouldJump)
{
//Translate it upwards with time.
player.transform.Translate(new Vector3(0, Time.deltaTime * 5, 0));
//Make sure the Rigidbody is kinematic, or gravity will pull us down again
if (player.GetComponent<Rigidbody>().isKinematic == false)
player.GetComponent<Rigidbody>().isKinematic = true;
}
//Not jumping anymore? reset the Rigidbody.
else
player.GetComponent<Rigidbody>().isKinematic = false;
}
//When the button is being pressed down, this function is called.
public void ButtonPressedDown(BaseEventData e)
{
shouldJump = true;
}
//When the button is released again, this function is called.
public void ButtonPressedUp(BaseEventData e)
{
shouldJump = false;
}
}
The thing with switching to a kinematic rigidbody is optional, though. Also the speed can be adjusted with the multiplicative constant in the Translate() call. I tested this code with a standard cube, that has the Player tag and a Rigidbody on it, and it works fine.
Happy coding.
You could use a unity coroutine.
At the start of the routine, you'd set (for example) "isJumping" (a bool), and then before you start your loop bit, you'd check if you are jumping by checking 'isJumping'.
If not "isJumping", set isJumping to true, do your jump, and then on the completion of the routine, set isJumping to false.
//untested (uncompiled) code written on the fly
bool isJumping = false;
IEnumerator doJump()
{
if (!isJumping) {
isJumping = true;
// do jump (probably a loop)
while (jumpCondition) {
// jump instructions
yield return
}
//unset isJumping, inside 'if' but after yield return
isJumping = false
}
}
Note : code after yield return in a coroutine will only (probably) be run once, and only run as the coroutine exists (because no more yielding means the coroutine is at an end)