What is making the player character fall sharply - c#

I'm currently getting an issue when my player sprite falls off the land. When I press the 'right arrow' to move horizontally, the sprite suddenly accelerates downwards really fast. I think it is something with the left and right movement but I am unsure if it is the culprit and what the better solution is.
The main portion that I think is causing this issue is this line:
controller.velocity = controller.velocity + new Vector2(horizontal * speed, controller.velocity.y);
I copied this code from a unity forum and at the time it made sense but I believe it is a culprit. If it is, please could you educate on the better solution.
Please let me know if I should include anything else!
Project settings
The y gravity for the project is set to '-9.81'
Player Sprite Object (picture 1)
(picture 2)
Player class (attached to player sprite)
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Player_script : MonoBehaviour
{
Animator animator = null;
Rigidbody2D controller = null;
SpriteRenderer sprite_renderer = null;
bool walking = false;
bool jumping = false;
int speed = 2;
int jumpSpeed = 200;
const int RIGHT = 1;
const int LEFT = 0;
int direction = RIGHT;
// Start is called before the first frame update
void Start()
{
animator = gameObject.GetComponent<Animator>();
controller = gameObject.GetComponent<Rigidbody2D>();
sprite_renderer = gameObject.GetComponent<SpriteRenderer>();
controller.velocity = Vector3.down * speed;
//Physics.gravity = new Vector3(0, -11.0f, 0);
//controller.AddForce(Vector3.down * 2);
}
// Update is called once per frame
void Update()
{
animate();
//fall
//controller.AddForce(Physics.gravity + (new Vector3(0,-150) * 3), ForceMode2D.Force);
}
void FixedUpdate()
{
//controller.AddForce(Physics.gravity + (new Vector3(0, -150) * 3), ForceMode2D.Force);
//controller.AddForce(Vector3.down * 2);
float horizontal = Input.GetAxis("Horizontal");
float veritical = Input.GetAxis("Vertical");
if (horizontal > 0f)
{
controller.velocity = controller.velocity + new Vector2(horizontal * speed, controller.velocity.y);
walking = true;
if (direction != RIGHT)
{
flipPlayer();
}
}
else if (horizontal < 0f)
{
controller.velocity = controller.velocity + new Vector2((horizontal * speed), controller.velocity.y);
walking = true;
if (direction != LEFT)
{
flipPlayer();
}
}
else
{
walking = false;
}
//jump
if (isGrounded() && veritical > 0f)
{
controller.velocity = controller.velocity + new Vector2(0, veritical * jumpSpeed);
walking = false;
jumping = true;
Debug.Log("Jumping");
}
else
{
jumping = false;
Debug.Log("Not Jumping");
}
}
void animate()
{
if (walking)
{
animator.Play("player_animation");
}
else
{
animator.Play("Idle");
}
}
void flipPlayer() {
if(direction == RIGHT)
{
direction = LEFT;
sprite_renderer.flipX = true;
}
else
{
direction = RIGHT;
sprite_renderer.flipX = false;
}
}
void Jump() { }
bool isGrounded()
{
float raycastDistance = 0.5f;
RaycastHit2D hit = Physics2D.Raycast(transform.position, -Vector2.up, raycastDistance);
if (hit.collider != null && hit.transform.gameObject.layer == LayerMask.NameToLayer("landscapes")) {
return true;
}
return false;
}
}

So the problem you are experiencing is in fact due to the line you were quoting
controller.velocity = controller.velocity + new Vector2(horizontal * speed, controller.velocity.y);
In the Y direction, you are adding the controllers velocity to itself and therefore its Y velocity becomes exponential.
If you wish to override your characters velocity, you should use
controller.velocity = new Vector2(horizontal * speed, controller.velocity.y);
If you wish to add a force to your current velocity, you could do so through code with
controller.velocity = controller.velocity + new Vector2(horizontal * speed * Time.deltaTime, 0);
or by using Rigibody.AddForce(Vector3) with
controller.AddForce(new Vector2(horizontal*speed,0));

Related

UNITY C#..my enemys are piling up with vector2.move towards

hi there thanks for taking the time to look at my question
im currenty making a 2D side scroller/platformer and im currently facing a issue where my enemies are piling up on top of each other. through googling i see alot of Astar pathfinding solving this however i hesitant to jump into ai right now as i glanced over its internal scripts and they are outside my current knowledge and im still attempting to get a understanding of just using scripting to achieve what i want.
i currently have my enemies correctly chasing my player with a vector2.movetowards however eventually they all pile on each other.
through google i have found this is a typical outcome of movetowards and i found this solution
https://answers.unity.com/questions/1608266/stop-enemies-from-grouping-up.html
and i implemented its code
void avoidOthers()
{
var hits = Physics2D.OverlapCircleAll(enemy.transform.position, avoidenceRadius);//create a circle around each enemy and check to see if they are not colliding
foreach (var hit in hits)
{
if(hit.GetComponent<DartFish>() != null && hit.transform != transform)//check to see if it is a enemy
{
Debug.Log("enemy transform" + enemy.transform.position);
Debug.Log("hit transform" + hit.transform.position);
Vector2 difference = enemy.transform.position - hit.transform.position;//check how close we are to another enemy
difference = difference.normalized / Mathf.Abs(difference.magnitude);//calculate how long the vector is
sum += difference;//add together differences so we can calculate a average of the group
count++;
}
}
if(count > 0)// if we found enemys interfearing with each other
{
sum /= count;//average of the movement
sum = sum.normalized * avoidenceSpeed;//calculate movement speed
Debug.Log("sum = " + sum);
enemy.transform.position = Vector2.MoveTowards(enemy.transform.position, enemy.transform.position + (Vector3)sum, avoidenceSpeed * Time.deltaTime);
}
}
however i needed to add "enemy" to each transform.position or they would instantly snap from my spawn location to the player.
after adding enemy they stopped snapping over a large distance except now they started piling again
all of my debug logs look like they are printing out the correct values
i was also reading through transform.translate as looking at my "sum" values this should be how much they are moving away from each other
so i changed the line
enemy.transform.position = Vector2.MoveTowards(enemy.transform.position, enemy.transform.position + (Vector3)sum, avoidenceSpeed * Time.deltaTime);
to
transform.Translate((Vector3)sum * avoidenceSpeed * Time.deltaTime, Space.World);
now it seems to only effect one fish and the others clump together still
from my understanding physics.overlapcircle all should be functioning as a list?
heres my entire code albeit long(still relatively new to coding)
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class DartFish : MonoBehaviour
{
public Transform target;
public float movementSpeed;
private float initialMovementSpeed;
public float dashSpeed;
private float spawnSpeed = 1.5f;
public float chaseRadius;
private float initialChaseRadius;
public float dashRadius;
private Vector2 targetDirection;
private float directionX;
private float previousDirectionX;
private float directionY;
private float spriteAngle;
private float previousAngle;
private float currentSpriteAngle;
private float difference;
private SpriteRenderer mySpriteRenderer;
private Rigidbody2D myRigidbody;
private bool directionIsAboutToChange;
private bool directionHasChanged;
private Vector3 angleCompensation;
// avoid others variables
public float avoidenceSpeed;
public float avoidenceRadius;
public Transform enemy;
private Vector2 sum = Vector2.zero;
private float count;
// Start is called before the first frame update
void Start()
{
enemy = GameObject.FindWithTag("dartfish").transform;
target = GameObject.FindWithTag("Player").transform;
mySpriteRenderer = GetComponent<SpriteRenderer>();
myRigidbody = GetComponent<Rigidbody2D>();
initialMovementSpeed = movementSpeed;
initialChaseRadius = chaseRadius;
}
// Update is called once per frame
void Update()
{
targetDirection = target.position - transform.position;// where is the player?
directionX = targetDirection.x;//extract only x for "check direction"
directionY = targetDirection.y;
if(directionX < -initialChaseRadius + .5f)// is the player further then the chase radius?
{
myRigidbody.velocity = new Vector2(-1.5f, 0);
}
else
{
myRigidbody.velocity = Vector2.zero;
}
if(directionX > 0)//calculate tangent angle to the player in radians and then convert it to degrees
{
spriteAngle = Mathf.Atan2(targetDirection.y, targetDirection.x) * Mathf.Rad2Deg;
}
else if(directionX < 0)//if player is to the left flip opp/adj and add 100° to zero angle
{
spriteAngle = Mathf.Atan2(targetDirection.x, targetDirection.y) * Mathf.Rad2Deg +100f;
}
currentSpriteAngle = spriteAngle;
difference = spriteAngle - previousAngle;
difference = Mathf.Abs(difference);
if(directionX < 1 && directionX > -1)//are we about to change directions?
{
//Debug.Log("direction is about to change");
directionIsAboutToChange = true;
}
if(directionIsAboutToChange == true)//did we pass through trigger zone?
{
if(directionX > 1 || directionX < -1)
//Debug.Log("direction has changed");
directionHasChanged = true;
}
lookAtMe();
chaseMe();
avoidOthers();
/*
//debug logs with spam control
if(previousAngle != spriteAngle)
{
Debug.Log("angle = " + spriteAngle);
}
if(difference != 0)
{
Debug.Log("difference = " + difference);
}
if(previousDirectionX != directionX)
{
Debug.Log("directionX = " + directionX);
}
if(previousAngle != currentSpriteAngle)
{
Debug.Log("previous angle = " + previousAngle);
}
*/
previousAngle = currentSpriteAngle;
previousDirectionX = directionX;
}
void lookAtMe()
{
if(directionHasChanged == true)//angle compensation for sprite flip
{
if(directionY > 0)//is the player above or below us
{
angleCompensation = transform.localEulerAngles;//get current rotation
//flip it
if(directionX > 0)
{
transform.localEulerAngles = -angleCompensation;
}
if(directionX < 0)
{
transform.localEulerAngles = angleCompensation;
}
}
if(directionY < 0)
{
if(directionX > 0)
{
transform.localEulerAngles = angleCompensation;
}
if(directionX < 0)
{
transform.localEulerAngles = -angleCompensation;
}
}
directionHasChanged = false;
directionIsAboutToChange = false;
}
if(directionX < -1)
{
mySpriteRenderer.flipX = true;
//Debug.Log("entered void lookAtMe.directionX <");
if(spriteAngle > previousAngle && spriteAngle < 50f )
{
transform.Rotate(0f, 0f, -difference);
}
else if(spriteAngle < previousAngle && spriteAngle > -50f)
{
transform.Rotate(0f, 0f, difference);
}
}
else if(directionX > 1)
{
mySpriteRenderer.flipX = false;
//Debug.Log("entered void lookAtMe.directionX >");
if(spriteAngle > previousAngle && spriteAngle < 50f)
{
transform.Rotate(0f, 0f, difference);
}
else if(spriteAngle < previousAngle && spriteAngle > -50f)
{
transform.Rotate(0f, 0f, -difference);
}
}
}
void avoidOthers()
{
var hits = Physics2D.OverlapCircleAll(enemy.transform.position, avoidenceRadius);//create a circle around each enemy and check to see if they are not colliding
foreach (var hit in hits)
{
if(hit.GetComponent<DartFish>() != null && hit.transform != transform)//check to see if it is a enemy
{
Debug.Log("enemy transform" + enemy.transform.position);
Debug.Log("hit transform" + hit.transform.position);
Vector2 difference = enemy.transform.position - hit.transform.position;//check how close we are to another enemy
difference = difference.normalized / Mathf.Abs(difference.magnitude);//calculate how long the vector is
sum += difference;//add together differences so we can calculate a average of the group
count++;
}
}
if(count > 0)// if we found enemys interfearing with each other
{
sum /= count;//average of the movement
sum = sum.normalized * avoidenceSpeed;//calculate movement speed
Debug.Log("sum = " + sum);
transform.Translate((Vector3)sum * avoidenceSpeed * Time.deltaTime, Space.World);
}
}
void chaseMe()
{
if(Vector3.Distance(target.position, transform.position) <= chaseRadius && Vector3.Distance(target.position, transform.position) > dashRadius)
{
transform.position = Vector3.MoveTowards(transform.position, target.position, movementSpeed * Time.deltaTime);
}
else if(Vector3.Distance(target.position, transform.position) <= dashRadius)
{
transform.position = Vector3.MoveTowards(transform.position, target.position, dashSpeed * Time.deltaTime);
}
}
}
please help me stop my enemys from clumping up without the use of AI
thanks again for any assistance and your time its much appreciated

Rotate Object Smoothly

i am trying to rotate object to 90 degrees smoothly on swipe here in my code its rotate instantly, how do i rotate object smoothly at given speed.
void Update()
{
if (fingerDown == false && Input.GetMouseButtonDown(0))
{
startPos = Input.mousePosition;
fingerDown = true;
}
if (fingerDown)
{
if (Input.mousePosition.x >= startPos.x + pixelDistToMove)
{
startPos = Input.mousePosition;
Vector3 rotationToAdd = new Vector3(0, 0, 90);
transform.Rotate(rotationToAdd);
fingerDown = false;
}
if (Input.mousePosition.x <= startPos.x - pixelDistToMove)
{
startPos = Input.mousePosition;
Vector3 rotationToAdd = new Vector3(0, 0, -90);
transform.Rotate(rotationToAdd);
fingerDown = false;
}
}
if (fingerDown && Input.GetMouseButtonUp(0))
{
fingerDown = false;
}
}
Thank you
transform.Rotate() rotates the object without animating it's rotation.
If you want it to rotate smoothly, you have to implement either an animation, or a turning state, or an IEnumerator.
My C# is a bit rusty, but I cooked this up:
public Vector3 desired_angle = Vector3.zero; // Turn the Gameobject to this angle
public float turn_time = 1f; // How long should turning take
public float rate = 60;
private void Update ()
{
if (Input.GetKeyDown(KeyCode.Space))
{
StartCoroutine(TurnTo());
}
}
IEnumerator TurnTo ()
{
Vector3 original_angle = transform.rotation.eulerAngles;
for (float i = 0f; i < 1f + turn_time / rate; i += turn_time / rate)
{
transform.rotation = Quaternion.Euler(Vector3.Lerp(original_angle, desired_angle, i));
yield return new WaitForSeconds(turn_time/rate);
}
}

Getting the right movement down

i want a karlson-esque movement for my game but i cant seem to nail it correctly, i basically want to add a force to the players base velocity just bieng tossed around in the game, like a velocity offset if you will,
for example if the player gets hit by a high velocity cube and tossed back naturally, they should struggle to regain thier stability and kind of come to a gradual halt assuming they are moving in the opposite direction than where they were being tossed, but my method (setting the players velocity) doesnt really work that well for what im trying to achieve, it simply comes to a semi-immediate halt, ive tried interpolation to make a gradual speed increase but input.getaxis and velocity both already somewhat cover that, anything more and the "coming to a halt" part works but movement isnt as snappy as i wish it was, here is my full code (note that i am somewhat of a beginner, ive done coding elsewhere but i just started unity a few weeks ago)
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class charactercontroller : MonoBehaviour {
//variables and functions
public float moveSpeed = 7f;
public bool tweening = false;
public bool jumping = false;
public bool reteleporing = false;
public Vector3 smoothedvel;
public Vector3 smoothedvectorweapon;
public float smoothedweaponspeed;
public Vector3 smoothedrotationalvector;
public Quaternion smoothedrotateweapon;
public Vector3 cameraoffset;
public float[] tweeninformation = {3f,5f,6f,7f,8f,9f,10f};
public float[] tweeninformationreverse = {10f,9f,8f,7f,6f,5f,3f};
void Start () {
cameraoffset = new Vector3(0,0,0);
smoothedvel = new Vector3(0,0,0);
smoothedrotateweapon = Quaternion.Euler(0,0,0);
smoothedweaponspeed = 0.1f;
smoothedvectorweapon = new Vector3(0.559f,0,-0.523f);
StartCoroutine(waiter());
}
IEnumerator waiter()
{
while(true)
{
if (new Vector3(Input.GetAxis("Vertical"),0,Input.GetAxis("Horizontal")).magnitude != 0 && Physics.Raycast(transform.position, -Vector3.up, gameObject.GetComponent<Collider>().bounds.extents.y + 0.3f) == true)
{
gameObject.GetComponent<ParticleSystem>().Emit(new ParticleSystem.EmitParams(), 3);
transform.GetChild(0).GetComponent<AudioSource>().pitch = Random.Range(1.0f,1.5f);
transform.GetChild(0).GetComponent<AudioSource>().Play();
}
yield return new WaitForSeconds(0.25f);
}
}
void Update (){
//movement
smoothedrotationalvector = Vector3.Lerp(smoothedrotationalvector, new Vector3(-Input.GetAxis("Vertical"),0,Input.GetAxis("Horizontal")), smoothedweaponspeed);
transform.GetChild(2).GetChild(0).transform.localPosition = Vector3.Lerp(transform.GetChild(2).GetChild(0).transform.localPosition, smoothedvectorweapon, smoothedweaponspeed);
transform.GetChild(2).GetChild(0).transform.localRotation = Quaternion.Lerp(transform.GetChild(2).GetChild(0).transform.localRotation, smoothedrotateweapon, smoothedweaponspeed);
if (new Vector3(Input.GetAxis("Vertical"),0,Input.GetAxis("Horizontal")).magnitude != 0)
{
transform.GetChild(2).transform.LookAt(transform.position + smoothedrotationalvector);
}
if (transform.position.y < -100)
{
reteleporing = true;
}
if (reteleporing == true)
{
transform.position = GameObject.Find("spawnpos").transform.position;
}
if (transform.position.y > 2.4)
{
reteleporing = false;
}
///if (Physics.Raycast(transform.position,transform.forward * Time.deltaTime * Input.GetAxis("Vertical"), gameObject.GetComponent<Collider>().bounds.extents.x + 0.3f) == false && reteleporing == false)
///{
/// transform.Translate(transform.forward * Time.deltaTime * Input.GetAxis("Vertical")* moveSpeed);
///}
///else
///{
// transform.Translate(transform.forward * Time.deltaTime * Input.GetAxis("Vertical")* 1);
//}
//if (Physics.Raycast(transform.position,transform.right * Time.deltaTime * Input.GetAxis("Horizontal"),gameObject.GetComponent<Collider>().bounds.extents.z + 0.3f) == false && reteleporing == false)
//{
// transform.Translate(transform.right * Time.deltaTime * Input.GetAxis("Horizontal")* moveSpeed);
//}
//else
//{
// transform.Translate(transform.right * Time.deltaTime * Input.GetAxis("Horizontal")* 1);
//}
if (reteleporing == false)
{
gameObject.GetComponent<Rigidbody>().velocity = Vector3.Lerp(gameObject.GetComponent<Rigidbody>().velocity,new Vector3(Input.GetAxis("Horizontal") * moveSpeed,gameObject.GetComponent<Rigidbody>().velocity.y,Input.GetAxis("Vertical") * moveSpeed), 0.1f);
}
//if (Physics.Raycast(transform.position, -Vector3.up, gameObject.GetComponent<Collider>().bounds.extents.y + 0.3f) == true)
//{
// gameObject.GetComponent<Rigidbody>().velocity = Vector3.Lerp(gameObject.GetComponent<Rigidbody>().velocity, new Vector3(0,0,0), 0.01f);
//}
//camera controlling
smoothedvel = Vector3.Lerp(smoothedvel, gameObject.GetComponent<Rigidbody>().velocity * 0.1f, 0.1f);
Camera maincam = GameObject. Find("Main Camera"). GetComponent<Camera>();
Vector3 camend = transform.position + new Vector3(Input.GetAxis("Horizontal") * 0.5f,0,0);
maincam.transform.position = transform.position + new Vector3(0, 4, -7f) + cameraoffset;
maincam.transform.LookAt(transform.position + smoothedvel);
//jumping
if (Input.GetKeyDown(KeyCode.Space))
{
if (Physics.Raycast(transform.position, -Vector3.up, gameObject.GetComponent<Collider>().bounds.extents.y + 0.3f) == true)
{
gameObject.GetComponent<Rigidbody>().AddForce(transform.up * 250);
moveSpeed = 9f;
}
}
if (Physics.Raycast(transform.position, -Vector3.up, gameObject.GetComponent<Collider>().bounds.extents.y + 0.3f) == false)
{
moveSpeed = 9f;
jumping = true;
}
else
{
moveSpeed = 7f;
if (jumping == true)
{
jumping = false;
transform.GetChild(1).GetComponent<AudioSource>().Play();
gameObject.GetComponent<ParticleSystem>().Emit(new ParticleSystem.EmitParams(), 4);
StartCoroutine(jumpanimwait());
IEnumerator jumpanimwait()
{
yield return new WaitForSeconds(0.2f);
}
}
}
//weapon
if (Input.GetKeyDown(KeyCode.Mouse0))
{
StartCoroutine(gunwait());
IEnumerator gunwait()
{
smoothedweaponspeed = 0.5f;
smoothedvectorweapon = new Vector3(-0.021f,0.172f,-0.523f);
smoothedrotateweapon = Quaternion.Euler(0,0,33.318f);
transform.GetChild(2).GetChild(0).GetComponent<ParticleSystem>().Emit(new ParticleSystem.EmitParams(), 2);
GameObject clone = Instantiate(GameObject.Find("bullet"), transform.position + transform.GetChild(2).transform.right * 2 + -transform.GetChild(2).transform.forward * 0.5f, Quaternion.Euler(0,0,0), transform.parent);
clone.GetComponent<Rigidbody>().constraints = RigidbodyConstraints.None;
transform.GetChild(2).GetChild(0).GetComponent<AudioSource>().Play();
clone.transform.LookAt(clone.transform.position + transform.GetChild(2).transform.right * 5 + -transform.GetChild(2).transform.forward * 0.5f );
clone.GetComponent<Rigidbody>().velocity = transform.GetChild(2).transform.right * 50;
Destroy(clone, 2);
yield return new WaitForSeconds(0.1f);
smoothedweaponspeed = 0.05f;
smoothedrotateweapon = Quaternion.Euler(0,0,0);
smoothedvectorweapon = new Vector3(0.559f,0,-0.523f);
}
}
}
}
i got it, it was a mixture of programming more movement tech for my controller and generally messing around with physics materials and rigidbody mass, also interpolation was pretty important in the process

Trying to making a ledge. The problem: transform.position always returns to vector( 0, 0)

I'm trying to make a method that lets players climb a ledge. I have two raycast one for Ledge and one for Wall detection. I the ledge is false, then climb the ledge.
Here comes the problem:
When the Wall check is true and the ledge Check is true, Set player transform.position to be near the ledge. Then afterward transform.position to be above the ledge. But for some reason whenever I try to call Set player transform.position near the ledge, it just teleports back to the default vector value 0, 0.
[Header("Ledge check")]
private bool canClimbLedge = false;
private bool ledgeDetected;
private Vector2 workspace;
//NEW SHIT
private Vector2 detectedPos;
private Vector2 cornerPos;
private Vector2 startPos;
private Vector2 stopPos;
[Header("Ledge Climb State")]
public Vector2 startOffset;
public Vector2 stopOffset;
private void FixedUpdate()
{ if (coll.isTouchingWall && !coll.isTouchingRightLedge || !coll.isTouchingLeftLedge)
{
SetDetectedPosition(transform.position);
}
}
void Update()
{
DetermineCornerPosition();
if (coll.onWall && !coll.isTouchingRightLedge)
CheckLedgeClimb();
if(canClimbLedge && coll.onGround)
FinishLedgeClimb();
if (dir.x < 0)
{
if (groundTouch == true && !wallGrab)
// dustParticle.Play();
if (wallGrab != true)
{
side = -1;
//anim.Flip(side);
}
}
if (dir.x > 0)
{
if (groundTouch == true && !wallGrab)
// dustParticle.Play();
if (wallGrab != true)
{
side = 1;
// anim.Flip(side);
}
}
}
public void SetDetectedPosition(Vector2 pos) => detectedPos = pos;
public Vector2 DetermineCornerPosition()
{
RaycastHit2D xHit = Physics2D.Raycast(coll.wallCheck.position, Vector2.right * side, coll.wallCheckDistance, coll.groundLayer);
float xDist = xHit.distance;
workspace.Set((xDist * side) * side, 0.015f);
RaycastHit2D yHit = Physics2D.Raycast(coll.ledgeCheck.position + (Vector3)(workspace), Vector2.down, coll.ledgeCheck.position.y - coll.wallCheck.position.y + 0.015f, coll.groundLayer);
float yDist = yHit.distance;
//Upper Corner Position of ledge
workspace.Set(coll.wallCheck.position.x + (xDist * side), coll.ledgeCheck.position.y - yDist);
return workspace;
}
private void CheckLedgeClimb()
{
if (coll.isTouchingWall && !coll.isTouchingRightLedge && !ledgeDetected)
{
ledgeDetected = true;
//Freeze player in the detectedPos
rb.velocity = Vector2.zero;
rb.gravityScale = 0f;
transform.position = detectedPos;
cornerPos = DetermineCornerPosition();
}
if(ledgeDetected && !canClimbLedge)
{
canClimbLedge = true;
startPos.Set(cornerPos.x - (side * startOffset.x), cornerPos.y - startOffset.y);
stopPos.Set(cornerPos.x + (side * stopOffset.x), cornerPos.y + stopOffset.y);
}
Debug.Log(startPos);
canMove = false;
transform.position = startPos;
canClimbLedge = true;
}
public void FinishLedgeClimb()
{
//Call the last part of climbing the ledge
}
In the Collision Script:
void FixedUpdate()
{
isTouchingWall = Physics2D.Raycast(wallCheck.position, transform.right, wallCheckDistance, groundLayer);
isTouchingRightLedge = isTouchingWall = Physics2D.Raycast(ledgeCheck.position, transform.right, wallCheckDistance, groundLayer);
}
Any help will be much appreciated, and if you have any other solution to make a ledge climber, I'm all ears.
I reevaluated the purpose was with the script.
The problem was Raycast was not really working correctly
And instead of making the raycast shoot in one direction, I made it follow change 180 degrees if the player was facing left.
And in my game, I didn't want the player to be able to hang from a ledge so the transform.position was removed.
Changes:
Collision Script:
isTouchingWall = Physics2D.Raycast(wallCheck.position, transform.right * move.side, wallCheckDistance, groundLayer);
isTouchingLedge = Physics2D.Raycast(ledgeCheck.position, transform.right * move.side, wallCheckDistance, groundLayer);
ClimbLedge Function:
private void CheckLedgeClimb()
{
if (coll.isTouchingWall && !coll.isTouchingLedge && !ledgeDetected)
{
//Reference point to startPos and stopPos
ledgeDetected = true;
//Freeze player in the detectedPos
rb.velocity = Vector2.zero;
rb.gravityScale = 0f;
transform.position = detectedPos;
cornerPos = DetermineCornerPosition();
Debug.Log("cornerPos Vector Value: " + cornerPos);
canClimbLedge = false;
}
if(ledgeDetected && !canClimbLedge)
{
//This part is only necessary if you want the player to hang from a ledge.
/*startPos.Set(cornerPos.x - (side * startOffset.x), cornerPos.y - startOffset.y);
stopPos.Set(cornerPos.x + (side * stopOffset.x), cornerPos.y + stopOffset.y);
Debug.Log("startPos when ledgeDetected + !canClimbLedge:" + startPos);
canMove = false;
transform.position = startPos;
rb.velocity = Vector2.zero;
rb.gravityScale = 0f;*/
stopPos.Set(cornerPos.x + (side * stopOffset.x), cornerPos.y + stopOffset.y);
rb.velocity = Vector2.zero;
rb.gravityScale = 0f;
canMove = false;
canClimbLedge = true;
}
}
public void FinishLedgeClimb()
{
if (canClimbLedge)
{
transform.position = stopPos;
canClimbLedge = false;
canMove = true;
ledgeDetected = false;
Debug.Log("transform.position = stopPos");
//anim.SetBool("canClimbLedge", canClimbLedge);
}
}
This is working, but the timing of when the player transform.position to the stopPos, is sometimes delayed.

How to stop player from pushing NPCs while moving

my problem today is simple (two problems if you count the fact that English isn't my first language), yet I can't manage to get a hold of it. I'm trying to make an up down game in c# and I'm trying to improve the movement scripts before working on anything else (since I don't want to resolve major bugs later).
The problem is that as soon as the player comes in contact with the NPC, it should stop moving in its general direction (it can move in 8 directions, using combinations of the W A S D keys). The NPC movement doesn't give any problems, it stops moving as soon as it perceives the player. Instead, when the player collides with the NPC it keeps on moving in that direction pushing it for what feels like half a second before stopping (as it should). So, to summarize, it doesn't immediately stop, which is unnerving since I've tried many things to make it stop (including freezing the position of the NPC but that just made things worse).
Now the codes:
The NPC movement code:
public class NPCFreeMovement : MonoBehaviour
{
public float speed = 2f; //how fast does the npc move
public float maxIdleTime = 3f; //max time the npc spends idling
public float maxChooseTime = 20f; //max time he spends moving
public float chooseDirTime = 0; //if 0, he chooses a direction
//possible directions
readonly Vector3[] directions = {Vector3.down, new Vector3(-0.5f, -0.5f, 0), Vector3.left, new Vector3(-0.5f, 0.5f, 0), Vector3.up,
new Vector3(0.5f, 0.5f, 0), Vector3.right, new Vector3(0.5f, -0.5f, 0)};
public int dir; //current direction
public bool canMove = true; //pretty self explainatory
public bool idle = true; //is the npc idle
public bool chase = false; //is the npc chasing after the player
public Vector3 goTo; //where to go if it's chasing after something
void Start()
{
StartCoroutine(Idle(maxIdleTime));
}
void Update()
{
chase = GetComponent<NPCLookForPlayerScript>().found;
if(canMove && !idle)
{
//move in the chosen direction
transform.position = Vector3.MoveTowards(transform.position, transform.position + directions[dir], Time.deltaTime * speed);
if (chooseDirTime > 0) //decrease movement time
{
chooseDirTime -= Time.deltaTime;
}
else
{
if(chase) StartCoroutine(Idle(0));
else StartCoroutine(Idle(Random.Range(0, maxIdleTime)));
}
}
}
//npc goes idle, then chooses a direction
public IEnumerator Idle(float f)
{
idle = true;
yield return new WaitForSeconds(f);
idle = false;
//here he chooses the direction depending of wether he's roaming or chasing
if (chase)
{
ChooseDirection();
chooseDirTime = maxChooseTime/4;
}
else
{
dir = Random.Range(0, directions.Length);
chooseDirTime = maxChooseTime;
}
}
//chooses a direction to take
void ChooseDirection()
{
Vector3 v = goTo - transform.position; //to check where to go
if (Mathf.Abs(v.x) <= 0.5)
{
if (v.y < 0) dir = 0; //go down
else dir = 4; //go up
}
if (Mathf.Abs(v.y) <= 0.5)
{
if (v.x < 0) dir = 2; //go left
else dir = 6; //go right
}
if (v.x < 0.5 && v.y < 0.5) dir = 1; //go down/left
if (v.x < 0.5 && v.y > 0.5) dir = 3; //go up/left
if (v.x > 0.5 && v.y > 0.5) dir = 5; //go up/right
if (v.x > 0.5 && v.y < 0.5) dir = 7; //go down/right
}
void OnCollisionEnter2D(Collision2D c)
{
if(c.gameObject.tag == "Obstacle") //stop and choose a new direction
{
StartCoroutine(Idle(Random.Range(0, maxIdleTime)));
}
if (c.gameObject.tag == "Player") //stop
{
canMove = false;
}
}
private void OnCollisionExit2D(Collision2D c)
{
if (c.gameObject.tag == "Player") //resume chasing the player
{
canMove = true;
}
}
}
The player's movement script:
public class PlayerFreeMovement : MonoBehaviour
{
public float speed = 2.0f; //movement speed
//where he's facing
public bool up;
public bool down;
public bool left;
public bool right;
public bool idle; //false if a movement button is pressed
public bool canMove = true;
//movement direction
public float dx;
public float dy;
public Vector3 v;
CollisionScript cs; //collision script
void Start()
{
down = true;
cs = GetComponent<CollisionScript>();
}
void Update() //move stickman in the direction of the keys and maintain the direction he's facing with animations
{
dx = 0;
dy = 0;
if (!(Input.GetKey(KeyCode.D) || Input.GetKey(KeyCode.A) || Input.GetKey(KeyCode.W) || Input.GetKey(KeyCode.S))) //check if idle
{
idle = true;
v = new Vector3();
}
else //the player's moving
{
idle = false;
AllFalse();
//set dx and dy
if (canMove && Input.GetKey(KeyCode.D))
{
if(!cs.hitRight) dx = 1;
right = true;
}
if (canMove && Input.GetKey(KeyCode.A))
{
if (!cs.hitLeft) dx = -1;
left = true;
}
if (canMove && Input.GetKey(KeyCode.W))
{
if (!cs.hitUp) dy = 1;
up = true;
}
if (canMove && Input.GetKey(KeyCode.S))
{
if (!cs.hitDown) dy = -1;
down = true;
}
//create the motion vector
v = new Vector3(dx, dy, 0);
if(dx !=0 && dy != 0)
{
v = v / 2;
}
}
//move
transform.position = Vector3.MoveTowards(transform.position, transform.position + v, Time.deltaTime * speed);
}
//avoid bug by deactivating all direction booleans before changing one
void AllFalse()
{
up = false;
down = false;
left = false;
right = false;
}
}
And finally, the collision script used to detect collisions in its path
public class CollisionScript: MonoBehaviour
{
//where is the wall
public bool hitDown= false;
public bool hitLeft = false;
public bool hitRight = false;
public bool hitUp = false;
//gizmos
public float collisionRadius = 0.5f;
public Vector2 downOffset = new Vector2(0, -0.5f);
public Vector2 rightOffset = new Vector2(0, 0.5f);
public Vector2 leftOffset = new Vector2(-0.5f, 0);
public Vector2 upOffset = new Vector2(0, 0.5f);
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
void Update()
{
hitDown = Physics2D.OverlapCircle((Vector2)transform.position + downOffset, collisionRadius).gameObject!=gameObject;
hitRight = Physics2D.OverlapCircle((Vector2)transform.position + rightOffset, collisionRadius).gameObject != gameObject;
hitLeft = Physics2D.OverlapCircle((Vector2)transform.position + leftOffset, collisionRadius).gameObject != gameObject;
hitUp = Physics2D.OverlapCircle((Vector2)transform.position + upOffset, collisionRadius).gameObject != gameObject;
}
void OnDrawGizmos()
{
Gizmos.color = Color.red;
Gizmos.DrawWireSphere((Vector2)transform.position + downOffset, collisionRadius);
Gizmos.DrawWireSphere((Vector2)transform.position + rightOffset, collisionRadius);
Gizmos.DrawWireSphere((Vector2)transform.position + leftOffset, collisionRadius);
Gizmos.DrawWireSphere((Vector2)transform.position + upOffset, collisionRadius);
}
}

Categories