zl程序教程

您现在的位置是:首页 >  后端

当前栏目

《Java 2D游戏编程入门》—— 8.7 编写原型游戏

JAVA游戏编程入门 编写 原型 2D
2023-09-11 14:17:36 时间

本节书摘来异步社区《Java 2D游戏编程入门》一书中的第8章,第8.7节,作者:【美】Timothy Wright(莱特),更多章节内容可以访问云栖社区“异步社区”公众号查看。

8.7 编写原型游戏

原型游戏如图8.12所示,位于javagames.prototype包中,它使用了我们目前为止所见过的所有技术。尽管这只是一个原型,并且目前还没有成为一款完整的游戏,但我已经展示了足够的工具来让一些功能奏效。如果要等到最后再制作一款游戏,可能需要等太长的时间。

20765ff4c59ca5899cb50dd0396c2754a4d31336

该原型游戏使用了我们在本章前面所介绍的如下的类。

PolygonWrapper PrototypeShip PrototypeAsteroid PrototypeAsteroidFactory PrototypeBullet

当你在本章末尾尝试编译和运行代码之前,确保已经创建了这些类。

initialize()方法为原型创建了所有这些对象,包括创建了一些星星作为背景。如下的代码创建了星星,并且创建了颜色的一个数组。Color类接受3个值:red、blue和green,这3个值在0到1之间。将每种颜色值设置为相同的值,将会产生灰色的阴影。本书稍后会详细介绍颜色,但现在,只要使用Java语言所提供的java.awt.Color类就行了。

// PrototypeGame.java

private void createStars() {

stars = new Vector2f[ STAR_COUNT ];

 colors = new Color[ STAR_COUNT ];

 for( int i = 0; i stars.length; ++i ) { 

 float x = rand.nextFloat() * 2.0f - 1.0f;

 float y = rand.nextFloat() * 2.0f - 1.0f;

 stars[i] = new Vector2f( x, y );

 float color = rand.nextFloat();

 colors[i] = new Color( color, color, color );

当创建小行星的时候,注意getAsteroidStartPosition()方法。和产生各种大小的随机小行星的示例不同,这个方法只创建一个较大的随机小行星,并且使用如下代码将其放置到一个圆圈中,以使得它们不会在飞船之上产生。

// PrototypeGame.java
private Vector2f getAsteroidStartPosition() {
float angle = (float)Math.toRadians( rand.nextInt( 360 ) );
float minimum = appWorldWidth / 4.0f;
float extra = rand.nextFloat() * minimum;
float radius = minimum + extra;
return Vector2f.polar( angle, radius );
}`
前面的代码在圆圈中放置了新的多边形,该圆圈是屏幕的四分之一大,如图8.13所示。

036c14119a901bbef04e11d5f25c08cd99410ba5

这会防止这种现象发生:新产生的小行星出现于飞船的顶部,玩家还没来得及开火,就碰到它并爆炸了。这是游戏程序员所面对的各种挑战的一个很好的例子。只有在原型游戏开始运行时,这个问题才会变得明显。不管游戏多么简单,总是会有奇怪的问题需要解决。

processInput()方法使用向左键和向右键来旋转飞船,向上键会激活加速动作,空格键会发射子弹,Escape键会重新产生小行星。

当子弹击中小行星时,不仅小行星会从渲染列表中删除,而且如果小行星不是太小的话,它会分裂成两块更小的小行星。

updateShip()方法检查碰撞。如果飞船被击中,会设置毁灭标志。尽管在真实的游戏中,当飞船被击中时,游戏会重新启动,但我们还没有介绍玩家生命或游戏结束状态的概念,因此,目前当飞船被击中时,将其绘制为红色。

render()方法绘制星星、所有的小行星、子弹、飞船以及常用的帧速率和指令。还有一些新的代码,它们会开启抗锯齿功能,以使线条绘制得更为平滑。第10章将会介绍抗锯齿。

Graphics2D g2d = (Graphics2D)g;

 g2d.setRenderingHint(

 RenderingHints.KEY_ANTIALIASING,

 RenderingHints.VALUE_ANTIALIAS_ON

 );```

drawStars()、drawShip()、drawAsteroids()和drawBullets()方法负责绘制原型中的各种物体。PrototypeGame的代码如下所示:

package javagames.prototype;
import java.awt.*;
import java.awt.event.KeyEvent;
import java.util.*;
import javagames.prototype.PrototypeAsteroid.Size;
import javagames.util.*;

public class PrototypeGame extends SimpleFramework {
private static final int STAR_COUNT = 1500;
private PrototypeShip ship;
private PolygonWrapper wrapper;
private PrototypeAsteroidFactory factory;
private ArrayList bullets;
private ArrayList asteroids;
private Random rand;
private Vector2f[] stars;
private Color[] colors;
public PrototypeGame() {
appBorderScale = 0.9f;
appWidth = 640;
appHeight = 640;
appMaintainRatio = true;
appSleep = 1L;
appTitle = "Prototype Game";
}
@Override
protected void initialize() {
super.initialize();
// create game objects
rand = new Random();
bullets = new ArrayList();
asteroids = new ArrayList();
wrapper = new PolygonWrapper( appWorldWidth, appWorldHeight );
ship = new PrototypeShip( wrapper );
factory = new PrototypeAsteroidFactory( wrapper );
createStars();
createAsteroids();
}
// this creates the random stars for the background
private void createStars() {
stars = new Vector2f[ STAR_COUNT ];
colors = new Color[ STAR_COUNT ];
for( int i = 0; i stars.length; ++i ) {
float x = rand.nextFloat() * 2.0f - 1.0f;
float y = rand.nextFloat() * 2.0f - 1.0f;
stars[i] = new Vector2f( x, y );
float color = rand.nextFloat();
colors[i] = new Color( color, color, color );
}
}
// create the random asteroids
private void createAsteroids() {
asteroids.clear();
for( int i = 0; i ++i ) {
Vector2f position = getAsteroidStartPosition();
asteroids.add( factory.createLargeAsteroid( position ) );
}
}
// create random position for an asteroid
private Vector2f getAsteroidStartPosition() {
float angle = (float)Math.toRadians( rand.nextInt( 360 ) );
float minimum = appWorldWidth / 4.0f;
float extra = rand.nextFloat() * minimum;
float radius = minimum + extra;
return Vector2f.polar( angle, radius );
}
@Override
protected void processInput( float delta ) {
super.processInput( delta );
// fly the ship
if( keyboard.keyDown( KeyEvent.VK_LEFT ) ) {
ship.rotateLeft( delta );
}
if( keyboard.keyDown( KeyEvent.VK_RIGHT ) ) {
ship.rotateRight( delta );
}
if( keyboard.keyDownOnce( KeyEvent.VK_SPACE ) ) {
bullets.add( ship.launchBullet() );
}
if( keyboard.keyDownOnce( KeyEvent.VK_ESCAPE ) ) {
createAsteroids();
}
ship.setThrusting( keyboard.keyDown( KeyEvent.VK_UP ) );
}
@Override
protected void updateObjects( float delta ) {
super.updateObjects( delta );
updateAsteroids( delta );
updateBullets( delta );
updateShip( delta );
}
private void updateAsteroids( float delta ) {
for( PrototypeAsteroid asteroid : asteroids ) {
asteroid.update( delta );
}
}
private void updateBullets( float delta ) {
ArrayList copy =
new ArrayList( bullets );
for( PrototypeBullet bullet : copy ) {
updateBullet( delta, bullet );
}
}
// check for bullet collisions
private void updateBullet( float delta, PrototypeBullet bullet ) {
bullet.update( delta );
if( wrapper.hasLeftWorld( bullet.getPosition() ) ) {
bullets.remove( bullet );
} else {
ArrayList ast =
new ArrayList( asteroids );
for( PrototypeAsteroid asteroid : ast ) {
if( asteroid.contains( bullet.getPosition() ) ) {
bullets.remove( bullet );
asteroids.remove( asteroid );
spawnBabies( asteroid );
}
}
}
}
// create smaller asteroids when one is broken apart
private void spawnBabies( PrototypeAsteroid asteroid ) {
if( asteroid.getSize() == Size.Large ) {
asteroids.add(
factory.createMediumAsteroid( asteroid.getPosition() ) );
asteroids.add(
factory.createMediumAsteroid( asteroid.getPosition() ) );
}
if( asteroid.getSize() == Size.Medium ) {
asteroids.add(
factory.createSmallAsteroid( asteroid.getPosition() ) );
asteroids.add(
factory.createSmallAsteroid( asteroid.getPosition() ) );
}
}
// update the ship object
private void updateShip( float delta ) {
ship.update( delta );
boolean isHit = false;
for( PrototypeAsteroid asteroid : asteroids ) {
if( ship.isTouching( asteroid ) ) {
isHit = true;
}
}
ship.setDamaged( isHit );
}
@Override
protected void render( Graphics g ) {
// render instructions
super.render( g );
g.drawString( "Rotate: Left/Right Arrow", 20, 35 );
g.drawString( "Thrust: Up Arrow", 20, 50 );
g.drawString( "Fire: Space Bar", 20, 65 );
g.drawString( "Press ESC to respawn", 20, 80 );
Graphics2D g2d = (Graphics2D)g;
g2d.setRenderingHint(
RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON
);
// draw game objects
Matrix3x3f view = getViewportTransform();
drawStars( g2d, view );
drawAsteroids( g2d, view );
drawBullets( g2d, view );
drawShip( g2d, view );
}
private void drawStars( Graphics2D g, Matrix3x3f view ) {
for( int i = 0; i stars.length; ++i ) {
g.setColor( colors[i] );
Vector2f screen = view.mul( stars[i] );
g.fillRect( (int)screen.x, (int)screen.y, 1, 1 );
}
}
private void drawShip( Graphics2D g, Matrix3x3f view ) {
ship.draw( g, view );
}
private void drawAsteroids( Graphics2D g, Matrix3x3f view ) {
for( PrototypeAsteroid asteroid : asteroids ) {
asteroid.draw( g, view );
}
}
private void drawBullets( Graphics2D g, Matrix3x3f view ) {
for( PrototypeBullet b : bullets ) {
b.draw( g, view );
}
}
public static void main( String[] args ) {
launchApp( new PrototypeGame() );
}
}`


《Java 2D游戏编程入门》—— 导读 多年前,当我第一次将软件开发作为专业工作的时候,有人请我编写一个applet。那时候,我对于Java语言知道得并不多。在整个上学期间,我很广泛地使用C++。我确实用Java编写过一些代码,但认为它太慢并且是C++的没落版。
《Java 2D游戏编程入门》—— 8.6 原型Ship类 PrototypeShip代码位于javagames.prototype包中,这也是一目了然的。构造方法为移动飞船设置了一些常量,并且直接编码了模型的点。还有set()和get()方法用于销毁状态、角度、加速等,还有一些方法能够向左或向右旋转飞船。
《Java 2D游戏编程入门》—— 8.5 原型Bullet类 PrototypeBullet代码位于javagames.prototype包中,这是一个最简单的原型游戏源代码。除了绘制圆以便可以调整屏幕大小外,没有其他任何值得讨论的内容。
《Java 2D游戏编程入门》—— 8.4 用原型小行星工厂生产小行星 getRandomAsteroid()方法创建了一个随机的位置,然后选择一个随机的大小:small、medium或large。记住,工厂的每一个方法都从3种不同的多边形模型中针对每个大小选取一个模型,并且为每个模型生成4个镜像的版本。
《Java 2D游戏编程入门》—— 8.3 创建一个原型编辑器 现在是时候创建一些多边形了。尽管有可能可以猜到每个点,但要创建9个小行星形状,手动进行的话,工作量还是很大的。就像大多数程序一样,我也很懒。编写一个编辑器来创建多边形,这样会容易很多。位于javagames.prototype包中的PrototypeEditor,如图8.9所示。
《Java 2D游戏编程入门》—— 8.2 创建一个原型小行星 PrototypeAsteroid类位于javagames.prototype包中,它表示一个穿越太空的陨石。在创建的时候,使用了一个随机的速率和旋转。Java的随机数生成器只能返回0到1之间的浮点数,因此,要创建在任意范围内分布的随机数,需要一些额外的步骤。
《Java 2D游戏编程入门》—— 8.1 创建一个多边形包装类 制作一款2D太空飞船游戏时,首先要解决的大问题是,当飞船到达屏幕边缘时,会发生什么事情。一个解决方案是,将飞船保持在屏幕的中央,而移动其周围的环境。没有对加载文件的任何支持,也没有关卡编辑器的话,要做到这点似乎有点难。
《Java 2D游戏编程入门》—— 第8章 游戏原型 本章基于你在前面各章中已经学到的所有内容,介绍如何创建一个原型太空游戏。尽管它还有很多元素缺失,因而不能称之为一款完整的游戏,但我们已经有了足够的可用工具来创建一个可以工作的原型。
异步社区 异步社区(www.epubit.com)是人民邮电出版社旗下IT专业图书旗舰社区,也是国内领先的IT专业图书社区,致力于优质学习内容的出版和分享,实现了纸书电子书的同步上架,于2015年8月上线运营。公众号【异步图书】,每日赠送异步新书。