Currently, I want to make a dash for the player in a 2D game in unity. I'm using game objects to the left and right of the player to use raycasts to check the distance from a wall in a certain area. If its too close to a wall, I need it to dash only that distance (to the wall) instead of the full distance (behind/through the wall).
This is my code for dashing in my player movement (DashCheckLeft is -0.5 from the player) (DashCheckRight is 0.5 from the player):
public float dashDistance = 3f;
float distance;
public Transform DashCheckLeft;
public Transform DashCheckRight;
private void Update() {
if(Input.GetKeyDown(KeyCode.LeftShift)) {
Debug.Log("Dashed");
Dash();
private void FixedUpdate() {
RaycastHit2D hitLeft = Physics2D.Raycast(DashCheckLeft.position, Vector2.left, -dashDistance);
RaycastHit2D hitRight = Physics2D.Raycast(DashCheckRight.position, Vector2.right, dashDistance);
if(hitLeft.collider != null) {
distance = Mathf.Abs(hitLeft.point.x - transform.position.x);
}
else if(hitRight.collider != null) {
distance = Mathf.Abs(hitRight.point.x - transform.position.x);
}
else {
distance = dashDistance;
}
}
private void Dash() {
rb.position = new Vector2(rb.position.x + distance, rb.position.y);
}
The problem now is that apperently I'm only dashing the distance between the player and the DashChecks (0.5f) instead of the intended 3f and I believe it may be because the raycasts are hitting the collider of the player somehow, but changing my player to the "Ignore Raycast" layer makes it fall into the floor, and also doesn't fix the issue.
I worked on this problem, and found the answer. Basically, your raycasts were detecting the player's collider too. There is a simple fix for this. You should just add the fourth argument to your raycast. The fourth argument is a LayerMask. A LayerMask is like a tag, but you can have several on at the same time. This is what I changed the code to (I made some extra adjustments too):
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Player : MonoBehaviour
{
Rigidbody2D rb;
public float dashDistance = 3f;
public LayerMask floor;
float distance;
private void Start()
{
rb = GetComponent<Rigidbody2D>();
}
private void Update()
{
if (Input.GetKeyDown(KeyCode.LeftShift))
{
RaycastHit2D left = Physics2D.Raycast(transform.position, -transform.right, dashDistance, floor);
RaycastHit2D right = Physics2D.Raycast(transform.position, transform.right, dashDistance, floor);
if (left.collider != null)
{
print("left");
distance = Mathf.Abs(left.point.x - transform.position.x);
distance = -distance;
}
else if (right.collider != null)
{
print("right");
distance = Mathf.Abs(right.point.x - transform.position.x);
}
else
{
distance = dashDistance;
}
print(distance);
Debug.Log("Dashed");
Dash();
}
void Dash()
{
rb.position = new Vector2(rb.position.x + distance, rb.position.y);
}
}
}
(when I say 'world objects', I mean the objects that make up the terrain. For example the ground or trees) You should add a new layer by clicking on the world objects. Then, you should look at the top of the inspector, then click the 'Layer Default' dropdown menu, and click the 'Add Layer...' button. Then write a new name on that list. Go back to the world game object, and click the same dropdown menu, and select the layer that you want for the world. You should make sure that all of the world objects have the same layer. Go back to the player object, and in the inspector, set the 'floor' variable to the same layer as the world. If that didn't make sense, here is a link of how to set layers.
Related
Trying to work myself through basic FPS shooting as practice and I want to have bullet holes where you shoot. However, Texture Z-fighting occurs when I attempt to do so.
The gun works using raycasting like so:
Physics.Raycast(playercam.transform.position, playercam.transform.forward, out hit)
The bullet holes are currently a 2d sprite that I place on the target using this script:
GameObject ceffect = Instantiate(bullethole, hit.point, Quaternion.LookRotation(hit.normal));
theoretically this should work, and it does, however, when it is placed on the world, it Z- fights with the floor texture.
I have tried to render the bullet holes on a different layer, but this simply does not work.
Is there a way to kind of pull the sprite to the top of the object?
Am I missing something with the layers?
If you need more code, here's my shooting script currently, but look at your own risk.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerShooting : MonoBehaviour
{
public float fireRate = 2f;
public float weapon = 1f;
public float pistoldmg = 5f;
public Camera playercam;
public GameObject redblood;
public GameObject bullethole;
private float timetofire = 0f;
void Start()
{
}
void Update()
{
if(Input.GetKeyDown(KeyCode.Mouse0) && (Time.time > timetofire))
{
timetofire = Time.time + 1f / fireRate;
PistolShoot();
}
else if(Input.GetKey(KeyCode.Mouse0))
{
}
}
void PistolShoot()
{
RaycastHit hit;
if(Physics.Raycast(playercam.transform.position, playercam.transform.forward, out hit))
{
Enemy1 enemy = hit.transform.GetComponent<Enemy1>();
if(enemy != null)
{
enemy.Shot(pistoldmg);
GameObject beffect = Instantiate(redblood, hit.point, Quaternion.LookRotation(hit.normal));
GameObject ceffect = Instantiate(bullethole, hit.point, Quaternion.LookRotation(hit.normal));
}
else
{
GameObject beffect = Instantiate(redblood, hit.point, Quaternion.LookRotation(hit.normal));
GameObject ceffect = Instantiate(bullethole, hit.point, Quaternion.LookRotation(hit.normal));
}
}
}
}
`
From the raycast hit information, we get the normal vector, which you're using to rotate the objects. We can use the same normal vector to 'nudge' the objects away from the hit point as well. An example piece of code might look something like this:
void PistolShoot ( )
{
if ( Physics.Raycast ( playercam.transform.position, playercam.transform.forward, out var hit ) )
{
if ( hit.transform.TryGetComponent<Enemy1> ( out var enemy ) )
enemy.Shot ( pistoldmg );
var rotation = Quaternion.LookRotation(hit.normal);
var beffect = Instantiate(redblood, hit.point + hit.normal * 0.01f, rotation );
var ceffect = Instantiate(bullethole, hit.point + hit.normal * 0.02f, rotation );
// .. are you using 'beffect' and 'ceffect' after this? There may not be a need to store these.
}
}
This will nudge the redblood object about "1 cm" away from the hit point, and the bullethole object about "2 cm" away from the hit point. This will likely need to be adjusted to suit your measurements, but if you've followed a one-to-one Unity unit to metre guide, then this will likely do the trick.
Note that some mobile phone use a lower precision when calculating positions, so you might need to increase this value to make it more pronounced.
Here's an example using a slightly exaggerated nudging amount - 0.05 and 0.1 instead of 0.01 and 0.02 - on a 1x1x1 cube.
I'm trying to check collision with Polygon collider using Raycast on my field in my Unity game. And then create crop on position of ray cast if conditions met by clicking button. Even though it checks collision perfectly i have a few issues that i just cant figure out how to fix. Like:
my shooter game object teleport on scene randomly, but raycasting is always correct O_o.
Instantiated crop disappear in moment of next instantiation...
Can some one help me to fix it? Here is the code:
public class PlayerRay : MonoBehaviour
{
float borderLeft = -4.34f;
float borderRight = 3.85f;
float borderUp = 1.61f;
float borderDown = -2.32f;
public GameObject field;
public GameObject shooter;
public Transform shooterPos;
PolygonCollider2D fieldCollider;
public GameObject repka;
private void Start()
{
fieldCollider = field.GetComponent<PolygonCollider2D>();
}
void Update()
{
}
public void Sow()
{
Vector3 rayCastPos = new Vector3(Random.Range(borderLeft, borderRight), Random.Range(borderDown, borderUp), 0);
shooter.transform.Translate(rayCastPos);
Debug.DrawRay(transform.position, transform.forward * 10, Color.yellow);
RaycastHit2D hit = Physics2D.Raycast(rayCastPos, Vector3.forward);
if (hit == fieldCollider)
{
Debug.Log("We hit collider");
Instantiate(repka, shooterPos);
}
else
{
Debug.Log("There is no colider at: " + rayCastPos);
}
}
}
enter image description here
I found solution! It's just that i tried to use Transform overload for instantiate instead of using Vector3. Because I forgot to add "rotation" as third parameter. So I switched to Vector3 overload, added Quaternion.identity for rotation and it's all works just fine now :)
Here is the fix:
Instantiate(repka, rayCastPos, Quaternion.identity);
I'm currently making a 2D game as a beginner and I made a spinning platform. But when it's rotating the player's rotation (z-axis) also changes because it's a child of the platform. I need this when I use moving platforms. Now I want to lock the z-axis of the rotation of the player. I already tried it in 3 different ways, but none of them seems to be working. Does anybody know how to do this?
These are the three ways I tried:
// 1
PlayerTrans.transform.Rotate(
PlayerTrans.transform.rotation.x,
PlayerTrans.transform.rotation.y,
0);
// 2
PlayerTrans.transform.Rotate(
PlayerTrans.transform.rotation.x,
PlayerTrans.transform.rotation.y,
0,
Space.Self);
// 3
PlayerTrans.transform.localRotation = Quaternion.Euler(new Vector3(
PlayerTrans.transform.localEulerAngles.x,
PlayerTrans.transform.localEulerAngles.y,
0f));
and this is, what my code looks like for staying on the moving platforms. I used raycasting for this:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Raycasting : MonoBehaviour
{
// Start is called before the first frame update
Transform PlayerTrans;
public float RayCastRange = 3;
void Start()
{
PlayerTrans = transform.parent;
}
// Update is called once per frame
void Update()
{
RaycastHit2D PlattformCheck = Physics2D.Raycast(transform.position, -Vector2.up, RayCastRange);
if (PlattformCheck.collider != null)
{
if (PlattformCheck.collider.gameObject.tag == "Platform")
{
PlayerTrans.transform.SetParent(PlattformCheck.collider.gameObject.transform);
}
else
{
PlayerTrans.transform.SetParent(null);
}
}
else
{
PlayerTrans.transform.SetParent(null);
}
}
}
There are 2 ways that might help you:
Just freeze the rotation from the inspector:
you can use some LookAt function (there is one for 3D but you can look and find ones for 2D) and just look at the camera.
(if you cant find it let me know and I will add it)
You should raycast directly down and then apply velocities to both objects (un-child the player from the platforms). You could do something like this for the player:
public LayerMask mask; //set ‘mask’ to the mask of the
//platform in the Unity Editor.
public Vector3 velocity;
void Update()
{
RaycastHit hit;
if (Physics.Raycast(transform.position, -Vector3.up, out hit, 0.1f, mask))
//0.1f is the distance to the platform to be able to be moved by the platform.
{
velocity = hit.collider.gameObject.GetComponent<Platform>().velocity;
}
float h = Input.GetAxis(“Horizontal”);
//this one is for CharacterController:
cc.Move(velocity);
//this one is for rigidbody:
rb.velocity = velocity;
velocity = 0;
}
It takes the velocity from the ‘Platform’ script and moves the player based on it. Now we should add the platform script. Call it ‘Platform’.
public Vector3 velocity;
public Vector3 a; //a and b are the two points you want the platform to go between.
public Vector3 b;
public float period = 2f; //the amount of seconds per cycle.
float cycles;
void Update()
{
cycles = Time.time / period;
float amplitude = Mathf.Sin(Mathf.PI * 2f * cycles);
Vector3 location = Vector3.Lerp(a, b, amplitude);
velocity = transform.position - location;
transform.position = velocity;
}
This script interpolates between the point a and b, then it finds the velocity and applies it. The player takes this velocity and it moves the player. Comment if you found an error.
I am having trouble getting the enemy's projectile to fly from the enemy to the player's position. When I play the game, the enemy bullet projectiles fly off in one direction on the screen and not toward the player. I think the issue might be in how I am assigning direction to the projectile prefab? Any suggestions would be much appreciated.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class EnemyController : MonoBehaviour
{
public float speed;
public Rigidbody enemyRb;
[SerializeField] float rateOfFire;
private GameObject player;
public GameObject projectilePrefab;
float nextFireAllowed;
public bool canFire;
Transform enemyMuzzle;
void Awake()
{
enemyRb = GetComponent<Rigidbody>();
player = GameObject.Find("Player");
enemyMuzzle = transform.Find("EnemyMuzzle");
}
void Update()
{
//move enemy rigidbody toward player
Vector3 lookDirection = (player.transform.position - transform.position).normalized;
enemyRb.AddForce(lookDirection * speed);
//overallSpeed
Vector3 horizontalVelocity = enemyRb.velocity;
horizontalVelocity = new Vector3(enemyRb.velocity.x, 0, enemyRb.velocity.z);
// turns enemy to look at player
transform.LookAt(player.transform);
//launches projectile toward player
projectilePrefab.transform.Translate(lookDirection * speed * Time.deltaTime);
Instantiate(projectilePrefab, transform.position, projectilePrefab.transform.rotation);
}
public virtual void Fire()
{
canFire = false;
if (Time.time < nextFireAllowed)
return;
nextFireAllowed = Time.time + rateOfFire;
//instantiate the projectile;
Instantiate(projectilePrefab, enemyMuzzle.position, enemyMuzzle.rotation);
canFire = true;
}
}
It looks like what is actually happening is that you create a bunch of bullets but don't store a reference to them. So each bullets sits in one place while the enemy moves closer to the player ( which might give the appearance that the bullets are moving relative to the enemy. ) I also assume the enemy is moving very fast since it is not scaled by delta time but is being updated every frame.
I think projectilePrefab is just the template object you're spawning, so you probably don't want to move it directly and you certainly don't want to instantiate a new bullet every frame.
If you want to move the object you spawned the least changes ( but still problematic ) from your example code might be:
public class EnemyController : MonoBehaviour
{
// add a reference
private GameObject projectileGameObject = null;
void Update()
{
//Update position of spawned projectile rather than the template
if(projectileGameObject != null ) {
projectileGameObject.transform.Translate(lookDirection * speed * Time.deltaTime);
}
// Be sure to remove this extra instantiate
//Instantiate(projectilePrefab, transform.position, projectilePrefab.transform.rotation);
}
public virtual void Fire()
{
//instantiate the projectile
projectileGameObject = Instantiate(projectilePrefab, enemyMuzzle.position, enemyMuzzle.rotation);
}
}
Or keep multiple bullets in a list. This implementation has the bug that it will always use the current enemy to player vector as the direction rather than the direction that existed when it was fired.
What you will probably want eventually is that each projectile is has it's own class script to handle projectile logic. All the enemyController class has to do is spawn the projectile and sets it's direction and position on a separate monobehavior that lives on the Projectile objects that handles it's own updates.
everyone! I am new to Unity and try to create a 2D arcade game by allowing my character to jump up at a trajectory motion to reach something then fall down. I use gravity scale equal to 1 and move_speed 1000 and rest_speed 500 but as soon as I hit space, the character just fell down instead of going up.
Also, walk.IsWalk is an int from Walking class(as soon as I hit right arrow, set IsWalk to 2 for example). My expected result would be as soon as we hold both space and right arrow key, the character should move upwards follow a curved motion. I dont know what is going on here, can anyone kindly point me to a direction? Thanks!
My code as follows:
using UnityEngine;
using System.Collections;
public class Jumping : MonoBehaviour
{
Rigidbody2D rb2D;
Animator anim;
Walking walk = new Walking();
public float move_speed;
public float rest_speed;
void Start()
{
rb2D = GetComponent<Rigidbody2D>();
anim = GetComponent<Animator>();
}
void FixedUpdate()
{
//float xmove = Input.GetAxis("Horizontal");
//float ymove = Input.GetAxis("Vertical");
//var curr = new Vector2(xmove, ymove);
if (Input.GetKey("space"))
{
anim.SetTrigger("JumpButtonPres");
rb2D.gravityScale = 1;
if (walk.isWalk == 2)
{
rb2D.AddForce(rb2D.position * move_speed);
}
else if (walk.isWalk == 1)
{
//rb2D.velocity += (Vector2.up * (-rb2D.velocity.x));
rb2D.AddForce(-rb2D.position * move_speed);
}
else
{
rb2D.AddForce(rb2D.position * rest_speed);
}
}
}
}
partial code for rigidbody2D.AddForce
It seems your problem is that whenever you are adding force to your rigidbody, you are multiplying it by the position where it's located, so by this i'm guessing your character is placed at a negative y component coordenate, and this is why rb2D.position * rest_speed will result on your playing falling. Change it for vector2.up * rest_speed and you should be fine.
Hope I was able to help.
Noé