Unity/C# - Cannot move backwards - c#

I'm new to Unity/C#, working on a script for PS4 controller, to get my character to be able to move in any directions using left stick and aim using right stick.
I used raycast to prevent my avatar from going through walls; that solved my issue of walking directly through walls.
However, when I aimed with right stick and moved in an opposite direction with my left, it still passed through the walls.
To tackle that, I adjusted the raycast parameter by adding the direction of the left stick (movement).
That worked, but it gave birth to a bug - I couldn't move backwards directly at all.
Diagonal-backs were fine, but I simply cannot move backwards in an open space.
Here is my code:
using System.Collections; using System.Collections.Generic; using UnityEngine;
public class NewMove : MonoBehaviour
{
Rigidbody m_Rigidbody;
public float m_Speed = 10f;
public float DashStamina = 100f;
void Start()
{
//Fetch the Rigidbody from the GameObject with this script attached
m_Rigidbody = GetComponent<Rigidbody>();
}
void FixedUpdate()
{
// Left Stick Input - Movement
float HorizontalMovementInput = Input.GetAxis("LStickHorizontal");
float VerticalMovementInput = Input.GetAxis("LStickVertical");
// Right Stick Input - Aim
float RSHorizontalMovementInput = Input.GetAxis("RStickHorizontal");
float RSVerticalMovementInput = Input.GetAxis("RStickVertical");
Vector3 CharDirection = new Vector3(HorizontalMovementInput, 0, VerticalMovementInput);
if (Input.GetButton("SubMovement") && DashStamina > 1)
// Dash speed
{
Vector3 fwd = transform.TransformDirection(Vector3.forward);
if (Physics.Raycast(transform.position + CharDirection, fwd, 3) == false)
{
//Store user input as a movement vector
Vector3 m_Input = new Vector3(Input.GetAxis("LStickHorizontal"), 0, Input.GetAxis("LStickVertical"));
//Apply the movement vector to the current position, which is //multiplied by deltaTime and speed for a smooth MovePosition
m_Rigidbody.MovePosition(transform.position + m_Input * Time.fixedDeltaTime * (m_Speed * 2));
DashStamina -= 0.5f;
}
}
else
// Normal running speed
{
Vector3 fwd = transform.TransformDirection(Vector3.forward);
if (Physics.Raycast(transform.position + CharDirection, fwd, 3) == false)
{
Vector3 m_Input = new Vector3(Input.GetAxis("LStickHorizontal"), 0, Input.GetAxis("LStickVertical"));
m_Rigidbody.MovePosition(transform.position + m_Input * Time.fixedDeltaTime * m_Speed);
DashStamina += 0.05f;
}
}
//Faces Archer to last direction of left stick
transform.LookAt(transform.position + CharDirection);
//Faces Archer to aiming direction of right stick; will override above
Vector3 CharAim = new Vector3(RSHorizontalMovementInput, 0, RSVerticalMovementInput);
transform.LookAt(transform.position + CharAim);
DashStamina = Mathf.Clamp(DashStamina, 0, 100);
}
}
Please advise.

Related

How can I allow for the player to detach from a wall after initiating climbing?

I am admittedly trying to hack and slash some code together for a simple free climbing system in unity. It's my first intermediate project and has turned out to be a bit more complicated than I thought. I have a character controller than when jumping towards a wall, will disable the character controller script and switch to a climbing controller script.
I am trying to allow for the player to press space to jump off of the wall, and back to the normal character controller script, but whenever I implement any sort of jumping behavior, the entire thing falls apart. Can anyone give me a push in the right direction or a simple clue as to how to allow for the character to detach cleanly from the wall?
Here is the code:
climbing
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Climbing : MonoBehaviour
{
[SerializeField] private float speed = 5f;
Rigidbody rb;
void Start()
{
rb = GetComponent<Rigidbody>();
rb.useGravity = false;
}
private void Update()
{
}
void FixedUpdate()
{
float h = Input.GetAxis("Horizontal");
float v = Input.GetAxis("Vertical");
Vector2 input = SquareToCircle(new Vector2(h, v));
{
// Check walls in a cross pattern
Vector3 offset = transform.TransformDirection(Vector2.one * 0.5f);
Vector3 checkDirection = Vector3.zero;
int k = 0;
for (int i = 0; i < 4; i++)
{
RaycastHit checkHit;
if (Physics.Raycast(transform.position + offset,
transform.forward,
out checkHit))
{
checkDirection += checkHit.normal;
k++;
}
// Rotate Offset by 90 degrees
offset = Quaternion.AngleAxis(90f, transform.forward) * offset;
}
checkDirection /= k;
// Check wall directly in front
RaycastHit hit;
if (Physics.Raycast(transform.position, // Position
transform.forward, // Direction
out hit)) // Hit Data
{
transform.forward = -hit.normal;
rb.position = Vector3.Lerp(rb.position,
hit.point + hit.normal * 0.51f,
10f * Time.fixedDeltaTime);
}
rb.velocity = transform.TransformDirection(input) * speed;
}
Vector2 SquareToCircle(Vector2 input)
{
return (input.sqrMagnitude >= 1f) ? input.normalized : input;
}
}
}

Swerve Control Unity C#

Hi I am creating a hyper casual game with unity, but I have encountered a problem with the swerve control (I have also seen many git hubs but even these do not work perfectly)
I've put this in my code:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerMovement : MonoBehaviour
{
private float lastframeposx;
private float movefactorx;
public float MoveFactorX => movefactorx;
public Camera m_MainCam;
private float speed = 2.0f;
[SerializeField]
GameObject character;
[SerializeField] private float swerveSpeed = 0.5f;
[SerializeField] private float maxSwerveAmount = 1f;
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
void Update()
{
transform.position += Vector3.forward * speed * Time.deltaTime;
Cammina();
/*Vector3 destra = Camera.main.ScreenToWorldPointt(Input.touches[i].position);
transform.position += Vector3.zero destra;*/
}
void Cammina()
{
if(Input.GetMouseButtonDown(0))
{
lastframeposx = Input.mousePosition.x;
float swerveAmount = Time.deltaTime * swerveSpeed * MoveFactorX;
swerveAmount = Mathf.Clamp(swerveAmount, -maxSwerveAmount, maxSwerveAmount);
transform.Translate(swerveAmount, 0, 0);
}
else if (Input.GetMouseButton(0))
{
movefactorx = Input.mousePosition.x - lastframeposx;
lastframeposx = Input.mousePosition.x;
float swerveAmount = Time.deltaTime * swerveSpeed * MoveFactorX;
swerveAmount = Mathf.Clamp(swerveAmount, -maxSwerveAmount, maxSwerveAmount);
transform.Translate(swerveAmount, 0, 0);
}
else if(Input.GetMouseButtonUp(0))
{
movefactorx = 0f;
float swerveAmount = Time.deltaTime * swerveSpeed * MoveFactorX;
swerveAmount = Mathf.Clamp(swerveAmount, -maxSwerveAmount, maxSwerveAmount);
transform.Translate(swerveAmount, 0, 0);
}
}
/*void vaidoveschiacciato()
{
if (Input.touchCount > 0 && Input.touches[0].phase == TouchPhase.Began)
{
Ray ray = Camera.main.ScreenPointToRay(Input.touches[0].position);
RaycastHit hit;
if(Physics.Raycast(ray, out hit))
{
if(hit.collider != null)
{
transform.position += hit.collider.GetComponent<Transform.position> * speed * Time.deltaTime;
}
}
}
}*/
}
1 Problem: he don't go when the finger is
2 Problem: How do I eliminate the movement from right to left (Without making it go out of the path)
(Langauge: C#)
The problem: When you swerve, it swerves just in the direction, there is no limits on how far it goes.
How I would fix this: I would put the movement to change it through a function. This could clamp it, so the higher the distance to the center of the track, the less it swerves. Or, you can altogether check if the distance is a maximum and then stop swerving.
Note: you can use other functions to do this (they just have to flatten out the larger the input).
Smooth, good looking bell curve way
For example you could use a bell curve. Look one up if you've never seen one before. It is at it's highest possible output of one, at a zero input. When it gets hiher or lower, it outputs lower to zero.
the simplest equation is y = i-(x2). The lower i is (above 1), the wider the curve, or the larger the output is for a larger input. I made a graph here.
x can be the distance to the center of the track, so you should adjust i, so the maximum distance from the track is flat.
This output is what you should change swerveAmount to.
The flatter parts of the graoh is how much you will swerve when you are that distance from the center (x axis)
Alternatively
You could just check the distance, and if it passes a certain distance don't translate it.
Let me know in the omments if there are any problems! :)

Dash against slopes using physics in Unity 2D

I'm working on a 2D project in Unity.
The character controller is physics based, so I use rigidbody to move the player. Everything is working fine except when I try to apply a high speed movement to the character, like a dash.
This is how the code looks like.
I just check if the player is dashing, so I increase the Vector2 movement in a certain amount.
private void DashMovement() {
if (isDashing) {
movement.x *= dashFactor;
}
}
I'm also calculating the ground angle, so I set the movement vector to follow the ground inclination.
private void OnSlopeMovement() {
if (isGrounded && !isJumping) {
float moveDistance = Mathf.Abs(movement.x);
float horizontalOnSlope = Mathf.Cos(groundAngle * Mathf.Deg2Rad) * moveDistance * Mathf.Sign(movement.x);
float verticalOnSlope = Mathf.Sin(groundAngle * Mathf.Deg2Rad) * moveDistance;
if (horizontalOnSlope != 0)
movement.x = horizontalOnSlope;
if (isGrounded && verticalOnSlope != 0)
movement.y = verticalOnSlope;
}
SetMaxFallVelocity();
}
So I set the rigidbody velocity for making it move.
private void Move() {
movement.x *= Time.fixedDeltaTime;
if(isGrounded && !isJumping) movement.y *= Time.fixedDeltaTime;
Vector3 targetVelocity = new Vector2(movement.x, movement.y);
PlayerController.rb2d.velocity = Vector3.SmoothDamp(PlayerController.rb2d.velocity, targetVelocity, ref velocity, movementSmoothing);
}
The problem appears when I apply a speed high enough. I understand this issue is because of physics.
I think the ray that checks the ground and is used to calculate the groundAngle doesn't work fast enough to keep track of that movement, so I can not keep the player fixed on the ground.
I would like to find a solution without making the player kinematic, or stopping the dash on slopes.
This is how it looks ingame.
And this is how the rigidbody movement remain right over the ground, following the slopes angle.
EDIT:
This is how I get the ground angle:
private void GroundAngle() {
Vector2 rayOrigin = feetCollider.bounds.center;
rayOrigin.y += 0.1f;
Vector2 rayDirection = (Input.GetAxisRaw("Horizontal") == 0) ? Vector2.right : new Vector2(Input.GetAxisRaw("Horizontal"), 0);
int groundCollisions = Physics2D.RaycastNonAlloc(rayOrigin, Vector2.down, groundResults, Mathf.Infinity, groundMask);
if (groundCollisions > 0) {
groundAngle = Vector2.Angle(groundResults[0].normal, rayDirection) - 90f;
//Debug.DrawRay(rayOrigin, Vector2.down, Color.green);
if (groundAngle > 0 && !isDashing) {
rayOrigin.x += Input.GetAxisRaw("Horizontal") * .125f;
Physics2D.RaycastNonAlloc(rayOrigin, Vector2.down, groundResults, Mathf.Infinity, groundMask);
groundAngle = Vector2.Angle(groundResults[0].normal, rayDirection) - 90f;
//Debug.DrawRay(rayOrigin, Vector2.down, Color.blue);
}
}
}
Thanks to #Ruzhim for the help. I just post a first "solution" for the problem.
According to Ruzhim advises, I've used him code this way.
private void SetPositionAfterTick() {
if (isDashMovement) {
Vector2 currentPosition = new Vector2(transform.position.x, transform.position.y);
currentPosition.y = feetCollider.bounds.min.y;
Vector2 feetPosAfterTick = currentPosition + PlayerController.rb2d.velocity * Time.deltaTime;
float maxFloorCheckDist = .1f;
RaycastHit2D groundCheckAfterTick = Physics2D.Raycast(feetPosAfterTick + Vector2.up * maxFloorCheckDist, Vector2.down, maxFloorCheckDist * 5f);
if (groundCheckAfterTick) {
Vector2 wantedFeetPosAfterTick = groundCheckAfterTick.point;
if (wantedFeetPosAfterTick != feetPosAfterTick) {
//PlayerController.rb2d.transform.position = (wantedFeetPosAfterTick + new Vector2(0f, feetCollider.bounds.min.y - PlayerController.rb2d.position.y));
PlayerController.rb2d.velocity = Vector2.zero;
}
}
}
}
This is how it looks like.
This is good enough to continue polishing that mechanic. I still need to set the position in some way. The rigidbody's position calculation is not working as it
is raised right now, as the condition (wantedFeetPosAfterTick != feetPosAfterTick) is always true, so the character goes throw the floor and fall.
As you can see, I also need to control the down slopes movement, as it uses the slopes movement sometimes, and dash straight forward others.
This is how asker Rubzero implemented the below code to work for them:
private void SetPositionAfterTick() {
if (isDashMovement) {
Vector2 currentPosition = new Vector2(transform.position.x, transform.position.y);
currentPosition.y = feetCollider.bounds.min.y;
Vector2 feetPosAfterTick = currentPosition + PlayerController.rb2d.velocity * Time.deltaTime;
float maxFloorCheckDist = .1f;
RaycastHit2D groundCheckAfterTick = Physics2D.Raycast(feetPosAfterTick + Vector2.up * maxFloorCheckDist,
Vector2.down, maxFloorCheckDist * 5f);
if (groundCheckAfterTick) {
Vector2 wantedFeetPosAfterTick = groundCheckAfterTick.point;
if (wantedFeetPosAfterTick != feetPosAfterTick) {
//PlayerController.rb2d.transform.position = (wantedFeetPosAfterTick + new Vector2(0f, feetCollider.bounds.min.y -
PlayerController.rb2d.position.y));
PlayerController.rb2d.velocity = Vector2.zero;
}
}
}
}
This is how it looks like.
This is good enough to continue polishing that mechanic. I still need
to set the position in some way. The rigidbody's position calculation
is not working as it is raised right now, as the condition
(wantedFeetPosAfterTick != feetPosAfterTick) is always true, so the
character goes throw the floor and fall.
As you can see, I need to control the down slopes movement, as it uses
the slopes movement sometimes, and dash straight forward others.
I agree with AresCaelum; using physics to do slope movement is pretty much the opposite of what you want to be doing if you don't want to preserve momentum when you're done going up/down the slope. Specifically, your problem is here:
float moveDistance = Mathf.Abs(movement.x);
float horizontalOnSlope = Mathf.Cos(groundAngle * Mathf.Deg2Rad) * moveDistance * Mathf.Sign(movement.x);
float verticalOnSlope = Mathf.Sin(groundAngle * Mathf.Deg2Rad) * moveDistance;
This is a problem because the more the player moves horizontally in a frame, the more they will move vertically based on the slope of the ramp they are on. However, this assumption doesn't hold if they should only be traveling up the ramp during only part of the movement during the frame. So, you need a way to handle that situation.
One solution is to use a raycast from where the player would be then if it's above the floor, alter the vertical velocity so that it would place them at that floor's position instead.
First, determine if slope movement has occurred in a physics frame...
private bool slopeMovementOccurred = false;
void FixedUpdate() {
slopeMovementOccurred = false;
// ...
}
private void OnSlopeMovement() {
if (isGrounded && !isJumping) {
slopeMovementOccurred = true;
// ...
}
SetMaxFallVelocity();
}
... and if it has, determine where the player is going to be after the physics update. Then do a physics2d raycast from above that position (by some amount) downward (double the previous amount) to find where the player's position should be, and then change the rb2d.velocity such that it will place the player exactly at the height they should be at.
Assuming you can calculate some kind of Vector2 feetOffset that has the local position of the player's feet:
void FixedUpdate() {
// ...
StickToSlopeLanding();
}
void StickToSlopeLanding() {
if (slopeMovementOccurred) {
Vector2 curVelocity = PlayerController.rb2d.velocity;
Vector2 feetPosAfterTick = PlayerController.transform.position
+ PlayerController.feetOffset
+ curVelocity * Time.deltaTime;
float maxFloorCheckDist = 1.0f;
// determine where the player should "land" after this frame
RaycastHit2D groundCheckAfterTick = Physics2D.Raycast(
feetPosAfterTick + Vector2.up * maxFloorCheckDist,
-Vector2.up, maxFloorCheckDist * 2f);
if (groundCheckAfterTick.collider != null) {
Vector2 wantedFeetPosAfterTick = groundCheckAfterTick.point;
// if basic physics won't take them to landing position
if (wantedFeetPosAfterTick != feetPosAfterTick) {
Vector2 wantedVelocity = curVelocity
+ Vector2.up
* ((wantedFeetPosAfterTick.y - feetPosAfterTick.y)
/ Time.deltaTime);
// adjust velocity so that physics will take them to landing position
PlayerController.rb2d.velocity = wantedVelocity;
// optionally, set a flag so that next frame
// it knows the player should be grounded
}
}
}
}
Hopefully this gets you towards a solution that will work.
Note: you may need to also move the rigidbody so that it doesn't try to clip through the corner at the top of the ramp, and you can determine where to put the rigidbody using another raycast, setting the velocity from that point to be horizontal:
void StickToSlopeLanding() {
if (slopeMovementOccurred) {
Vector2 curVelocity = PlayerController.rb2d.velocity;
Vector2 feetPosAfterTick = PlayerController.transform.position
+ PlayerController.feetOffset
+ curVelocity * Time.deltaTime;
float maxFloorCheckDist = 1.0f;
// determine where the player should "land" after this frame
RaycastHit2D groundCheckAfterTick = Physics2D.Raycast(
feetPosAfterTick + Vector2.up * maxFloorCheckDist,
-Vector2.up, maxFloorCheckDist * 2f);
if (groundCheckAfterTick.collider != null) {
Vector2 wantedFeetPosAfterTick = groundCheckAfterTick.point;
// if basic physics won't take them to landing position
if (wantedFeetPosAfterTick != feetPosAfterTick) {
// look for corner of ramp+landing.
// Offsets ensure we don't raycast from inside/above it
float floorCheckOffsetHeight = 0.01f;
float floorCheckOffsetWidth = 0.5f;
RaycastHit2D rampCornerCheck = Physics2D.Raycast(
wantedFeetPosAfterTick
- floorCheckOffsetHeight * Vector2.up
- floorCheckOffsetWidth * Mathf.Sign(movement.x) * Vector2.right,
Mathf.Sign(movement.x) * Vector2.right);
if (rampCornerCheck.collider != null) {
// put feet at x=corner position
Vector2 cornerPos = Vector2(rampCornerCheck.point.x,
wantedFeetPosAfterTick.y);
PlayerController.rb2d.position = cornerPos
- PlayerController.feetOffset;
// adjust velocity so that physics will take them from corner
// to landing position
Vector2 wantedVelocity = (wantedFeetPosAfterTick - cornerPos)
/ Time.deltaTime;
PlayerController.rb2d.velocity = wantedVelocity;
// optionally, set a flag so that next frame
// it knows the player should be grounded
}
}
}
}
}

Slowly moving gameobject to mouse position

I want to change the position of the object to the position of the mouse, moving slowly from first to second position.
My object is moving slowly to the random direction which appears to be connected with lower-left corner. When I go higher than the corner my object is moving upwards, same with left and right.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Rocket : MonoBehaviour
{
public float speed = 10f;
private Vector3 shippos;
void Start()
{
shippos = transform.position;
}
void FixedUpdate()
{
if (Input.mousePosition.x > shippos.x)
shippos.x=shippos.x+speed*Time.deltaTime;
if (Input.mousePosition.x < shippos.x)
shippos.x=shippos.x-speed*Time.deltaTime;
if (Input.mousePosition.y > shippos.y)
shippos.y=shippos.y+speed*Time.deltaTime;
if (Input.mousePosition.y < shippos.y)
shippos.y=shippos.y-speed*Time.deltaTime;
transform.position = shippos;
}
}
The mouse position is returned in screenspace coordinates. What you need to do is convert this to world coordinates so that they are compared in the same coordinate space as the transform (shippos).
void FixedUpdate()
{
if (Camera.main.ScreenToWorldPoint(Input.mousePosition).x > shippos.x)
shippos.x = shippos.x + speed * Time.deltaTime;
if (Camera.main.ScreenToWorldPoint(Input.mousePosition).x < shippos.x)
shippos.x = shippos.x - speed * Time.deltaTime;
if (Camera.main.ScreenToWorldPoint(Input.mousePosition).y > shippos.y)
shippos.y = shippos.y + speed * Time.deltaTime;
if (Camera.main.ScreenToWorldPoint(Input.mousePosition).y < shippos.y)
shippos.y = shippos.y - speed * Time.deltaTime;
transform.position = shippos;
}
If I did not misunderstand, you want to change your player's position straight to the point of mouse's position and looking towards mouse.
void Update() {
Transform target = mousePosition; //get your mouse position per frame
Vector3 relativePos = target.position - transform.position; //create a vector3 between them
Quaternion rotation = Quaternion.LookRotation(relativePos); //then give a rotation your player towards this vector.
transform.rotation = rotation; //and apply it.
}
Taken from here: http://answers.unity3d.com/questions/633873/how-to-make-an-object-move-towards-the-mouse-point.html
public float moveSpeed = 2.0; // Units per second
void Update () {
var targetPos = Camera.main.ScreenToWorldPoint(Input.mousePosition);
targetPos.z = transform.position.z;
transform.position = Vector3.MoveTowards(transform.position, targetPos, moveSpeed * Time.deltaTime);
}
May not be accurate C#, but you get the idea.
i guess you are doing wrong , because wile you have Mathf.Lerp you Dont need to go as that clumsy way
Here is a video tutorial from youtube for mathf.lerp
and here is the base code:
someValue = Mathf.Lerp(initialValue , finalValue , Time.deltaTime * smoothness);
just take a look to the youtube link you will definitely get the idea!
AS A SIDE NOTE
you dont need to do alot of stuff to decrease your game performance! be careful about this kinda coding!

Unity: Move camera based on forward horiz direction without changing y position

I'm creating a Google Cardboard VR app in Unity. I want the camera to constantly move forwards horizontally in the direction the camera is facing but not change its Y position, i.e. not rise or fall.
I've managed to get it so that the camera moves forwards in whichever direction it's looking but can go up and down if you look that way, using this line of code:
transform.position = transform.position + cam.transform.forward * WalkingSpeed * Time.deltaTime;
Is there a simple way of fixing the Y axis, so that I get the behaviour I'm looking for? Here's the full code so far:
using UnityEngine;
using System.Collections;
public class CameraMovement : MonoBehaviour {
public float WalkingSpeed = 1.0f;
public bool WalkEnabled = true;
GameObject cam;
void Start () {
// This is the part of the Cardboard camera where I'm getting
// the forward position from:
cam = GameObject.FindWithTag("CCHead");
}
void Update ()
{
if (WalkEnabled)
{
walk();
}
}
void walk()
{
transform.localPosition = transform.localPosition + cam.transform.forward * WalkingSpeed * Time.deltaTime;
}
}
Note: ticking the 'freeze position' y value in rigidbody constraints doesn't work.
Many thanks in advance.
You can try and split the forward vector up and build a new one where the y axis does not change:
transform.position =
transform.position +
new Vector3(
cam.transform.forward.x * WalkingSpeed * Time.deltaTime,
0, // add 0 to keep the y coordinate the same
cam.transform.forward.z * WalkingSpeed * Time.deltaTime);

Categories