From 970988a5eb10b836db591ac8dc6d437fd569b684 Mon Sep 17 00:00:00 2001 From: Joshua Goins Date: Sat, 30 Apr 2022 19:52:28 -0400 Subject: [PATCH] Add A* pathing algorithm I adapted the A* I had already implemented in a Realm of Chaos, now adapted in Java and is used to calculate the player's path to their new location. --- core/src/com/redstrate/watersymbol/AStar.java | 110 ++++++++++++++++++ .../watersymbol/screens/GameScreen.java | 20 ++++ 2 files changed, 130 insertions(+) create mode 100644 core/src/com/redstrate/watersymbol/AStar.java diff --git a/core/src/com/redstrate/watersymbol/AStar.java b/core/src/com/redstrate/watersymbol/AStar.java new file mode 100644 index 0000000..2204b1f --- /dev/null +++ b/core/src/com/redstrate/watersymbol/AStar.java @@ -0,0 +1,110 @@ +package com.redstrate.watersymbol; + +import com.badlogic.gdx.math.Vector2; + +import java.util.ArrayList; +import java.util.List; + +/* +This is a direct port of the A* pathing implementation in Realm of Chaos. + */ +public class AStar { + static class Node { + Vector2 position; + int g = 0; + int h = 0; + int f = 0; + + Node parent; + } + + private static final int maxOpenNodes = 200; + + public static ArrayList path(Vector2 start, Vector2 end) { + Node startNode = new Node(); + startNode.position = start; + + Node endNode = new Node(); + endNode.position = end; + + ArrayList openList = new ArrayList<>(); + openList.add(startNode); + + ArrayList closedList = new ArrayList<>(); + while(!openList.isEmpty() && openList.size() < maxOpenNodes) { + Node currentNode = openList.get(0); + int currentIndex = 0; + for(int i = 0; i < openList.size(); i++) { + if(openList.get(i).f < currentNode.f) { + currentNode = openList.get(i); + currentIndex = i; + } + } + + openList.remove(currentIndex); + closedList.add(currentNode); + + // check if we found the goal + if(currentNode.position.epsilonEquals(endNode.position)) { + ArrayList path = new ArrayList<>(); + Node current = currentNode; + while(current != null) { + path.add(current.position); + current = current.parent; + } + + System.out.println(path.toString()); + + return path; + } + + ArrayList children = new ArrayList<>(); + + ArrayList adjacentPositions = new ArrayList<>(); + adjacentPositions.add(new Vector2(0, -1)); + adjacentPositions.add(new Vector2(0, 1)); + adjacentPositions.add(new Vector2(-1, 0)); + adjacentPositions.add(new Vector2(1, 0)); + adjacentPositions.add(new Vector2(-1, -1)); + adjacentPositions.add(new Vector2(-1, 1)); + adjacentPositions.add(new Vector2(1, -1)); + adjacentPositions.add(new Vector2(1, 1)); + for (Vector2 position : adjacentPositions) { + Node newNode = new Node(); + newNode.position = new Vector2(currentNode.position.x + position.x, currentNode.position.y + position.y); + newNode.parent = currentNode; + + children.add(newNode); + } + + for(Node child : children) { + boolean shouldContinue = false; + for(Node closedChild : closedList) { + if(child.position.epsilonEquals(closedChild.position)) { + shouldContinue = true; + } + } + + if(shouldContinue) + continue; + + child.g = currentNode.g + 1; + child.h = (int) (Math.pow(child.position.x - endNode.position.x, 2) + Math.pow(child.position.y - endNode.position.y, 2)); + child.f = child.g + child.h; + + for(Node openNode : openList) { + if(child.position.epsilonEquals(openNode.position) && child.g > openNode.g) { + shouldContinue = true; + } + } + + if(shouldContinue) + continue; + + openList.add(child); + } + } + + return null; + } +} diff --git a/core/src/com/redstrate/watersymbol/screens/GameScreen.java b/core/src/com/redstrate/watersymbol/screens/GameScreen.java index 2675b6a..9bee976 100644 --- a/core/src/com/redstrate/watersymbol/screens/GameScreen.java +++ b/core/src/com/redstrate/watersymbol/screens/GameScreen.java @@ -12,9 +12,12 @@ import com.badlogic.gdx.maps.tiled.renderers.OrthogonalTiledMapRenderer; import com.badlogic.gdx.math.Vector2; import com.badlogic.gdx.math.Vector3; import com.badlogic.gdx.utils.ScreenUtils; +import com.redstrate.watersymbol.AStar; import com.redstrate.watersymbol.Player; import com.redstrate.watersymbol.WaterSymbol; +import java.util.ArrayList; + public class GameScreen implements Screen { private final WaterSymbol game; private boolean hasStartedMoving = false; @@ -64,6 +67,23 @@ public class GameScreen implements Screen { // player is trying to move if(Gdx.input.isButtonPressed(0)) { hasStartedMoving = true; + + Vector3 mousePos = new Vector3(Gdx.input.getX(), Gdx.input.getY(), 0); + + camera.unproject(mousePos); + + double newX = Math.floor(mousePos.x); + double newY = Math.floor(mousePos.y); + + int newFixedX = (int) (newX / 32.0); + int newFixedY = (int) (newY / 32.0); + + ArrayList path = AStar.path(new Vector2(player.positionX, player.positionY), new Vector2((float)newFixedX, (float)newFixedY)); + if(path != null) { + for (Vector2 position : path) { + game.batch.draw(playerTexture, position.x * 32, position.y * 32); + } + } } else if(hasStartedMoving) { Vector3 mousePos = new Vector3(Gdx.input.getX(), Gdx.input.getY(), 0);