Unity Boxcast 3D always return false - unity3d

I'm learning Unity and want to use Boxcasting to detected if the player is grounded. I have this code:
void Jump()
{
float maxDistance = 0.1f;
RaycastHit hit;
bool isGrounded = Physics.BoxCast(transform.position, transform.lossyScale / 2, Vector3.down, out hit, transform.rotation, maxDistance, groundMask);
if (isGrounded)
rb.AddForce(Vector3.up * jumpForce);
Debug.Log(isGrounded);
}
But it always return false. If I have it inside a OnDrawGizoms method, it works as indented, but if I have it in my Jump() method (as the code above) will it always return false.
I would appreciate any help I could get.

Related

Unity 2D Platformer Jumping Issue

I'm able to get my sprite to jump using a Axis.RawInput. This input also serves as a parameter to trigger the jumping animation when the RawInput is greater than 0. This issue with this is when you release the key, the sprite instantly falls back down. How can I perform a fixed jump when the key is pressed once or held down and then have the sprite fall at a fixed rate while also having the animations trigger?
This is what I have in my PlayerMover script now.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerMover : MonoBehaviour
{
public Animator anim;
public Vector3 velocity = Vector3.zero;
public float runSpeed = 0f;
public float jumpSpeed = 0f;
private SpriteRenderer sp;
public float maxJump = 4f;
private void Awake()
{
sp = GetComponent<SpriteRenderer>();
}
void Update()
{
runSpeed = Input.GetAxisRaw("Horizontal");
jumpSpeed = Input.GetAxisRaw("Vertical");
anim.SetFloat("Jump", jumpSpeed);
anim.SetFloat("Speed", Mathf.Abs(runSpeed));
}
private void FixedUpdate()
{
Move(runSpeed, jumpSpeed*4);
}
void Move(float horizontal, float vertical)
{
if(horizontal > 0 || horizontal > 0 && vertical >0)
{
anim.SetBool("Idle", false);
sp.flipX = false;
}
else if(horizontal < 0 || horizontal <0 && vertical >0)
{
anim.SetBool("Idle", false);
sp.flipX = true;
}
else
anim.SetBool("Idle", true);
velocity.x = horizontal;
velocity.y = vertical;
transform.position += velocity * Time.fixedDeltaTime;
}
}
I've read about using something like
if(Input.GetKeyDown(GetKeyCode("Space"){
rigidbody2D.AddForce(new Vector2(0, 10), ForceMode2D.Impulse);
}
In order to move but it allows additional jumps whenever Space is pressed.
If you want to use something like:
if(Input.GetKeyDown(GetKeyCode("Space"))){
rigidbody2D.AddForce(new Vector2(0, 10), ForceMode2D.Impulse);
}
but need to stop the player from jumping when they're already in the air, just only allow them to do this when they're already on the floor. So:
if(Input.GetKeyDown(GetKeyCode("Space")) && isOnFloor()){
rigidbody2D.AddForce(new Vector2(0, 10), ForceMode2D.Impulse);
}
Where isOnFloor() is some function that checks if your character is on the floor. Depending on your game implementation this could be done several ways, but the most common one is to check if the player character is colliding with anything, and if so, if that collision object is below them. This stackexchange thread gives some code samples for how to achieve this.
In order to use this
if (Input.GetKeyDown(GetKeyCode("Space"))
{
rigidbody2D.AddForce(new Vector2(0, 10), ForceMode2D.Impulse);
}
you need to check if your player is colliding with the ground, so instead you would have a bool like bool isGrounded to check if you are touching the ground, to do this you can do it in the OnCollisionStay() to confirm it is true when you are colliding with the ground. You can use tags to check if the collider you are colliding with is the ground. Then when you jump, you need to say isGrounded = false; then it will not be true untill you land on the ground again
if (Input.GetKeyDown(GetKeyCode("Space") && isGrounded == true)
{
rigidbody2D.AddForce(new Vector2(0, 10), ForceMode2D.Impulse);
isGrounded = false;
}

Raycast only returns false, even when true expected

I have the following FollowingNPC game object, which is supposed to follow the Player object if there is direct vision:
Here the Player object:
The BlockingLayer and Player Layers have the physics collision enabled between each other:
The FollowingNPC hast the following script attached, that always returns a "Not Hit" result: Raycast always false. This is not the expected output, as both objects seem to have a clear view between each other and the debug ray can be drawn without problems.
public class FollowingNPC : MonoBehaviour
{
private Vector3 heading, direction;
private float distance;
void Update()
{
heading = GameObject.FindGameObjectWithTag("Player").transform.position - transform.position;
distance = heading.magnitude;
direction = heading / distance;
RaycastHit hit;
if (Physics.Raycast(transform.position, direction, out hit))
{
if (hit.transform== GameObject.FindGameObjectWithTag("Player").transform)
{
Debug.DrawRay(transform.position, direction * distance, Color.red);
Debug.Log("Hit Player");
}
else
{
Debug.DrawRay(transform.position, direction * distance, Color.yellow);
Debug.Log("Hit Wall");
}
}
else
{
Debug.DrawRay(transform.position, direction * distance, Color.white);
Debug.Log("Not Hit");
}
}
}
Solved:
As derHugo suggested, Physics2D.Raycast should be used here. This function does not return a bool, so this is the implementation that worked for me:
void Update()
{
heading = GameObject.FindGameObjectWithTag("Player").transform.position - transform.position;
RaycastHit2D hit = Physics2D.Raycast(transform.position, heading.normalized, LayerMask.GetMask("Player"));
if (hit.collider != null)
if (hit.transform == GameObject.FindGameObjectWithTag("Player").transform)
Debug.Log("Hit Player");
else
Debug.Log("Hit Wall");
else
Debug.Log("Not Hit");
}
Also, it's important to note that, even with the mask, the Raycast returned the hit with the collider of FolloginNPC, so I had to disable it. I'll have to do some investigation or search a workaround.
Note that in Unity the Physics and Physics2D are completely independent and separated Physics engines!
Built-in 3D physics (Nvidia PhysX engine integration)
Built-in 2D physics (Box2D engine integration)
You have Rigidbody2D and Collider2D so you would rather want to use Physics2D.Raycast!
You should also strongly avoid using FindGameObjectWithTag in Update and even worse multiple times as it is quite expensive! Rather do it once and store the result.
// If possible and best would be to already reference it via the Inspector
[SerilaizeField] private Transform player;
// As fallback get it ONCE on runtime
private void Awake()
{
if(!player) player = GameObject.FindGameObjectWithTag("Player").transform;
}
void Update()
{
// actually those wouldn't really need to be fields
heading = player.position - transform.position;
distance = heading.magnitude;
// This line isn't really necessary
// If something I would use
//direction = heading.normalized
direction = heading / distance;
var hit = Physics2D.Raycast(transform.position, direction);
if (hit.collider)
{
if (hit.transform == player)
{
Debug.DrawRay(transform.position, direction * distance, Color.red);
Debug.Log("Hit Player");
}
else
{
Debug.DrawRay(transform.position, direction * distance, Color.yellow);
Debug.Log("Hit Wall");
}
}
else
{
Debug.DrawRay(transform.position, direction * distance, Color.white);
Debug.Log("Not Hit");
}
}
Later you should also remove all these Debug.Log since they are also quite expensive when done in Update!

Unity jumping issue, character is not jumping at all

(This is 2D project)
My character need to run left and right and jump on ground. It is my first experience with Unity and it latest available version of it, I manage to make my Character run left and right and flip when it is change direction, but it does not jump at all.
For the Character I am currently using 2 Box Collider 2Ds and Rigidbody 2D. Character has mass equal 1.
For the Ground I am currently using 2 Box Collider 2Ds. Ground is single sprite which is cover bottom part of screen.
Below is the code for jumping and grounded I am currently trying to use.
'''
{
public float maxSpeed = 10f;
public float jumpVelocity = 10f;
private bool isGrounded;
private float move = 0f;
private Rigidbody2D rb2d; //Store a reference to the Rigidbody2D component required to use 2D Physics.
private SpriteRenderer sprt_render;
// Start is called before the first frame update
void Start()
{
rb2d = GetComponent<Rigidbody2D>();
isGrounded = true;
}
// Update is called once per frame
void Update()
{
GetInput();
}
private void GetInput()
{
move = Input.GetAxis("Horizontal");
if (transform.position.x > -6.2 && transform.position.x < 5.7)
{
rb2d.velocity = new Vector2(move * maxSpeed, rb2d.velocity.y);
}
else
{
rb2d.velocity = new Vector2(move * maxSpeed * -1, rb2d.velocity.y);
}
if (Input.GetKeyDown(KeyCode.Space) && isGrounded)
{
Debug.Log("Jump");
rb2d.velocity = new Vector2(rb2d.velocity.x, jumpVelocity);
isGrounded = false;
//rb2d.AddForce(Vector2.up * jumpVelocity, ForceMode2D.Impulse);
}
}
private void OnCollisionEnter2D(Collision2D collision)
{
if (collision.gameObject.CompareTag("Ground"))
{
isGrounded = true;
}
}
}
'''
As you can see I try to use two different approach in connection with jump realisation using Velocity and using AddForce result is totally the same it is not jumping even first time. I check thought breakpoint it definitely go trough jumping code but nothing happened.

Dragging an object with raycast is laggy

When dragging an object slowly with a raycast the object moves with a bit of lag.
When dragging the object fast the mouse pointer gets out of the field of layer raycasting so the object is no more moving.
The main project is dragging a cube on a plane.
But in order to make the project more simpler, I opened a new 2D project and made a circle and assigned to it the following script, and attached to it a sphere collider (the main target is in 3D space).
// If some one wrote:
private Vector2 deltaPos;
void Update () {
Vector2 touchPos;
if (Input.GetMouseButtonDown (0)) { // Clicking the Target
RaycastHit hit;
var ray = Camera.main.ScreenPointToRay (Input.mousePosition);
if (Physics.Raycast (ray, out hit, Mathf.Infinity)) {
touchPos = new Vector3 (hit.point.x, hit.point.y);
deltaPos.x = touchPos.x - transform.position.x;
deltaPos.y = touchPos.y - transform.position.y;
Debug.Log ("You Clicked Me");
}
}
if (Input.GetMouseButton (0)) {
RaycastHit hit;
var ray = Camera.main.ScreenPointToRay (Input.mousePosition);
if (Physics.Raycast (ray, out hit, Mathf.Infinity)) {
transform.position = new Vector2 (hit.point.x - deltaPos.x, hit.point.y - deltaPos.y);
}
}
}
I expected to drag the sphere regularly, but what happens is that the pointer goes outside the sphere collider when moving fast, therefore the circle stops moving.
I found this article, then I changed the void from Update() to FixedUpdate() but same result.
Try putting your physics code in FixedUpdate() function which is built for physics calculation. then if it's laggy, you can changeFixed Timestep in physics settings.
Fixed Timestep: A framerate-independent interval that dictates when physics calculations and FixedUpdate() events are performed.
https://docs.unity3d.com/Manual/class-TimeManager.html
EDIT
this code:
if (Physics.Raycast (ray, out hit, Mathf.Infinity))
checks if the raycast has hit something, therefore when the pointer goes out of the sphere there is nothing else to hit, so the if condition returns false and you cannot move it, to solve the problem add a big quad or plane as child to your camera and make sure it fills the camera view perfectly, and it's behind all your other scene elements.
you also can make a script that sets this plane for you.
EDIT 2
As another approach to solve the issue, you can use flags.
Add this to your camera, or edit it to your needs.
public class DragObjects : MonoBehaviour
{
Camera thisCamera;
private Transform DraggingObject;
bool DraggingFlag = false;
RaycastHit raycast;
Ray ray;
Vector3 deltaPosition;
void Start()
{
thisCamera = GetComponent<Camera>();
}
void Update()
{
if (Input.GetMouseButtonDown(0))
{
ray = thisCamera.ScreenPointToRay(Input.mousePosition);
if (Physics.Raycast(ray, out raycast, Mathf.Infinity))
{
DraggingObject = raycast.collider.transform;
DraggingFlag = true;
deltaPosition = thisCamera.ScreenToWorldPoint (Input.mousePosition) - DraggingObject.position;
}
}
else if (Input.GetMouseButton(0))
{
if (DraggingFlag)
{
DraggingObject.position = new Vector3 (thisCamera.ScreenToWorldPoint (Input.mousePosition).x - deltaPosition.x, thisCamera.ScreenToWorldPoint (Input.mousePosition).y - deltaPosition.y, DraggingObject.position.z);
}
}
else if (Input.GetMouseButtonUp(0))
{
DraggingFlag = false;
}
}
}
Remember to cash your Camera.main in a variable at the start, because it is not performant and does this in the background:
GameObject.FindGameObjectsWithTag("MainCamera").GetComponent<Camera>();

Player touch input and continuous one direction movement combination

I want to create Mmm Finger 2 game like player movement, here is game play video: Mmm Fingers 2 by Noodlecake Android Gameplay ᴴᴰ
In this player is continuously moving upward as well based on touch, you have full control over player movement. These both things together not working properly for me. Finger based movement also working in all directions still you are continuously moving up.
I have tried to write some code with different ways but can't able to create smooth experience in game play.
Upto now I reached up to here:
void Update ()
{
// checking condition for death
if (!isAlive)
return;
#if UNITY_EDITOR
// executed in Unity editor
if (Input.GetMouseButtonDown (0)) {
//Get the mouse position on the screen and send a raycast into the game world from that position.
Vector2 worldPoint = Camera.main.ScreenToWorldPoint (Input.mousePosition);
RaycastHit2D hit = Physics2D.Raycast (worldPoint, Vector2.zero);
//If something was hit, the RaycastHit2D.collider will not be null.
if (hit.collider != null && hit.transform.CompareTag (GameConstants.TAG_HUMAN_PLAYER)) {
playerFound = true;
GameManager.Instance.IsGameRunning = true;
GameHUDController.Instance.HideGameInstruction();
hidePlayerName();
}
} else if (Input.GetMouseButtonUp (0)) {
playerFound = false;
StartCoroutine (PerformGameOver ());
}
Vector3 nextPosition = transform.position;
nextPosition.x += (Time.deltaTime * speed * 0.5f);
transform.position = nextPosition;
if (playerFound) {
Vector3 worldPoint = Camera.main.ScreenToWorldPoint (Input.mousePosition);
// worldPoint.x += (speed * Time.deltaTime);
worldPoint.z = 0f;
transform.position = worldPoint;
// transform.position = Vector3.Lerp (transform.position, worldPoint, Time.deltaTime * 10f);
}
}
Please give some help into this.