I'm new to Unity and after watching and reading some tutorials I'm now trying to make a simple 2D platformer kind of game. In the said game both enemies and player can jump to different platforms and traverse it like the old SnowBros game.
The problem I'm facing is related to programming the enemy movement. In my game there would be several types of enemies but generally for now there are two types, one that can jump from the platform and one that only walks upto the length of the platform, wait for 1 second then flip and walk backwards; meaning they don't get off the platform. Now this is an issue I'm having trouble with. I can't seem to find a way to calculate the length of the underlying current platform. I thought of using the collider.bound.min.x and max.x to come around the problem but the issue is I can't seem to find a simple way to reach the current platform's collider without fetching the script and then going through it.
Since, there would be many platforms of many different sizes and each platform is made up of a prefab of other platforms, it just doesn't seem like a workable solution to use the platform script and then traverse through it.
You can use Physics2D.Raycast to "sense" for collisions on a Ray. Imagine the enemy putting their toe one step forward, feeling if there is still solid ground, and then deciding whether to stop.
void Update()
{
Vector2 newPosition = transform.position + velocity * Time.deltaTime;
Vector2 downwardDirection = Vector2.down; // you may have to replace this with your downward direction if you have a different one
RaycastHit2D hit = Physics2D.Raycast(newPosition, downwardDirection);
if (hit.collider != null)
{
// solid ground detected
transform.position = newPosition;
}
else
{
// no ground detected. Do something else...
}
}
You can and should define the Layers your Raycast is supposed to hit, so it can ignore the enemy itself and avoid self-collision.
Well, I hope that you have prefabs of platform and in those prefabs put colliders at start and at end. You can specify layers and tags so that only enemy can detect those colliders and then you can detect tags on collision from enemy script and make your operation.
First create layers by opening Edit -> Project Settings -> Tags and Layers. Create two Layers
Create layers for enemy and enemyColliders and Goto Edit -> Project Settings -> Physics2D. Set collision matrix as EnemyCollider will collider with enemy only.
And your prefab will be looks like,
I hope this would help you.
Related
I made the endless movement of the object and its repulsion from the walls, but it does not always work correctly. At rounded corners (sometimes even at a straight wall), it just gets stuck and stops moving altogether, or moves slowly to the point where it stops moving. What can this be related to and how can it be fixed?
private void FixedUpdate() {
rb.velocity = direction * normalSpeed;
lastDirection = direction;
}
private void OnCollisionEnter2D(Collision2D collision) {
//Repulsion from objects.
direction = Vector3.Reflect(lastDirection.normalized, collision.GetContact(0).normal);
}
There is a small distance between the objects, but the circle seems to stick to the wall and moves with it until it collides with another collider:
Example
there are objects under the circle that also have colliders, but the collision between them is not considered, since they have the same layer (in the settings, I disabled the collision for objects on the same layer). What can be done to fix this error and what can it be related to?
The object in the general scale:
Example
I tried to increase the size of the wall collider, tried to change polygon collider to box collider, connect composite collider, changed the mechanics of the object movement (in these cases, the movement could work incorrectly), but the result was always the same - the jams (sticking to the wall) continued.
It is difficult to answer your question without having more information, but I can suggest if you are using physics to move your objects - utilize physic materials and remove code that changes direction manually in OnCollisionEnter. Using physic materials you can easily make your object bounce from colliders of your choice without losing velocity.
I have 3d cube which have 3d box collider.
I want to write jump system for cube with collision, but without physics (without gravity, without rotation, etc) (Like 3d platformer)
You can take advantage of the Physics.OverlapBox API to check for collisions before committing to move your object.
Your code will look something like this:
Vector3 nextPosition = transform.position;
/*
You do your normal movement code, but apply
it to nextPosition instead of transform.position
*/
Collider[] hitColliders = Physics.OverlapBox(nextPosition, transform.localScale/2);
if(hitColliders.Length == 0){
transform.position = nextPosition;
}
Note that the object itself shouldn't have a collider, otherwise it will detect itself. You also shouldn't move in big steps as this method doesn't take colliders on the path into account.
There is a great way of doing this. You will still need physics.
The Steps
Have a rigidbody on your player.
There should be a dropdown menu called spmethiing like "constraints". Find it.
Then Set all rotation constraints in this menu to true.
However, I don't understand why you wouldn't want gravity. Don't all platformers have gravity? (There must be some force to pull your player down when they jump). Anyways, if you don't want gravity, then you must uncheck Use Gravity variable.
**Notes: **
To control your player, you must use AddForce(). If you have any questions about adding force, let me know in the comments.
:) Thanks.
Basic Problem: Unity's physics engine produces weird collisions when a player is moving over a flat surface made of more than one Collider. The ghost collisions occur at the joints between Colliders, and express as two behaviors:
This seems to be a problem with physics engines in general, based on this talk by Bennett Foddy:
https://www.youtube.com/watch?v=NwPIoVW65pE&ab_channel=GDC
Game Specifics:
In my case, the player is moving through a procedurally generated wormhole, composed of Segment objects using a MeshCollider. The wormhole twists randomly through 3D space, while the width and height change dynamically. The player can strafe 360 degrees around the inside of the tunnel (direction of gravity is relative to position).
This makes the simpler solutions I've found impractical. Those include:
Using a single object instead of many
Placing redundant Colliders behind the joints
I've managed to flag these erroneous collisions in OnCollisionEnter(). This method on the PlayerController works fine to identify these erroneous collisions, and raise a flag.
private void OnCollisionEnter(Collision other)
{
if (other.gameObject.tag != "Tunnel"){return;}
// Bit mask for tunnel layer.
int tunnelLayerMask = 1 << 10;
// Get the direction from the nearest Segment's origin to the collision point.
Vector3 toCollision = other.contacts[0].point - nearestSegment.transform.position;
if (Physics.Raycast(nearestSegment.transform.position, toCollision, out RaycastHit hit, 100f, tunnelLayerMask))
{
// Flag the collision if the detected surface normal
// isn't equal to the collision normal.
if (other.contacts[0].normal != hit.normal) { colFidelityFlag = true; }
}
}
But I'm at a complete loss when it comes to gracefully resolving the issue.
Currently, I'm just caching the player's velocity each frame. If a collision is flagged, I overwrite the resulting velocity with the cached velocity from the previous frame. This works for most conditions: the player ghosts imperceptibly into the floor for a frame, and gets past the offending joint.
But under high enough velocities or interactions with obstacles inside the tunnel, it is possible for the player to be ejected through the floor, and into space. I don't want to limit the velocity of the player too much, since the feel of the game partially relies on high velocity and hard collisions.
Does anyone know of a better way to resolve these erroneous collisions?
This is called "ghost vertices", and happens if you have like 2 box colliders (or something equivalent) and they are connected to each other. You could try to join the colliders so that instead of 2 separate connected colliders you have a single one.
Here ghost vertices are explained in more detail: https://www.iforce2d.net/b2dtut/ghost-vertices
I'm creating a fast-paced, 2D side-scrolling game on Unity 5.2, building my terrain out of discrete "blocks", each with its own EdgeCollider2D component.
Having a problem where my character gets bumped upward as it crosses from one block to another (imagine driving your car over a speed bump on the road).
This doesn't happen all the time. Seems to be random, which is even more irritating, as it makes finding a solution more difficult.
I've tried all of the suggestions that I could find for similar questions on this site, including:
Using CircleCollider2D's on the character
making sure the terrain blocks and their corresponding colliders are perfectly aligned. The attached screenshot shows one of the intersections.
changing the "Min penetration for penalty" setting to the minimum allowed value (0.0001)
switching between discrete and continuous collision detection for the character's RigidBody2D
increasing the mass and gravity scale for the character's RigidBody2D
... to no avail.
Beyond building a single, massive terrain object with a single edge collider from start to finish (which I'm trying to avoid), I've run out of ideas. Anything else I'm missing? Is it just a Unity bug?
Help!
Try detect the collision and set the vertical velocity to zero.
void OnCollisionEnter2D(Collision2D col)
{
if (col.gameObject.name.StartsWith("block"))
rigidbody2d.velocity = new Vector2(rigidbody2d.velocity.x, 0);
}
I am trying to build a 2D space shooter game where the player will remain constant at the bottom of the screen and will move left and right. When the player fires a bullet(projectile), the bullet is going up just fine, but it is coming back again. Also if two bullets collide, they react to the collision.
I have two questions here:
How can I ensure that the bullet does not come back? (One way is to destroy it after a few seconds, but not sure if this is the right way)
How do I avoid collision between the bullets.
Here is my code snippet:
void Update () {
if (Input.GetButtonDown("Fire1"))
{
Rigidbody2D clone = (Rigidbody2D)Instantiate(bullet, transform.position + transform.up, transform.rotation);
clone.velocity = transform.TransformDirection(Vector3.up * 20);
}
}
I am very new to Unity and somehow wrote this code by looking into Unity Forums.Any help will be very much appreciated.
Thanks
More details:
I have created the bullet and added Rigidbody2D and a BoxCollider2D for this object. Made the bullet object a prefab and I dragged it under the Player object. Now bullet is a child of the Player object. Attached the script above to the Player object.
To answer your immediate questions:
1) I am not too sure about how you have the scene setup or about using the Unity 2D tools but usually if your bullets are coming back down then I would assume that you still have gravity applied to the rigidbody -- so make sure that you have that unchecked.
2) With Unity3D for objects to interact with each other they need rigidbodies attached. This is vital, say, if you want your lasers to destroy Monster #1. However, you only need one rigidbody attached to an object to have a desired effect. I would suggest removing the rigidbody from your laser and attach rigidbodies to objects ( Monster #1 ) that you want to be affected by the laser fire. ( That should work, if not there are other options -- one using layers and ignoring particular objects on those layers ).
Tips:
Here are some extra things. When you are creating objects and they fly off screen over time they will build up. Imagine you are in a large battle and you instantiated hundreds of lasers -- it will eventually be an issue for performance. So always consider Destroying objects after a certain amount of time.
Also, after looking at your code, I can't tell whether the velocity of the object is based upon its current position and nothing is being added. What I think is happening is when you instantiate an object it may be moving up, but because there is no incrementer, the object ( as it gets higher ) slows until it is at a rate which it is falling. For example this
clone.velocity = transform.TransformDirection(Vector3.up * 20);
should probably do this:
clone.velocity += transform.TransformDirection(Vector3.up * 20);
Heres http://docs.unity3d.com/Documentation/ScriptReference/Vector3-up.html, to read up on velocity. The problem is is that you need to continuously apply a constant forward motion so things in motion will tend to stay in motion. If not gravity will pull it down.
Also, heres a bit of code that I've used in the past that's created a pretty cool shooting laser effect thing:
public class Laser : MonoBehaviour {
public int fireRate = 70;
void Start(){
InvokeRepeating("FireLaser", 0.01f, 0.009f);
Destroy( gameObject, 2.0f );
}
void FireLaser(){
transform.Translate( Vector3.up * fireRate * Time.deltaTime );
}
}
edit: it's 3 a.m. and I hate proofreading.