Swing Java的同步问题
我正试图实现一个简单的足球游戏。我有一门球类课程:
import java.util.ArrayList;
import java.util.Random;
public class Ball {
Team lastHitBy;
public int curr_x;
public int curr_y;
public int count = 0;
int neg_y = 0;
boolean neg_x;
int prev_x;
int prev_y;
int speed;
public Ball(int curr_x, int curr_y) {
this.curr_x = curr_x;
this.curr_y = curr_y;
this.prev_x = curr_x - 1;
this.prev_y = curr_y - 1;
}
void update_position(int x, int y) {
System.out.println("Update:" + x + " "+y);
this.prev_x = this.curr_x;
this.prev_y = this.curr_y;
this.curr_x = x;
this.curr_y = y;
}
public Player check_collisions(Player[] players) {
for (int i = 0; i < players.length; i++) {
// first check if any intersection
if (this.curr_x + Constants.ball_r >= players[i].x &&
this.curr_x + Constants.ball_r <= players[i].x + Constants.player_width &&
this.curr_y + Constants.ball_r >= players[i].y &&
this.curr_y + Constants.ball_r <= players[i].y + Constants.player_height) {
return players[i];
}
}
return null;
}
public void move_step() {
count += 1;
System.out.println(count+" Px,y:" + this.prev_x + "," + this.prev_y + " -- " + this.curr_x + "," + this.curr_y);
System.out.flush();
boolean left = false, right = false, top = false, bottom = false;
if(this.curr_x >= Constants.screen_width - Constants.ball_r / 2){
right = true;
}
if(this.curr_x <= Constants.ball_r / 2){
left = true;
}
if(this.curr_y >= Constants.screen_height - Constants.ball_r / 2){
bottom = true;
}
if(this.curr_y <= Constants.ball_r / 2){
top = true;
}
double slope = (curr_y - prev_y) / (curr_x - prev_x);
if (right || left || bottom || top) slope = -slope;
if (right && bottom) this.neg_y = -1;
else if (right && top) this.neg_y = 1;
else if (left && top) this.neg_y = 1;
else if (left && bottom) this.neg_y = -1;
else if (right || left || bottom || top) this.neg_y = 0;
if (right) this.neg_x = true;
if (left) this.neg_x = false;
double c = (curr_y - slope * curr_x);
int new_x = curr_x + Constants.step;
if (this.neg_x) new_x = curr_x - Constants.step;
int new_y = (int) (slope * new_x + c);
if (this.neg_y == -1) { new_y = prev_y - Constants.step; }
if (this.neg_y == 1) { new_y = prev_y + Constants.step; }
this.prev_x = this.curr_x;
this.prev_y = this.curr_y;
update_position(new_x, new_y);
}
// @assumption: This method is called after a collision.
public void reflection(Player player, Player[] players) {
double slope = - (curr_y - prev_y) / (curr_x - prev_x);
double c = (curr_y - slope * curr_x);
int new_x, new_y;
boolean left = false, right = false;
if (curr_x > prev_x) new_x = curr_x + Constants.step;
else new_x = curr_x - Constants.step;
if (this.curr_y >= player.y &&
this.curr_y <= player.y + Constants.player_height &&
this.curr_x <= player.x + Constants.player_width / 2) {
left = true;
this.neg_x = true;
}
else if (this.curr_y >= player.y &&
this.curr_y <= player.y + Constants.player_height &&
this.curr_x >= player.x + Constants.player_width / 2) {
right = true;
this.neg_x = false;
}
if (left) {
// if left collision pass to the next player/obstacle
System.out.println("Passed: ");
ArrayList<Player> passTo= new ArrayList<Player>();
for (int i=0;i<players.length;i++)
{
if (players[i].x>player.x)
{
passTo.add(players[i]);
}
}
if (passTo.size() != 0) {
Random randomPlayer=new Random();
int randomIndex=randomPlayer.nextInt(passTo.size());
int error=(int)(Math.random()*10)-5;
int error_x=(passTo.get(randomIndex).x+error);
int error_y=(passTo.get(randomIndex).y+error);
new_x += Constants.player_width + 5;
double pass_slope = (double)(curr_y - error_y) / (double)(curr_x - error_x);
double pass_c = ((double)curr_y - (double)(pass_slope * curr_x));
new_y = (int) (pass_slope * (new_x) + pass_c);
System.out.println(pass_c + " " + pass_slope + " " + new_y);
this.neg_x = false;
update_position(new_x, new_y);
return;
}
else {
Constants.speed = (int) (Math.random() * 8) + 2;
System.out.println("Kicked!\n");
int goal = Constants.screen_height/2;
int goal_error = (int)(Math.random()*20)-5;
int goalx = Constants.screen_width;
int error_goaly = goal+goal_error;
new_x += Constants.player_width + 5;
double kick_slope = (double)(curr_y - error_goaly) / (double)(curr_x - goalx);
double kick_c = ((double)curr_y - (double)(kick_slope * curr_x));
new_y = (int) (kick_slope * (new_x) + kick_c);
this.neg_x = false;
System.out.println("Kicked at : " + new_x + "," + new_y);
update_position(new_x, new_y);
return;
}
}
if (right) {
new_x = curr_x + Constants.step;
}
new_y = (int) (slope * new_x + c);
update_position(new_x, new_y);
}
}
我有一个使用此ball类渲染的面板:
package BigBalls;
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.geom.Line2D;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import javax.imageio.ImageIO;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;
import sun.font.FileFont;
import foosball.commonClasses.*;
public class BouncyBall extends JPanel implements ActionListener, KeyListener {
int speed = 10;
int frameCount = 0;
boolean player_has_moved = true;
int oneX = 100, oneY = 100;
Ball b;
Rod[] rods = new Rod[8];
public Team[] teams = new Team[2];
boolean firstPaint = true;
Player[] players_left = new Player[11];
Player[] players_right = new Player[11];
Timer t;
JFrame f;
Image background;
private static final long serialVersionUID = 1L;
public BouncyBall() {
b = new Ball(10, 10);
this.repaint();
this.t = new Timer(2, this);
t.start();
addKeyListener((KeyListener) this);
setFocusable(true);
for (int i = 0; i < players_left.length; i++) {
players_left[i] = new Player(teams[0], 1000, 1000, i);
}
for (int i = 0; i < players_right.length; i++) {
players_right[i] = new Player(teams[1], 1000, 1000, i);
}
teams[0] = new Team(2, 5, 3, players_left, true);
teams[1] = new Team(2, 5, 3, players_right, false);
rods[0] = new Rod(100, teams[0], 0, 1);
rods[1] = new Rod(200, teams[0], 1, 2);
rods[2] = new Rod(300, teams[1], 8, 3);
rods[3] = new Rod(400, teams[0], 3, 5);
rods[4] = new Rod(500, teams[1], 3, 5);
rods[5] = new Rod(600, teams[0], 8, 3);
rods[6] = new Rod(700, teams[1], 1, 2);
rods[7] = new Rod(800, teams[1], 0, 1);
initUI();
try {
background = ImageIO.read(new File("img/background.jpg"));
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public void animate() {
Player left_p = this.b.check_collisions(this.teams[0].players);
if (left_p != null)
this.b.reflection(left_p, this.teams[0].players);
this.b.move_step();
this.repaint();
}
public void paintComponent(Graphics g){
frameCount+=1;
super.paintComponent(g);
//if (frameCount == 30) { this.t.setDelay((int)(Constants.speed)); frameCount = 0; }
g.drawImage(this.background, 0, 0, 1000, 600, this);
// g.fillRect(5, 84, 770, 450);
// g.setColor(Color.green);
// g.fillRect(5, 5, 900, 500);
int i,j,dist;
for (i = 0; i < 8; i++)
{
dist = (500/(rods[i].number_of_players+1));
int Ycoordinate=dist;
for (j=0;j<rods[i].number_of_players;j++)
{
if (i == 0 || i == 1 || i == 3 || i == 5)
g.setColor(Color.red);
else
g.setColor(Color.black);
if (rods[i].team.players[rods[i].start + j].y == 1000) {
rods[i].team.players[rods[i].start + j].x = rods[i].x - 5;
rods[i].team.players[rods[i].start + j].y = Ycoordinate - 10;
g.drawRect((rods[i].x - 5), (Ycoordinate-10), Constants.player_height, Constants.player_width);
g.fillRect((rods[i].x - 5), (Ycoordinate-10), Constants.player_height, Constants.player_width);
Ycoordinate=Ycoordinate+dist;
} else {
g.drawRect((rods[i].x - 5), (rods[i].team.players[rods[i].start + j].y), Constants.player_height, Constants.player_width);
g.fillRect((rods[i].x - 5), (rods[i].team.players[rods[i].start + j].y), Constants.player_height, Constants.player_width);
}
}
}
// Draw ball
g.setColor(Color.yellow);
//player_has_moved = false;
g.fillOval(this.b.curr_x, this.b.curr_y, 10, 10);
}
private void initUI() {
//setTitle("Foosball");
setSize(1000,650);
//setLocationRelativeTo(null);
//setDefaultCloseOperation(EXIT_ON_CLOSE);
}
public static void main(String[] args) {
JPanel f = new BouncyBall();
f.setVisible(true);
}
@Override
public void actionPerformed(ActionEvent arg0) {
this.animate();
}
@Override
public void keyPressed(KeyEvent arg0) {
if (arg0.getKeyCode() == KeyEvent.VK_UP) {
ArrayList<Integer> al = new ArrayList<Integer>();
for (int i = 0; i < teams[0].players.length; i++) {
if (teams[0].players[i].y <= Constants.step+10) {
al.add(teams[0].players[i].x);
}
} for (int i = 0; i < teams[0].players.length; i++) {
if (!al.contains(teams[0].players[i].x)) {
teams[0].players[i].y -= Constants.step_player;
}
}
}
if (arg0.getKeyCode() == KeyEvent.VK_DOWN) {
ArrayList<Integer> al = new ArrayList<Integer>();
for (int i = 0; i < teams[0].players.length; i++) {
if (teams[0].players[i].y >= Constants.screen_height + Constants.step) {
al.add(teams[0].players[i].x);
}
} for (int i = 0; i < teams[0].players.length; i++) {
if (!al.contains(teams[0].players[i].x)) {
teams[0].players[i].y += Constants.step_player;
}
}
}
}
@Override
public void keyReleased(KeyEvent arg0) {
// TODO Auto-generated method stub
}
@Override
public void keyTyped(KeyEvent arg0) {
// TODO Auto-generated method stub
}
}
我面临的bug非常奇怪:
首先,打印球中的语句。move_next()打印两次(计数值相同)。我猜这是因为Swing使用了一些我不知道的内部线程
当球从左侧撞击玩家对象时,球将获得预期的新方向和该方向上的一组新坐标(预期),但随后球将改变其坡度并开始沿平行于x轴的方向移动
错误日志:
180 Px,y:188,188 -- 189,189
Update:190 190
181 Px,y:189,189 -- 190,190
Update:191 191
181 Px,y:189,189 -- 190,190
Update:191 191
Passed:
211.59803921568627 -0.10784313725490197 188
Update:217 188
182 Px,y:191,191 -- 217,188
Update:218 188
182 Px,y:190,190 -- 191,191
Update:192 192
注意最后2个“Px”打印语句
共 (0) 个答案