There is a player and a small ball in the middle of the level, the player can only jump, and when we press the spacebar again during the jump, he must look for a ball nearby and attach a rope to it, and swing, how can I do this? are there any sources or code?
private Rigidbody2D rb;
public float jumpforce;
public Transform grCheck;
public float grRadius = 0.2f;
private bool gr = false;
public LayerMask whatis;
void Start()
{
rb = GetComponent<Rigidbody2D>();
}
// Update is called once per frame
void Update()
{
gr = Physics2D.OverlapCircle(grCheck.position, grRadius, whatis);
if (Input.GetKeyDown("space") && gr)
{
rb.AddForce(Vector3.up * jumpforce*100f);
}
}
First add a rigid body and a collider to the object. Write the following code in "FixedUpdate", it cannot be "Update", because it is a physical property, it must be "FixedUpdate"
transform.rotation = Quaternion.LookRotation(Vector3.forward, Vector3.up);
if (Input.GetButtonDown("Jump"))
{
if (ground == true)
{
//transform.Translate(new Vector3(Input.GetAxis("Horizontal")*distance, 2, Input.GetAxis("Vertical")*distance));
GetComponent<Rigidbody>().velocity += new Vector3(0, 5, 0);
GetComponent<Rigidbody>().AddForce(Vector3.up * mJumpSpeed);
ground = false;
Debug.Log("I am Pressing Jump");
}
}
"ground" is used to determine whether you are in the air or on the ground, and if it is in the air, of course, it will not let you jump. In addition, if you want to cancel the recoil, add "GetComponent().freezeRotation = true" in the "start" method;
Related
I have a character, he can move and jump. I need to check if it is grounded, so I made a trigger box collider as a characters component, and I use OnTriggerEnter and OnTriggerExit to check if it is grounded, but the exit of collision with object that the character is standing on is detected one physics update late, and when it is detected, the upward velocity appears to become 0, and the character starts falling. Here is my code:
using System.Collections;
using UnityEngine;
public class Player : MonoBehaviour
{
public float speed = 4.0f;
public float jumpSpeed = 8.0f;
private bool doJump = false;
private Rigidbody rb;
bool isGrounded = false;
private float x, z;
private void Awake()
{
rb = GetComponent<Rigidbody>();
}
private void Update()
{
x = Input.GetAxis("Horizontal");
z = Input.GetAxis("Vertical");
if (Input.GetKeyDown(KeyCode.Space))
{
StartCoroutine(Jump());
}
}
void FixedUpdate()
{
if (isGrounded)
{
//this is movement
rb.velocity = (transform.right * x) * speed * Time.fixedDeltaTime + (transform.forward * z) * speed * Time.fixedDeltaTime;
}
if (isGrounded && doJump)
{
doJump = false;
rb.AddForce(0, jumpSpeed, 0, ForceMode.VelocityChange);
}
}
IEnumerator Jump()
{
//need the coroutine to make the player jump even if space pressed a bit earlier than
//the character landed
doJump = true;
yield return new WaitForSeconds(0.15f);
doJump = false;
}
private void OnTriggerStay(Collider other)
{
if (other != this.gameObject)
{
isGrounded = true;
}
}
private void OnTriggerExit(Collider other)
{
if (other != this.gameObject)
{
isGrounded = false;
}
}
}
I tried to not use coroutine for jumping but it doesn't help. What helps is deleting the movement line.
I think you are trying to implement "Pre_Update" function, I have found this solution maybe you can use it:
https://answers.unity.com/questions/614343/how-to-implement-preupdate-function.html
I am not sure but I think if you initialize your physics component in the Start function instead of the Awake function then it might work.
I have Googled Everything but cannot get the right results. I want the GameObject to only jump once in the air, come back to the ground and then the player can jump. My current results are that the GameObject flies in the air if you press the spacebar. I wanna limit the GameObject to jump only once, come back and then jump if the player desires to. I have Shown some code down`
public class SphereController : MonoBehaviour
{
private bool IsOnGround = true;
Rigidbody rb;
public float BallSpeed = 10f;
// Start is called before the first frame update
void Start()
{
rb = GetComponent<Rigidbody>();
}
// Update is called once per frame
void Update()
{
float Hmove = Input.GetAxis("Horizontal");
float Vmove = Input.GetAxis("Vertical");
Vector3 MoveBall = new Vector3(Hmove, 0f, Vmove);
rb.AddForce(MoveBall * BallSpeed);
if ((Input.GetKey(KeyCode.Space)) && IsOnGround == true)
{
rb.AddForce(0, 20, 0);
}
}
private void OnCollisionStay()
{
IsOnGround = true;
}
Change the IsOnGround to false.
if ((Input.GetKey(KeyCode.Space)) && IsOnGround)
{
rb.AddForce(0, 20, 0);
IsOnGround = false
}
You have the OnCollision method that changes it back to true so this should work fairly well.
So, the way I do it is the following.
STEPS:
1- Tag the floor object as whatever you like. I always tag it as ground. You tag objects in the Inspector window, at the top left. I says Untagged by default
2- This is the Code I write:
bool isGrounded;
void OnCollisionEnter(Collision other)
{
if(other.gameObject.tag == "ground")
{
isGrounded = true; // if its colliding with "ground", isGrounded is true
}
else
{
isGrounded = false;
}
if(Input.GetKeyDown(KeyCode.space) && isGrounded) // change space to whatever key to jump
{
Jump(); // your jump code goes here EG. Rigidbody.AddForce(0, 15, 0);
}
}
I hope this is helpful.
So, I am trying to create a soccer game from scratch... all I have done until now, is setting up the ball. This is how I want it to work: When the player collides with the ball, the ball jumps forward a bit. If you start running the ball will be pushed further away.
Now, here is my script for the ball (I am using the standard FPSController as character):
using UnityEngine;
using System.Collections;
public class BallController : MonoBehaviour {
private Rigidbody rb;
public GameObject character;
public float moveSpeed = 1000;
public float shootSpeed = 2000;
bool isTurnedUp = false;
bool isTurnedDown = false;
bool done = false;
// Use this for initialization
void Start () {
rb = GetComponent<Rigidbody>();
}
// Update is called once per frame
void FixedUpdate () {
//Debug.Log(isTurnedUp + ", " + isTurnedDown);
switch (character.GetComponent<UnityStandardAssets.Characters.FirstPerson.FirstPersonController>().m_IsWalking)
{
case true:
if (isTurnedUp == false)
{
moveSpeed = moveSpeed / 1.4f;
isTurnedUp = true;
isTurnedDown = false;
}
break;
case false:
if (isTurnedDown == false)
{
moveSpeed = moveSpeed * 1.4f;
isTurnedDown = true;
isTurnedUp = false;
}
break;
}
}
void Update()
{
if (Input.GetMouseButtonDown(0))
{
if (Vector3.Distance(gameObject.transform.position, character.transform.position) <= 5)
{
float distance = Vector3.Distance(gameObject.transform.position, character.transform.position);
}
}
}
void OnCollisionEnter(Collision collision) {
FixedUpdate();
if (done == false) {
rb.AddForce(Vector3.forward * moveSpeed, ForceMode.Impulse);
done = true;
}
else {
done = false;
}
}
//other
void OnDrawGizmosSelected()
{
Gizmos.color = Color.yellow;
Gizmos.DrawWireSphere(transform.position, 2);
}
}
My problem is that the ball doesn't behave how I want it... it feels like it's about luck if the ball will jump forward when I touch it. Can someone tell me what I did wrong?
Inside of OnCollisionEnter you need to ensure the ball can only be kicked by the player. You can check whether or not the player has collided with the ball by checking the name or tag of the collision. The following example uses the name and assumes your player GameObject is named "Player".
Remove the done flag since this will only allow the player to kick the ball every other time they collide, and remove the FixedUpdate() call since FixedUpdate() is already called automatically every physics calculation.
Finally, if you want to kick the ball away from the player, then you need to calculate the direction away from the collision point instead of using Vector3.forward as seen below.
void OnCollisionEnter(Collision collision)
{
if(collision.gameObject.name == "Player")
{
Vector3 direction = (collision.transform.position - transform.position).normalized;
rb.AddForce(-direction * moveSpeed, ForceMode.Impulse);
}
}
I am working on a 2D game project. I would like the user to be able to hit the ball when he presses on the "space" key. I assigned;
Circle collider 2D & Rigidbody 2D to the ball
Rigidbody 2D & Box Collider 2D to the hero
Edge Collider 2D to the baseball bat.
Here is my script which I have called "KickTheBall.cs":
using UnityEngine;
using System.Collections;
public class KickTheBall : MonoBehaviour {
public float bounceFactor = 0.9f; // Determines how the ball will be bouncing after landing. The value is [0..1]
public float forceFactor = 10f;
public float tMax = 5f; // Pressing time upper limit
private float kickStart; // Keeps time, when you press button
private float kickForce; // Keeps time interval between button press and release
private Vector2 prevVelocity; // Keeps rigidbody velocity, calculated in FixedUpdate()
[SerializeField]
private EdgeCollider2D BatCollider;
private Rigidbody2D rb;
void Start () {
rb = GetComponent<Rigidbody2D>();
}
void FixedUpdate () {
if(kickForce != 0)
{
float angle = Random.Range(0,20) * Mathf.Deg2Rad;
rb.AddForce(new Vector2(0.0f,
forceFactor * Mathf.Clamp(kickForce, 0.0f, tMax) * Mathf.Sin(angle)),
ForceMode2D.Impulse);
kickForce = 0;
}
prevVelocity = rb.velocity;
}
void Update(){
if(Input.GetKeyDown (KeyCode.Space))
{
kickStart = Time.time;
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
RaycastHit hit;
if (Physics.Raycast(ray, out hit))
{
if(hit.collider.name == "Ball") // Rename ball object to "Ball" in Inspector, or change name here
kickForce = Time.time - kickStart;
}
}
}
public void KickBall(){
BatCollider.enabled = true;
}
void OnCollisionEnter(Collision col)
{
if(col.gameObject.tag == "Ground") // Do not forget assign tag to the field
{
rb.velocity = new Vector2(prevVelocity.x,
-prevVelocity.y * Mathf.Clamp01(bounceFactor));
}
}
}
However, I am unable to kick the ball when I press the space key. The ball is just bouncing because of colliders. What am I missing?
Check my result:
I would advocate something more like this to start with. This is the script you would add onto your baseball bat.
Part 1:
using UnityEngine;
using System.Collections;
public class KickTheBall : MonoBehaviour
{
public float forceFactor = 10f;
private float kickForce = 50f;
void OnCollisionEnter(Collision col)
{
if(col.gameObject.tag == "Ball") // Do not forget assign tag to the field
{
rb = col.gameobject.GetComponent<Rigidbody>();
rb.AddForce(transform.right * kickForce);
}
}
}
I have simplified your AddForce function for demonstration purposes. Feel free to replace it with your more complex AddForce function if everything is working.
Part 2:
If you really want to include the part where holding the space button makes the hit stronger, then add this:
void Update()
{
if(Input.GetKey(KeyCode.Space))
{
kickForce += 0.5f;
}
}
and add at the end of the oncollisionenter
kickForce = 0;
What this will do is build up force while you hold the space button down. After a successful hit the force will reset to 0. So subsequent collisions will not result in a hit until the space button is held again.
Let me know if this did anything for you.
I solved the issue with the help of #TylerSigi. I updated my script file with these codes:
using UnityEngine;
using System.Collections;
public class KickTheBall : MonoBehaviour {
public float forceFactor = 10f;
private float kickForce = 0f;
private EdgeCollider2D BatCollider;
public GameObject Ball;
void Start () {
}
void Update()
{
if (Input.GetKey (KeyCode.Space)) {
kickForce = 1000;
} else {
kickForce = 0;
}
}
void OnTriggerEnter2D(Collider2D col)
{
if(col.gameObject.tag == "Enemy") // Do not forget assign tag to the field
{
Ball.GetComponent<Rigidbody2D>().AddForce(transform.right * kickForce);
}
}
}
I have a little problem with my player control script (C#) in the unity enigne. I worked out the following script with the basic movement of the player. The problem is that the player can enter the jump statement (the debug log printed it out)
Debug Log
but it will not work. The character is still on the ground.
The jump function will be enabled when the player is on the ground (grounded) and did not a double jump.
So my question is are there any "code mistakes" or maybe some configuration problems which I do not see?
Thank you for your help in advance!
using UnityEngine;
using System.Collections;
public class PlayerControl : MonoBehaviour
{
// public variables
public float speed = 3f;
public float jumpHeight = 5f;
// private variables
Vector3 movement;
Animator anim;
Rigidbody2D playerRigidbody;
// variables for the ground check
public Transform groundCheck;
public float groundCheckRadius;
public LayerMask whatIsGround;
private bool grounded;
private bool doubleJump;
// Use this for initialization
void Start()
{
}
// Update is called once per frame
void Update()
{
// Proves if the player is on the ground and activate the double jump function
if (grounded)
{
doubleJump = false;
}
// First line of proving the jump
if (Input.GetMouseButtonDown(0) && grounded)
{
Debug.Log("Jump if entered");
Jump();
}
if (Input.GetMouseButtonDown(0) && !doubleJump && !grounded)
{
Debug.Log("double Jump");
Jump();
doubleJump = true;
}
// Flipping the Player when he runs back
if (Input.GetAxis("Horizontal") < 0)
{
playerRigidbody.transform.localScale = new Vector2(-1.7f, 1.7f);
}
else
{
playerRigidbody.transform.localScale = new Vector2(1.7f, 1.7f);
}
}
void Awake()
{
// References setting up
playerRigidbody = this.GetComponent<Rigidbody2D>();
anim = GetComponent<Animator>();
}
void FixedUpdate()
{
float horizontal = Input.GetAxisRaw("Horizontal");
float vertical = Input.GetAxisRaw("Vertical");
// simple Movement without a speed control
Move(horizontal, vertical);
Animating(horizontal, vertical);
// Section for ground detection
grounded = Physics2D.OverlapCircle(groundCheck.position, groundCheckRadius, whatIsGround);
// Set the parameter for the jump animation false or true
anim.SetBool("Grounded", grounded);
}
void Move(float horizontal, float vertical)
{
movement.Set(horizontal, 0f, vertical);
movement = movement.normalized * speed * Time.deltaTime;
playerRigidbody.MovePosition(transform.position + movement);
}
void Jump()
{
playerRigidbody.AddForce(Vector3.up * jumpHeight);
// playerRigidbody.AddForce(new Vector2(0f, jumpHeight), ForceMode2D.Impulse);
Debug.Log("Jump function");
}
void Animating(float h, float v)
{
bool walking = h != 0f || v != 0f;
anim.SetBool("IsWalking", walking);
}
}
Just guessing here, but maybe Vector3.up does not work for 2D physics? I'm not really into 2D, but you could try
playerRigidbody.AddForce(transform.up * jumpHeight);
instead.
Also, have you tried different values for jumpHeight? 5 might be way to small depending on the mass you set for your rigidbody.
And make sure you haven't restricted any axes in the inspector.
// Note: If you want the object to move in a reliable predictable way but still allow physics interactions, use MovePosition (set the object to kinematic if you want it to be unaffected by physics but still be able to affect other things, and uncheck kinematic if you want both objects to be able to be acted on by physics.
If you want to move your object but let physics handle the finer details, add a force.
playerRigidbody.rigidbody2D.AddForce(Vector3.up * 10 * Time.deltaTime);
use Vector.up, Vector.down, vector.right, Vectore.left along with time.deltaTime to have smooth movement along the frame.