Separate turn rate for each axis, smooth turning with specifable turn speed

This commit is contained in:
DBotThePony 2025-03-08 21:59:29 +07:00
parent be97560f01
commit 25a312b56f
Signed by: DBot
GPG Key ID: DCC23B5715498507
2 changed files with 79 additions and 20 deletions

View File

@ -124,10 +124,13 @@ fun registerPlacedFeatures(context: BootstrapContext<PlacedFeature>) {
HeightRangePlacement.of(StandardDeviationHeightProvider(VerticalAnchor.absolute(120), 15.0)),
)
),
wormLength = UniformInt.of(40, 200),
wormTurnChance = BooleanProvider.BiasedLinear(0.6f, 4),
wormTurnXY = WormPlacement.normalDistributedTurnRate(60f),
wormTurnXZ = WormPlacement.normalDistributedTurnRate(60f),
length = UniformInt.of(40, 200),
turnRateXY = WormPlacement.normalDistributedTurnRate(10f),
turnRateXZ = WormPlacement.normalDistributedTurnRate(60f),
turnSpeedXZ = WormPlacement.constantTurnRate(10f),
turnSpeedXY = WormPlacement.constantTurnRate(4f),
turnChanceXY = BooleanProvider.Unbiased(6),
turnChanceXZ = BooleanProvider.BiasedLinear(0.6f, 5)
)
)
))

View File

@ -11,6 +11,8 @@ import net.minecraft.util.valueproviders.IntProvider
import net.minecraft.util.valueproviders.UniformFloat
import net.minecraft.world.level.levelgen.placement.PlacementModifierType
import ru.dbotthepony.mc.otm.core.math.Vector
import ru.dbotthepony.mc.otm.core.math.angleDifference
import ru.dbotthepony.mc.otm.core.math.normalizeAngle
import ru.dbotthepony.mc.otm.core.math.plus
import ru.dbotthepony.mc.otm.core.math.toBlockPos
import ru.dbotthepony.mc.otm.core.nextDouble
@ -18,22 +20,32 @@ import ru.dbotthepony.mc.otm.data.world.BooleanProvider
import ru.dbotthepony.mc.otm.registry.data.MPlacementModifiers
import java.util.stream.Stream
import kotlin.math.PI
import kotlin.math.absoluteValue
import kotlin.math.cos
import kotlin.math.sign
import kotlin.math.sin
class WormPlacement(
parameters: Parameters,
val wormLength: IntProvider,
val wormTurnChance: BooleanProvider,
val wormTurnXZ: FloatProvider,
val wormTurnXY: FloatProvider,
val length: IntProvider,
val turnChanceXZ: BooleanProvider,
val turnChanceXY: BooleanProvider,
val turnSpeedXZ: FloatProvider,
val turnSpeedXY: FloatProvider,
val turnRateXZ: FloatProvider,
val turnRateXY: FloatProvider,
val initialAngleXY: FloatProvider = DEFAULT_INITIAL_ANGLE_XY,
) : AbstractEnormousPlacement(parameters) {
override fun getPositions(center: BlockPos, random: RandomSource): Stream<BlockPos> {
var position = Vector.ZERO
val maxDistance = wormLength.sample(random)
val maxDistance = length.sample(random)
// determine initial worm facing angle
var xzRotation = random.nextDouble(-PI / 2.0, PI / 2.0)
var xyRotation = random.nextDouble(-PI / 16.0, PI / 16.0)
var xyRotation = normalizeAngle(initialAngleXY.sample(random).toDouble())
// determine initial "turn to" angle
var xzTargetRotation = random.nextDouble(-PI / 2.0, PI / 2.0)
var xyTargetRotation = normalizeAngle(initialAngleXY.sample(random).toDouble())
var xzSin = sin(xzRotation)
var xzCos = cos(xzRotation)
@ -43,18 +55,48 @@ class WormPlacement(
var prevPos = position.toBlockPos()
positions.add(prevPos)
val wormTurnChance = wormTurnChance.instance()
val turnChanceXZ = turnChanceXZ.instance()
val turnChanceXY = turnChanceXY.instance()
for (traveledDistance in 0 .. maxDistance) {
// wormy turn
if (wormTurnChance.sample(random)) {
if (turnChanceXZ.sample(random)) {
// wormy angle
// TODO: smooth turning, instead of snapping to new angle make it gradually face new angle
xzRotation += wormTurnXZ.sample(random)
xyRotation += wormTurnXY.sample(random)
xzTargetRotation += turnRateXZ.sample(random)
xzTargetRotation = normalizeAngle(xzTargetRotation)
}
// wormy-o!
if (turnChanceXY.sample(random)) {
// worm?
xyTargetRotation += turnRateXY.sample(random)
xzTargetRotation = normalizeAngle(xzTargetRotation)
}
if (xzTargetRotation != xzRotation) {
val diff = angleDifference(xzTargetRotation, xzRotation)
val abs = diff.absoluteValue
val speed = turnSpeedXZ.sample(random).toDouble()
if (abs <= speed)
xzRotation = xzTargetRotation
else
xzRotation += speed * diff.sign
xzSin = sin(xzRotation)
xzCos = cos(xzRotation)
}
if (xyTargetRotation != xyRotation) {
val diff = angleDifference(xyTargetRotation, xyRotation)
val abs = diff.absoluteValue
val speed = turnSpeedXZ.sample(random).toDouble()
if (abs <= speed)
xyRotation = xyTargetRotation
else
xyRotation += speed * diff.sign
xySin = sin(xyRotation)
}
@ -87,11 +129,21 @@ class WormPlacement(
if (sum != value) {
return sum
} else {
i += 1f
i *= 2f
}
}
}
val DEFAULT_INITIAL_ANGLE_XY: UniformFloat = UniformFloat.of(-PI.toFloat() / 16f, increment(PI.toFloat() / 16f))
fun constantTurnRate(degrees: Float): FloatProvider {
return constantTurnRateRadians(degrees * DEGREES_TO_RADIANS)
}
fun constantTurnRateRadians(rad: Float): FloatProvider {
return ConstantFloat.of(rad)
}
fun uniformTurnRate(degrees: Float): FloatProvider {
return uniformTurnRateRadians(degrees * DEGREES_TO_RADIANS)
}
@ -117,10 +169,14 @@ class WormPlacement(
val CODEC: MapCodec<WormPlacement> = RecordCodecBuilder.mapCodec {
it.group(
PARAMETERS_CODEC.forGetter(WormPlacement::parameters),
IntProvider.CODEC.fieldOf("length").forGetter(WormPlacement::wormLength),
BooleanProvider.CODEC.fieldOf("turn_chance").forGetter(WormPlacement::wormTurnChance),
FloatProvider.CODEC.fieldOf("turn_xz").forGetter(WormPlacement::wormTurnXZ),
FloatProvider.CODEC.fieldOf("turn_xy").forGetter(WormPlacement::wormTurnXY),
IntProvider.CODEC.fieldOf("length").forGetter(WormPlacement::length),
BooleanProvider.CODEC.fieldOf("turn_chance_xz").forGetter(WormPlacement::turnChanceXZ),
BooleanProvider.CODEC.fieldOf("turn_chance_xy").forGetter(WormPlacement::turnChanceXY),
FloatProvider.CODEC.fieldOf("turn_speed_xz").forGetter(WormPlacement::turnSpeedXZ),
FloatProvider.CODEC.fieldOf("turn_speed_xy").forGetter(WormPlacement::turnSpeedXY),
FloatProvider.CODEC.fieldOf("turn_rate_xz").forGetter(WormPlacement::turnRateXZ),
FloatProvider.CODEC.fieldOf("turn_rate_xy").forGetter(WormPlacement::turnRateXY),
FloatProvider.CODEC.optionalFieldOf("initial_angle_xy", DEFAULT_INITIAL_ANGLE_XY).forGetter(WormPlacement::initialAngleXY),
).apply(it, ::WormPlacement)
}
}