我目前正在使用David Brackeen撰写的“用Java开发游戏”一书来构建一个2D平台游戏作为项目。每个精灵的动画都是以这样的方式完成的,即在程序运行时使它们保持不变,但我希望能够在玩家按下跳转时更改动画,以及冻结动画或添加另一个动画来播放器站着不动我绝不是一个经验丰富的程序员,所以我为可怕的代码道歉,但希望它有点可读。
这是包含主要方法的类
package tilegame;
import java.awt.*;
import java.awt.event.KeyEvent;
import java.io.File;
import java.util.Iterator;
import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.Clip;
import graphics.*;
import sound.*;
import input.*;
import core.GameCore;
import tilegame.sprites.*;
import tilegame.ResourceManager;
/**
GameManager manages all parts of the game.
*/
public class GameManager extends GameCore {
public static void main(String[] args) {
new GameManager().run();
}
private static final AudioFormat PLAYBACK_FORMAT =
new AudioFormat(44100, 16, 1, true, false);
public static final float GRAVITY = 0.002f;
private Point pointCache = new Point();
private TileMap map;
private SoundManager soundManager;
private ResourceManager resourceManager;
private InputManager inputManager;
private TileMapRenderer renderer;
private Sound jumpSound;
private GameAction moveLeft;
private GameAction moveRight;
private GameAction jump;
private GameAction exit;
public void init() {
super.init();
// set up input manager
initInput();
// start resource manager
resourceManager = new ResourceManager(
screen.getFullScreenWindow().getGraphicsConfiguration());
// load resources
renderer = new TileMapRenderer();
renderer.setBackground(
resourceManager.loadImage("background.png"));
// load first map
map = resourceManager.loadNextMap();
// load sounds
soundManager = new SoundManager(PLAYBACK_FORMAT);
jumpSound = soundManager.getSound("sounds/jump.wav");
String fileName = "sounds/music.wav";
playLoop(fileName);
}
public void stop() {
super.stop();
soundManager.close();
}
private void initInput() {
moveLeft = new GameAction("moveLeft");
moveRight = new GameAction("moveRight");
jump = new GameAction("jump",
GameAction.DETECT_INITAL_PRESS_ONLY);
exit = new GameAction("exit",
GameAction.DETECT_INITAL_PRESS_ONLY);
inputManager = new InputManager(
screen.getFullScreenWindow());
inputManager.setCursor(InputManager.INVISIBLE_CURSOR);
inputManager.mapToKey(moveLeft, KeyEvent.VK_LEFT);
inputManager.mapToKey(moveRight, KeyEvent.VK_RIGHT);
inputManager.mapToKey(jump, KeyEvent.VK_SPACE);
inputManager.mapToKey(exit, KeyEvent.VK_ESCAPE);
}
// checks the users input for player movement
private void checkInput(long elapsedTime) {
if (exit.isPressed()) {
stop();
}
Player player = (Player)map.getPlayer();
if (player.isAlive()) {
float velocityX = 0;
if (moveLeft.isPressed()) {
velocityX-=player.getMaxSpeed();
}
if (moveRight.isPressed()) {
velocityX+=player.getMaxSpeed();
}
if (jump.isPressed()) {
player.jump(false);
soundManager.play(jumpSound);
}
player.setVelocityX(velocityX);
}
}
// plays an instance of a chosen sound
public void playSound(String soundName){
try {
AudioInputStream audioInputStream = AudioSystem.getAudioInputStream(new File(soundName).getAbsoluteFile( ));
Clip clip = AudioSystem.getClip( );
clip.open(audioInputStream);
clip.start( );
}
catch(Exception ex)
{
System.out.println("Error");
ex.printStackTrace( );
}
}
// loops an instance of a chosen sound
public void playLoop(String soundName){
try {
AudioInputStream audioInputStream = AudioSystem.getAudioInputStream(new File(soundName).getAbsoluteFile( ));
Clip clip = AudioSystem.getClip( );
clip.open(audioInputStream);
clip.start( );
clip.loop(Clip.LOOP_CONTINUOUSLY);
}
catch(Exception ex)
{
System.out.println("Error");
ex.printStackTrace( );
}
}
public void draw(Graphics2D g) {
renderer.draw(g, map,
screen.getWidth(), screen.getHeight());
}
public TileMap getMap() {
return map;
}
public Point getTileCollision(Sprite sprite,
float newX, float newY)
{
float fromX = Math.min(sprite.getX(), newX);
float fromY = Math.min(sprite.getY(), newY);
float toX = Math.max(sprite.getX(), newX);
float toY = Math.max(sprite.getY(), newY);
// get the tile locations
int fromTileX = TileMapRenderer.pixelsToTiles(fromX);
int fromTileY = TileMapRenderer.pixelsToTiles(fromY);
int toTileX = TileMapRenderer.pixelsToTiles(
toX + sprite.getWidth() - 1);
int toTileY = TileMapRenderer.pixelsToTiles(
toY + sprite.getHeight() - 1);
// check each tile for a collision
for (int x=fromTileX; x<=toTileX; x++) {
for (int y=fromTileY; y<=toTileY; y++) {
if (x < 0 || x >= map.getWidth() ||
map.getTile(x, y) != null)
{
// collision found, return the tile
pointCache.setLocation(x, y);
return pointCache;
}
}
}
// no collision found
return null;
}
public boolean isCollision(Sprite s1, Sprite s2) {
// if the Sprites are the same, return false
if (s1 == s2) {
return false;
}
// if one of the Sprites is a dead Creature, return false
if (s1 instanceof Creature && !((Creature)s1).isAlive()) {
return false;
}
if (s2 instanceof Creature && !((Creature)s2).isAlive()) {
return false;
}
// get the pixel location of the Sprites
int s1x = Math.round(s1.getX());
int s1y = Math.round(s1.getY());
int s2x = Math.round(s2.getX());
int s2y = Math.round(s2.getY());
// check if the two sprites' boundaries intersect
return (s1x < s2x + s2.getWidth() &&
s2x < s1x + s1.getWidth() &&
s1y < s2y + s2.getHeight() &&
s2y < s1y + s1.getHeight());
}
public Sprite getSpriteCollision(Sprite sprite) {
// run through the list of Sprites
Iterator i = map.getSprites();
while (i.hasNext()) {
Sprite otherSprite = (Sprite)i.next();
if (isCollision(sprite, otherSprite)) {
// collision found, return the Sprite
return otherSprite;
}
}
// no collision found
return null;
}
public void update(long elapsedTime) {
Creature player = (Creature)map.getPlayer();
// player is dead! start map over
if (player.getState() == Creature.STATE_DEAD) {
map = resourceManager.reloadMap();
return;
}
// get keyboard/mouse input
checkInput(elapsedTime);
// update player
updateCreature(player, elapsedTime);
player.update(elapsedTime);
// update other sprites
Iterator i = map.getSprites();
while (i.hasNext()) {
Sprite sprite = (Sprite)i.next();
if (sprite instanceof Creature) {
Creature creature = (Creature)sprite;
if (creature.getState() == Creature.STATE_DEAD) {
i.remove();
}
else {
updateCreature(creature, elapsedTime);
}
}
// normal update
sprite.update(elapsedTime);
}
}
private void updateCreature(Creature creature,
long elapsedTime)
{
// apply gravity
if (!creature.isFlying()) {
creature.setVelocityY(creature.getVelocityY() +
GRAVITY * elapsedTime);
}
// change x
float dx = creature.getVelocityX();
float oldX = creature.getX();
float newX = oldX + dx * elapsedTime;
Point tile =
getTileCollision(creature, newX, creature.getY());
if (tile == null) {
creature.setX(newX);
}
else {
// line up with the tile boundary
if (dx > 0) {
creature.setX(
TileMapRenderer.tilesToPixels(tile.x) -
creature.getWidth());
}
else if (dx < 0) {
creature.setX(
TileMapRenderer.tilesToPixels(tile.x + 1));
}
creature.collideHorizontal();
}
if (creature instanceof Player) {
checkPlayerCollision((Player)creature, false);
}
// change y
float dy = creature.getVelocityY();
float oldY = creature.getY();
float newY = oldY + dy * elapsedTime;
tile = getTileCollision(creature, creature.getX(), newY);
if (tile == null) {
creature.setY(newY);
}
else {
// line up with the tile boundary
if (dy > 0) {
creature.setY(
TileMapRenderer.tilesToPixels(tile.y) -
creature.getHeight());
}
else if (dy < 0) {
creature.setY(
TileMapRenderer.tilesToPixels(tile.y + 1));
}
creature.collideVertical();
}
if (creature instanceof Player) {
boolean canKill = (oldY < creature.getY());
checkPlayerCollision((Player)creature, canKill);
}
}
public void checkPlayerCollision(Player player,
boolean canKill)
{
if (!player.isAlive()) {
return;
}
// check for player collision with other sprites
Sprite collisionSprite = getSpriteCollision(player);
if (collisionSprite instanceof Items) {
acquirePowerUp((Items)collisionSprite);
}
else if (collisionSprite instanceof Creature) {
Creature badguy = (Creature)collisionSprite;
if (canKill) {
// kill the badguy and make player bounce
String fileName = "sounds/impact.wav";
playSound(fileName);
badguy.setState(Creature.STATE_DYING);
player.setY(badguy.getY() - player.getHeight());
player.jump(true);
}
else {
// player dies!
String fileName = "sounds/death.wav";
playSound(fileName);
player.setState(Creature.STATE_DYING);
}
}
}
public void acquirePowerUp(Items powerUp) {
// remove it from the map
map.removeSprite(powerUp);
if (powerUp instanceof Items.Coin) {
// do something here, like give the player points
String fileName = "sounds/coin.wav";
playSound(fileName);
}
else if (powerUp instanceof Items.Door) {
// advance to next map
String fileName = "sounds/door.wav";
playSound(fileName);
map = resourceManager.loadNextMap();
}
}
}
这是为玩家创建动画的类。
package tilegame;
import java.awt.*;
import java.awt.geom.AffineTransform;
import java.io.*;
import java.util.ArrayList;
import javax.swing.ImageIcon;
import graphics.*;
import tilegame.sprites.*;
/**
The ResourceManager class loads and manages tile Images and
Sprites used in the game. Game Sprites are cloned from
the original Sprites.
*/
public class ResourceManager{
private ArrayList tiles;
private int currentMap;
private GraphicsConfiguration gc;
// Sprites used for cloning
private Sprite playerSprite;
private Sprite playerJump;
private Sprite coinSprite;
private Sprite doorSprite;
private Sprite grubSprite;
private Sprite batSprite;
private Sprite houndSprite;
public ResourceManager(GraphicsConfiguration gc) {
this.gc = gc;
loadTileImages();
loadCreatureSprites();
loadItemSprites();
}
public Image loadImage(String name) {
String filename = "images/" + name;
return new ImageIcon(filename).getImage();
}
public Image getMirrorImage(Image image) {
return getScaledImage(image, -1, 1);
}
public Image getFlippedImage(Image image) {
return getScaledImage(image, 1, -1);
}
private Image getScaledImage(Image image, float x, float y) {
// set up the transform
AffineTransform transform = new AffineTransform();
transform.scale(x, y);
transform.translate(
(x-1) * image.getWidth(null) / 2,
(y-1) * image.getHeight(null) / 2);
// create a transparent (not translucent) image
Image newImage = gc.createCompatibleImage(
image.getWidth(null),
image.getHeight(null),
Transparency.BITMASK);
// draw the transformed image
Graphics2D g = (Graphics2D)newImage.getGraphics();
g.drawImage(image, transform, null);
g.dispose();
return newImage;
}
public TileMap loadNextMap(){
TileMap map = null;
while (map == null) {
currentMap++;
try {
map = loadMap(
"maps/map" + currentMap + ".txt");
Thread.sleep(200);
} catch(InterruptedException ex) {
Thread.currentThread().interrupt();
}
catch (IOException ex) {
if (currentMap == 1) {
// no maps to load!
return null;
}
currentMap = 0;
map = null;
}
}
return map;
}
public TileMap reloadMap() {
try {
return loadMap(
"maps/map" + currentMap + ".txt");
}
catch (IOException ex) {
ex.printStackTrace();
return null;
}
}
private TileMap loadMap(String filename)
throws IOException
{
ArrayList lines = new ArrayList();
int width = 0;
int height = 0;
// read every line in the text file into the list
BufferedReader reader = new BufferedReader(
new FileReader(filename));
while (true) {
String line = reader.readLine();
// no more lines to read
if (line == null) {
reader.close();
break;
}
// add every line except for comments
if (!line.startsWith("#")) {
lines.add(line);
width = Math.max(width, line.length());
}
}
// parse the lines to create a TileEngine
height = lines.size();
TileMap newMap = new TileMap(width, height);
for (int y=0; y<height; y++) {
String line = (String)lines.get(y);
for (int x=0; x<line.length(); x++) {
char ch = line.charAt(x);
// check if the char represents tile A, B, C etc.
int tile = ch - 'A';
if (tile >= 0 && tile < tiles.size()) {
newMap.setTile(x, y, (Image)tiles.get(tile));
}
// check if the char represents a sprite
else if (ch == 'o') {
addSprite(newMap, coinSprite, x, y);
}
else if (ch == '*') {
addSprite(newMap, doorSprite, x, y);
}
else if (ch == '1') {
addSprite(newMap, grubSprite, x, y);
}
else if (ch == '2') {
addSprite(newMap, batSprite, x, y);
}
else if (ch == '3') {
addSprite(newMap, houndSprite, x, y);
}
}
}
// add the player to the map
Sprite player = (Sprite)playerSprite.clone();
player.setX(TileMapRenderer.tilesToPixels(2));
player.setY(0);
newMap.setPlayer(player);
return newMap;
}
private void addSprite(TileMap map,
Sprite hostSprite, int tileX, int tileY)
{
if (hostSprite != null) {
// clone the sprite from the "host"
Sprite sprite = (Sprite)hostSprite.clone();
// center the sprite
sprite.setX(
TileMapRenderer.tilesToPixels(tileX) +
(TileMapRenderer.tilesToPixels(1) -
sprite.getWidth()) / 2);
// bottom-justify the sprite
sprite.setY(
TileMapRenderer.tilesToPixels(tileY + 1) -
sprite.getHeight());
// add it to the map
map.addSprite(sprite);
}
}
// -----------------------------------------------------------
// code for loading sprites and images
// -----------------------------------------------------------
public void loadTileImages() {
// keep looking for tile A,B,C, etc. this makes it
// easy to drop new tiles in the images/ directory
tiles = new ArrayList();
char ch = 'A';
while (true) {
String name = "tile_" + ch + ".png";
File file = new File("images/" + name);
if (!file.exists()) {
break;
}
tiles.add(loadImage(name));
ch++;
}
}
public void loadCreatureSprites() {
Image[][] images = new Image[8][];
// load left-facing images
images[0] = new Image[] {
loadImage("player1.png"),
loadImage("player2.png"),
loadImage("player3.png"),
loadImage("player4.png"),
loadImage("player5.png"),
loadImage("player6.png"),
loadImage("player7.png"),
loadImage("player8.png"),
loadImage("bat1.png"),
loadImage("bat2.png"),
loadImage("bat3.png"),
loadImage("bat4.png"),
loadImage("grub1.png"),
loadImage("grub2.png"),
loadImage("hound1.png"),
loadImage("hound2.png"),
loadImage("hound3.png"),
loadImage("hound4.png"),
loadImage("hound5.png"),
loadImage("jump1.png"),
loadImage("jump2.png"),
loadImage("jump3.png")
};
images[1] = new Image[images[0].length];
images[2] = new Image[images[0].length];
images[3] = new Image[images[0].length];
for (int i=0; i<images[0].length; i++) {
// right-facing images
images[1][i] = getMirrorImage(images[0][i]);
// left-facing "dead" images
images[2][i] = getFlippedImage(images[0][i]);
// right-facing "dead" images
images[3][i] = getFlippedImage(images[1][i]);
}
// create creature animations
Animation[] playerAnim = new Animation[4];
Animation[] batAnim = new Animation[4];
Animation[] grubAnim = new Animation[4];
Animation[] houndAnim = new Animation[4];
Animation[] playerJumpAnim = new Animation[4];
for (int i=0; i<4; i++) {
playerAnim[i] = createPlayerAnim(
images[i][0], images[i][1], images[i][2],
images[i][3], images[i][4], images[i][5],
images[i][6], images[i][7]);
batAnim[i] = createBatAnim(
images[i][8], images[i][9], images[i][10], images[i][11]);
grubAnim[i] = createGrubAnim(
images[i][12], images[i][13]);
houndAnim[i] = createHoundAnim(
images[i][14], images[i][15], images[i][16],
images[i][17], images [i][18]);
playerJumpAnim[i] = createJumpAnim(
images[i][19], images[i][20], images[i][21]);
}
// changing player sprite for different movements notes.
// possible solutions:
// add keylistener
playerSprite = new Player(playerAnim[0], playerAnim[1],
playerAnim[2], playerAnim[3]);
playerJump = new Player(playerJumpAnim[0], playerJumpAnim[1],
playerJumpAnim[2], playerJumpAnim[3]);
batSprite = new Bat(batAnim[0], batAnim[1],
batAnim[2], batAnim[3]);
grubSprite = new Grub(grubAnim[0], grubAnim[1],
grubAnim[2], grubAnim[3]);
houndSprite = new Hound(houndAnim[0], houndAnim[1],
houndAnim[2], houndAnim[3]);
}
private Animation createPlayerAnim(Image img1, Image img2,
Image img3, Image img4,
Image img5, Image img6,
Image img7, Image img8)
{
Animation anim = new Animation();
anim.addFrame(img1, 100);
anim.addFrame(img2, 100);
anim.addFrame(img3, 100);
anim.addFrame(img4, 100);
anim.addFrame(img5, 100);
anim.addFrame(img6, 100);
anim.addFrame(img7, 100);
anim.addFrame(img8, 100);
return anim;
}
private Animation createJumpAnim(Image img1, Image img2,
Image img3)
{
Animation anim = new Animation();
anim.addFrame(img1, 100);
anim.addFrame(img2, 100);
anim.addFrame(img3, 100);
return anim;
}
private Animation createBatAnim(Image img1, Image img2,
Image img3, Image img4)
{
Animation anim = new Animation();
anim.addFrame(img1, 100);
anim.addFrame(img2, 100);
anim.addFrame(img3, 100);
anim.addFrame(img4, 125);
return anim;
}
private Animation createGrubAnim(Image img1, Image img2) {
Animation anim = new Animation();
anim.addFrame(img1, 250);
anim.addFrame(img2, 250);
return anim;
}
private Animation createHoundAnim(Image img1, Image img2,
Image img3, Image img4, Image img5) {
Animation anim = new Animation();
anim.addFrame(img1, 200);
anim.addFrame(img2, 150);
anim.addFrame(img3, 200);
anim.addFrame(img4, 150);
anim.addFrame(img5, 150);
return anim;
}
private void loadItemSprites() {
// create "door" sprite
Animation anim = new Animation();
anim.addFrame(loadImage("door1.png"), 300);
anim.addFrame(loadImage("door2.png"), 250);
anim.addFrame(loadImage("door3.png"), 300);
anim.addFrame(loadImage("door4.png"), 475);
anim.addFrame(loadImage("door3.png"), 300);
anim.addFrame(loadImage("door2.png"), 200);
anim.addFrame(loadImage("door1.png"), 800);
doorSprite = new Items.Door(anim);
// create "coin" sprite
anim = new Animation();
anim.addFrame(loadImage("coin1.png"), 150);
anim.addFrame(loadImage("coin2.png"), 150);
anim.addFrame(loadImage("coin3.png"), 150);
anim.addFrame(loadImage("coin4.png"), 150);
anim.addFrame(loadImage("coin5.png"), 150);
anim.addFrame(loadImage("coin6.png"), 150);
coinSprite = new Items.Coin(anim);
}
}
我想要的是使用下面的方法在按下“跳转”时更改玩家当前的动画,但我似乎无法弄清楚如何让它工作。项目中还包含其他可能需要看到的类来解决这个问题。我不想发布过多的代码,但现在看起来有点晚了。
private Animation createJumpAnim(Image img1, Image img2,
Image img3)
{
Animation anim = new Animation();
anim.addFrame(img1, 100);
anim.addFrame(img2, 100);
anim.addFrame(img3, 100);
return anim;
}