200 lines
8.1 KiB
Java
200 lines
8.1 KiB
Java
package com.atsuishio.superbwarfare.client.overlay;
|
|
|
|
import com.atsuishio.superbwarfare.Mod;
|
|
import com.atsuishio.superbwarfare.init.ModCapabilities;
|
|
import com.atsuishio.superbwarfare.component.ModDataComponents;
|
|
import com.atsuishio.superbwarfare.entity.vehicle.base.ArmedVehicleEntity;
|
|
import com.atsuishio.superbwarfare.init.ModItems;
|
|
import com.atsuishio.superbwarfare.item.common.ammo.AmmoSupplierItem;
|
|
import com.atsuishio.superbwarfare.item.common.ammo.box.AmmoBoxInfo;
|
|
import com.atsuishio.superbwarfare.tools.AmmoType;
|
|
import com.atsuishio.superbwarfare.tools.animation.AnimationCurves;
|
|
import com.atsuishio.superbwarfare.tools.animation.AnimationTimer;
|
|
import com.atsuishio.superbwarfare.tools.animation.ValueAnimator;
|
|
import com.mojang.blaze3d.systems.RenderSystem;
|
|
import net.minecraft.client.Minecraft;
|
|
import net.minecraft.network.chat.Component;
|
|
import net.minecraft.util.FastColor;
|
|
import net.minecraft.world.entity.player.Player;
|
|
import net.minecraft.world.item.ItemStack;
|
|
import net.neoforged.api.distmarker.Dist;
|
|
import net.neoforged.bus.api.SubscribeEvent;
|
|
import net.neoforged.fml.common.EventBusSubscriber;
|
|
import net.neoforged.neoforge.client.event.RenderGuiEvent;
|
|
|
|
@EventBusSubscriber(modid = Mod.MODID, value = Dist.CLIENT)
|
|
public class AmmoOverlay {
|
|
|
|
private static final AnimationTimer ammoInfoTimer = new AnimationTimer(500, 2000)
|
|
.forwardAnimation(AnimationCurves.EASE_OUT_EXPO)
|
|
.backwardAnimation(AnimationCurves.EASE_IN_EXPO);
|
|
private static final AnimationTimer ammoBoxTimer = new AnimationTimer(500)
|
|
.forwardAnimation(AnimationCurves.EASE_OUT_EXPO)
|
|
.backwardAnimation(AnimationCurves.EASE_IN_EXPO);
|
|
|
|
private static final ValueAnimator<Integer>[] ammoCountAnimators = ValueAnimator.create(
|
|
AmmoType.values().length, 800, 0
|
|
);
|
|
private static final ValueAnimator<Integer>[] ammoBoxAnimators = ValueAnimator.create(
|
|
AmmoType.values().length, 800, 0
|
|
);
|
|
|
|
|
|
/**
|
|
* 在手持弹药或弹药盒时,渲染玩家弹药总量信息
|
|
*/
|
|
@SubscribeEvent
|
|
public static void renderAmmoInfo(RenderGuiEvent.Pre event) {
|
|
boolean startRenderingAmmoInfo = false;
|
|
Player player = Minecraft.getInstance().player;
|
|
if (player == null || player.isSpectator()) return;
|
|
|
|
boolean isAmmoBox = false;
|
|
|
|
// 动画计算
|
|
var currentTime = System.currentTimeMillis();
|
|
ItemStack stack = player.getMainHandItem();
|
|
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);
|
|
|
|
if (stack.getItem() == ModItems.AMMO_BOX.get()) {
|
|
isAmmoBox = true;
|
|
ammoBoxTimer.forward(currentTime);
|
|
} else {
|
|
ammoBoxTimer.backward(currentTime);
|
|
}
|
|
} else {
|
|
ammoInfoTimer.backward(currentTime);
|
|
ammoBoxTimer.backward(currentTime);
|
|
}
|
|
if (!ammoInfoTimer.isForward() && ammoInfoTimer.finished(currentTime)) return;
|
|
|
|
var poseStack = event.getGuiGraphics().pose();
|
|
poseStack.pushPose();
|
|
|
|
int w = event.getGuiGraphics().guiWidth();
|
|
int h = event.getGuiGraphics().guiHeight();
|
|
|
|
var ammoX = ammoInfoTimer.lerp(w + 120, (float) w / 2 + 40, currentTime);
|
|
final int fontHeight = 15;
|
|
var yOffset = (-h - AmmoType.values().length * fontHeight) / 2f;
|
|
|
|
// 渲染总弹药数量
|
|
var cap = player.getCapability(ModCapabilities.PLAYER_VARIABLE, null);
|
|
if (cap == null) return;
|
|
var font = Minecraft.getInstance().font;
|
|
|
|
for (var type : AmmoType.values()) {
|
|
var index = type.ordinal();
|
|
var ammoCount = type.get(cap);
|
|
var animator = ammoCountAnimators[index];
|
|
|
|
var boxAnimator = ammoBoxAnimators[index];
|
|
var boxAmmoCount = boxAnimator.newValue();
|
|
boolean boxAmmoSelected = false;
|
|
|
|
if (isAmmoBox) {
|
|
var info = stack.get(ModDataComponents.AMMO_BOX_INFO);
|
|
if (info == null) info = new AmmoBoxInfo("All", false);
|
|
|
|
var ammoBoxType = info.type();
|
|
boxAmmoCount = type.get(stack);
|
|
if (ammoBoxType.equals("All") || ammoBoxType.equals(type.name)) {
|
|
boxAnimator.forward(currentTime);
|
|
boxAmmoSelected = true;
|
|
} else {
|
|
boxAnimator.reset(boxAmmoCount);
|
|
}
|
|
}
|
|
|
|
// 首次开始渲染弹药信息时,记录弹药数量,便于后续播放动画
|
|
if (startRenderingAmmoInfo) {
|
|
animator.reset(ammoCount);
|
|
animator.endForward(currentTime);
|
|
if (isAmmoBox) {
|
|
boxAnimator.reset(type.get(stack));
|
|
boxAnimator.endForward(currentTime);
|
|
}
|
|
}
|
|
|
|
int ammoAdd = Integer.compare(ammoCount, animator.oldValue());
|
|
// 弹药数量变化时,更新并开始播放弹药数量更改动画
|
|
animator.compareAndUpdate(ammoCount, () -> {
|
|
// 弹药数量变化时,开始播放弹药数量更改动画
|
|
animator.beginForward(currentTime);
|
|
});
|
|
|
|
var progress = animator.getProgress(currentTime);
|
|
var ammoCountStr = Integer.toString(
|
|
Math.round(animator.lerp(animator.oldValue(), ammoCount, currentTime))
|
|
);
|
|
|
|
// 弹药增加时,颜色由绿变白,否则由红变白
|
|
var fontColor = FastColor.ARGB32.lerp(progress, switch (ammoAdd) {
|
|
case 1 -> 0xFF00FF00;
|
|
case -1 -> 0xFFFF0000;
|
|
default -> 0xFFFFFFFF;
|
|
}, 0xFFFFFFFF);
|
|
|
|
RenderSystem.setShaderColor(1, 1, 1, ammoInfoTimer.lerp(0, 1, currentTime));
|
|
|
|
// 弹药数量
|
|
event.getGuiGraphics().drawString(
|
|
font,
|
|
ammoCountStr,
|
|
ammoX + (30 - font.width(ammoCountStr)),
|
|
h + yOffset,
|
|
fontColor,
|
|
true
|
|
);
|
|
|
|
// 弹药类型
|
|
event.getGuiGraphics().drawString(
|
|
font,
|
|
Component.translatable(type.translatableKey).getString(),
|
|
ammoX + 35,
|
|
h + yOffset,
|
|
fontColor,
|
|
true
|
|
);
|
|
|
|
// 弹药盒信息渲染
|
|
RenderSystem.setShaderColor(1, 1, 1, ammoBoxTimer.lerp(0, 1, currentTime));
|
|
var ammoBoxX = ammoBoxTimer.lerp(-30, (float) w / 2, currentTime);
|
|
|
|
int ammoBoxAdd = Integer.compare(boxAmmoCount, boxAnimator.oldValue());
|
|
boxAnimator.compareAndUpdate(boxAmmoCount, () -> boxAnimator.beginForward(currentTime));
|
|
|
|
// 选中时显示为黄色,否则为白色
|
|
var targetColor = boxAmmoSelected ? 0xFFFFFF00 : 0xFFFFFFFF;
|
|
|
|
var boxFontColor = FastColor.ARGB32.lerp(boxAnimator.getProgress(currentTime),
|
|
switch (ammoBoxAdd) {
|
|
case 1 -> 0xFF00FF00;
|
|
case -1 -> 0xFFFF0000;
|
|
default -> targetColor;
|
|
},
|
|
targetColor
|
|
);
|
|
|
|
// 弹药盒内弹药数量
|
|
event.getGuiGraphics().drawString(
|
|
Minecraft.getInstance().font,
|
|
Integer.toString(
|
|
Math.round(boxAnimator.lerp(boxAnimator.oldValue(), boxAmmoCount, currentTime))
|
|
),
|
|
ammoBoxX - 70,
|
|
h + yOffset,
|
|
boxFontColor,
|
|
true
|
|
);
|
|
|
|
yOffset += fontHeight;
|
|
}
|
|
|
|
RenderSystem.setShaderColor(1, 1, 1, 1);
|
|
poseStack.popPose();
|
|
}
|
|
}
|