Unity 2D. Why raycasting does not work properly? - unity3d

With this code I am changing color of gun object if raycast can hit player. Color changes as soon as Player walks into raycast radius. However color won't switch back from red to green as soon as player either goes away (more than Range distance) or hide behind walls. It will eventually switch back to green but not right away. Can you please help me figure out what seems to be the problem?
void Update()
{
Vector2 targetPos = Target.position;
Direction = targetPos - (Vector2)transform.position;
RaycastHit2D rayInfo = Physics2D.Raycast(transform.position, Direction, Range, layerMask);
if (rayInfo)
{
if (rayInfo.collider.gameObject.tag == "Player")
{
if (Detected == false)
{
Detected = true;
Gun.GetComponent<SpriteRenderer>().color = Color.red;
}
}
else
{
if (Detected == true)
{
Detected = false;
Gun.GetComponent<SpriteRenderer>().color = Color.green;
}
}
}
}

When your raycasthit doesn't hit anything with specified LayerMask you don't change your gun's color maybe this is the issue. if your reset your gun color it can solve. Here is the example
//define gunColor variable it is default color of your gun
Color gunColor=Color.green;
void Update()
{
Vector2 targetPos = Target.position;
Direction = targetPos - (Vector2)transform.position;
RaycastHit2D rayInfo = Physics2D.Raycast(transform.position, Direction, Range, layerMask);
if (rayInfo)
{
gunColor=rayInfo.collider.gameObject.CompareTag("Player")?Color.red:Color.green,
}else{
//when raycasthit doesnt hit any thing set gun color to green;
gunColor=Color.green;
}
//update gun color
Gun.GetComponent<SpriteRenderer>().color = gunColor;
}

Related

How to register a fall from height in unity 2D

So i'm working on a 2D game, first stage is a platformer so i'm trying to make it look nicer. I added a particle system with dust, so in case he falls down from height animation should be played. How do i register a fall from height to play the animation?
You can play animation on collision with the ground collider, when player's falling velocity is higher than 0. Using specific positive value may be nicer, cos it's gonna look like only achieving enough speed will spread dust.
I can see another way of doing this, but it takes more calculations:
To define the last position and current position of Y coordinates of the player.
If it is going down currentPos < lastPos
If it is going up currentPos > lastPos
public GameObject player;
public GameObject particleDust;
Vector3 lastPos;
Vector3 currentPos;
float _time = 0;
private bool up = false;
private bool down = false;
private bool equal = false;
void Awake()
{
lastPos = player.transform.position;
}
void Update()
{
//assign player's position to current position
currentPos = player.transform.position;
//going up
if (lastPos.y < currentPos.y)
{
up = true;
down = false;
equal = false;
}
//going down
else if (lastPos.y > currentPos.y)
{
up = false;
down = true;
equal = false;
}
//same level
else if (lastPos.y == currentPos.y)
{
equal = true;
}
if (down == true && equal == true)
{
particleDust.Play();
}
lastPos = currentPos;
}
You can define the up and down functions to define player's movement with bool.
When the direction down is True and lastPos = currentPos
then it means that he was going down and he stopped because the player hit the ground.
I choose this option without using colliders because it can be versatile and be used on every level without adding new things.
I assume this will work but it need more things, i hope this will get you started.
(If i said something wrong please correct me , it help me improve too, thank you!)
Just thinking of how to detect falls from a specific height, I think this should work just fine in most cases:
private float startingHeight = 0.0f;
private bool grounded = true;
private bool landed = false;
//this is the distance the player needs to fall before dust shows up
private float fallingDist = 5.0f;
private void Start()
{
startingHeight = transform.position.y;
}
private void Update()
{
if(grounded) //set this to false when not colliding with the ground
{
startingHeight = transform.position.y;
}
else if(landed) //set this to true when hitting the ground while grounded is false
{
landed = false;
if((startingHeight - transform.position.y) >= fallingDist)
{
//trigger dust particles or animation
}
}
}

Jump functionality for a 2D Top Down Unity game?

I am struggling to find an efficient way to let my player jump in a 2D Top Down world. I can see a lot of tutorials about platformer views where the camera is oriented at the side of the player, but nothing really working for a top down view like startdew Valley.
I am not using physics, so I move the character on the tilemap using a Couroutine which moves the player to the next position on grid, here it is my Update and DoMove methods:
private void Update()
{
if (!isMoving)
{
input.x = Input.GetAxisRaw("Horizontal");
input.y = Input.GetAxisRaw("Vertical");
if (input.x != 0)
input.y = 0;
if (input != Vector2.zero)
{
animator.SetFloat("Horizontal", input.x);
animator.SetFloat("Vertical", input.y);
var targetPos = transform.position + new Vector3(input.x, input.y, 0f);
// obstacle detection
Vector3Int obstaclesMapTile = obstacles.WorldToCell(targetPos - new Vector3(0, .5f, 0));
if (obstacles.GetTile(obstaclesMapTile) == null)
{
StartCoroutine(DoMove(targetPos));
}
}
animator.SetFloat("Speed", input.sqrMagnitude);
}
}
private IEnumerator DoMove(Vector3 newPos)
{
isMoving = true;
while ((newPos - transform.position).sqrMagnitude > Mathf.Epsilon)
{
transform.position = Vector3.MoveTowards(transform.position, newPos, moveSpeed * Time.fixedDeltaTime);
yield return null;
}
transform.position = newPos;
isMoving = false;
}
Is there anybody which could give me an hint on how to add a jumping feature? ( ideally with animation support?) I am kind of running out of ideas.
Thanks in advance.
Just think of it as animation only. Since it is 2D top down, it's more about it looking like it jumps, and then if it has to go over something while in the jump animation, test for just that.
For example; if over hole and jump animation is playing, then allow movement over the whole, otherwise fall. So if the player presses the button for jump, the animation would play, and there should be some variable storing what animation the player is currently in.

(Big unity noob here) I can jump while in the air, and I can't jump while moving on the x-axis

Have tried a few things but they didn't seem to work, so I was hoping that you guys could help me.
I've trying to make this demo for a little time now, but I can't seem to get the jumping to work.
When I try to jump while running, I can't. But I can however jump forever when i get up in the air, which is something that I would like to remove from the game.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class movement : MonoBehaviour
{
Rigidbody2D rb2d;
public float moveVelocity = 8f;
public float jumpVelocity = 15f;
public float fallMultiplier = 2.5f;
public float lowJumpMultiplier = 2f;
public const string RIGHT = "right";
public const string LEFT = "left";
public const string UP = "up";
string buttonPressed;
void Start()
{
rb2d = GetComponent<Rigidbody2D>();
}
void Update()
{
if (rb2d.velocity.y < 0)
{
rb2d.velocity += Vector2.up * Physics2D.gravity.y * (fallMultiplier - 1) *
Time.deltaTime;
}
else if (rb2d.velocity.y > 0 && !Input.GetButton ("Jump"))
{
rb2d.velocity += Vector2.up * Physics2D.gravity.y * (lowJumpMultiplier - 1) *
Time.deltaTime;
}
if (Input.GetKey(KeyCode.RightArrow))
{
buttonPressed = RIGHT;
}
else if (Input.GetKey(KeyCode.LeftArrow))
{
buttonPressed = LEFT;
}
else if (Input.GetKey(KeyCode.UpArrow))
{
buttonPressed = UP;
}
else
{
buttonPressed = null;
}
}
private void FixedUpdate()
{
if (buttonPressed == RIGHT)
{
rb2d.velocity = new Vector2(moveVelocity, rb2d.velocity.y);
}
else if (buttonPressed == LEFT)
{
rb2d.velocity = new Vector2(-moveVelocity, rb2d.velocity.y);
}
else if (buttonPressed == UP)
{
rb2d.velocity = Vector2.up * jumpVelocity;
}
else
{
rb2d.velocity = new Vector2(0, rb2d.velocity.y);
}
}
}
I am not sure why you are trying to control the gravity of the player when gravity is already applied to any gameObject with the RigidBody or RigidBody2D component attached to it. It is good that you are reading input in the Update() function and applying the motion inside of the FixedUpdate(). Here is a slight tweak to your current code, let me know how this goes.
Rigidbody2D rb2d;
public float moveVelocity = 8f;
public float jumpVelocity = 15f;
private float horizontalInput = 0.0f;
// did the player just try to jump
private bool justJumped = false;
void Start()
{
rb2d = GetComponent<Rigidbody2D>();
}
void Update()
{
// grab how the player is moving - this value is mapped to your arrow keys
// so horizontal is left / right arrow and Vertical is up/down arrow
// the value is between [-1, 1] respectively
horizontalInput = Input.GetAxis("Horizontal");
// player tried to jump, we are not currently jumping and the player is grounded
if(IsGrounded() && Input.GetKeyDown(KeyCode.UpArrow))
{
justJumped = true;
}
}
private void FixedUpdate()
{
// handle our jump
if(justJumped)
{
// we just applied a jump so do not apply it again
justJumped = false;
// you can either apply the jump by setting velocity, but I would recommend using AddForce instead
rb2d.AddForce(Vector2.up * jumpVelocity);
}
// we are moving in either the left or right direction
if(horizontalInput != 0)
{
// move in the horizontal axis, but keep our Y component of velocity the same in case we jumped
rb2d.velocity = new Vector2 (horizontalInput * moveVelocity, rigidBody.velocity.y);
}
else
{
// just in case we are not moving, assure this by setting the horizontal component of velocity to 0
rb2d.velocity = new Vector2 (0f, rigidBody.velocity.y);
}
}
// determines if this object is currently touching another object that is marked as ground
private bool IsGrounded() {
// our current position (the player)
Vector2 position = transform.position;
// the direction we are going to aim the raycast (down as that is where the ground is)
Vector2 direction = Vector2.down;
// the ground should be close, so check it very close to the player
float distance = 1.0f;
// check if we hit anything that is on the layer of just ground - ignore all other layers
// IMPORTANT:: Make sure to make a Layer and set all of your ground to this layer
RaycastHit2D hit = Physics2D.Raycast(position, direction, distance, LayerMask.GetMask("GroundLayer"));
// we hit a ground collider, so we are grounded
if (hit.collider != null) {
return true;
}
return false;
}
Let me know if this works for you. I changed a few things around such as using GetAxis() instead of using the arrow keys as in Unity, these are the same. I also changed your jump to use an AddForce2D instead of setting velocity. The one addition was I added a IsGrounded() which will detect if whatever object this script is on (I assume it is on your player object) is near or touching objects below them that are marked as GroundLayer. If you have questions comment below.

How to make Touch Controls like mini Golf King

Goal
Hello Guys! I am new with unity 3-D . I want to make controls exactly like Mini Golf king . Like when ball stops pointers becomes visible on the screen . On clicking that pointer and dragged its scale changes and points always towards ball.
This is what I want to achieve
MY Approach
Initially according to my knowledge I Have implemented something using ray-cast. In the pointer I placed 3-d pointer as child object of ball . when i touch on the screen I send a ray cast to world from screen that detects Ball if i am touching Ball the i show Pointer and on every point on the screen i am continuously sending ray-casts on the world and changing pointer direction accordingly but i think it is not the good way on performance point
RaycastHit GenerateRayCast(Vector2 position, Camera camera,LayerMask mask) { // GENERATE RAY CAST AT GIVEN DIRECTION IN 3D WORLD
RaycastHit hito;
Ray ray = camera.ScreenPointToRay(position);
Physics.Raycast(ray, out hito, rayLength, mask);
return hito;
}
#endregion
#region Updatemethod
void FixedUpdate () {
if (IsBallInStopPos) { // IF BALL IN STATIC POSITOIN THEN LISTEN FOR TOUCH INPUTS
//if (Input.GetMouseButton(0) && !EventSystem.current.IsPointerOverGameObject())
if (Input.touchCount > 0 && !EventSystem.current.IsPointerOverGameObject()) // CHECK FOR SREEN TOUCH
{
touchInput = Input.touches[0];
// touchInput = Input.mousePosition; // get touch information
hitObject = GenerateRayCast(touchInput.position, Camera.main, mask);
if (touchInput.phase == TouchPhase.Began)
{
if (hitObject.collider.name == "Pointer") { // IF TOUCHED ON POINTER :
if (touchPointSet == false) {
touchPointSet = true;
touchStartPoint = hitObject.point; // SETTING START TOUCH POINT
}
}
}
else if (touchInput.phase == TouchPhase.Moved) {
newScale= Mathf.Clamp (Vector3.Distance(pointerChild.transform.position , hitObject.point),1f,2f);
pointerPivot.transform.localScale = Vector3.one * newScale;// SETTING SCALE ACCORDING TO DRAG VALUE
if (touchPointSet == true) { // WHEN TOUCH DRAGGED AND PREVIOULY POINTER IS TOUCHED ROTATE THE POINTER AT GIVEN DIRECTION
newDirection = new Vector3(hitObject.point.x, transform.position.y, hitObject.point.z);
transform.LookAt(2 * transform.position - newDirection);
canShoot = true;
}
}
}
else if (touchInput.phase == TouchPhase.Ended)
{
if (newScale <= 1f)
return;
if (IsBallInStopPos && canShoot )
{
//shooted = true;
newScale = newScale -1;// AS SCALE VALUE IS BETWEEN 1 AND 2 SO SUBSTACT FROM TO MAKE IT BETWEEN
pointerPivot.gameObject.SetActive(false);
rigidBody.constraints = RigidbodyConstraints.None;
GetComponent<Rigidbody>().AddRelativeForce(new Vector3(0f, 0f, 10000f * newScale));
// Time.timeScale = 2f;
canShoot = false;
IsBallInStopPos = false; // AFTER SHOOT : after the ball is shooted now the ball is not in staticstatic condition
}
}
}

buttons only react to clicks/touches when clicking/touching to the right of them

I'm making a 2D game in Unity3D for android. Right now I'm making buttons. And this buttons does not react clicks/touched properly. I've got same issue with mouse clicks and touches both. Every button has trigger boxcollider with a same size as an object. BUT buttons react only when I click on area, that is right from a button. I don't understand why is it so. What should I do? Here is my code:
if (Input.GetMouseButtonDown(0)) {
Vector3 i = Camera.main.ScreenToWorldPoint (new Vector3 (Input.mousePosition.x, Input.mousePosition.y, 1));
RaycastHit2D hit = Physics2D.Raycast (i, i);
if (hit.transform != null) {
if (hit.transform.tag == "button") {
hit.transform.gameObject.SetActive(false);
}
}
}
Also, I've instantiated an object on mouse click on "i" position to check does it convert screen position to world correctly, and it works fine.
the first parameter in Physics2D.Raycast is the origin and the second one is direction so you should make the raycast from your ray.origin in the direction of ray.direction
void Update () {
if (Input.GetMouseButtonDown(0)) {
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
RaycastHit2D hit = Physics2D.Raycast (ray.origin, ray.direction, Mathf.Infinity);
if (hit) {
if(hit.collider.gameObject.tag=="button"){
//do something
}
}
}
}
Try to handle it by this way:
if (Input.GetMouseButtonDown(0)) {
Vector3 pos = Camera.main.ScreenToWorldPoint (Input.mousePosition);
Vector2 touchPos = new Vector2(pos.x, pos.y);
Collider2D hit = Physics2D.OverlapPoint(touchPos);
if (hit) {
Debug.Log(hit.transform.gameObject.name);
if (hit.transform.tag == "button") {
hit.transform.gameObject.SetActive(false);
}
}
}