code:
package tennisgame;
import java.awt.*;
import java.awt.event.*;
import java.applet.*;
/**
* TennisGame
* David Sala
*/
public class Applet1 extends Applet {
private Bal bal; // de bal
private Bat bat_1, bat_2; // de rackets
private Field field_1; // tennisveld
private Button startKnop, stopKnop; // start en stop spel
/** Initialization method that will be called after the applet is loaded
* into the browser.
*/
public void init() { // deze methode wordt altijd als eerste aangeroepen door java (automatisch)
// maak een knop aan, voeg een 'listener' toe aan de knop die luistert naar 'gebeurtenissen'
startKnop = new Button("Start");
startKnop.addActionListener(new StartKnopHandler());
stopKnop = new Button("stop");
stopKnop.addActionListener(new StopKnopHandler());
// nu worden ze ook daadwerkelijk opgenomen in het programma
add(startKnop);
add(stopKnop);
// maak het veld en de rackets
field_1 = new Field();
bat_1 = new Bat(30, 5, Color.white);
bat_1.verplaats(100, 100);
bat_2 = new Bat(30, 5, Color.white);
bat_2.verplaats(300, 400);
// startknop heeft de focus, toetsaanslagen worden nu naar startknop doorgestuurd
startKnop.addKeyListener(new ToetsenHandler());
stopKnop.addKeyListener(new ToetsenHandler());
// requestFocus();
}
// deze methode ontvangt van Java de grafische context (Graphics g) en wordt standaard na init() aangeroepen door java
public void paint(Graphics g){
// de grafische context wordt meegestuurd met de methoden, anders kan er niet getekend worden
field_1.teken(g); // teken een veld met de methode 'teken()' van Field
bat_1.teken(g); // idem
bat_2.teken(g); // idem
}
class StartKnopHandler implements ActionListener{
// wordt aangeroepen wanneer je op 'startknop' klikt
public void actionPerformed(ActionEvent e){
bal = new Bal(getGraphics(), 10, Color.yellow, bat_1, bat_2); // maak een nieuwe bal aan, roep de grafische context op met getGraphics()
bal.start(); // start de thread (loopt tegelijkertijd met andere processen, zodat je meerdere dingen 'tegelijk' kan doen
// zoals het verplaatsen van de bal en 'tegelijkertijd' het racket verplaatsen met de toetsen
}
}
class StopKnopHandler implements ActionListener{
public void actionPerformed(ActionEvent e){
bal.nuStoppen();
}
}
// maak een keylistener aan, deze ontvangt toetsaanslagen van het keyboard
class ToetsenHandler extends KeyAdapter implements KeyListener {
// wordt aangeroepen wanneer er een 'toets' is ingedrukt.
public void keyPressed(KeyEvent e){
int keyCode = e.getKeyCode(); // zoek de 'keycode' op, deze vertelt je welke toets is ingedrukt
switch(keyCode){
case KeyEvent.VK_RIGHT: // verplaats bat_1 naar rechts als toets 'VK_RIGHT' is ingedrukt.
if(bat_1.getX() < 350){ // kan niet uit het veld 'verplaatsen'
bat_1.teken(getGraphics()); // teken opnieuw de bat om deze uit te wissen
bat_1.verplaats((bat_1.getX() + 5), bat_1.getY()); // verplaats dan de positie
bat_1.teken(getGraphics()); // en teken de nieuwe bat (als je nu weer teken() zou aanroepen, wordt deze uitgewist)
}
break;
case KeyEvent.VK_LEFT:
if(bat_1.getX() > 20){
bat_1.teken(getGraphics());
bat_1.verplaats((bat_1.getX() - 5), bat_1.getY());
bat_1.teken(getGraphics());
}
break;
case KeyEvent.VK_A: // VK staat voor 'virtual key'. Toetsenborden die in dit geval 'A' op een andere plek hebben zitten, genereren toch VK_A
if(bat_2.getX() > 20){
bat_2.teken(getGraphics());
bat_2.verplaats((bat_2.getX() - 5), bat_2.getY());
bat_2.teken(getGraphics());
}
break;
case KeyEvent.VK_D:
if(bat_2.getX() < 350){
bat_2.teken(getGraphics());
bat_2.verplaats((bat_2.getX() + 5), bat_2.getY());
bat_2.teken(getGraphics());
}
break;
}
}
}
}
class Field{
public Field(){
}
public void teken(Graphics g){ // teken het veld
g.setColor(Color.green);
g.fillRect(0, 10, 400, 500);
g.setColor(Color.white);
g.drawRect(10, 20, 380, 480);
g.drawLine(10, 250, 390, 250);
g.drawLine(200, 155, 200, 345);
g.drawLine(30, 345, 370, 345);
g.drawLine(30, 155, 370, 155);
g.drawLine(370, 20, 370, 500);
g.drawLine(30, 20, 30, 500);
}
}
class Bat{
private int breedte = 30;
private int hoogte = 5;
private int x = 0;
private int y = 50;
private int dy = 3;
private Color kleur;
public Bat(int breedte, int hoogte, Color kleur){ // de constructor van klasse Bat, deze wordt aangeroepen wanneer je een nieuwe Bat maakt, bijv zo: Bat bat = new Bat(arg1, arg2);
this.breedte = breedte;
this.hoogte = hoogte;
this.kleur = kleur;
verplaats(50, 50);
}
// teken de bat
public void teken(Graphics g){
g.setXORMode(Color.green); // deze zorgt ervoor dat, als je de bat weer op dezelfde plaats tekent, hij zichzelf uitwist
g.setColor(kleur); // kleur van de bat
g.fillRect(x, y, breedte, hoogte); // grootte en positie van de bat
}
public void verplaats(int x, int y){ // verplaats, zet x en y voor positie op andere waarde
this.x = x;
this.y = y;
}
public int getX(){
return this.x;
}
public int getY(){
return this.y;
}
}
class Bal extends Thread { // Bal zit in een 'thread'. Als dat niet zo was, zou je niet tegelijkertijd een bat kunnen bewegen
// als je wilt dat je ook tegelijkertijd bat_1 en bat_2 kan bewegen, moet je 1 van deze ook in een thread zetten
private int grootte;
private int x = 200;
private int y = 60;
//private int dx = 2;
private int dy = 4;
private int dx = 0;
private Color kleur;
private boolean doorgaan;
private Graphics g;
private Bat bat_1;
private Bat bat_2;
public Bal(Graphics g, int grootte, Color kleur, Bat bat_1, Bat bat_2){ // maak een nieuwe bal aan, geef referenties naar objecten van bat_1 en bat_2 door
this.g = g;
this.grootte = grootte;
this.kleur = kleur;
doorgaan = true;
g.setXORMode(Color.green);
this.bat_1 = bat_1; // deze referenties worden gebruikt om te kijken wanneer de bal bat_1 of bat_2 raakt
this.bat_2 = bat_2;
}
/* deze methode wordt door de klasse Thread van Java aangeroepen om de zoveel tijd
(in de tussentijd kunnen andere processen hun werk doen, zoals het verplaatsen van de bats met de toetsen) */
public void run(){
while(doorgaan){ // als doorgaan == false, dan stopt de methode run en daarmee de thread
teken(g, kleur); // teken de bal
/* geeft andere threads zoals de main thread (die je altijd hebt,
daar loopt je hoofdprogramma in) de kans om methoden uit te voeren.
deze thread 'slaapt' als het ware even en geeft andere threads de mogelijkheid gebruik
te maken van de processor e.d */
slaap(10);
teken(g, kleur); // wis de bal (want op zelfde positie weer getekend)
verplaats(); // verplaats bal
}
}
public void nuStoppen(){ // stop
doorgaan = false;
}
private void teken(Graphics g, Color kleur){
g.setColor(kleur);
g.fillOval(x, y, grootte, grootte);
}
// ingewikkelde methode die bepaalt in welke richting de bal gaat.
private void verplaats(){
if(y > 490 || y < 40){
nuStoppen(); // de bal is uit het veld gegaan, stop het spel
}else{
int hit_x = x - bat_1.getX();
int hit_y = y - bat_1.getY();
if(hit_y < 5 && hit_y > -5){
if(hit_x < 30 && hit_x > -10){
dy = -dy;
dx = ((hit_x - 10)/5);
}
}else{
hit_x = x - bat_2.getX();
hit_y = y - bat_2.getY();
if(hit_y < 5 && hit_y > -5){
if(hit_x < 30 && hit_x > -10){
dy = -dy;
dx = ((hit_x - 10)/5);
}
}
}
}
if(x < 10 || x > 400){
nuStoppen(); // de bal is uit het veld, stop het spel
}
y += dy;
x += dx;
}
// stop de thread even en geef andere threads de mogelijkheid iets te doen
private void slaap(int millisec){
try{
Thread.sleep(millisec);
}catch(InterruptedException e){}
}
}