So for my game I want to be able to pick up objects with my cursor and fling them. I got the drag and drop working on my own but I don't know how to make it fling the object if you throw it. If you try to fling it, the object just drops to the floor. Can someone help me? I tried looking online but I couldn't find a solution. Here's the code:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class DragAndDropObjects : MonoBehaviour
{
public bool canDrag = true;
public bool isDragging;
GameObject player;
Rigidbody2D rb;
void Start()
{
rb = gameObject.GetComponent<Rigidbody2D>();
player = GameObject.Find("Player");
}
void OnMouseDown()
{
if(canDrag && player.GetComponent<Movement>().draggingEnabled)
{
if(!isDragging)
{
print("start dragging");
isDragging = true;
rb.gravityScale = 0f;
gameObject.GetComponent<Rigidbody2D>().constraints = RigidbodyConstraints2D.FreezeRotation;
player.GetComponent<Movement>().draggingObject = true;
GameObject[] heavyObjects = GameObject.FindGameObjectsWithTag("Heavy");
foreach (GameObject heavy in heavyObjects)
{
heavy.GetComponent<Rigidbody2D>().constraints = RigidbodyConstraints2D.None;
}
}
}
}
void OnMouseUp()
{
if(isDragging)
{
isDragging = false;
rb.gravityScale = 1f;
gameObject.GetComponent<Rigidbody2D>().constraints = RigidbodyConstraints2D.None;
player.GetComponent<Movement>().draggingObject = false;
print("stop dragging");
GameObject[] heavyObjects = GameObject.FindGameObjectsWithTag("Heavy");
foreach (GameObject heavy in heavyObjects)
{
heavy.GetComponent<Rigidbody2D>().constraints = RigidbodyConstraints2D.FreezePositionX;
}
}
}
void FixedUpdate()
{
Vector3 mousePos = Input.mousePosition;
mousePos = Camera.main.ScreenToWorldPoint(mousePos);
if(isDragging)
{
transform.position = Vector2.Lerp(transform.position, mousePos, 1f);
if (Input.GetAxis("Mouse ScrollWheel") > 0f )
{
gameObject.transform.Rotate(0, 0, 10f);
}
else if (Input.GetAxis("Mouse ScrollWheel") < 0f )
{
gameObject.transform.Rotate(0, 0, -10f);
}
}
}
}
If you have the answer please tell me! Thank you!
The way to do it would be to get the object velocity using RigidBody2D.velocity and add it to the object transform. You might also multiply the velocity by Time.deltaTime to make the flying process smoother.
Related
I have a problem with an enemy on Unity2D.
The enemy should run to the player and if it's in the attackRange then it has to attack the enemy with a bullet, but the enemy follows my Player.
But there is a problem:
The enemy doesn't shoot with the bullet.
I changed the code, so when I press a button the enemy attacks too.
It worked only with the button.
Here's my code for the enemy:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Pathfinding;
public class Enemy2 : MonoBehaviour
{
public Transform target;
public Transform firePoint;
public float speed = 200f;
public float nextWaypointDistance = 3f;
public float range = 10f; // the range at which the enemy will start moving towards the player
public float attackRange = 8f; // the range at which the enemy will attack the player
float distance;
public Transform enemyGFX;
private Transform player; // reference to the player's transform
public GameObject EnemyWeapon;
Path path;
int currentWaypoint = 0;
bool reachedEndOfPath = false;
Seeker seeker;
Rigidbody2D rb;
public Animator animator;
bool Stop = false;
public static float Enemy2Direction;
// Start is called before the first frame update
void Start()
{
seeker = GetComponent<Seeker>();
rb = GetComponent<Rigidbody2D>();
animator = GetComponentInChildren<Animator>();
player = GameObject.FindGameObjectWithTag("Player").transform;
InvokeRepeating("UpdatePath", 0f, .5f);
}
void UpdatePath()
{
if (seeker.IsDone())
{
seeker.StartPath(rb.position, target.position, OnPathComplete);
}
}
void OnPathComplete (Path p)
{
if (!p.error)
{
path = p;
currentWaypoint = 0;
}
}
// Update is called once per frame
void FixedUpdate()
{
if (Pause.IsPause == false)
{
if (path == null)
{
return;
}
if (currentWaypoint >= path.vectorPath.Count)
{
reachedEndOfPath = true;
return;
}
else
{
reachedEndOfPath = false;
}
Vector2 direction = ((Vector2)path.vectorPath[currentWaypoint] -rb.position).normalized;
Vector2 force = direction * speed * Time.deltaTime;
rb.AddForce(force);
float distance = Vector2.Distance(rb.position, path.vectorPath[currentWaypoint]);
if (distance < nextWaypointDistance)
{
currentWaypoint++;
}
//You can make look it differently, if you delete 'rb.velocity' and add 'force' instead.
if (rb.velocity.x >= 0.01f)
{
enemyGFX.transform.localScale = new Vector3(-1f, 1f, 1f);
Enemy2Direction = 1f;
}
else if (rb.velocity.x <= -0.01f)
{
enemyGFX.transform.localScale = new Vector3(1f, 1f, 1f);
Enemy2Direction = 0f;
}
if (distance < attackRange)
{
if (Stop = false)
{
StartCoroutine(Attack());
}
}
}
distance = Vector2.Distance(transform.position, player.position);
if (distance > range)
{
Destroy(gameObject);
}
}
void OnCollisionEnter2D(Collision2D collision)
{
if (collision.gameObject.tag == "Player")
{
animator.SetBool("Damage", true);
}
if (collision.gameObject.tag == "Bullet")
{
animator.SetBool("Damage", true);
}
}
void Update()
{
if (animator.GetBool("Damage"))
{
StartCoroutine(DamageAnimation());
}
if (Input.GetKeyDown(KeyCode.L))
{
StartCoroutine(Attack());
}
}
IEnumerator Attack()
{
Debug.Log("Attacked");
Stop = true;
yield return new WaitForSeconds(2.0f);
animator.SetBool("Attack", true);
Instantiate(EnemyWeapon, firePoint.position, firePoint.rotation);
yield return new WaitForSeconds(2.0f);
animator.SetBool("Attack", false);
StartCoroutine(Wait());
}
IEnumerator DamageAnimation()
{
yield return new WaitForSeconds(2.0f);
animator.SetBool("Damage", false);
}
IEnumerator Wait()
{
yield return new WaitForSeconds(2.0f);
Stop = false;
}
}
I don't know what's wrong with my code.
Can somebody please help me?
if(Stop == false)
Replace the = in when you check the Stop bool with ==, in C# you use == in order to check for equality
See https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/operators/equality-operators for more detail.
So im coding a grappler from my game (code is from a tutorial with minor tweaks), and im trying to get an prefab instantiated on the top of the grapple that shows the top. its currently just an empty object with a sprite renderer. The grappling is working i just need to figure out how to delete the object when im not pressing the grapple button.
Code:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class grapple : MonoBehaviour
{
public Camera mainCamera;
public LineRenderer _lineRenderer;
public DistanceJoint2D _distanceJoint;
public Transform target;
// Start is called before the first frame update
void Start()
{
_distanceJoint.enabled = false;
}
// Update is called once per frame
void Update()
{
if (Input.GetMouseButtonDown(1))
{
Vector2 mousePos = (Vector2)mainCamera.ScreenToWorldPoint(Input.mousePosition);
_lineRenderer.SetPosition(0, mousePos);
_lineRenderer.SetPosition(1, transform.position);
_distanceJoint.connectedAnchor = mousePos;
_distanceJoint.enabled = true;
_lineRenderer.enabled = true;
Instantiate(target, mousePos, Quaternion.identity);
//if (Input.GetKey("Space"))
//{
//transform.position = Vector2.MoveTowards(transform.position, target.position, 4 * Time.deltaTime);
//}
}
else if (Input.GetMouseButtonUp(1))
{
_distanceJoint.enabled = false;
_lineRenderer.enabled = false;
Destroy(target);
}
if (_distanceJoint.enabled)
{
_lineRenderer.SetPosition(1, transform.position);
}
}
}
Save instantiated object to a class member variable and use it for destroying later
GameObject _instantiatedObj;
void Update()
{
if (Input.GetMouseButtonDown(1))
{
Vector2 mousePos = (Vector2)mainCamera.ScreenToWorldPoint(Input.mousePosition);
_lineRenderer.SetPosition(0, mousePos);
_lineRenderer.SetPosition(1, transform.position);
_distanceJoint.connectedAnchor = mousePos;
_distanceJoint.enabled = true;
_lineRenderer.enabled = true;
_instantiatedObj = Instantiate(target, mousePos, Quaternion.identity);
//if (Input.GetKey("Space"))
//{
//transform.position = Vector2.MoveTowards(transform.position, target.position, 4 * Time.deltaTime);
//}
}
else if (Input.GetMouseButtonUp(1))
{
_distanceJoint.enabled = false;
_lineRenderer.enabled = false;
Destroy(_instantiatedObj);
}
if (_distanceJoint.enabled)
{
_lineRenderer.SetPosition(1, transform.position);
}
}
I am trying to flip my character sprite when moving left in my game, and I have followed multiple tutorials however my sprite does not seem to flip. It is always facing the same way.
Below is my code for my character's movement. I have created a Flip() function and 2 if statements used to call the function. The character can move left, right, up and down (no jumping).
I cannot seem to see where an error would be and why it is not flipping, so any help would be appreciated. thank you.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerMovement : MonoBehaviour
{
// Start is called before the first frame update
private Animator animate;
public float moveSpeed = 6f;
bool facingRight = true;
public Rigidbody2D rb;
Vector2 movement;
private void Start()
{
animate = gameObject.GetComponent<Animator>();
}
// Update is called once per frame
void Update()
{
movement.x = Input.GetAxisRaw("Horizontal");
movement.y = Input.GetAxisRaw("Vertical");
animate.SetFloat("Speed", Mathf.Abs(movement.x));
if(movement.x < 0 && facingRight)
{
Flip();
}
else if (movement.x > 0 && !facingRight)
{
Flip();
}
}
void FixedUpdate()
{
rb.MovePosition(rb.position + movement * moveSpeed * Time.fixedDeltaTime);
}
void Flip()
{
Vector3 currentScale = gameObject.transform.localScale;
currentScale.x *= -1;
gameObject.transform.localScale = currentScale;
facingRight = !facingRight;
}
}
Updated code:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerMovement : MonoBehaviour
{
// Start is called before the first frame update
private Animator animate;
public float moveSpeed = 6f;
bool facingRight = true;
public Rigidbody2D rb;
Vector2 movement;
private void Start()
{
animate = gameObject.GetComponent<Animator>();
}
// Update is called once per frame
void Update()
{
movement.x = Input.GetAxisRaw("Horizontal");
movement.y = Input.GetAxisRaw("Vertical");
animate.SetFloat("Speed", Mathf.Abs(movement.x));
if (movement.x < 0 && facingRight)
{
GetComponent<SpriteRenderer>().flipX = true;
}
else if (movement.x > 0 && !facingRight)
{
GetComponent<SpriteRenderer>().flipX = false;
}
}
void FixedUpdate()
{
rb.MovePosition(rb.position + movement * moveSpeed * Time.fixedDeltaTime);
}
void Flip()
{
Vector3 currentScale = gameObject.transform.localScale;
currentScale.x *= -1;
gameObject.transform.localScale = currentScale;
facingRight = !facingRight;
}
}
Try to set the flipX property of the SpriteRenderer.
GetComponent<SpriteRenderer>().flipX = true;
You have an animator attached to the game object, if the scale value is controlled by the animation clip, you cannot change it. A typical workaround is give the game object an empty parent and change its scale.
Player <---- Change scale here
Model <---- Animator here
transform.Rotate(0f, 180f, 0f); you have to change y while fliping
will work better instead of using currentScale.x *= -1;
gameObject.transform.localScale = currentScale;
This code worked for me
private void Flip()
{
// Rotate the player
if (transform.localEulerAngles.y != 180 && !facingRight)
transform.Rotate(0f, 180f, 0f);
else if(transform.localEulerAngles.y != 0 && facingRight)
transform.Rotate(0f, -180f, 0f);
// player flip point of attck also flip is direction
//transform.Rotate(0f, 180f, 0f);
}
if (Input.GetKeyDown(KeyCode.LeftArrow))
{
GetComponent<SpriteRenderer>().flipX = true;
isLookingRight = false;
}
if (Input.GetKeyDown(KeyCode.RightArrow))
{
GetComponent<SpriteRenderer>().flipX = false;
isLookingRight = true;
}
Going to right
Going to left
I followed a tutorial on Youtube and it was from a man named Dani. I also followed another one from someone called Dave / GameDevelopment on how to pick up objects in Unity 3D. I have ran into a problem where if I pick up a weapon that was on the ground by default it does not work. My gun floats in the air. I believe the main reason for this (don't quote me on this) is that the Gun is some how not becoming a child of the camera, which is what supposed to happen. Please fix and thanks.
This is my pick up script
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PickUpScript : MonoBehaviour
{
public GrappleGun gunScript;
public Rigidbody rb;
public BoxCollider coll;
public Transform player, gunContainer, fpsCam;
public float pickUpRange;
public float dropForwardForce, dropUpwardForce;
public bool equipped;
public static bool slotFull;
private void Start()
{
if(!equipped)
{
gunScript.enabled = false;
rb.isKinematic = false;
coll.isTrigger = false;
}
if (equipped)
{
gunScript.enabled = true;
rb.isKinematic = true;
coll.isTrigger = true;
slotFull = true;
}
}
private void Update()
{
//equipped and e is pressed
Vector3 distanceToPlayer = player.position - transform.position;
if (!equipped && distanceToPlayer.magnitude <= pickUpRange && Input.GetKeyDown(KeyCode.E) && !slotFull) PickUp();
//Drop if equipped and q is pressed
if (equipped && Input.GetKeyDown(KeyCode.Q)) Drop();
}
private void PickUp()
{
equipped = true;
slotFull = true;
transform.SetParent(gunContainer);
transform.localPosition = Vector3.zero;
transform.localRotation = Quaternion.Euler(Vector3.zero);
transform.localScale = Vector3.one;
//Enable rb and km and coll = trigger
rb.isKinematic = true;
coll.isTrigger = true;
//Enable Script
gunScript.enabled = true;
}
private void Drop()
{
equipped = false;
slotFull = false;
transform.SetParent(null);
//Enable rb and km and coll = trigger
rb.isKinematic = false;
coll.isTrigger = false;
//GunCarries momentum of player
rb.velocity = player.GetComponent<Rigidbody>().velocity;
//AddForce
rb.AddForce(fpsCam.forward * dropForwardForce, ForceMode.Impulse);
rb.AddForce(fpsCam.up * dropUpwardForce, ForceMode.Impulse);
//Enable Script
gunScript.enabled = false;
}
}
This is grapple hook script
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class GrappleGun : MonoBehaviour
{
private LineRenderer lr;
private Vector3 grapplePoint;
public LayerMask whatIsGrappable;
public Transform gunTip, camera, player;
private float maxDistance = 50f;
private SpringJoint joint;
void Awake()
{
lr = GetComponent<LineRenderer>();
}
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
void Update()
{
if (Input.GetMouseButtonDown(0))
{
StartGrapple();
}
if (Input.GetMouseButtonUp(0))
{
StopGrapple();
}
}
void LateUpdate()
{
DrawRope();
}
void StartGrapple()
{
RaycastHit hit;
if (Physics.Raycast(camera.position, camera.forward, out hit, maxDistance, whatIsGrappable))
{
grapplePoint = hit.point;
joint = player.gameObject.AddComponent<SpringJoint>();
joint.autoConfigureConnectedAnchor = false;
joint.connectedAnchor = grapplePoint;
float distanceFromPoint = Vector3.Distance(player.position, grapplePoint);
//the distance
joint.maxDistance = distanceFromPoint * 0.8f;
joint.minDistance = distanceFromPoint * 0.25f;
joint.spring = 5f;
joint.damper = 0;
joint.massScale = 1f;
lr.positionCount = 2;
}
}
void DrawRope()
{
//if not grappling
if (!joint) return;
lr.SetPosition(0, gunTip.position);
lr.SetPosition(1, grapplePoint);
}
void StopGrapple()
{
lr.positionCount = 0;
Destroy(joint);
}
public bool IsGrappling()
{
return joint != null;
}
public Vector3 GetGrapplePoint()
{
return grapplePoint;
}
}
I think a better way for your situation would be to create an empty game object where you want the grappling gun to be held when it's picked up, and the empty game object parented to the camera from the scene. Then from the script, you can write these lines of code.
To reference the empty game object:
public transform gunHoldPosition;
And you can attach that from the scene view in Unity.
Then to make the gun snap to the position when it's held:
private void PickUp()
{
equipped = true;
slotFull = true;
transform.localPosition = Vector3.zero;
transform.localScale = Vector3.one;
//Enable rb and km and coll = trigger
rb.isKinematic = true;
coll.isTrigger = true;
//Enable Script
gunScript.enabled = true;
}
Now In the Update function, you have to write a little more:
private void Update()
{
//equipped and e is pressed
Vector3 distanceToPlayer = player.position - transform.position;
if (!equipped && distanceToPlayer.magnitude <= pickUpRange && Input.GetKeyDown(KeyCode.E) && !slotFull) PickUp();
//Drop if equipped and q is pressed
if (equipped && Input.GetKeyDown(KeyCode.Q)) Drop();
if (equipeed){
/* If this script is on the gun itself, then you just have to do transform.position, but if it's on some other object then you have to reference the gun that's being picked with the variable of 'public gameObject gun;' up and say gun.transform.position*/
transform.position = gunHoldPosition.position;
}
}
I'm not exactly sure why you have to do this in the Update function, but once I made a pickup script and the same thing happened to me, so I had to put the transform.postition in the Update Function. Hopefully this works for you if it doesn't reply to me and I will try something else.
Also sorry that I am late to answer my question even though I fixed it really fast. I was making the object with the script, aka a child of the model without actually making the model a child of thing.
I have a script to move my character(player)
The script should be fine and it does not have any errors, although when I press play I try to use the arrows and it does not work and I don't know why.
Here is the code. I appreciate any help you can give me, thanks
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerMovement : MonoBehaviour
{
Direction currentDir;
Vector2 input;
bool isMoving = false;
Vector3 startPos;
Vector3 endPos;
float t;
public float walkSpeed = 3f;
// Update is called once per frame
void Update()
{
if (isMoving)
{
input = new Vector2(Input.GetAxis("Horizontal"), Input.GetAxis("Vertical"));
if (Mathf.Abs(input.x) > input.y)
input.y = 0;
else
input.x = 0;
if (input != Vector2.zero)
{
StartCoroutine(Move(transform));
}
}
}
public IEnumerator Move(Transform entity)
{
isMoving = true;
startPos = entity.position;
t = 0;
endPos = new Vector3(startPos.x + System.Math.Sign(input.x), startPos.y +
System.Math.Sign(input.y), startPos.z);
while (t < 1f)
{
t += Time.deltaTime * walkSpeed;
entity.position = Vector3.Lerp(startPos, endPos, t);
yield return null;
}
isMoving = false;
yield return 0;
}
enum Direction
{
North,
East,
South,
West
}
}
Change
void Update()
{
if (isMoving)
{
to
void Update()
{
if (!isMoving)
{
Otherwise, on each Update you check your isMoving variable and do nothing if it is false. The only place where isMoving could become true is your Move coroutine, but it could only be launched from Update, which does not do anything since isMoving is false.