I am developing an infinite tower jumping game using Unity2D, and currently working on a continually moving object which causes the player to die if contact is made. The player can also die if they either fall off of a platform or off-screen. All methods of death rely on a BoxCollider2D I am using as a Killbox (tagged accordingly) - the player sprite has a RigidBody2D and BoxCollider2D attached to it - so there is one attached to the main camera (it moves as the player sprite progresses through the level) and to the top of the moving object.
The current code I have works up to the point where the game over screen appears on player death, but the object continues to move whilst everything else stops.
Here is my code for the moving object:
public class Water : MonoBehaviour {
private Collider2D playerCollider;
public ControllerNew thePlayer;
private float speed = 2f;
public GameManager theGameManager;
//reference scoremanager
private ScoreManager theScoreManager;
bool shouldMove = true;
// Start is called before the first frame update
void Start()
{
theScoreManager = FindObjectOfType<ScoreManager>();
thePlayer = FindObjectOfType<ControllerNew>();
lastPlayerPosition = thePlayer.transform.position;
}
// Update is called once per frame
void Update()
{
if (shouldMove = true)
{
transform.position += Vector3.up * speed * Time.deltaTime;
if (theScoreManager.scoreCount > 100 && shouldMove)
{
transform.position += Vector3.up * (speed+1) * Time.deltaTime;
}
if (theScoreManager.scoreCount > 250 && shouldMove)
{
transform.position += Vector3.up * (speed +2) * Time.deltaTime;
}
if (theScoreManager.scoreCount > 500 && shouldMove)
{
transform.position += Vector3.up * (speed+4) * Time.deltaTime;
}
if (theScoreManager.scoreCount > 1000 && theScoreManager.scoreCount > theScoreManager.hiScoreCount && shouldMove)
{
transform.position += Vector3.up * (speed+5) * Time.deltaTime;
}
}
}
void OnTriggerEnter2D(Collider2D other)
{
if (other.gameObject.tag == "Player New")
{
transform.position += Vector3.zero * (speed * 0) * Time.deltaTime;
}
//call object by its tag
if (other.gameObject.tag == "Killbox")
{
shouldMove = false;
if (shouldMove = false){
theGameManager.RestartGame();
transform.position += Vector3.zero * (speed * 0) * Time.deltaTime;
}
}
}
Edit (Issue resolved)
So it turns out that after adding the Water.StopMoving() method into my controller script, the water had not been called as a GameObject in void Start(). Once this was added, the water object stopped on collision.
Just want to say thank you #D.B for your help and bearing with me - apologies if the info I gave wasn't everything you needed to be able to assist me
You made a mistake on the first line of the Update() method :
if (shouldMove = true)
You set the bool to true, not comparing it. Use double = otherwise it will set the bool to true at every frame.
if (shouldMove == true)
By the way you can simplify this part :
//call object by its tag
if (other.gameObject.tag == "Killbox")
{
shouldMove = false;
theGameManager.RestartGame();
transform.position += Vector3.zero * (speed * 0) * Time.deltaTime;
}
(You forgot a = too)
I made a test with this simplified script
void Update()
{
if (shouldMove == true)
{
Debug.Log("move");
transform.position += Vector3.up * speed * Time.deltaTime * GetDifficultyFactor();
}
}
private float GetDifficultyFactor()
{
float factor = 1f;
if(theScoreManager.scoreCount > 100)
{
factor += 1f;
}
if (theScoreManager.scoreCount > 250)
{
factor += 2f;
}
// Add all your speed modification condition here
return factor;
}
void OnTriggerEnter2D(Collider2D other)
{
Debug.Log("trigger");
//call object by its tag
if (other.gameObject.tag == "Killbox")
{
Debug.Log("die");
shouldMove = false;
}
}
And it work fine. Are you sure you have a collider2D set to trigger on your charactert with the tag "Killbox" (with the first letter in uppercase ?). You should have a rigidbody2d on the character too.
Mistake come frome another part of your code or with some trouble with collider2D/tag/RigidBody2D. Without seeing all it's difficult to help you more.
You should try to add some Debug.Log() or use debugeur with breakpoint to be sure code enter into your "die" statement and then not going on the Update if statement. If yes, it's mean you probably set the shouldMove variable in another part of your script.
Answer regarding discussion in comments
I think you want to make this OnTriggerEnter2D logic in both script.
Without seeing all your project I suggest you to make a reference bewteen your character and your water script. Then when the player die the player script will call a method on water to stop it.
public class Player : MonoBehaviour
{
public Water Water;
private void OnTriggerEnter2D(Collider2D other)
{
if (other.gameObject.tag == "Killbox")
{
Debug.Log("die");
Water.StopMoving();
}
}
}
public class Water : MonoBehaviour
{
private bool shouldMove;
public void Update()
{
...
}
public void StopMoving()
{
shouldMove = false;
}
// No Trigger logic here
}
Related
So my problem here is that when the player holds the space button the addForce function is increased which I don't want.
So what I want is that if a player holds the space button they can keep jumping continuously if they're on the ground...
Here is my code:
private void Update()
{
GetComponent<Rigidbody2D>().velocity = new Vector2(1.0f * movementSpeed, GetComponent<Rigidbody2D>().velocity.y);
if (IsGrounded() && Input.GetKey("Jump"))
{
Debug.Log("IS JUMPING");
_rigidBody.AddForce(new Vector2(0, jumpForce), ForceMode2D.Impulse);
}
}
This is the IsGrounded Code:
private bool IsGrounded()
{
RaycastHit2D raycastHid2d = Physics2D.BoxCast(boxCollider2d.bounds.center, boxCollider2d.bounds.size, 0f, Vector2.down, .1f, layerMask);
//Debug.Log(raycastHid2d.collider);
return raycastHid2d.collider != null;
}
As said the issue is most probably that the rigibody doesn't move far enough away from the ground immediately so you might get multiple input frames before IsGrounded returns false.
In general for physics related things you should rather use FixedUdpate.
While Update is executed every frame, FixedUpdate uses a fixed time delta => There might be multiple Update calls before he physics are actually applied and your scene is updated accordingly!
While you will want to get one time event input (GetKeyDown) still in Update (otherwise you might miss it) I would move continuous user input into FixedUpdate
[Serializefield] Rigidbody2D rigidbody;
private void Awake()
{
if(!rigidbody) rigidbody = GetComponent<Rigigbody2D>();
}
private void FixedUpdate()
{
rigidbody.velocity = new Vector2(movementSpeed, rigidbody.velocity.y);
if (IsGrounded() && Input.GetKey("Jump"))
{
Debug.Log("IS JUMPING");
rigidbody.AddForce(Vector2.up * jumpForce), ForceMode2D.Impulse);
}
}
And as said just to be super sure you could still add some cooldown like e.g.
private float timer;
public float jumpCooldown = 0.1f;
private void FixedUpdate()
{
rigidbody.velocity = new Vector2(movementSpeed, rigidbody.velocity.y);
timer += Time.deltaTime;
if(timer < jumpCooldown) return;
if (IsGrounded() && Input.GetKey("Jump"))
{
Debug.Log("IS JUMPING");
rigidbody.AddForce(Vector2.up * jumpForce), ForceMode2D.Impulse);
timer = 0f;
}
}
I created a multiplayer game with pun2 (Photon Unity Networking) but when I move and look actually changes of my character will apply to other characters, also when my friends move their changes will apply to my character
void Update(){
isGrounded = Physic.CheckSqhere(groundCheck.position,groundDistance, LayeMask);
if (isGrounded && velocity.y<0)
{
velocity.y=-1f;
}
float x = Input.GetAxis("Horizontal");
float z = Input.GetAxis("Vertical");
if (Input.GetButtonDown("Jump") && isGrounded)
{
velocity.y = Mathf.Sqrt(jumpHeight * -2f * gravity);
}
Vector3 Movement = transform.right * x * transform.forward *z;
if (isGrounded)
{
characterController.Move(Movement * speed * Time.deltaTime)
}
else{
characterController.Move(Movement * speedOnJumping * Time.deltaTime)
}
velocity.y +=gravity * Time.deltaTime;
characterController.Move(velocity * Time.deltaTime);}
and
void Start(){
PhotonNetwork.ConnectUsingsettings();
}
public override void onConnectedToMaster(){
PhotonNetwork. AutomaticallySyncScene = true;
createButton.onclick.AddListener(()=>{
PhotonNetwork.createRoom("Amin's Room");
});
joinButton.onclick.AddListener(()=>{
PhotonNetwork.JoinRoom("Amin'sRoom");
});
base.OnConnectedToMaster();
}
public override void OnJoinedRoom(){
if (PhotonNetwork.IsMasterClient){
Debug.Log("you are the master");
PhotonNetwork.LoadLevel(1);
}
base.OnJoined Room();
}
For the future: Please add code as TEXT not as images to your questions!
In your Update method you listen to global keyboard events. These will be executed on all instances of that script.
You should check if the component actually belongs to your own player and otherwise ignore it or even better disable the entire component!
See Photon User Input Management
// Note that inheriting from MonoBehaviourPun instead of MonoBehaviour is mandatory!
public class YourClass : MonoBehaviourPun
{
...
private void Update()
{
// As also described in the link the IsConnected is checked in order to allow
// offline debugging of your behavior without being in a network session
if(PhotonNetwork.IsConnected && !photonView.IsMine)
{
// optional but why keep an Update method running of a script that
// shall anyway only be handled by the local player?
//enabled = false;
// Or you could even remove the entire component
//Destroy(this);
// Do nothing else
return;
}
...
}
}
So basicy i need my character to go up when space or mousebutton are pressed. I added rigbody 2d and box colider 2d to my gameobject (player). The problem is when I hit space or mousebuttonit only jump not constantly moving up.
Here is my code:
using UnityEngine;
using System.Collections;
public class PixelMovement : MonoBehaviour {
Vector3 velocity = Vector3.zero;
public Vector3 PressVelocity;
public float maxSpeed = 5f;
public float fowardSpeed = 1f;
public float jumpForce;
bool didPress = false;
// Use this for initialization
void Start () {
}
//Do Graphic & Input updates
void Update()
{
if (Input.GetKey(KeyCode.Space) || Input.GetMouseButton(0))
{
didPress = true;
}
}
//Do physics engine updates here
void FixedUpdate()
{
velocity.x = fowardSpeed;
if (didPress == true)
{
didPress = false;
velocity += PressVelocity * Time.deltaTime *jumpForce;
}
velocity = Vector3.ClampMagnitude(velocity, maxSpeed);
transform.position += velocity * Time.deltaTime;
}
}
Ok this works for me. Thanks everyone for help :)
using UnityEngine;
using System.Collections;
public class PixelMovement : MonoBehaviour {
public float playerSpeed;
public Vector3 gravity;
public float maxSpeed = 5f;
Vector3 velocity = Vector3.zero;
public float fowardSpeed = 1f;
bool didPress = false;
void Update()
{
if (Input.GetKey(KeyCode.Space) || Input.GetMouseButton(0))
{
didPress = true;
}
else
{
didPress = false;
}
}
void FixedUpdate()
{
velocity.x = fowardSpeed;
transform.position += velocity * Time.deltaTime;
if (didPress == true)
{
float amntToMove1 = playerSpeed * Time.deltaTime;
transform.Translate(Vector3.up * amntToMove1);
}
velocity = Vector3.ClampMagnitude(velocity, maxSpeed);
transform.position += velocity * Time.deltaTime;
}
}
If you are using gravity and RigitBody2D's mass. I recomend you use the RigitBody2D.Addforce() method to jump your caracter, because if you just change the caracter position, the gravity will turn down him to the ground inmediately
This code creates the effect of a "rocketman" that takes off when the user keeps the spacebar pressed:
using UnityEngine;
using System.Collections;
public class jumpAntigravity : MonoBehaviour {
Vector2 upForce;
void Start () {
//Up force set to double of gravity
upForce = new Vector2(0, 9.8f*2);
}
void Update () {
if (Input.GetKey(KeyCode.Space))
{
print("Spacebar is down");
GetComponent<Rigidbody2D>().AddForce(upForce);
}
}
}
if (Input.GetKey(KeyCode.Space) || Input.GetMouseButton(0))
{
didPress = true;
}
else
{
didPress = false;
}
and remove didPress = false; from FixedUpdate() function
EDIT: Ok, wait, I just noticed you update transform.position in FixedUpdate() which is not really a good idea. When you do so you basically teleport your object from one position to another ignoring all kinds of physics (which probably is the reason you are using FixedUpdate()). With your script colliding with other objects will give you weird results. Find a tutorial on using RigidBodies to do proper physics-aware movement, or just move all your code to Update() because right now you might have some frames where your object doesn't move and other frames where it moves twice the distance. This will happen because FixedUpdate() may get executed any number of times (including 0) in a single frame, depending on a setup. FixedUpdate runs firmly 50 times per second by default, while Update runs roughly 60 times per second (on mobile 30) by default. And lastly, in FixedUpdate never use Time.deltaTime, use Time.fixedDeltaTime:
Time.deltaTime is equal to roughly 1 / 60th of a second (1 frame duration)
Time.fixedDeltaTime is roughly 1 / 50th of a second (1 physics update duration)
FixedUpdate can be called multiple times per frame in succession. This is based on the physics settings for your project. You can edit this to add more or less accuracy to your physics.
Update is called only 1 time a frame.
So you want to avoid doing logic in the FixedUpdate. If you want to move a rigid body use MovePosition.
From the Unity docs: If Rigidbody interpolation is enabled on the Rigidbody, calling Rigidbody.MovePosition results in a smooth transition between the two positions in any intermediate frames rendered. This should be used if you want to continuously move a rigidbody in each FixedUpdate.
I am trying to make a script where i can move a ball, horizontal and vertical. I managed to get that working.
But now I want to make my ball "jump". I ended with script below, but now my ball just get launched like a rocket xD
Can anyone help me out
using UnityEngine;
using System.Collections;
public class PlayerController : MonoBehaviour
{
public float speed;
public float jumpSpeed;
public GUIText countText;
public GUIText winText;
private int count;
void Start()
{
count = 0;
SetCountText();
winText.text = " ";
}
void FixedUpdate()
{
float moveHorizontal = Input.GetAxis ("Horizontal");
float moveVertical = Input.GetAxis ("Vertical");
Vector3 movement = new Vector3 (moveHorizontal, 0, moveVertical);
Vector3 jump = new Vector3 (0, jumpSpeed, 0);
GetComponent<Rigidbody>().AddForce (movement * speed * Time.deltaTime);
if (Input.GetButtonDown ("Jump"));
GetComponent<Rigidbody>().AddForce (jump * jumpSpeed * Time.deltaTime);
}
void OnTriggerEnter(Collider other)
{
if (other.gameObject.tag == "PickUp") {
other.gameObject.SetActive(false);
count = count +1;
SetCountText();
}
}
void SetCountText()
{
countText.text = "Count: " + count.ToString();
if (count >= 10)
{
winText.text = "YOU WIN!";
}
}
}
Jumping does not work with adding a continuous force on an object. You will have to apply a single impulse to the object once when the jump button is first pressed. This impulse will also not include a time factor, because it is applied only once. So you would get something like this:
bool jumping;
if (Input.GetButtonDown ("Jump") && !this.jumping);
{
GetComponent<Rigidbody>().AddForce (jumpForce * new Vector3(0,1,0));
this.jumping = true;
}
Also note that in your example you are multiplying the upward unit vector by the jumpspeed twice. Once in the jump vector initialization and then once in the AddForce method.
Of course, you will also have to make sure that gravity applies to pull the object back down (and if the object hits the ground, reset the jump bool.
In general, depending on what kind of game you are making, it is easier to just set the velocity of the object yourself and don't work with the Unity physics engine to do some simple moving around.
There is an error in your code in the function FixedUpdate:
if (Input.GetButtonDown ("Jump"));
in that way you are applying a force on your object at every frame because the semicolon is excluding the row below from the condition. By removing the semicolon you will have a correct if implementation in case of a jump, as long as on your RigidBody component UseGravity is enabled.
if (Input.GetButtonDown ("Jump"))
GetComponent<Rigidbody>().AddForce (jump * jumpSpeed * Time.deltaTime);
Hope it helps.
Thanks everyone, it was a great help. I now have a jumping character. One who can only jump when grounded.
public bool IsGrounded;
void OnCollisionStay (Collision collisionInfo)
{
IsGrounded = true;
}
void OnCollisionExit (Collision collisionInfo)
{
IsGrounded = false;
}
if (Input.GetButtonDown ("Jump") && IsGrounded)
{
GetComponent<Rigidbody>().velocity = new Vector3(0, 10, 0);
}
I'm trying to find a way to pause my game in Unity without using "Time.timeScale = 0;". The reason I want to change this is that I want to make the character play an animation while the game is paused. Is there a way to change this script so that the gravity and forward speed only "sets in" after the player have clicked space? Or is there a better way to solve the problem?
This is the script:
public class PlayerMove : MonoBehaviour {
Vector3 velocity = Vector3.zero;
public Vector3 gravity;
public Vector3 FlyVelocity;
public float maxSpeed = 5f;
public float forwardSpeed = 1f;
bool didFly = false;
bool dead = false;
float deathCooldown;
Animator animator;
// Use this for initialization
void Start () {
animator = GetComponentInChildren<Animator>();
}
// Do Graphic & Input updates here
void Update(){
if (dead) {
deathCooldown -= Time.deltaTime;
if (deathCooldown <= 0) {
if (Input.GetKeyDown(KeyCode.Space) || Input.GetMouseButtonDown(0) ) {
Application.LoadLevel( Application.loadedLevel );
}
}
}
if (Input.GetKeyDown(KeyCode.Space) || Input.GetMouseButtonDown(0) ) {
didFly = true;
animator.SetTrigger ("DoFly");
}
}
void OnCollisionEnter2D(Collision2D collision) {
animator.SetTrigger ("Death");
dead = true;
}
// Do physics engine updates here
void FixedUpdate () {
if (dead)
return;
velocity += gravity * Time.deltaTime;
velocity.x = forwardSpeed;
if(didFly == true) {
didFly = false;
velocity += FlyVelocity;
}
velocity = Vector3.ClampMagnitude(velocity, maxSpeed);
transform.position += velocity * Time.deltaTime;
deathCooldown = 0.5f;
}
}
If you are using Mechanim you could update animation state from script using Animator.Update even while actual time scale is zero.
Not sure if the trick is possible with legacy animation.