public FParticleSystem (int maxParticleCount) { _maxParticleCount = maxParticleCount; _particles = new FParticle[_maxParticleCount]; _availableParticles = new FParticle[_maxParticleCount]; _availableParticleCount = _maxParticleCount; _unavailableParticleIndex = _maxParticleCount-1; for(int p = 0; p<_maxParticleCount; p++) { _particles[p] = _availableParticles[p] = new FParticle(); } ListenForUpdate(HandleUpdate); }
public FParticleSystem(int maxParticleCount) { _maxParticleCount = maxParticleCount; _particles = new FParticle[_maxParticleCount]; _availableParticles = new FParticle[_maxParticleCount]; _availableParticleCount = _maxParticleCount; _unavailableParticleIndex = _maxParticleCount - 1; for (int p = 0; p < _maxParticleCount; p++) { _particles[p] = _availableParticles[p] = new FParticle(); } ListenForUpdate(HandleUpdate); }
private void VerletIntegrate(float InSubstepTime, Vector3 Gravity) { int NumParticles = NumSegments + 1; float SubstepTimeSqr = InSubstepTime * InSubstepTime; for (int ParticleIndex = 0; ParticleIndex < NumParticles; ParticleIndex++) { FParticle particle = Particles[ParticleIndex]; if (particle.bFree) { Vector3 Velocity = particle.position - particle.OldPosition; Vector3 NewPosition = particle.position + Velocity + (SubstepTimeSqr * Gravity); particle.OldPosition = particle.position; particle.position = NewPosition; } } }
private void HandleUpdate() { float deltaTime = Time.deltaTime; for (int p = 0; p < _maxParticleCount; p++) { FParticle particle = _particles[p]; if (particle.timeRemaining <= 0) { //this particle isn't alive, go to the next one } else if (particle.timeRemaining <= deltaTime) //is it going to end during this update? { //add it back to the available particles _availableParticles[_availableParticleCount] = particle; _availableParticleCount++; particle.timeRemaining = 0; //don't bother updating it because it won't be rendered anyway } else //do the update! { particle.timeRemaining -= deltaTime; particle.color.r += particle.redDeltaPerSecond * deltaTime; particle.color.g += particle.greenDeltaPerSecond * deltaTime; particle.color.b += particle.blueDeltaPerSecond * deltaTime; particle.color.a += particle.alphaDeltaPerSecond * deltaTime; particle.scale += particle.scaleDeltaPerSecond * deltaTime; particle.speedX += accelX * deltaTime; particle.speedY += accelY * deltaTime; particle.x += particle.speedX * deltaTime; particle.y += particle.speedY * deltaTime; } } _isMeshDirty = true; //needs redraw! }
void Start() { int NumParticles = NumSegments + 1; Particles.Clear(); // Use linerenderer as visual cable representation _lineRenderer = transform.GetComponent <LineRenderer>(); if (_lineRenderer == null) { _lineRenderer = gameObject.AddComponent <LineRenderer>(); } _lineRenderer.SetVertexCount(NumSegments); _lineRenderer.SetWidth(.2f, .2f); _lineRenderer.SetColors(Color.cyan, Color.blue); Vector3 Delta = CableEnd.position - CableStart.position; for (int ParticleIndex = 0; ParticleIndex < NumParticles; ParticleIndex++) { Transform newTransform = Instantiate(PrefabParticle, Vector3.zero, Quaternion.identity) as Transform; float Alpha = (float)ParticleIndex / (float)NumParticles; Vector3 InitializePosition = CableStart.transform.position + (Alpha * Delta); FParticle particle = newTransform.GetComponent <FParticle>(); particle.position = InitializePosition; particle.OldPosition = InitializePosition; particle.transform.parent = this.transform; particle.name = "Particle_0" + ParticleIndex.ToString(); Particles.Add(particle); if (ParticleIndex == 0 || ParticleIndex == (NumParticles - 1)) { particle.bFree = false; } else { particle.bFree = true; } } }
private void SolveConstraints() { float SegmentLength = CableLength / (float)NumSegments; // For each iteration for (int IterationIndex = 0; IterationIndex < SolverIterations; IterationIndex++) { // For each segment for (int SegmentIndex = 0; SegmentIndex < NumSegments; SegmentIndex++) { FParticle ParticleA = Particles[SegmentIndex]; FParticle ParticleB = Particles[SegmentIndex + 1]; // Solve for this pair of particles SolveDistanceConstraint(ParticleA, ParticleB, SegmentLength); // Update render position _lineRenderer.SetPosition(SegmentIndex, ParticleA.position); } } }
void Update() { // Update start+end positions first FParticle StartParticle = Particles[0]; StartParticle.position = StartParticle.OldPosition = CableStart.position; FParticle EndParticle = Particles[NumSegments]; EndParticle.position = EndParticle.OldPosition = CableEnd.position; Vector3 Gravity = Physics.gravity; float UseSubstep = Mathf.Max(SubstepTime, 0.005f); TimeRemainder += Time.deltaTime; while (TimeRemainder > UseSubstep) { PreformSubstep(UseSubstep, Gravity); TimeRemainder -= UseSubstep; } }
void SolveDistanceConstraint(FParticle ParticleA, FParticle ParticleB, float DesiredDistance) { // Find current difference between particles Vector3 Delta = ParticleB.position - ParticleA.position; float CurrentDistance = Delta.magnitude; float ErrorFactor = (CurrentDistance - DesiredDistance) / CurrentDistance; // Only move free particles to satisfy constraints if (ParticleA.bFree && ParticleB.bFree) { ParticleA.position += ErrorFactor * 0.5f * Delta; ParticleB.position -= ErrorFactor * 0.5f * Delta; } else if (ParticleA.bFree) { ParticleA.position += ErrorFactor * Delta; } else if (ParticleB.bFree) { ParticleB.position -= ErrorFactor * Delta; } }
override public void PopulateRenderLayer() { if (_isOnStage && _firstFacetIndex != -1) { _isMeshDirty = false; Vector3[] vertices = _renderLayer.vertices; Vector2[] uvs = _renderLayer.uvs; Color[] colors = _renderLayer.colors; float a = _concatenatedMatrix.a; float b = _concatenatedMatrix.b; float c = _concatenatedMatrix.c; float d = _concatenatedMatrix.d; float tx = _concatenatedMatrix.tx; float ty = _concatenatedMatrix.ty; // Vector2 unitVector = _concatenatedMatrix.GetTransformedUnitVector(); // float ux = unitVector.x; // float uy = unitVector.y; int vertexIndex0 = _firstFacetIndex * 4; int vertexIndex1 = vertexIndex0 + 1; int vertexIndex2 = vertexIndex0 + 2; int vertexIndex3 = vertexIndex0 + 3; float px; float py; float ps; for (int p = 0; p < _maxParticleCount; p++) { FParticle particle = _particles[p]; if (particle.timeRemaining > 0) { ps = particle.scale; px = particle.x + particle.resultTopLeftX * ps; py = particle.y + particle.resultTopLeftY * ps; vertices[vertexIndex0] = new Vector3(px * a + py * c + tx, px * b + py * d + ty, _meshZ); px = particle.x + particle.resultTopRightX * ps; py = particle.y + particle.resultTopRightY * ps; vertices[vertexIndex1] = new Vector3(px * a + py * c + tx, px * b + py * d + ty, _meshZ); px = particle.x + particle.resultBottomRightX * ps; py = particle.y + particle.resultBottomRightY * ps; vertices[vertexIndex2] = new Vector3(px * a + py * c + tx, px * b + py * d + ty, _meshZ); px = particle.x + particle.resultBottomLeftX * ps; py = particle.y + particle.resultBottomLeftY * ps; vertices[vertexIndex3] = new Vector3(px * a + py * c + tx, px * b + py * d + ty, _meshZ); uvs[vertexIndex0] = particle.uvTopLeft; uvs[vertexIndex1] = particle.uvTopRight; uvs[vertexIndex2] = particle.uvBottomRight; uvs[vertexIndex3] = particle.uvBottomLeft; colors[vertexIndex0] = particle.color; colors[vertexIndex1] = particle.color; colors[vertexIndex2] = particle.color; colors[vertexIndex3] = particle.color; } else //it's dead so put zeroes in { vertices[vertexIndex0].Set(50, 0, 1000000); vertices[vertexIndex1].Set(50, 0, 1000000); vertices[vertexIndex2].Set(50, 0, 1000000); vertices[vertexIndex3].Set(50, 0, 1000000); } vertexIndex0 += 4; vertexIndex1 += 4; vertexIndex2 += 4; vertexIndex3 += 4; } _renderLayer.HandleVertsChange(); } }
private void HandleUpdate() { float deltaTime = Time.deltaTime; for (int p = 0; p < _maxParticleCount; p++) { FParticle particle = _particles[p]; if (particle.timeRemaining <= 0) { //this particle isn't alive, go to the next one } else if (particle.timeRemaining <= deltaTime) //is it going to end during this update? { //add it back to the available particles _availableParticles[_availableParticleCount] = particle; _availableParticleCount++; particle.timeRemaining = 0; //don't bother updating it because it won't be rendered anyway } else //do the update! { particle.timeRemaining -= deltaTime; particle.color.r += particle.redDeltaPerSecond * deltaTime; particle.color.g += particle.greenDeltaPerSecond * deltaTime; particle.color.b += particle.blueDeltaPerSecond * deltaTime; particle.color.a += particle.alphaDeltaPerSecond * deltaTime; particle.scale += particle.scaleDeltaPerSecond * deltaTime; particle.speedX += accelX * deltaTime; particle.speedY += accelY * deltaTime; particle.x += particle.speedX * deltaTime; particle.y += particle.speedY * deltaTime; if (particle.doesNeedRotationUpdates) { particle.rotation += particle.rotationDeltaPerSecond * (double)deltaTime; float sin = (float)Math.Sin(particle.rotation); float cos = (float)Math.Cos(particle.rotation); float ix, iy; ix = particle.initialTopLeft.x; iy = particle.initialTopLeft.y; particle.resultTopLeftX = ix * cos - iy * sin; particle.resultTopLeftY = ix * sin + iy * cos; ix = particle.initialTopRight.x; iy = particle.initialTopRight.y; particle.resultTopRightX = ix * cos - iy * sin; particle.resultTopRightY = ix * sin + iy * cos; ix = particle.initialBottomRight.x; iy = particle.initialBottomRight.y; particle.resultBottomRightX = ix * cos - iy * sin; particle.resultBottomRightY = ix * sin + iy * cos; ix = particle.initialBottomLeft.x; iy = particle.initialBottomLeft.y; particle.resultBottomLeftX = ix * cos - iy * sin; particle.resultBottomLeftY = ix * sin + iy * cos; } } } _isMeshDirty = true; //needs redraw! }