velocidad una tipos que pistolas humano fuego entra cuerpo como balas bala armas alcanza 9mm java math bukkit

java - tipos - velocidad de una bala 9mm



Tratando de disparar una bala en un mundo 3D. Experimentando un desplazamiento impar en x y z (2)

Bien, entonces estoy usando Bukkit API (Minecraft), que no debería ser un gran problema en esto, ya que se usa mínimamente. Así que una ubicación contiene mundo, x, y, z, guiñada y tono. Esto puede ser útil, pero lo dudo.

Mi problema es que voy a disparar usando la clase de Disparo (a continuación), y parece que hay una diferencia de + -5 en cualquiera de las dos cuando está aproximadamente a 3 cuadras de distancia, y el HitBox se crea como una instancia a aproximadamente 5 cuadras de distancia (este podría ser el problema (Mover / rotar métodos)). He intentado resolver esto en papel, y he usado medio bloc de notas para hacerlo, pero todavía no puedo encontrar una solución. Lo que necesito es alguien que entienda bien la trigonometría y Java, para que puedan ayudar.

Otra información que puede ser de utilidad:

  • + z es 0 grados de orientación, -x es 90 grados, -z es 180 y + x es 270.
  • Las variables parecen ser incorrectas esporádicamente, y bajo ciertas circunstancias funcionan correctamente y constituyen un éxito.
  • El parámetro Ubicación (desde) en el constructor de Disparo es de la ubicación del jugador en el mundo, por lo tanto, desde no es (0, 0, 0).
  • ShotData no debería afectar ningún valor, ya que la velocidad del viento y la dirección del viento en mi caso son 0 (si hay un problema con las matemáticas relacionadas con esto, no dude en avisarme, jaja)
  • El tono parece estar bien, aunque + y es -90, y -y es 90 (¿verdad raro?)

Entonces mi pregunta es ... ¿Dónde está el problema y cómo lo soluciono? Lamento que sea una pregunta tan general y que sea muy común, pero este es uno de esos momentos en que es realmente necesario. Intenté eliminar todo el código innecesario, pero puede eliminar más si es necesario. Además, si desea ver cualquier otra cosa a la que se pueda hacer referencia aquí, puedo obtenerla para usted.

Shot.java:

private final Location from; private ShotData data; public Shot(Location from, ShotData data) { this.from = from; this.data = data; } // TODO - Checking for obstacles public List<Hit> shoot(List<HitBox> hitBoxes) { List<Hit> hits = new ArrayList<Hit>(); for (HitBox hitBox : hitBoxes) { hitBox.update(); float fromYaw = from.getYaw() % 360; float fromPitch = from.getPitch() % 360; // making sure the center location is within range if (hitBox.getCenter().distanceSquared(from) > Math.pow(data.getDistanceToTravel(), 2)) { continue; } /* TODO Only allow hits on parts of the rectangle that are within range, * not just the whole thing if the center is within range. */ // accounting for wind speed/direction float windCompassDirection = data.getWindCompassDirection(from.getWorld()); float windSpeed = data.getWindSpeedMPH(from.getWorld()); fromYaw += (windCompassDirection > fromYaw ? 1 : windCompassDirection < fromYaw ? -1 : 0) * windSpeed; fromYaw %= 360; int[] orderClockwise = new int[] {0, 1, 4, 3}; Location thisSideCorner = hitBox.getCorner(0); Location oppositeSideCorner = hitBox.getCorner(0); for (int i = 0; i < orderClockwise.length; i++) { int num = orderClockwise[i]; Location corner = hitBox.getCorner(num); Location clockwise = hitBox.getCorner(orderClockwise[(i + 1) % 3]); if ((Math.atan2(from.getZ() - corner.getZ(), from.getX() - corner.getX()) * 180 / Math.PI) > 0 && corner.distanceSquared(from) < clockwise.distanceSquared(from)) { thisSideCorner = corner; int exitCornerClockwiseAmount = (Math.atan2(from.getZ() - clockwise.getZ(), from.getX() - clockwise.getX()) * 180 / Math.PI) < 0 ? 2 : 3; oppositeSideCorner = hitBox.getCorner((i + exitCornerClockwiseAmount) % 3); } } Location entrance = getProjectileLocation(thisSideCorner, data, hitBox, fromYaw, fromPitch); double distance = entrance.distance(from); double deltaX = data.getDeltaX(distance, fromYaw); double deltaY = data.getDeltaY(distance, fromPitch); double deltaZ = data.getDeltaZ(distance, fromYaw); entrance.add(deltaX, deltaY, deltaZ); Location exit = getProjectileLocation(oppositeSideCorner, data, hitBox, deltaX, deltaY, deltaZ, fromYaw, fromPitch); // hit detection and reaction boolean hitX = entrance.getX() <= hitBox.getHighestX() && entrance.getX() >= hitBox.getLowestX(); boolean hitY = entrance.getY() <= hitBox.getHighestY() && entrance.getY() >= hitBox.getLowestY(); boolean hitZ = entrance.getZ() <= hitBox.getHighestZ() && entrance.getZ() >= hitBox.getLowestZ(); if (hitX && hitY && hitZ) { hits.add(new Hit(from, entrance, exit, hitBox, data)); } } return hits; } private Location getProjectileLocation(Location thisSideCorner, ShotData data, HitBox hitBox, float fromYaw, float fromPitch) { return getProjectileLocation(thisSideCorner, data, hitBox, 0, 0, 0, fromYaw, fromPitch); } private Location getProjectileLocation(Location thisSideCorner, ShotData data, HitBox hitBox, double addX, double addY, double addZ, float fromYaw, float fromPitch) { double deltaFromToSideCornerX = thisSideCorner.getX() - from.getX(); double deltaFromToSideCornerY = thisSideCorner.getY() - from.getY(); double deltaFromToSideCornerZ = thisSideCorner.getZ() - from.getZ(); double xzDistFromSideCorner = Math.sqrt(Math.pow(deltaFromToSideCornerX, 2) + Math.pow(deltaFromToSideCornerZ, 2)); double yawToSideCorner = Math.atan2(deltaFromToSideCornerX, deltaFromToSideCornerZ) * 180 / Math.PI;// flipped x and z from normal double theta1 = yawToSideCorner - fromYaw; double theta2 = yawToSideCorner - theta1; double outerAngle = 180 - yawToSideCorner - 90;// previously theta1 double outerAngleInShotCone = outerAngle + 90 + hitBox.getYawRotation(); double lastAngleInShotCone = 180 - theta1 - outerAngleInShotCone; double xzDistanceFromHit = (xzDistFromSideCorner * Math.sin(Math.toRadians(outerAngleInShotCone))) / Math.sin(Math.toRadians(lastAngleInShotCone)); double deltaX = xzDistanceFromHit * Math.sin(Math.toRadians(theta2));// leaves out sin 90 because its just equal to 1... double deltaZ = xzDistanceFromHit * Math.sin(Math.toRadians(90 - theta2));// leaves out sin 90 because its just equal to 1... double xyzDistFromSideCorner = Math.sqrt(Math.pow(xzDistFromSideCorner, 2) + Math.pow(deltaFromToSideCornerY, 2)); double theta3 = Math.atan2(Math.abs(deltaFromToSideCornerY), xzDistFromSideCorner) * 180 / Math.PI; double theta4 = Math.abs(fromPitch) - theta3; double theta5 = 90 + theta3; double theta6 = 180 - theta4 - theta5; double hitDistance = (xyzDistFromSideCorner * Math.sin(Math.toRadians(theta5))) / Math.sin(Math.toRadians(theta6)); double deltaY = hitDistance * Math.sin(Math.toRadians(Math.abs(fromPitch)));// leaves out sin 90 because its just equal to 1... if (deltaFromToSideCornerX < 0 && deltaX > 0) { deltaX *= -1; } if (fromPitch > 0 && deltaY > 0) {// pitch in minecraft is backwards, normally it would be fromPitch < 0 deltaY *= -1; } if (deltaFromToSideCornerZ < 0 && deltaZ > 0) { deltaZ *= -1; } Location hit = from.clone().add(deltaX + addX, deltaY + addY, deltaZ + addZ); hit.setYaw(fromYaw); hit.setPitch(fromPitch); return hit; }

HitBox.java:

private float yawRotation; private double x, y, z; private double[][] additions; private Location center; private Location[] corners = new Location[8]; private List<DataZone> dataZones = new ArrayList<DataZone>(); private UUID uuid = UUID.randomUUID(); //@formatter:off /* * O = origin * X = x-axis * Y = y-axis * Z = z-axis * C = center * * --------------------- * / /| * / / | * Y-------------------- | * | 90 | | 0 yaw * | ^ | | / * | | | | * | | | | / * | HEIGHT C | | * | | | |/ * | | | Z * | v | / * | <---WIDTH---> |/<---LENGTH * O-------------------X - - - - - - - - - -270 yaw */ /** * An invisible box in the world that can be hit with a shot. * Additionally, {@link DataZone} instances can be added to this, * allowing for different damage and thickness on an area of the box. * * @param center The center of the hit box * @param length The length (z axis) of the hit box * @param width The width (x axis) of the hit box * @param height The height (y axis) of the hit box * @param yawRotation The rotation around the center of the origin (or any other point) */ public HitBox(Location center, double length, double width, double height, float yawRotation) { corners[0] = center.clone().add(-1 * width / 2, -1 * height / 2, -1 * length / 2); this.center = center; this.x = width; this.y = height; this.z = length; rotate(yawRotation); } //@formatter:on public Location[] getCorners() { return corners; } public Location getCorner(int corner) { return corners[corner]; } public Location getOrigin() { return corners[0]; } public void update() {}; public boolean isZoneOpen(DataZone zone) { for (DataZone placed : dataZones) { boolean Xs = overlap_1D(placed.xFrom, placed.xTo, zone.xFrom, zone.xTo); boolean Ys = overlap_1D(placed.yFrom, placed.yTo, zone.yFrom, zone.yTo); boolean Zs = overlap_1D(placed.zFrom, placed.zTo, zone.zFrom, zone.zTo); if (Xs && Ys && Zs) { return true; } } return false; } public void rotate(float degrees) { Location origin = corners[0]; this.yawRotation = (yawRotation + degrees) % 360; additions = new double[][] { {0, 0, 0}, {x, 0, 0}, {0, y, 0}, {0, 0, z}, {x, 0, z}, {x, y, 0}, {x, y, z}, {0, y, z}}; for (int i = 0; i < 8; i++) { double[] addition = additions[i]; double xPrime = center.getX() + (center.getX() - (origin.getX() + addition[0])) * Math.cos(Math.toRadians(yawRotation)) - (center.getZ() - (origin.getZ() + addition[2])) * Math.sin(Math.toRadians(yawRotation)); double zPrime = center.getZ() + (center.getX() - (origin.getX() + addition[0])) * Math.sin(Math.toRadians(yawRotation)) + (center.getZ() - (origin.getZ() + addition[2])) * Math.cos(Math.toRadians(yawRotation)); corners[i] = new Location(center.getWorld(), xPrime, origin.getY() + addition[1], zPrime, yawRotation, 0); } } public void move(Location center) { double deltaX = center.getX() - this.center.getX(); double deltaY = center.getY() - this.center.getY(); double deltaZ = center.getZ() - this.center.getZ(); for (int i = 0; i < 8; i++) { corners[i].add(deltaX, deltaY, deltaZ); } this.center = center; } protected void setY(double y) { int[] toChange = new int[] {2, 5, 6, 7}; for (int i : toChange) { corners[i].setY(corners[0].getY() + y); } this.y = y; } public double getHighestX() { double highestX = Double.MIN_VALUE; for (Location location : corners) { if (location.getX() > highestX) { highestX = location.getX(); } } return highestX; } public double getHighestY() { return corners[0].getY() + y; } public double getHighestZ() { double highestZ = Double.MIN_VALUE; for (Location location : corners) { if (location.getZ() > highestZ) { highestZ = location.getZ(); } } return highestZ; } public double getLowestX() { double lowestX = Double.MAX_VALUE; for (Location location : corners) { if (location.getX() < lowestX) { lowestX = location.getX(); } } return lowestX; } public double getLowestY() { return corners[0].getY(); } public double getLowestZ() { double lowestZ = Double.MAX_VALUE; for (Location location : corners) { if (location.getZ() < lowestZ) { lowestZ = location.getZ(); } } return lowestZ; } public float getYawRotation() { return yawRotation; }


Sé que esto es extremadamente tarde (casi 5 años en realidad), pero desarrollé una solución unas semanas después de esta pregunta. Después de volver a visitar , decidí brindar mi solución a cualquiera que lo encuentre útil.

El problema con el muro de código masivo encontrado en la pregunta es que se están calculando muchos valores y cada cálculo pierde precisión, lo que resulta en cierto grado de variación (como dije, +/- 5 bloques).

La fuente de la solución se puede encontrar aquí: https://github.com/JamesNorris/MCShot

Para calcular la intersección (que se encuentra en util / Plane3D.java):

public Vector getIntersect(LineSegment3D segment) { Vector u = segment.getEnd().subtract(segment.getStart()); Vector w = segment.getStart().subtract(point); double D = normal.dot(u); double N = -normal.dot(w); if (Math.abs(D) < .00000001) { /* if N == 0, segment lies in the plane */ return null; } double sI = N / D; if (sI < 0 || sI > 1) { return null; } return segment.getStart().add(u.multiply(sI)); }

Como puede ver, esto requiere mucho menos cálculos y, como resultado, proporciona una precisión mucho mayor. Esta función obtiene la intersección de un plano 3D. Un plano 3D se construye utilizando los valores:

point - algún punto encontrado dentro del plano
normal - el vector normal del plano

¡Espero que alguien encuentre útil esta solución, o al menos pueda usarla como una lección de precisión computacional!


Tal vez considere dibujar una línea siguiendo el mismo vector por el que viaja su bala, esto proporcionará un indicador visual de lo que está sucediendo, pasar los mismos cálculos y etc.

Como otros han mencionado también incluyen muchas impresiones de depuración. Con suerte, una vez que tenga una indicación visual, podrá ver cuándo y dónde se están produciendo los cálculos del problema.

También debe tratar de usar un tipo de datos estándar para cálculos, una flotación o un doble, NO ambos, ya que esto puede causar algunos redondeos extraños y problemas de cálculo.