I am currently working on a game in Unity and I have a huge problem. I want to draw a level with a tilemap and then move the player on this tilemap. But I want to add an edge collider with the script at the start of the level, because I want to include a Level-Creator in the game. So, I cannot create every collider manual.
Here is an example picture of a "level":
I want to have an edge collider to prevent moving outside the tilemap, but I do not know how to implement that in code. I either cannot find anything helpful on web.
I would be glad about any ideas!
If you get the Collider component of your tilemap, you are able to access the "OverlapPoint" method. With this method you're able to make a basic edge detection system for your custom tile map.
https://docs.unity3d.com/ScriptReference/Collider2D.OverlapPoint.html
What I would do is:
Save Your player's current position in a "lastPosition" variable, check for every update if the corners are inside the collider with the "OverlapPoint" method. If not: do not save the current position but set the current position of the player to the lastPosition variable.
public Vector3 playerSize;
public Collider2d collider;
Vector2 lastPosition;
void Start()
{
lastPosition = transform.position;
}
void Update()
{
if(!collider.OverlapPoint(transform.position) ||
!collider.OverlapPoint(transform.position + playerSize) ||
!collider.OverlapPoint(transform.position + new Vector2(playerSize.x, 0)) ||
!collider.OverlapPoint(transform.position + new Vector2(0, playerSize.y)))
{
transform.position = lastPosition;
}
lastPosition = transform.position;
}
Related
So I'm trying to make a little pushback effect in my tests arena, I've got a sphere collider and here is my script:
// PushBack Class Script
if (Input.GetKeyDown(KeyCode.Q))
{
explosion_ball.transform.position = transform.position;
StartCoroutine(WaitAndPrint());
}
IEnumerator WaitAndPrint()
{
float i = 0;
while (i < 1)
{
i += 0.01f;
explosion_ball.radius = curve.Evaluate(i) * 10;
yield return new WaitForSeconds(0.01f);
}
}
//__________//
Sphere collider is set and stuff, but it doesn't push things back like I thought it would.
Thanks!
Edit:
explosion_ball is a sphere collider, I'm changing it with the point on the animation curve and * it by 10
EDIT:Unity Rigid bodies go to sleep so[Also Change interpolation to continuous if collider changes size too quickly]
A.check if obstacle rigid bodies are Sleeping with onTriggerEnter and Wake Up
void OnTriggerEnter(collider){ if(rb.IsSleeping()){rb.WakeUp();}
or
B.Attach this forceWakeUp Script to all Objects you want to be obstacles.
using UnityEngine;
public class forceWakeUp : MonoBehaviour
{
private Rigidbody rb;
void Start()
{
rb = gameObject.GetComponent<Rigidbody>();
}
void Update()
{
if(rb.IsSleeping()){rb.WakeUp();}
}
}
Forcibly Keeping Many objects awake Will impact performance.So ,your decision.
You need to scale up the collider on the object by radius and all the objects it is supposed to wobble need to have Rigid body component attached to them
2.if you ARE doing above things and its not adding any force you could just add a force on all the overlapping objects using the "OnCollisionEnterTrigger" and AddForceMethod radially away from the Sphere
Obstacle.position - Sphere.position is the vector Radially away from Sphere I think.
You don't need coroutines for this I think.
While searching through the Unity scripting API, found a method in there called
Rigidbody.AddExplosionForce(explosionForce, explosionPosition, explosionRadius, upwardsModifier, mode)
In order to get the rigid bodies that are to be affected by the explosion I would need to get them using Physics.OverlapSphere(position, radius) this gets all of the objects within the radius variable, then get the component.
Combining these two would also look like:
Collider[] colliders = Physics.OverlapSphere(transform.position, radius);
foreach (Collider hit in colliders)
{
if (hit.transform.tag == "Interactable")
{
if (hit.gameObject != hitgameObject)
{
Rigidbody rb = hit.GetComponent<Rigidbody>();
if (rb != null)
rb.AddExplosionForce(power, transform.position, radius, upForce, ForceMode.Impulse);
}
}
}
If there is any explaining that you would like me to do about my variables mentioned I will reply :)
Thanks for the help guys.
I don't know your curve and what values that evaluation produces, but you can check your code visually with Window/Analysis/Physics Debugger, or write a gizmo:
private void OnDrawGizmos()
{
Gizmos.color = new(1.0f, 0.0f, 0.0f, 0.5f);
Gizmos.DrawSphere(explosion_ball.transform.position, explosion_ball.radius);
}
Or simply just use https://docs.unity3d.com/ScriptReference/Rigidbody.AddExplosionForce.html
I am currently creating a game in Unity, in which you move a ball around using OnMouseDrag(), a CircleCollider2D and a RigidBody2D. This is how I set the position of the ball:
private void OnMouseDrag()
{
Vector2 mouseInWorld = Camera.main.ScreenToWorldPoint(Input.mousePosition);
playerRb.position = new Vector3(mouseInWorld.x, mouseInWorld.y, 0);
}
I still want the ball to slide on collision while the mouse moves around. Is there a way to do this?
I have tried RigidBody2D.MovePosition(), but the ball jumped around from one point to another, and Raycasts but couldn't get that to work either.
EDIT:
This is what I've got now:
playerRb.velocity = new Vector3(mouseInWorld.x - playerRb.position.x, mouseInWorld.y - playerRb.position.y, 0);
Now the problem is, that the ball lags behind the mousePosition.
When you use RigidBody.MovePosition, you don't call the physics engine and so it ignores collisions. If you want collisions to happen you need to use RigidBody.Velocity instead.
Doing this change will require you to make some change to your code though because what you give to RigidBody.Velocity is a velocity and not a position so you will need to calculate the velocity required in x,y (and z if you are in 3d) to reach your destination.
I invite you to read the Unity page about velocity for more info
https://docs.unity3d.com/ScriptReference/Rigidbody-velocity.html
Note: This will make the player/ball stick to collisions.
Modifying the velocity could cause the ball to bounce around unexpectedly when the ball collides with the wall. I would use a CircleCast for this, check if it hit anything, then use MovePosition accordingly:
float cursorDepth;
Rigidbody2D playerRb;
CircleCollider cc;
void Awake()
{
playerRb = GetComponent<Rigidbody2D>();
cc = GetComponent<CircleCollider>();
}
private void OnMouseDrag()
{
Vector2 mouseInWorld = Camera.main.ScreenToWorldPoint(Input.mousePosition);
Vector2 posToMouse = mouseInWorld - playerRb.position;
RaycastHit2D hit = Physics2D.CircleCast(playerRb.position,
cc.radius * transform.lossyScale.x, posToMouse, posToMouse.magnitude);
if (hit.collider != null)
{
mouseInWorld = hit.centroid;
}
playerRb.MovePosition(mouseInWorld);
}
But notice that if the ball can't move all the way to the mouse, it might cause the drag to end. So, plan accordingly.
I'm creating a 2d game and I want to make it so that tiles are destructible whenever a projectile collides with a tile. The problem is I don't know how to get the tile that the projectile is colliding with, I would like to make it so that it area of damage.
However for now I want to make it so that once the projectile reaches the ground it destroys the tile it's sitting on I've made a collider2d to help me with that but I still have no idea how to get the tile that's the projectile is sitting on.
IEnumerator OnCollisionEnter2D(Collision2D collision)
{
//Projectile has reached the ground and is in collision with some tile
Vector2 hit = gameObject.transform.position;
Debug.Log("y" + hit.y);
hit.y =- 3; // i have no idea what y i should put in order to get the tile
if (x.gameObject.tag != "Player")
{
Collider2D[] collidedwith = Physics2D.OverlapCircleAll(this.gameObject.transform.position, radius);
//what should the hit vector be in order to destroy the tile.
tilemap.SetTile(tilemap.WorldToCell(hit), null);
}
}
A screenshot for better explanation (I would like to get rid of the blue tile):
If possible I would like to make it into an aoe projectile but for now it's not necessary
Assuming you have colliders in place, that is:
Collider in the rocket with is trigger selected (to allow OnTriggerEnter2D be triggered)
Collider on the tiles to actually trigger the OnTriggerEnter2D of the rocket during the collision
Now, to detect collisions between rocket and tiles, do the following:
Give the tile gameObject (prefab) the tag name tile
Replace your code in the rocket with:
Script
// It will be triggered the the rocket crashes against the tile
void OnTriggerEnter2D(Collider2D col)
{
if(collision.gameObject.tag == "tile")
{
// Destroy the tile the rockets collided with
Destroy(collision.collider.gameObject);
// Destroy the rocket itself
Destroy(gameObject);
}
}
ok i came up with a solution but this solution doesn't really have the feature i really wanted which is, i want the projectile to do aoe damage
Tilemap tilemap = GetComponent<Tilemap>();
Vector3 hitPosition = Vector3.zero;
foreach (ContactPoint2D hit in collision.contacts)
{
Debug.Log(hit.point);
hitPosition.x = hit.point.x - 0.1f;
hitPosition.y = hit.point.y - 0.1f ;
tilemap.SetTile(tilemap.WorldToCell(hitPosition), null);
}
So, my boss moves in a specific direction when it detects the player. The problem I'm having is how to get the boss to move depending on where the player is within a certain proximity. So if the boss is on the player's left, he'll move to the left. If he's on the player's right, he'll move to the right. But I can't figure out how to make him react based on distance. Right now I'm just doing a Debug.Log to save a few seconds.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class phantom : MonoBehaviour {
private Rigidbody2D rb;
private Animator anim;
public Transform Target;
void Start ()
{
rb = GetComponent<Rigidbody2D> ();
anim = GetComponent<Animator> ();
}
void Update ()
{
if (transform.position.x > Target.position.x ) {
Debug.Log ("left");
}
if (transform.position.x < Target.position.x ) {
Debug.Log ("right");
}
}
}
You could use the Vector3.Distance method to determine the distance between your two object based on thier respective transform. That way, you can modify your boss's behavior according to his proximity to the player. The smaller the magnitude value is, the closer your two transforms are.
Ex:
int distanceYouWant;
if(Vector3.Distance(transform.position, Target.position).magnitude < distanceToDoStuff)
{
Debug.Log("Boss do stuff!");
}
Here is the link to the Unity scripting API doc: https://docs.unity3d.com/ScriptReference/Vector3.Distance.html
Hope this helps!
I figured it out. I just made the function not in Update but with an OnTriggerEnterStay2d (Collider2D other). Then I placed a trigger collider on the same GameObject and only when it detects the Target (the player) does the debug come up.
I try to move my character but he moves through the border of the scene.
When I debug it sayscharTransform has 0 0 0 coords in Vector3.
Transform charTransform;
float leftHorizontalBound;
float rightHorizontalBound;
void Start()
{
charTransform = this.transform;
leftHorizontalBound = camera.ViewportToWorldPoint (new Vector3 (0,0, camera.nearClipPlane)).x;
rightHorizontalBound= camera.ViewportToWorldPoint (new Vector3 (1,0, camera.nearClipPlane)).x;
}
void Update()
{
if(charTransform.position.x <= leftHorizontalBound)
{
charTransform.position = new vector2(leftHorizontalBound + 0.1f);
return;
}
if(charTransform.position.x >= rightHorizontalBound)
{
charTransform.position = new vector2(rightHorizontalBound - 0.1f);
return;
}
//MAKE HERE YOUR MOVEMENT BASED ON INPUT.
}
i cant exactly say what is your problem and wish you assume your problem more accurate but i think you are working something like a boad game with a fixed camera and something like a ball always moves and you just want to keep that object in the scene.
in your code you defined a position by variables and made a position check for every frame. thats not what basically is done in unity and there will be problems. you can make an empty object and put in on the borders you want and check the position of that object with your moving object.
your next way is make an object and add a collider component to it. if your game is 3d add a collider and if its 2d game add a 2d collider and a collider to moving object and after that it never moves toward the borders but still there will be some limits so if it didnt work i think you should add a rigidBody to both of them.