这是我的程序,它有一个运行模拟的 run 方法。
import java.util.*;
public class Game{
public static int size;
public int numObjects;
public static int speedX;
public static int speedY;
ArrayList<Rock> rockArrayList = new ArrayList<>();
ArrayList<Paper> paperArrayList = new ArrayList<>();
ArrayList<Scissors> scissorsArrayList = new ArrayList<>();
public Game(int size, int numObjects, int speedX, int speedY){
Game.size = size;
Game.speedX = speedX;
Game.speedY = speedY;
this.numObjects = numObjects;
StdDraw.setCanvasSize(size, size); //set up drawing canvas
StdDraw.setXscale(0, size); //<0, 0> is bottom left. <size-1, size-1> is top right
StdDraw.setYscale(0, size);
Random random = new Random();
for(int i = 0; i<numObjects; i++) {
int neg = random.nextInt(2);
speedX *= ((neg == 0) ? 1:-1);
int x = random.nextInt(size);
neg = random.nextInt(2);
speedY*=((neg == 0) ? 1:-1);
int y = random.nextInt(size);
rockArrayList.add(new Rock(x,y,speedX, speedY));
}
for(int i = 0; i<numObjects; i++) {
int neg = random.nextInt(2);
speedX *= ((neg == 0) ? 1:-1);
int x = random.nextInt(size);
neg = random.nextInt(2);
speedY*=((neg == 0) ? 1:-1);
int y = random.nextInt(size);
paperArrayList.add(new Paper(x,y,speedX,speedY));
}
for(int i = 0; i<numObjects; i++) {
int neg = random.nextInt(2);
speedX *= ((neg == 0) ? 1:-1);
int x = random.nextInt(size);
neg = random.nextInt(2);
speedY*=((neg == 0) ? 1:-1);
int y = random.nextInt(size);
scissorsArrayList.add(new Scissors(x,y,speedX,speedY));
}
}
public void run() {
while (true){
StdDraw.clear(StdDraw.BLACK);
StdDraw.enableDoubleBuffering();
for(Rock r : rockArrayList) {
r.update();
}
for(Paper p : paperArrayList) {
p.update();
}
for(Scissors s : scissorsArrayList) {
s.update();
}
for(int i = 0; i < paperArrayList.size(); i++) {
for(int j = 0; j < rockArrayList.size(); j++) {
if(paperArrayList.get(i).doesCollideWith(rockArrayList.get(j))) {
paperArrayList.add(new Paper(rockArrayList.get(j).getX(), rockArrayList.get(j).getY(),speedX,speedY));
paperArrayList.get(paperArrayList.size()-1).changeSpeedX(-1);
rockArrayList.remove(j);
}
}
}
for(int i = 0; i < rockArrayList.size(); i++) {
for(int j = 0; j < scissorsArrayList.size(); j++) {
if(rockArrayList.get(i).doesCollideWith(scissorsArrayList.get(j))) {
rockArrayList.add(new Rock(scissorsArrayList.get(j).getX(), scissorsArrayList.get(j).getY(),speedX,speedY));
rockArrayList.get(rockArrayList.size()-1).changeSpeedY(-1);
scissorsArrayList.remove(j);
}
}
}
for(int i = 0; i < scissorsArrayList.size(); i++) {
for(int j = 0; j < paperArrayList.size(); j++) {
if(scissorsArrayList.get(i).doesCollideWith(paperArrayList.get(j))) {
scissorsArrayList.add(new Scissors(paperArrayList.get(j).getX(), paperArrayList.get(j).getY(),speedX,speedY));
scissorsArrayList.get(scissorsArrayList.size()-1).changeSpeedY(-1);
paperArrayList.remove(j);
}
}
}
if((rockArrayList.isEmpty() && paperArrayList.isEmpty()) || (rockArrayList.isEmpty() && scissorsArrayList.isEmpty()) || (paperArrayList.isEmpty() && scissorsArrayList.isEmpty()) )
break;
for(Rock r : rockArrayList)
r.draw();
for(Paper p : paperArrayList)
p.draw();
for(Scissors s : scissorsArrayList)
s.draw();
StdDraw.show();
StdDraw.pause(20);
}
}
}
这里,石头、布和剪刀都是被模拟在弹跳中生成的物体(我可能应该创建一个超类),直到其中一个“获胜”。这是它们的构造函数(除了名称之外它们都是相同的):
public Rock(int x, int y, int speedX, int speedY){
this.x = x;
this.y = y;
this.speedX = speedX;
this.speedY = speedY;
}
每个对象都有一个更新方法,可以帮助对象保留在屏幕上:
public void update(){
x += speedX;
y += speedY;
if(x+speedX >= Game.size || x+speedX<=0)
speedX *= -1;
if(y+speedY >= Game.size || y+speedY<=0)
speedY*=-1;
}
最后我有一个名为 Collideable 的接口,它检查一个对象是否与另一个对象发生碰撞(此方法的实现在所有 3 个类中都是相同的)
@Override
public boolean doesCollideWith(Collideable collideable){
if(Math.abs(collideable.getX()-this.x)<10){
return Math.abs(collideable.getY() - this.y) < 10;
}
return false;
}
正如你在我的 run 方法中看到的,我想要一种方法来使每个对象相互反弹,而不会使该程序的时间复杂度超过 O(n^2)。本质上,我想停止使用如此多的循环来检查可以以更简洁的方式完成的事情。对于所有图形内容,我使用 Princeton 的 StdDraw 类。
我尝试使用三重嵌套的 for 循环来检查,但它看起来一团糟,我羞于分享它,因为代码质量很差。我不是 100% 确定,但我认为使用不同的数据结构而不是 Arraylist 可能更容易,但我目前不知道任何此类其他数据结构。
以下是该计划中的所有课程:
public class Main {
public static void main(String[] args) {
Game game = new Game(900,100, 3,3);
game.run();
}
}
import java.util.*;
public class Game{
public static int size;
public int numObjects;
public static int speedX;
public static int speedY;
ArrayList<Rock> rockArrayList = new ArrayList<>();
ArrayList<Paper> paperArrayList = new ArrayList<>();
ArrayList<Scissors> scissorsArrayList = new ArrayList<>();
public Game(int size, int numObjects, int speedX, int speedY){
Game.size = size;
Game.speedX = speedX;
Game.speedY = speedY;
this.numObjects = numObjects;
StdDraw.setCanvasSize(size, size); //set up drawing canvas
StdDraw.setXscale(0, size); //<0, 0> is bottom left. <size-1, size-1> is top right
StdDraw.setYscale(0, size);
Random random = new Random();
for(int i = 0; i<numObjects; i++) {
int neg = random.nextInt(2);
speedX *= ((neg == 0) ? 1:-1);
int x = random.nextInt(size);
neg = random.nextInt(2);
speedY*=((neg == 0) ? 1:-1);
int y = random.nextInt(size);
rockArrayList.add(new Rock(x,y,speedX, speedY));
}
for(int i = 0; i<numObjects; i++) {
int neg = random.nextInt(2);
speedX *= ((neg == 0) ? 1:-1);
int x = random.nextInt(size);
neg = random.nextInt(2);
speedY*=((neg == 0) ? 1:-1);
int y = random.nextInt(size);
paperArrayList.add(new Paper(x,y,speedX,speedY));
}
for(int i = 0; i<numObjects; i++) {
int neg = random.nextInt(2);
speedX *= ((neg == 0) ? 1:-1);
int x = random.nextInt(size);
neg = random.nextInt(2);
speedY*=((neg == 0) ? 1:-1);
int y = random.nextInt(size);
scissorsArrayList.add(new Scissors(x,y,speedX,speedY));
}
}
public void run() {
while (true){
StdDraw.clear(StdDraw.BLACK);
StdDraw.enableDoubleBuffering();
for(Rock r : rockArrayList) {
r.update();
}
for(Paper p : paperArrayList) {
p.update();
}
for(Scissors s : scissorsArrayList) {
s.update();
}
for(int i = 0; i < paperArrayList.size(); i++) {
for(int j = 0; j < rockArrayList.size(); j++) {
if(paperArrayList.get(i).doesCollideWith(rockArrayList.get(j))) {
paperArrayList.add(new Paper(rockArrayList.get(j).getX(), rockArrayList.get(j).getY(),speedX,speedY));
paperArrayList.get(paperArrayList.size()-1).changeSpeedX(-1);
rockArrayList.remove(j);
}
}
}
for(int i = 0; i < rockArrayList.size(); i++) {
for(int j = 0; j < scissorsArrayList.size(); j++) {
if(rockArrayList.get(i).doesCollideWith(scissorsArrayList.get(j))) {
rockArrayList.add(new Rock(scissorsArrayList.get(j).getX(), scissorsArrayList.get(j).getY(),speedX,speedY));
rockArrayList.get(rockArrayList.size()-1).changeSpeedY(-1);
scissorsArrayList.remove(j);
}
}
}
for(int i = 0; i < scissorsArrayList.size(); i++) {
for(int j = 0; j < paperArrayList.size(); j++) {
if(scissorsArrayList.get(i).doesCollideWith(paperArrayList.get(j))) {
scissorsArrayList.add(new Scissors(paperArrayList.get(j).getX(), paperArrayList.get(j).getY(),speedX,speedY));
scissorsArrayList.get(scissorsArrayList.size()-1).changeSpeedY(-1);
paperArrayList.remove(j);
}
}
}
if((rockArrayList.isEmpty() && paperArrayList.isEmpty()) || (rockArrayList.isEmpty() && scissorsArrayList.isEmpty()) || (paperArrayList.isEmpty() && scissorsArrayList.isEmpty()) )
break;
for(Rock r : rockArrayList)
r.draw();
for(Paper p : paperArrayList)
p.draw();
for(Scissors s : scissorsArrayList)
s.draw();
StdDraw.show();
StdDraw.pause(20);
}
}
}
public class Rock implements Collideable {
int x;
int y;
int speedX;
int speedY;
public Rock(int x, int y, int speedX, int speedY){
this.x = x;
this.y = y;
this.speedX = speedX;
this.speedY = speedY;
}
public void draw(){
StdDraw.picture(x,y,"res/rock.png", 20, 20);
}
public void update(){
x += speedX;
y += speedY;
if(x+speedX >= Game.size || x+speedX<=0)
speedX *= -1;
if(y+speedY >= Game.size || y+speedY<=0)
speedY*=-1;
}
@Override
public int getX() {
return x;
}
@Override
public int getY() {
return y;
}
public void changeSpeedX(int speedX){
this.speedX *= speedX;
}
public void changeSpeedY(int speedY){
this.speedY *= speedY;
}
@Override
public boolean doesCollideWith(Collideable collideable){
if(Math.abs(collideable.getX()-this.x)<10){
return Math.abs(collideable.getY() - this.y) < 10;
}
return false;
}
}
public class Paper implements Collideable {
int x;
int y;
int speedX;
int speedY;
public Paper(int x, int y, int speedX, int speedY){
this.x = x;
this.y = y;
this.speedX = speedX;
this.speedY = speedY;
}
public void draw(){
StdDraw.picture(x,y,"res/paper.png",20,20);
}
public void update(){
x += speedX;
y += speedY;
if(x+speedX >= Game.size || x+speedX<=0)
speedX *= -1;
if(y+speedY >= Game.size || y+speedY<=0)
speedY*=-1;
}
@Override
public int getX() {
return x;
}
@Override
public int getY() {
return y;
}
public void changeSpeedX(int speedX){
this.speedX *= speedX;
}
public void changeSpeedY(int speedY){
this.speedY *= speedY;
}
@Override
public boolean doesCollideWith(Collideable collideable){
if(Math.abs(collideable.getX()-this.x)<10){
return Math.abs(collideable.getY() - this.y) < 10;
}
return false;
}
}
public class Scissors implements Collideable {
int x;
int y;
int speedX;
int speedY;
public Scissors(int x, int y, int speedX, int speedY){
this.x = x;
this.y = y;
this.speedX = speedX;
this.speedY = speedY;
}
public void draw(){
StdDraw.picture(x,y,"res/scissors.png",20,20);
}
public void update(){
x += speedX;
y += speedY;
if(x+speedX >= Game.size || x+speedX<=0)
speedX *= -1;
if(y+speedY >= Game.size || y+speedY<=0)
speedY*=-1;
}
@Override
public int getX() {
return x;
}
@Override
public int getY() {
return y;
}
public void changeSpeedX(int speedX){
this.speedX *= speedX;
}
public void changeSpeedY(int speedY){
this.speedY *= speedY;
}
@Override
public boolean doesCollideWith(Collideable collideable){
if(Math.abs(collideable.getX()-this.x)<10){
return Math.abs(collideable.getY() - this.y) < 10;
}
return false;
}
}
public interface Collideable {
public boolean doesCollideWith(Collideable collideable);
public int getX();
public int getY();
}
因此,#1,在 HashSet 中使用 .contains() 比在 ArrayList 中使用 .contains() 效率更高(O(1) vs O(n))。因此,您应该使用 HashSet(或者可能是 TreeSet,您可以在 oracle 或 smth 上了解有关这些的更多信息)来跟踪它们的位置。
然后,使用pairs(也请阅读这些)来存储数据,并获取一组岩石(假设您当前正在检查剪刀和岩石碰撞)并检查每个剪刀的坐标Pair是否包含在HashSet中。利用这些坐标,您可以更改这些坐标处的每块石头/纸。您可以对其他检查重复此过程。
因为您想要检查对象何时位于坐标的距离内,所以您可能必须将所有坐标除以 10 或您想要的半径,并且您可能希望首先执行此操作您添加到包含石头/布/剪刀的集合中的所有坐标,以避免将来出现烦恼。您可能需要对代码进行大量更改,但这是我认为可行的方式。