Jump functionality for a 2D Top Down Unity game? - unity3d

I am struggling to find an efficient way to let my player jump in a 2D Top Down world. I can see a lot of tutorials about platformer views where the camera is oriented at the side of the player, but nothing really working for a top down view like startdew Valley.
I am not using physics, so I move the character on the tilemap using a Couroutine which moves the player to the next position on grid, here it is my Update and DoMove methods:
private void Update()
{
if (!isMoving)
{
input.x = Input.GetAxisRaw("Horizontal");
input.y = Input.GetAxisRaw("Vertical");
if (input.x != 0)
input.y = 0;
if (input != Vector2.zero)
{
animator.SetFloat("Horizontal", input.x);
animator.SetFloat("Vertical", input.y);
var targetPos = transform.position + new Vector3(input.x, input.y, 0f);
// obstacle detection
Vector3Int obstaclesMapTile = obstacles.WorldToCell(targetPos - new Vector3(0, .5f, 0));
if (obstacles.GetTile(obstaclesMapTile) == null)
{
StartCoroutine(DoMove(targetPos));
}
}
animator.SetFloat("Speed", input.sqrMagnitude);
}
}
private IEnumerator DoMove(Vector3 newPos)
{
isMoving = true;
while ((newPos - transform.position).sqrMagnitude > Mathf.Epsilon)
{
transform.position = Vector3.MoveTowards(transform.position, newPos, moveSpeed * Time.fixedDeltaTime);
yield return null;
}
transform.position = newPos;
isMoving = false;
}
Is there anybody which could give me an hint on how to add a jumping feature? ( ideally with animation support?) I am kind of running out of ideas.
Thanks in advance.

Just think of it as animation only. Since it is 2D top down, it's more about it looking like it jumps, and then if it has to go over something while in the jump animation, test for just that.
For example; if over hole and jump animation is playing, then allow movement over the whole, otherwise fall. So if the player presses the button for jump, the animation would play, and there should be some variable storing what animation the player is currently in.

Related

How to use AddForce to make a gameobject jump. The following code is attached to a gameobject. Gameobject wont jump when mouse key pressed

float translation = Input.GetAxis("Vertical") * playerspeed * Time.deltaTime;
float rotation = Input.GetAxis("Horizontal") * playerRotationSpeed * Time.deltaTime;
//check if mouse button prsessed for jumping
IsClicked = (Input.GetMouseButtonUp(0));
if ((IsClicked) && IsOnGround())
rb.AddForce(Vector3.up * jumpForce, ForceMode.Impulse);
//move player
transform.Translate(0,0, translation);
transform.Rotate(0, rotation, 0);
}
//checks if berry is grounded
bool IsOnGround()
{
if (Physics.Raycast(transform.position, Vector3.down, distancetoground))
return true;
else
return false;
}
}
The above code is attached to a gameobject. Gameobject won't jump when mouse key pressed. I think the problem is I can move the gameobject using translate. but unable to add a jumping force as required when the left mouse button is pressed as I have set the y axis paraemter in the translate. Don't know how to get round this one. Any offers?
Try to use a rigid body instead it might not be more efficient but it works fine for me. You add a force upwards when the button is pressed (This won't work in games where you move your platform instead of a player)

Unity 2D. Why raycasting does not work properly?

With this code I am changing color of gun object if raycast can hit player. Color changes as soon as Player walks into raycast radius. However color won't switch back from red to green as soon as player either goes away (more than Range distance) or hide behind walls. It will eventually switch back to green but not right away. Can you please help me figure out what seems to be the problem?
void Update()
{
Vector2 targetPos = Target.position;
Direction = targetPos - (Vector2)transform.position;
RaycastHit2D rayInfo = Physics2D.Raycast(transform.position, Direction, Range, layerMask);
if (rayInfo)
{
if (rayInfo.collider.gameObject.tag == "Player")
{
if (Detected == false)
{
Detected = true;
Gun.GetComponent<SpriteRenderer>().color = Color.red;
}
}
else
{
if (Detected == true)
{
Detected = false;
Gun.GetComponent<SpriteRenderer>().color = Color.green;
}
}
}
}
When your raycasthit doesn't hit anything with specified LayerMask you don't change your gun's color maybe this is the issue. if your reset your gun color it can solve. Here is the example
//define gunColor variable it is default color of your gun
Color gunColor=Color.green;
void Update()
{
Vector2 targetPos = Target.position;
Direction = targetPos - (Vector2)transform.position;
RaycastHit2D rayInfo = Physics2D.Raycast(transform.position, Direction, Range, layerMask);
if (rayInfo)
{
gunColor=rayInfo.collider.gameObject.CompareTag("Player")?Color.red:Color.green,
}else{
//when raycasthit doesnt hit any thing set gun color to green;
gunColor=Color.green;
}
//update gun color
Gun.GetComponent<SpriteRenderer>().color = gunColor;
}

Collision with object on another layer isn't working in Unity?

I have two box colliders in my scene. I am basically manipulating one and the other is stationary and just on the default layer and it also has a rigidbody attached. The other object I am mostly rotating and for some reason it rotates right through the other object. It is on another layer but, I have checked the layer collision matrix and all of the boxes are checked so I'm not sure why the collision isn't happening. Is there a reason for this?
I am Rotating it with transform.Rotate. Neither of the colliders have the isTrigger selected. Any thoughts?
EDIT: Added this to show implementation of rigidbody.MoveRotation
private void FixedUpdate()
{
if (Input.GetKey(KeyCode.Y) && !colliding)
{
if (rigidBody == null)
{
rigidBody = gameObject.AddComponent<Rigidbody>();
rigidBody.isKinematic = true;
rigidBody.useGravity = false;
rigidBody.interpolation = RigidbodyInterpolation.Interpolate;
}
rot = Quaternion.Euler(0, .5f, 0);
rigidBody.MoveRotation(rigidBody.rotation * rot );
}
if (Input.GetKey(KeyCode.I) && !colliding)
{
if (rigidBody == null)
{
rigidBody = gameObject.AddComponent<Rigidbody>();
rigidBody.isKinematic = true;
rigidBody.useGravity = false;
rigidBody.interpolation = RigidbodyInterpolation.Interpolate;
}
rot = Quaternion.Euler(0, -.5f, 0);
rigidBody.MoveRotation(rigidBody.rotation * rot);
}
else if (colliding)
{
rigidBody.MoveRotation(rigidBody.rotation * Quaternion.Inverse(rot));
}
}
Collisions do not happen if you update the position or rotation of any object through the transform. You can receive the OnCollision events but you will not get the desire results if you rotate or move using the transform. Update your code to use the rigidbody for any changes to rotation and position in a fixedUpdate to receive these effects, aka colliding.

Move object with hinge joint, but keep it connected to hinge

I have multiple spheres in my mobile game that are attached to hinge joints. The spheres are able to swing and knock into each other, causing other spheres to swing. I am creating movement in the spheres by touching on a sphere and dragging it to a new location. Letting go is supposed to cause the sphere that I just moved to swing accordingly.
The issue is that I am able to move the spheres well outside of the space provided by the hinge. I never want the spheres to move anywhere that they wouldn't be able to swing using the hinge. I am able to move the spheres multiple units/meters away from their original position, when ideally I wouldn't be able to move them more than a few centimeters. The spheres should just stop moving if I hit a limit in the hinge.
Here's my code for the script that controls movement of the spheres:
GameObject selectedObject;
Vector3 screenPoint;
Vector3 offset;
void Update () {
if (Input.touchCount == 0)
{
return;
}
Touch touch = Input.GetTouch(0);
if (touch.phase == TouchPhase.Began) // when screen is touched...
{
RaycastHit hit;
if (Physics.Raycast(Camera.main.ScreenToWorldPoint(touch.position), Camera.main.transform.forward, out hit)) // ...cast a ray...
{
if (hit.collider.tag == "Sphere") //...and check if ray hits a sphere
{
selectedObject = hit.collider.gameObject;
screenPoint = Camera.main.WorldToScreenPoint(selectedObject.transform.position);
offset = selectedObject.transform.position - Camera.main.ScreenToWorldPoint(new Vector3(touch.position.x, touch.position.y, screenPoint.z));
}
}
}
if (touch.phase == TouchPhase.Moved)
{
Vector3 touchPoint = new Vector3(touch.position.x, touch.position.y, screenPoint.z);
Vector3 touchPosition = Camera.main.ScreenToWorldPoint(touchPoint) + offset;
selectedObject.transform.position = touchPosition;
}
}
Any help is greatly appreciated! Let me know if I need to explain more or show a video of the issue.
I know I am a little late but you can use AddForce() and AddTorque() methods on the object you want to move but that works only if you have RigidBody on the object.

buttons only react to clicks/touches when clicking/touching to the right of them

I'm making a 2D game in Unity3D for android. Right now I'm making buttons. And this buttons does not react clicks/touched properly. I've got same issue with mouse clicks and touches both. Every button has trigger boxcollider with a same size as an object. BUT buttons react only when I click on area, that is right from a button. I don't understand why is it so. What should I do? Here is my code:
if (Input.GetMouseButtonDown(0)) {
Vector3 i = Camera.main.ScreenToWorldPoint (new Vector3 (Input.mousePosition.x, Input.mousePosition.y, 1));
RaycastHit2D hit = Physics2D.Raycast (i, i);
if (hit.transform != null) {
if (hit.transform.tag == "button") {
hit.transform.gameObject.SetActive(false);
}
}
}
Also, I've instantiated an object on mouse click on "i" position to check does it convert screen position to world correctly, and it works fine.
the first parameter in Physics2D.Raycast is the origin and the second one is direction so you should make the raycast from your ray.origin in the direction of ray.direction
void Update () {
if (Input.GetMouseButtonDown(0)) {
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
RaycastHit2D hit = Physics2D.Raycast (ray.origin, ray.direction, Mathf.Infinity);
if (hit) {
if(hit.collider.gameObject.tag=="button"){
//do something
}
}
}
}
Try to handle it by this way:
if (Input.GetMouseButtonDown(0)) {
Vector3 pos = Camera.main.ScreenToWorldPoint (Input.mousePosition);
Vector2 touchPos = new Vector2(pos.x, pos.y);
Collider2D hit = Physics2D.OverlapPoint(touchPos);
if (hit) {
Debug.Log(hit.transform.gameObject.name);
if (hit.transform.tag == "button") {
hit.transform.gameObject.SetActive(false);
}
}
}