八.音效实现
SoundEffects class
利用MIDP2.0 的mediaAPI创建犬吠,绵羊叫,还有游戏结束音
1创建SoundEffects类
2.引入类
import javax.microedition.media.*;
import java.io.*;
3.创建参数
class SoundEffects
{
private static SoundEffects instance;
private Player sheepSoundPlayer;
private Player dogSoundPlayer;
4.初始化
private SoundEffects()
{
sheepSoundPlayer = createPlayer("/sheep.wav", "audio/x-wav");
dogSoundPlayer = createPlayer("/dog.wav", "audio/x-wav");
}
static SoundEffects getInstance()
{
if (instance == null)
{
instance = new SoundEffects();
}
return instance;
}
5.创建声音播放方法
void startSheepSound()
{
startPlayer(sheepSoundPlayer);
}
void startDogSound()
{
startPlayer(dogSoundPlayer);
}
void startGameOverSound()
{
startPlayer(createPlayer("/gameover.mid", "audio/midi"));
}
void startHighScoreSound()
{
startPlayer(createPlayer("/highscore.mid", "audio/midi"));
}
6.创建音效控制方法
private void startPlayer(Player p)
{
if (p != null)
{
try
{
p.stop();
p.setMediaTime(0L);
p.start();
}
catch (MediaException me)
{
// ignore
}
}
}
7.创建createPlayer方法
private Player createPlayer(String filename, String format)
{
Player p = null;
try
{
InputStream is = getClass().getResourceAsStream(filename);
p = Manager.createPlayer(is, format);
p.prefetch();
}
catch (IOException ioe)
{
// ignore
}
catch (MediaException me)
{
// ignore
}
return p;
}
}
九.实现游戏功能
SheepdogCanvas class
1. 创建类
2. 引入类
import java.util.Random;
import java.util.Vector;
import javax.microedition.lcdui.*;
import javax.microedition.lcdui.game.*;
import javax.microedition.media.*;
import java.io.*;
3. SheepdogCanvas类继承GameCanvas类和Runable接口,GameCanvas是Canvas的一个子类,它提供了一些方便的游戏接口,还有一些特殊的游戏特性,例如帧缓冲,按键侦听。
class SheepdogCanvas
extends GameCanvas
implements Runnable
{
4. 定义和初始化参数
static final int NONE = -1;
static final int UP = 0;
static final int LEFT = 1;
static final int DOWN = 2;
static final int RIGHT = 3;
private static final int MILLIS_PER_TICK = 50;
private static final int NUM_SHEEP = 5;
private final SheepdogMIDlet midlet;
private final Field field;
private final Sheepdog sheepdog;
private final Vector sheep = new Vector();
private final LayerManager layerManager;
private final Graphics graphics;
private long gameDuration;
private long startTime;
private volatile Thread animationThread = null;
5.创建SheepdogCanvas对象,getGraphic方法用于获得Graphics对象来渲染GameCanvas,LayerManager类用于管理一系列的图层
SheepdogCanvas(SheepdogMIDlet midlet)
{
super(true); // suppress key events for game keys
this.midlet = midlet;
setFullScreenMode(true);
graphics = getGraphics();
layerManager = new LayerManager();
field = new Field();
sheepdog = new Sheepdog(this);
layerManager.append(sheepdog);
for (int i = 0; i < NUM_SHEEP; ++i)
{
Sheep newSheep = new Sheep(this);
layerManager.append(newSheep);
sheep.addElement(newSheep);
}
layerManager.append(field); // last layer, behind sprites
init();
}
6.创建用于按键侦听的方法,如果按了一个负数按键码的按键了,则跳出菜单
public void keyPressed(int keyCode)
{
// The constructor suppresses key events for game keys, so we'll
// only get key events for non-game keys. The number keys, * & #
// have positive keyCodes, so negative keyCodes mean non-game
// special keys like soft-keys. We'll use key-presses on special
// keys to take us to the menu.
if (keyCode < 0)
{
stop();
midlet.sheepdogCanvasMenu();
}
}
7.初见初始化函数,getWidth和getHeight方法用于获得当前画布的宽和高,setPosition方法用于设定层得位置(左上角为基准点)
void init()
{
sheepdog.setPosition(field.getSheepdogStartX(),
field.getSheepdogStartY());
for (int i = 0; i < sheep.size(); ++i)
{
Sheep sh = (Sheep)(sheep.elementAt(i));
// find a valid position for the sheep
do
{
int x = midlet.random(field.getWidth() - Sheep.WIDTH);
int y = midlet.random(field.getHeight() - Sheep.HEIGHT);
sh.setPosition(x, y);
} while (field.containsImpassableArea(sh.getX(),
sh.getY(),
sh.getWidth(),
sh.getHeight()) ||
overlapsSheepdog(sh) ||
overlapsSheep(sh, i) ||
field.inFold(sh));
}
}
8.创建用于开始和终止游戏的方法
public synchronized void start()
{
animationThread = new Thread(this);
animationThread.start();
startTime = System.currentTimeMillis() - gameDuration;
}
public synchronized void stop()
{
gameDuration = System.currentTimeMillis() - startTime;
animationThread = null;
}
9.创建run方法,FlushGraphics方法用于将缓冲区的图像在屏幕上显示
public void run()
{
Thread currentThread = Thread.currentThread();
try
{
// This ends when animationThread is set to null, or when
// it is subsequently set to a new thread; either way, the
// current thread should terminate
while (currentThread == animationThread)
{
long startTime = System.currentTimeMillis();
// Don't advance game or draw if canvas is covered by
// a system screen.
if (isShown())
{
tick();
draw();
flushGraphics();
}
long timeTaken = System.currentTimeMillis() - startTime;
if (timeTaken < MILLIS_PER_TICK)
{
synchronized (this)
{
wait(MILLIS_PER_TICK - timeTaken);
}
}
else
{
currentThread.yield();
}
}
}
catch (InterruptedException e)
{
// won't be thrown
}
}
10.创建用于监视多按键同时按下的情况,用到了getKeyStates方法来获得当前按键情况
private void tick()
{
// If player presses two or more direction buttons, we ignore them
// all. But pressing fire is independent. The code below also ignores
// direction buttons if GAME_A..GAME_D are pressed.
int keyStates = getKeyStates();
boolean bark = (keyStates & FIRE_PRESSED) != 0;
keyStates &= ~FIRE_PRESSED;
int direction = (keyStates == UP_PRESSED) ? UP :
(keyStates == LEFT_PRESSED) ? LEFT:
(keyStates == DOWN_PRESSED) ? DOWN :
(keyStates == RIGHT_PRESSED) ? RIGHT : NONE;
sheepdog.tick(direction, bark);
for (int i = 0; i < sheep.size(); ++i)
{
Sheep sh = (Sheep)(sheep.elementAt(i));
sh.tick();
}
field.tick();
}
11.创建多个方法用于提取对象和控制犬吠
Field getField()
{
return field;
}
Sheepdog getSheepdog()
{
return sheepdog;
}
Vector getSheep()
{
return sheep;
}
void handleDogBark()
{
for (int i = 0; i < sheep.size(); ++i)
{
Sheep sh = (Sheep)(sheep.elementAt(i));
sh.handleDogBark();
}
}
12.创建精灵的碰撞控制方法,一个精灵是一个基本的视觉对象,它储存在一个图像中,并能变化;不同的帧能够显示精灵的运动,一些变换,如旋转,缩放也能应用到精灵上,用于进一步改变他们的显示。collidesWith方法用于检测精灵碰撞。
boolean overlapsSheepdog(Sprite sprite)
{
return sprite.collidesWith(sheepdog, false); // false -> not pixelLevel
}
boolean overlapsSheep(Sprite sprite)
{
return overlapsSheep(sprite, sheep.size());
}
// whether the sprite overlaps the first 'count' sheep
boolean overlapsSheep(Sprite sprite, int count)
{
for (int i = 0; i < count; ++i)
{
Sheep sh = (Sheep)(sheep.elementAt(i));
if (sprite.collidesWith(sh, false)) // false -> not pixelLevel
{
return true;
}
}
return false;
}
boolean overlapsOtherSheep(Sprite sprite)
{
for (int i = 0; i < sheep.size(); ++i)
{
Object obj = sheep.elementAt(i);
if (obj != sprite)
{
Sheep sh = (Sheep)obj;
if (sprite.collidesWith(sh, false)) // false -> not pixelLevel
{
return true;
}
}
}
return false;
}
void vibrate(int millis)
{
midlet.vibrate(millis);
}
13.创建方法用于画出游戏中可视的对象。getX方法获取x值,getY获取y之。
// draw game
private void draw()
{
int width = getWidth();
int height = getHeight();
// clear screen to grey
graphics.setColor(0x00888888);
graphics.fillRect(0, 0, width, height);
// clip and translate to centre
int dx = origin(sheepdog.getX() + sheepdog.getWidth() / 2,
field.getWidth(),
width);
int dy = origin(sheepdog.getY() + sheepdog.getHeight() / 2,
field.getHeight(),
height);
graphics.setClip(dx, dy, field.getWidth(), field.getHeight());
graphics.translate(dx, dy);
The paint method paints this Layer if it is visible.
For more information, see paint in the MIDP 2.0 API specification.
// draw background and sprites
layerManager.paint(g, 0, 0);
// undo clip & translate
graphics.translate(-dx, -dy);
graphics.setClip(0, 0, width, height);
// display time & score
long time = (System.currentTimeMillis() - startTime) / 1000;
int score = numSheepInFold();
graphics.setColor(0x00FFFFFF); // white
graphics.drawString(Integer.toString(score),
1,
1,
Graphics.TOP | Graphics.LEFT);
graphics.drawString(Long.toString(time),
width - 2,
1,
Graphics.TOP | Graphics.RIGHT);
if (score == sheep.size())
{
midlet.sheepdogCanvasGameOver(time);
}
}
14.创建用于计算场景大小的方法
// If the screen is bigger than the field, we center the field
// in the screen. Otherwise we center the screen on the focus, except
// that we don't scroll beyond the edges of the field.
private int origin(int focus, int fieldLength, int screenLength)
{
int origin;
if (screenLength >= fieldLength)
{
origin = (screenLength - fieldLength) / 2;
}
else if (focus <= screenLength / 2)
{
origin = 0;
}
else if (focus >= (fieldLength - screenLength / 2))
{
origin = screenLength - fieldLength;
}
else
{
origin = screenLength / 2 - focus;
}
return origin;
}
15.创建用于计算羊的数目的方法
int numSheepInFold()
{
int count = 0;
for (int i = 0; i < sheep.size(); ++i)
{
Sheep sh = (Sheep)(sheep.elementAt(i));
if (field.inFold(sh))
{
count++;
}
}
return count;
}
}