| 735 | } |
| 736 | |
| 737 | void MovementController::updateForceRegions(float) { |
| 738 | auto geometry = world()->geometry(); |
| 739 | auto pos = position(); |
| 740 | auto body = collisionBody(); |
| 741 | RectF boundBox = body.boundBox(); |
| 742 | |
| 743 | m_appliedForceRegion = false; |
| 744 | auto handleForceRegions = [&](List<PhysicsForceRegion> const& forces) { |
| 745 | for (auto const& force : forces) { |
| 746 | bool categoryCheck = force.call([myCategories = m_parameters.physicsEffectCategories.value()](auto& fr) { |
| 747 | return fr.categoryFilter.check(myCategories); |
| 748 | }); |
| 749 | if (!categoryCheck) |
| 750 | continue; |
| 751 | |
| 752 | bool boundsCheck = force.call([geometry, myBounds = collisionBoundBox()](auto& fr) { |
| 753 | return geometry.rectIntersectsRect(myBounds, fr.boundBox()); |
| 754 | }); |
| 755 | if (!boundsCheck) |
| 756 | continue; |
| 757 | |
| 758 | m_appliedForceRegion = true; |
| 759 | if (auto directionalForceRegion = force.ptr<DirectionalForceRegion>()) { |
| 760 | float forceEffect = geometry.polyOverlapArea(directionalForceRegion->region, body) / body.convexArea(); |
| 761 | if (directionalForceRegion->xTargetVelocity) |
| 762 | approachXVelocity(*directionalForceRegion->xTargetVelocity, directionalForceRegion->controlForce * forceEffect); |
| 763 | if (directionalForceRegion->yTargetVelocity) |
| 764 | approachYVelocity(*directionalForceRegion->yTargetVelocity, directionalForceRegion->controlForce * forceEffect); |
| 765 | |
| 766 | } else if (auto radialForceRegion = force.ptr<RadialForceRegion>()) { |
| 767 | Vec2F direction = geometry.diff(pos, radialForceRegion->center); |
| 768 | float distance = vmag(direction); |
| 769 | if (distance > 0 && distance < radialForceRegion->outerRadius) { |
| 770 | float incidence = min(1.0f - (distance - radialForceRegion->innerRadius) / (radialForceRegion->outerRadius - radialForceRegion->innerRadius), distance / radialForceRegion->innerRadius); |
| 771 | if (radialForceRegion->targetRadialVelocity < 0) |
| 772 | direction = -direction; |
| 773 | approachVelocityAlongAngle(direction.angle(), |
| 774 | abs(radialForceRegion->targetRadialVelocity), |
| 775 | radialForceRegion->controlForce * incidence, |
| 776 | true); |
| 777 | } |
| 778 | } else if (auto gradientForceRegion = force.ptr<GradientForceRegion>()) { |
| 779 | float overlapFactor = geometry.polyOverlapArea(gradientForceRegion->region, body) / body.convexArea(); |
| 780 | |
| 781 | Vec2F gNorm = gradientForceRegion->gradient.direction(); |
| 782 | Vec2F pDiff = geometry.diff(pos, gradientForceRegion->gradient.min()); |
| 783 | float projected = pDiff[0] * gNorm[0] + pDiff[1] * gNorm[1]; |
| 784 | float gradientFactor = 1.0 - clamp(projected / gradientForceRegion->gradient.length(), -1.0f, 1.0f); |
| 785 | |
| 786 | approachVelocityAlongAngle(gradientForceRegion->gradient.angle(), |
| 787 | gradientForceRegion->baseTargetVelocity * overlapFactor * gradientFactor, |
| 788 | gradientForceRegion->baseControlForce * overlapFactor * gradientFactor, |
| 789 | true); |
| 790 | } |
| 791 | } |
| 792 | }; |
| 793 | |
| 794 | for (auto& physicsEntity : world()->query<PhysicsEntity>(boundBox)) { |
nothing calls this directly
no test coverage detected