好吧所以我正在创建一个基于游戏的简单瞄准游戏:CS:GO和我一直有关于创建主菜单和使用MouseListener的问题。这是Game类,其中包含游戏状态的枚举:
/*
* This code is protected under the Gnu General Public License (Copyleft), 2005 by
* IBM and the Computer Science Teachers of America organization. It may be freely
* modified and redistributed under educational fair use.
*/
import java.awt.Color;
import java.awt.Cursor;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.util.ArrayList;
import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.Timer;
/**
* An abstract Game class which can be built into Pong.<br>
* <br>
* The default controls are for "Player 1" to move left and right with the
* 'Z' and 'X' keys, and "Playr 2" to move left and right with the 'N' and
* 'M' keys.<br>
* <br>
* Before the Game begins, the <code>setup</code> method is executed. This will
* allow the programmer to add any objects to the game and set them up. When the
* game begins, the <code>act</code> method is executed every millisecond. This
* will allow the programmer to check for user input and respond to it.
*
* @see GameObject
*/
public abstract class Game extends JFrame {
private boolean _isSetup = false;
private boolean _initialized = false;
private ArrayList _ObjectList = new ArrayList();
private static Timer _t;
public static enum STATE{
MENU,
MENU1,
GAME
};
public static STATE State = STATE.MENU;
//
/**
* <code>true</code> if the 'Z' key is being held down
*/
private boolean p1Left = false;
/**
* <code>true</code> if the 'X' key is being held down.
*/
private boolean p1Right = false;
/**
* <code>true</code> if the 'N' key is being held down.
*/
private boolean p2Left = false;
/**
* <code>true</code> if the 'M' key is being held down.
*/
private boolean p2Right = false;
/**
* Returns <code>true</code> if the 'Z' key is being pressed down
*
* @return <code>true</code> if the 'Z' key is being pressed down
*/
public boolean RKeyPressed() {
return p1Left;
}
/**
* Returns <code>true</code> if the 'X' key is being pressed down
*
* @return <code>true</code> if the 'X' key is being pressed down
*/
public boolean XKeyPressed() {
return p1Right;
}
/**
* Returns <code>true</code> if the 'N' key is being pressed down
*
* @return <code>true</code> if the 'N' key is being pressed down
*/
public boolean NKeyPressed() {
return p2Left;
}
/**
* Returns <code>true</code> if the 'M' key is being pressed down
*
* @return <code>true</code> if the 'M' key is being pressed down
*/
public boolean MKeyPressed() {
return p2Right;
}
/**
* When implemented, this will allow the programmer to initialize the game
* before it begins running
*
* Adding objects to the game and setting their initial positions should be
* done here.
*
* @see GameObject
*/
public abstract void setup();
/**
* When the game begins, this method will automatically be executed every
* millisecond
*
* This may be used as a control method for checking user input and
* collision between any game objects
*/
public abstract void act();
/**
* Sets up the game and any objects.
*
* This method should never be called by anything other than a <code>main</code>
* method after the frame becomes visible.
*/
public void initComponents() {
getContentPane().setBackground(Color.black);
setup();
for (int i = 0; i < _ObjectList.size(); i++) {
GameObject o = (GameObject)_ObjectList.get(i);
o.repaint();
}
_t.start();
}
/**
* Adds a game object to the screen
*
* Any added objects will have their <code>act</code> method called every
* millisecond
*
* @param o the <code>GameObject</code> to add.
* @see GameObject#act()
*/
public void add(GameObject o) {
_ObjectList.add(o);
getContentPane().add(o);
}
/**
* Removes a game object from the screen
*
* @param o the <code>GameObject</code> to remove
* @see GameObject
*/
public void remove(GameObject o) {
_ObjectList.remove(o);
getContentPane().remove(o);
}
/**
* Sets the millisecond delay between calls to <code>act</code> methods.
*
* Increasing the delay will make the game run "slower." The default delay
* is 1 millisecond.
*
* @param delay the number of milliseconds between calls to <code>act</code>
* @see Game#act()
* @see GameObject#act()
*/
public void setDelay(int delay) {
_t.setDelay(delay);
}
/**
* Sets the background color of the playing field
*
* The default color is black
*
* @see java.awt.Color
*/
public void setBackground(Color c) {
getContentPane().setBackground(c);
}
/**
* The default constructor for the game.
*
* The default window size is 400x400
*/
public Game() {
setSize(1280, 720);
getContentPane().setBackground(Color.BLACK);
getContentPane().setLayout(null);
JMenuBar menuBar = new JMenuBar();
JMenu menuFile = new JMenu("File");
JMenuItem menuFileExit = new JMenuItem("Exit");
menuBar.add(menuFile);
menuFile.add(menuFileExit);
setJMenuBar(menuBar);
setTitle("Mid Peek");
addKeyListener(new KeyAdapter()
{
public void keyPressed(KeyEvent e)
{
if (e.getKeyCode() == KeyEvent.VK_ENTER)
{
System.out.println("ENTER key pressed");
State=STATE.GAME;
startGame();
}
}
});
// Add window listener.
addWindowListener (
new WindowAdapter() {
public void windowClosing(WindowEvent e) {
System.exit(0);
}
}
);
menuFileExit.addActionListener(
new ActionListener() {
public void actionPerformed(ActionEvent e) {
System.exit(0);
}
}
);
_t = new Timer(1, new ActionListener() {
public void actionPerformed(ActionEvent e) {
act();
for (int i = 0; i < _ObjectList.size(); i++) {
GameObject o = (GameObject)_ObjectList.get(i);
o.act();
}
}
});
addKeyListener(new KeyListener() {
public void keyTyped(KeyEvent e) {
}
public void keyPressed(KeyEvent e) {
char pressed = Character.toUpperCase(e.getKeyChar());
switch (pressed) {
case 'Z' : p1Left = true; break;
case 'X' : p1Right = true; break;
case 'N' : p2Left = true; break;
case 'M' : p2Right = true; break;
}
}
public void keyReleased(KeyEvent e) {
char released = Character.toUpperCase(e.getKeyChar());
switch (released) {
case 'Z' : p1Left = false; break;
case 'X' : p1Right = false; break;
case 'N' : p2Left = false; break;
case 'M' : p2Right = false; break;
}
}
});
}
/**
* Starts updates to the game
*
* The game should automatically start.
*
* @see Game#stopGame()
*/
public static void startGame() {
_t.start();
}
/**
* Stops updates to the game
*
* This can act like a "pause" method
*
* @see Game#startGame()
*/
public void stopGame() {
_t.stop();
}
/**
* Displays a dialog that says "Player 1 Wins!"
*
*/
public void p1Wins() {
_WinDialog d = new _WinDialog(this, "Player 1 Wins!");
d.setVisible(true);
}
/**
* Displays a dialog that says "Player 2 Wins!"
*
*/
public void p2Wins() {
_WinDialog d = new _WinDialog(this, "Player 2 Wins!");
d.setVisible(true);
}
/**
* Gets the pixel width of the visible playing field
*
* @return a width in pixels
*/
public int getFieldWidth() {
return getContentPane().getBounds().width;
}
/**
* Gets the pixel height of the visible playing field
*
* @return a height in pixels
*/
public int getFieldHeight() {
return getContentPane().getBounds().height;
}
class _WinDialog extends JDialog {
JButton ok = new JButton("OK");
_WinDialog(JFrame owner, String title) {
super(owner, title);
Rectangle r = owner.getBounds();
setSize(200, 100);
setLocation(r.x + r.width / 2 - 100, r.y + r.height / 2 - 50);
getContentPane().add(ok);
ok.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
_WinDialog.this.setVisible(false);
}
});
}
}
}
以下是实际编码,因为Game类来自Pong游戏示例:
import java.awt.AWTException;
import java.awt.Color;
import java.awt.Cursor;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.MouseInfo;
import java.awt.Point;
import java.awt.PointerInfo;
import java.awt.Robot;
import java.awt.Toolkit;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JTextField;
public class GlobalOffensive extends Game{
JLabel rifleOverlay;
JLabel rifleShooting1;
JLabel rifleShooting2;
JLabel pistolOverlay;
JLabel pistolShooting1;
JLabel pistolShooting2;
JLabel backImage;
JLabel Terrorist;
JLabel menu1;
static JLabel open = new JLabel();
private static Menu menu;
private static int timer = 0;
Player p;
Terrorists t;
Terrorists t1;
Terrorists t2;
Terrorists t3;
Terrorists t4;
private static int spawnLimit = 1;
private static int numBots = 0;
private static int spawnTime;
MouseEvent e;
public void setup(){
menu = new Menu();
ImageIcon menu = new ImageIcon("menu1.jpg");
menu1 = new JLabel(menu);
menu1.setSize(1280, 720);
if (State==STATE.MENU || State==STATE.MENU1){
add(menu1);
}
if (State==STATE.GAME){
p = new Player(4, 3);
t = new Terrorists();
//t1 = new Terrorists(100,50);
//t2 = new Terrorists(100,50);
//t3 = new Terrorists(100,50);
//t4 = new Terrorists(100,50);
ImageIcon background = new ImageIcon("DustMid.jpg");
ImageIcon overlay = new ImageIcon("m414mask.png");
ImageIcon bot = new ImageIcon("Terrorist");
Toolkit toolkit = Toolkit.getDefaultToolkit();
Image image = toolkit.getImage("Crosshair.png");
//Creating bot
Terrorist = new JLabel(bot);
Terrorist.setSize(50,100);
add(Terrorist);
//Creating the gun overlay and setting the background
rifleOverlay = new JLabel(overlay);
rifleOverlay.setSize(1280,720);
add(rifleOverlay);
backImage = new JLabel(background);
backImage.setSize(1280, 720);
add(backImage);
//setting the cursor to the cross hair when it is over the background image or the overlay
backImage.setCursor(new Cursor(Cursor.CROSSHAIR_CURSOR));
Cursor c = toolkit.createCustomCursor(image , new Point(backImage.getX(),
backImage.getY()), "Crosshair");
backImage.setCursor (c);
rifleOverlay.setCursor(new Cursor(Cursor.CROSSHAIR_CURSOR));
Cursor d = toolkit.createCustomCursor(image , new Point(rifleOverlay.getX(),
rifleOverlay.getY()), "Crosshair");
rifleOverlay.setCursor (d);
//ImageIcon rifleShooting = new ImageIcon("rifleShooting2.png");
//rifleShooting2 = new JLabel(rifleShooting);
//rifleShooting2.setSize(1280, 720);
//add(rifleShooting2);
}
}
public void act(){
if (State==STATE.GAME){
setDelay(10);
PointerInfo a = MouseInfo.getPointerInfo();
Point b = a.getLocation();
int x = (int) b.getX();
int y = (int) b.getY();
//Rifle follows mouse movement
if (x != 0){
rifleOverlay.setLocation(x-700, 0);
repaint();
}
//Spawn bot
if (numBots <= spawnLimit && timer%60 == 0){
t.spawn();
numBots += 1;
System.out.println("Bot spawned");
spawnTime = timer;
Terrorist.setLocation(549, 404);
repaint();
}
//Shoots the player after set amount of time
if ((timer - spawnTime)%200 == 0){
t.shoots(p);
System.out.println("Bot fired");
}
//Bot disappears after set amount of time
if ((timer - spawnTime)%210 == 0){
System.out.println("Bot ran away");
t.lifeTime(t);
}
//Ammo
if (p.getCurrentAmmo() == 0){
p.reload();
System.out.println("Out of Ammo");
}else if (p.getCurrentAmmo() > 0){
//To fire bullet
if (XKeyPressed() == true){
p.shotsFired(true);
System.out.println("Player fired");
//if(XKeyPressed() == false){
// p.shotsFired(false);
//}
//rifleShooting2.setLocation(x-700, 0);
//repaint();
}
}else if (RKeyPressed() == true){
p.reload();
}
Robot r = null;
try {
r = new Robot();
} catch (AWTException e1) {
// TODO Auto-generated catch block
System.out.println("An error of sorts");
e1.printStackTrace();
}
//If terrorist fires, player takes damage
//if (t.shoots(p) == true){
// p.health(true);
//}
//Game ends if player dies
if (p.dies() == true){
stopGame();
}
timer ++;
}
}
public static void main(String[] args) {
GlobalOffensive p = new GlobalOffensive();
p.initComponents();
p.pack();
p.setVisible(true);
p.setSize(1280, 720);
p.getContentPane().setBackground(Color.BLACK);
}
}
//Spawn location coordinates
//404y
//549x
//526y
//1133x
//301y
//297x
//413
//696
答案 0 :(得分:2)
MouseInfo
不是监控鼠标活动的最佳选择,它提供屏幕坐标的位置,而不是本地/组件坐标,这实际上会让你感到困惑。
相反,您应该使用注册到您有兴趣管理的组件的MouseListener
(可能是MouseMotionListener
,具体取决于您的需要)。
有关详细信息,请参阅How to Write a Mouse Listener。
MouseListener
会自动将鼠标坐标转换为本地(组件)上下文,以使顶部/左侧位置为0x0
。它还会告诉您什么时候发生,所以您不需要经常轮询信息
相反,我会使用JFrame
,可能使用CardLayout
“菜单”面板和“游戏”面板。这样,您可以将两者的功能分开,并将责任隔离到他们自己的类中。
我认为您还会发现密钥绑定API比KeyListener
更可靠。见How to Use Key Bindings