How to make a open/close door with an action range? - c#

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.

Related

How to convert my Character Controller into Rigibody Movement in Unity?

I'm making a 3D Side-Scroll Platformer Game,
I have trouble with my character when it steps on the moving platform it will not come along on the platform. I want my character to stay on the moving platform so I think converting my Character Controller into Rigibody will help me,
I need help to give me ideas on how I can reuse my Character Controller Script in Rigibody. This is my code, how can I reuse this in Rigibody script?
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerController : MonoBehaviour
{
public CharacterController controller;
private Vector3 direction;
public float speed = 8;
public float jumpForce = 30;
public float gravity = -20;
public Transform groundCheck;
public LayerMask groundLayer;
public bool ableToMakeADoubleJump = true;
public Animator animator;
public Transform model;
void Start()
{
}
// Update is called once per frame
void Update()
{
if (PlayerManager.gameOver)
{
//play death animation
animator.SetTrigger("die");
//disable the script
this.enabled = false;
}
float hInput = Input.GetAxis("Horizontal");
direction.x = hInput * speed;
animator.SetFloat("speed", Mathf.Abs(hInput));
bool isGrounded = Physics.CheckSphere(groundCheck.position, 0.15f, groundLayer);
animator.SetBool("isGrounded", isGrounded);
if (isGrounded)
{
//Jump Codes
ableToMakeADoubleJump = true;
if (Input.GetButtonDown("Jump"))
{
Jump();
}
}
else
{
direction.y += gravity * Time.deltaTime;
if (ableToMakeADoubleJump & Input.GetButtonDown("Jump"))
{
DoubleJump();
}
}
if (hInput != 0)
{
Quaternion newRoattion = Quaternion.LookRotation(new Vector3(hInput, 0, 0));
model.rotation = newRoattion;
}
//Move the player using the character controller
controller.Move(direction * Time.deltaTime);
}
private void DoubleJump()
{
//Double Jump Codes
animator.SetTrigger("doubleJump");
direction.y = jumpForce;
ableToMakeADoubleJump = false;
}
private void Jump()
{
direction.y = jumpForce;
}
}
I would not recommend switching between the two. It would get tricky, and think about it, you are alternating between two very different things. One is movement and one is physics.
However, I would reccomend adding to your current script so that the player would move with the moving platform.
There is a lot of stuff in this answer, so read the whole thing.
Btw, when I talk about velocity, in your case it is direction.
Since it seems like you know how to code pretty well, I won’t write out the script, rather tell you some physics ideas to get you going in the right direction.
The reason people can stand on a moving platform and not fall off is because of friction.
If you are standing on a gameObject with enough friction (you could add a physics material the gameObject you stand on and change friction there. Note that physics materials only work with rigidbodies, but you might want to use it to just read the value)
First of all, you are going to want to raycast down to obtain the object you are standing on. From there you can get the physics material from hit.collider.sharedMaterial (or any other hit. to obtain data about what object you are standing on.
If they friction is too low, just make the character slip off, like it was before (I assume)
If the friction is above a threshold, get the velocity from the object you are standing on. If it was a rigidbody, hit.rigidbody.velocity. If it is controlled by script, use hit.collider.gameObject.GetComponent<scriptname>().velocityvariablename This part is continued later on
This is not necessary but useful: You can think of this as grabbing on a rope. When you are grabbing on a slippery rope, and someone pulls it (Like tug of war), You won’t move because the rope will slide through your hands. If the rope had grip tape on it and someone pulled it, you would come with it because it has more friction. You can think of the platform the same way. Now on to the more complex part: When you grip a rope that is stationary, and someone pulls it, you come with it as its velocity changes. When the rope is already being pulled, so its velocity is not stationary and it is already something. You grab onto it and a similar thing happens. It is like you are becoming a part of that rope. Similar to how if you are running, the arms and legs and head is a part of you. If you lose grip, you are no longer a part of that body, like your arms falling off when running. In other words, you become part of the body when you attach yourself to it.
Bottom line:
Get the velocity of the platform and set platformVel to it, do not add that to velocity, rather do a seperate controller.Move(platformVel).
A small customization:
Vector3.Lerp the platformVel to 0, so it doesn’t change while on the platform, but gradually goes to (0,0,0) when you get off. This way, there is a little momentum maintained from standing on the platform.
Feel free to ask anything in the comments.

How To Add Mobile Touch Controllers In Unity

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 ;)

My Player Movement is presenting some Issues

I'm starting to learn C# with Unity and I guess my code present some issues, the movement of my player works but not that good. Let me explain, I have a player at the bottom of the screen, moving only from left to right by itself, using transform.translate (I didn't used rigidbody) because on collision with the sides it stops, and is not a constant movement, the idea is that, once collides with the sides, it changes of direction, but same velocity.
The issue happens when the player colides with the walls (removed the mesh renderer to keep them transparent) but if at the same time you press the key to trigger also the change of direction the player gets stuck at the corner, as shown on this gif example:
Wait for the Player to get stuck at the corners, the gif takes like 15 secs.
And here's my actual Script for the Player
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PMovement : MonoBehaviour
{
public float playerSpeed = 8.0f;
void Update()
{
float moveX = playerSpeed * Time.deltaTime;
transform.Translate(moveX, 0, 0);
if (Input.GetKeyUp(KeyCode.Space))
{
playerSpeed = playerSpeed * -1;
}
}
void OnCollisionEnter(Collision target)
{
if (target.gameObject.tag.Equals("SideWalls") == true)
{
playerSpeed = playerSpeed * -1;
}
}
}
Your code looks ok for what you want to achieve. Unfortunately, in Unity it may not be enough to pin point the problem, as the code heavily depends on the setting from the editor. One possible solution to this or similar problems:
If you still have blocking colliders, (The collision functions need some sort of rigidbody.), or if you clamp your player's position, to stop overflow, the following can happen:
Collider on right side is hit
Player direction change to left
Space is hit while colliders are still touching
Player direction change to right again
There is no collider on right side left to start the colliderEnter event again.
In this case block your space recognition while the player is touching one side.
If you change direction when you hit the wall, but you press Space at just the right time, you'd end up inside the wall a bit most likely. Then it'd keep thinking it was entering the wall collision and reversing direction over and over. Here's what I'd do.
public class PMovement : MonoBehaviour
{
private List<GameObject> Collisions = new List<GameObject>();
public float playerSpeed = 8.0f;
void Update()
{
float moveX = playerSpeed * Time.deltaTime;
transform.Translate(moveX, 0, 0);
if (Collisions.Count <= 0 && Input.GetKeyUp(KeyCode.Space))
{
playerSpeed = playerSpeed * -1;
}
}
void OnCollisionEnter(Collision target)
{
if (!Collisions.Contains(target.gameObject) && target.gameObject.tag.Equals("SideWalls") == true)
{
Collisions.Add(target.gameObject);
playerSpeed = playerSpeed * -1;
}
}
void OnCollisionExit(Collision target)
{
if (Collisions.Contains(target.gameObject)) {
Collisions.Remove(target.gameObject);
}
}
}
By keeping a list of wall objects you're inside, you can disallow the space bar if you're inside a wall. Keep in mind there's probably better ways to do the things you're doing, but this should fix the issue you're having for now.

Open kitchen cupboard on keypressed with Unity

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!

Scripts not working as they should in C# Unity

Got a few issues with using Unity 2d scripting. I have sprite factory, and currently have 2 scripts. One is for running, one is for attack. Problems I am having are the following:
1) My character runs perfectly fine when moving right. When he runs in the left direction, the idle animation is always set to the right. So when he stops running left, it automatically moves the character back in the right direction when hes finished running
2) I have an attack script. This script works fine when scripted alone i.e. Attack.cs. However, when I activate my walk script aswell, the attack animation drops out completely. Do i need to merge the codes together?
3) Furthermore, I have 3 set of attacks, which I wish to program as the letter A. My character initiates the first attack fine, but as it is 3 sets of attack, the user would need to press the attack 3 times to initiate the 3 attacks. Should the character do 2 attacks, it should reset back to its initial attack.
Any recommendation with how to get profecient in C# would also be beneficial because i suck at Unity coding =(
My Code (Attack):
using UnityEngine;
using System.Collections;
using FactorySprite = SpriteFactory.Sprite;
public class Attack : MonoBehaviour {
// you forgot to set name of variable representing your sprite
private FactorySprite sprite;
// Use this for initialization
void Start () {
sprite = GetComponent<FactorySprite> (); // Edited
}
void Update ()
{
if(Input.GetKeyDown(KeyCode.A))
{
sprite.Play("Attack");
Vector3 pos = transform.position;
pos.x += Time.deltaTime * 1;
transform.position = pos;
}
}
}
My Code (Run)
using UnityEngine;
using System.Collections;
using FactorySprite = SpriteFactory.Sprite;
public class Walk : MonoBehaviour {
// you forgot to set name of variable representing your sprite
private FactorySprite sprite;
// Use this for initialization
void Start () {
sprite = GetComponent<FactorySprite> (); // Edited
}
// Update is called once per frame
void Update () {
if (Input.GetKey (KeyCode.RightArrow)) {
sprite.Play ("Walk"); // heh, remember C# is case sensitive :)
Vector3 pos = transform.position;
pos.x += Time.deltaTime * 6;
transform.position = pos;
} else if (Input.GetKey (KeyCode.LeftArrow)) {
sprite.Play ("Walk0"); // heh, remember C# is case sensitive :)
Vector3 pos = transform.position;
pos.x += Time.deltaTime * -6;
transform.position = pos;
} else {
sprite.Stop ();
}
}
}
I think that you should consider using state machine to manage your character position. In fact, it is a classic example of state machine usefulness. The book "Game Programming Patterns" has a great chapter about it; in fact, the very example that is used there is very close to the code that you're working on.
In the update function of the walk script you call sprite.stop() wich will stop the attack animation.
You could check if the active animation is Walk or Walk0 to not stop other animations.
http://docs.unity3d.com/Documentation/ScriptReference/Animation.IsPlaying.html
Solution could be something like this (untested):
Animation anim = gameObject.GetComponent<Animation>();
if (anim.IsPlaying("Walk") || anim.IsPlaying("Walk0")) {
sprite.Stop();
}
Or rather since you are using "Sprite Factory" as far as I can see from your code:
if (sprite.IsAnimationPlaying(1) || sprite.IsAnimationPlaying(2)) {
sprite.Stop();
}
Assuming in this case that the animationIndex for "Walk" is 1 and "Walk0" is 2.
You can read more about IsAnimationPlaying here: http://www.guavaman.com/projects/spritefactory/docs/pages/classes/Sprite-IsAnimationPlaying.html

Categories

Resources