// handleParticleInfluence -- Handles interaction between entities and particles public void handleParticleInfluence(string levelUid, Particle particle) { for (int i = 0; i < particle.entityInfluenceCount; i++) { int entityId = particle.entitiesToInfluence[i]; ParticleInfluenceComponent particleInfluenceComponent = _entityManager.getComponent(levelUid, entityId, ComponentType.ParticleInfluence) as ParticleInfluenceComponent; particleInfluenceComponent.particleCount++; if (particleInfluenceComponent.type == ParticleInfluenceType.Physical) { // Physical body influences -- body-to-particle influences are usually already handled by resolveCollisions() PhysicsComponent physicsComponent = _entityManager.getComponent(levelUid, entityId, ComponentType.Physics) as PhysicsComponent; physicsComponent.body.ApplyLinearImpulse(particle.oldPosition - particle.position, particle.oldPosition); } else if (particleInfluenceComponent.type == ParticleInfluenceType.Dynamite) { // Dynamite influence PhysicsComponent physicsComponent = _entityManager.getComponent(levelUid, entityId, ComponentType.Physics) as PhysicsComponent; Vector2 bodyVelocity = physicsComponent.body.LinearVelocity; physicsComponent.body.LinearVelocity = bodyVelocity * 0.98f + particle.velocity; physicsComponent.body.AngularVelocity = physicsComponent.body.AngularVelocity * 0.98f; particle.velocity += bodyVelocity * 0.003f; } else if (particleInfluenceComponent.type == ParticleInfluenceType.Character) { // Character influence PhysicsComponent physicsComponent = _entityManager.getComponent(levelUid, entityId, ComponentType.Physics) as PhysicsComponent; Vector2 bodyVelocity = physicsComponent.body.LinearVelocity; physicsComponent.body.LinearVelocity = bodyVelocity * 0.95f + particle.velocity; particle.velocity += bodyVelocity * 0.003f; } else if (particleInfluenceComponent.type == ParticleInfluenceType.Explosion) { ExplosionComponent explosionComponent = _entityManager.getComponent(levelUid, entityId, ComponentType.Explosion) as ExplosionComponent; Vector2 relative; float distanceSq; Vector2 force; relative = particle.position - explosionComponent.position; distanceSq = relative.LengthSquared(); relative.Normalize(); force = relative * (explosionComponent.strength / Math.Max(distanceSq, 1f)); particle.velocity += force * 0.0055f; } } }
public void update(GameTime gameTime) { if (!_paused || _singleStep) { LevelSystem levelSystem = _systemManager.getSystem(SystemType.Level) as LevelSystem; if (levelSystem.finalized) { string levelUid = LevelSystem.currentLevelUid; List <int> characterEntities = _entityManager.getEntitiesPosessing(levelUid, ComponentType.CharacterMovement); for (int i = 0; i < characterEntities.Count; i++) { PhysicsComponent physicsComponent = _entityManager.getComponent(levelUid, characterEntities[i], ComponentType.Physics) as PhysicsComponent; ParticleInfluenceComponent particleInfluenceComponent = _entityManager.getComponent(levelUid, characterEntities[i], ComponentType.ParticleInfluence) as ParticleInfluenceComponent; CharacterMovementComponent characterMovementComponent = _entityManager.getComponent(levelUid, characterEntities[i], ComponentType.CharacterMovement) as CharacterMovementComponent; RopeGrabComponent ropeGrabComponent = _entityManager.getComponent(levelUid, characterEntities[i], ComponentType.RopeGrab) as RopeGrabComponent; Body body = physicsComponent.body; float currentSpeed = body.LinearVelocity.Length(); // Handle fluid properties characterMovementComponent.inFluid = particleInfluenceComponent.particleCount > 2; // Handle rope grabs if (characterMovementComponent.allowRopeGrab && characterMovementComponent.doRopeGrab) { attemptRopeGrab(levelUid, characterEntities[i], characterMovementComponent, physicsComponent, ropeGrabComponent); } // Calculate movement vector if (characterMovementComponent.collisionNormals.Count > 0) { characterMovementComponent.movementUnitVector = Vector2.Zero; for (int j = 0; j < characterMovementComponent.collisionNormals.Count; j++) { characterMovementComponent.movementUnitVector += characterMovementComponent.collisionNormals[j] / characterMovementComponent.collisionNormals.Count; } characterMovementComponent.movementUnitVector = new Vector2(characterMovementComponent.movementUnitVector.Y, -characterMovementComponent.movementUnitVector.X); characterMovementComponent.movementUnitVector.Normalize(); } else { characterMovementComponent.movementUnitVector = new Vector2(-1, 0); } // On surface movement if (characterMovementComponent.onSurface) { if (characterMovementComponent.walkLeft || characterMovementComponent.walkRight) { // Adjust friction if (body.LinearVelocity.X < -0.1f && characterMovementComponent.walkRight) { body.Friction = 10f; } else if (body.LinearVelocity.X > 0.1f && characterMovementComponent.walkLeft) { body.Friction = 10f; } else { body.Friction = 0.1f; } // Walk if (currentSpeed <= characterMovementComponent.speedLimit) { Vector2 impulse = characterMovementComponent.movementUnitVector * _baseWalkMultiplier; if (characterMovementComponent.walkRight) { impulse *= -1; } if (characterMovementComponent.inFluid) { impulse *= 0.5f; } body.ApplyLinearImpulse(ref impulse); } } else { body.Friction = 10f; } } else // In-air movement { if (characterMovementComponent.walkLeft || characterMovementComponent.walkRight) { if (ropeGrabComponent != null) { // Swing Vector2 impulse = characterMovementComponent.movementUnitVector * _baseSwingMultiplier; if (characterMovementComponent.walkRight) { impulse *= -1; } body.ApplyLinearImpulse(ref impulse); } else { // Air walk if ((body.LinearVelocity.X < 0 && characterMovementComponent.walkRight) || (body.LinearVelocity.X > 0 && characterMovementComponent.walkLeft) || (body.LinearVelocity.X > -characterMovementComponent.speedLimit && characterMovementComponent.walkLeft) || (body.LinearVelocity.X < characterMovementComponent.speedLimit && characterMovementComponent.walkRight)) { Vector2 impulse = characterMovementComponent.movementUnitVector * _baseAirWalkMultiplier; if (characterMovementComponent.walkRight) { impulse *= -1; } body.ApplyLinearImpulse(ref impulse); } } } } // Jump if (characterMovementComponent.attemptJump) { // While holding rope if (ropeGrabComponent != null) { RopeComponent ropeComponent = _entityManager.getComponent(levelUid, ropeGrabComponent.ropeEntityId, ComponentType.Rope) as RopeComponent; Vector2 impulse = new Vector2(0, -1.2f); if (ropeComponent != null && ropeComponent.destroyAfterRelease) { ropeComponent.timeToLive = 100; } _ropeSystem.releaseRope(ropeGrabComponent, physicsComponent.body); _entityManager.removeComponent(levelUid, characterEntities[i], ropeGrabComponent); ropeGrabComponent = null; body.ApplyLinearImpulse(ref impulse); } if (characterMovementComponent.onSurface) { Vector2 impulse = new Vector2(0, -2f); float adjustment = 0f; // Try to limit the impulse based on the current y velocity. // This is done to prevent jumps from contributing too much to the y velocity when // the player is already moving upwards too fast (which results in a super-jump). adjustment = (body.LinearVelocity.Y / 6f); impulse.Y -= adjustment; body.ApplyLinearImpulse(ref impulse); characterMovementComponent.attemptJump = false; } } // Swim if (characterMovementComponent.inFluid && characterMovementComponent.swimUp) { Vector2 impulse = new Vector2(0, -0.25f); body.ApplyLinearImpulse(ref impulse); } // Climbing if (ropeGrabComponent != null) { float climbSpeed = characterMovementComponent.climbAmount * CLIMB_SPEED; if (characterMovementComponent.climbUp) { _ropeSystem.moveAttachedBody(ropeGrabComponent, physicsComponent.body, climbSpeed); } else if (characterMovementComponent.climbDown) { _ropeSystem.moveAttachedBody(ropeGrabComponent, physicsComponent.body, -climbSpeed); } } } } } _singleStep = false; }
// resolveCollisions private void resolveCollision(string levelUid, int index) { Particle particle = liquid[index]; // Resolve collisions between particles and fixtures for (int i = 0; i < particle.numFixturesToTest; i++) { Fixture fixture = particle.fixturesToTest[i]; if (fixture.Shape == null) // fixtures can be destroyed before they're tested { continue; } Vector2 newPosition = particle.position + particle.velocity + _delta[index]; if (fixture.TestPoint(ref newPosition, 0.01f)) { Body body = fixture.Body; int entityId = (int)body.UserData; SkipFluidResolutionComponent skipFluidResolutionComponent = _entityManager.getComponent(levelUid, entityId, ComponentType.SkipFluidResolution) as SkipFluidResolutionComponent; ParticleInfluenceComponent particleInfluenceComponent = _entityManager.getComponent(levelUid, entityId, ComponentType.ParticleInfluence) as ParticleInfluenceComponent; bool influenceEntity = particleInfluenceComponent != null; if (skipFluidResolutionComponent == null) { Vector2 closestPoint = Vector2.Zero; Vector2 normal = Vector2.Zero; Vector2 resolvedPosition = Vector2.Zero; if (fixture.ShapeType == ShapeType.Polygon) { // Polygons PolygonShape shape = fixture.Shape as PolygonShape; Transform collisionXF; body.GetTransform(out collisionXF); for (int v = 0; v < shape.Vertices.Count; v++) { particle.collisionVertices[v] = MathUtils.Multiply(ref collisionXF, shape.Vertices[v]); particle.collisionNormals[v] = MathUtils.Multiply(ref collisionXF.R, shape.Normals[v]); } // Find closest edge float shortestDistance = 9999999f; for (int v = 0; v < shape.Vertices.Count; v++) { float distance = Vector2.Dot(particle.collisionNormals[v], particle.collisionVertices[v] - particle.position); if (distance < shortestDistance) { shortestDistance = distance; closestPoint = particle.collisionNormals[v] * (distance) + particle.position; normal = particle.collisionNormals[v]; } } resolvedPosition = closestPoint + 0.025f * normal; particle.skipMovementUpdate = true; particle.pressure = MAX_PRESSURE; } else if (fixture.ShapeType == ShapeType.Circle) { // Circles CircleShape shape = fixture.Shape as CircleShape; Vector2 center = shape.Position + body.Position; Vector2 difference = particle.position - center; normal = difference; normal.Normalize(); closestPoint = center + difference * (shape.Radius / difference.Length()); resolvedPosition = closestPoint + 0.025f * normal; particle.skipMovementUpdate = true; particle.pressure = MAX_PRESSURE; } // Update particle position and velocity particle.position = resolvedPosition; particle.velocity = (particle.velocity - 1.2f * Vector2.Dot(particle.velocity, normal) * normal) * 0.85f; // Handle fast moving bodies if (body.LinearVelocity.LengthSquared() > 50f) { Vector2 bodyVelocity = body.GetLinearVelocityFromWorldPoint(particle.oldPosition); body.LinearVelocity = body.LinearVelocity * 0.995f; body.AngularVelocity = body.AngularVelocity * 0.95f; particle.velocity += bodyVelocity * 0.005f; } } // Particle influences if (influenceEntity) { if (particleInfluenceComponent.type == ParticleInfluenceType.Rope) { // Handle rope particle-to-body influences here, since trying to find the correct body through the list of rope nodes would be a pain Vector2 bodyVelocity = body.LinearVelocity; body.LinearVelocity = bodyVelocity * 0.98f + particle.velocity * 1.5f; particle.velocity += bodyVelocity * 0.003f; } else { // Add entityId to list of entities being influenced by this particle particle.entitiesToInfluence[particle.entityInfluenceCount] = (int)body.UserData; particle.entityInfluenceCount++; } } } } }