我正在制作一个简单的迷宫解决算法(A *但这并不相关)和一个用于显示导航迷宫的代理的GUI。我有一个处理状态的MapModel类和一个将所有东西都绘制到JPanel的MapView类。每次状态改变时我都会调用MapModel类重绘,但是当我需要我的单元进行动画处理时(在moveAgent()方法中),不会调用重绘。我调试了程序,并且每个“帧”都会到达重绘方法,但是没有调用MapView的paintComponent方法。
我对UI和动画比较陌生,除了脚本和C程序之外我没有编写其他许多代码,所以我可能完全错了。让我知道我是否应该重新设计我的任何课程以更好地适应标准的Java swing实践!
这是我的代码。还有其他课程,但我很确定他们与这个问题无关。如果你愿意,我也可以发布它们。
编辑:我忘了提到重绘有时会起作用,而不是在moveAgent()中。当我从createRandomObstacles()调用它时,它会正确绘制。
MapModel.java:
import java.util.ArrayList;
import java.util.PriorityQueue;
import java.awt.Point;
import java.util.HashMap;
public class MapModel {
int width, height, start_diameter, speed;
ArrayList<Obstacle> obstacle_list = new ArrayList<Obstacle>();
Agent agent;
GridSpaceManager grid_manager;
String current_algorithm = "NONE";
ArrayList<Point> subgoal_list;
MapView map_view;
boolean animate = false;
AnimationManager animation_manager = new AnimationManager();
public MapModel(int size, MapView map_view)
{
this.width = size;
this.height = size;
this.map_view = map_view;
}
public void updateMapModel (){
map_view.repaint();
}
//if obstacles can't fit then method returns
public void createRandomObstacles(int num_obstacles, int start_diameter)
{
this.start_diameter = start_diameter;
obstacle_list.clear();
ArrayList<Point> point_list = new ArrayList<Point>();
for(int i = 0; i < num_obstacles; i++) {
int rand_x = (int)(Math.random()*(width-start_diameter))+start_diameter;
int rand_y = (int)(Math.random()*(height-start_diameter))+start_diameter;
point_list.add(new Point(rand_x, rand_y));
}
for(int i = 0; i < num_obstacles; i++) {
double min_distance = Double.MAX_VALUE;
Point p1 = point_list.get(i);
for(int j = 0; j < num_obstacles; j++) {
Point p2 = point_list.get(j);
if(j != i && p1.distance(p2) < min_distance)
min_distance = p1.distance(p2);
}
min_distance = Math.sqrt(min_distance*min_distance/2);
int min_int = (int)(min_distance/2);
if(min_int > 1) {
int width = (int)(Math.random()*(min_int));
width = Math.min(width, Math.max(p1.x, this.width - p1.x));
int height = (int)(Math.random()*(min_int));
height = Math.min(height, Math.max(p1.y, this.height - p1.y));
if(p1.x + width > this.width - start_diameter && p1.y + height > this.height - start_diameter) {
width = this.width - start_diameter - p1.x;
height = this.height - start_diameter - p1.y;
}
if(!(width < 0 && height < 0))
obstacle_list.add(new Obstacle(p1.x, p1.y, width, height));
}
}
updateMapModel();
}
public void moveAgent() {
if(animation_manager.running) {
animation_manager.act();
double speed = Math.sqrt(width*height/10);
Point p = subgoal_list.get(0);
if(p.x == agent.x && p.y == agent.y) {
if(subgoal_list.size() == 1) {
animate = false;
return;
}
subgoal_list.remove(0);
p = subgoal_list.get(0);
}
double distance = Point.distance(agent.x, agent.y, p.x, p.y);
double delta_x = (p.x - agent.x)/distance;
double delta_y = (p.y - agent.y)/distance;
double distance2 = Math.sqrt(delta_x*delta_x + delta_y+delta_y);
if(distance2 > distance) {
agent.x = p.x;
agent.y = p.y;
}
else {
agent.x += delta_x;
agent.y += delta_y;
}
long sleep_time = animation_manager.timeTillNextFrame();
if(sleep_time > 0)
try {
Thread.sleep(sleep_time);
}
catch(InterruptedException e) {
}
updateMapModel();
moveAgent();
}
else {
endPathfinding();
}
}
public void startAnimation(int agent_diameter, boolean animate) {
agent = new Agent(0,0,agent_diameter);
this.animate = animate;
animation_manager.start();
moveAgent();
}
public void startPathfinding(String algorithm, int agent_diameter, boolean animate) {
if(algorithm.equals("A*")) {
startAStar(agent_diameter);
this.current_algorithm = "A*";
}
if(subgoal_list == null) {
this.current_algorithm = "NONE";
}
startAnimation(agent_diameter, animate);
}
public void endPathfinding() {
agent = null;
subgoal_list = null;
animation_manager.end();
this.current_algorithm = "NONE";
}
public void startAStar(int agent_diameter) {
grid_manager = new GridSpaceManager(obstacle_list, width, height);
if(agent_diameter > start_diameter) return;
agent = new Agent(agent_diameter/2, agent_diameter/2, agent_diameter);
subgoal_list = AStar(grid_manager.getNode(0, 0), grid_manager.getNode(width - 1, height - 1));
}
public ArrayList<Point> AStar(SearchSpaceNode start, SearchSpaceNode goal) {
Point start_point = start.point_list[0];
Point goal_point = goal.point_list[0];
PriorityQueue<SearchSpaceNode> open_set = new PriorityQueue<SearchSpaceNode>();
ArrayList<SearchSpaceNode> closed_set = new ArrayList<SearchSpaceNode>();
HashMap<SearchSpaceNode, SearchSpaceNode> came_from = new HashMap<SearchSpaceNode, SearchSpaceNode>();
HashMap<SearchSpaceNode, Integer> g_score = new HashMap<SearchSpaceNode, Integer>();
HashMap<SearchSpaceNode, Integer> f_score = new HashMap<SearchSpaceNode, Integer>();
int start_f_value = (int)manhattan_distance(start,goal);
g_score.put(start, 0);
f_score.put(start, start_f_value);
start.f_value = start_f_value;
open_set.add(start);
while(open_set.size() > 0) {
SearchSpaceNode current = open_set.poll();
if(current == goal) {
ArrayList<Point> subgoal_list = reconstructPath(came_from, current);
subgoal_list.add(goal_point);
return subgoal_list;
}
closed_set.add(current);
ArrayList<SearchSpaceNode> neighbors = current.getNeighbors();
for(int i = 0; i < neighbors.size(); i++) {
SearchSpaceNode neighbor = neighbors.get(i);
if(closed_set.contains(neighbor))
continue;
int tentative_g_score = g_score.get(current) + 1;
if(!open_set.contains(neighbor) || !g_score.containsKey(neighbor)
|| tentative_g_score < g_score.get(neighbor)) {
int tentative_f_score = tentative_g_score + (int)manhattan_distance(neighbor, goal);
came_from.put(neighbor, current);
g_score.put(neighbor, tentative_g_score);
f_score.put(neighbor, tentative_f_score);
neighbor.f_value = tentative_f_score;
if(!open_set.contains(neighbor))
open_set.add(neighbor);
}
}
}
return null;
}
public ArrayList<Point> reconstructPath(
HashMap<SearchSpaceNode,SearchSpaceNode> came_from,SearchSpaceNode current_node) {
ArrayList<Point> subgoal_list = new ArrayList<Point>();
while(came_from.containsKey(current_node)) {
SearchSpaceNode temp = came_from.get(current_node);
subgoal_list.add(0, temp.point_list[0]);
came_from.remove(current_node);
current_node = temp;
}
return subgoal_list;
}
public double manhattan_distance(SearchSpaceNode start, SearchSpaceNode goal) {
Point start_point = start.point_list[0];
Point goal_point = goal.point_list[0];
return Math.sqrt(Math.pow(goal_point.x - start_point.x,2) + Math.pow(goal_point.x - start_point.x,2));
//return Math.abs(goal_point.x - start_point.x) + Math.abs(goal_point.y - start_point.y);
}
public String algorithmRunning(){return current_algorithm;}
}
class AnimationManager {
boolean running = false;
int frame_number = -1;
int milliseconds_per_frame = 500;
long start_time = -1;
public void start() {
running = true;
start_time = System.currentTimeMillis();
frame_number = 0;
}
public void end() {
running = false;
start_time = frame_number = -1;
}
public void act() {
frame_number++;
}
public long timeTillNextFrame() {
return (frame_number + 1)*milliseconds_per_frame - (System.currentTimeMillis() - start_time);
}
}
MapView.java:
import java.awt.event.*;
import java.awt.*;
import javax.swing.*;
import java.util.ArrayList;
public class MapView extends JPanel{
private int size, actual_map_size;
MapModel map_model;
Point current_subgoal = null;
int frame_number = 0;
long start_time;
public MapView(int size)
{
this.setBounds(0,200,600,600);
this.size = size;
}
boolean starting_print = true;
public void paintComponent(Graphics g) {
int x_offset = 10, y_offset = 10;
super.paintComponent(g);
g.setColor(Color.BLACK);
g.fillRect((600-size)/2 + x_offset - 2, y_offset - 2,size + 5, size + 5);
g.setColor(Color.WHITE);
g.fillRect((600-size)/2 + x_offset - 1, y_offset - 1,size+3,size+3);
g.setColor(Color.GREEN);
if(this.map_model != null) {
ArrayList<Obstacle> obstacle_list = map_model.obstacle_list;
for(int i = 0; i < obstacle_list.size(); i++) {
Obstacle o = obstacle_list.get(i);
g.fillRect(scaleX(o.x) + x_offset,scale(o.y) + y_offset,
scale(o.width),scale(o.height));
}
g.setColor(Color.RED);
if(map_model.current_algorithm.equals("A*")) {
GridSpaceManager grid = map_model.grid_manager;
for(int i = 0; i < map_model.width; i++) {
for(int j = 0; j< map_model.height; j++) {
SearchSpaceNode node = grid.getNode(i, j);
if(node != null) {
Point p = node.point_list[0];
g.drawRect(scaleX(p.x) + x_offset, scale(p.y) + y_offset, scale(1), scale(1));
}
}
}
}
g.setColor(Color.BLUE);
Agent agent = map_model.agent;
if(agent != null) {
g.fillOval(scaleX(agent.x) + x_offset, scale(agent.y) + y_offset,
Math.max(2,scale(agent.diameter)), Math.max(2,scale(agent.diameter)));
}
}
}
private int scaleX(int x) {
double scale = ((double)size) / ((double)actual_map_size);
return (int)(((double)x)*scale)+(600-size)/2;
}
private int scale(int val) {
double scale = ((double)size) / ((double)actual_map_size);
return (int)(((double)val)*scale);
}
public void setMapModel(MapModel map) {
this.map_model = map;
}
public void setMapScale(int actual_map_size) {
this.actual_map_size = actual_map_size;
}
}
答案 0 :(得分:0)
我根据MadProgrammer的建议重新设计了我的代码以使用Timer类。这是让我的动画工作的更简洁的方式!这是下面的新代码。 MapView类保持不变。
MapModel.java
import java.util.ArrayList;
import javax.swing.*;
import java.awt.event.*;
import java.util.PriorityQueue;
import java.awt.Point;
import java.util.HashMap;
public class MapModel implements ActionListener{
boolean running = false;
int milliseconds_per_frame = 500;
Timer timer = new Timer(milliseconds_per_frame, this);
int width, height, start_diameter, speed;
ArrayList<Obstacle> obstacle_list = new ArrayList<Obstacle>();
Agent agent;
GridSpaceManager grid_manager;
String current_algorithm = "NONE";
ArrayList<Point> subgoal_list;
MapView map_view;
boolean animate = false;
public MapModel(int size, MapView map_view)
{
this.width = size;
this.height = size;
this.map_view = map_view;
}
public void updateMapModel (){
map_view.repaint();
}
//if obstacles can't fit then method returns
public void createRandomObstacles(int num_obstacles, int start_diameter)
{
this.start_diameter = start_diameter;
obstacle_list.clear();
ArrayList<Point> point_list = new ArrayList<Point>();
for(int i = 0; i < num_obstacles; i++) {
int rand_x = (int)(Math.random()*(width-start_diameter))+start_diameter;
int rand_y = (int)(Math.random()*(height-start_diameter))+start_diameter;
point_list.add(new Point(rand_x, rand_y));
/*
double min_distance = Double.MAX_VALUE;
Point p1 = point_list.get(i);
for(int j = 0; j < point_list.size(); j++) {
Point p2 = point_list.get(j);
if(j != i && p1.distance(p2) < min_distance)
min_distance = p1.distance(p2);
}
min_distance = Math.sqrt(min_distance*min_distance/2);
int min_int = (int)(min_distance/2);
if(min_int > 1) {
int width = (int)(Math.random()*(min_int));
width = Math.min(width, Math.max(p1.x, this.width - p1.x));
int height = (int)(Math.random()*(min_int));
height = Math.min(height, Math.max(p1.y, this.height - p1.y));
if(p1.x + width > this.width - start_diameter && p1.y + height > this.height - start_diameter) {
width = this.width - start_diameter - p1.x;
height = this.height - start_diameter - p1.y;
}
if(!(width < 0 && height < 0))
obstacle_list.add(new Obstacle(p1.x, p1.y, width, height));
}
*/
}
for(int i = 0; i < num_obstacles; i++) {
double min_distance = Double.MAX_VALUE;
Point p1 = point_list.get(i);
for(int j = 0; j < num_obstacles; j++) {
Point p2 = point_list.get(j);
if(j != i && p1.distance(p2) < min_distance)
min_distance = p1.distance(p2);
}
min_distance = Math.sqrt(min_distance*min_distance/2);
int min_int = (int)(min_distance/2);
if(min_int > 1) {
int width = (int)(Math.random()*(min_int));
width = Math.min(width, Math.max(p1.x, this.width - p1.x));
int height = (int)(Math.random()*(min_int));
height = Math.min(height, Math.max(p1.y, this.height - p1.y));
if(p1.x + width > this.width - start_diameter && p1.y + height > this.height - start_diameter) {
width = this.width - start_diameter - p1.x;
height = this.height - start_diameter - p1.y;
}
if(!(width < 0 && height < 0))
obstacle_list.add(new Obstacle(p1.x, p1.y, width, height));
}
}
updateMapModel();
}
public void moveAgent() {
if(animate) {
double speed = Math.sqrt(width*height/10);
Point p = subgoal_list.get(0);
if(p.x == agent.x && p.y == agent.y) {
if(subgoal_list.size() == 1) {
animate = false;
return;
}
subgoal_list.remove(0);
p = subgoal_list.get(0);
}
double distance = Point.distance(agent.x, agent.y, p.x, p.y);
double delta_x = (p.x - agent.x)/distance;
double delta_y = (p.y - agent.y)/distance;
double distance2 = Math.sqrt(delta_x*delta_x + delta_y+delta_y);
if(distance2 > distance) {
agent.x = p.x;
agent.y = p.y;
}
else {
agent.x += delta_x;
agent.y += delta_y;
}
updateMapModel();
}
else {
endPathfinding();
}
}
public void startAnimation(int agent_diameter, boolean animate) {
agent = new Agent(0,0,agent_diameter);
this.animate = animate;
timer.start();
moveAgent();
}
public void startPathfinding(String algorithm, int agent_diameter, boolean animate) {
if(algorithm.equals("A*")) {
startAStar(agent_diameter);
this.current_algorithm = "A*";
}
if(subgoal_list == null) {
this.current_algorithm = "NONE";
}
startAnimation(agent_diameter, animate);
}
public void endPathfinding() {
agent = null;
subgoal_list = null;
timer.stop();
this.current_algorithm = "NONE";
}
public void startAStar(int agent_diameter) {
grid_manager = new GridSpaceManager(obstacle_list, width, height);
if(agent_diameter > start_diameter) return;
agent = new Agent(agent_diameter/2, agent_diameter/2, agent_diameter);
subgoal_list = AStar(grid_manager.getNode(0, 0), grid_manager.getNode(width - 1, height - 1));
}
public ArrayList<Point> AStar(SearchSpaceNode start, SearchSpaceNode goal) {
Point start_point = start.point_list[0];
Point goal_point = goal.point_list[0];
PriorityQueue<SearchSpaceNode> open_set = new PriorityQueue<SearchSpaceNode>();
ArrayList<SearchSpaceNode> closed_set = new ArrayList<SearchSpaceNode>();
HashMap<SearchSpaceNode, SearchSpaceNode> came_from = new HashMap<SearchSpaceNode, SearchSpaceNode>();
HashMap<SearchSpaceNode, Integer> g_score = new HashMap<SearchSpaceNode, Integer>();
HashMap<SearchSpaceNode, Integer> f_score = new HashMap<SearchSpaceNode, Integer>();
int start_f_value = (int)manhattan_distance(start,goal);
g_score.put(start, 0);
f_score.put(start, start_f_value);
start.f_value = start_f_value;
open_set.add(start);
while(open_set.size() > 0) {
SearchSpaceNode current = open_set.poll();
if(current == goal) {
ArrayList<Point> subgoal_list = reconstructPath(came_from, current);
subgoal_list.add(goal_point);
return subgoal_list;
}
closed_set.add(current);
ArrayList<SearchSpaceNode> neighbors = current.getNeighbors();
for(int i = 0; i < neighbors.size(); i++) {
SearchSpaceNode neighbor = neighbors.get(i);
if(closed_set.contains(neighbor))
continue;
int tentative_g_score = g_score.get(current) + 1;
if(!open_set.contains(neighbor) || !g_score.containsKey(neighbor)
|| tentative_g_score < g_score.get(neighbor)) {
int tentative_f_score = tentative_g_score + (int)manhattan_distance(neighbor, goal);
came_from.put(neighbor, current);
g_score.put(neighbor, tentative_g_score);
f_score.put(neighbor, tentative_f_score);
neighbor.f_value = tentative_f_score;
if(!open_set.contains(neighbor))
open_set.add(neighbor);
}
}
}
return null;
}
public ArrayList<Point> reconstructPath(
HashMap<SearchSpaceNode,SearchSpaceNode> came_from,SearchSpaceNode current_node) {
ArrayList<Point> subgoal_list = new ArrayList<Point>();
while(came_from.containsKey(current_node)) {
SearchSpaceNode temp = came_from.get(current_node);
subgoal_list.add(0, temp.point_list[0]);
came_from.remove(current_node);
current_node = temp;
}
return subgoal_list;
}
public double manhattan_distance(SearchSpaceNode start, SearchSpaceNode goal) {
Point start_point = start.point_list[0];
Point goal_point = goal.point_list[0];
return Math.sqrt(Math.pow(goal_point.x - start_point.x,2) + Math.pow(goal_point.x - start_point.x,2));
//return Math.abs(goal_point.x - start_point.x) + Math.abs(goal_point.y - start_point.y);
}
public String algorithmRunning(){return current_algorithm;}
public void actionPerformed(ActionEvent e) {
if(animate) {
moveAgent();
}
}
}