- Выберите загрузчик игры
- Fabric
Пр юг, простенький KillEffect для ексоса ( лень было делать чтото с рендером сделал просто из фееров крестик,доработать и +- норм, первые темы тут, жду del )
Видео ->
Видео ->
Пожалуйста, авторизуйтесь для просмотра ссылки.
GPT KillEffect:
package ru.levin.modules.render;
import net.minecraft.entity.Entity;
import net.minecraft.entity.LivingEntity;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.particle.ParticleTypes;
import net.minecraft.sound.SoundCategory;
import net.minecraft.sound.SoundEvents;
import net.minecraft.util.math.Vec3d;
import ru.levin.events.Event;
import ru.levin.events.impl.EventUpdate;
import ru.levin.modules.Function;
import ru.levin.modules.FunctionAnnotation;
import ru.levin.modules.Type;
import ru.levin.modules.setting.BooleanSetting;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
@FunctionAnnotation(name = "KillEffect", keywords = "Death, Effect", type = Type.Render, desc = "Эффект креста при смерти")
public class KillEffect extends Function {
private final BooleanSetting mobs = new BooleanSetting("Мобы", false);
private final Map<String, DeathData> deaths = new ConcurrentHashMap<>();
private final Map<String, Long> processedDeaths = new ConcurrentHashMap<>();
public KillEffect() {
addSettings(mobs);
}
@Override
public void onEnable() {
System.out.println("§a[KillEffect] Модуль включен!");
}
@Override
public void onDisable() {
deaths.clear();
processedDeaths.clear();
}
@Override
public void onEvent(Event event) {
if (mc.world == null || mc.player == null) return;
if (event instanceof EventUpdate) {
for (Entity entity : mc.world.getEntities()) {
if (!(entity instanceof LivingEntity living)) continue;
if (entity == mc.player) continue;
float health = living.getHealth();
String entityKey = entity.getUuid().toString();
if (health <= 0) {
if (!processedDeaths.containsKey(entityKey)) {
boolean isPlayer = entity instanceof PlayerEntity;
boolean shouldAdd = mobs.get() || isPlayer;
if (shouldAdd) {
addDeathEffect(entity);
processedDeaths.put(entityKey, System.currentTimeMillis());
}
}
} else {
processedDeaths.remove(entityKey);
}
}
deaths.entrySet().removeIf(entry -> System.currentTimeMillis() - entry.getValue().getTime() > 3000);
processedDeaths.entrySet().removeIf(entry -> System.currentTimeMillis() - entry.getValue() > 5000);
renderEffects();
}
}
private void renderEffects() {
if (deaths.isEmpty()) return;
long currentTime = System.currentTimeMillis();
for (DeathData data : deaths.values()) {
float progress = Math.min(1f, (currentTime - data.getTime()) / 3000f);
Vec3d pos = data.getPos();
drawCross(pos, progress);
}
}
private void drawCross(Vec3d pos, float progress) {
double centerX = pos.x;
double centerY = pos.y + 1.5;
double centerZ = pos.z;
// Получаем направление от креста к игроку (камера)
double cameraX = mc.player.getX();
double cameraZ = mc.player.getZ();
double dx = centerX - cameraX;
double dz = centerZ - cameraZ;
double angleToPlayer = Math.atan2(dz, dx);
double armLength = 0.7;
float brightness = 1f - progress * 0.6f;
// РАСПАД НА ЧАСТИЦЫ (когда progress > 0.85)
if (progress > 0.85f) {
float decayProgress = (progress - 0.85f) / 0.15f;
int particleCount = (int) (200 * decayProgress);
for (int i = 0; i < particleCount; i++) {
// Случайное направление разлета
double angle = Math.random() * Math.PI * 2;
double pitch = Math.random() * Math.PI * 2;
double radius = 1.0 * decayProgress;
// Позиция разлета (от центра креста)
double x = centerX + Math.cos(angle) * Math.cos(pitch) * radius;
double y = centerY + Math.sin(pitch) * radius;
double z = centerZ + Math.sin(angle) * Math.cos(pitch) * radius;
// Скорость разлета
double vx = (x - centerX) * 0.2;
double vy = (y - centerY) * 0.2 + 0.05;
double vz = (z - centerZ) * 0.2;
// Разные типы частиц для красивого распада
if (Math.random() < 0.6) {
mc.world.addParticle(ParticleTypes.END_ROD, x, y, z, vx, vy, vz);
} else {
mc.world.addParticle(ParticleTypes.GLOW, x, y, z, vx, vy, vz);
}
}
return;
}
// Нормальный рендер креста (оба луча повернуты к игроку)
float flicker = 0.8f + (float) (Math.sin(System.currentTimeMillis() / 120.0) * 0.2f) * brightness;
int particleCount = (int) (35 * brightness);
// ВЕРТИКАЛЬНАЯ ПАЛКА (теперь тоже поворачивается к игроку)
for (int i = 0; i <= particleCount; i++) {
double t = (double) i / particleCount;
double offset = -armLength + t * armLength * 2;
// Поворачиваем вертикальную палку вверх-вниз, но она должна оставаться вертикальной?
// Нет, для 2D билборда нужно повернуть оба луча к камере
// Вертикальная палка в 2D билборде - это линия вверх-вниз в плоскости камеры
// Для этого используем два направления: вверх (0,1,0) и в сторону камеры
// Вектор "вверх" в мировой системе координат
double upX = 0;
double upY = 1;
double upZ = 0;
// Вектор "вправо" (перпендикулярно направлению к камере)
double rightX = Math.cos(angleToPlayer);
double rightZ = Math.sin(angleToPlayer);
double rightY = 0;
// Нормализуем
double len = Math.sqrt(rightX * rightX + rightZ * rightZ);
rightX /= len;
rightZ /= len;
// Вертикальная палка: смещение по вектору UP
double x = centerX + upX * offset;
double y = centerY + upY * offset;
double z = centerZ + upZ * offset;
mc.world.addParticle(ParticleTypes.END_ROD, x, y, z, 0, 0, 0);
if (brightness > 0.5f && Math.random() < 0.2f) {
mc.world.addParticle(ParticleTypes.GLOW,
x + (Math.random() - 0.5) * 0.08,
y + (Math.random() - 0.5) * 0.08,
z + (Math.random() - 0.5) * 0.08,
0, 0, 0);
}
}
// ГОРИЗОНТАЛЬНАЯ ПАЛКА (поворачивается к игроку)
for (int i = 0; i <= particleCount; i++) {
double t = (double) i / particleCount;
double offset = -armLength + t * armLength * 2;
// Вектор "вправо" (перпендикулярно направлению к камере)
double rightX = Math.cos(angleToPlayer);
double rightZ = Math.sin(angleToPlayer);
double rightY = 0;
// Нормализуем
double len = Math.sqrt(rightX * rightX + rightZ * rightZ);
rightX /= len;
rightZ /= len;
// Горизонтальная палка: смещение по вектору RIGHT
double x = centerX + rightX * offset;
double y = centerY;
double z = centerZ + rightZ * offset;
mc.world.addParticle(ParticleTypes.END_ROD, x, y, z, 0, 0, 0);
if (brightness > 0.5f && Math.random() < 0.2f) {
mc.world.addParticle(ParticleTypes.GLOW,
x + (Math.random() - 0.5) * 0.08,
y + (Math.random() - 0.5) * 0.08,
z + (Math.random() - 0.5) * 0.08,
0, 0, 0);
}
}
// Свечение на пересечении
for (int i = 0; i < 12; i++) {
mc.world.addParticle(ParticleTypes.GLOW,
centerX + (Math.random() - 0.5) * 0.25,
centerY + (Math.random() - 0.5) * 0.25,
centerZ + (Math.random() - 0.5) * 0.25,
0, 0, 0);
}
// Парящие частицы вокруг креста (вращаются)
if (brightness > 0.6f) {
for (int i = 0; i < 10; i++) {
double angle = Math.toRadians(i * 36 + System.currentTimeMillis() / 12.0);
double radius = 0.55;
double x = centerX + Math.cos(angle) * radius;
double z = centerZ + Math.sin(angle) * radius;
double y = centerY + Math.sin(angle * 2) * 0.2;
mc.world.addParticle(ParticleTypes.ELECTRIC_SPARK, x, y, z, 0, 0.01, 0);
}
}
// Искры на концах палок (только в начале)
if (progress < 0.35f) {
double endYTop = centerY + armLength;
double endYBottom = centerY - armLength;
double endXRight = centerX + Math.cos(angleToPlayer) * armLength;
double endZRight = centerZ + Math.sin(angleToPlayer) * armLength;
double endXLeft = centerX - Math.cos(angleToPlayer) * armLength;
double endZLeft = centerZ - Math.sin(angleToPlayer) * armLength;
for (int i = 0; i < 6; i++) {
mc.world.addParticle(ParticleTypes.ELECTRIC_SPARK, endXLeft, centerY, endZLeft, (Math.random() - 0.5) * 0.08, (Math.random() - 0.5) * 0.08, (Math.random() - 0.5) * 0.08);
mc.world.addParticle(ParticleTypes.ELECTRIC_SPARK, endXRight, centerY, endZRight, (Math.random() - 0.5) * 0.08, (Math.random() - 0.5) * 0.08, (Math.random() - 0.5) * 0.08);
mc.world.addParticle(ParticleTypes.ELECTRIC_SPARK, centerX, endYTop, centerZ, (Math.random() - 0.5) * 0.08, 0.08, (Math.random() - 0.5) * 0.08);
mc.world.addParticle(ParticleTypes.ELECTRIC_SPARK, centerX, endYBottom, centerZ, (Math.random() - 0.5) * 0.08, -0.08, (Math.random() - 0.5) * 0.08);
}
}
}
public void addDeathEffect(Entity entity) {
System.out.println("§e[KillEffect] Смерть: " + entity.getName().getString());
mc.world.playSound(mc.player, entity.getBlockPos(),
SoundEvents.ENTITY_PLAYER_DEATH,
SoundCategory.PLAYERS,
1.0f, 1.0f);
mc.world.playSound(mc.player, entity.getBlockPos(),
SoundEvents.BLOCK_BEACON_ACTIVATE,
SoundCategory.PLAYERS,
0.8f, 1.2f);
deaths.put(entity.getUuid().toString(), new DeathData(System.currentTimeMillis(), entity.getPos()));
}
private static class DeathData {
private final long time;
private final Vec3d pos;
public DeathData(long time, Vec3d pos) {
this.time = time;
this.pos = pos;
}
public long getTime() { return time; }
public Vec3d getPos() { return pos; }
}
}