I'm making a 2D Block breaker game; the issue is that my ball will slow down after a while, yet there isn't any gravity and the bounciness is at 100% so it should keep all its kinetic energy. I just need the ball to stay at a constant speed.
Here's my code:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Ball : MonoBehaviour {
public Paddle paddle;
private Vector3 paddleToBallVector;
private bool Started = false;
void Start () {
paddleToBallVector = this.transform.position
paddle.transform.position;
print(paddleToBallVector);
//this.GetComponent<Rigidbody2D>().drag = 0f;
}
void FixedUpdate () {
if (!Started) {
this.transform.position = paddle.transform.position + paddleToBallVector;
if (Input.GetMouseButtonDown(0))
{
Debug.Log("mouse clicked, Started = " + Started);
Started = true;
this.GetComponent<Rigidbody2D>().velocity = new Vector2(2f, 10f);
}
}
}
}
The issue isn't in the code - it's in the game Gravity settings. You could solve it in one of two ways:
1) change the gravity scale of the ball - go to the ball game object or Prefab, and look at the RigidBody2D component. In there, you have a field called "Gravity Scale", usually set to 1. Changing it to 0.1 will make your ball light and quick. However, this setup isn't ideal for a game with multiple levels.
2) Change the global gravity in the project settings. Go in the Edit Menu to the Project Settings and in the menu choose Physics2D:
In the panel that is opened you usually have a realistic gravity scale of -9.81. Change it to something like -1.
This will make all the objects in your game light, and lessen the hold of gravity for all levels. In a brick-breaker type game when only the ball is loose and thrown around, it makes the most sense.
If you want the ball to have constant velocity, you could set it each frame in Update
myRigidbody.velocity = speed * (myRigidbody.velocity.normalized);
Where myRigidBody is a private RigidBody declared somewhere in your script, and set in Start() like this
myRigidbody = this.GetComponent<Rigidbody>();
Because you dont want to have to call GetComponent every single frame.
Create a physics material 2D. Keep the bounciness at 1 but reduce the friction to zero. Now attach that material to your Ball Collider. Your ball won't lose any speed when colliding now
Related
I'm making a 3D Side-Scroll Platformer Game,
I have trouble with my character when it steps on the moving platform it will not come along on the platform. I want my character to stay on the moving platform so I think converting my Character Controller into Rigibody will help me,
I need help to give me ideas on how I can reuse my Character Controller Script in Rigibody. This is my code, how can I reuse this in Rigibody script?
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerController : MonoBehaviour
{
public CharacterController controller;
private Vector3 direction;
public float speed = 8;
public float jumpForce = 30;
public float gravity = -20;
public Transform groundCheck;
public LayerMask groundLayer;
public bool ableToMakeADoubleJump = true;
public Animator animator;
public Transform model;
void Start()
{
}
// Update is called once per frame
void Update()
{
if (PlayerManager.gameOver)
{
//play death animation
animator.SetTrigger("die");
//disable the script
this.enabled = false;
}
float hInput = Input.GetAxis("Horizontal");
direction.x = hInput * speed;
animator.SetFloat("speed", Mathf.Abs(hInput));
bool isGrounded = Physics.CheckSphere(groundCheck.position, 0.15f, groundLayer);
animator.SetBool("isGrounded", isGrounded);
if (isGrounded)
{
//Jump Codes
ableToMakeADoubleJump = true;
if (Input.GetButtonDown("Jump"))
{
Jump();
}
}
else
{
direction.y += gravity * Time.deltaTime;
if (ableToMakeADoubleJump & Input.GetButtonDown("Jump"))
{
DoubleJump();
}
}
if (hInput != 0)
{
Quaternion newRoattion = Quaternion.LookRotation(new Vector3(hInput, 0, 0));
model.rotation = newRoattion;
}
//Move the player using the character controller
controller.Move(direction * Time.deltaTime);
}
private void DoubleJump()
{
//Double Jump Codes
animator.SetTrigger("doubleJump");
direction.y = jumpForce;
ableToMakeADoubleJump = false;
}
private void Jump()
{
direction.y = jumpForce;
}
}
I would not recommend switching between the two. It would get tricky, and think about it, you are alternating between two very different things. One is movement and one is physics.
However, I would reccomend adding to your current script so that the player would move with the moving platform.
There is a lot of stuff in this answer, so read the whole thing.
Btw, when I talk about velocity, in your case it is direction.
Since it seems like you know how to code pretty well, I won’t write out the script, rather tell you some physics ideas to get you going in the right direction.
The reason people can stand on a moving platform and not fall off is because of friction.
If you are standing on a gameObject with enough friction (you could add a physics material the gameObject you stand on and change friction there. Note that physics materials only work with rigidbodies, but you might want to use it to just read the value)
First of all, you are going to want to raycast down to obtain the object you are standing on. From there you can get the physics material from hit.collider.sharedMaterial (or any other hit. to obtain data about what object you are standing on.
If they friction is too low, just make the character slip off, like it was before (I assume)
If the friction is above a threshold, get the velocity from the object you are standing on. If it was a rigidbody, hit.rigidbody.velocity. If it is controlled by script, use hit.collider.gameObject.GetComponent<scriptname>().velocityvariablename This part is continued later on
This is not necessary but useful: You can think of this as grabbing on a rope. When you are grabbing on a slippery rope, and someone pulls it (Like tug of war), You won’t move because the rope will slide through your hands. If the rope had grip tape on it and someone pulled it, you would come with it because it has more friction. You can think of the platform the same way. Now on to the more complex part: When you grip a rope that is stationary, and someone pulls it, you come with it as its velocity changes. When the rope is already being pulled, so its velocity is not stationary and it is already something. You grab onto it and a similar thing happens. It is like you are becoming a part of that rope. Similar to how if you are running, the arms and legs and head is a part of you. If you lose grip, you are no longer a part of that body, like your arms falling off when running. In other words, you become part of the body when you attach yourself to it.
Bottom line:
Get the velocity of the platform and set platformVel to it, do not add that to velocity, rather do a seperate controller.Move(platformVel).
A small customization:
Vector3.Lerp the platformVel to 0, so it doesn’t change while on the platform, but gradually goes to (0,0,0) when you get off. This way, there is a little momentum maintained from standing on the platform.
Feel free to ask anything in the comments.
I am making a simple 2d shooter in unity. I have made a prefab for my weapons and a script to shoot. When I enter the game mode I can see the bullet objects being created, but the bullets don't show on the screen. When I pause it and enter the scene mode they show (most of the time) any idea what could be causing this??
Here is the various settings on my bullet :
Thanks in advance for your help
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Weapon : MonoBehaviour
{
//variable to handle what progectile to spawn
public GameObject projectile;
//from where does the bullet coem from
public Transform shotPoint;
//How much time should be taken between shots
public float timeBetweenShots;
//time to shoot another bullet
private float shotTime;
// Update is called once per frame
private void Update()
{
//Callculating the the current mouse position to the current weapon position
//Input.mouse position returns a screenpoint
Vector2 direction = Camera.main.ScreenToWorldPoint(Input.mousePosition) - transform.position;
float angle = Mathf.Atan2(direction.y, direction.x) * Mathf.Rad2Deg;
Quaternion rotation = Quaternion.AngleAxis(angle, Vector3.forward);
transform.rotation = rotation;
//if the left mouse button is pressed
if(Input.GetMouseButton(0)){
//if the current time in the game is greater than the shot time
if (Time.time >= shotTime)
{
//shoot projectile
Instantiate(projectile, shotPoint.position, transform.rotation);
//recalculate shot time current time + time between shots
shotTime = Time.time + timeBetweenShots;
}
}
}
}
Check the order layer if you're by mistake not covering your bullets with the background image. Just make your bullet prefab layer higher then background equivalent.
Moreover, move the background node out of the scope of Player (currently you have it in the Player node), it should be equally set as your Main Camera and Player nodes in the tree. Then check the layering order and make sure order value in background is the lowest of all of your sprites.
Basically you are creating bullets inside of the weapon thats why you are not able to see your bullets. I create simple scene and adding sphere as a bullet then I realized sphere spawning in the gun(for me in the cube). If you will adding force everything will be okay.
Assume the shootPoint is somewhere over the gun barrel,
Instantiate(projectile, shotPoint.position, transform.rotation);
You should give them force,
GameObject projectile= Instantiate (prefab, position, rotation) as GameObject;
rb = projectile.GetComponent<Rigidbody>();
rb.AddForce (direction * speed);
Dont forget to add rigidbody to the bullet
I am currently creating a game in Unity, in which you move a ball around using OnMouseDrag(), a CircleCollider2D and a RigidBody2D. This is how I set the position of the ball:
private void OnMouseDrag()
{
Vector2 mouseInWorld = Camera.main.ScreenToWorldPoint(Input.mousePosition);
playerRb.position = new Vector3(mouseInWorld.x, mouseInWorld.y, 0);
}
I still want the ball to slide on collision while the mouse moves around. Is there a way to do this?
I have tried RigidBody2D.MovePosition(), but the ball jumped around from one point to another, and Raycasts but couldn't get that to work either.
EDIT:
This is what I've got now:
playerRb.velocity = new Vector3(mouseInWorld.x - playerRb.position.x, mouseInWorld.y - playerRb.position.y, 0);
Now the problem is, that the ball lags behind the mousePosition.
When you use RigidBody.MovePosition, you don't call the physics engine and so it ignores collisions. If you want collisions to happen you need to use RigidBody.Velocity instead.
Doing this change will require you to make some change to your code though because what you give to RigidBody.Velocity is a velocity and not a position so you will need to calculate the velocity required in x,y (and z if you are in 3d) to reach your destination.
I invite you to read the Unity page about velocity for more info
https://docs.unity3d.com/ScriptReference/Rigidbody-velocity.html
Note: This will make the player/ball stick to collisions.
Modifying the velocity could cause the ball to bounce around unexpectedly when the ball collides with the wall. I would use a CircleCast for this, check if it hit anything, then use MovePosition accordingly:
float cursorDepth;
Rigidbody2D playerRb;
CircleCollider cc;
void Awake()
{
playerRb = GetComponent<Rigidbody2D>();
cc = GetComponent<CircleCollider>();
}
private void OnMouseDrag()
{
Vector2 mouseInWorld = Camera.main.ScreenToWorldPoint(Input.mousePosition);
Vector2 posToMouse = mouseInWorld - playerRb.position;
RaycastHit2D hit = Physics2D.CircleCast(playerRb.position,
cc.radius * transform.lossyScale.x, posToMouse, posToMouse.magnitude);
if (hit.collider != null)
{
mouseInWorld = hit.centroid;
}
playerRb.MovePosition(mouseInWorld);
}
But notice that if the ball can't move all the way to the mouse, it might cause the drag to end. So, plan accordingly.
Ok - I'm super new at Unity (just learning for fun) and wanted to have an enemy cube fall as the player gets within 15 on the Z. I can get the rigidbody function of the enemy cube to 'sleep' but then when I get within 15 or less, it will not awaken and start to fall. Can you help me with my code? The Debug.Log is telling me what I want as I run it, but the rigidbody is not reactivating on the enemy cube. Sorry if this is a super simple request...just trying to learn!
using UnityEngine;
public class activatefall : MonoBehaviour
{
public Transform Player;
public Rigidbody rbgo;
private float coolnumber;
private float badtogood;
// Update is called once per frame
void FixedUpdate()
{
coolnumber = transform.position.z;
badtogood = coolnumber - Player.position.z;
Debug.Log(badtogood);
if (badtogood < 15f)
{
rbgo.WakeUp();
Debug.Log("Falling!");
}
else
{
rbgo.Sleep();
Debug.Log("Frozen");
}
}
}
If you want a Rigidbody to be stopped and then fall, you can just use rbgo.useGravity = false/true.
There are other ways though, you can play with RigidbodyConstraints, making the Rigidbody freeze in Y axis and then remove this constraint.
If you want to stop a Rigidbody completely after it moves, you can just do rbgo.constraints = RigidbodyConstraints.FreezeAll or rbgo.velocity = Vector3.zero (and then, if you want to disable the gravity, you do rbgo.useGravity = false.
You can also use transform.position and/or transform.Translate if you don't want to deal with the Rigidbody itself.
I am in the middle of working on a game, and I just started. I added in the map as a png and have been adding in colliders around the areas that I want to be impassable (it is a 2D platformer). I have an enemy already designed and added a 2DRigidBody component to it as it moves around, and started to use 2DBoxColliders as the colliders for the level, and my script that I have written:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Sexapus : MonoBehaviour {
public static int Velocity = 42;
public Rigidbody2D rb;
public Vector2 dir;
public Animator anim;
void Start () {
rb = GetComponent<Rigidbody2D>();
dir = new Vector2(1, 0);
anim = GetComponent<Animator>();
}
// Update is called once per frame
void Update () {
rb.velocity = dir * Velocity;
anim.SetFloat ("Direction", dir.x);
}
void OnCollisionEnter2D (Collision2D col) {
dir = dir * -1;
}
//CHECK TASKS
}
Meant that the enemy would hit the side of a wall and then rotate and start going the other way. I realised with the size of my map that using multiple 2DBoxColliders (and when I say multiple I mean I would probably have to use over a hundred) was a very bad way of doing it. I have now started to use a 2DpolygonCollider for the map as well, but now the enemy doesn't collide with the sides of the wall and turn around, it just stays facing the same direction but doesn't move. Anyone know why?
You are using the same collider for the floor and the walls... So when you collide with the wall, and are already touching the floor, the OnCollisionEnter will not happen.
So, you do get the collision, hence the object cant move past the wall, BUT it's not a new collision!
Solution: Use a collider to the floor, and a different one to the walls, Edge colliders are good for this.