589 words
3 minutes
[Minecraft] Raycast 구현
또 정말 오랜만에 돌아옵니다. 요즘 Mojo로 작은 프로젝트하고 있어서 좀 뜸하긴 한데요. 일단 오늘은 간단하게 raycasting을 구현해보려고 합니다.
먼저 Event를 만들어주고, 그 이후에 발생 처리를 해보겠습니다.
이번 구현은 고정된 곳에서 플레이어가 지나가는지 체크를 하는 로직을 좀 구현하고, 딱히 할 대상이 없으니 현재 같은 월드에 있는 모든 엔티티에 대해서 다 처리를 해서 확인을 해보겠습니다.
public class RaycastEvent extends Event {
private static final HandlerList handlers = new HandlerList();
private final Player player;
private final Entity entity;
private final Location sourceLocation;
private final Location targetLocation;
public RaycastEvent(Player player, Entity entity, Location sourceLocation, Location targetLocation){
this.player = player;
this.entity = entity;
this.sourceLocation = sourceLocation;
this.targetLocation = targetLocation;
}
public Player getPlayer() {
return player;
}
public Entity getEntity() {
return entity;
}
public Location getSourceLocation() {
return sourceLocation;
}
public Location getTargetLocation() {
return targetLocation;
}
@Override
public HandlerList getHandlers() {
return handlers;
}
public static HandlerList getHandlerList(){
return handlers;
}
}
뭐 여기까지는 너무 그냥 당연하게 작성한 것이라 넘어가구요!
public class RaycatManager {
public RaycatManager(){
register();
}
public void register(){
ProtocolManager manager = ProtocolLibrary.getProtocolManager();
manager.addPacketListener(new PacketAdapter(BlogPlugin.plugin,
ListenerPriority.HIGH,
PacketType.Play.Client.POSITION,
PacketType.Play.Client.POSITION_LOOK
) {
@Override
public void onPacketReceiving(PacketEvent event) {
Player player = event.getPlayer();
PacketContainer container = event.getPacket();
double x = container.getDoubles().read(0);
double y = container.getDoubles().read(1);
double z = container.getDoubles().read(2);
tryRaycast(new Location(player.getWorld(), x, y, z), player);
}
});
}
private void tryRaycast(Location playerLoc, Player player){
if(playerLoc.getWorld() == null) return;
Bukkit.getScheduler().runTask(BlogPlugin.plugin, ()->
{
playerLoc.getWorld().getEntities().stream().filter(entity ->
entity instanceof LivingEntity && !entity.equals(player)
).forEach(entity -> raycast(playerLoc, player, entity));
});
}
private void raycast(Location loc, Player player, Entity entity){
if(loc.getWorld() == null) return;
Location entityLoc = entity.getLocation();
double distance = loc.distanceSquared(entityLoc);
if(distance <= 5*5){
Vector dir = entityLoc.getDirection();
Vector toPlayer = loc.toVector().subtract(entityLoc.toVector()).normalize();
double angle = Math.toDegrees(dir.angle(toPlayer));
if(angle <= 45f){
if(isBlocked(entityLoc, loc)) return;
Bukkit.getScheduler().runTask(BlogPlugin.plugin, ()-> {
RaycastEvent event = new RaycastEvent(player, entity, entityLoc, player.getLocation());
Bukkit.getPluginManager().callEvent(event);
});
}
}
}
private boolean isBlocked(Location from, Location to){
from.setY(from.getY() + 1.5f);
return from.getWorld().rayTraceBlocks(from, to.toVector().subtract(from.toVector()), to.distance(from)) != null;
}
}
여기까지 이렇게 raycast를 구현할 수 있어요. 이것도 게임을 공부하다 보면 당연히 보이는 것들이 있을 거구요!from.setY(from.getY() + 1.5f);
여기는 좀 중요한데… 이게 발가락이 from이 되면서 시야가 너무 낮아지면서 블록이 있는 것으로 알더라구요?! 그래서 이렇게 올려준겁니다.
구현 영상
이제 곧 리버싱, 암호학, 인공지능 이렇게 올라가긴 할겁니당
다들 너무 수고하셨습니다.
[Minecraft] Raycast 구현
https://compy07.github.io/Blog/posts/development/bukkit/packet/raycasting/