Solid plane in Unity - visual-studio

So I created a plane to be my floor in my unity project. I also assigned that with a mesh collider and a box collider and set it with convex but not as trigger.
I then created an item with also a mesh and sphere collider and set it to use gravity, since I wanted the item to fall onto the floor. But when I start the game, it still falling past the floor.
I have tried to find a solution already in YT, here and other places, but the only ideas they give is assigning a collider. This doesn't work as for me.
I also tried to fill the colliders with materials but cannot assign anything with it.
I also tried to write a code, but this does not help either.
Does anyone have an idea how to solve it?
public class IsGrounded : MonoBehaviour
{
Vector3 velocity;
public float gravity = -9.81f;
public Transform groundCheck;
public float groundDistance = 0.4f;
public LayerMask groundMask;
bool isGrounded;
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
void Update()
{
isGrounded = Physics.CheckSphere(groundCheck.position, groundDistance, groundMask);
if (isGrounded && velocity.y < 0)
{
velocity.y = -2f;
}
}
}

So finally, I manage to find the solution from a helpful yt video.
What I needed to change was to deactivate both, the floor and the items, the trigger event. Since Unity does not allow you to use without kinematic and convex, I just clicked on convex and nothing changes. Now, items will not fall down the plane (still can happen, like when I throw the item down, it will sometimes go through).

Related

How to ignore one OnTrigger Collider in an Object?

I have 3(Three) BoxCollider2D components where 2(two) have OnTrigger checked in my Object and both have different functions. Due to having OnTrigger on both, the projectiles I am casting collide with the wrong collider and instead activate that function. Is there a way to ignore 1(one) OnTrigger collider?
I have already tried Layer-based collision detection and set up a layer. Unfortunately, the object now collides with the collider which eliminates the player on collision
However, there are several ways to solve this problem. All kinds of physics.checks as well as raycasts but this code helps you to ignore the obstacle collider.
public Collider2D playerCollider;
public Collider2D obstacleCollider;
public void Start() => Physics2D.IgnoreCollision(playerCollider, obstacleCollider);
I have a very simple script I use to handle collisions in my games.
It's very easy to setup because it makes everything drop and draggable, which is a much easier way to program.
Below is the script and below that is instructions on how to use. Note it is a layer based system, but you can select multiple layers.
[System.Serializable]
public class TriggerEvent : UnityEvent<Collider> { }
[System.Serializable]
public class CollisionEvent : UnityEvent<Collision>{ }
public class EnterEvent: MonoBehaviour
{
public TriggerEvent TriggerEnteredEvent;
public CollisionEvent CollisionEnteredEvent;
[SerializedField]private LayerMask validLayers;
// Initalize Event System
void Awake()
{
if (OnTriggerEnter == null)
{
TriggerEnteredEvent = new TriggerEvent();
}
if (OnCollisionEnter == null)
{
CollisionEnteredEvent = new CollisionEvent();
}
}
// Called if transform is a trigger
void OnTriggerEnter(Collider collider)
{
if (validLayers == (validLayers | 1 << collider.gameObject.layer))
{
TriggerEnteredEvent?.Invoke(collider);
}
}
// Called if transform is not a trigger
void OnCollisionEnter(Collision collision)
{
if (validLayers == (validLayers | 1 << collision.gameObject.layer))
{
CollisionEnteredEvent?.Invoke(collision);
}
}
}
This is how it would work, and in this example I will be "coding" it from the perspective of a Bullet.
Basically I want to check if I (The Bullet) hits either the terrain or an enemy then call the relevent funcitons in the Bullet class respectively.
Obviously if I hit an enemy I want to deal damage.
So this will be my example bullet class
public class Bullet : MonoBehaviour
{
public int BulletDamage = 10;
public int BulletSpeed = 5;
void FixedUpdate() => transform.position = Vector3.Lerp(transform.position, transform.position + transform.forward * speed * Time.deltaTime, 1f);
public void OnEnemyHit(Collision collision)
{
// Try to get the enemy script
Enemy enemy = collision.gameObject.transform.GetComponent<Enemy>();
if (enemy != null)
{
enemy.DealDamage(this.BulletDamage);
}
}
public void OnTerrainHit(Collision collision)
{
Destroy(this.gameObject);
}
}
Add the EnterEvent script to the bullet.
Add the Bullet Script to the bullet.
There will be a space on the Inspecter where you can add your events. It should have a Plus and Minus in the top right corner. Press the plus.
From the inspector drag the bullet in game GameObject to the open space provider.
In the dropdown to the right, click on it, look for the Bullet Script, and select the OnEnemyHit function from it.
Create another event, do the exact same, but this time select the OnTerrainHit funciton instead - now but would be called in the order you added them.
Just underneath the event system should be the be able to see a dropdown for the Layers. Select all the layers you want your bullet to interact with. In this case it will be the Enemy and Terrain.
Finally remember to setup your layers properly. Ensure the Enemy has an Enemy Layer, the Terrain has a Terrain Layer, Bullet bullet layer and Player has a Player Layer

Play a particle system when Time.timeScale = 0?

I have a particle system explosion that I want to play when the player dies. The idea that is that everything else pauses but the explosion continues, like the Pacman animation when you die (everything freezes and the pacman death animation plays).
Trouble is, it won't work. I know Time.timeScale = 0 pauses everything, and I've tried using this script to combat that, but it doesn't seem to be working:
void Update()
{
if (Time.timeScale < 0.01f)
{
particleSystem.Simulate(Time.deltaTime, true, false);
}
}
I have also tried this, but it doesn't work either:
private ParticleSystem pSystem;
public void Awake()
{
pSystem = gameObject.GetComponent<ParticleSystem>();
}
public void Play()
{
pSystem.Simulate(Time.unscaledDeltaTime,true,true);
}
public void Update()
{
pSystem.Simulate(Time.unscaledDeltaTime,true,false);
}
I have tried this code with a script that is attached to my explosion particle system prefab, which is instantiated at the player's position when you die.
Thanks!
UPDATE:
Turns out I had tried using particleSystem.Simulate(Time.unscaledDeltaTime, true, false);, but I was calling it in FixedUpdate() rather than Update().
However, the Asteroid Base post below posted by Garfty is really interesting and is probably worth doing in the long run!
One way you could do it is by using Time.unscaledDeltaTime
Another way you could approach something like this is by creating your own time manager, but it requires some discipline to stick to. The people at Asteroid Base wrote a nice article on something like this here.
I hope this helps!

How to cache TextureAtlas results?

When using a TextureAtlas to create a Sprite with the createSprite method, the LibGDX documentation says: This method uses string comparison to find the region and constructs a new sprite, so the result should be cached rather than calling this method multiple times.
How do I cache these results? Is it just a variable I create to store the created sprite? If so then how do I create different copies of the same sprite?
Each time you use the createSprite method, a new Sprite gets created. Usually you'd have one sprite per enemy for example. Let's say that you have a class Frog which is one of your enemies. It should look like this (pseudo-code):
public class Frog {
private Sprite sprite;
public Frog(TextureAtlas atlas) {
sprite = atlas.createSprite("frog");
}
public void update(float deltaTime) {
// update the sprite position
}
public void render(Batch batch) {
sprite.draw(batch);
}
}
Now each Frog would have its own Sprite. This is necessary, since all frogs can be in different places. The position will be configured via the Sprite. You will create the sprite just once in the constructor and all of those sprites share the same TextureRegion of the same TextureAtlas, which will result in a good performance, since there won't be many texture switches on the graphics card, when you render your frogs.

LibGDX - How to make a touchable image?

so I'm developing a game for android in LibGDX and I've stumbled upon a problem: I have a scene with an image in it and I want to be able to click/touch the image and make stuff happen after doing so.
I've been trying to google a solution for the past day but I keep on missing something vital. Here's my code:
public class ScreenSplash implements Screen {
private Texture textureGlobe = new Texture(Gdx.files.internal("graphics/splash.png"));
private Image imageGlobe = new Image((new TextureRegion(textureGlobe)));
public ScreenSplash() {
imageGlobe.addListener(new InputListener() {
public boolean touchDown(InputEvent event, float x, float y, int pointer, int button) {
Gdx.app.log(Game.LOG, "image clicked");
return true;
}
});
stageGame.addActor(imageGlobe);
}
...
}
I've also heard that I'm supposed to put this somewhere:
Gdx.input.setInputProcessor(inputProcessor);
But I don't really know what to do with it.
Your Stage is your InputProcessor so do something like Gdx.input.setInputProcessor(stageGame);. The Stage will route the events to the actors.
Ah, I've found out what the problem was.
I imported java.awt.event.InputEvent instead of com.badlogic.gdx.scenes.scene2d.InputEvent and the touchDown function wasn't properly overriden because of this.

How to draw horizontal line in blackberry

I tried following code for draw a single line horizontal line but it is not working. i am not getting what is the problem.
HorizontalFieldManager horline = new HorizontalFieldManager()
{
protected void paint(Graphics graphics)
{
super.paint(graphics);
graphics.setColor(Color.RED);
graphics.drawLine(5, 21,10, 20);
}
};
There's at least a couple problems here:
Extent
The extent of a field (or manager) is basically the size of that field on screen. This size is normally set by a Field object in its layout() method, or by a Manager object in its sublayout() method. The problem is that your HorizontalFieldManager does not override these methods to set the size (by calling setExtent()), and it doesn't look like you add any fields to the manager. So, I believe your horline manager object simply has a size of {0, 0}. Drawing outside its extent doesn't do anything.
Manager vs Field
Manager classes are containers for fields. In this case, all you have is a line. I would definitely not use a Manager (including HorizontalFieldManager) for this, since you're not putting any fields into it, and there is overhead to adding Manager objects. Use a lighter-weight Field, or maybe even modify the paint() or paintBackground() method on whatever class contains this code ... you don't show us that, so I can't say for sure.
If you want to represent the line with a Field, then this will work:
Field line = new Field() {
protected void layout(int width, int height) {
setExtent(20, 21);
}
protected void paint(Graphics g) {
int oldColor = g.getColor();
g.setColor(Color.RED);
g.drawLine(5, 21,10, 20);
g.setColor(oldColor);
}
};
add(line);
Note that I am setting the extent to width=20, height=21, because those are the maximum coordinates you pass to drawLine(). Also, because your y values are 20 and 21, this isn't actually a truly horizontal line.
add()
This might have simply been left out of the code you show to keep the question short, but whether you use a Manager or a Field, you do need to remember to call add() for your field/manager object. Objects created, but not added to a screen, will never show. In your case, the setExtent() problem would also have caused this problem.
Update:
As Dinesh shows in his answer, you could also solve the problem by using SeparatorField. However, I believe that only gives you purely horizontal/vertical lines. Because of the coordinates in your code, I wasn't sure if you needed the ability to draw lines of any orientation ... if you do, then overriding paint() is necessary. If not, use SeparatorField ... but hopefully, you learned something from this answer, too :).
Use this
HorizontalFieldManager horline = new HorizontalFieldManager()
{
protected void paint(Graphics graphics)
{
super.paint(graphics);
graphics.setColor(Color.RED);
}
};
horline.add(new SeparatorField(SeparatorField.LINE_HORIZONTAL|SeparatorField.VISUAL_STATE_FOCUS));

Resources