《Android 应用案例开发大全(第3版)》——第2章,第2.6节绘制相关类

    xiaoxiao2024-01-23  20

    本节书摘来自异步社区《Android 应用案例开发大全(第3版)》一书中的第2章,第2.6节绘制相关类,作者 吴亚峰 , 苏亚光 , 于复兴,更多章节内容可以访问云栖社区“异步社区”公众号查看

    2.6 绘制相关类前面详细介绍了百纳水族馆辅助绘制类的开发过程,下面将对百纳水族馆中的绘制相关类进行详细介绍,主要包括气泡绘制相关类、群鱼绘制相关类、鱼群绘制相关类以及鱼食绘制相关类,从而使读者对百纳水族馆的开发有一个更加深刻地理解。

    2.6.1 气泡绘制相关类真实的水族馆中时常会冒出一些气泡,这样使壁纸显得更加真实,更加具有观赏性。下面将详细介绍绘制气泡相关类,绘制气泡相关类分为气泡控制类BubbleControl,以及用来控制所有气泡的绘制和单个气泡绘制类SingleBubble。单个气泡绘制类SingleBubble用来对单个气泡进行绘制,开发步骤如下所示。

    (1)首先介绍单个气泡绘制类SingleBubble。在单个气泡绘制类中给出了气泡的初始位置,随机设置了气泡上升的最大高度等。绘制气泡时用到了混合技术,对对象的绘制顺序是有严格要求的,即绘制顺序是由远及近的,所以,在绘制气泡之前要根据气泡的位置进行排序,具体代码如下所示。

    ![{37}](/api/storage/getbykey/screenshow?key=151178a4d1d9e6d6e470)代码位置:见随书光盘源代码/第2章/wyf/lxg/bubble/目录下的SingleBubble.Java。 1 package wyf.lxg.bubble; 2 .....//此处省略部分类和包的导入代码,请读者自行查阅随书附带光盘的源代码 3 public class SingleBubble implements Comparable<SingleBubble>{ 4 Bubble bubble; //气泡对象 5 float cuerrentX=0; //气泡当前X位置 6 float cuerrentY=1; //气泡当前Y位置 7 float cuerrentZ=0; //气泡当前Z位置 8 float border; //气泡的最大高度 9 int TexId; //纹理ID 10 public SingleBubble(MySurfaceView mySurfaceView,int TexId){ 11 this.TexId=TexId; 12 bubble=new Bubble(mySurfaceView); //创建气泡 13 newposition(-1); //初始气泡的位置 14 } 15 public void drawSelf(){ 16 MatrixState.pushMatrix(); //保护矩阵 17 MatrixState.translate(cuerrentX, cuerrentY, cuerrentZ); //移动 18 bubble.drawSelf(TexId); //绘制气泡 19 MatrixState.popMatrix() //恢复矩阵 20 } 21 public void bubbleMove(float x,float y) { 22 this.cuerrentY += Constant.BubbleMoveDistance; //气泡上下移动 23 this.cuerrentX +=(float)(0.01*y); //气泡左右晃动 24 this.cuerrentZ +=(float)(0.015*y)+0.1; //越来越大效果 25 if (this.cuerrentY > border) { 26 newposition(x); //重置气泡位置 27 }} 28 public void newposition(float x) { 29 if(x==-1){ //第一处气泡的初始位置 30 cuerrentX = ; //X位置 31 cuerrentY = ; //Y位置 32 cuerrentZ = ; //Z位置 33 }else if(x==1){ //第二处气泡的初始位置 34 cuerrentX = ; //X位置 35 cuerrentY = ; //Y位置 36 cuerrentZ = ; //Z位置 37 }else if(x==0){ //第三处气泡的初始位置 38 cuerrentX = ; //X位置 39 cuerrentY = ; //Y位置 40 cuerrentZ = ; //Z位置 41 } 42 border = (float) (2 * Math.random() + 3); //气泡上升的最大高度 43 } 44 public int compareTo(SingleBubble another){//重写的比较两个气泡与摄像机距离的方法 45 return ((this.cuerrentZ-another.cuerrentZ)==0)?0:((this.cuerrentZ-another. cuerrentZ)>0)?1:-1; 46 }}

    第1~14行首先声明相关变量,包括气泡的当前位置、气泡的纹理ID、气泡的最大高度、气泡对象等,然后在构造器中第一次调用newposition方法,初始化百纳水族馆中三处气泡的位置,并且随机设置气泡的上升最大高度。第15~27行首先是根据气泡的当前位置绘制气泡,设置气泡的移动速度,并修改气泡的位置,尤其是Z位置,Z位置离摄像机越来越近,气泡会就产生越来越大的效果。判断气泡的位置是否大于气泡的最大高度border,如果大于border,则调用newposition方法重新设置气泡的位置。第28~46行首先根据接收到的x值确定气泡出现的位置,其次随机产生气泡上升的最大高度,气泡每次消失后都会重新调用newposition方法,然后重写compareTo方法根据气泡的位置对气泡列表中的气泡对象进行排序。(2)上面已经对单个气泡绘制类SingleBubble类进行了详细介绍,接下来就应该对所有气泡控制类BubbleControl进行介绍。气泡控制类中包括创建单个气泡对象,创建并且启动气泡移动线程,绘制气泡等。具体代码如下所示。

    代码位置:见随书光盘源代码/第2章/wyf/lxg/bubble/目录下的BubbleControl.Java。

    1 package wyf.lxg.bubble; 2 .....//此处省略部分类和包的导入代码,请读者自行查阅随书附带光盘的源代码 3 public class BubbleControl { 4 public ArrayList<SingleBubble> BubbleSingle=new ArrayList<SingleBubble>(); //气泡类的列表 5 int texld; //气泡的纹理ID 6 MySurfaceView mv; //场景渲染器 7 public BubbleControl(MySurfaceView mv,int texld ) { 8 this.mv=mv; 9 this.texld = texld; //获取ID 10 for (int i = 0; i <Constant.BUBBLE_NUM; i++) { //创建多个气泡 11 BubbleSingle.add(new SingleBubble(mv,this.texld));//添加到列表 12 } 13 BubbleThread Bgt = new BubbleThread(this); //创建气泡移动线程 14 Bgt.start(); //启动气泡移动线程 15 } 16 public void drawSelf() { 17 try { 18 Collections.sort(this.BubbleSingle); //对气泡排序 19 for (int i = 0; i < this.BubbleSingle.size(); i++) { 20 MatrixState.pushMatrix(); //保护矩阵 21 BubbleSingle.get(i).drawSelf(); //绘制气泡 22 MatrixState.popMatrix(); //恢复矩阵 23 }} catch (Exception e) { 24 e.printStackTrace(); //打印异常栈信息 25 }}} `` 第1~15行首先声明包名,创建气泡类列表,声明气泡纹理ID和场景渲染器,在构造器中获取纹理ID,创建多个气泡并且将其添加到气泡列表中,然后创建并且启动气泡移动线程。其中省略部分类和包的导入代码,请读者自行查阅随书附带光盘的源代码。 第16~25行的主要作用是绘制气泡,因为采用混合技术,所以在绘制气泡之前,要先对气泡列表中的气泡进行排序,之后遍历气泡列表,保护现场,进行气泡绘制,然后恢复现场。 **2.6.2 群鱼绘制相关类** 群鱼是百纳水族馆的主要元素,下面将详细介绍群鱼绘制相关类。群鱼绘制相关类分为单条鱼绘制类SingleFish,用来对单条鱼进行绘制;以及群鱼控制类FishControl,用来控制群鱼里所有鱼的绘制,当然也包括乌龟和珍珠贝的绘制。开发步骤如下所示。 (1)首先进行的是单条鱼绘制类SingleFish的开发介绍。在SingleFish类中设置了群鱼(包括乌龟)中每个鱼的位置、速度、质量(力的缩放比)、所受到的外力、鱼食对鱼的吸引力、旋转角度等。其中动态修改鱼游动的方法fishMove代码较长,将在后面详细介绍。具体代码如下所示。 代码位置:见随书光盘源代码/第2章/wyf/lxg/fish/目录下的SingleFish.Java。

    1 package wyf.lxg.fish;2 .....//此处省略部分类和包的导入代码,请读者自行查阅随书附带光盘的源代码3 public class SingleFish {4 .....//此处省略相关成员变量的声明代码,请读者自行查阅随书附带光盘的源代码5 public SingleFish(MS3DModel mx,int texid,6 Vector Position, Vector Speed, Vector force,Vector attractforce, float weight) {7 this.md=mx; //鱼的模型8 this.texid=texid; //鱼的纹理ID9 this.position = Position; //鱼的位置10 this.speed = Speed; //鱼的速度11 this.force = force; //鱼所受外力12 this.attractforce = attractforce; //鱼食对鱼的吸引力13 this.weight = weight; //鱼的质量14 }15 public void drawSelf() {16 MatrixState.pushMatrix(); //保护矩阵17 MatrixState.translate(this.position.x,this.position.y,this.position.z); //平移18 MatrixState.rotate(yAngle, 0, 1, 0); //Y轴旋转19 MatrixState.rotate(zAngle, 0, 0, 1); //Z轴旋转20 if (md != null) {21 this.md.animate(time,texid); //绘制鱼22 }23 MatrixState.popMatrix(); //恢复矩阵24 time += ; //更新模型动画时间25 if(time > this.md.getTotalTime()) {//若当前播放时间大于总的动画时间26 time = time - this.md.getTotalTime();

    //播放时间等于当前播放时间减去总的动画时间

    27 }}28 public void fishMove() {29 .....//此处省略动态修改鱼游动的代码,将在后面详细介绍30 }}

    第1~14行首先声明包名,通过构造器接收传递过来的鱼的纹理ID、鱼的位置、鱼的速度、鱼所受的外力、鱼食对鱼的吸引力等参数信息。其中此处省略了部分类和包的导入代码以及相关成员变量的声明代码,请读者自行查阅随书附带光盘的源代码。 第15~30行是鱼类绘制方法,当然也包括乌龟的绘制。绘制之前先保护变换矩阵再将鱼平移到指定位置,并让坐标轴旋转相应的角度,从而使鱼能以一个正确的姿态显示在屏幕上,然后再进行鱼的绘制。其中骨骼动画播放时间若大于总的动画时间,则实际播放时间等于当前播放时间减去总的动画时间。 (2)接下来详细介绍前面省略的fishMove方法,该方法的作用是根据鱼的速度矢量确定出鱼的朝向,然后计算出坐标轴相应的旋转角度;根据鱼所受到的外力和食物吸引力的作用,动态修改鱼的速度。每次计算每条鱼的受力之后,把所受的力置零。具体代码如下所示。 代码位置:见随书光盘源代码/第2章/wyf/lxg/fish/目录下的SingleFish.Java。

    1 public void fishMove() {2 float fz = (speed.x speed.x + speed.y 0 + speed.z * speed.z); //分子3 float fm = (float) (Math.sqrt(speed.x speed.x + speed.y speed.y//分母4 + speed.z speed.z) Math.sqrt(speed.x speed.x + speed.z speed.z));5 float angle = fz / fm; //cos值6 tempZ = (float)( / Math.PI) * (float) Math.acos(angle);//绕Z轴的旋转角度7 fz = (speed.x Constant.initialize.x + speed.z Constant.initialize.z);//分子8 fm = (float) (Math.sqrt(Constant.initialize.x * Constant.initialize.x+//分母9 Constant.initialize.zConstant.initialize.z)Math.sqrt(speed.x*speed.x+ speed.z*speed.z));10 angle = fz / fm; //cos值11 tempY = (float) ( / Math.PI) * (float) Math.acos(angle);//绕Y轴的旋转角度12 if (speed.y <= 0) { //获取夹角,根据Speed.y的正负性来确定夹角的正负性13 zAngle = tempZ;14 } else { //上述计算得出的角度均为正值15 zAngle = -tempZ;16 }17 if (speed.z > 0) { //获取夹角,根据Speed.z的正负性来确定夹角的正负性18 yAngle = tempY;19 } else { //上述计算得出的角度均为正值20 yAngle = -tempY;21 }22 if (Math.abs(speed.x + force.x) < Constant.MaxSpeed) {23 speed.x += force.x; //动态修改鱼X方向的速度24 }25 if (Math.abs(speed.y + force.y) < Constant.MaxSpeed){26 speed.y += force.y; //动态修改鱼Y方向的速度27 }28 if (Math.abs(speed.z + force.z) < Constant.MaxSpeed) {29 speed.z += force.z; //动态修改鱼Z方向的速度30 }31 if (Math.abs(speed.x + attractforce.x) < Constant.MaxSpeed) {32 speed.x += attractforce.x; //动态修改鱼X方向的速度33 }34 if (Math.abs(speed.y + attractforce.y) < Constant.MaxSpeed) {35 speed.y += attractforce.y; //动态修改鱼Y方向的速度36 }37 if (Math.abs(speed.z + attractforce.z) < Constant.MaxSpeed) {38 speed.z += attractforce.z; //动态修改鱼Z方向的速度39 }40 position.plus(speed); //改变鱼的位置41 this.force.x = 0; //外力置为零42 this.force.y = 0;43 this.force.z = 0;44 attractforce.x = 0; //鱼食对鱼的吸引力置为零45 attractforce.y = 0;46 attractforce.z = 0;47 }

    第1~21行为计算坐标轴相应旋转角度的方法。根据鱼的速度矢量确定出鱼的朝向,利用初等函数计算出坐标轴相应的旋转角度。因为计算出来的角度均为正值,所以需要根据Speed.y和Speed.z的正负性来确定夹角的正负性。 第22~39行为动态修改鱼速度的方法,鱼可能会受到外力(排斥力)和食物吸引力的作用,力会改变鱼的速度,当鱼的速度超过阈值时,速度不再增加。将鱼的速度矢量和位移矢量相加就会得到鱼的新位移矢量。 第40~47行改变鱼的位置,防止鱼穿过地面,然后每次计算每条鱼的受力之后,把所受的力置零。因为每次都要重新计算鱼的受力,因此当鱼不受到力的作用时,鱼的速度就不会再改变,鱼将沿着当前的速度方向游动。 (3)前面已经对单条鱼绘制类SingleFish进行了介绍,下面将进行鱼群控制类FishControl的开发介绍。在该类中将创建群鱼列表,创建并且启动群鱼的游动线程,然后遍历群鱼列表对除鱼群以外的单条鱼(包括乌龟)进行绘制。具体代码如下所示。 代码位置:见随书光盘源代码/第2章/wyf/lxg/fish/目录下的FishControl.Java。

    1 package wyf.lxg.fish;2 .....//此处省略部分类和包的导入代码,请读者自行查阅随书附带光盘的源代码3 public class FishControl {4 public ArrayList fishAl; //群鱼列表5 FishGoThread fgt; //鱼Go线程6 public MySurfaceView My; //渲染器7 public FishControl(ArrayList fishAl,MySurfaceView my){8 this.fishAl = fishAl; //群鱼列表9 this.My=my;10 fgt= new FishGoThread(this); //创建鱼移动线程对象11 fgt.start(); //启动鱼的移动线程12 }13 public void drawSelf(){14 try {15 for(int i=0;i16 MatrixState.pushMatrix(); //保护矩阵17 fishAl.get(i).drawSelf(); //绘制鱼18 MatrixState.popMatrix(); //恢复矩阵19 }}catch (Exception e) {20 e.printStackTrace(); //打印异常栈信息21 }}}

    第1~12行为声明群鱼列表、鱼游动线程以及场景渲染器等相关变量,通过构造方法接收群鱼列表,创建鱼游动线程对象并且启动鱼的游动线程。此处省略部分类和包的导入代码,请读者自行查阅随书附带光盘的源代码。 第13~21行为绘制鱼的方法。首先保护变换矩阵,其次遍历群鱼列表,循环绘制除鱼群以外的单条鱼以及乌龟,最后恢复变换矩阵,进行异常处理。 **2.6.3 鱼群绘制相关类** 前面已经详细介绍了群鱼的绘制相关类,下面将对鱼群绘制相关类的开发进行详细介绍。鱼群绘制相关类分为单条鱼绘制类SingleFishSchool,用来对鱼群中单条鱼进行绘制;以及鱼群控制类FishSchoolControl,用来控制鱼群里所有鱼的绘制。开发步骤如下所示。 (1)首先对鱼群中单个鱼的绘制类SingleFishSchool的开发进行详细的介绍。在单个鱼绘制类中设置鱼的位置,鱼的速度,鱼的质量,鱼受到的外力,鱼受到的向心力(第一条鱼不受到向心力作用)以及鱼的旋转角度,具体代码如下所示。 代码位置:见随书光盘源代码/第2章/wyf/lxg/fishschool/目录下的SingleFishSchool.Java。

    1 package wyf.lxg.fishschool;2 .....//此处省略部分类和包的导入代码,请读者自行查阅随书附带光盘的源代码3 public class SingleFishSchool {4 .....//此处省略相关成员变量的声明代码,请读者自行查阅随书附带光盘的源代码5 public SingleFishSchool(MS3DModel md,int texid,Vector Position,6 Vector Speed, Vector force,Vector ConstantForce, float weight) {7 this.texid=texid; //鱼的纹理ID8 this.position = Position; //鱼的位置9 this.speed = Speed; //鱼的速度10 this.force = force; //鱼所受到的外力11 this.weight = weight; //鱼的质量12 this.mt=md; //鱼的模型13 this.ConstantPosition.x = Position.x; //X位移14 this.ConstantPosition.y = Position.y; //Y位移15 this.ConstantPosition.z = Position.z; //Z位移16 this.ConstantForce = ConstantForce; //鱼受到的向心力17 }18 public void drawSelf() {19 MatrixState.pushMatrix(); //保护矩阵20 MatrixState.translate(this.position.x, this.position.y, this.

    position.z);

    21 MatrixState.rotate(yAngle, 0, 1, 0); //绕Y轴旋转相应角度22 MatrixState.rotate(zAngle, 0, 0, 1); //绕Z轴旋转相应角度23 if (mt != null) {24 this.mt.animate(time,texid); //播放动画,绘制鱼25 }26 MatrixState.popMatrix(); //恢复矩阵27 .....//此处省略动画更新时间的代码,请读者自行查阅随书附带光盘的源代码28 }29 public void fishschoolMove() { //根据鱼类的位置以及速度来计算鱼的下一个位置30 if (speed.x == 0 && speed.z == 0 && speed.y > 0){ //Y轴速度大于031 tempZ = -90;32 tempY = 0;33 } else if (speed.x == 0 && speed.z == 0 && speed.y < 0){//Y轴速度小于034 tempZ = 90;35 tempY = 0;36 } else if (speed.x == 0 && speed.z == 0 && speed.y == 0){//Y轴速度等于037 tempZ = 90;38 tempY = 0;39 } else {40 .....//此处与前面的fishMove方法相似,故省略,请读者自行查阅随书附带光盘的源代码41 }}

    第1~17行通过构造器接收鱼的纹理ID,鱼的初始位置,鱼的初始速度,鱼所受到的外力,鱼受到的向心力等。此处省略了部分类和包的导入代码以及相关成员变量的声明代码,请读者自行查阅随书附带光盘的源代码。 第18~41行为鱼的绘制方法以及修改鱼速度的方法。首先平移到指定的位置,绕Y轴、Z轴旋转相应的角度,从而使鱼能以一个正确的姿态显示在屏幕上,其次进行鱼的绘制。然后根据鱼类的位置以及速度来计算鱼的下一个位置。 说明 第40行省略的代码与群鱼绘制时单条鱼绘制类中的fishMove方法相似,请读者自行查阅随书附带光盘的源代码。但是鱼群中第一条鱼是不会受到向心力的作用的,且只有其他鱼超出阈值之后才会受到向心力的作用。 (2)前面已经完成了对鱼群中单个鱼的绘制类SingleFishSchool的详细介绍,接下来进行鱼群控制类FishSchoolControl的开发介绍。在鱼群控制类中创建了鱼群列表,并将单条鱼对象以及单条鱼的相关信息添加进鱼群列表,同时创建了鱼群游动线程并启动。具体代码如下所示。 代码位置:见随书光盘源代码/第2章/wyf/lxg/fishschool/目录下的FishSchoolControl.Java。

    1 package wyf.lxg.fishschool;2 .....//此处省略部分类和包的导入代码,请读者自行查阅随书附带光盘的源代码3 public class FishSchoolControl {4 .....//此处省略相关成员变量的声明代码,请读者自行查阅随书附带光盘的源代码5 public FishSchoolControl(MS3DModel md,int texid,6 MySurfaceView tr,Vector weizhi,Vector sudu,float weight) {7 this.Tr = tr; //场景渲染器8 this.texid=texid; //纹理ID9 if(sudu.x>0){ //根据第一条鱼的速度10 x=sudu.x; //计算鱼的X、Z方向速度11 }else{12 x=sudu.x+; //计算鱼的X、Z方向速度13 }14 fishSchool.add(new SingleFishSchool(md,this.texid, //第一条鱼15 weizhi, sudu,new Vector(0, 0, 0), new Vector(0, 0, 0), weight));16 fishSchool.add(new SingleFishSchool(md,this.texid, //第二条鱼17 new Vector(weizhi.x, weizhi.y, -Constant.Radius), new Vector(x,18 , x), new Vector(0, 0, 0), new Vector(0,0, 0), weight));

    //方向吸引力重力

    19 fishSchool.add(new SingleFishSchool(md,this.texid, //第三条鱼20 new Vector(Constant.Radius, weizhi.y, weizhi.z), new Vector(x,21 , x), new Vector(0, 0, 0), new Vector(0,0, 0), weight));22 fishSchool.add(new SingleFishSchool(md,this.texid, //第四条鱼23 new Vector(weizhi.x, weizhi.y, Constant.Radius), new Vector(x,24 , x), new Vector(0, 0, 0), new Vector(0,0, 0), weight));25 Thread = new FishschoolThread(this); //创建鱼群游动线程26 hread.start(); //启动鱼群游动线程27 }28 public void drawSelf() {29 try {30 for (int i = 0; i < this.fishSchool.size(); i++){31 MatrixState.pushMatrix(); //保护矩阵32 fishSchool.get(i).drawSelf(); //绘制鱼群33 MatrixState.popMatrix(); //恢复矩阵34 }} catch (Exception e){35 e.printStackTrace(); //打印异常栈信息36 }}}

    第1~13行通过构造器接收鱼类的纹理ID、场景渲染器,并且同过接收到的第一条鱼的速度计算出其余3条鱼的X方向和Z方向速度。此处省略部分类和包的导入代码以及相关成员变量的声明代码,请读者自行查阅随书附带光盘的源代码。 第14~27行向鱼群列表中添加鱼对象,同时创建并启动鱼群游动线程。鱼群列表里的第一条鱼不受其他任何鱼的作用力,只受到墙壁的作用力,并且鱼群里面的鱼(不包括第一条鱼)在特定的条件下受到从该鱼本身指向某个位置的向心力作用。 第28~36行为绘制鱼群的方法。首先循环遍历fishSchool列表,绘制鱼群里面的鱼。在绘制之前要先保护变换矩阵,然后再进行鱼群的绘制,最后恢复变换矩阵。 **2.6.4 鱼食绘制相关类** 本小节详细介绍鱼食绘制相关类。在百纳水族馆中可以对游动的鱼进行喂食,点击地面,鱼食就会下落。并且点击地面远点时食物会相对小一些,点击地面近点时食物会相对大一些,从而产生近大远小的效果。其中鱼食的绘制相关类包括鱼食绘制类SingleFood,用来绘制鱼食;以及鱼食控制类FeedFish,用来控制鱼食的绘制以及鱼食的下落速度等。开发步骤如下所示。 (1)首先介绍单个鱼食的绘制类SingleFood的开发。SingleFood类具体包括实例化食物移动线程和食物吸引力线程,动态改变食物的Y位置和X位置,并且启动食物移动线程和食物吸引力线程,然后进行食物的绘制等。具体代码如下所示。 代码位置:见随书光盘源代码/第2章/wyf/lxg/fishfood/目录下的SingleFood.Java。

    1 package wyf.lxg.fishfood;2 .....//此处省略部分类和包的导入代码,请读者自行查阅随书附带光盘的源代码3 public class SingleFood {4 public FoodThread Ft; //食物移动线程5 public AttractThread At; //吸引力线程6 public MySurfaceView mv; //场景渲染器7 public float Ypositon =Constant.FoodPositionMax_Y; //获取Ypositon8 LoadedObjectVertexNormalTexture fishFoods; //创建鱼食对象9 int texld; //纹理ID10 public SingleFood(int texld,LoadedObjectVertexNormalTexture fishfoods, MySurfaceView mv){11 this.texld=texld; //获取纹理ID12 this.mv = mv;13 fishFoods = fishfoods; //实例化食物

    Ft = new FoodThread(this); //实例化食物移动线程

    15 At = new AttractThread(this); //实例化吸引力线程16 }17 public void StartFeed(){ Ft.start(); //启动鱼食移动线程19 At.start(); //启动吸引力线程20 }21 public void drawSelf() {22 MatrixState.pushMatrix(); //保护矩阵23 MatrixState.translate(mv.Xposition,this.Ypositon,mv.Zposition);//平移24 fishFoods.drawSelf(texld); //绘制鱼食25 MatrixState.popMatrix(); //恢复矩阵26 }}

    第1~16行主要获取鱼食的Ypositon,创建鱼食对象,声明食物移动线程和吸引力线程,同时通过构造器实例化食物移动线程和吸引力线程。此处省略部分类和包的导入代码,请读者自行查阅随书附带光盘的源代码。 第17~26行首先是StartFeed方法,用来启动鱼食移动线程和吸引力线程。然后是drawSelf方法,进行鱼食的绘制,先平移到指定的位置,从而使鱼食能以一个正确的姿态显示在屏幕上,再进行鱼食的绘制。 (2)下面将对鱼食控制类FeedFish进行详细的介绍,具体包括设置鱼食的初始位置,根据地面的高度算出t值,根据t计算出拾取射线与近平面和远平面的交点坐标,更改鱼食移动线程和吸引力线程的标志位等,具体代码如下所示。 代码位置:见随书光盘源代码/第2章/wyf/lxg/fishfood/目录下的FeedFish.Java。

    1 package wyf.lxg.fishfood;2 .....//此处省略部分类和包的导入代码,请读者自行查阅随书附带光盘的源代码3 public class FeedFish {4 MySurfaceView Tr; //场景渲染器5 boolean start; //启动移动食物线程标志位6 public FeedFish(MySurfaceView tr) {7 start = true; //启动移动食物线程8 this.Tr = tr;9 }10 public void startFeed(Vector Start,Vector End) {11 Vector dv=End.cutPc(Start); //喂食的位置12 float t=(Constant.Y_HEIGHT -Start.y)/dv.y; //根据地面的高度算出t值13 float xd=Start.x+t*dv.x; //根据t计算出交点的X坐标值14 float zd=Start.z+t*dv.z; //根据t计算出交点的Z坐标值15 if(zd<=Constant.ZTouch_Min ||zd>Constant.ZTouch_Max){16 Constant.isFeed=true; //超出一定范围鱼食的大小不改变17 return; //并且位置不改变,食物不重置18 }19 Tr.Xposition = xd; //食物的位置20 Tr.Zposition = zd;21 Tr.Fooddraw = true; //绘制食物的标志位22 Tr.singlefood.Ft.Fresit = true; //把重置Yposition的标志位变为true23 Tr.singlefood.At.Go = true; //将吸引力线程标志位设为true24 Tr.singlefood.Ft.Go = true; //将喂食线程标志位设为true25 if (start) { //调用此方法开始移动食物的方法26 Tr.singlefood.StartFeed(); //开始喂食27 start = false; //标志位设为false28 }}}

    第1~14行为计算屏幕触控点的位置的算法。首先声明启动食物移动线程的标志位,再根据地面的高度算出t值,然后根据t计算出近平面和远平面与地面的交点的X、Z坐标值(根据3点共线求出与地面平面的交点)。 相关资源:敏捷开发V1.0.pptx
    最新回复(0)