Rewrote Direction utility class for accuracy

Rewrote Direction utility class to relate directions based on tile instead of unit circle
MapRenderer will not longer update angles of objects that have no target set
This commit is contained in:
Collin Smith 2019-02-23 03:09:31 -08:00
parent edc4166a8d
commit 5d6a140b54
4 changed files with 274 additions and 135 deletions

View File

@ -2,7 +2,11 @@ package gdx.diablo.entity;
import com.badlogic.gdx.math.MathUtils;
import org.apache.commons.lang3.ArrayUtils;
public class Direction {
private Direction() {}
public static final int SOUTH = 0;
public static final int WEST = 1;
public static final int NORTH = 2;
@ -12,172 +16,185 @@ public class Direction {
public static final int UP = 6;
public static final int RIGHT = 7;
/*
static private final int SIN_BITS[] = {3, 4, 5};
static private final int SIN_MASK[] = {~(-1 << SIN_BITS[0]), ~(-1 << SIN_BITS[1]), ~(-1 << SIN_BITS[2])};
static private final int SIN_COUNT[] = {SIN_MASK[0] + 1, SIN_MASK[1] + 1, SIN_MASK[2] + 1};
static private final float radFull = MathUtils.PI2;
static private final float radToIndex[] = {SIN_COUNT[0] / radFull, SIN_COUNT[1] / radFull, SIN_COUNT[2] / radFull};
static final int DIRS[][] = {
{7, 2, 6, 1, 5, 0, 4, 3},
{7, 13, 2, 12, 6, 11, 1, 10, 5, 9, 0, 8, 4, 15, 3, 14},
{7, 27, 13, 26, 2, 25, 12, 24, 6, 23, 11, 22, 1, 21, 10, 20, 5, 19, 9, 18, 0, 17, 8, 16, 4, 31, 15, 30, 3, 29, 14, 28}
static final float RADIANS_4[] = {
MathUtils.atan2(-2, -4),
MathUtils.atan2(-2, 4),
MathUtils.atan2( 2, 4),
MathUtils.atan2( 2, -4),
};
*/
static final int DIRS_4M[] = {0, 3, 2, 1};
static final float RADIANS_4M[];
static {
RADIANS_4M = new float[4];
float min = RADIANS_4[3];
for (int i = 0; i < 4; i++) {
RADIANS_4M[i] = (min + RADIANS_4[i]) / 2;
min = RADIANS_4[i];
}
RADIANS_4M[0] = -MathUtils.PI;
}
static final byte[][] OFFSETS = new byte[][] {
{ 0, 2},
{-2, 0},
{ 0,-2},
{ 2, 0},
{ 2, 2},
{-2, 2},
{-2,-2},
{ 2,-2},
{ 1, 2},
{-1, 2},
{-2, 1},
{-2,-1},
{-1,-2},
{ 1,-2},
{ 2,-1},
{ 2, 1},
static final float RADIANS_8[] = {
RADIANS_4[0],
MathUtils.atan2(-4, 0),
RADIANS_4[1],
MathUtils.atan2( 0, 8),
RADIANS_4[2],
MathUtils.atan2( 4, 0),
RADIANS_4[3],
MathUtils.atan2( 0, -8),
};
static final int DIRS_8M[] = {5, 0, 4, 3, 7, 2, 6, 1};
static final float RADIANS_8M[];
static {
RADIANS_8M = new float[8];
float min = -RADIANS_8[7];
for (int i = 0; i < 8; i++) {
RADIANS_8M[i] = (min + RADIANS_8[i]) / 2;
min = RADIANS_8[i];
}
}
static final float[] RADIANS = new float[] {
MathUtils.PI * 5 / 4,
MathUtils.PI * 3 / 4,
MathUtils.PI * 1 / 4,
MathUtils.PI * 7 / 4,
MathUtils.PI * 3 / 2,
MathUtils.PI * 2 / 2,
MathUtils.PI * 1 / 2,
MathUtils.PI * 0 / 2,
MathUtils.PI * 11 / 8,
MathUtils.PI * 9 / 8,
MathUtils.PI * 7 / 8,
MathUtils.PI * 5 / 8,
MathUtils.PI * 3 / 8,
MathUtils.PI * 1 / 8,
MathUtils.PI * 15 / 8,
MathUtils.PI * 13 / 8,
static final float RADIANS_16[] = {
MathUtils.atan2(-1, -6),
RADIANS_8[0],
MathUtils.atan2(-3, -2),
RADIANS_8[1],
MathUtils.atan2(-3, 2),
RADIANS_8[2],
MathUtils.atan2(-1, 6),
RADIANS_8[3],
MathUtils.atan2(1, 6),
RADIANS_8[4],
MathUtils.atan2(3, 2),
RADIANS_8[5],
MathUtils.atan2(3, -2),
RADIANS_8[6],
MathUtils.atan2(1, -6),
RADIANS_8[7],
};
static final int DIRS_16M[] = {5, 9, 0, 8, 4, 15, 3, 14, 7, 13, 2, 12, 6, 11, 1, 10};
static final float RADIANS_16M[];
static {
RADIANS_16M = new float[16];
float min = -RADIANS_16[15];
for (int i = 0; i < 16; i++) {
RADIANS_16M[i] = (min + RADIANS_16[i]) / 2;
min = RADIANS_16[i];
}
}
private Direction() {}
static final float RADIANS_32[] = {
MathUtils.atan2(-0.5f, -7),
RADIANS_16[0],
MathUtils.atan2(-1.5f, -5),
RADIANS_16[1],
MathUtils.atan2(-2.5f, -3),
RADIANS_16[2],
MathUtils.atan2(-3.5f, -1),
RADIANS_16[3],
MathUtils.atan2(-3.5f, 1),
RADIANS_16[4],
MathUtils.atan2(-2.5f, 3),
RADIANS_16[5],
MathUtils.atan2(-1.5f, 5),
RADIANS_16[6],
MathUtils.atan2(-0.5f, 7),
RADIANS_16[7],
MathUtils.atan2(0.5f, 7),
RADIANS_16[8],
MathUtils.atan2(1.5f, 5),
RADIANS_16[9],
MathUtils.atan2(2.5f, 3),
RADIANS_16[10],
MathUtils.atan2(3.5f, 1),
RADIANS_16[11],
MathUtils.atan2(3.5f, -1),
RADIANS_16[12],
MathUtils.atan2(2.5f, -3),
RADIANS_16[13],
MathUtils.atan2(1.5f, -5),
RADIANS_16[14],
MathUtils.atan2(0.5f, -7),
RADIANS_16[15],
};
static final int DIRS_32M[] = {5, 19, 9, 18, 0, 17, 8, 16, 4, 31, 15, 30, 3, 29, 14, 28, 7, 27, 13, 26, 2, 25, 12, 24, 6, 23, 11, 22, 1, 21, 10, 20};
static final float RADIANS_32M[];
static {
RADIANS_32M = new float[32];
float min = -RADIANS_32[31];
for (int i = 0; i < 32; i++) {
RADIANS_32M[i] = (min + RADIANS_32[i]) / 2;
min = RADIANS_32[i];
}
}
public static int radiansToDirection(float radians, int directions) {
switch (directions) {
case 1: return 0;
case 4: return radiansToDirection4(radians);
case 8: return radiansToDirection8(radians);
case 16: return radiansToDirection16(radians);
case 32: return radiansToDirection32(radians);
default: return 0;
}
}
static final int DIRS_16[] = {7, 13, 2, 12, 6, 11, 1, 10, 5, 9, 0, 8, 4, 15, 3, 14};
static final float RADIANS_16[];
static {
float r = MathUtils.PI2 / 32;
float a = r * 2;
RADIANS_16 = new float[16];
for (int i = 0; i < 16; i++) {
RADIANS_16[i] = r;
r += a;
private static int radiansToDirection4(float radians) {
for (int i = 0; i < 4; i++) {
if (radians < RADIANS_4M[i]) {
return DIRS_4M[i];
}
}
//System.out.println(Arrays.toString(RADIANS_16));
return DIRS_4M[0];
}
static final int DIRS_8[] = {7, 2, 6, 1, 5, 0, 4, 3};
static final float RADIANS_8[];
static {
float r = MathUtils.PI2 / 16;
float a = r * 2;
RADIANS_8 = new float[8];
private static int radiansToDirection8(float radians) {
for (int i = 0; i < 8; i++) {
RADIANS_8[i] = r;
r += a;
if (radians < RADIANS_8M[i]) {
return DIRS_8M[i];
}
}
//System.out.println(Arrays.toString(RADIANS_8));
return DIRS_8M[0];
}
public static int radiansToDirection16(float radians) {
if (radians < 0) radians += MathUtils.PI2;
private static int radiansToDirection16(float radians) {
for (int i = 0; i < 16; i++) {
if (radians < RADIANS_16[i]) return DIRS_16[i];
if (radians < RADIANS_16M[i]) {
return DIRS_16M[i];
}
}
return DIRS_16[0];
return DIRS_16M[0];
}
public static int radiansToDirection8(float radians) {
if (radians < 0) radians += MathUtils.PI2;
for (int i = 0; i < 8; i++) {
if (radians < RADIANS_8[i]) return DIRS_8[i];
private static int radiansToDirection32(float radians) {
for (int i = 0; i < 32; i++) {
if (radians < RADIANS_32M[i]) {
return DIRS_32M[i];
}
}
return DIRS_8[0];
return DIRS_32M[0];
}
public static int getOffX(float radians) {
int id = radiansToDirection16(radians);
return OFFSETS[id][0];
}
public static int getOffY(float radians) {
int id = radiansToDirection16(radians);
return OFFSETS[id][1];
}
public static float radiansToDirection16Radians(float radians) {
if (radians < 0) radians += MathUtils.PI2;
for (int i = 0; i < 16; i++) {
if (radians < RADIANS_16[i]) return RADIANS[DIRS_16[i]];
}
return RADIANS[DIRS_16[0]];
}
/*
public static int radiansToDirection(float radians, int directions) {
int d;
public static float snapToDirection(float radians, int directions) {
switch (directions) {
case 8: d = 0; break;
case 16: d = 1; break;
case 32: d = 2; break;
default: throw new GdxRuntimeException("Invalid directions num: " + directions);
case 1: return RADIANS_4[0];
case 4: return _snapToDirection(radians, directions, DIRS_4M, RADIANS_4);
case 8: return _snapToDirection(radians, directions, DIRS_8M, RADIANS_8);
case 16: return _snapToDirection(radians, directions, DIRS_16M, RADIANS_16);
case 32: return _snapToDirection(radians, directions, DIRS_32M, RADIANS_32);
default: return RADIANS_4[0];
}
int id = (int) (radians * radToIndex[d]) & SIN_MASK[d];
System.out.println(id);
return DIRS[d][id];
}
public static int getOffX(float radians) {
int id = DIRS[1][(int) (radians * radToIndex[1]) & SIN_MASK[1]];
switch (id) {
case 8: id = 0; break;
case 9: id = 0; break;
case 10: id = 0; break;
case 11: id = 0; break;
case 12: id = 0; break;
case 13: id = 0; break;
case 14: id = 0; break;
case 15: id = 0; break;
}
//System.out.println(id);
return OFFSETS[id][0];
private static float _snapToDirection(float radians, int dirs, int[] dirsm, float[] rads) {
int dir = radiansToDirection(radians, dirs);
int index = ArrayUtils.indexOf(dirsm, dir);
if (--index < 0) index = dirs - 1;
return rads[index];
}
public static int getOffY(float radians) {
int id = DIRS[0][(int) (radians * radToIndex[0]) & SIN_MASK[0]];
return OFFSETS[id][1];
}
*/
}

View File

@ -127,7 +127,7 @@ public class Entity {
String weaponClass;
Vector3 position = new Vector3();
Vector3 velocity = new Vector3();
float angle = MathUtils.atan2(-1, -2);//MathUtils.PI * 3 / 2;
float angle = MathUtils.atan2(-1, -2);
boolean running = false;
float walkSpeed = 6;
@ -470,10 +470,12 @@ public class Entity {
shapes.setColor(Color.RED);
shapes.line(x, y, x + MathUtils.cos(angle) * R, y + MathUtils.sin(angle) * R);
// FIXME: Should be number of direction dependent, not 16, one of 4,8,16,32
float rounded = Direction.radiansToDirection16Radians(angle);
shapes.setColor(Color.GREEN);
shapes.line(x, y, x + MathUtils.cos(rounded) * R * 0.5f, y + MathUtils.sin(rounded) * R * 0.5f);
if (animation != null) {
int numDirs = animation.getNumDirections();
float rounded = Direction.snapToDirection(angle, numDirs);
shapes.setColor(Color.GREEN);
shapes.line(x, y, x + MathUtils.cos(rounded) * R * 0.5f, y + MathUtils.sin(rounded) * R * 0.5f);
}
}
public void drawDebugTarget(ShapeRenderer shapes) {

View File

@ -436,7 +436,7 @@ public class MapRenderer {
if ((stx <= position.x && position.x < stx + Tile.SUBTILE_SIZE)
&& (sty <= position.y && position.y < sty + Tile.SUBTILE_SIZE)) {
entity.update(Gdx.graphics.getDeltaTime());
if (!entity.position().epsilonEquals(entity.target())) {
if (!entity.position().epsilonEquals(entity.target()) && !entity.target().isZero()) {
entity.setAngle(angle(entity.position(), entity.target()));
}

View File

@ -0,0 +1,120 @@
package gdx.diablo.entity;
import org.junit.Assert;
import org.junit.Test;
import java.util.Arrays;
public class DirectionTest {
@Test
public void testRadians4() {
System.out.println(Arrays.toString(Direction.RADIANS_4));
double t = Integer.MIN_VALUE;
for (float f : Direction.RADIANS_4) {
Assert.assertTrue(f > t);
t = f;
}
}
@Test
public void testRadians4m() {
System.out.println(Arrays.toString(Direction.RADIANS_4));
System.out.println(Arrays.toString(Direction.RADIANS_4M));
double t = Integer.MIN_VALUE;
for (float f : Direction.RADIANS_4M) {
Assert.assertTrue(f > t);
t = f;
}
}
@Test
public void testRadians8() {
System.out.println(Arrays.toString(Direction.RADIANS_8));
double t = Integer.MIN_VALUE;
for (float f : Direction.RADIANS_8) {
Assert.assertTrue(f > t);
t = f;
}
}
@Test
public void testRadians8m() {
System.out.println(Arrays.toString(Direction.RADIANS_8));
System.out.println(Arrays.toString(Direction.RADIANS_8M));
double t = Integer.MIN_VALUE;
for (float f : Direction.RADIANS_8M) {
Assert.assertTrue(f > t);
t = f;
}
}
@Test
public void testRadians16() {
System.out.println(Arrays.toString(Direction.RADIANS_16));
double t = Integer.MIN_VALUE;
for (float f : Direction.RADIANS_16) {
Assert.assertTrue(f > t);
t = f;
}
}
@Test
public void testRadians16m() {
System.out.println(Arrays.toString(Direction.RADIANS_16));
System.out.println(Arrays.toString(Direction.RADIANS_16M));
double t = Integer.MIN_VALUE;
for (float f : Direction.RADIANS_16M) {
Assert.assertTrue(f > t);
t = f;
}
}
@Test
public void testRadians32() {
System.out.println(Arrays.toString(Direction.RADIANS_32));
double t = Integer.MIN_VALUE;
for (float f : Direction.RADIANS_32) {
Assert.assertTrue(f > t);
t = f;
}
}
@Test
public void testRadians32m() {
System.out.println(Arrays.toString(Direction.RADIANS_32));
System.out.println(Arrays.toString(Direction.RADIANS_32M));
double t = Integer.MIN_VALUE;
for (float f : Direction.RADIANS_32M) {
Assert.assertTrue(f > t);
t = f;
}
}
@Test
public void test_radiansToDirection4() {
for (float f : Direction.RADIANS_8M) {
System.out.println(f + " : " + Direction.radiansToDirection(f, 4));
}
}
@Test
public void test_radiansToDirection8() {
for (float f : Direction.RADIANS_16M) {
System.out.println(f + " : " + Direction.radiansToDirection(f, 8));
}
}
@Test
public void test_radiansToDirection16() {
for (float f : Direction.RADIANS_32M) {
System.out.println(f + " : " + Direction.radiansToDirection(f, 16));
}
}
@Test
public void test_radiansToDirection32() {
for (float f : Direction.RADIANS_32M) {
System.out.println(f + " : " + Direction.radiansToDirection(f, 32));
}
}
}