I tryed to make an elevator and i came around something that i could not explain.
So here is the scenario:
Once i put my object(in this case a cube) on the elevator it will go up and down.
If the object sits out the ride without moving and waits for the next ride, the colliding will stop when the elevator comes back through the ground.
If the object moves while the elevator come's back everything is fine and the object go's for another ride.
Could someone explain to my why this is happening and is there a fix for this ?
The platform is expected to go through the ground and pick up the object once it comes back above ground. (Imagine a not all to sectret elevator)
I alredy tried to add the script DontGoThroughThings.cs. It didnt work either.
Here is a screenshot of the inspectors.
Here is the script i made for the elevator to go up and down.
Elevator.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Elevator: MonoBehaviour {
public float speed;
public float distance;
private bool goingUp;
void Start () {
goingUp = true;
}
void Update () {
var currentPosition = transform.position;
currentPosition.y = goingUpDown(currentPosition.y);
transform.position = currentPosition;
}
private float goingUpDown(float currentPosition)
{
if (goingUp)
currentPosition += speed;
else
currentPosition -= speed;
if (currentPosition > distance / 2)
goingUp = false;
if (currentPosition < -distance / 2)
goingUp = true;
return currentPosition;
}
}
If you need any more information leave a comment. Thank you
You need to add a RigidBody to your elevator object, and then check the "Is Kinematic" option on it.
From the Unity Documentation RigidBody Manual:
Is Kinematic : If enabled, the object will not be driven by the physics engine, and can only be manipulated by its Transform. This is useful for moving platforms or if you want to animate a Rigidbody that has a HingeJoint attached.
Related
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.
I'm creating a basic pool game in Unity with C#, what im trying to do is that if the cue ball is moving, the stick will disappear, and once it becomes stationary again, it will reappear to where the cue ball is located. This is my code so far:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class stickDeplacement : MonoBehaviour
{
public bool bIsOnTheMove = false;
Vector3 lastPos;
public GameObject Stick;
void Start()
{
}
void Update()
{
var stick = Instantiate(Stick, gameObject.transform.position, gameObject.transform.rotation);
if (this.transform.position != lastPos)
{
Destroy(stick);
Debug.Log("Is moving");
}
else
{
Debug.Log("Is not moving");
}
lastPos = this.transform.position;
}
}
But what happens is that the ball, along with the stick, will just spasm and be buggy right from the start (when I open and play the game). Am I missing something here?
This is extremely inefficient and dangerous!
Why instantiate a stick every frame just to eventually already destroy it in that very same frame? And if the ball is stationary you want an additional stick to be spawned every frame?
Instead of all the time instantiating and destroying it at all you should rather keep one stick and only (de)activate it.
In your case you could do this in a single line
bIsOnTheMove = transform.position == lastPos;
stick.SetActive(!bIsOnTheMove);
Also I doubt a lot you would like the stick to have the same rotation as a rolling ball! Of course this will behave awkward
Most certainly you do not simply want to clone the ball's orientation. I would e.g. try to determine the closest point of the table edge to the current ball's position (iterate through the wall colliders and use Collider.ClosestPoint) and let the stick face the direction from that edge point towars the ball position (+ maybe an offset in X so the stick is slightly inclined by default).
And finally you anyway do not want to assign that rotation every frame, since you most probably later want your users to be able to rotate that stick. You only want to apply this once when the ball becomes stationary.
Something like e.g.
// The stick is not a prefab anymore but simply always exists in the scene!
[SerializeField] private Transform stick;
[SerializeField] private Vector3 eulerOffset;
[SerializeField] private Collider[] wallColliders;
public bool bIsOnTheMove;
private Vector3 lastPos;
private void Start()
{
lastPos = transform.position;
}
private void Update()
{
// is the ball currently moving?
var isMoving = transform.position == lastPos;
last Post = transform.position;
// Did this state change since the last frame?
if(bIsOnTheMove == isMoving) return;
bIsOnTheMove = isMoving;
// (de)activate the stick accordingly
stick.gameObject.SetActive(!isMoving);
// Do this ONCE when ball becomes stanionary
if(!isMoving)
{
var ballPosition = transform.position;
// among the wall colliders find which one is closest to the ball
Vector3 closestPoint;
var smallestDistance = float.PositiveInifinity;
foreach(var wall in wallColliders)
{
var edgePoint = wall.ClosestPoint(ballPosition);
var distane = (edgePoint - ballPosition).sqrMagnitude;
if(distance < smallestDistance)
{
closestPoint = point;
smallestDistance = distance;
}
}
// then make the stick look towards the ball from that edge
var direction = ballPosition - closestPoint;
var rotation = Quaternion.LookRotation(direction);
// optional add the offset
rotation *= Quaternion.Euler(eulerOffset);
stick.rotation = rotation;
}
}
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.
My game is a topdown zombie shooter and whenever the zombies get to the player they bunch up underneath them, to the point where the player can just walk over the zombies. I noticed that when I check isKinematic on the Rigidbody the zombies cant push the player up to go underneath him, so they just run into him(which is what I want). Despite this I am then unable to move. How can i fix this?
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerMoving1 : MonoBehaviour {
public float moveSpeed;
private Rigidbody myRigidbody;
private Vector3 moveInput;
private Vector3 moveVelocity;
private Camera mainCamera;
public GunController theGun;
void Start () {
myRigidbody = GetComponent <Rigidbody>();
mainCamera = FindObjectOfType<Camera>();
}
// Update is called once per frame
void Update () {
moveInput = new Vector3(Input.GetAxisRaw("Horizontal"), 0f, Input.GetAxisRaw("Vertical"));
moveVelocity = moveInput * moveSpeed;
Ray cameraRay = mainCamera.ScreenPointToRay(Input.mousePosition);
Plane groundPlane = new Plane(Vector3.up, Vector3.zero);
float rayLength;
if(groundPlane.Raycast(cameraRay,out rayLength))
{
Vector3 pointToLook = cameraRay.GetPoint(rayLength);
transform.LookAt(new Vector3(pointToLook.x,transform.position.y,pointToLook.z));
}
if (Input.GetMouseButtonDown(0))
theGun.isFiring = true;
if (Input.GetMouseButtonUp(0))
theGun.isFiring = false;
}
void FixedUpdate(){
myRigidbody.velocity = moveVelocity;
}
}
With isKinematic == true You can't change object position through rigidbody, You can only change transform.position.
I think it could be better, if You set isKinematic to false and add stopping distance to enemies, so they can't get too close to player.
Being that your player can no longer be effected by the physics engine, you'd have to manipulate the object's transform manually. Your script isn't ideally setup for it currently, but if I was to hack it into it and try to make it work it would look something like this:
(you can change it from fixedUpdate to update if you're no longer utilizing the physics engine)
void update(){
float x = Input.GetAxisRaw("Horizontal")* Time.Deltatime;
float z = Input.GetAxisRaw("Vertical") * Time.Deltatime;
transform.position = new Vector3(transform.position.x+x,0,transform.position.z+z);
Another way of doing this is to lock the position of Y for the player (assuming Y is the positive "up" direction). isKinimatic is best when you want to move the player or objects around yourself.
I would say upping the mass is better in this case, and you can keep isKinematic unchecked in this case then too. Also apply the lock for Y movement (again if it is the "up" direction from the plane)
Let me know what your solution is regardless, I've had some issues in the past as well with these types of events happening
hi i was wondering if someone could help me fix practice code (i make practice codes before i make the real thing because its just how i roll) it is basically an object that requires the user to click on the screen in order for it to not touch the ground much like flappy bird however although i have applied gravity correctly to the sprite i cannot fix the velocity section (i coded is to every time the user clicks with his mouse or taps the space key the object will move up like flappy bird)
using UnityEngine;
using System.Collections;
public class BirdMovment : MonoBehaviour {
Vector3 Velocity = Vector3.zero;
public Vector3 gravity;
public Vector3 flapVelocity;
public float maxSpeed = 5f;
bool didFlap = false;
// Use this for initialization
void Start () {
}
void update (){
if (Input.GetKeyDown (KeyCode.Mouse0))
{
didFlap = true;
}
}
// Update is called once per frame
void FixedUpdate () {
Velocity += gravity* Time.deltaTime;
if (didFlap) {
didFlap = false;
Velocity += flapVelocity;
}
Velocity = Vector3.ClampMagnitude (Velocity, maxSpeed);
transform.position += Velocity * Time.deltaTime;
}
}
can you please fix the error as every time i set the velocity in unity for the sprite ad run the program the sprite just keeps on falling and no matter how much i click or tap the space key the sprite does not stop falling even if i increase the velocity
First of all, the correct Update function is with a capital U, so Update() instead of update(). Then, since you're not doing anything with physics, you can do everything in Update and not use FixedUpdate at all. So you can remove the didFlap variable and add to Velocity directly inside the if (Input.GetKeyDown ...) block. Furthermore, regarding gravity, you're multiplying it twice with Time.deltaTimethere, so remove the first one. That should get you started.