添加子弹数量更改时的颜色和数值更改动画

This commit is contained in:
Light_Quanta 2025-03-20 11:40:36 +08:00
parent c237cca842
commit 1aeb3d65fc
No known key found for this signature in database
GPG key ID: 11A39A1B8C890959
3 changed files with 147 additions and 7 deletions

View file

@ -14,6 +14,7 @@ import com.atsuishio.superbwarfare.tools.GunsTool;
import com.atsuishio.superbwarfare.tools.InventoryTool; import com.atsuishio.superbwarfare.tools.InventoryTool;
import com.atsuishio.superbwarfare.tools.animation.AnimationCurves; import com.atsuishio.superbwarfare.tools.animation.AnimationCurves;
import com.atsuishio.superbwarfare.tools.animation.AnimationTimer; import com.atsuishio.superbwarfare.tools.animation.AnimationTimer;
import com.atsuishio.superbwarfare.tools.animation.DualValueHolder;
import com.mojang.blaze3d.systems.RenderSystem; import com.mojang.blaze3d.systems.RenderSystem;
import com.mojang.blaze3d.vertex.PoseStack; import com.mojang.blaze3d.vertex.PoseStack;
import net.minecraft.ChatFormatting; import net.minecraft.ChatFormatting;
@ -215,11 +216,16 @@ public class AmmoBarOverlay {
.forwardAnimation(AnimationCurves.EASE_OUT_EXPO) .forwardAnimation(AnimationCurves.EASE_OUT_EXPO)
.backwardAnimation(AnimationCurves.EASE_IN_EXPO); .backwardAnimation(AnimationCurves.EASE_IN_EXPO);
private static final DualValueHolder<Integer>[] ammoCountHolders = DualValueHolder.create(AmmoType.values().length, 0);
private static final AnimationTimer[] ammoCountTimers = AnimationTimer.createTimers(AmmoType.values().length, 800, AnimationCurves.EASE_OUT_EXPO);
/** /**
* 在手持弹药或弹药盒时渲染玩家弹药总量信息 * 在手持弹药或弹药盒时渲染玩家弹药总量信息
*/ */
@SubscribeEvent @SubscribeEvent
public static void renderAmmoInfo(RenderGuiEvent.Pre event) { public static void renderAmmoInfo(RenderGuiEvent.Pre event) {
boolean startRenderingAmmoInfo = false;
Player player = Minecraft.getInstance().player; Player player = Minecraft.getInstance().player;
if (player == null || player.isSpectator()) return; if (player == null || player.isSpectator()) return;
@ -227,6 +233,8 @@ public class AmmoBarOverlay {
var currentTime = System.currentTimeMillis(); var currentTime = System.currentTimeMillis();
ItemStack stack = player.getMainHandItem(); ItemStack stack = player.getMainHandItem();
if ((stack.getItem() instanceof AmmoSupplierItem || stack.getItem() == ModItems.AMMO_BOX.get()) && !(player.getVehicle() instanceof ArmedVehicleEntity vehicle && vehicle.banHand(player))) { if ((stack.getItem() instanceof AmmoSupplierItem || stack.getItem() == ModItems.AMMO_BOX.get()) && !(player.getVehicle() instanceof ArmedVehicleEntity vehicle && vehicle.banHand(player))) {
// 刚拿出弹药物品时视为开始弹药信息渲染
startRenderingAmmoInfo = ammoInfoTimer.getProgress(currentTime) == 0;
ammoInfoTimer.forward(currentTime); ammoInfoTimer.forward(currentTime);
} else { } else {
ammoInfoTimer.backward(currentTime); ammoInfoTimer.backward(currentTime);
@ -245,25 +253,68 @@ public class AmmoBarOverlay {
int w = event.getWindow().getGuiScaledWidth(); int w = event.getWindow().getGuiScaledWidth();
int h = event.getWindow().getGuiScaledHeight(); int h = event.getWindow().getGuiScaledHeight();
// 总体透明度设置
RenderSystem.setShaderColor(1, 1, 1, Mth.lerp(ammoInfoTimer.getProgress(currentTime), 0, 1)); RenderSystem.setShaderColor(1, 1, 1, Mth.lerp(ammoInfoTimer.getProgress(currentTime), 0, 1));
var font = Minecraft.getInstance().font; var font = Minecraft.getInstance().font;
for (var type : AmmoType.values()) { for (var type : AmmoType.values()) {
var ammoCountStr = Integer.toString(type.get(cap)); var index = type.ordinal();
var ammoCount = type.get(cap);
var holder = ammoCountHolders[index];
var timer = ammoCountTimers[index];
// 首次开始渲染弹药信息时记录弹药数量便于后续播放动画
if (startRenderingAmmoInfo) {
holder.reset(ammoCount);
timer.endForward(currentTime);
}
int isAdd = ammoCount == holder.oldValue() ? 0 : (ammoCount > holder.oldValue() ? 1 : -1);
// 弹药数量变化时开始播放弹药数量更改动画
if (holder.newValue() != ammoCount) {
// 更新初始和当前弹药数量播放由 初始弹药数量 -> 当前弹药数量 的动画
holder.update(ammoCount);
// 开始播放弹药数量更改动画
timer.beginForward(currentTime);
}
var progress = timer.getProgress(currentTime);
var ammoCountStr = Integer.toString(
Math.round(Mth.lerp(progress, holder.oldValue(), ammoCount))
);
// 弹药增加时颜色由绿变白否则由红变白
var fontColor = switch (isAdd) {
case 1 -> Mth.color(
Mth.lerp(progress, 0, 1),
1,
Mth.lerp(progress, 0, 1)
);
case -1 -> Mth.color(
1,
Mth.lerp(progress, 0, 1),
Mth.lerp(progress, 0, 1)
);
default -> 0xFFFFFF;
};
// 弹药数量
event.getGuiGraphics().drawString( event.getGuiGraphics().drawString(
Minecraft.getInstance().font, Minecraft.getInstance().font,
ammoCountStr, ammoCountStr,
w + xOffset + (30 - font.width(ammoCountStr)), w + xOffset + (30 - font.width(ammoCountStr)),
h + yOffset, h + yOffset,
0xFFFFFF, fontColor,
true true
); );
// 弹药类型
event.getGuiGraphics().drawString( event.getGuiGraphics().drawString(
Minecraft.getInstance().font, Minecraft.getInstance().font,
Component.translatable(type.translatableKey).getString(), Component.translatable(type.translatableKey).getString(),
w + xOffset + 35, w + xOffset + 35,
h + yOffset, h + yOffset,
0xFFFFFF, fontColor,
true true
); );

View file

@ -4,6 +4,9 @@ import net.minecraft.util.Mth;
import java.util.function.Function; import java.util.function.Function;
/**
* 可以更改计时方向的动画计时器
*/
public class AnimationTimer { public class AnimationTimer {
private final long duration; private final long duration;
private long startTime; private long startTime;
@ -23,15 +26,25 @@ public class AnimationTimer {
this.duration = duration; this.duration = duration;
} }
/**
* 设置正向和反向计时时采用的动画曲线
*/
public AnimationTimer animation(Function<Double, Double> animationCurve) { public AnimationTimer animation(Function<Double, Double> animationCurve) {
return this.forwardAnimation(animationCurve).backwardAnimation(animationCurve); return this.forwardAnimation(animationCurve).backwardAnimation(animationCurve);
} }
/**
* 设置反向计时时采用的动画曲线
*/
public AnimationTimer forwardAnimation(Function<Double, Double> animationCurve) { public AnimationTimer forwardAnimation(Function<Double, Double> animationCurve) {
this.forwardAnimationCurve = animationCurve; this.forwardAnimationCurve = animationCurve;
return this; return this;
} }
/**
* 设置反向计时时采用的动画曲线
*/
public AnimationTimer backwardAnimation(Function<Double, Double> animationCurve) { public AnimationTimer backwardAnimation(Function<Double, Double> animationCurve) {
this.backwardAnimationCurve = animationCurve; this.backwardAnimationCurve = animationCurve;
return this; return this;
@ -72,12 +85,14 @@ public class AnimationTimer {
var currentTime = System.currentTimeMillis(); var currentTime = System.currentTimeMillis();
for (int i = 0; i < size; i++) { for (int i = 0; i < size; i++) {
timers[i] = new AnimationTimer(duration).forwardAnimation(forwardAnimationCurve).backwardAnimation(backwardAnimationCurve); timers[i] = new AnimationTimer(duration).forwardAnimation(forwardAnimationCurve).backwardAnimation(backwardAnimationCurve);
timers[i].end(); timers[i].endBackward(currentTime);
timers[i].backward(currentTime);
} }
return timers; return timers;
} }
/**
* 当前计时方向是否为正向
*/
public boolean isForward() { public boolean isForward() {
return !reversed; return !reversed;
} }
@ -130,7 +145,7 @@ public class AnimationTimer {
} }
/** /**
* 正向开始计时 * 将计时方向更改为正向
*/ */
public void forward(long currentTime) { public void forward(long currentTime) {
if (!initialized) { if (!initialized) {
@ -143,7 +158,24 @@ public class AnimationTimer {
} }
/** /**
* 反向开始计时 * 开始正向计时
*/
public void beginForward(long currentTime) {
begin();
forward(currentTime);
}
/**
* 结束正向计时
*/
public void endForward(long currentTime) {
end();
forward(currentTime);
}
/**
* 将计时方向更改为反向
*/ */
public void backward(long currentTime) { public void backward(long currentTime) {
if (!initialized) { if (!initialized) {
@ -155,4 +187,20 @@ public class AnimationTimer {
reversed = true; reversed = true;
} }
/**
* 开始反向计时
*/
public void beginBackward(long currentTime) {
begin();
backward(currentTime);
}
/**
* 结束反向计时
*/
public void endBackward(long currentTime) {
end();
backward(currentTime);
}
} }

View file

@ -0,0 +1,41 @@
package com.atsuishio.superbwarfare.tools.animation;
public class DualValueHolder<T> {
private T oldValue;
private T newValue;
public static <T> DualValueHolder<T>[] create(int size, T defaultValue) {
// 傻逼Java
@SuppressWarnings("unchecked")
DualValueHolder<T>[] holders = new DualValueHolder[size];
for (int i = 0; i < size; i++) {
holders[i] = new DualValueHolder<>();
holders[i].reset(defaultValue);
}
return holders;
}
public void update(T value) {
this.oldValue = this.newValue;
this.newValue = value;
}
public void reset(T value) {
this.oldValue = value;
this.newValue = value;
}
public T oldValue() {
return this.oldValue;
}
public T newValue() {
return this.newValue;
}
public boolean changed() {
return this.oldValue.equals(this.newValue);
}
}