Java 在任意方向连续滚动一个大型无缝图像
这个问题与游戏有关,但我认为它可以应用于其他用例 我有一个比屏幕大的无缝图像。大约两倍大。目标是使此图像可以在曲面上的任何方向滚动。这是Android的 我看到了一些关于一般图像的问题/答案,但不是无缝图像 这里的区别,我的问题是如何处理滚动,在某些情况下,显示的图像可能有4个独立的部分(当用户沿对角线滚动图像的一半时) 很明显,当您想将图像边到边滚动时,该如何操作。使用世界值,并使用矩形显示您所在位置的某种“视口” 比如:Java 在任意方向连续滚动一个大型无缝图像,java,android,image,math,Java,Android,Image,Math,这个问题与游戏有关,但我认为它可以应用于其他用例 我有一个比屏幕大的无缝图像。大约两倍大。目标是使此图像可以在曲面上的任何方向滚动。这是Android的 我看到了一些关于一般图像的问题/答案,但不是无缝图像 这里的区别,我的问题是如何处理滚动,在某些情况下,显示的图像可能有4个独立的部分(当用户沿对角线滚动图像的一半时) 很明显,当您想将图像边到边滚动时,该如何操作。使用世界值,并使用矩形显示您所在位置的某种“视口” 比如: Rect oRect1 = new Rect(dWorldX, dWo
Rect oRect1 = new Rect(dWorldX, dWorldY, dWorldX + canvas.getWidth(), dWorldY + canvas.getHeight());
Rect oRect2 = new Rect(0, 0, canvas.getWidth(), canvas.getHeight());
canvas.drawBitmap(largeBitmapTexture, oRect1, oRect2, new Paint());
(-100,-100) (0,-100) (100,-100) (200,-100)
******************************************
* * * *
* * * *
* * * *
* * * *
*(-100,0) *(0,0) *(100,0) *(200,0)
******************************************
* * * *
* * * *
* * * *
* * * *
*(-100,100) *(0,100) *(100,100) *(200,100)
******************************************
* * * *
* * * *
* * * *
* * * *
*(-100,200) *(0,200) *(100,200) *(200,200)
******************************************
(-100,-100) (0,-100) (100,-100) (200,-100)
******************************************
* * * *
* * * *
* * * *
* * * *
*(-100,0) *(0,0) *(100,0) *(200,0)
******************************************
* * * *
* * * *
* * (75,75) * (125,75) *
* * ####### *
*(-100,100) *(0,100) # * # *(200,100)
************************#*****#***********
* * # * # *
* * ####### *
* * (75,125) * (125,125) *
* * * *
*(-100,200) *(0,200) *(100,200) *(200,200)
******************************************
但是,当位图无缝且连续滚动时,这对我来说是一个编程挑战。我是否使用了一堆if语句?有没有更有效的方法来做这样的事情
编辑:还有一些想法。这里的一个复杂问题是世界(x,y)是无限大的。因此,我必须使用屏幕宽度和高度的划分来显示需要显示的内容。我最初考虑只进行4次Rect迭代,因为屏幕上的图像不会超过4个。如果这有意义的话。我想我只是对如何计算有点模糊
编辑:这是我现在拥有的代码,以及@glowcoder的建议
public void draw(Canvas canvas){
int iImagesOverX=0;
int iImagesOverY=0;
iImagesOverX = (int)dX / mCloud.getIntrinsicWidth();
iImagesOverY = (int)dY / mCloud.getIntrinsicHeight();
mCloud.setBounds(iImagesOverX * (int)mCloud.getIntrinsicWidth() , iImagesOverY * (int)mCloud.getIntrinsicHeight() , (iImagesOverX * (int)mCloud.getIntrinsicWidth()) + mCloud.getIntrinsicWidth() , (iImagesOverY * (int)mCloud.getIntrinsicHeight()) + mCloud.getIntrinsicHeight() );
Log.d(TAG, "bounds:"+ mCloud.getBounds());
mCloud.draw(canvas);
mCloud.setBounds((iImagesOverX + 1) * (int)mCloud.getIntrinsicWidth() , iImagesOverY * (int)mCloud.getIntrinsicHeight() , ((iImagesOverX + 1) * (int)mCloud.getIntrinsicWidth()) + mCloud.getIntrinsicWidth() , (iImagesOverY * (int)mCloud.getIntrinsicHeight()) + mCloud.getIntrinsicHeight() );
mCloud.draw(canvas);
mCloud.setBounds((iImagesOverX + 1) * (int)mCloud.getIntrinsicWidth() , (iImagesOverY + 1)* (int)mCloud.getIntrinsicHeight() , ((iImagesOverX + 1) * (int)mCloud.getIntrinsicWidth()) + mCloud.getIntrinsicWidth() , ((iImagesOverY + 1) * (int)mCloud.getIntrinsicHeight()) + mCloud.getIntrinsicHeight() );
mCloud.draw(canvas);
mCloud.setBounds((iImagesOverX) * (int)mCloud.getIntrinsicWidth() , (iImagesOverY + 1)* (int)mCloud.getIntrinsicHeight() , ((iImagesOverX) * (int)mCloud.getIntrinsicWidth()) + mCloud.getIntrinsicWidth() , ((iImagesOverY + 1) * (int)mCloud.getIntrinsicHeight()) + mCloud.getIntrinsicHeight() );
mCloud.draw(canvas);
Log.d(TAG, "imagesoverx:"+ iImagesOverX);
}
我必须将dX和dY添加到边界以使图像移动。但是,一旦向右移动一个“磁贴”,第三个磁贴就不会出现
所以这在一定程度上是可行的,但不完全是我需要的。共有4个面板,但仅因为bounds和draw的4个实例。我需要这4个面板来画出它们需要的位置,无论我们使用x和y在哪里。我认为谷歌地图在你四处平移时也会做类似的事情。 他们将地图分成许多更小的瓷砖(128x128或196x196)。 如果您想要更平滑的滚动,您需要预先加载一些位图。
这些都是位图虚拟化技术。基本思想是,您有一个无限平面,其中包含在各个方向反复重复的图像。然后你就有了一个“视口”——你可以把它看作是一个窗口,它限制了你对无限平面的观察。换句话说,视口“下方”的无限平面的面积就是屏幕上实际显示的面积 因此,当视口的左上角位于(0,0)时,可以看到从(0,0)到(50,50)的无限平面部分(假设视口的宽度和高度为50像素)。类似地,如果视口位于(238753),则可以看到从(238753)到(288803)的无限平面部分 如果图像为100x100,则无限平面的形状如下:
Rect oRect1 = new Rect(dWorldX, dWorldY, dWorldX + canvas.getWidth(), dWorldY + canvas.getHeight());
Rect oRect2 = new Rect(0, 0, canvas.getWidth(), canvas.getHeight());
canvas.drawBitmap(largeBitmapTexture, oRect1, oRect2, new Paint());
(-100,-100) (0,-100) (100,-100) (200,-100)
******************************************
* * * *
* * * *
* * * *
* * * *
*(-100,0) *(0,0) *(100,0) *(200,0)
******************************************
* * * *
* * * *
* * * *
* * * *
*(-100,100) *(0,100) *(100,100) *(200,100)
******************************************
* * * *
* * * *
* * * *
* * * *
*(-100,200) *(0,200) *(100,200) *(200,200)
******************************************
(-100,-100) (0,-100) (100,-100) (200,-100)
******************************************
* * * *
* * * *
* * * *
* * * *
*(-100,0) *(0,0) *(100,0) *(200,0)
******************************************
* * * *
* * * *
* * (75,75) * (125,75) *
* * ####### *
*(-100,100) *(0,100) # * # *(200,100)
************************#*****#***********
* * # * # *
* * ####### *
* * (75,125) * (125,125) *
* * * *
*(-100,200) *(0,200) *(100,200) *(200,200)
******************************************
现在,假设视口的左上角为75,75。从图形上看,它看起来像:
Rect oRect1 = new Rect(dWorldX, dWorldY, dWorldX + canvas.getWidth(), dWorldY + canvas.getHeight());
Rect oRect2 = new Rect(0, 0, canvas.getWidth(), canvas.getHeight());
canvas.drawBitmap(largeBitmapTexture, oRect1, oRect2, new Paint());
(-100,-100) (0,-100) (100,-100) (200,-100)
******************************************
* * * *
* * * *
* * * *
* * * *
*(-100,0) *(0,0) *(100,0) *(200,0)
******************************************
* * * *
* * * *
* * * *
* * * *
*(-100,100) *(0,100) *(100,100) *(200,100)
******************************************
* * * *
* * * *
* * * *
* * * *
*(-100,200) *(0,200) *(100,200) *(200,200)
******************************************
(-100,-100) (0,-100) (100,-100) (200,-100)
******************************************
* * * *
* * * *
* * * *
* * * *
*(-100,0) *(0,0) *(100,0) *(200,0)
******************************************
* * * *
* * * *
* * (75,75) * (125,75) *
* * ####### *
*(-100,100) *(0,100) # * # *(200,100)
************************#*****#***********
* * # * # *
* * ####### *
* * (75,125) * (125,125) *
* * * *
*(-100,200) *(0,200) *(100,200) *(200,200)
******************************************
在本例中,视口的角位于(75,75)、(75125)、(125,75)和(125125)。因此,您可以看到图像的右下角位于(0,0),图像的左下角位于(100,0),以此类推
现在,假设您实现了一个函数,该函数计算特定点所在的网格。具体来说,它返回包含该点的栅格的左上角。举几个例子:
gridContainingPoint(0,0) -> (0,0)
gridContainingPoint(50,50) -> (0,0)
gridContainingPoint(100,100) -> (100,100)
gridContainingPoint(123, -27) -> (100,-100)
此功能的实现相当简单:
Point gridContainingPoint(Point pt) {
int newX = ((int)Math.floor(pt.x/100f)) * 100;
int newY = ((int)Math.floor(pt.y/100f)) * 100;
return new Point(newX, newY);
}
现在,要确定需要绘制哪些图像,需要为视口的每个角调用gridContainingPoint()
方法。在本例中,您将得到:
gridContainingPoint(75,75) -> (0,0)
gridContainingPoint(75,125) -> (0,100)
gridContainingPoint(125,75) -> (100, 0)
gridContainingPoint(125,125) -> (100, 100)
现在,您可以明确地知道需要绘制哪些图像才能完全覆盖视口
在绘制图像之前,必须正确设置视口。默认情况下,在画布上开始绘制时,视口的位置为(0,0)。因此,您只能看到绘制在画布上的(0,0)x(50,50)区域内的对象。但是,我们希望视口的位置为(75,75),以便在区域(75,75)x(125125)中看到东西。为此,需要调用Canvas.translate()
方法。例如,canvas.translate(-75,-75)
。它必须是负数,因为从概念上讲,它是在视口下方移动画布,而不是移动视口
现在,使用对gridContainingPoint()
的4个调用中的信息,在(0,0)、在(0100)、在(100,0)和在(100,100)处绘制图像。你完成了:)
需要记住的几件事-本例中使用的数字不是您想要使用的实际数字
首先,视口的大小不是50x50,而是绘制视图时的实际大小。您可以通过View.getWidth()
和View.getHeight()
来实现这一点
其次,您需要根据图像大小调整网格大小和相关计算-我怀疑您使用的图像是100x100
最后,请记住,当您为视口的每个角点调用
gridContainingPoint()
方法时,它可能会为多个角点返回相同的网格。例如,如果视口改为位于(25,25),则它将返回每个角的(0,0)图像,因为(25,25)、(25,75)、(75,25)和(75,75)都在从(0,0)到(100100)的图像中。因此,这将是您必须绘制的唯一图像,以便完全覆盖视口。因为您知道您的图像明显大于画布,所以您知道您一次只能在屏幕上看到图像的一个角。这是有用的
将当前位置设为x,y,原点为0,0。让你的形象是w,h的尺寸
计算从原点到您上方的完整图像数。这只是x/w和