I'm learning C# while programming my game, I'm stuck doing the movement. I want my character to move continuously by pressing 'D' or 'A' once. Then, after colliding with an invisible wall while going to the right, go backwards until it hits another invisible wall and stop.
I managed to make my GameObject move, but when it collides with the wall, nothing happens. Both objects have a rigidbody2D, the same z-coordinates, and correct tags.
public class SquadMovement : MonoBehaviour {
float speed;
bool collisionRightWall = false;
// Update is called once per frame
void Update () {
if (Input.GetKeyDown (KeyCode.D)) {
CancelInvoke ();
InvokeRepeating ("RightMovement", Time.deltaTime, Time.deltaTime);
}
if (Input.GetKeyDown (KeyCode.A)) {
CancelInvoke ();
InvokeRepeating ("LeftMovement", Time.deltaTime, Time.deltaTime);
}
}
void RightMovement () {
speed = 10f;
transform.Translate (speed * Time.deltaTime, 0, 0);
}
void LeftMovement () {
speed = -7f;
transform.Translate (speed * Time.deltaTime, 0, 0);
}
void OnCollisionWallR (Collider2D colR) {
if (colR.gameObject.tag == "invisibleWallRight") {
collisionRightWall = true;
Debug.Log (collisionRightWall);
}
}
}
I'm using invisible walls because I don't know how to use x-coordinates, There HAS to be a more efficient way but I want to know first why this don't work. I would be glad if someone could teach me that too.
using UnityEngine;
using System.Collections;
public class SquadMovement : MonoBehaviour {
float constantspeed = 3;
float speed;
//Key inputs
void Update () {
transform.Translate (constantspeed * Time.deltaTime, 0, 0);
if (Input.GetKeyDown (KeyCode.D)) {
StopAllCoroutines ();
StartCoroutine (RightMovement(0f));
}
if (Input.GetKeyDown (KeyCode.A)) {
StopAllCoroutines ();
StartCoroutine (LeftMovement(0f));
}
}
//Movement itself (Right, Left)
IEnumerator RightMovement (float Rloop) {
while (transform.position.x < Time.time * constantspeed + 6) {
speed = 10f;
transform.Translate (speed * Time.deltaTime, 0, 0);
yield return new WaitForSeconds (Rloop);
}
if (transform.position.x > Time.time * constantspeed + 5.9) {
StopAllCoroutines ();
StartCoroutine (LeftMovement (0f));
}
}
IEnumerator LeftMovement (float Lloop) {
while (transform.position.x > Time.time * constantspeed -8) {
speed = -7f;
transform.Translate (speed * Time.deltaTime, 0, 0);
yield return new WaitForSeconds (Lloop);
}
}
}
Related
I am making a Unity 2D game but I have an script where the player goes up with vector2 and back down but if it goes down and I still hold space it doesn't go smooth anymore how do I fix that?
using UnityEngine;
using System.Collections;
public class playercontrol : MonoBehaviour {
void Update ()
{
Movment ();
}
void Movment()
{
if (Input.GetKey (KeyCode.D))
{
transform.Translate(Vector2.right *4f* Time.deltaTime);
transform.eulerAngles = new Vector2(0, 0);
}
if (Input.GetKey (KeyCode.A))
{
transform.Translate(Vector2.left *4f* Time.deltaTime);
transform.eulerAngles = new Vector2(0, 0);
}
if (Input.GetKey (KeyCode.Space))
{
transform.Translate(Vector2.up *4f* Time.deltaTime);
transform.Translate(Vector2.up *4f* Time.deltaTime);
transform.eulerAngles = new Vector2(0, 0);
}
}
}
As others have mentioned, this is a known common occurrence with Unity and the best solution is to handle movement with RigidBody...
However, there are other ways around it some are much less elegant, but some are ok.
Method 1
Using raw inputs.
// Get the raw inputs
var x = Input.GetAxis("Horizontal");
var jump = Input.GetAxis("Jump");
var move = new Vector2(x, 0);
// Move horizontally
transform.Translate(move);
// Handle Jump
if (jump > 0) { ... }
Method 2
What you need to do is check for combined inputs and then return out of the function.
// Handle multiple input first
if(Input.GetKey (KeyCode.D) && Input.GetKey (KeyCode.Space))
{
...
return;
}
if(Input.GetKey (KeyCode.A) && Input.GetKey (KeyCode.Space))
{
...
return;
}
if(Input.GetKey (KeyCode.D)) { ... }
if(Input.GetKey (KeyCode.A)) { ... }
if(Input.GetKey (KeyCode.Space)) { ... }
Hello so i have this script and in the void update in doesnt matter wich is first for backwards or run up it always makes the animator play the animation backwards walk or run it plays the animation half way or full way and it plays part of the idle state without it been called that means your finger is still in the on the button so it must still play backward/forwards animation over and over .
here is the code :
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class playerController : MonoBehaviour {
public float moveSpeed = 10f;
public float turnSpeed = 50f;
Animator anim;
// Use this for initialization
void Start () {
anim = GetComponent<Animator> ();
}
// Update is called once per frame
void Update () {
if (Input.GetKey (KeyCode.S)) {
anim.SetBool ("isIdle", false);
anim.SetBool ("isWalkingBack", true);
transform.Translate (-Vector3.forward * moveSpeed * Time.deltaTime);
}
else
{
anim.SetBool ("isIdle", true);
anim.SetBool ("isWalkingBack", false);
}
if (Input.GetKey (KeyCode.W)) {
anim.SetBool ("isRunning", true);
anim.SetBool ("isIdle", false);
transform.Translate (Vector3.forward * moveSpeed * Time.deltaTime);
}
else
{
anim.SetBool ("isRunning", false);
anim.SetBool ("isIdle", true);
}
}
}
`
Using boolean fields may cause some problems, for example, which you described above.
I recommend to use: anim.SetInteger("unitState", someIntValue);
Configure the connections and transitions in the animator to work with the field "unitState".
In your code it will look something like this:
void Update () {
// for example
anim.SetInteger("unitState", 0); // 0 is Idle
if (Input.GetKey (KeyCode.S)) {
anim.SetInteger("unitState", -1); // -1 is WalkBack
transform.Translate (-Vector3.forward * moveSpeed * Time.deltaTime);
}
if (Input.GetKey (KeyCode.W)) {
anim.SetInteger("unitState", 1); // 1 is run forward
transform.Translate (Vector3.forward * moveSpeed * Time.deltaTime);
}
if (Input.GetKeyDown (KeyCode.Space)) {
anim.SetInteger("unitState", 2); // 2 is jump
//Jump code here. for example
}
....
}
Make sure you have unchecked exit time on every transition.
I am pretty new to Unity so how I did it may not be the best way, but when the character jumps it is inconsistent.
Some bounces are a lot further than others and I am not sure why this is happening.
Also if I press the up arrow really quickly the cube jumps really far but if I wait a couple seconds it bounce like normal.
Here is my code:
using UnityEngine;
using System.Collections;
public class MovePlayer : MonoBehaviour
{
Vector3 endPos;
int numBackwards = 0;
bool jumping = false;
public Rigidbody rigidBody;
//public Collider theCollider;
void Start()
{
rigidBody = GetComponent<Rigidbody> ();
}
// Update is called once per frame
void Update()
{
rigidBody.freezeRotation = true;
endPos = gameObject.transform.position;
if (!jumping)
{
if (Input.GetButtonDown("up") && gameObject.transform.position == endPos) {
if (numBackwards < 0)
{
numBackwards++;
}
else
{
UpdateScore.score++;
}
transform.Translate(Vector3.up * 50 * Time.deltaTime, Space.World);
transform.Translate(Vector3.forward * 110 * Time.deltaTime, Space.World);
}
else if (Input.GetButtonDown("down") && gameObject.transform.position == endPos)
{
transform.Translate(Vector3.up * 50 * Time.deltaTime, Space.World);
transform.Translate(-Vector3.forward * 110 * Time.deltaTime, Space.World);
numBackwards--;
}
else if (Input.GetButtonDown("left") && gameObject.transform.position == endPos)
{
transform.Translate(Vector3.up * 50 * Time.deltaTime, Space.World);
transform.Translate(Vector3.left * 110 * Time.deltaTime, Space.World);
}
else if (Input.GetButtonDown("right") && gameObject.transform.position == endPos)
{
transform.Translate(Vector3.up * 50 * Time.deltaTime, Space.World);
transform.Translate(Vector3.right * 110 * Time.deltaTime, Space.World);
}
}
}
void OnCollisionEnter(Collision other)
{
if (other.gameObject.CompareTag("Ground"))
jumping = false;
}
void OnCollisionExit(Collision other)
{
if (other.gameObject.CompareTag("Ground"))
jumping = true;
}
}
Instead of translate the object, make use of the rigidbodys ability to add a force to it. I also replaced the collision events with a simpler way. It checks the distance between the objects center and the ground. (You can still use your way obviously). The FixedUpdate insure that the code will be called regularly instead of depending on the frame speed. (More on that topic Here)
//PUBLIC
public float distance;
public float fspeed;
public float uspeed;
//PRIVATE
private Rigidbody rigidBody;
void Awake()
{
rigidBody = GetComponent<Rigidbody>();
rigidBody.freezeRotation = true;
}
void FixedUpdate()
{
if (Physics.Raycast(transform.position, -Vector3.up, distance + 0.1F))
{
if (Input.GetKeyDown(KeyCode.UpArrow))
{
rigidBody.AddForce(new Vector3(0, uspeed, fspeed));
}
if (Input.GetKeyDown(KeyCode.DownArrow))
{
rigidBody.AddForce(new Vector3(0, uspeed, -fspeed));
}
if (Input.GetKeyDown(KeyCode.LeftArrow))
{
rigidBody.AddForce(new Vector3(fspeed, uspeed, 0));
}
if (Input.GetKeyDown(KeyCode.RightArrow))
{
rigidBody.AddForce(new Vector3(-fspeed, uspeed, 0));
}
}
}
public float distance
Is the min distance to the ground until you can jump again
public float fspeed
Is the forward or side speed (jump distance)
public float uspeed
Is the upwards speed (jump height)
I am making a game where the player battles a robot, I have implemented some code to make the AI move back and rotate away from the player if a condition is met. However the co routine that does this loops forever and I am unsure in how to make it break.
void Update ()
{
//looking at player
playerVelocity = ((TTarget.position - previous).magnitude) / Time.deltaTime;
previous = TTarget.position;
GameObject thePlayer = GameObject.Find("Player");
PlayerMovement playerMovement = thePlayer.GetComponent<PlayerMovement>();
enemyHit = playerMovement.hitEnemy;
if (enemyHit == false)
{
//enemy moving
transform.LookAt(TTarget);
transform.Translate(Vector3.forward * Time.deltaTime * movementSpeed);
}
else if (enemyHit == true)
{
StartCoroutine("Evade");
//Debug.Log ("Hello");
StopCoroutine("Evade");
}
}
IEnumerator Evade()
{
//GameObject thePlayer = GameObject.Find("Player");
//PlayerMovement playerMovement = thePlayer.GetComponent<PlayerMovement>();
//enemyHit = playerMovement.hitEnemy;
transform.Translate(Vector3.back * Time.deltaTime * movementSpeed);
yield return new WaitForSeconds(1);
Vector3 to = new Vector3(0, -45, 0);
if (Vector3.Distance(transform.eulerAngles, to) > 0.01f)
{
transform.eulerAngles = Vector3.Lerp(transform.rotation.eulerAngles, to, 99*Time.deltaTime);
}
yield break;
}
Your problem is that you are starting the coroutine, then immediately stopping it.
void Update ()
{
enemyHit = playerMovement.hitEnemy;
if (enemyHit == false)
{
//enemy moving
transform.LookAt(TTarget);
transform.Translate(Vector3.forward * Time.deltaTime * movementSpeed);
}
else if (enemyHit == true)
{
StartCoroutine("Evade");
Debug.Log ("Back From Coroutine");
StopCoroutine("Evade");
Debug.Log("Stopped Coroutine");
}
}
IEnumerator Evade()
{
Debug.Log("Starting Coroutine");
transform.Translate(Vector3.back * Time.deltaTime * movementSpeed);
yield return new WaitForSeconds(1);
Debug.Log("This is never called");
Vector3 to = new Vector3(0, -45, 0);
if (Vector3.Distance(transform.eulerAngles, to) > 0.01f)
{
transform.eulerAngles = Vector3.Lerp(transform.rotation.eulerAngles, to, 99*Time.deltaTime);
}
yield break;
}
This would output:
Starting Coroutine
Back From Coroutine
Stopped Coroutine
I think the better would to do this would just be with a bool and Invoke http://docs.unity3d.com/ScriptReference/MonoBehaviour.Invoke.html
private bool avoidPlayer = false;
void Update ()
{
enemyHit = playerMovement.hitEnemy;
if (enemyHit == false)
{
//enemy moving
transform.LookAt(TTarget);
transform.Translate(Vector3.forward * Time.deltaTime * movementSpeed);
}
else if (enemyHit == true)
{
transform.Translate(Vector3.back * Time.deltaTime * movementSpeed);
avoidPlayer = true;
}
// Invoke the evade function every second until we have avoided the player
if(avoidPlayer)
Invoke("Evade", 1);
}
void Evade()
{
Vector3 to = new Vector3(0, -45, 0);
if (Vector3.Distance(transform.eulerAngles, to) > 0.01f)
transform.eulerAngles = Vector3.Lerp(
transform.rotation.eulerAngles, to, 99*Time.deltaTime);
else
avoidPlayer = false;
}
I've been trying to get collision to work but so far no good.
Screenshot Unity
This is my moveBall.cs which I put on my Ball Object.
using UnityEngine;
using System.Collections;
public class moveBall : MonoBehaviour {
float balSnelheid = 1;
void Update () {
transform.Translate (0, balSnelheid * Time.deltaTime, 0);
}
void OnCollisionTrigger2D (Collision2D coll) {
if (coll.gameObject.name == "Brick") {
Destroy(coll.gameObject);
}
}
}
And this is my movePlayer.cs which I put on my Player Object.
using UnityEngine;
using System.Collections;
public class movePlayer : MonoBehaviour {
public float snelheid;
// Use this for initialization
void Start () {
Screen.showCursor = false;
}
// Update is called once per frame
void Update () {
if (transform.position.x + Input.GetAxis ("hor") * snelheid * Time.deltaTime < 2.9) {
if (transform.position.x + Input.GetAxis ("hor") * snelheid * Time.deltaTime > -2.9) {
transform.Translate(Input.GetAxis("hor") * snelheid * Time.deltaTime, 0, 0);
}
}
if (transform.position.x + Input.GetAxis ("hor") * snelheid * Time.deltaTime > 3) {
transform.position = new Vector3(2.9f, -4.7f, 0);
} else if (transform.position.x + Input.GetAxis ("hor") * snelheid * Time.deltaTime < -3) {
transform.position = new Vector3(-2.9f, -4.7f, 0);
}
}
}
If anyone could give me a tip/solution it would help me out a lot!
One issue I see right off the bat is that you are using the RigidBody component rather than the RigidBody2D component. You need to be careful which components you use.
Also, OnTriggerEnter2D() or OnCollisionEnter2D() is what you are looking for, not OnCollisionTrigger2D.
If using the the 3d components was by choice, please look at OnCollisionEnter() or OnTriggerEnter()