I wrote a code for an enemy that, when he sees my character, will chase him. But when he sees my character and chases him, he goes through objects.There is a box collider 2D on it, but it moves with it. I've already tried everything, I don't know how to fix it. Can you please help fix
Here is my code:
void Start()
{
player = GameObject.FindGameObjectWithTag("Player").transform;
idleSpeed = speed;
barDelta = Vector3.Distance(parent.position, barPoint.position);
bar = UIManager.AddEnemy(this);
}
void Update()
{
if (Vector2.Distance(transform.position, point.position) < positionOfPatrol && angry == false)
{
idle = true;
}
if (Vector2.Distance(transform.position, player.position) < stoppingDistance)
{
angry = true;
idle = false;
goBack = false;
}
if (Vector2.Distance(transform.position, player.position) > stoppingDistance)
{
goBack = true;
angry = false;
}
if (idle == true)
{
Idle();
}
else if (angry == true)
{
Angry();
}
else if (goBack == true)
{
GoBack();
}
}
void Idle()
{
if (transform.position.x > point.position.x + positionOfPatrol)
{
moveingRight = false;
}
else if (transform.position.x < point.position.x - positionOfPatrol)
{
moveingRight = true;
}
if (moveingRight)
{
if (!facingRight) Flip();
facingRight = true;
transform.position = new Vector2(transform.position.x + speed * Time.deltaTime, transform.position.y);
}
else
{
if (facingRight) Flip();
facingRight = false;
transform.position = new Vector2(transform.position.x - speed * Time.deltaTime, transform.position.y);
}
}
void Angry()
{
transform.position = Vector2.MoveTowards(transform.position, player.position, speed * Time.deltaTime);
speed = idleSpeed + 1;
}
void GoBack()
{
transform.position = Vector2.MoveTowards(transform.position, point.position, speed * Time.deltaTime);
speed = idleSpeed;
}
}
You should try to use a rigidbody with the collider. The collider does not actually do physics, that is what the rigidbody is for. If you add a rigidbody and set its velocity instead of setting the transform's position, it will not only detect collisions with walls but it will stop moving and do all of the physics you would expect.
Related
so I have a script that rotates a cube (by 90 degrees when a direction is pressed) currently im using the oncollision enter to detect walls and when I try to use it to also check if grounded then it will just completely stop everything when i leave one collision and enter another, or it won't fully check when im in mid air and will allow me to move when i don't want to be able to. Any and all help is greatly appreciated.
{
bool isGrounded = true;
private Rigidbody2D rb;
bool leftInput = true;
bool rightInput = true;
public float RollingDuration = 0.2f;
// Start is called before the first frame update
void Start()
{
rb = GetComponent<Rigidbody2D>();
}
// fixed update is for physics
void FixedUpdate()
{
var dir = Vector3.zero;
if (Input.GetKey(KeyCode.LeftArrow) && leftInput && isGrounded)
{
dir = Vector3.left;
}
if (Input.GetKey(KeyCode.RightArrow) && rightInput && isGrounded)
{
dir = Vector3.right;
}
if (dir !=Vector3.zero && !isRolling)
{
StartCoroutine(Roll(dir));
}
}
private void OnCollisionEnter2D(Collision2D collision)
{
//check to see if our player is grounded
if (collision.gameObject.tag == "Grounded")
{
isGrounded = true;
}
if (collision.gameObject.tag == "LeftWall" || collision.gameObject.tag == "RightWall")
{
StopCoroutine("Roll");
if (collision.gameObject.tag == "LeftWall")
{
leftInput = false;
// we are grounded when touching walls
isGrounded = true;
}
if (collision.gameObject.tag == "RightWall")
{
rightInput = false;
// we are grounded when touching walls
isGrounded = true;
}
if (collision.gameObject.tag == null)
{
isGrounded = false;
}
else
{
isRolling = false;
rb.velocity = Vector2.zero;
rb.velocity = new Vector2(0.0f, 0.0f);
rb.angularVelocity = 0.0f;
rb.transform.rotation = Quaternion.Euler(0.0f, 0.0f, 0.0f);
rb.rotation = 0.0f;
}
}
}
bool isRolling = false;
IEnumerator Roll(Vector3 direction)
{
if (direction == Vector3.right && isGrounded)
{
leftInput = true;
}
else if (direction == Vector3.left && isGrounded)
{
rightInput = true;
}
isRolling = true;
var rotAxis = Vector3.Cross(Vector3.up, direction);
var pivot = (rb.transform.position + Vector3.down * 0.5f) + direction * 0.5f;
var startRotation = rb.transform.rotation;
var endRotation = Quaternion.AngleAxis(90.0f, rotAxis) * startRotation;
var startPosition = rb.transform.position;
var endPosition = rb.transform.position + direction;
var rotSpeed = 90.0f / RollingDuration;
var t = 0.0f;
while (t < RollingDuration && isGrounded)
{
t += Time.deltaTime;
if (t < RollingDuration && isGrounded)
{
rb.transform.RotateAround(pivot, rotAxis, rotSpeed * Time.deltaTime);
yield return null;
}
else
{
rb.transform.rotation = endRotation;
rb.transform.position = endPosition;
}
}
isRolling = false;
}
}
I think the most simple and common way to do ground checks is with casting a ray. So just cast a ray into the direction you want to check or try Overlap functions.
Example:
if(Physics.OverlapCircle(point, radius, layerMask)) {
//do stuff
}
So just cast a ray in all direction you want to check or add a overlap function to each side of the cube.
I am new to coding. I've been trying to Frankenstein basic tutorials into something of my own and it seems ive finally hit a wall. I'm really not sure what is causing this and would like some help to weed out the problem.
at the moment when I press the dash button (left shift) my character dashes in the direction he is facing but for a random duration. I would like it to be consistent and working properly.
Thanks in advance!
PS: Sorry for the long script, it contains everything to do with player movment.
using System.Collections;
using System.Collections.Generic;
using System.Security.Cryptography;
using UnityEngine;
public class CharacterController : MonoBehaviour
{
//Player Movement
public float speed;
public float jumpForce;
public Transform feetPos;
public float checkRadius;
public LayerMask whatIsGround;
public float dashSpeed;
public float startDashTime;
public float dashCooldownTime = 2;
private float nextFireTime = 0;
public Animator animator;
private Rigidbody2D rb;
private float moveInput;
private bool isGrounded;
private float jumpTimeCounter;
public float jumpTime;
private bool isJumping;
private float dashTime;
public int direction;
void Start()
{
animator.GetComponent<Animator>();
rb = GetComponent<Rigidbody2D>();
dashTime = startDashTime;
}
void FixedUpdate()
{
moveInput = Input.GetAxisRaw("Horizontal");
if (direction < 1 )
rb.velocity = new Vector2(moveInput * speed, rb.velocity.y);
}
void Update()
{
// Moving
isGrounded = Physics2D.OverlapCircle(feetPos.position, checkRadius, whatIsGround);
if (moveInput > 0)
{
transform.eulerAngles = new Vector3(0, 0, 0);
animator.SetBool("Moving", true);
}
else if (moveInput < 0)
{
transform.eulerAngles = new Vector3(0, 180, 0);
animator.SetBool("Moving", true);
}
else
{
animator.SetBool("Moving", false);
}
// Jumping
if (isGrounded == true && Input.GetKeyDown(KeyCode.Space))
{
animator.SetTrigger("IsJumping");
isJumping = true;
jumpTimeCounter = jumpTime;
rb.velocity = Vector2.up * jumpForce;
}
if (Input.GetKey(KeyCode.Space) && isJumping == true)
{
if (jumpTimeCounter > 0)
{
rb.velocity = Vector2.up * jumpForce;
jumpTimeCounter -= Time.deltaTime;
}
else
{
isJumping = false;
}
}
if (Input.GetKeyUp(KeyCode.Space))
{
isJumping = false;
}
if (isGrounded == false)
{
animator.SetBool("Grounded", false);
}
if (isGrounded == true)
{
animator.SetBool("Grounded", true);
}
// Dashing
if (Time.time > nextFireTime)
{
if (direction == 0)
{
if (Input.GetKeyDown(KeyCode.LeftShift))
{
UnityEngine.Debug.Log("beaners");
nextFireTime = Time.time + dashCooldownTime;
if ((transform.rotation.eulerAngles.y == 180))
{
Dashleft();
}
else
{
DashRight();
}
}
}
}
else
{
if(dashTime <= 0)
{
direction = 0;
dashTime = startDashTime;
}
else
{
dashTime -= Time.deltaTime;
}
}
}
void Dashleft()
{
direction = 1;
rb.velocity = Vector2.left * dashSpeed;
}
void DashRight()
{
direction = 1;
rb.velocity = Vector2.right * dashSpeed;
}
}
Random duration is because of the use of Rigidbody2D.
See in Unity Rigidbody2D is responsible for each and every single physical interaction. It mean forces from player like player movement and forces from your environment like friction and collision.
Here what is happening is that when your player is dashing there is also player movement force, which is also applied on your player's Rigidbody2d. And friction of ground on which your player is running/dashing on.
I've added a comment on parts that I've changed.
Updated part of your script:
private bool isDashing;
.
.
.
void Update()
{
//Added: putting a Condition to check if you player is not dashing, if it is then
//player won't be able to do anything, As I've scene and done in many games. if you
//don't want this remove it and see what happens, this is not tested so sorry if there
//is something that is not working as intended.
//dashing condition check
if(!isDashing)
{
// Moving
isGrounded = Physics2D.OverlapCircle(feetPos.position, checkRadius, whatIsGround);
if (moveInput > 0)
{
transform.eulerAngles = new Vector3(0, 0, 0);
animator.SetBool("Moving", true);
}
else if (moveInput < 0)
{
transform.eulerAngles = new Vector3(0, 180, 0);
animator.SetBool("Moving", true);
}
else
{
animator.SetBool("Moving", false);
}
// Jumping
if (isGrounded == true && Input.GetKeyDown(KeyCode.Space))
{
animator.SetTrigger("IsJumping");
isJumping = true;
jumpTimeCounter = jumpTime;
//Changed: use Add force method instead of changing the velocity.
rb.AddForce(Vector2.up * jumpForce, ForceMode2D.Impulse);
//rb.velocity = Vector2.up * jumpForce;
}
if (Input.GetKey(KeyCode.Space) && isJumping == true)
{
if (jumpTimeCounter > 0)
{
//Changed: Same this rb.AddForce...
rb.AddForce(Vector2.up * jumpForce, ForceMode2D.Impulse);
//rb.velocity = Vector2.up * jumpForce;
jumpTimeCounter -= Time.deltaTime;
}
else
{
isJumping = false;
}
}
if (Input.GetKeyUp(KeyCode.Space))
{
isJumping = false;
}
if (isGrounded == false)
{
animator.SetBool("Grounded", false);
}
if (isGrounded == true)
{
animator.SetBool("Grounded", true);
}
}
//dashing condition ends
// Dashing
if (Time.time > nextFireTime)
{
//Here your Dash timer ends.
isDashing = false;
if (direction == 0)
{
if (Input.GetKeyDown(KeyCode.LeftShift))
{
UnityEngine.Debug.Log("beaners");
nextFireTime = Time.time + dashCooldownTime;
//Here your Dash timer Starts.
isDashing = true;
if ((transform.rotation.eulerAngles.y == 180))
{
Dashleft();
}
else
{
DashRight();
}
}
}
}
else
{
if(dashTime <= 0)
{
direction = 0;
dashTime = startDashTime;
}
else
{
dashTime -= Time.deltaTime;
}
}
}
visit Unity - Scripting API: Rigidbody2D.AddForce hope it helps.
Happy Coding
I am creating a clone of Billiards and I cannot work out how to stop the player from interacting with and launching the ball while it is still moving; below is my attempt. I have placed an if statement that checks whether the ball is moving on both the mouseDrag and mouseUp functions. I have also tried using isSleeping() but this caused the ball to not move at all.
If possible I would like to apply this method to all of the balls and not just the cue ball; so that all balls have to have stopped before any actions may happen. This is currently in my "player" script, if I should move it a GameManager script please let me know.
private void Update()
{
speed = rb.velocity.magnitude;
if (speed < 0.5)
{
rb.velocity = new Vector3(0, 0, 0);
}
}
void OnMouseDrag()
{
if (speed == 0)
{
mousePointB.GetComponent<SpriteRenderer>().enabled = true;
currDistance = Vector3.Distance(mousePointA.transform.position, transform.position);
if (currDistance <= 3f)
{
spaceLimit = currDistance;
}
else
{
spaceLimit = maxDistance;
}
shootPower = Mathf.Abs(spaceLimit) * shootPowervar;
Vector3 dimxy = mousePointA.transform.position - transform.position;
float difference = dimxy.magnitude;
mousePointB.transform.position = transform.position + ((dimxy / difference) * currDistance * -1);
mousePointB.transform.position = new Vector3(mousePointB.transform.position.x, mousePointB.transform.position.y, -0.8f);
shootDirection = Vector3.Normalize(mousePointA.transform.position - transform.position);
}
else
{
}
}
void OnMouseUp()
{
if (speed == 0)
{
mousePointB.GetComponent<SpriteRenderer>().enabled = false;
arrow.GetComponent<SpriteRenderer>().enabled = false;
circle.GetComponent<SpriteRenderer>().enabled = false;
Vector3 push = shootDirection * shootPower * -1;
GetComponent<Rigidbody2D>().AddForce(push, ForceMode2D.Impulse);
}
else
{
}
}
if your test speed == 0 is not functional, you could record the last position of the ball, and set a boolean isMoving = true, if actual position of ball is different thant the last, then record the lastposition and so on
Vector3 LastPosition;
bool isMoving;
void Update()
{
isMoving = BallPosition == LastPosition;
:
:
}
void OnMOuseDrag()
{
if(!isMoving) return;
}
void OnMOuseUp()
{
if(!isMoving) return;
}
I made a controller for a 2d character, I fixed the issue of the player jittering through the wall but I cant fix the player jittering through the ground. Got this code from multiple tutorials and tweaking stuff. If you have any tips that would be greatly appreciated I'm new to this stuff and working on my first game (had to ramble cuz I put too much code) thanks.
{
public float speed, height;
Rigidbody2D rb;
private bool horizontalRight = false;
private bool horizontalLeft = false;
private bool verticalMove = false;
private void Start()
{
rb = GetComponent<Rigidbody2D>();
}
void Update()
{
if (Input.GetAxisRaw("Horizontal") > 0)
{
horizontalRight = true;
}
else if (Input.GetAxisRaw("Horizontal") < 0)
{
horizontalLeft = true;
}
if (Input.GetButton("Jump") && rb.velocity.y == 0)
{
verticalMove = true;
}
}
private void FixedUpdate()
{
if (horizontalRight == true)
{
transform.Translate(Vector2.right * Time.deltaTime * speed);
horizontalRight = false;
}
else if (horizontalLeft == true)
{
transform.Translate(Vector2.left * Time.deltaTime * speed);
horizontalLeft = false;
}
if (verticalMove == true)
{
rb.velocity = new Vector2(0, height);
verticalMove = false;
}
}
}
Activate continuous collision detection on your rigid bodies, it'll keep them from phasing through things so long as they're being moved via their velocity.
A typical jump in unity would look like:
void Jump()
{
if (_isGrounded == true)
{
rb.AddForce(Vector2.up * _jumpSpeed);
_isGrounded = false;
}
}
and in collision event
void OnCollisionEnter (Collision hit)
{
_isGrounded = true;
}
this would limit when you can use a jump.
I cannot seem to find a way to collide the player with objects that are supposed to stop the player. For example, when I move the player up to a wall of trees, it just moves through them (and bounces away from the grid alignment slightly) like the player were a ghost.
And below is the code I'm using as far as Player's movement is concerned:
using System.Collections;
using UnityEngine;
public class PlayerMovement : Character {
Direction currentDir;
Vector2 input;
bool IsMoving = false;
Vector3 startpos;
Vector3 endpos;
float t;
public Sprite upsprite;
public Sprite rightsprite;
public Sprite downsprite;
public Sprite leftsprite;
public float walkSpeed = 3f;
public bool isAllowedToMove = true;
private Rigidbody2D myRB;
void Start()
{
isAllowedToMove = true;
myRB = GetComponent<Rigidbody2D>();
}
// Update is called once per frame
protected override void Update () {
if (! IsMoving && isAllowedToMove) {
input = new Vector2(Input.GetAxis("Horizontal"), Input.GetAxis("Vertical"));
if (Mathf.Abs(input.x) > Mathf.Abs(input.y))
input.y = 0;
else
input.x = 0;
if (input != Vector2.zero) {
if (input.x < 0) {
currentDir = Direction.Left;
}
if (input.x > 0) {
currentDir = Direction.Right;
}
if (input.y < 0) {
currentDir = Direction.Down;
}
if (input.y > 0) {
currentDir = Direction.Up;
}
switch (currentDir) {
case Direction.Up:
gameObject.GetComponent<SpriteRenderer>().sprite = upsprite;
break;
case Direction.Right:
gameObject.GetComponent<SpriteRenderer>().sprite = rightsprite;
break;
case Direction.Down:
gameObject.GetComponent<SpriteRenderer>().sprite = downsprite;
break;
case Direction.Left:
gameObject.GetComponent<SpriteRenderer>().sprite = leftsprite;
break;
}
StartCoroutine (Move (transform));
}
myRB.velocity = new Vector2 (Input.GetAxisRaw ("Horizontal") * walkSpeed, myRB.velocity.y);
myRB.velocity = new Vector2 (myRB.velocity.x, Input.GetAxisRaw ("Vertical") * walkSpeed);
if (Input.GetAxisRaw ("Horizontal") < 0.5f && Input.GetAxisRaw ("Horizontal") > -0.5f)
{
myRB.velocity = new Vector2 (0f, myRB.velocity.y);
}
if (Input.GetAxisRaw ("Vertical") < 0.5f && Input.GetAxisRaw ("Vertical") > -0.5f)
{
myRB.velocity = new Vector2(myRB.velocity.y, 0f);
}
}
base.Update ();
}
public IEnumerator Move(Transform entity)
{
IsMoving = true;
startpos = entity.position;
t = 0;
endpos = new Vector3(startpos.x + System.Math.Sign(input.x), startpos.y + System.Math.Sign(input.y), startpos.z);
while(t < 1f)
{
t += Time.deltaTime * walkSpeed;
entity.position = Vector3.Lerp(startpos, endpos, t);
yield return null;
}
IsMoving = false;
yield return 0;
}
}
enum Direction
{
Up,
Right,
Down,
Left
}
Other things to note are that I made sure to use Rigidbody2D and Box Collider2D components, and I made sure to make the Gravity scale 0 for the player and froze the rotation from the Z axis. Also, I did use Tiled and Tiled2Unity extensions to create the tiles you see in game, despite the preinstalled tilemap assets being a decent choice to create 2d game worlds.
Forgive me if it seems too long, but I can't seem to figure out what the problem is with the collision detection. Can anyone help?