Basic C# Unity2D movement script not functioning - c#

Hi there fellow Overflowers!
I have recently dived into C# in Unity, because I believe that it has more functionality than UnityScript, and I come from a C++ background. Referencing some code from a 2D script in the Sample Assets, I have tried to create my own. The code is below:
using UnityEngine;
public class PlayerControl : MonoBehaviour {
//Variables
[HideInInspector]
public bool facingForward = true; //for Flip() Function
bool isGround = true; //for Grounded() Function
public float maxSpeed = 5.0f; //Terminal sideways velocity
public float HorizonAxis; //Checks for a/d movement
public float jumpFloat = 1000.0f; //Modular, use Unity Editor
public float moveFloat = 400.0f; // " "
void Start() {
//transform.position(0,0,0);
}
void Flip() {
facingForward = !facingForward; //switches boolean
Vector3 theScale = transform.localScale; //assigns vector to localscale of Player
theScale.x *= -1; //if x = 1, position becomes -1 and thus flips
transform.localScale = theScale; //reassigns the localscale to update theScale
}
bool Grounded() {
if (transform.position.y > 1) { //if position of gameObject is greater that 1, not grounded
isGround = false;
} else {
isGround = true;
}
return isGround; //function returns true or false for isGround
}
void Update() {
HorizonAxis = /*UnityEngine.*/Input.GetAxis ("Horizontal"); //assigns HorizonAxis to a/d movement from UnityEngine.Input
if (HorizonAxis * rigidbody2D.velocity.x > maxSpeed) { // if Input a/d by current x velocity of gameObject is greater than maxSpeed
rigidbody2D.velocity = new Vector2 (Mathf.Sign (rigidbody2D.velocity.x) * maxSpeed, rigidbody2D.velocity.y); //1 or -1 times the max speed, depending on direction
}
else if (HorizonAxis * rigidbody2D.velocity.x < maxSpeed) { //if Input a/d is less than terminal velocity
rigidbody2D.AddForce(Vector2.right * HorizonAxis * moveFloat); //add force to the right equivilant to Input by scalar moveFloat
}
if (Input.GetButtonDown ("Jump")) { //If Space
if(isGround) { //and isGround returns true
rigidbody2D.AddForce(new Vector2(0.0f, jumpFloat)); //add upwards force to bottom of rigidbody2D
isGround = false; //Resets isGround value
}
}
if (HorizonAxis > 0 && !facingForward) {//if UnityEngine.Input is to the right and facing left
Flip (); //execute
}
else if (HorizonAxis < 0 && facingForward) { //else
Flip (); //execute
}
}
}
Unfortunately, the code just doesn't work. I get no compile errors, but any Input does not effect the current position of the character. Should I be using transform.Translate to change the position, or stick with AddForce to a Vector2 until the character hits a maxSpeed?
Thanks heaps :)

I (kinda) fixed the jerky jumping issue, basically you look for the input in the Update() function which switches a Bool in FixedUpdate()
void Update () {
if (Input.GetKeyDown (KeyCode.Space) && playerGrounded) {
playerJumped = true;
}
}
Then in FixedUpdate() I looked for this Bool and did my AddForce
void FixedUpdate () {
if (playerJumped) {
playerJumped = false;
rigidbody2D.AddForce (new Vector2 (0, jumpForce),ForceMode2D.Impulse);
playerGrounded = false;
}
}
Setting playerJumped to false makes sure it doesn't run several times and the player can't jump again because I also set the grounded to false. grounded gets set back to true when the player collides with things tagged "ground".
I'm still new to Unity and C# overall so I can't guarantee this is the best (or even a good) way. Hope I could help somehow though ;)

Related

Any way of moving my player other then the controller script teleports

I'm trying to make a spring wall in my 2d platformer. However every way I've tried to move my character (addforce, transform.translate and even tried using the bouncy naterial) teleports my character rather then moving it. This doesn't happen with my controller script. I suspect something in my script is causing this interaction but I'm not sure exactly what. Here is my controller script. Any suggestions would be greatly appreciated :))
using UnityEngine;
using System.Collections;
public class controller : MonoBehaviour
{
//how fast he can go
public float topSpeed = 15f;
bool facingRight = true;
//what direction character is facing
bool grounded = false;
//check if the character is grounded
public Transform groundCheck;
//the transform is used to see if character has touched the ground yet
float groundRadius = 0.2f;
//creates a ground radius for the transform circle for ground detection
GameObject Player, Player2;
int characterselect;
//I'm pretty sure this stuff ^^ is unnessecary and is from when I had the character switch in this script but dont want to remove just in case
public float jumpForce = 700f;
//the characters jumpforce
public GameObject jumpParticles;
public LayerMask whatIsGround;
//what layer is the ground
void Start()
{
characterselect = 1;
Player = GameObject.Find("Player");
Player2 = GameObject.Find("Player2");
//loads game objects as variables I'm pretty sure this stuff ^^^^ is unnessecary and is from when I had the character switch in this script but dont want to remove just in case
}
void FixedUpdate()
{
//has the transform hit the ground yet returns a true or false value
grounded = Physics2D.OverlapCircle(groundCheck.position, groundRadius, whatIsGround);
// get direction
float move = Input.GetAxis("Horizontal");
//add velocity to the move direction times by the speed
GetComponent<Rigidbody2D>().velocity = new Vector2(move * topSpeed, GetComponent<Rigidbody2D>().velocity.y);
if (move > 0 && !facingRight) //if facing not right then use the flip function
flip();
else if (move < 0 && facingRight)
flip();
//the whole flip turned out not to be nesseary as my sprites were symetric
}
void Update()
{
//if the character is in fact touching the ground then when space is pressed the function will run
if(grounded&& Input.GetKeyDown(KeyCode.Space))
{
//adds the jump force to the rigidbody attached to the character
GetComponent<Rigidbody2D>().AddForce(new Vector2(0, jumpForce));
//Instantiate(jumpParticles, transform.position, transform.rotation);
//Destroy(jumpParticles, 3f);
}
{
//this was code I was working on for character switching but couldn't get it to work properly. I didn't delete it because it took me ages to do and was recycled in the characterswitch script
// if (Input.GetKeyDown(KeyCode.E))
// {
// if (characterselect==1)
// {
// characterselect = 2;
// }
// else if (characterselect==2)
// {
// characterselect = 1;
// }
// }
// if (characterselect==1)
// {
// Player.SetActive(true);
// Player2.SetActive(false);
// }
// else if (characterselect==2)
// {
// Player.SetActive(false);
// Player2.SetActive(true);
// }
}
if (Input.GetKeyDown(KeyCode.LeftShift))
{
topSpeed = topSpeed * 2;
}
else if (Input.GetKeyUp(KeyCode.LeftShift))
{
topSpeed = 15;
}
}
void flip()
{
//for when facing the other direction
facingRight = ! facingRight;
//load the local scale
Vector3 theScale = transform.localScale;
//flip character on the x axis
theScale.x *= -1;
//and then apply it to the local scale
transform.localScale = theScale;
}
Edit
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class boost : MonoBehaviour {
private Rigidbody2D rb2d;
// Use this for initialization
void OnCollisionEnter2D(Collision2D other){
if (other.gameObject.tag == "booster") {
Vector2 tempvect = new Vector2 (2, 0);
rb2d.MovePosition ((Vector2)transform.position + tempvect);
}
}
void Start () {
rb2d = GetComponent<Rigidbody2D>();
}
// Update is called once per frame
void Update () {
}
}
This is the code that I think should make it work the error comes at
rb2d.MovePosition ((Vector2)transform.position + tempvect);

Switching between two or more cameras unity3D

I'm making a game in which the player controls two different characters (each one has its own empty object with a camera as child), and switchs one or another by pressing the control key. The thing is, I'm trying to make a little transition between both characters cameras by using another camera, so it doesn't just teleports between one and another but I can't seem to do it. I tried with lerp but I don't know if I got it right, so I read and tried Vector3.MoveTowards but still couldn't do it. This is my code so far (the while is because a last-moment-braindead I had):
public class CameraController : MonoBehaviour
{
public Camera cam1;
public Camera cam2;
public Camera movingCamera;
public bool isCurrentPlayer;
public Transform target1;
public Transform target2;
public float speed = 0.2f;
void FixedUpdate()
{
float step = speed * Time.deltaTime;
if (Input.GetButtonDown("Control"))
{
if (isCurrentPlayer)
{
movingCamera.enabled = true;
cam2.enabled = false;
while (transform.position != target1.position)
{
transform.position = Vector3.MoveTowards(transform.position, target1.position, step);
}
if (transform.position == target1.transform.position)
{
movingCamera.enabled = false;
cam1.enabled = true;
}
isCurrentPlayer = false;
}
else if (!isCurrentPlayer)
{
movingCamera.enabled = true;
cam1.enabled = false;
while (transform.position != target2.position)
{
transform.position = Vector3.MoveTowards(transform.position, target2.position, step);
}
if (transform.position == target2.transform.position)
{
movingCamera.enabled = false;
cam2.enabled = true;
}
isCurrentPlayer = true;
}
}
}
I'm curious about two things. Why did you use FixedUpdate to manage your updates? This isn't physics code. Is there a particular reason you are using multiple cameras? If I may, I propose the following changes.
You can simply make use of the main camera instead of multiple cameras. Additionally, you can increase the number of player objects you can toggle through by using an array of player GameObjects, and by changing the input parameters to left control and right control, you can toggle between next player and previous player to navigate bi-directionally through the array of players.
Here's my example code that implements these changes (tested and works, though improvements can be made.)
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
// Attached to Main Camera
public class CameraController : MonoBehaviour {
// set manually in inspector
public GameObject[] players;
public float movementSpeed = 1.0f;
public float rotationSpeed = 1.0f;
private int currentPlayer;
private float startTime;
private float distanceToPlayer;
private Vector3 startPosition;
private Quaternion startOrientation;
// Use this for initialization
void Start () {
currentPlayer = 0;
ResetCamera();
}
// Update is called once per frame
void Update () {
float distanceCovered;
float rotationCovered;
float fractionTraveled;
// switch to previous
if (Input.GetButtonDown("left ctrl")) {
if (currentPlayer == 0) currentPlayer = players.Length - 1;
else currentPlayer--;
ResetCamera();
}
// switch to nextPlayer
if (Input.GetButtonDown("right ctrl")) {
if (currentPlayer == players.Length - 1) currentPlayer = 0;
else currentPlayer++;
ResetCamera();
}
// Keep moving camera
if (transform.position != players[currentPlayer].transform.position)
{
distanceCovered = (Time.time - startTime) * movementSpeed;
fractionTraveled = distanceCovered / distanceToPlayer;
rotationCovered = (Time.time - startTime) * rotationSpeed;
// Lerp to player position
transform.position = Vector3.Lerp(
startPosition,
players[currentPlayer].transform.position,
fractionTraveled
);
// match player orientation
transform.rotation = Quaternion.RotateTowards(
transform.rotation,
players[currentPlayer].transform.rotation,
rotationCovered
);
// Stop moving camera
} else {
// Match orientation
if (transform.rotation != players[currentPlayer].transform.rotation)
transform.rotation = players[currentPlayer].transform.rotation;
// Set parent transform to current player
transform.parent = players[currentPlayer].transform;
}
}
void ResetCamera() {
transform.parent = null;
startTime = Time.time;
startPosition = transform.position;
startOrientation = transform.rotation;
distanceToPlayer = Vector3.Distance(
transform.position,
players[currentPlayer].transform.position
);
}
}
Obviously the values would need to be tweaked, and the movement algorithm is pretty basic. Crude but function. You can also add player movement code into the camera, just make sure it points to players[currentPlayer] and it will work for each of your player objects without having to use additional scripts unless there is a reason to do so.
Feel free to use this code. Like I said, it works. However, should you choose to do so, it can easily be modified to function like your original code simply by removing the array and reinstating the individual GameObjects.
transform.position points to the position of CameraController game object. If you want to move movingCamera you probably want to use movingCamera.transform.position. Also keep in mind that in your script the MoveTowards() would only fire when you are pressing your "Control" button.
As memBrain said it would be the best practice to use only one camera for this - visually it would look the same.
The script should look something like this:
// Assuming target1 is player 1 and target2 is player 2
private float snapThreshold = 0.1f;
private Vector3 movingCameraDestination = Vector3.zero;
void FixedUpdate()
{
if(Input.GetButtonDown("Control"))
{
if(isCurrentPlayer)
{
//Set position of transition camera to player 1 and set it's destination to player's 2 position
movingCamera.transform.position = player1.position;
movingCameraDestination = player2.position;
//Disable player 1 camera and enable transition camera
cam1.enabled = false;
movingCamera.enabled = true;
}
else
{
//Set position of transition camera to player 21 and set it's destination to player's 1 position
movingCamera.transform.position = player2.position;
movingCameraDestination = player1.position;
//Disable player 1 camera and enable transition camera
cam2.enabled = false;
movingCamera.enabled = true;
}
}
//If transition camera is enabled and its destination is not Vector3.zero - move it
if(movingCameraDestination != Vector3.zero && movingCamera.enabled)
{
movingCamera.transform.position = Vector3.Lerp(movingCamera.transform.position, movingCameraDestination, speed * Time.deltaTime);
//If the distance between transition camera and it's destination is smaller or equal to threshold - snap it to destination position
if(Vector3.Distance(movingCamera.transform.position, movingCameraDestination) <= snapThreshold)
{
movingCamera.transform.position = movingCameraDestination;
}
//If transition camera reached it's destination set it's destination to Vector3.zero and disable it
if(movingCamera.transform.position == movingCameraDestination)
{
movingCameraDestination = Vector3.zero;
movingCamera.enabled = false;
}
}
}

Character won't jump in Unity2D but entered the jump statement

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.

Object not orienting correctly

I have a small script that causes an object to bounce back and forth. It is a bird for an upwards scrolling endless runner. So it represents its flight path. This script moves it from one end to the other and when it reaches the end it flips the 2D sprite and travels in the opposite direction. It works most of the time. But the problem is that sometimes the image flips twice so now it looks like its flying backwards until it does it again. Each time it does it it appears to be random.
public class Fly : MonoBehaviour {
private bool dirRight = false;
public float speed;
public bool facingRight = false;
void Start (){
speed = Random.Range (15.0f, 22.0f);
}
void Update () {
if(transform.position.x >= 25.0f) {
dirRight = false;
Flip();
}
if(transform.position.x <= -25.0f) {
dirRight = true;
Flip();
}
if (dirRight)
transform.Translate (Vector2.right * speed * Time.deltaTime);
else
transform.Translate (-Vector2.right * speed * Time.deltaTime);
}
void Flip()
{
// Switch the way the player is labelled as facing
facingRight = !facingRight;
// Multiply the player's x local scale by -1
Vector3 theScale = transform.localScale;
theScale.x *= -1;
transform.localScale = theScale;
}
I modified the if statements and use my bools as well as the position as such:
if(transform.position.x >= 25.0f && dirRight == true) {
dirRight = false;
Flip();
}
if(transform.position.x <= -25.0f && dirRight == false) {
dirRight = true;
Flip();
}
I am running it now and waiting to see if it works.
you are calling Flip() method based on position. and position is updated per frame. So it takes time to Lerp from >=25 to <25 so in every frame when position is >= 25 or <= -25 it calls to Flip(). So you need to add another check for calling Flip(). May be facingright == true will work.

Unity Click on 1 object to trigger another object

Please keep in mind that I'm new to Unity. I have 2 script that I want to "combline" but when I try then it don't Work.
I have a Script (Name : RobotController). This script controls the movement of the player. Up/Jump, Down, Left and Right. (This Works with Keyboard keys only atm)
This script Works just fine but now I want to add the feature of touch keys for phone. With this I mean that if a person click on the "up-Arrow" the player shall jump.
The Up-Arrow is an object.
This is were I get my problem. I have created the Up-Arrow with a collider and a script.
Up-Arrow script:
public class NewJumpScript : MonoBehaviour {
// Use this for initialization
void Start () {
}
// Update is called once per frame
void Update () {
}
void OnMouseOver()
{
if ((Input.touchCount > 0 && Input.GetTouch(0).phase == TouchPhase.Began) || (Input.GetMouseButtonDown(0)))
{
Debug.Log("test");
}
}
}
Here is the RobotController script´, with ground check and so on.
public class RobotController : MonoBehaviour {
//This will be our maximum speed as we will always be multiplying by 1
public float maxSpeed = 2f;
public GameObject player;
public GameObject sprite;
//a boolean value to represent whether we are facing left or not
bool facingLeft = true;
//a value to represent our Animator
Animator anim;
//to check ground and to have a jumpforce we can change in the editor
bool grounded = true;
public Transform groundCheck;
public float groundRadius = 1f;
public LayerMask whatIsGround;
public float jumpForce = 300f;
private bool isOnGround = false;
void OnCollisionEnter2D(Collision2D collision) {
isOnGround = true;
}
void OnCollisionExit2D(Collision2D collision) {
anim.SetBool ("Ground", grounded);
anim.SetFloat ("vSpeed", rigidbody2D.velocity.y);
isOnGround = false;
}
// Use this for initialization
void Start () {
player = GameObject.Find("player");
//set anim to our animator
anim = GetComponent <Animator>();
}
void FixedUpdate () {
//set our vSpeed
//set our grounded bool
grounded = Physics2D.OverlapCircle (groundCheck.position, groundRadius, whatIsGround);
//set ground in our Animator to match grounded
anim.SetBool ("Ground", grounded);
float move = Input.GetAxis ("Horizontal");//Gives us of one if we are moving via the arrow keys
//move our Players rigidbody
rigidbody2D.velocity = new Vector3 (move * maxSpeed, rigidbody2D.velocity.y);
//set our speed
anim.SetFloat ("Speed",Mathf.Abs (move));
//if we are moving left but not facing left flip, and vice versa
if (move > 0 && !facingLeft) {
Flip ();
} else if (move < 0 && facingLeft) {
Flip ();
}
}
void Update(){
if ((isOnGround == true && Input.GetKeyDown (KeyCode.UpArrow)) || (isOnGround == true && Input.GetKeyDown (KeyCode.Space))) {
anim.SetBool("Ground",false);
rigidbody2D.AddForce (new Vector2 (0, jumpForce));
}
if (isOnGround == true && Input.GetKeyDown (KeyCode.DownArrow))
{
gameObject.transform.localScale = new Vector3(transform.localScale.x, 0.2f, 0.2f);
}
if (isOnGround == true && Input.GetKeyUp (KeyCode.DownArrow))
{
gameObject.transform.localScale = new Vector3(transform.localScale.x, 0.3f, 0.3f);
}
}
//flip if needed
void Flip(){
facingLeft = !facingLeft;
Vector3 theScale = transform.localScale;
theScale.x *= -1;
transform.localScale = theScale;
}
}
What needs to happen is that when The "Up-arrow" in the game is clicked then The person shall jump on the same tearms as in the RobotController script.
I hope you understand my question.
Thanks for your time and help.
I posted this same answer to both of the questions, because they are so similar. You can easily modify the code to your needs.
This is only one way to do it. There are probably many more, but this is the best I have encountered so far.
On the QUI button, script like this is needed:
private Mover playerMover;
void Start()
{
playerMover = GameObject.Find("Character").GetComponent<Mover>();
}
void OnMouseOver()
{
if (Input.GetMouseButton(0))
{
Debug.Log("pressed");
playerMover.MoveButtonPressed();
}
}
Notice that find is only done ones in start function, because it is computationally heavy.
And on the Character gameobject, script component like this is needed:
using UnityEngine;
using System.Collections;
public class Mover : MonoBehaviour {
public void MoveButtonPressed()
{
lastPressedTime = Time.timeSinceLevelLoad;
}
public double moveTime = 0.1;
private double lastPressedTime = 0.0;
void Update()
{
if(lastPressedTime + moveTime > Time.timeSinceLevelLoad)
{
// Character is moving
rigidbody.velocity = new Vector3(1.0f, 0.0f, 0.0f);
}
else
{
rigidbody.velocity = new Vector3(0.0f, 0.0f, 0.0f);
}
}
}

Categories