Separate turn rate for each axis, smooth turning with specifable turn speed
This commit is contained in:
parent
be97560f01
commit
25a312b56f
@ -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)
|
||||
)
|
||||
)
|
||||
))
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user