Posts: 18
Threads: 1
Joined: Nov 2020
Reputation:
0
23-11-2020, 03:01 PM
(This post was last modified: 23-11-2020, 03:02 PM by JoseCarlos S.)
(23-11-2020, 01:56 PM)josemendez Wrote: Hi there,
If you run this script, it will result in a NullRefException error (visible in the console), and the script will halt execution.
This is because of this line:
"emitter" will always be null because you only require a component of type ObiSolver to be present:
Code: [RequireComponent(typeof(ObiSolver))]
But then you try to retrieve a ObiEmitter component, which is more than likely to be absent. So this call to GetComponent will return null:
Code: emitter = GetComponent<ObiEmitter>();
Easiest fix is to just make the emitter member public, then assign the emitter instance trough the inspector:
Code: using UnityEngine;
using Obi;
[RequireComponent(typeof(ObiSolver))]
public class KillFluidOnContact : MonoBehaviour
{
ObiSolver solver;
public ObiEmitter emitter;
public float targetTime = 2.0f;
void Awake()
{
solver = GetComponent<ObiSolver>();
}
private void Update()
{
targetTime -= Time.deltaTime;
if (targetTime <= 0.0f)
{
timerEnded();
}
}
void timerEnded()
{
if (emitter != null)
emitter.speed = 0;
else Debug.LogWarning("No se ha proporcionado un emisor a este script.");
}
void LateUpdate()
{
if (!isActiveAndEnabled)
return;
// iterate over all particles in the solver, looking for particles
// that have had their diffusion data altered by contact with other particles.
for (int i = 0; i < solver.particleToActor.Length; ++i)
{
// if this particle is part of an actor,
if (solver.particleToActor[i] != null)
{
// if the "user" (aka diffusion) data is not either (1,0,0,0) or (0,0,0,0)
if (solver.userData[i].x < 0.9f && solver.userData[i].x > 0.1f)
{
// take a reference to the emitter that the particle belongs to, and kill it.
var emitter = solver.particleToActor[i].actor as ObiEmitter;
emitter.KillParticle(solver.particleToActor[i].indexInActor);
}
}
}
}
}
This is basics of the basics, tough. You should train your programming skills a bit further .
It keeps spawning, when all particles are destroyed. Doesn´t seem to change emitter speed... Yeah, this is my training!
Posts: 6,348
Threads: 24
Joined: Jun 2017
Reputation:
400
Obi Owner:
23-11-2020, 03:13 PM
(This post was last modified: 23-11-2020, 03:14 PM by josemendez.)
(23-11-2020, 03:01 PM)JoseCarlos S Wrote: It keeps spawning, when all particles are destroyed. Doesn´t seem to change emitter speed...
It does stop after 2 seconds for me :S.
Did you make sure to set the emitter reference by dragging the emitter from the scene into the inspector? If there's no emitter, the script will do nothing and will instead spam a warning to the console.
(23-11-2020, 03:01 PM)JoseCarlos S Wrote: Yeah, this is my training!
Fluid simulation is quite complex, and quite hard to work with for someone that's starting out. All Obi assets in fact are aimed at advanced users, so this is kinda like practicing to get your driver's license on a McLaren F1 instead of a Fiat Punto. Not meant to discourage you, but be prepared for a really steep learning curve!
Posts: 18
Threads: 1
Joined: Nov 2020
Reputation:
0
23-11-2020, 04:32 PM
(This post was last modified: 23-11-2020, 04:47 PM by JoseCarlos S.)
(23-11-2020, 03:13 PM)josemendez Wrote: It does stop after 2 seconds for me :S.
Did you make sure to set the emitter reference by dragging the emitter from the scene into the inspector? If there's no emitter, the script will do nothing and will instead spam a warning to the console.
Fluid simulation is quite complex, and quite hard to work with for someone that's starting out. All Obi assets in fact are aimed at advanced users, so this is kinda like practicing to get your driver's license on a McLaren F1 instead of a Fiat Punto. Not meant to discourage you, but be prepared for a really steep learning curve!
Yep, the correct emitter is asigned, no alerts on console, and still keeps spawning new particles...
Yeah, i know is gonna be hard learning, but afterwards ill drive the Fiat like a pro
Posts: 6,348
Threads: 24
Joined: Jun 2017
Reputation:
400
Obi Owner:
(23-11-2020, 04:32 PM)JoseCarlos S Wrote: Yep, the correct emitter is asigned, no alerts on console, and still keeps spawning new particles...
I just realized that you were using Burst emission mode, which won't stop emitting even if speed is zero. I was testing with Stream mode instead.
Open ObiEmitter.cs, and change line 467 from this:
Code: if (activeParticleCount == 0)
to this:
Code: if (activeParticleCount == 0 && speed > 0)
That will make Burst emission stop when speed is set to zero.
Posts: 18
Threads: 1
Joined: Nov 2020
Reputation:
0
(23-11-2020, 05:09 PM)josemendez Wrote: I just realized that you were using Burst emission mode, which won't stop emitting even if speed is zero. I was testing with Stream mode instead.
Open ObiEmitter.cs, and change line 467 from this:
Code: if (activeParticleCount == 0)
to this:
Code: if (activeParticleCount == 0 && speed > 0)
That will make Burst emission stop when speed is set to zero.
Hi, yes that seemed to fix the issue! With that i have all my interactions between particles solved (unless i decide to change or add to the main mechaninc). But for now my last question is about particle collision with objects/player. Where do i have to put my script? On the object or the fluid? Collision is detected between particles and objects? I found this in an older post in here ;
Code: using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using Obi;
[RequireComponent(typeof(ObiSolver))]
public class CollisionEventHandler : MonoBehaviour {
ObiSolver solver;
public Collider killer;
void Awake(){
solver = GetComponent<Obi.ObiSolver>();
}
void OnEnable () {
solver.OnCollision += Solver_OnCollision;
}
void OnDisable(){
solver.OnCollision -= Solver_OnCollision;
}
void Solver_OnCollision (object sender, Obi.ObiSolver.ObiCollisionEventArgs e)
{
for(int i = 0; i < e.contacts.Length; ++i)
{
if (e.contacts[i].distance < 0.001f)
{
Component collider;
if (ObiCollider.idToCollider.TryGetValue(e.contacts[i].other,out collider)){
if (collider == killer){
ObiSolver.ParticleInActor pa = solver.particleToActor[e.contacts[i].particle];
ObiEmitter emitter = pa.actor as ObiEmitter;
if (emitter != null)
emitter.life[pa.indexInActor] = 0;
}
}
}
}
}
}
I´m looking for a script that works the other way round, that destroys the object instead of the particles. Any help?
Big thanks!
Posts: 6,348
Threads: 24
Joined: Jun 2017
Reputation:
400
Obi Owner:
27-11-2020, 09:04 AM
(This post was last modified: 27-11-2020, 09:06 AM by josemendez.)
Hi Jose Carlos,
Just call GameObject.Destroy() passing the object reported by the contact.
The manual describes how to retrieve the collider involved in a contact:
http://obi.virtualmethodstudio.com/tutor...sions.html
So the code would look like this:
Code: ObiColliderBase collider = ObiColliderWorld.GetInstance().colliderHandles[contact.other].owner;
GameObject.Destroy(collider.gameObject);
The script you posted pretty clearly hints at where to place it :
[RequireComponent(typeof( ObiSolver ))]
Posts: 18
Threads: 1
Joined: Nov 2020
Reputation:
0
(27-11-2020, 09:04 AM)josemendez Wrote: Hi Jose Carlos,
Just call GameObject.Destroy() passing the object reported by the contact.
The manual describes how to retrieve the collider involved in a contact:
http://obi.virtualmethodstudio.com/tutor...sions.html
So the code would look like this:
Code: ObiColliderBase collider = ObiColliderWorld.GetInstance().colliderHandles[contact.other].owner;
GameObject.Destroy(collider.gameObject);
The script you posted pretty clearly hints at where to place it :
[RequireComponent(typeof( ObiSolver ))]
Hi, found this script in the API, but it dosnt seem to read my variables ... Any help?:
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using Obi;
[RequireComponent(typeof(ObiSolver))]
public class Collision2 : MonoBehaviour
{
ObiSolver solver;
public ObiCollider2D collider;
Obi.ObiSolver.ObiCollisionEventArgs collisionEvent;
void Awake()
{
solver = GetComponent<Obi.ObiSolver>();
}
void OnEnable()
{
solver.OnCollision += Solver_OnCollision;
}
void OnDisable()
{
solver.OnCollision -= Solver_OnCollision;
}
void Solver_OnCollision(object sender, Obi.ObiSolver.ObiCollisionEventArgs e)
{
var world = ObiColliderWorld.GetInstance();
foreach (Oni.Contact contact in e.contacts)
{
// this one is an actual collision:
if (contact.distance < 0.01)
{
ObiColliderBase collider = world.colliderHandles[contact.other].owner;
if (collider != null)
{
ObiColliderBase collider = ObiColliderWorld.GetInstance().colliderHandles[contact.other].owner;
GameObject.Destroy(collider.gameObject); // do something with the collider.
}
}
}
}
}
Posts: 6,348
Threads: 24
Joined: Jun 2017
Reputation:
400
Obi Owner:
(27-11-2020, 02:38 PM)JoseCarlos S Wrote: // this one is an actual collision:
if (contact.distance < 0.01)
{
ObiColliderBase collider = world.colliderHandles[contact.other].owner;
if (collider != null)
{
ObiColliderBase collider = ObiColliderWorld.GetInstance().colliderHandles[contact.other].owner;
GameObject.Destroy(collider.gameObject); // do something with the collider.
}
}
This won't compile because you're defining "collider" twice. Fixing it is left as an exercise to the reader (you should really be able to fix simple things as these, but let me know if you struggle too much with it).
Posts: 18
Threads: 1
Joined: Nov 2020
Reputation:
0
(27-11-2020, 02:53 PM)josemendez Wrote: This won't compile because you're defining "collider" twice. Fixing it is left as an exercise to the reader (you should really be able to fix simple things as these, but let me know if you struggle too much with it).
Okay, i did this one, no compilation errors, put the script in the solver. But insted of only killing the player when it touches the fluid, it destroys a lot of blocks of terrain right from the start (wich have the obicollider2d). Why is that?
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using Obi;
[RequireComponent(typeof(ObiSolver))]
public class Collision2 : MonoBehaviour
{
ObiSolver solver;
public ObiCollider2D player;
Obi.ObiSolver.ObiCollisionEventArgs collisionEvent;
void Awake()
{
solver = GetComponent<Obi.ObiSolver>();
}
void OnEnable()
{
solver.OnCollision += Solver_OnCollision;
}
void OnDisable()
{
solver.OnCollision -= Solver_OnCollision;
}
void Solver_OnCollision(object sender, Obi.ObiSolver.ObiCollisionEventArgs e)
{
var world = ObiColliderWorld.GetInstance();
foreach (Oni.Contact contact in e.contacts)
{
// this one is an actual collision:
if (contact.distance < 0.01)
{
if (player != null)
{
ObiColliderBase collider = ObiColliderWorld.GetInstance().colliderHandles[contact.other].owner;
GameObject.Destroy(collider.gameObject); // do something with the collider.
}
}
}
}
}
Posts: 6,348
Threads: 24
Joined: Jun 2017
Reputation:
400
Obi Owner:
27-11-2020, 03:16 PM
(This post was last modified: 27-11-2020, 03:22 PM by josemendez.)
You're not checking if the collider reported by the contact is the player, you're merely checking if the player exists. Since this is probably always true, any collider relatively close to the fluid will be destroyed.
Correct solution:
Code: void Solver_OnCollision(object sender, Obi.ObiSolver.ObiCollisionEventArgs e)
{
var world = ObiColliderWorld.GetInstance();
foreach (Oni.Contact contact in e.contacts)
{
// this one is an actual collision:
if (contact.distance < 0.01)
{
ObiColliderBase collider = world.colliderHandles[contact.other].owner;
if (collider == player)
GameObject.Destroy(collider.gameObject);
}
}
}
|