天天看點

《Java 2D遊戲程式設計入門》—— 2.4 相對滑鼠移動

本節書摘來異步社群《java 2d遊戲程式設計入門》一書中的第2章,第2.4節,作者:【美】timothy wright(萊特),更多章節内容可以通路雲栖社群“異步社群”公衆号檢視。

對于圖2.3所示的目前的滑鼠輸入類來說,有一個問題。首先,它看上去似乎挺明顯,但是,隻有在滑鼠位于視窗之中的時候,程式才接受滑鼠事件。一旦滑鼠離開了視窗,滑鼠指針的坐标位置在應用程式中就變得不再有效。更為糟糕的是,在全屏模式中,當滑鼠到達螢幕邊緣的時候,它會直接停下來,而不會繼續注冊事件。根據應用程式的需要,可能需要相對滑鼠移動。好在,更新滑鼠輸入類以支援相對滑鼠移動并不難。

《Java 2D遊戲程式設計入門》—— 2.4 相對滑鼠移動

relativemouseinput類位于javagames.util包中,建構于前面示例中的類的基礎之上,并且添加了相對滑鼠移動。為了實作這一點,用robot類來将滑鼠保持在視窗的中央。還有監聽滑鼠事件的swing元件,可以計算視窗的中央位置,并且從相對視窗坐标轉換為絕對螢幕坐标。如果滑鼠光标總是位于視窗的中央,那麼,它可能不會離開,并且視窗将總是接受滑鼠事件。如下代碼保持滑鼠居中:

package javagames.util;

import java.awt.*;

import java.awt.event.*;

import javax.swing.*;

public class relativemouseinput

implements mouselistener, mousemotionlistener, mousewheellistener {

  private static final int button_count = 3;

  private point mousepos;

  private point currentpos;

  private boolean[] mouse;

  private int[] polled;

  private int notches;

  private int pollednotches;

  private int dx, dy;

  private robot robot;

  private component component;

  private boolean relative;

  public relativemouseinput( component component ) {

    this.component = component;

    try {

      robot = new robot();

    } catch( exception e ) {

      // handle exception [game specific]

      e.printstacktrace();

    }

    mousepos = new point( 0, 0 );

    currentpos = new point( 0, 0 );

    mouse = new boolean[ button_count ];

    polled = new int[ button_count ];

  }

  public synchronized void poll() {

    if( isrelative() ) {

      mousepos = new point( dx, dy );

    } else {

      mousepos = new point( currentpos );

    dx = dy = 0;

    pollednotches = notches;

    notches = 0;

    for( int i = 0; i < mouse.length; ++i ) {

      if( mouse[i] ) {

        polled[i]++;

      } else {

        polled[i] = 0;

      }

  public boolean isrelative() {

    return relative;

  public void setrelative( boolean relative ) {

    this.relative = relative;

    if( relative ) {

      centermouse();

  public point getposition() {

    return mousepos;

  public int getnotches() {

    return pollednotches;

  public boolean buttondown( int button ) {

    return polled[ button - 1 ] > 0;

  public boolean buttondownonce( int button ) {

    return polled[ button - 1 ] == 1;

  public synchronized void mousepressed( mouseevent e ) {

    int button = e.getbutton() - 1;

    if( button >= 0 && button < mouse.length ) {

      mouse[ button ] = true;

  public synchronized void mousereleased( mouseevent e ) {

      mouse[ button ] = false;

  public void mouseclicked( mouseevent e ) {

    // not needed

  public synchronized void mouseentered( mouseevent e ) {

    mousemoved( e );

  public synchronized void mouseexited( mouseevent e ) {

  public synchronized void mousedragged( mouseevent e ) {

  public synchronized void mousemoved( mouseevent e ) {

      point p = e.getpoint();

      point center = getcomponentcenter();

      dx += p.x - center.x;

      dy += p.y - center.y;

      currentpos = e.getpoint();

  public synchronized void mousewheelmoved( mousewheelevent e ) {

    notches += e.getwheelrotation();

  private point getcomponentcenter() {

    int w = component.getwidth();

    int h = component.getheight();

    return new point( w / 2, h / 2 );

  private void centermouse() {

    if( robot != null && component.isshowing() ) {

      swingutilities.convertpointtoscreen( center, component );

      robot.mousemove( center.x, center.y );

}<code>`</code>

relativemouseexample位于javagames.input包中,如圖2.4所示,它針對滑鼠輸入類測試更新的新功能。

《Java 2D遊戲程式設計入門》—— 2.4 相對滑鼠移動

如下的代碼,通過将光标圖像設定為在運作時建立的一個空的光标,進而關閉滑鼠光标。

package javagames.input;

import java.awt.image.*;

import javagames.util.*;

public class relativemouseexample extends jframe

          implements runnable {

  private framerate framerate;

  private bufferstrategy bs;

  private volatile boolean running;

  private thread gamethread;

  private canvas canvas;

  private relativemouseinput mouse;

  private keyboardinput keyboard;

  private point point = new point( 0, 0 );

  private boolean disablecursor = false;

  public relativemouseexample() {

    framerate = new framerate();

  protected void createandshowgui() {

    canvas = new canvas();

    canvas.setsize( 640, 480 );

    canvas.setbackground( color.black );

    canvas.setignorerepaint( true );

    getcontentpane().add( canvas );

    settitle( "relative mouse example" );

    setignorerepaint( true );

    pack();

    // add key listeners

    keyboard = new keyboardinput();

    canvas.addkeylistener( keyboard );

    // add mouse listeners

    // for full screen : mouse = new relativemouseinput( this );

    mouse = new relativemouseinput( canvas );

    canvas.addmouselistener( mouse );

    canvas.addmousemotionlistener( mouse );

    canvas.addmousewheellistener( mouse );

    setvisible( true );

    canvas.createbufferstrategy( 2 );

    bs = canvas.getbufferstrategy();

    canvas.requestfocus();

    gamethread = new thread( this );

    gamethread.start();

  public void run() {

    running = true;

    framerate.initialize();

    while( running ) {

      gameloop();

  private void gameloop() {

    processinput();

    renderframe();

    sleep( 10l );

  private void renderframe() {

    do {

      do {

        graphics g = null;

        try {

          g = bs.getdrawgraphics();

          g.clearrect( 0, 0, getwidth(), getheight() );

          render( g );

        } finally {

          if( g != null ) {

            g.dispose();

          }

        }

      } while( bs.contentsrestored() );

      bs.show();

    } while( bs.contentslost() );

  private void sleep( long sleep ) {

      thread.sleep( sleep );

    } catch( interruptedexception ex ) { }

  private void processinput() {

    keyboard.poll();

    mouse.poll();

    point p = mouse.getposition();

    if( mouse.isrelative() ) {

      point.x += p.x;

      point.y += p.y;

      point.x = p.x;

      point.y = p.y;

    // wrap rectangle around the screen

    if( point.x + 25 &lt; 0 )

      point.x = canvas.getwidth() - 1;

    else if( point.x &gt; canvas.getwidth() - 1 )

      point.x = -25;

    if( point.y + 25 &lt; 0 )

      point.y = canvas.getheight() - 1;

    else if( point.y &gt; canvas.getheight() - 1 )

      point.y = -25;

    // toggle relative

    if( keyboard.keydownonce( keyevent.vk_space ) ) {

      mouse.setrelative( !mouse.isrelative() );

    // toggle cursor

    if( keyboard.keydownonce( keyevent.vk_c ) ) {

      disablecursor = !disablecursor;

      if( disablecursor ) {

        disablecursor();

        // setcoursor( cursor.default_cursor ) is deprecated

        setcursor( new cursor( cursor.default_cursor ) );

  private void render( graphics g ) {

    g.setcolor( color.green );

    framerate.calculate();

    g.drawstring( mouse.getposition().tostring(), 20, 20 );

    g.drawstring( "relative: " + mouse.isrelative(), 20, 35 );

    g.drawstring( "press space to switch mouse modes", 20, 50 );

    g.drawstring( "press c to toggle cursor", 20, 65 );

    g.setcolor( color.white );

    g.drawrect( point.x, point.y, 25, 25 );

  private void disablecursor() {

    toolkit tk = toolkit.getdefaulttoolkit();

    image image = tk.createimage( "" );

    point point = new point( 0, 0 );

    string name = "canbeanything";

    cursor cursor = tk.createcustomcursor( image, point, name );

    setcursor( cursor );

  protected void onwindowclosing() {

      running = false;

      gamethread.join();

    } catch( interruptedexception e ) {

    system.exit( 0 );

  public static void main( string[] args ) {

    final relativemouseexample app = new relativemouseexample();

    app.addwindowlistener( new windowadapter() {

      public void windowclosing( windowevent e ) {

        app.onwindowclosing();

    });

    swingutilities.invokelater( new runnable() {

      public void run() {

        app.createandshowgui();