Tetrisklone

Grundprinzip:

In einem begrenzten Spielfeld fallen zufällig bestimmte Steine von oben nach unten. Der Spieler kann sowohl die Steine drehen und als auch die Position, auf der sie landen, verändern. Werden komplette Reihen gebildet, lösen sich diese auf und der Spieler erhält Punkte. Die Geschwindigkeit, mit der die Steine hinunter fallen, erhöht sich pro Level. Nach einer bestimmten Anzahl aufgelöster Reihen erreicht der Spieler das nächste Level. Das Spiel endet; wenn der Spieler keine Reihen mehr auflösen kann und die Steine bis an den oberen Spielfeldrand reichen.

Grunddesign:

Wir teilen das Spielfeld erstmal in ein Raster auf:
 _ _ _ _ _
|_|_|_|_|_|
|_|_|_|_|_|
|_|_|_|_|_|
|_|_|_|_|_|
|_|_|_|_|_|
|_|_|_|_|_|
Als nächstes haben wir unsere Spielsteine.
Ein Spielstein besteht aus mehreren Blöcken.

Bsp:
                                               _
                   _    _                     |_|
   _ _   _ _      |_|  |_|      _ _      _    |_|
 _|_|_| |_|_|_   _|_|  |_|_    |_|_|   _|_|_  |_|
|_|_|     |_|_| |_|_|  |_|_|   |_|_|  |_|_|_| |_|
Aus dieser Grundidee ergeben sich drei nötige Klassen: Block, Stone, Field.
Ein Block hat eine X- und Y-Koordinate sowie eine Farbe. Die Koordinaten sind relativ zu dem übergeordneten Objekt.
Ein Stein besteht aus mehreren Blöcken.
Das Feld besteht immer aus einem gerade herabfallenden Stein sowie verschiedenen Blöcken.

Blöcke: ( Block.scala )
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
package de.blauerfalke.tetris

import java.awt.Color
import java.awt.Graphics

object Block {
	val blockSize = 10
	def apply(b:(Int,Int), c:Color) = new Block(b, c)
	def apply(x:Int, y:Int, c:Color) = new Block((x,y), c)
}
class Block(var p:(Int,Int),var c:Color) {
	
	def paint(g:Graphics) { 
		g.setColor(c)
		g.fillRect(p._1*Block.blockSize , p._2*Block.blockSize , Block.blockSize, Block.blockSize)
	}
}

Mit dem Objekt Block können wir schnell und einfach Blöcke erstellen:

Block(0,0,Color.green)

Steine: ( Stone.scala )
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
package de.blauerfalke.tetris

import java.awt.Graphics
import java.awt.Color
import java.util.Random

object Stone {
	
	def apply(typ:Int) = {
		typ match {
			case -1 => new Stone(Array())
			case 1 => new Stone(Array( Block(0,0,Color.blue)  ,Block(0,1,Color.blue)  ,Block(0,2,Color.blue)  ,Block(1,2, Color.blue) ))
			case 2 => new Stone(Array( Block(1,0,Color.green) ,Block(1,1,Color.green) ,Block(1,2,Color.green) ,Block(0,2,Color.green) ))
			case 3 => new Stone(Array( Block(0,0,Color.red)   ,Block(0,1,Color.red)   ,Block(1,1,Color.red)   ,Block(1,2,Color.red)   ))
			case 4 => new Stone(Array( Block(1,0,Color.orange),Block(1,1,Color.orange),Block(0,1,Color.orange),Block(0,2,Color.orange)))
			case 5 => new Stone(Array( Block(1,0,Color.pink)  ,Block(1,1,Color.pink)  ,Block(0,1,Color.pink)  ,Block(1,2,Color.pink)  ))
			case 6 => new Stone(Array( Block(0,0,Color.yellow),Block(1,0,Color.yellow),Block(0,1,Color.yellow),Block(1,1,Color.yellow)))
			case 7 => new Stone(Array( Block(0,0,Color.cyan)  ,Block(0,1,Color.cyan)  ,Block(0,2,Color.cyan)  ,Block(0,3,Color.cyan)  ))
		}
	}
}

class Stone(var blocks:Array[Block]) {
	var p = (0,0)		//position
	
	def down() { 
		p = (p._1, p._2+1) 
	}
	
	def paint(g:Graphics) {
		for(b <- blocks)
			b.paint(g)	
	}
}
Auch hier hilft uns das Objekt Stone beim Erstellen der Steine. Es gibt sieben verschiedene Steine (siehe oben Beispiel Blöcke).

Spielfeld: ( Field.scala )
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
package de.blauerfalke.tetris

import scala.swing.Component
import java.awt.Graphics2D
import java.awt.Color

class Field extends Component {
	val fieldWidth = 11
	val fieldHeight = 16
	
	var stone:Stone = Stone(1)
	
	override def paintComponent(g: Graphics2D) {
		g.setColor(Color.black)
		g.fillRect(0,0, fieldWidth*Block.blockSize ,fieldHeight*Block.blockSize)
	
		stone.paint(g)
	}
}

Für unser Spielfeld zeichnen wir einen schwarzen Hintergrund mit Feldbreite x Feldhöhe, die jeweils noch mit der Blockgröße multipliziert werden.

Damit das Ganze jetzt auch angezeigt werden kann, brauchen wir noch ein Hauptfenster: ( Main.scala )
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
package de.blauerfalke.tetris

import swing.SimpleGUIApplication
import swing.MainFrame

object Main extends SimpleGUIApplication {
	
	def top = new MainFrame {
	
		//Frametitle
		title="Tetris"
		
		//Size und Position
		location=new java.awt.Point(200, 200)
		minimumSize=new java.awt.Dimension(200, 300)

		contents = new Field()
	}
}
Das war es schon mit der ersten Lektion. Wir haben die Grundstrukturen angelegt. In der nächsten Lektion werden wir die Steine zum Fallen bringen.

Hier noch einmal die komplette Lektion 1: TetrisLection1.zip