I'm wanting my player to move to the left when the player hits the left of the screen. Right now, my player only moves as and when I hold down my mouse button. What I'm really wanting is for him to continually move to the left until he hits the target position when I press the screen once.
Can someone please tell me what I'm missing from my code to allow this to happen?
void FixedUpdate()
{
if(Input.GetMouseButtonDown(0))
{
if(Input.mousePosition.x < (Screen.width*2)/3 && Input.mousePosition.y > Screen.height/3)
{
if(position == middle)
{
MoveLeft();
}
}
}
}
void MoveLeft()
{
var pos = rigidbody.position;
float xPosition = left.transform.position.x;
pos.x = Mathf.Lerp(pos.x, xPosition, speed * Time.deltaTime);
rigidbody.position = pos;
}
My method is in the FixedUpdate because I'm moving the players rigidbody as oppose to translating the actual player.
Right now the player only moves when you hit mouse button because that's how your code is written: you check if the mouse is pressed every frame, and only if it is move the rigidbody.
If you want the player to move regardless of whether the mouse is still pressed or not, you should create some kind of variable to save the state of the player, and set to move left when the mouse button is pressed and set it to stop when the player reaches his target.
If I correctly understood your goal, it would look something like this:
bool moveLeft = false;
void FixedUpdate()
{
if(Input.GetMouseButtonDown(0)
&& (Input.mousePosition.x < (Screen.width*2)/3 && Input.mousePosition.y > Screen.height/3))
{
moveLeft = true;
}
if (moveLeft
&& (position == middle))
{
MoveLeft();
}
else
{
moveLeft = false;
}
}
void MoveLeft()
{
var pos = rigidbody.position;
float xPosition = left.transform.position.x;
pos.x = Mathf.Lerp(pos.x, xPosition, speed * Time.deltaTime);
rigidbody.position = pos;
}
Related
whenever the player uses its jetpack or when there's a lot of velocity, the player stutters. I tried using interpolate and other things like that but the only outcome was even more stutter. If anyone knows what the cause for the stuttering is, please tell me and if you want to, maybe even explain your answer :)
here is what i mean by the player stuttering :
https://www.youtube.com/watch?v=k6q3vvQtwjM
here is my player code :
using UnityEngine;
using UnityEngine.SceneManagement;
public class Player : MonoBehaviour
{
//basic variables
[SerializeField]
private float speed = 5f;
[SerializeField]
private float Jumpforce = 5f;
[SerializeField]
private float JetPackForce = 5f;
[SerializeField]
public bool canUseJetpack = true;
[SerializeField]
private Rigidbody2D rb;
[SerializeField]
private Animator animator;
private bool isFacingRight = true;
//runs when game starts
void Start()
{
rb = GetComponent<Rigidbody2D>();
}
//runs every frame
void Update()
{
//applies force thus making player to move left or right
var move = Input.GetAxis("Horizontal");
transform.position = transform.position + new Vector3(move * speed * Time.deltaTime, 0, 0);
//changes player animation state
animator.SetFloat("Speed", Mathf.Abs(move));
//flip the player if facing right or left
if (move < 0 && isFacingRight)
{
flip();
}
else if (move > 0 && !isFacingRight)
{
flip();
}
//checks if the space key is pressed and that the player velocity on the y axis is smaller than 0.001
if(Input.GetKeyDown("space") && Mathf.Abs(rb.velocity.y) < 0.001f)
{
//adds force from below the player thus making the player jump
rb.AddForce(new Vector2(0, Jumpforce), ForceMode2D.Impulse);
}
//checks for the key 'Q' to be pressed and that there is enough fuel in the jetpack
if (Input.GetKey(KeyCode.Q) && canUseJetpack == true)
{
//ads force from below the player thus making the player fly using its jetpack
rb.AddForce(Vector2.up * JetPackForce);
//decreases the fuel in the jetpack
JetpackBar.instance.UseFuel(0.1f);
//makes the player run the using jetpack animation
animator.SetBool("UsingJetpack", true);
}
else
{
//if the player isn't using the jetpack, switch to the idle animation or the run animation depending if the player is moving or not
animator.SetBool("UsingJetpack", false);
}
//checks if the player health is less than 0
if (HealthBar.instance.currentHealth <= 0)
{
//if so, restart the game
SceneManager.LoadScene(SceneManager.GetActiveScene().buildIndex);
}
}
//checks if someting collided with the player
private void OnCollisionEnter2D(Collision2D collision)
{
//if the thing collided with the player has a tag of 'Enemy'
if (collision.gameObject.CompareTag("Enemy"))
{
//then, make the player take damage
HealthBar.instance.takeDamage(25);
}
}
//flip the player
void flip()
{
isFacingRight = !isFacingRight;
transform.Rotate(0f, 180f, 0f);
}
}
Thanks :D
First of all whenever dealing with Rigidbodies you do not want to use the Transform component to move an object. You rather want to only move it via the Rigidbody/Rigidbody2D component!
Then there is a general issue. You can either move your object hard based on the input or use the physics and forces. Both at the same time is not possible because both transform.position or the actually "correct" Rigidbody2D.MovePosition will overrule the forces so these two systems are clashing all the time.
Therefore I would rather simply overwrite the velocity directly like e.g.
void Update()
{
// Store the current velocity
var velocity = rb.velocity;
var move = Input.GetAxis("Horizontal");
// Only overwrite the X component
// We don't need Time.deltaTime since a velocity already
// moves the object over time
velocity.x = move * speed;
animator.SetFloat("Speed", Mathf.Abs(move));
if (move < 0 && isFacingRight)
{
flip();
}
else if (move > 0 && !isFacingRight)
{
flip();
}
if(Input.GetKeyDown("space") && Mathf.Abs(rb.velocity.y) < 0.001f)
{
// simply overwrite the Y velocity
// You'll have to adjust that value of course
// and might want to rename it ;)
velocity.y = Jumpforce;
}
if (Input.GetKey(KeyCode.Q) && canUseJetpack)
{
// Here we want to use Time.deltaTime since the jetpack
// shall increase the Y velocity over time
// again you'll have to adjust/rename that value
velocity.y += JetPackForce * Time.deltaTime;
// Also adjust this value!
// To be frame-rate independent you want to use Time.deltaTime here
JetpackBar.instance.UseFuel(0.1f * Time.deltaTime);
animator.SetBool("UsingJetpack", true);
}
else
{
animator.SetBool("UsingJetpack", false);
}
// After having calculated all changes in the velocity now set it again
rb.velocity = velocity;
if (HealthBar.instance.currentHealth <= 0)
{
SceneManager.LoadScene(SceneManager.GetActiveScene().buildIndex);
}
}
I`m trying to make a wallrun in unity like the wallrun of the Prince of Persia.
The idea is that when you are touching the wall and you press "left shift" the player would run some seconds without falling.
I would like to add that if you press "enter" the character would jump to the side using the Wall as support for impulse.
You can watch this in the first minutes of the video:
https://www.youtube.com/watch?v=zsnB7HEiLr0
I have made this script for the character controller:
public Transform playerPosition;
//controls the x movement. (right/left)
public float horizontalmove;
//controls the y movement. (forward/back)
public float verticalmove;
//controls the movement direction.
private Vector3 playerInput;
//Here I store my character controller.
public CharacterController player;
//controls the player speed.
public float playerSpeed;
//controls de movement direction according to camera
public Vector3 movePlayer;
//controls the last movement
public Vector3 lastMovePlayer;
public float gravity = 9.8f;
public float fallVelocity;
public float jumpForce = 5.0f;
public float verticalSpeed;
private RaycastHit HitR;
private RaycastHit HitL;
//Here I store the main camera
public Camera mainCamera;
//It stores the camera direction when the player is looking forward.
private Vector3 camForward;
//It stores the camera direction when the player is looking right.
private Vector3 camRight;
//Checks
//The meaning of Caida is fall.
public bool Caida;
//The meaning of salto is jump.
public bool Salto;
public bool Wallrun;
public bool WallrunCount;
// Start is called befoe the first frame update
void Start()
{
//i store the character controler.
player = GetComponent<CharacterController>();
Caida = true;
}
// Update is called once per frame
void Update()
{
if (Wallrun == true)
{
Caida = false;
}
if (Salto == true)
{
fallVelocity -= gravity * Time.deltaTime;
movePlayer = lastMovePlayer;
}
if (Caida == true)
{
fallVelocity -= gravity * Time.deltaTime;
}
if (player.isGrounded && Wallrun == false)
{
Caida = false;
Salto = false;
WallrunCount = false;
//I assign the horizontal move to the w and s keys.
horizontalmove = Input.GetAxis("Horizontal");
//I assign the vertical move to the a and d keys.)
verticalmove = Input.GetAxis("Vertical");
//controls the movement direction
playerInput = new Vector3(horizontalmove, 0, verticalmove);
//limits the player speed. With this method if teh player waalks in diagonal doesn´t
//exceed the speed limit.
playerInput = Vector3.ClampMagnitude(playerInput, 1);
// It calls the function that give the camera look direction.
camDirection();
//Here, It`s calculates the player movement considering the camera point and the movement
//we have assing to teh player earlier
//With this method the player always moves looking to the camera
movePlayer = playerInput.x * camRight + playerInput.z * camForward;
//The movement * the speed we want.
movePlayer = movePlayer * playerSpeed;
//we are going to say to the player where is looking at.
player.transform.LookAt(player.transform.position + movePlayer);
//It gives the gravity to the player.
fallVelocity = -gravity * Time.deltaTime;
if (Input.GetKeyDown(KeyCode.Space))
{
Salto = true;
fallVelocity = jumpForce;
}
}
else if (!player.isGrounded && Salto == false && Wallrun == false)
{
Caida = true;
}
movePlayer.y = fallVelocity;
//we give the movement to th eplayer.
player.Move(movePlayer * Time.deltaTime);
lastMovePlayer = movePlayer;
}
private void OnTriggerStay(Collider other)
{
if (Input.GetKeyDown(KeyCode.LeftShift) && Wallrun == false && WallrunCount == false)
{
if (Input.GetKey("w"))
{
Wallrun = true;
WallrunCount = true;
fallVelocity = 5f;
movePlayer.y = fallVelocity;
movePlayer.z = movePlayer.z * 1.6f;
if (Physics.Raycast(transform.position, transform.right, out HitR, 1))
{
movePlayer.x = 1.6f;
}
else if (Physics.Raycast(transform.position, -transform.right, out HitL, 1))
{
movePlayer.x = -1.6f;
}
StartCoroutine(wallrunTime());
}
}
}
void camDirection()
{
//we store the forward and right directions here.
camForward = mainCamera.transform.forward;
camRight = mainCamera.transform.right;
//we block the direction and the camera direction because we are not going to use it.
camForward.y = 0;
camRight.y = 0;
//It gives as the normalized vectors.
camForward = camForward.normalized;
camRight = camRight.normalized;
}
private void OnControllerColliderHit(ControllerColliderHit hit)
{
if (!player.isGrounded && hit.normal.y < 0.1f)
{
if (Input.GetKeyDown(KeyCode.Space))
{
fallVelocity = jumpForce;
movePlayer = hit.normal * 7;
player.transform.LookAt(player.transform.position + movePlayer);
}
}
}
IEnumerator wallrunTime()
{
yield return new WaitForSeconds(1);
Wallrun = false;
}
As you can see, when the player enters the leftshift it checks to what direction is moving the character, if this is front (w) the script make the z movement * 1.6 (to make the character run a bit in the wall) and the character go a bit up bit the y axis.Then, the script checks if the Wall it i son the right or on the left and, depending on where the wall is, sticks the character to that wall.
private void OnTriggerStay(Collider other)
{
if (Input.GetKeyDown(KeyCode.LeftShift) && Wallrun == false && WallrunCount == false)
{
if (Input.GetKey("w"))
{
Wallrun = true;
WallrunCount = true;
fallVelocity = 5f;
movePlayer.y = fallVelocity;
movePlayer.z = movePlayer.z * 1.6f;
if (Physics.Raycast(transform.position, transform.right, out HitR, 1))
{
movePlayer.x = 1.6f;
}
else if (Physics.Raycast(transform.position, -transform.right, out HitL, 1))
{
movePlayer.x = -1.6f;
}
StartCoroutine(wallrunTime());
}
}
}
With this method, I can make the character jump when the player enters space because the character is hitting the wall (a condition required to bounce in the wall).
And after some seconds, the character falls simulating a wallrun.
IEnumerator wallrunTime()
{
yield return new WaitForSeconds(1);
Wallrun = false;
}
The problem is that this works perfectly if the character makes the wallrun when is looking in the same direction as the axes of the environment.
When the character z axis is looking at the same direction of the environment z axes it works perfectly. But when the axes are not looking at the same direction is a disaster. I show you a video I have recorded.
https://youtu.be/KH7rE9kh5d0
The problem, I suppose, is that with the code I have written, I'm moving the character according to the axes of the environment, and not its axes, so I have to tell him to move according to his own.
My teacher says I might have to change the way I make the character move. I would like to know if you can tell me a way to fix this without changing the movement method or if it is not possible, how can I change that movement.
Thank you in advance.
I am new to Unity and develop mobile 2d game,now I am able to make an object move right and left when I touch the screen before or after the screen center. But I want to touch the object and drag it on the x axis while my finger is still touching the screen and move,so I want the object to be in the same x position of my finger,
Any One can help me how to do it correctly:
here is the code of how I am moving the object if I touched before or after the screen center:
public class paddle : MonoBehaviour {
public Rigidbody2D rb;
public float speed;
public float maxX;
bool currentisAndroid=false;
// Use this for initialization
void Start () {
rb = GetComponent<Rigidbody2D> ();
#if UNITY_ANDROID
currentisAndroid=true;
#else
currentisAndroid=false;
#endif
}
// Update is called once per frame
void Update () {
if (currentisAndroid == true) {
if (Input.GetTouch (0).position.x < Screen.width/2 && Input.GetTouch (0).phase == TouchPhase.Stationary)
moveLeft ();
else if (Input.GetTouch (0).position.x > Screen.width/2 && Input.GetTouch (0).phase == TouchPhase.Stationary)
moveRight ();
else
stop ();
} else {
float x = Input.GetAxis ("Horizontal");
//if (Input.GetTouch (0).position.x == rb.position.x && Input.GetTouch (0).phase == TouchPhase.Moved)
if (x == 0)
stop ();
if (x < 0)
moveLeft ();
if (x > 0)
moveRight ();
Vector2 pos = transform.position;
pos.x=Mathf.Clamp (pos.x,-maxX,maxX);
transform.position = pos;
}
}
void moveLeft()
{
rb.velocity = new Vector2 (-speed, 0);
}
void moveRight()
{
rb.velocity = new Vector2 (speed, 0);
}
void stop()
{
rb.velocity = new Vector2 (0, 0);
}
public float getposition()
{
return rb.position.y;
}
}
Easiest way:
Add component DragRigidbody script and you will be able to drag objects via mouse or touchScreen touches.
If I Understand correctly:
1 - Raycast from finger location vertically with your camera into the scene.
2 - select the hit object.
3 - map your camera to world coordinates and move that object according to hit point of your ray with map or game object\objects.
Physics.Raycast();
RaycastHit.collider();
Camera.main.ScreenToWorldPoint(Input.GetTouch(<0 or 1 or all>).position);
If you want to move object across a map you can track your touch and when its close to the corners move the camera on that direct (horizontal - vertical).
I'm making a wall-runner type of game, where I need my character to change walls when the mouse button is clicked. I made it work with gravity, but it gave undesired effects. Therefore I'm now working with transform.position, but now the character only moves for a split second (I assume the transform.position only activates while the mouse button is actually clicked).
How do I make it change direction on the mouseclick, instead of it just moving a bit?
Do I need some kind of while loop, or where am I at?
My class:
//Variables used by the Player
public int flyingSpeed;
bool rightWall = true;
bool inAir = false;
// Use this for initialization
void Start () {
}
// Update is called once per frame
void Update () {
//Constantly moves the Players position along the Y-axis
if (inAir == false) {
if (Input.GetMouseButtonDown (0) && rightWall == true) {
transform.position += Vector3.left * flyingSpeed * Time.deltaTime;
rightWall = false;
inAir = true;
} else if (Input.GetMouseButtonDown (0) && rightWall == false) {
transform.position += Vector3.right * flyingSpeed * Time.deltaTime;
rightWall = true;
inAir = true;
}
}
}
void OnCollisionEnter2D(Collision2D coll) {
inAir = false;
}
The Input.GetMouseButtonDown method only returns true on the first frame that the button is clicked, so your moving operations are only executed once, which is not enough to switch the walls.
To switch between the walls, you can do one of the following:
Move the player immediately when the mouse is clicked by setting transform.position
Make a function that checks if the player is on the right or left wall (let's call is WallCheck). Then change the rightWall value every time the mouse is clicked.And then add this to your Update method
if (WallCheck() != rightWall)
transform.position += rightWall ? Vector3.left : Vector3.right * flyingSpeed * Time.deltaTime;
I'm trying to control a set of character animations but I'm having trouble with the jump animations. My horizontal walk animations are working fine but when I hit the jump button I want one of two jump animations to play depending on whether the player was in an idle or walking state.
I've set up a bool that updates based on whether my character collider is contacting the ground and I check against to determine when to play the jump animation. However when I press the jump button currently it only plays the first frame of the respective jump animation and then goes right back to either idle or walk. How do I get the entire jump animation to play when the jump button is pressed and the character is airborne?
using UnityEngine;
using System.Collections;
public class AsherBlackMover : MonoBehaviour {
public float moveSpeed = 3;
public float rotateSpeed = 10;
public Transform graphics;
public SkeletonAnimation skeletonAnimation;
public Vector2 jumpVector;
public bool isGrounded;
// isGrounded Variables
public Transform grounderPosition;
public float grounderRadius;
public LayerMask grounderLayerMask;
private Rigidbody2D asherBlackRB;
private Animator asherBlackAnim;
Quaternion goalRotation = Quaternion.identity;
float xDir;
string currentAnimation = "";
void Start ()
{
// Create a reference to Asher Black Rigidbody2D
asherBlackRB = GetComponent<Rigidbody2D>();
}
void Update ()
{
xDir = Input.GetAxis ("Horizontal") * moveSpeed;
if (xDir > 0 && isGrounded == true) // ------ Walk Right
{
goalRotation = Quaternion.Euler (0, 0, 0);
SetAnimation ("Walk", true);
}
else if (xDir < 0 && isGrounded == true) // ------ Walk Left
{
goalRotation = Quaternion.Euler (0, 180, 0);
SetAnimation ("Walk", true);
}
else if (isGrounded == true) // ------ Idle
{
SetAnimation ("Idle", true);
}
// Jump Button
if (Input.GetKeyDown("space") && isGrounded == true)
{
isGrounded = false;
skeletonAnimation.state.SetAnimation (0, "Idle-Jump", true);
if (xDir > 0 && isGrounded == false)
{
Jump ("Walk-Jump");
}
else if (xDir < 0 && isGrounded == false)
{
Jump ("Walk-Jump");
}
else if (isGrounded == false)
{
Jump ("Idle-Jump");
}
}
// Circle on character that determines when grounded or not
isGrounded = Physics2D.OverlapCircle (grounderPosition.transform.position, grounderRadius, grounderLayerMask);
// Flip character smothly to emulate paper mario effect
graphics.localRotation = Quaternion.Lerp (graphics.localRotation, goalRotation, rotateSpeed * Time.deltaTime);
}
void OnDrawGizmos ()
{
Gizmos.color = Color.yellow;
Gizmos.DrawWireSphere (grounderPosition.transform.position, grounderRadius);
}
void SetAnimation (string name, bool loop)
{
if (name == currentAnimation)
{
return;
}
skeletonAnimation.state.SetAnimation (0, name, loop);
currentAnimation = name;
}
void Jump (string animName)
{
asherBlackRB.AddForce (jumpVector, ForceMode2D.Force);
SetAnimation (animName, true);
print ("Doing a jump using the " + animName + " animation");
}
// Physics Updates
void FixedUpdate ()
{
asherBlackRB.velocity = new Vector2 (xDir, asherBlackRB.velocity.y);
}
}
From what I can tell, in the // Jump Button if block you set isGrounded to false, but right after that you set isGrounded based on collision detection:
isGrounded = Physics2D.OverlapCircle (grounderPosition.transform.position, grounderRadius, grounderLayerMask);
When you get to this statement you are still processing the same frame and the character still didn't have time to move isGrounded will be true by the time you get to the end of the update function. On the next update the animation will be reverted to the walk/idle one by the first set of if/else blocks. You might want to put the collision detection statement in an else block for the jump if. This might not be enough though as the time between frames might not be long enough for the character to move far enough away from the ground. In that case you might hold a counter and count, say, 5 frames until you go back to check the collision with the ground.