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)),
|
HeightRangePlacement.of(StandardDeviationHeightProvider(VerticalAnchor.absolute(120), 15.0)),
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
wormLength = UniformInt.of(40, 200),
|
length = UniformInt.of(40, 200),
|
||||||
wormTurnChance = BooleanProvider.BiasedLinear(0.6f, 4),
|
turnRateXY = WormPlacement.normalDistributedTurnRate(10f),
|
||||||
wormTurnXY = WormPlacement.normalDistributedTurnRate(60f),
|
turnRateXZ = WormPlacement.normalDistributedTurnRate(60f),
|
||||||
wormTurnXZ = 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.util.valueproviders.UniformFloat
|
||||||
import net.minecraft.world.level.levelgen.placement.PlacementModifierType
|
import net.minecraft.world.level.levelgen.placement.PlacementModifierType
|
||||||
import ru.dbotthepony.mc.otm.core.math.Vector
|
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.plus
|
||||||
import ru.dbotthepony.mc.otm.core.math.toBlockPos
|
import ru.dbotthepony.mc.otm.core.math.toBlockPos
|
||||||
import ru.dbotthepony.mc.otm.core.nextDouble
|
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 ru.dbotthepony.mc.otm.registry.data.MPlacementModifiers
|
||||||
import java.util.stream.Stream
|
import java.util.stream.Stream
|
||||||
import kotlin.math.PI
|
import kotlin.math.PI
|
||||||
|
import kotlin.math.absoluteValue
|
||||||
import kotlin.math.cos
|
import kotlin.math.cos
|
||||||
|
import kotlin.math.sign
|
||||||
import kotlin.math.sin
|
import kotlin.math.sin
|
||||||
|
|
||||||
class WormPlacement(
|
class WormPlacement(
|
||||||
parameters: Parameters,
|
parameters: Parameters,
|
||||||
val wormLength: IntProvider,
|
val length: IntProvider,
|
||||||
val wormTurnChance: BooleanProvider,
|
val turnChanceXZ: BooleanProvider,
|
||||||
val wormTurnXZ: FloatProvider,
|
val turnChanceXY: BooleanProvider,
|
||||||
val wormTurnXY: FloatProvider,
|
val turnSpeedXZ: FloatProvider,
|
||||||
|
val turnSpeedXY: FloatProvider,
|
||||||
|
val turnRateXZ: FloatProvider,
|
||||||
|
val turnRateXY: FloatProvider,
|
||||||
|
val initialAngleXY: FloatProvider = DEFAULT_INITIAL_ANGLE_XY,
|
||||||
) : AbstractEnormousPlacement(parameters) {
|
) : AbstractEnormousPlacement(parameters) {
|
||||||
override fun getPositions(center: BlockPos, random: RandomSource): Stream<BlockPos> {
|
override fun getPositions(center: BlockPos, random: RandomSource): Stream<BlockPos> {
|
||||||
var position = Vector.ZERO
|
var position = Vector.ZERO
|
||||||
val maxDistance = wormLength.sample(random)
|
val maxDistance = length.sample(random)
|
||||||
// determine initial worm facing angle
|
// determine initial worm facing angle
|
||||||
var xzRotation = random.nextDouble(-PI / 2.0, PI / 2.0)
|
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 xzSin = sin(xzRotation)
|
||||||
var xzCos = cos(xzRotation)
|
var xzCos = cos(xzRotation)
|
||||||
@ -43,18 +55,48 @@ class WormPlacement(
|
|||||||
var prevPos = position.toBlockPos()
|
var prevPos = position.toBlockPos()
|
||||||
positions.add(prevPos)
|
positions.add(prevPos)
|
||||||
|
|
||||||
val wormTurnChance = wormTurnChance.instance()
|
val turnChanceXZ = turnChanceXZ.instance()
|
||||||
|
val turnChanceXY = turnChanceXY.instance()
|
||||||
|
|
||||||
for (traveledDistance in 0 .. maxDistance) {
|
for (traveledDistance in 0 .. maxDistance) {
|
||||||
// wormy turn
|
// wormy turn
|
||||||
if (wormTurnChance.sample(random)) {
|
if (turnChanceXZ.sample(random)) {
|
||||||
// wormy angle
|
// wormy angle
|
||||||
// TODO: smooth turning, instead of snapping to new angle make it gradually face new angle
|
xzTargetRotation += turnRateXZ.sample(random)
|
||||||
xzRotation += wormTurnXZ.sample(random)
|
xzTargetRotation = normalizeAngle(xzTargetRotation)
|
||||||
xyRotation += wormTurnXY.sample(random)
|
}
|
||||||
|
|
||||||
|
// 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)
|
xzSin = sin(xzRotation)
|
||||||
xzCos = cos(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)
|
xySin = sin(xyRotation)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -87,11 +129,21 @@ class WormPlacement(
|
|||||||
if (sum != value) {
|
if (sum != value) {
|
||||||
return sum
|
return sum
|
||||||
} else {
|
} 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 {
|
fun uniformTurnRate(degrees: Float): FloatProvider {
|
||||||
return uniformTurnRateRadians(degrees * DEGREES_TO_RADIANS)
|
return uniformTurnRateRadians(degrees * DEGREES_TO_RADIANS)
|
||||||
}
|
}
|
||||||
@ -117,10 +169,14 @@ class WormPlacement(
|
|||||||
val CODEC: MapCodec<WormPlacement> = RecordCodecBuilder.mapCodec {
|
val CODEC: MapCodec<WormPlacement> = RecordCodecBuilder.mapCodec {
|
||||||
it.group(
|
it.group(
|
||||||
PARAMETERS_CODEC.forGetter(WormPlacement::parameters),
|
PARAMETERS_CODEC.forGetter(WormPlacement::parameters),
|
||||||
IntProvider.CODEC.fieldOf("length").forGetter(WormPlacement::wormLength),
|
IntProvider.CODEC.fieldOf("length").forGetter(WormPlacement::length),
|
||||||
BooleanProvider.CODEC.fieldOf("turn_chance").forGetter(WormPlacement::wormTurnChance),
|
BooleanProvider.CODEC.fieldOf("turn_chance_xz").forGetter(WormPlacement::turnChanceXZ),
|
||||||
FloatProvider.CODEC.fieldOf("turn_xz").forGetter(WormPlacement::wormTurnXZ),
|
BooleanProvider.CODEC.fieldOf("turn_chance_xy").forGetter(WormPlacement::turnChanceXY),
|
||||||
FloatProvider.CODEC.fieldOf("turn_xy").forGetter(WormPlacement::wormTurnXY),
|
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)
|
).apply(it, ::WormPlacement)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user