热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

九、将背景与角色运动同步

九、将背景与角色运动同步在第8章中,介绍了创建可滚动的多层背景的解决方案。然而,如果你试图同

九、将背景与角色运动同步

在第 8 章中,介绍了创建可滚动的多层背景的解决方案。然而,如果你试图同步背景的滚动和角色的移动,你可能会遇到问题。

在这一章中,你会看到两个方法——第一个是在两个方向上滚动多图像背景,第二个是同步背景的滚动和可玩角色的移动。

9.1 向两个方向滚动背景

问题

当玩家可以两个方向奔跑时,背景只向一个方向滚动 。

解决办法

修改背景类以跟踪两个方向的运动。

它是如何工作的

这个解决方案假设你的游戏,可能是一个平台风格的游戏,有一个角色可以向两个方向移动。回想一下流行的平台风格游戏(如超级马里奥兄弟),很多时候可玩角色可以向右移动以在游戏中前进。人物也可以向左移动,通常是在有限的能力下,来追溯他们的脚步。

在背景可以与角色同步之前,它需要能够在两个方向上移动。这个解决方案将获取一个三幅图像的背景,加载它,向右滚动,然后反向向左滚动。

第一步是将用作背景的三幅图像复制到res/drawable文件夹中。图 9-1 到 9-3 代表了我在这个例子中使用的三张图片。请注意,它们是单一背景的图层,已经被拉开,以便它们可以以不同的速度滚动。

9781430257646_Fig09-01.jpg

图 9-1 。最远的背景层

9781430257646_Fig09-02.jpg

图 9-2。中间层

9781430257646_Fig09-03.jpg

图 9-3 。地面层

注意为了在本书中打印图像,图像的透明部分被涂成灰色。

一旦图像在项目中,实例化三个SBGBackground()类的实例——每个背景层一个。

private SBGBackground background1 = new SBGBackground();
private SBGBackground background2 = new SBGBackground();
private SBGBackground background3 = new SBGBackground();

下一步是创建三组变量来控制和跟踪每一层背景的速度和位置。

private float bgScroll1;
private float bgScroll2;
private float bgScroll3;
public static float SCROLL_BACKGROUND_1  = .002f;
public static float SCROLL_BACKGROUND_2  = .003f;
public static float SCROLL_BACKGROUND_3  = .004f;

在第 7 章(清单 7-1 和 7-2)中,给出了一个创建scrollBackground()方法的解决方案。

改变方法,允许背景向左或向右滚动,这取决于玩家移动的方向。

在本书的早期,提供了一个允许角色在屏幕上移动的解决方案(使用 spritesheet)。这个解决方案的一部分需要创建一些变量来跟踪玩家的动作。在这个解决方案中使用相同的变量。

public static int playerAction = 0;
public static final int PLAYER_MOVE_LEFT = 1;
public static final int PLAYER_MOVE_RIGHT = 2;

注意前面提到的变量应该在你收集玩家输入的时候设置。有关这方面的更多信息,请参见第 5 章和第 6 章。

使用 OpenGL ES 1 和 2/3 向接受playerAction变量的scrollBackground()方法添加一个新参数,如下所示。

对于 OpenGL ES 1:

private void scrollBackground1(GL10gl, int direction){
...
}

对于 OpenGL ES 2/3:

private void scrollBackground1(int direction){
...
}

传递给scrollBackground()方法的方向将用于决定如何滚动背景图像。在当前的scrollBackground()方法中,下面一行控制图像的滚动:

bgScroll1 +=  SCROLL_BACKGROUND_1;

这条线的关键部分是+=。要改变滚动方向,需要将操作者从+=切换到-=。创建一个switch...case语句,根据从玩家输入中收集的方向来改变这个操作符。

OpenGL ES 1 和 OpenGL ES 2/3 的scrollBackground()方法分别显示在清单 9-1 和清单 9-2 中。

清单 9-1scrollBackground() (OpenGL 是 1)

private void scrollBackground1(GL10gl, int direction){
if (bgScroll1 == Float.MAX_VALUE){
bgScroll1 = 0f;
}
gl.glMatrixMode(GL10.GL_MODELVIEW);
gl.glLoadIdentity();
gl.glPushMatrix();
gl.glScalef(1f, 1f, 1f);
gl.glTranslatef(0f, 0f, 0f);
gl.glMatrixMode(GL10.GL_TEXTURE);
gl.glLoadIdentity();
gl.glTranslatef(bgScroll1,0.0f, 0.0f);
background1.draw(gl);
gl.glPopMatrix();
switch(direction)
{
case PLAYER_MOVE_RIGHT:
bgScroll1 +=  SCROLL_BACKGROUND_1;
break;
case PLAYER_MOVE_LEFT:
bgScroll1 -=  SCROLL_BACKGROUND_1;
break;
}
gl.glLoadIdentity();
}

清单 9-2scrollBackground() (OpenGL 是 2/3)

private void scrollBackground1(int direction){
if (bgScroll1 == Float.MAX_VALUE){
bgScroll1 = 0f;
}
background1.draw(mMVPMatrix, bgScroll1);
switch(direction)
{
case PLAYER_MOVE_RIGHT:
bgScroll1 +=  SCROLL_BACKGROUND_1;
break;
case PLAYER_MOVE_LEFT:
bgScroll1 -=  SCROLL_BACKGROUND_1;
break;
}
}

背景现在将根据传递给scrollBackground()方法的方向向右或向左滚动。下一个解决方案将这个方法与玩家的移动联系起来。

9.2 移动背景以响应用户输入

问题

根据玩家的移动,背景不会开始或停止滚动。

解决办法

需要结合movePlayer()方法调用scrollBackground()方法来控制两个的移动。

它是如何工作的

在第 6 章中,清单 6-7 给出了一个解决方案,它创建了一个movePlayer()方法来促进角色的动画。这个方法需要修改,以允许背景的滚动同步到它。首先,更改它的名称以表明它的新用途。

在 OpenGL ES 1 中:

private void movePlayerAndBackground(GL10gl){
...
}

在 OpenGL ES 2/3 中:

private void movePlayerAndBackground(){
...
}

注意,在现有的movePlayer()方法中,有一个switch语句移动播放器(使用 spritesheet)。switch语句需要重写,以便当角色到达屏幕的大致中间时,它不再移动(参见清单 9-3 和 9-4 )。角色应该看起来在这一点上运行到位,背景应该滚动到近似运动。

清单 9-3movePlayerAndBackground() (OpenGL 是 1)

private void movePlayerAndBackground(GL10gl){
background1.draw(gl);
if(!goodguy.isDead)
{
switch(playerAction){
case PLAYER_MOVE_RIGHT:
currentStandingFrame = STANDING_RIGHT;
currentRunAniFrame += .25f;
if (currentRunAniFrame> .75f)
{
currentRunAniFrame = .0f;
}
if(playerCurrentLocation>= 3f)
{
scrollBackground1(gl, playerAction);
gl.glMatrixMode(GL10.GL_MODELVIEW);
gl.glLoadIdentity();
gl.glPushMatrix();
gl.glScalef(.15f, .15f, 1f);
gl.glTranslatef(playerCurrentLocation, .75f, 0f);
gl.glMatrixMode(GL10.GL_TEXTURE);
gl.glLoadIdentity();
gl.glTranslatef(currentRunAniFrame,.50f, 0.0f);
goodguy.draw(gl,spriteSheets,SBG_RUNNING_PTR);
gl.glPopMatrix();
gl.glLoadIdentity();
}else{
playerCurrentLocation += PLAYER_RUN_SPEED;
gl.glMatrixMode(GL10.GL_MODELVIEW);
gl.glLoadIdentity();
gl.glPushMatrix();
gl.glScalef(.15f, .15f, 1f);
gl.glTranslatef(playerCurrentLocation, .75f, 0f);
gl.glMatrixMode(GL10.GL_TEXTURE);
gl.glLoadIdentity();
gl.glTranslatef(currentRunAniFrame,.50f, 0.0f);
goodguy.draw(gl,spriteSheets,SBG_RUNNING_PTR);
gl.glPopMatrix();
gl.glLoadIdentity();
}
break;
case PLAYER_MOVE_LEFT:
currentStandingFrame = STANDING_LEFT;
currentRunAniFrame += .25f;
if (currentRunAniFrame> .75f)
{
currentRunAniFrame = .0f;
}
if(playerCurrentLocation<= 2.5f)
{
scrollBackground1(gl, playerAction);
gl.glMatrixMode(GL10.GL_MODELVIEW);
gl.glLoadIdentity();
gl.glPushMatrix();
gl.glScalef(.15f, .15f, 1f);
gl.glTranslatef(playerCurrentLocation, .75f, 0f);
gl.glMatrixMode(GL10.GL_TEXTURE);
gl.glLoadIdentity();
gl.glTranslatef(currentRunAniFrame,.75f, 0.0f);
goodguy.draw(gl,spriteSheets,SBG_RUNNING_PTR);
gl.glPopMatrix();
gl.glLoadIdentity();
}else{
playerCurrentLocation -= PLAYER_RUN_SPEED;
gl.glMatrixMode(GL10.GL_MODELVIEW);
gl.glLoadIdentity();
gl.glPushMatrix();
gl.glScalef(.15f, .15f, 1f);
gl.glTranslatef(playerCurrentLocation, .75f, 0f);
gl.glMatrixMode(GL10.GL_TEXTURE);
gl.glLoadIdentity();
gl.glTranslatef(currentRunAniFrame,.75f, 0.0f);
goodguy.draw(gl,spriteSheets,SBG_RUNNING_PTR);
gl.glPopMatrix();
gl.glLoadIdentity();
}
break;
case PLAYER_STAND:
gl.glMatrixMode(GL10.GL_MODELVIEW);
gl.glLoadIdentity();
gl.glPushMatrix();
gl.glScalef(.15f, .15f, 1f);
gl.glTranslatef(playerCurrentLocation, .75f, 0f);
gl.glMatrixMode(GL10.GL_TEXTURE);
gl.glLoadIdentity();
gl.glTranslatef(currentStandingFrame,.25f, 0.0f);
goodguy.draw(gl,spriteSheets,SBG_RUNNING_PTR);
gl.glPopMatrix();
gl.glLoadIdentity();
break;
}
}
}

清单 9-4movePlayerAndBackground() (OpenGL 是 2/3)

private void movePlayerAndBackground(){
background1.draw(mMVPMatrix, bgScroll1);
if(!goodguy.isDead)
{
switch(playerAction){
case PLAYER_MOVE_RIGHT:
currentStandingFrame = STANDING_RIGHT;
currentRunAniFrame += .25f;
if (currentRunAniFrame> .75f)
{
currentRunAniFrame = .0f;
}
if(playerCurrentLocation>= 3f)
{
scrollBackground1(playerAction);
goodguy.draw(spriteSheets,SBG_RUNNING_PTR, currentRunAniFrame, .75f);
}else{
playerCurrentLocation += PLAYER_RUN_SPEED;
goodguy.draw(spriteSheets,SBG_RUNNING_PTR, currentRunAniFrame, .50f);
}
break;
case PLAYER_MOVE_LEFT:
currentStandingFrame = STANDING_LEFT;
currentRunAniFrame += .25f;
if (currentRunAniFrame> .75f)
{
currentRunAniFrame = .0f;
}
if(playerCurrentLocation<= 2.5f)
{
scrollBackground1(playerAction);
goodguy.draw(spriteSheets,SBG_RUNNING_PTR, currentRunAniFrame, .75f);
}else{
playerCurrentLocation -= PLAYER_RUN_SPEED;
goodguy.draw(spriteSheets,SBG_RUNNING_PTR, currentRunAniFrame, .50f);
}
break;
case PLAYER_STAND:
goodguy.draw(spriteSheets,SBG_RUNNING_PTR, currentStandingFrame, .25f);
break;
}
}
}

角色动画大约在中途停止在屏幕上前进。然后该方法调用scrollBackground()方法开始移动背景。


推荐阅读
  • IOS开发之短信发送与拨打电话的方法详解
    本文详细介绍了在IOS开发中实现短信发送和拨打电话的两种方式,一种是使用系统底层发送,虽然无法自定义短信内容和返回原应用,但是简单方便;另一种是使用第三方框架发送,需要导入MessageUI头文件,并遵守MFMessageComposeViewControllerDelegate协议,可以实现自定义短信内容和返回原应用的功能。 ... [详细]
  • 如何在HTML中获取鼠标的当前位置
    本文介绍了在HTML中获取鼠标当前位置的三种方法,分别是相对于屏幕的位置、相对于窗口的位置以及考虑了页面滚动因素的位置。通过这些方法可以准确获取鼠标的坐标信息。 ... [详细]
  • 在Android开发中,使用Picasso库可以实现对网络图片的等比例缩放。本文介绍了使用Picasso库进行图片缩放的方法,并提供了具体的代码实现。通过获取图片的宽高,计算目标宽度和高度,并创建新图实现等比例缩放。 ... [详细]
  • 本文介绍了在Win10上安装WinPythonHadoop的详细步骤,包括安装Python环境、安装JDK8、安装pyspark、安装Hadoop和Spark、设置环境变量、下载winutils.exe等。同时提醒注意Hadoop版本与pyspark版本的一致性,并建议重启电脑以确保安装成功。 ... [详细]
  • 后台获取视图对应的字符串
    1.帮助类后台获取视图对应的字符串publicclassViewHelper{将View输出为字符串(注:不会执行对应的ac ... [详细]
  • sklearn数据集库中的常用数据集类型介绍
    本文介绍了sklearn数据集库中常用的数据集类型,包括玩具数据集和样本生成器。其中详细介绍了波士顿房价数据集,包含了波士顿506处房屋的13种不同特征以及房屋价格,适用于回归任务。 ... [详细]
  • 拥抱Android Design Support Library新变化(导航视图、悬浮ActionBar)
    转载请注明明桑AndroidAndroid5.0Loollipop作为Android最重要的版本之一,为我们带来了全新的界面风格和设计语言。看起来很受欢迎࿰ ... [详细]
  • 本文介绍了在Vue项目中如何结合Element UI解决连续上传多张图片及图片编辑的问题。作者强调了在编码前要明确需求和所需要的结果,并详细描述了自己的代码实现过程。 ... [详细]
  • Go Cobra命令行工具入门教程
    本文介绍了Go语言实现的命令行工具Cobra的基本概念、安装方法和入门实践。Cobra被广泛应用于各种项目中,如Kubernetes、Hugo和Github CLI等。通过使用Cobra,我们可以快速创建命令行工具,适用于写测试脚本和各种服务的Admin CLI。文章还通过一个简单的demo演示了Cobra的使用方法。 ... [详细]
  • 本文介绍了一款名为TimeSelector的Android日期时间选择器,采用了Material Design风格,可以在Android Studio中通过gradle添加依赖来使用,也可以在Eclipse中下载源码使用。文章详细介绍了TimeSelector的构造方法和参数说明,以及如何使用回调函数来处理选取时间后的操作。同时还提供了示例代码和可选的起始时间和结束时间设置。 ... [详细]
  • 本文详细介绍了Android中的坐标系以及与View相关的方法。首先介绍了Android坐标系和视图坐标系的概念,并通过图示进行了解释。接着提到了View的大小可以超过手机屏幕,并且只有在手机屏幕内才能看到。最后,作者表示将在后续文章中继续探讨与View相关的内容。 ... [详细]
  • 本文介绍了Cocos2dx学习笔记中的更新函数scheduleUpdate、进度计时器CCProgressTo和滚动视图CCScrollView的用法。详细介绍了scheduleUpdate函数的作用和使用方法,以及schedule函数的区别。同时,还提供了相关的代码示例。 ... [详细]
  • C#多线程解决界面卡死问题的完美解决方案
    当界面需要在程序运行中不断更新数据时,使用多线程可以解决界面卡死的问题。一个主线程创建界面,使用一个子线程执行程序并更新主界面,可以避免卡死现象。本文分享了一个例子,供大家参考。 ... [详细]
  • MySQL多表数据库操作方法及子查询详解
    本文详细介绍了MySQL数据库的多表操作方法,包括增删改和单表查询,同时还解释了子查询的概念和用法。文章通过示例和步骤说明了如何进行数据的插入、删除和更新操作,以及如何执行单表查询和使用聚合函数进行统计。对于需要对MySQL数据库进行操作的读者来说,本文是一个非常实用的参考资料。 ... [详细]
  • 微信小程序导航跟随的实现方法
    本文介绍了在微信小程序中实现导航跟随的方法。通过设置导航的position属性和绑定滚动事件,可以实现页面向下滚动到导航位置时,导航固定在页面最上方;页面向上滚动到导航位置时,导航恢复到原始位置;点击导航可以平滑跳转到相应位置。代码示例也给出了具体实现方法。 ... [详细]
author-avatar
二十三点二十三分_465
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有