using UnityEngine;
public class PlayerMovement : MonoBehaviour
{
public float speed;
public float jump;
private Rigidbody2D rb;
private void Start()
{
rb = GetComponent<Rigidbody2D>();
}
private void Update()
{
rb.position += new Vector2(Input.GetAxis("Horizontal"), 0) * Time.deltaTime * speed;
if(Mathf.Abs(rb.velocity.y) < 0.001f && Input.GetKeyDown(KeyCode.W))
{
rb.AddForce(new Vector2(0, jump), ForceMode2D.Impulse);
}
}
So I have this code for my player movement. I am wondering how can I reduce my character from sliding that much. I don't want to stop instantly after I release the key.
You could add counter-movement to make the movement to feel more responsive, or you could change the friction by adding a physics material. Counter-movement makes the player stop by adding a force opposite to the wanted direction of the movement. It will stop the player from sliding too much. Another approach is to add a physics material and up the friction a bit. This will make the player stop faster. I hope you find this helpful!
Inside of the Input Manager, Edit->Project Settings->Input Manager, there is a property called gravity.
Gravity: Speed in units per second that the axis falls toward neutral when no input is present.
Decreasing this value will cause the input to fall quicker, resulting in less/no sliding.
You can debug your input value to confirm this. You should notice a ramp up from 0 to 1/-1 when you first hold the horizontal input. Once you let go of the input, you should see the value fall back down to 0.
var inputHorz = Input.GetAxis("Horizontal");
Debug.Log(inputHorz);
Lower the value until it feel correct. This can be changed while you are playing the game, but you will need to paste that value back in after pressing stop.
Related
So I am making a small game in unity where you have to shoot the enemy. However, when I made the script for the bullet and enemy, it half worked and half didn't. Sometimes, the bullet would hit the enemy and destroy the enemy, however, sometimes, it would take multiple shots for it to work. But when I turn the speed of the bullet to 1 (the speed of the bullet was 500), the bullet always destroys the enemy. So this leads me to think that this has something to do with the speed of the bullet. Here is my script
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
void Update()
{
}
private void OnTriggerEnter(Collider other)
{
Destroy(other.gameObject);
Destroy(gameObject);
Debug.Log("e");
}
For the movement of the bullet, I just used transform.Translate(Vector3.up * Time.deltaTime * speed). How can I fix this?
The problem is not that Destroy do not work with a certain speed, the problem is that with certain speed you are not triggering the "OnTriggerEnter".
This fenomenon is called "tunneling" it happens when the object goes too fast.
That provokes that in one frame the projectile is on one side of the collider, and in the next frame is on the other side of the collider, giving the sensation like a teleport, so that's the why it do not collide, cause in any frame the engine has detected the collide.
If you're having troubles with high speed stuff, try to set your rigidbody (the one that is moving) to Interpolate, or use raycasts to fake bigger projectile colliders.
In addition to Lotan's answer
I just used transform.Translate(Vector3.up * Time.deltaTime * speed)
whenever using physics you do NOT want to set anything via Transform as this bypasses the physics engine and thereby breaks collision detection etc as in your case.
You rather want to through the Rigidbody component and e.g. use Rigidbody.MovePosition
Rigidbody.MovePosition moves a Rigidbody and complies with the interpolation settings
like
private Rigidbody _rigidbody;
private void Awake()
{
_rigidbody = GetComponent<Rigidbody>();
}
private void FixedUpdate()
{
_rigidbody.MovePosition(_rigidbody.position + _rigidbody.rotation * Vector3.up * Time.deltaTime * speed);
}
or why not simply set it only once
private void Start()
{
GetComponent<Rigidbody>().velocity = transform.up * speed;
}
Additionally you want to set the interpolation to dynamic.
A tricky way : bullet form A point to B point by one frame , so you can fake a point on a to b like
fake point: A+B/2
Point a ;
Point b ;
Update()
{
Point ab = (a+b)/2;
bullet.point = ab;
//check collider some .
bullet.point = b; // set it back.
a = b;
}
Not a good solution . but it have double hit rate.
When I release the character control button, character itself continues to move for about half a second. I want the character to stop right after I release the control button. I’ve tried diffirent methods: AddForce and velocity, but it’s all in vain.
Also, I tried to adjust the mass and drag momentum in Inspector of the character, but it didn’t help.
public class CapsuleMovement : MonoBehaviour
{
Rigidbody rb;
Vector3 playerMovement;
[SerializeField] float speed = 50;
void Start()
{
rb = GetComponent<Rigidbody>();
}
void FixedUpdate()
{
ProccessCapsuleMovement();
}
void ProccessCapsuleMovement ()
{
playerMovement = new Vector3 (Input.GetAxis("Horizontal"), 0, Input.GetAxis("Vertical"));
playerMovement.Normalize();
rb.velocity = playerMovement * speed * Time.deltaTime;
}
}
Don't normalize! If the Input magnitude is actually smaller than 1 you still normalize it always to a magnitude 1!
Rather use Vector3.ClampMagnitude which only limits the magnitude in the upper bound but allows it to be smaller
The other point might be that GetAxis is actually "smoothed" and not applied immediately! After releasing the button it is actually decreased over time. So since you normalized the vector it keeps having a magnitude of 1 for a while after releasing the buttons.
You might rather want to use GetAxisRaw for this.
Then when assigning a velocity you do not want to multiply by Time.deltaTime! This only is needed where you want to convert a value from a fixed value per frame into a frame-rate-independent value per second. A velocity already is a vector per second so remove the * Time.deltaTime.
so something like e.g.
playerMovement = Vector3.ClampMagnitude(new Vector3 (Input.GetAxisRaw("Horizontal"), 0, Input.GetAxisRaw("Vertical")), 1f);
rb.velocity = playerMovement * speed;
I am developing a VR game.
Is a fighting game, the player will be able the punch the enemies (on his fist will be a collider and a disabled object with the damage script).
I need a script that will activate another object (the one with damage script) - (placed on his fist) but just on certain speed or force (you know, like in real life- if the enemy will be touched with the hand he should not be damaged, just on high force or speed)
What is the best solution?
thank you!
Since your player's fist is not being controlled by the physics system, it will not be possible to read the velocity of the player's hand like you would a normal Rigidbody. That being said, you can still calculate the speed and handle all of what you wish to do in one script.
Here's an example:
[RequireComponent(typeof(DamageScript))]
public class HandSpeedMonitor : Monobehaviour
{
public float threshold;
DamageScript damageScript;
Vector3 lastPos;
public void Awake()
{
damageScript = this.GetComponent<DamageScript>();
}
public void Start()
{
lastPos = this.transform.position;
}
public void Update()
{
float velocity = (lastPos - this.transform.position).magnitude / Time.deltaTime;
if(!damageScript.enabled && velocity > threshold)
damageScript.enabled = true;
else if(damageScript.enabled)
damageScript.enabled = false;
}
}
However, since .magnitude is an expensive call, you may want to consider storing your "threshold" as a squared speed "sqrThreshold" and use .sqrMagnitude, since it removes the square root component of vector math (saving on processing).
public int power;
// Start is called before the first frame update
void Start()
{
player = GameObject.Find("Whyareyoulikethis");
while (Input.GetKey(KeyCode.Space))
{
power = power + 10;
}
// Places the ball at the player's current position.
transform.Translate(-player.transform.forward);
rb = GetComponent<Rigidbody>();
rb.AddForce(-player.transform.forward * power);
}
What this is meant to do is while the space key is held down, power will increase by 10. Unfortunately, this does absolutely nothing. When the ball is spawned, it simply just drops down with no force added whatsoever. I have also tried GetKeyUp and GetKeyDown as opposed to Getkey, but they made no difference to the final result. I have also tried this in an if statement under void Update(), but the same happened. As stupid as it was, I also tried it in its while statement under void Update() and crashed the engine as expected.
That while loop blocks your game until it is done. So as soon as you enter it you will never come out since the Input is not updated inside of your while loop.
Also it makes no sense in Start which is only called once when your GameObject is initialized and the space key won't be pressed there.
Move the check for Input.GetKey it to Update which is called every frame.
Than Cid's comment is correct and this will increase the power quite fast and frame dependent. You probably want to increase rather with a frame-independent 60/second so rather use Time.deltaTime
in this case power should be a float instead
Than it depends where the rest should be executed but I guess e.g. at button up
public float power;
private void Start()
{
player = GameObject.Find("Whyareyoulikethis");
rb = GetComponent<Rigidbody>();
}
private void Update()
{
if(Input.GetKey(KeyCode.Space))
{
power += 10 * Time.deltaTime;
}
if(Input.GetKeyUp(KeyCode.Space))
{
// Places the ball at the player's current position
transform.position = player.transform.position;
// you don't want to translate it but set it to the players position here
// rather than using addforce you seem to simply want to set a certain velocity
// though I don't understand why you shoot backwards...
rb.velocity = -player.transform.forward * power;
}
}
I am not new to programming, but I am new to C#. I am experienced in Python, Java, and HTML. My game is 2D I have a game where my character currently has to touch the enemy to kill it. Now I added code for shooting a bullet to kill the enemy. I also want the bullet to be shot if the spacebar is pressed. The character is supposed to a shoot bullet in either direction. I have taken my code from an example my professor gave me which was originally Javascript and I converted it to C#. Unity no longer supports Javascript. The example code he gave me was basically a rocket shooting as many bullets as I clicked (clicking the mouse shoots bullets) to eliminate an enemy, however the rocket in that example does not move. In my game, the character moves, so the bullet has to get the position of the character. What is the correct code for getting the character position and shooting a bullet correctly?
I tested my game with my current code. The bullet is being spit out of nowhere (from the bottom of my background wallpaper [smack in the middle of the bottom] to a little below the wallpaper). Not even from the character...
Also, I added the Hit class script to my Bullet category in Unity.
Complete Camera Controller (no issues here at all)
using UnityEngine;
using System.Collections;
public class CompleteCameraController : MonoBehaviour {
public GameObject player; //Public variable to store a reference to the player game object
private Vector3 offset; //Private variable to store the offset distance between the player and camera
// Use this for initialization
void Start ()
{
//Calculate and store the offset value by getting the distance between the player's position and camera's position.
offset = transform.position - player.transform.position;
}
// LateUpdate is called after Update each frame
void LateUpdate ()
{
// Set the position of the camera's transform to be the same as the player's, but offset by the calculated offset distance.
transform.position = player.transform.position + offset;
}
}
Complete Player Control Class (If you read the comments in the code that say the "BULLET CODE", that's new code I have placed in the game for the bullets.
using UnityEngine;
using System.Collections;
//Adding this allows us to access members of the UI namespace including Text.
using UnityEngine.UI;
public class CompletePlayerController : MonoBehaviour
{
public float speed; //Floating point variable to store the player's movement speed.
public Text countText; //Store a reference to the UI Text component which will display the number of pickups collected.
public Text winText; //Store a reference to the UI Text component which will display the 'You win' message.
private Rigidbody2D rb2d; //Store a reference to the Rigidbody2D component required to use 2D Physics.
private int count; //Integer to store the number of pickups collected so far.
Rigidbody2D bullet;
float speed2 = 30f; //BULLET CODE
// Use this for initialization
void Start()
{
//Get and store a reference to the Rigidbody2D component so that we can access it.
rb2d = GetComponent<Rigidbody2D> ();
//Initialize count to zero.
count = 0;
//Initialze winText to a blank string since we haven't won yet at beginning.
winText.text = "";
//Call our SetCountText function which will update the text with the current value for count.
SetCountText ();
}
//FixedUpdate is called at a fixed interval and is independent of frame rate. Put physics code here.
void FixedUpdate()
{
//Store the current horizontal input in the float moveHorizontal.
float moveHorizontal = Input.GetAxis ("Horizontal");
//Store the current vertical input in the float moveVertical.
float moveVertical = Input.GetAxis ("Vertical");
Rigidbody2D bulletInstance; //BULLET CODE
//Use the two store floats to create a new Vector2 variable movement.
Vector2 movement = new Vector2 (moveHorizontal, moveVertical);
//Call the AddForce function of our Rigidbody2D rb2d supplying movement multiplied by speed to move our player.
rb2d.AddForce (movement * speed);
if(Input.GetKeyDown(KeyCode.Space)&& Hit.hit == false) //BULLET CODE IN HERE
{
// ... instantiate the bullet facing right and set it's velocity to the right.
bulletInstance = Instantiate(bullet, transform.position, Quaternion.Euler(new Vector3(0,0,0)));
bulletInstance.velocity = new Vector2(speed2, 0);
bulletInstance.name = "Bullet";
}
}
//OnTriggerEnter2D is called whenever this object overlaps with a trigger collider.
void OnTriggerEnter2D(Collider2D other)
{
//Check the provided Collider2D parameter other to see if it is tagged "PickUp", if it is...
if (other.gameObject.CompareTag ("PickUp"))
{
//... then set the other object we just collided with to inactive.
other.gameObject.SetActive(false);
transform.localScale += new Vector3(0.1f, 0.1f, 0);
//Add one to the current value of our count variable.
count = count + 1;
//Update the currently displayed count by calling the SetCountText function.
SetCountText ();
}
}
//This function updates the text displaying the number of objects we've collected and displays our victory message if we've collected all of them.
void SetCountText()
{
//Set the text property of our our countText object to "Count: " followed by the number stored in our count variable.
countText.text = "Count: " + count.ToString ();
//Check if we've collected all 12 pickups. If we have...
if (count >= 12)
//... then set the text property of our winText object to "You win!"
winText.text = "You win!";
}
}
Hit code. All code in this class is made for the bullet.
using UnityEngine;
using System.Collections;
public class Hit : MonoBehaviour
{
GameObject[] gameObjects;
public static bool hit = false;
void Removal ()
{
gameObjects = GameObject.FindGameObjectsWithTag("Bullet");
for(var i= 0 ; i < gameObjects.Length ; i ++)
Destroy(gameObjects[i]);
}
void OnCollisionEnter2D ( Collision2D other )
{
if(other.gameObject.name=="Bullet")
{
Removal();
Destroy(gameObject);
hit = true;
}
}
}
I see several issues with the code you wrote. as #Kyle Delaney suggested, I'd also highly recommend you check out the Unity Learn website, and go through several tutorials before moving through. I've highlighted a few issues below that may help solve your problem, but you could really benefit from changing your approach in the first place to avoid many of these issues. See below.
In your camera controller class, why not make the offset public so you can set it yourself in the inspector>
In Player controller class:
changed:
if (Input.GetKeyDown(KeyCode.Space)) //Shoot bullet
{
// ... instantiate the bullet facing right and set it's velocity to the right.
Rigidbody2D bulletRB = Instantiate(bullet, transform.position, transform.rotation);
bulletRB.AddForce(new Vector2(speed2,0), ForceMode2D.Impulse);
}
On a click, this instantiates the bullet prefab and sets its transform to copy the position and rotation of the player. It then adds a force to it to the right. You should avoid setting the velocity manually with rigidbodies, this can cause unwanted behaviour. Use the Addforce/addTorque methods instead. The ForceMode says to ignore its mass and set its velocity.
Then delete your Hit class, and replace with this Bullet class, which you drag onto the bullet prefab. Your player shouldn't be in charge of checking for bullet hits. that's the bullet's job. The player just launches the bullets and then the bullets do what bullets do. this just checks to see if the bullet hit anything, if so it destroys it. You can make this more complicated if you want. I would recommend using layers to determine which layers the bullet checks collisions with. You probably don't want bullets destroying your terrain. and you definitely don't want bullets destroying the player itself!
public class Bullet : MonoBehaviour
{
private void OnCollisionEnter2D(Collision2D collision)
{
Destroy(collision.gameObject);
Destroy(this.gameObject);
}
}
Also you shouldn't need to set the name of the bullet, since your prefab bullet should already be named "bullet".
I hope this gets you started in the right direction. But based on your code, I HIGHLY recommend you work through the tutorials before continuing with any projects. The unity staff that make them are super helpful and the tutorials start off really simple but get really complicated fast, so you actually come away learning a ton!
Perhaps the problem has to do with the player's parent transform. You could try something like this to make sure the bullet has the right parent:
bulletInstance = Instantiate(bullet);
bulletInstance.transform.parent = transform.parent;
bulletInstance.transform.position = transform.position;
bulletInstance.velocity = new Vector2(speed2, 0);
bulletInstance.name = "Bullet";
If that doesn't work it may be worthwhile to check the player's Rect Transform to see where the anchors and pivot are. Perhaps the player's actual "position" coordinates aren't where you think they are.
Have you done the Space Shooter tutorial? It has a segment about shooting bullets.