JPCT: Einfaldur bílaleikur

Markmið: Að búa til og nota viðmót fyrir grafískan þrívíddarheim, í þessu tilfelli bílaleikur sem skrifaður er með hjálp JPCT (sjá neðar).
Forkröfur eru: grunnþekking á Java og hlutbundinni forritun
Tól sem þarf: Java SDK 1.4.2, JPCT og einhvert þróunarumhverfi t.d. Eclipse


JPCT er forritunarviðmót fyrir þrívíddarvél sem skrifuð er í JAVA. JPCT styður bæði OpenGL og hugbúnað til að varpa þrívídd á skjá (e. render). Það sem ætlunin er að gera í þessum leiðbeiningum er að sýna hvernig nota má tilbúinn þrívíddarheim sem skrifaður hefur verið í JPCT og búa til viðmót á hann. Í okkar tilfelli þá verður viðmótið í formi einfaldra skipana eins og "áfram", "stopp" og "beygja til hægri". Hér að ofan gefur svo að líta hvernig herlegheitin koma til með að líta út.

Við ætlum ekki að fara út í einstakar einingar JPCT hér en þeir sem vilja lesa sig meira til um það og skoða í hvað hægt er að nýta JPCT, geta nálgast frekari upplýsingar hér.

Til að varpa frekara ljósi á heiminn sem við ætlum að nota þá ætlum við að skoða hvern hluta fyrir sig og fjalla lítillega um hvern þeirra. Þeir eru:

  • CarTest - setur upp ramman og einingar leiksins sem birtir leikinn á skjánum
  • Car - bíll sem samanstendur af fjórum hjólum og "boddíi"
  • Entity - viðmót sem allir hlutar leikjaheimsins þurfa að útfæra
  • SkidMark - er hjólfar sem bíllinn skilur eftir sig
  • SkidMarkManager - sér um að birta x fjölda hjólfara fyrir aftan bílinn
  • AbstractEntity - abstract hlutur sem heimurinn okkar getur birt. Hver hlutur getur farið aftur á bak og áfram

Forritið sem við ætlum að smíða sér um það að taka inn skipanir frá notanda í gegnum glugga og láta bílinn bregðast við þeim. Við ætlum að útfæra þetta forrit sem hlut sem keyrir aðskilinn frá leikjaheiminum sjálfum. Við ætlum að styðjast við dæmi sem fylgir með JPCT sem má finna undir examples\car\, þar sem JPCT var sett upp.

Við ætlum að byrja á því að gera smávægilegar breytingar á CarTest.java. Með því að bæta við nokkrum „Get-Set"-föllum getum fáum við aðgang að stöðu bílsins úr CommandWindow. Við þurfum líka að breyta aðgangi að switchoptions fallinu í public , úr private.

public  boolean isLeft()
{ return left; }
public  void setLeft( boolean left )
{ this.left = left; }
public  boolean isRight()
{ return right; }
public  void setRight( boolean right )
{ this.right = right; }
public  boolean isForward()
{ return forward; }
public  void setForward( boolean forward )
{ this.forward = forward; }
public  boolean isBack()
{ return back; }
public  void setBack( boolean back )
{ this.back = back; }
public  boolean isExit()
{ return exit; }
public  void setExit( boolean exit )
{ this.exit = exit; }

Þar sem forritið okkar er útfært sem hlutur, þarf að byrja á að búa til nýjan klasa og nýja skrá fyrir hann. Þar sem forritið okkar er lítill gluggi sem maður slær inn skipanir í, er viðeigandi að láta klasann heita CommandWindow og þar af leiðandi láta skránna heita CommandWindow.java. Pakkarnir sem við þurfum eru eftirfarandi:

import javax.swing.*;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.util.StringTokenizer;

Klasinn sem við ætlum að gera þarf að erfa JFrame, en það er notað til að búa til glugga. Einnig ætlum við að útfæra KeyListener skilin, en þau notum við til að taka við inslætti.

public class Commandwindow extends JFrame implements KeyListener
{
	CarTest _cartest;
	JTextField commandField = new JTextField( 50 );

	public CommandWindow( CarTest cartest )
	{
		_cartest = cartest;

		this.getContentPane().add( commandField );
		commandField.addKeyListener( this );
		this.pack();
		this.setResizable( false );
		this.setVisible( true );
	}

Þessi smiður tekur inn tilvik af CarTest og geymum það í klasabreytu (e. member variable) vegna þess að við ætlum að nota það til að stýra bílnum. Þetta kann að hljóma dálítið undarlegt en þetta er einfaldasta leiðin til þess að stýra bílnum með skipunum úr glugga án þess að stöðva keyrslu heimsins á meðan. Við búum svo til gluggan sjálfan sem inniheldur einn textaglugga og setjum á hann takkahlustara (e. keylistener).

Til þess að geta beitt skipunum notanda, sem við tökum inn úr glugganum, á heiminn , þurfum við að vinna úr þeim.

public void executeCommand( String command )
{
    try
    {
        StringTokenizer token = new StringTokenizer( command );

        while ( token.hasMoreTokens() )
        {
            String commandPart = token.nextToken();

            if ( commandPart.equals( "left" ) )
            {
                if ( _cartest.isLeft() )
                {
                    if ( _cartest.isRight() )
                    {
                        _cartest.setRight( false );
                    }
                    _cartest.setLeft( false );
                }
                else
                {
                    _cartest.setLeft( true );
                }
            }
            else if ( commandPart.equals( "right" ) )
            {
                if ( _cartest.isRight() )
                {
                    if ( _cartest.isLeft() )
                    {
                        _cartest.setLeft( false );
                    }
                    _cartest.setRight( false );
                }
                else
                {
                    _cartest.setRight( true );
                }
            }

            if ( commandPart.equals( "forward" ) )
            {
                if ( _cartest.isForward() )
                {
                    _cartest.setForward( false );
                }
                else
                {
                    _cartest.setForward( true );
                }
            }
        }
    }
    catch ( Exception e )
    {
        System.out.println( "Exception: " + e.getMessage() );
        e.printStackTrace();
    }
}

Hér höfum við útfært fall sem skilur þrjár tegundir af skipunum þ.e. "left", "right" og "forward. Eins og sést þá pössum við upp á að ekki sé hægt að beygja bæði til hægri og vinstri á sama tíma. Nú er bara eitt vandamál eftir. Til þess að komast að því hvenær notandi hefur slegið inn skipun og vill að hún sé framkvæmd þá þurfum við að útfæra takkahlustara (hér koma KeyListener skilin til staðar)

public void keyTyped( KeyEvent e )
{
    if ( e.getKeyChar() == '\n' )
    {
        // grípum enter
        executeCommand( commandField.getText() );
    }
    else if ( e.getKeyCode() == '\u001B' )
    {
        // grípum escape
        _cartest.setExit( true );
    }
    else if ( e.getKeyChar() == 'x' )
    {
        // grípum stafinn x
        _cartest.switchOptions();
    }
}

Þá er ekkert eftri nema bara að bæta við „Dummy" föllum til að klára KeyListener skilin

public void keyPressed( KeyEvent e )
    {  }
    public void keyReleased( KeyEvent e )
    {  }
}

Nú þegar við höfum útfært klasann sem á að framkvæma skipanir á heiminum þá þurfum við að láta heiminn vita af þeim klasa og passa að hann sé gangsettur á sama tíma og leikurinn sjálfur. Það gerum við með því að bæta eftirfarandi kóða inn í smið(e. CarTest( String[] args ) CarTest klasans.

new CommandWindow( this );

Hér búum við til nýtt tilvik af skipanaglugganum okkar og sendum tilvik af klasanum CarTest inn sem færibreytu.

Nú ætti að vera ljóst hvernig hægt er að búa til forrit sem tekur inn skipanir og framkvæmir þær á tilbúnum heimi. Margir kunna að velta því fyrir sér af hverju ekki var bara hlustað á takkana á lyklaborðinu beint í stað þess að vera að greina skipanir. Ástæðan fyrir þessu er einföld. Eftir að hafa gert forritið með þessum hætti er auðvelt að breyta því og láta það taka inn skipanir í formi tals. Þá breytingu verður hins vegar ekki fjallað um að þessu sinni. Þeir sem hafa áhuga á að kynna sér frekar hvernig þetta er framkvæmt eru beðnir um að kynna sér Sphinx-4 talgreininnn eða lesa leiðbeingar þess efnis, sem birtar verða á þessari síðu innan tíðar. Þeir sem hafa áhuga á að skoða þann kóða sem notaður er í þessum leiðbeiningum geta nálgast hann hér.

 

CADIA
cadia@ru.is  |  Ofanleiti 2, IS -103 Reykjavík
Tel: +354 510 6427  |  Fax: +354 510 6201