I'm a beginner. I'm making a ball game in Unity, in which ball have to avoid the collision with the obstacle. In the game, I'm increasing the ball speed in every 3 seconds. Everything's working fine, but in the middle of game, I noticed the ball starts shaking, the speed decreases, and the camera can't catch the ball. I attached physics material to all gameobjects, and made all frictions zero, but the ball is still shaking.
Here is the link of the my game and the problem. Have a look: https://youtu.be/TR4M5whweTk
Here is the script attached to the ball:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;
using UnityEngine.UI;
public class PlayerController : MonoBehaviour
{
public Text gameOverText;
public Text scoreText;
public bool isGameOver;
public float speeder;
public float Score;
Touch touch;
public float speedmodifier ;
public float speed = 5;
// Start is called before the first frame update
private void Awake()
{
isGameOver = false;
Score = 0;
if(PlayerPrefs.GetFloat("HighScore") == 0)
{
PlayerPrefs.SetFloat("HighScore", 0);
}
PlayerPrefs.SetFloat("Score", Score);
}
void Start()
{
speeder = 4f;
gameOverText.enabled = false;
speedmodifier = 0.01f;
// GetComponent<Rigidbody>().velocity = new Vector3(0,0,speed);
}
// Update is called once per frame
void Update()
{ if(speeder >= 0)
{
speeder -= Time.deltaTime;
}
if (speeder<= 0 && speed < 50)
{
speed++;
speeder = 4f;
}
Debug.Log(speed);
if (isGameOver == false)
{
Score++;
}
scoreText.text = "Score : " + Score ;
if (Input.touchCount >0 && transform.position.x >= -3.5f && transform.position.x <= 3.5f)
{
touch = Input.GetTouch(0);
transform.Translate(touch.deltaPosition.x * speedmodifier,0,0);
}
else if(transform.position.x > 3.5f)
{
transform.position = new Vector3(3.49f,transform.position.y,transform.position.z);
}
else if(transform.position.x < -3.5f)
{
transform.position = new Vector3(-3.49f,transform.position.y,transform.position.z) ;
}
if (Input.GetKey(KeyCode.RightArrow) && transform.position.x < 3.5f)
{
transform.Translate(Vector3.right*speed* Time.deltaTime);
}
if (Input.GetKey(KeyCode.LeftArrow) && transform.position.x >-3.5f)
{
transform.Translate(Vector3.left*speed* Time.deltaTime);
}
transform.Translate(Vector3.forward * speed * Time.deltaTime);
}
private void OnTriggerEnter(Collider other)
{
if(other.gameObject.tag == "enemy")
{
isGameOver = true;
StartCoroutine("Wait");
GetComponent<MeshRenderer>().enabled = false;
gameObject.GetComponentInChildren<TrailRenderer>().enabled = false;
gameOverText.enabled = true;
if(PlayerPrefs.GetFloat("HighScore") < Score)
{
PlayerPrefs.SetFloat("HighScore", Score);
PlayerPrefs.SetFloat("Score", Score);
}
else
{
PlayerPrefs.SetFloat("Score", Score);
}
}
}
IEnumerator Wait()
{
Debug.Log(" My HighScore is : " + PlayerPrefs.GetFloat("HighScore"));
Debug.Log(" Score is : " + PlayerPrefs.GetFloat("Score"));
yield return new WaitForSeconds(3f);
SceneManager.LoadScene(1);
}
}
As BugFinder pointed out you are actually not moving the ball with physics, but just teleporting the ball with Transform.Translate which might be affecting the shacking issue, the other possible problem is that your ball speed might be varying due to a collision with the road, have you tried making the road RigidBody to Kinematic? so it won't affect the speed of the ball
OK you SHOULD NOT be using unity phsyics for this.
It's a "raster" game (and that's fun).
remove all physics everything. completely remove rigidbody, collider, etc
simply move the ball and/or scenery using a calculation each time.
(It's basically just frame time * speed, obviously.)
(Note, you can use strictly triggers - if you want - simply to know if the "ball" is near a "stick". But you can do that with 1 line of code, really no need for colliders/etc.)
Your Question
I just want to make sure that I am understanding your question correctly first, I believe you are asking for a way to prevent the ball from shaking during the game. (Let me know if this is incorrect, if so I apologize). From what I have gathered, this does not seem like a code based issue
Collision Detection
In unity, the rigidbody component has a field named 'Collision Detection' and this is set to discrete by default. This means that unity will look in direction of travel for a possible collider every now and again. That is an okay method to use when trying to save computer resources, however when in constant contact or at high velocities it is best to use the 'continuous' mode. This will check for a collision every physics update which occurs every physics time-step.
Colliders
Colliders in unity are a little finicky. Most notorious are mesh colliders as they have to be more heavenly processed/calculated. Using a box collider for your ground might give more accurate physics results.
Other Solutions
Whilst looking at your game video you published on YouTube, it looks like using physics may not be able to work. Since you are only traveling left, right, and forward globally, I would suggest implementing a movement script that uses an object's transform component instead of physics. This will be less resource intensive and will save further debugging headaches in the long run.
Related
So I'm creating a 2D top-down endless shooter game and need enemies to spawn faster as time goes on. The enemies health also scales with the player level. I'm using Unity 2020.1.4.
The problem I have is that at a certain point the framerate just drops cause of the amount of rigidbodies in the scene at the point in time.
Is there any way I can redo this or refine it to make it less resource intensive?
Code:
public class EnemySpawn : MonoBehaviour
{
public GameObject[] enemies, bossEnemy;
float bossTimer;
public float timeForBoss, bossTime, startTimeForBoss = 60f;
public float spawnRadius = 7f, time, defaultTime = 3f;
public float fasterSpawnIncrements, spawnIncTimer, spawnIncTimerHolder;
public bool timerDecreased = false;
// Start is called before the first frame update
void Start()
{
time = defaultTime;
spawnIncTimerHolder = spawnIncTimer; //Set timers for making enemies spawn faster over time
StartCoroutine(SpawnAnEnemy());
bossTimer = startTimeForBoss; //Set timers for making bosses spawn faster over time
timeForBoss = 60f;
}
void FixedUpdate()
{
spawnIncTimerHolder -= Time.deltaTime; //Decrease timer for enemies
while (spawnIncTimerHolder <= 0)
{
time *= fasterSpawnIncrements; //Decrease time between enemy spawns
spawnIncTimerHolder = spawnIncTimer;
}
bossTimer -= Time.deltaTime;
if (bossTimer <= 0)
{
StartCoroutine(SpawnABoss());
if (timeForBoss > 8)
{
timeForBoss -= 4f;
timerDecreased = true;
}
if (timeForBoss <= 8 && timeForBoss > 3)
{
timeForBoss -= 2f;
timerDecreased = true;
}
bossTimer = timeForBoss;
}
}
IEnumerator SpawnAnEnemy()
{
Vector2 spawnPos = GameObject.Find("Player").transform.position;
spawnPos += Random.insideUnitCircle.normalized * spawnRadius; //Set allowable spawn point area around the player
Instantiate(enemies[Random.Range(0, enemies.Length)], spawnPos, Quaternion.identity); //Spawn enemy
yield return new WaitForSeconds(time);
StartCoroutine(SpawnAnEnemy());
}
IEnumerator SpawnABoss()
{
Vector2 spawnPos = GameObject.Find("Player").transform.position;
spawnPos += Random.insideUnitCircle.normalized * spawnRadius; //Set allowable spawn point area for bosses around the player
Instantiate(bossEnemy[Random.Range(0, enemies.Length)], spawnPos, Quaternion.identity); //Spawn boss
yield return new WaitForSeconds(bossTime);
//StartCoroutine(SpawnABoss());
}
}
I know it's not the prettiest code but it works, kinda. I really need this optimised cause my computer is a potato and its getting more and more difficult to playtest every time I want to add a new feature.
Use Window->Profiler to see which steps/scripts actually take up most time.
Object Pooling. Basically, instead of "Instantiate" & "Destroy" you keep filling your pool with Instantiate, but disable instead of destroy. Then, instead of instantiate, you just enable objects and update position, reset health etc. This improves memory handling, garbage collection etc. You can look for a pooling solution or just use an Array/List and manage it yourself.
DOTS/ECS. Unity can handle a TON of entities when you use the Data oriented / entitiy component system. That is a bit different way to program and handle your data.
Unity supports Havoc Physics when using DOTS/ECS. That may help increase performance with your Rigidbodies.
I'm new to Unity and coding and am putting together a small project to help me get used to it. I have a problem with a particle system though. What I want it to do is to play two-particle systems at the same time when I hold down the spacebar and then stop when I let go, but the smoke particle system only plays after I let go of the spacebar and stops when I hold it down again. The flame particle system doesn't stop after I let go of the spacebar either. Can anyone help?
Here is the code.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Rocket : MonoBehaviour
{
public float fuel = 500f;
public float speed = 100f;
public Rigidbody rb;
public ParticleSystem flame;
public ParticleSystem smoke;
void Start()
{
flame.Stop();
smoke.Stop();
}
void FixedUpdate()
{
if (Input.GetKey(KeyCode.Space) && fuel > 0)
{
rb.AddForce(Vector3.up * speed);
float fuelUse = fuel-- * Time.deltaTime;
flame.Play();
smoke.Play();
}
}
}
You need to put an else after your if.
In this way when you aren't pressing space it will always stop, but will start when you press space and fuel is >0.
A great thing you can do in this cases is to put some Debug.Log() inside the if to check when it's playing so you can find other problems.
For example you can add the else with flame.Stop() and smoke.Stop() and put inside it a Debug.Log("stop") and inside the if a Debug.Log("play") so in the console you will always know what is happening and what is wrong
GetKey function resetting ur particle systems per frame so u can't see till release spacebar
if (Input.GetKeyDown(KeyCode.Space) && fuel > 0)
{
isPressed = true;
flame.Play();
smoke.Play();
}
if (isPressed && fuel > 0)
{
rb.AddForce(Vector3.up * speed);
float fuelUse = fuel-- * Time.deltaTime;
}
if (Input.GetKeyDown(KeyCode.Space))
{
isPressed = false;
flame.Stop();
smoke.Stop();
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerController : MonoBehaviour
{
public float speed;
public float jumpForce;
private float moveInput;
private Rigidbody2D rb;
private bool facingRight = true;
// Start is called before the first frame update
void Start()
{
rb = GetComponent<Rigidbody2D>();
}
// Update is called once per frame
void Update()
{
}
void FixedUpdate()
{
moveInput = Input.GetAxis("Horizontal");
rb.velocity = new Vector2(moveInput * speed, rb.velocity.y);
if(facingRight == false && moveInput > 0)
{
Flip();
}
else if(facingRight == true && moveInput < 0)
{
Flip();
}
}
void Flip()
{
facingRight = !facingRight;
Vector3 Scaler = transform.localScale;
Scaler.x *= -1;
transform.localScale = Scaler;
}
}
I'm made a c# 2D player controller script to use in unity, but when I hit play, my player won't flip and face a different direction when he moves a different direction. Can anyone spot what's wrong in my script?
Nevermind. Was just a dumb bug. I put an outdated AND updated script component into my player. Yes I know I'm stupid.
Unity seems a good choice to developp your game but due to the simplicity of your game, i think it will be easier to create it using Android Studio, it is more easier to handler Character Sprite and Animation. All depend of what kind of game you want to create.
"""For instances guys, i create a simple SkaterBoard game using simple gravity physics with Android Studio, I would really appreciate if you could left a review on it."""
(Android Link) Skater Soldier Game: https://play.google.com/store/apps/details?id=com.fight.exempleclass
Always make sure you double check settings, values, and where you attached scripts : )
I've heard a couple people advise against flipping via scale and instead prefer :
transform.Rotate(0f, 180f, 0f);
Or depending on the gameplay / utility needed using SpriteRenderer.flipX
In case you'd like alternatives.
I have a blockbreaker type game coded using C# that mainly works fine but upon play testing i have found the ball will slow right down in certain situations! i.e if it wedges between to game object bricks the force of the ball rapidly slows down! 8 times out of ten this will not happen but other times it does and im unsure why! i will post the Ball script i think you will need to help solve this but should you need anymore information then please ask.
public class Ball : MonoBehaviour {
private Paddle paddle;
private bool hasStarted = false;
private Vector3 paddleToBallVector;
void Start () {
paddle = GameObject.FindObjectOfType<Paddle> ();
paddleToBallVector = this.transform.position - paddle.transform.position;
}
// Update is called once per frame
void Update () {
if (!hasStarted) {
//lock ball relative to the paddle
this.transform.position = paddle.transform.position + paddleToBallVector;
//wait for mouse press to start
if (Input.GetMouseButtonDown (0)) {
//if (Input.GetTouch(0).phase == TouchPhase.Ended){
hasStarted = true;
this.GetComponent<Rigidbody2D> ().velocity = new Vector2 (2f, 10f);
}
}
}
void OnCollisionEnter2D(Collision2D collision){
Vector2 tweak = new Vector2 (Random.Range(0f,0.2f),Random.Range(0f,0.2f));
if (hasStarted) {
GetComponent<AudioSource> ().Play ();
GetComponent<Rigidbody2D>().velocity += tweak;
}
}
}
You are adding directly to the velocity of the ball. The velocity variable defines a direction and speed, not just a speed as you are thinking here.
So, when the ball collides with a block it has a velocity of (+x, +y). After the collision and bounce is has a velocity of (+x, -y). So by adding a random positive value to the velocity when it has the -y velocity means that it will slow down the ball.
This does not happen every time because you are moving the ball in your Update() method. Change that to 'FixedUpdated()'. Fixed Update handles all physics calculations.
Also, I would recommend having a RigidBody2D on your Ball object. Moving physics objects should always have RigidBodies. With this, you can then use AddForce in the forward direction of your ball and that should solve your problem.
EDIT: I see you have a RigidBody2D already. I missed that the first time. Instead of having GetComponent<RigidBody2D>().velocity try GetComponent<RigidBody2D>().AddForce( transform.forward * impulseAmount, ForceMode.Impluse );
everyone! I am new to Unity and try to create a 2D arcade game by allowing my character to jump up at a trajectory motion to reach something then fall down. I use gravity scale equal to 1 and move_speed 1000 and rest_speed 500 but as soon as I hit space, the character just fell down instead of going up.
Also, walk.IsWalk is an int from Walking class(as soon as I hit right arrow, set IsWalk to 2 for example). My expected result would be as soon as we hold both space and right arrow key, the character should move upwards follow a curved motion. I dont know what is going on here, can anyone kindly point me to a direction? Thanks!
My code as follows:
using UnityEngine;
using System.Collections;
public class Jumping : MonoBehaviour
{
Rigidbody2D rb2D;
Animator anim;
Walking walk = new Walking();
public float move_speed;
public float rest_speed;
void Start()
{
rb2D = GetComponent<Rigidbody2D>();
anim = GetComponent<Animator>();
}
void FixedUpdate()
{
//float xmove = Input.GetAxis("Horizontal");
//float ymove = Input.GetAxis("Vertical");
//var curr = new Vector2(xmove, ymove);
if (Input.GetKey("space"))
{
anim.SetTrigger("JumpButtonPres");
rb2D.gravityScale = 1;
if (walk.isWalk == 2)
{
rb2D.AddForce(rb2D.position * move_speed);
}
else if (walk.isWalk == 1)
{
//rb2D.velocity += (Vector2.up * (-rb2D.velocity.x));
rb2D.AddForce(-rb2D.position * move_speed);
}
else
{
rb2D.AddForce(rb2D.position * rest_speed);
}
}
}
}
partial code for rigidbody2D.AddForce
It seems your problem is that whenever you are adding force to your rigidbody, you are multiplying it by the position where it's located, so by this i'm guessing your character is placed at a negative y component coordenate, and this is why rb2D.position * rest_speed will result on your playing falling. Change it for vector2.up * rest_speed and you should be fine.
Hope I was able to help.
NoƩ