[案例研究]—superJumper 4.关卡

注:请务必结合代码理解!


经过上一节的分析,已经知道GameScreen中的一个World,就代表一个关卡,所有的GameObject都会被存储到World中。对于主角Bob和城堡Castle每一关只有一个,而对于其他游戏中的物体每一关都有多个,所以需要定义一个个List集合来存储它们,代码如下:
  
     public final Bob bob;
    public final List<Platform> platforms;
    public final List<Spring> springs;
    public final List<Squirrel> squirrels;
    public final List<Coin> coins;
    public Castle castle;

     public World(WorldListener listener) {
        this.bob = new Bob(5, 1);
        this.platforms = new ArrayList<Platform>();
        this.springs = new ArrayList<Spring>();
        this.squirrels = new ArrayList<Squirrel>();
        this.coins = new ArrayList<Coin>();
        this.listener = listener;
        rand = new Random();
        generateLevel();

        this.heightSoFar = 0;
        this.score = 0;
        this.state = WORLD_STATE_RUNNING;
    }

其中,在World的构造方法中,初始化了Bob ,Castle和所有的List,并且调用了 generateLevel()方法来生成关卡中除了Bob外所有的物体, generateLevel()方法代码如下:

private void generateLevel() {
        float y = Platform.PLATFORM_HEIGHT / 2;
        float maxJumpHeight = Bob.BOB_JUMP_VELOCITY * Bob.BOB_JUMP_VELOCITY
                / (2 * -gravity.y);
         while (y < WORLD_HEIGHT - WORLD_WIDTH / 2) {
            int type = rand.nextFloat() > 0.8f ? Platform.PLATFORM_TYPE_MOVING
                    : Platform.PLATFORM_TYPE_STATIC;
            float x = rand.nextFloat()
                    * (WORLD_WIDTH - Platform.PLATFORM_WIDTH)
                    + Platform.PLATFORM_WIDTH / 2;

            Platform platform = new Platform(type, x, y);
            platforms.add(platform);

            if (rand.nextFloat() > 0.9f
                    && type != Platform.PLATFORM_TYPE_MOVING) {
                Spring spring = new Spring(platform.position.x,
                        platform.position.y + Platform.PLATFORM_HEIGHT / 2
                                + Spring.SPRING_HEIGHT / 2);
                springs.add(spring);
            }

            if (y > WORLD_HEIGHT / 3 && rand.nextFloat() > 0.8f) {
                Squirrel squirrel = new Squirrel(platform.position.x
                        + rand.nextFloat(), platform.position.y
                        + Squirrel.SQUIRREL_HEIGHT + rand.nextFloat() * 2);
                squirrels.add(squirrel);
            }

            if (rand.nextFloat() > 0.6f) {
                Coin coin = new Coin(platform.position.x + rand.nextFloat(),
                        platform.position.y + Coin.COIN_HEIGHT
                                + rand.nextFloat() * 3);
                coins.add(coin);
            }

            y += (maxJumpHeight - 0.5f);
            y -= rand.nextFloat() * (maxJumpHeight / 3);
         }

        castle = new Castle(WORLD_WIDTH / 2, y);
    }
游戏中物体的创建主要是围绕Platform来生成的。在While循环内,通过不断增加y坐标的值,使用随机数rand 和 物体的内置属性来生成不同的游戏物体。比如,对于Playform 有移动和不移动两种,同时它内置的宽度为2(每单位为32个像素),高度为0.5,结合rand就能达到随机生成Playform的效果。

另外,对于每次Y坐标要增加多少,这里提供了一个参考的值为maxJumpHeight ,这个值表示每次主角Bob能跳过高,也就是在y轴上往上增加多少个单位。而它就是根据物理公式计算的,如下:
 
   float maxJumpHeight = Bob.BOB_JUMP_VELOCITY * Bob.BOB_JUMP_VELOCITY  / (2 * -gravity.y);

  其中Bob.BOB_JUMP_VELOCITY就是跳跃的初速度 为 11;gravity为重力,在World成员变量中已经定义,如下:

  public static final Vector2 gravity = new Vector2(0, -12);
  
 因为我们现在是要模拟在有重力的情况下的跳跃过程,那么真实的跳跃过程就是,一开始跳跃时,会有一个初速度,也就是Bob.BOB_JUMP_VELOCITY,但是受到重力gravity的影响gravity,主角Bob的速度会慢慢的减至为0,然后开始往下掉下来。所以Y方向重力被设置为-12,那么根据物理公式,在知道初速度,末速度,还有重力三个条件下,就可以计算出位移,在这里就是主角Bob能跳多高了。
那么把这个值作为每次Y坐标增加的基准,再用随机数rand做一些处理,让每次生Y坐标的增加量都有所不同。
这样一个World(关卡)就生成了,接下来就可以交给WorldRender开始渲染。

之前已经说过,WorldRender 是把World里面的游戏物体拿出来,把他们渲染到屏幕上,那么显然它需要在构造的时候传入两个东西,一个SpriteBatch,另一个则是World。再者,WorldRnder需要定义不同于GameScreen的OrthographicCamera,然后将OrthographicCamera的投影矩阵绑定给SpriteBatch。最后就是根据World中物体的属性,把它们绘制到屏幕上,关键代码如下:

        static final float FRUSTUM_WIDTH = 10;
static final float FRUSTUM_HEIGHT = 15;
World world;
OrthographicCamera cam;
SpriteBatch batch;
TextureRegion background;

public WorldRenderer (SpriteBatch batch, World world) {
this.world = world;
this.cam = new OrthographicCamera(FRUSTUM_WIDTH, FRUSTUM_HEIGHT);
this.cam.position.set(FRUSTUM_WIDTH / 2, FRUSTUM_HEIGHT / 2, 0);
this.batch = batch;
}

public void render () {
if (world.bob.position.y > cam.position.y) cam.position.y = world.bob.position.y;
cam.update();
batch.setProjectionMatrix(cam.combined);
renderBackground();
renderObjects();
}

public void renderBackground () {
batch.disableBlending();
batch.begin();
batch.draw(Assets.backgroundRegion, cam.position.x - FRUSTUM_WIDTH / 2, cam.position.y - FRUSTUM_HEIGHT / 2,                                             FRUSTUM_WIDTH, FRUSTUM_HEIGHT);
batch.end();
}

public void renderObjects () {
batch.enableBlending();
batch.begin();
renderBob();
renderPlatforms();
renderItems();
renderSquirrels();
renderCastle();
batch.end();
}
 其中,render()方法中第一行规定了,当bob的y坐标值,大于WorldRender中OrthographicCamera的position的y值时,就把bob的y值赋OrthographicCamera。 正式这句话,实现了游戏场景的移动。接着就是调用update 和 setProjectionMatrix把投影矩阵绑定给SpriteBatch告诉它要怎么绘图。
renderBackground ()方法是绘制背景图片。而renderObjects()就是真正根据World中游戏物体来绘制游戏画面,在这里作者把不同的物体分开来,让代码更为清晰。
      

欢迎转载!请注明原文链接,谢谢!  http://tonmly.blog.163.com/blog/static/17471285620116319463879/
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值