Hello I am trying to make a ragdoll player in unity 2d. All the parts of the character are held together by hinges and I'm trying to make it move. I do not want to use animations as I prefer a real ragdoll. My current movement isn't working, here is my code :)`
bool aKey = false;
float speedl = -20f;
private Rigidbody2D rb2D;
private void Start()
{
rb2D = gameObject.AddComponent<Rigidbody2D>();
bool aKey = Input.GetKey(KeyCode.A);
}
// Update is called once per frame
void Update()
{
if(aKey == true)
{
rb2D.AddForce(transform.forward * speedl);
}
}
Start function run only once so move your GetKey functions to inside of Update() function.
private void Start()
{
rb2D = gameObject.AddComponent<Rigidbody2D>();
}
void Update()
{
if(Input.GetKey(KeyCode.A))
{
rb2D.AddForce(transform.forward * speedl);
}
}
Related
I assigned the spacebar as jump key in my game but it doesn't seem to work 100% of the time. Also there is a slight delay when the character jumps and button is pressed. The jump key is like a gamble in the game. Here's the script that i attached to the character.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class MonsterScript : MonoBehaviour
{
[SerializeField] private float walkStrength = 10f;
[SerializeField] private float jumpStrength = 11f;
private float movementX;
private bool onCloud = true;
private string CLOUD_TAG = "Cloud";
private string WALK_ANIMATION = "walk";
private Rigidbody2D mybody;
private SpriteRenderer sr;
private Animator anim;
private void Awake()
{
mybody = GetComponent<Rigidbody2D>();
anim = GetComponent<Animator>();
sr = GetComponent<SpriteRenderer>();
}
// Update is called once per frame
void Update()
{
monsterWalk();
}
private void FixedUpdate()
{
monsterJump();
}
void monsterWalk()
{
movementX = Input.GetAxisRaw("Horizontal");
transform.position += walkStrength * Time.deltaTime * new Vector3(movementX, 0f, 0f);
}
void monsterJump()
{
if (Input.GetKeyUp(KeyCode.Space) && onCloud == true)
{
mybody.AddForce(new Vector3(0, jumpStrength,0), ForceMode2D.Impulse);
onCloud = false;
}
}
private void OnCollisionEnter2D(Collision2D collision)
{
if (collision.gameObject.CompareTag(CLOUD_TAG))
{
onCloud = true;
Debug.Log("Landed!");
}
}
}
I tried changing the collider of my player thinking it might have got stuck with other collider. Again I trying changing the key thinking it was a problem of my keyboard but wasn't.
In general: get single event input in Update!
If you check GetKeyUp within FixedUpdate - which is not called every frame - you might miss an Input.
So you should do e.g.
private bool isJump;
private void Update ()
{
...
if(Input.GetKeyUp(KeyCode.Space) && onCloud)
{
isJump = true;
}
}
private void FixedUpdate ()
{
...
if(isJump)
{
mybody.AddForce(new Vector3(0, jumpStrength,0), ForceMode2D.Impulse);
onCloud = false;
isJump = false;
}
}
However, further
transform.position += walkStrength * Time.deltaTime * new Vector3(movementX, 0f, 0f);
is a problem as well when using a Rigidbody/Rigidbody2D since you completely overwrite the position here => the physics has no effect whatsoever so your adding force is good for nothing.
You also want to shift this into FixedUpdate and only go through the myBody here as well
private void FixedUpdate ()
{
var movementX = Input.GetAxisRaw("Horizontal") * walkStrength * Time.deltaTime;
// Keep Y velocity untouched and only overwrite X
var vel = mybody.velocity;
vel.x = movementX;
mybody.velocity = vel:
}
as soon as physics is involved you do not want to get or set anything through the Transform component.
https://www.youtube.com/watch?v=gB1F9G0JXOo&t=11865s
I'm watching this tutorial and I did everything the same as the guy in the video did until the "Player Jumping" part, when his character can jump whenever he presses the space button, but for me it doesn't work the same way. Can somebody help or tell me what is the problem?
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Player : MonoBehaviour
{
[SerializeField]
private float moveForce = 10f;
[SerializeField]
private float jumpForce = 11f;
private float movementX;
private Rigidbody2D myBody;
private SpriteRenderer sr;
private Animator anim;
private string WALK_ANIMATION = "Walk";
private void Awake()
{
myBody = GetComponent<Rigidbody2D>();
anim = GetComponent<Animator>();
sr = GetComponent<SpriteRenderer>();
}
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
void Update()
{
PlayerMoveKeyboard();
AnimatePlayer();
}
private void FixedUpdate()
{
PlayerJump();
}
void PlayerMoveKeyboard()
{
movementX = Input.GetAxisRaw("Horizontal");
transform.position += new Vector3(movementX, 0f, 0f) * moveForce * Time.deltaTime;
}
void AnimatePlayer()
{
// we are going to the right side
if (movementX > 0)
{
anim.SetBool(WALK_ANIMATION, true);
sr.flipX = false;
}
// we are going to the left side
else if (movementX < 0)
{
anim.SetBool(WALK_ANIMATION, true);
sr.flipX = true;
}
else
{
anim.SetBool(WALK_ANIMATION, false);
}
}
void PlayerJump()
{
if (Input.GetButtonDown("Jump"))
{
myBody.AddForce(new Vector2(0f, jumpForce), ForceMode2D.Impulse);
}
}
} // class
Try moving your jump function from the FixedUpdate into the normal Update Function.
That should fix it.
Update gets called every frame and thus captures every input while FixedUpdate gets called in a fixed offset to update the physics logic of the engine. Now when you are looking for keyboard input, you want to always do that in Update, never in FixedUpdate because you'll miss input that was given to the player between the fixed update frames.
But since you want to do physics related changes only in FixedUpdate, you want to split the code between the two methods.
bool shouldJump = false;
void Update()
{
if (Input.GetButtonDown("Jump"))
shouldJump = true;
}
void FixedUpdate()
{
if (shouldJump)
{
myBody.AddForce(new Vector2(0f, jumpForce), ForceMode2D.Impulse);
shouldJump = false;
}
}
I have looked into the code in the video and he does the jump-logic in FixedUpdate. It seems weird to me and this is definitely bad practice. But one of the comments below addresses your issue as well and proposes a similar solution.
I'm trying to solve an issue in Unity 2d game creation.
So, my issue is when the subject is idle, the 2d player object should be idle and when I move the character, it must animate like walking.
But in my case, the walking animation is not working but the character is moving.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Player : MonoBehaviour
{
[SerializeField]
private float jumpmovement = 11f;
[SerializeField]
private float movement = 10f;
private float movementx;
[SerializeField]
private Rigidbody2D mybody;
private Animator anim;
[SerializeField]
private string Walk_Ani = "Player is walking";
private SpriteRenderer sr;
private void Awake()
{
mybody = GetComponent<Rigidbody2D>();
anim = GetComponent<Animator>();
sr = GetComponent<SpriteRenderer>();
}
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
void Update()
{
Playerkeymove();
animateplayer1();
}
void Playerkeymove()
{
movementx = Input.GetAxisRaw("Horizontal");
// Debug.Log(movementx);
transform.position += new Vector3(movementx, 0f, 0f) * movement * Time.deltaTime;
// Debug.Log(transform.position);
}
void animateplayer1()
{
// anim.SetBool(Walk_Ani , true);
// we are going to the right side
if (movementx > 0)
{
anim.SetBool(Walk_Ani, true);
sr.flipX = false;
}
else if (movementx < 0)
{
// we are going to the left side
anim.SetBool(Walk_Ani, true);
sr.flipX = true;
}
else
{
anim.SetBool(Walk_Ani, false);
}
}
}
I can't understand, why I have a warning issue with boolean part where I guess that's where my animation takes part.
You are trying to set a boolean parameter in the Animator that doesn't exists. The code is correct. Check what name you choose for the bool parameter to active correctly the animation.
I have one issue in unity 2d with my object , when i shoot the arrow to the box collider to the other element , and when it hit and go into child i mean arrow become child of parent (BOX) the child start to rotate to the left and to the right .. I really want to disable left and right rotation of the child .. the box (parent) still need to rotate as same as it was before.. i have code like this and my arrow in rigidbody2d is on kinematic mode...
this is script of the arrow ..
{
public float flySpeed = 20f;
private Rigidbody2D arrowBody;
private bool shouldFly;
// Start is called before the first frame update
void Start()
{
shouldFly = true;
arrowBody = GetComponent<Rigidbody2D>();
}
// Update is called once per frame
void Update()
{
if (shouldFly == true)
{
//make our pin fly
arrowBody.MovePosition(arrowBody.position + Vector2.up * flySpeed * Time.deltaTime);
}
}
private void OnTriggerEnter2D(Collider2D collision)
{
if(collision.tag == "target")
{
shouldFly = false;
transform.SetParent(collision.gameObject.transform);
} else if(collision.tag == "arrow")
{
SceneManager.LoadScene("quickGameOverScene");
}
}
}
I am really confused what you are trying to do. I do not understand if you want to freeze rotation or movement so i will post answers for both. In order to prevent translations and rotations caused by parent object you can use LateUpdate like this:
Quaternion InitRot;
Vector3 InitPos;
void Start () {
InitRot = transform.rotation;
InitPos = transform.position;
}
void Update()
{
//figuring out when to save position when attached to BOX
if(gameObject.transform.parent == null)
{
InitRot = transform.rotation;
InitPos = transform.position;
}
}
void LateUpdate () {
//If attached to box do not translate do not rotate
if (gameObject.transform.parent != null)
{
transform.rotation = InitRot;
transform.position = InitPos;
}
}
You can have more information about this solution from here
EDIT
Since the answer above did not work out for OP. I figured out what the actual problem is. OP's code is perfectly fine for moving the arrow but the problem is most likely where he rotates the box.
If he rotates the box using transform.Rotate(Vector3.forward* 90), there will be a distortion caused by same amount of rotation in each Update since frame times are not same in each Update. Therefore, he needs to rotate the box using Time.deltaTime for consistent rotation like this: transform.Rotate(Vector3.forward* 90*Time.deltaTime); This rotate the box same amount in each time interval and eliminate distortion. These are the scripts i used for the task and it works for me.
Script for the arrow:
public float flySpeed = 20f;
private Rigidbody2D arrowBody;
private bool shouldFly;
private Vector2 initPos;
private Quaternion initRot;
// Start is called before the first frame update
void Start()
{
shouldFly = true;
arrowBody = GetComponent<Rigidbody2D>();
//arrowBody.isKinematic = true;
initPos = gameObject.transform.position;
initRot = gameObject.transform.rotation;
}
// Update is called once per frame
void Update()
{
if (shouldFly == true)
{
//make our pin fly
arrowBody.MovePosition(arrowBody.position + Vector2.up * flySpeed * Time.deltaTime);
}
if(gameObject.transform.parent == null)
{
initPos = gameObject.transform.position;
initRot = gameObject.transform.rotation;
}
}
void LateUpdate()
{
if (gameObject.transform.parent != null)
{
gameObject.transform.position = initPos;
gameObject.transform.rotation = initRot;
}
}
private void OnTriggerEnter2D(Collider2D collision)
{
Debug.Log("Collision happened");
if (collision.tag == "target")
{
shouldFly = false;
transform.SetParent(collision.gameObject.transform);
}
else if (collision.tag == "arrow")
{
SceneManager.LoadScene("quickGameOverScene");
}
}
And The script for rotating the box:
public float rotationSpeed = 70f;
void Update()
{
transform.Rotate(Vector3.back, rotationSpeed * Time.deltaTime);
}
I have a problem. I'm doing a project in Unity 3D (c#), a 3D worlds editor. My problem is that I want to move multiple objects by selecting them. I managed to move one with my mouse cursor, but for multiple I failed :D
This is my code to move one :
public class ClickAndDrag : MonoBehaviour {
private RaycastHit raycastHit;
private GameObject Gobj;
private float distance;
private Vector3 ObjPosition;
private bool Bobj;
// Use this for initialization
void Start() {
}
// Update is called once per frame
void Update() {
if (Input.GetMouseButton (0)) {
var ray = GetComponent<Camera> ().ScreenPointToRay (Input.mousePosition);
var hit = Physics.Raycast (ray.origin, ray.direction, out raycastHit);
if (hit && !Bobj) {
Gobj = raycastHit.collider.gameObject;
distance = raycastHit.distance;
Debug.Log (Gobj.name);
}
Bobj = true;
ObjPosition = ray.origin + distance * ray.direction;
Gobj.transform.position = new Vector3 (ObjPosition.x, ObjPosition.y, ObjPosition.z);
} else {
Bobj = false;
Gobj = null;
}
}
}
Thanks for your help!
private GameObject Gobj; is a variable for a single GameObject. Reformat it to private List<GameObject> objects; and instead of Gobj.transform.position = new Vector3 (ObjPosition.x, ObjPosition.y, ObjPosition.z) do this:
foreach (GameObject item in objects)
{
item.transform.position = new Vector3 (ObjPosition.x, ObjPosition.y, ObjPosition.z)
}
EDIT: In case you aren't sure about how to manipulate a List, List<T> has a set of built in functions to make it really easy. You can now just call objects.Add(newObject); to add an object, and objects.Remove(oldObject); to remove an object.