[Gambas-user] the math behind full screen rotation
Kevin Fishburne
kevinfishburne at ...1887...
Tue Mar 29 03:38:16 CEST 2011
On 03/27/2011 03:22 PM, Kevin Fishburne wrote:
> On 03/26/2011 03:49 AM, Doriano Blengino wrote:
>> Il 26/03/2011 04:08, Kevin Fishburne ha scritto:
>>> On 03/24/2011 12:05 AM, John Spikowski wrote:
>>>
>>>> On Wed, 2011-03-23 at 23:03 -0400, Kevin Fishburne wrote:
>>>>
>>>>
>>>>> That will probably work, but there should be a mathematical way to
>>>>> compensate for not cropping the image twice, or even once. As long as
>>>>> the entire image is preserved by the rotation function (it is) and it
>>>>> behaves in a predictable manner (it does), the camera's coordinates
>>>>> should be able to be translated and rotated so that they are in
>>>>> the same
>>>>> position in the rotated image as they were in the non-rotated
>>>>> image. For
>>>>> the sake of efficiency that is what I'm trying to accomplish.
>>>>>
>>>> This thread might help. (or not)
>>>>
>>>> http://forums.libsdl.org/viewtopic.php?t=2983&sid=1d2c6a94470c0fd56f3f542cd702ec37
>>>>
>>>>
>>> No go, but thanks for trying to help. Right now my code looks something
>>> like this:
>>>
>>> ' Convert camera coordinates to their distance from the center
>>> of the
>>> tile grid.
>>> newcx = newcx - (bworkspace.Width / 2)
>>> newcy = newcy - (bworkspace.Height / 2)
>>>
>>> ' Rotate camera.
>>> newcx = Cos(Rad(- Client.orientation)) * newcx - Sin(Rad(-
>>> Client.orientation)) * newcy
>>> newcy = Sin(Rad(- Client.orientation)) * newcx + Cos(Rad(-
>>> Client.orientation)) * newcy
>>>
>>> ' Adjust the camera coordinates to fit the rotated tile grid.
>>> newcx = newcx + (brotated.Width / 2)
>>> newcy = newcy + (brotated.Height / 2)
>>>
>>> ' Draw the rotated workspace centered on the camera and cropped by
>>> the render window size.
>>> Draw.Image(brotated, 0, 0, swidth, sheight, newcx - swidth / 2,
>>> newcy
>>> - sheight / 2, swidth, sheight)
>>>
>>> First I figure out the distance of the camera from the center of the
>>> non-rotated image. Then I rotate the camera using those distance values
>>> as the camera's coordinates. That should in effect make the center of
>>> the non-rotated image the origin of rotation. I then take the rotated
>>> camera values and add them to the center point of the rotated image to
>>> determine the camera's position in the rotated image.
>>>
>>> Maybe my logic is wrong, maybe it's my math. Maybe demons are hovering
>>> over my shoulder casting black magic. I'm about to hit up Facebook for
>>> an old math whiz I knew in high school, as gamedev.net has failed me as
>>> well.<blood curdling Arnold scream from Predator>
>>>
>>>
>
> Hi Doriano, thanks for helping. You're definitely getting your name in
> the game credits when it's done. :)
>
>> Dear Kevin,
>>
>> if I well understand, you have to rotate your world around the player.
>> To rotate a point around another arbitrary point (different from the
>> origin), you must first translate the point, then rotate it, then
>> translate it again in the original position. If you want I can give you
>> a working routine to do so. Your code seems to do something similar,
>
> Yes, I hope that's what my code is doing. Basically I find the
> distance of the camera from the center of the non-rotated image,
> whether negative or positive. That should mean that when I rotate
> those new coordinates, then add them to the center point of the
> rotated image, that they've effectively been rotated about the center
> of the rotated image. For example, if the camera in the non-rotated
> image is at (10,10) and the center of the non-rotated image is at
> (11,11), I'd do (10,10) - (11,11) = (-1,-1), rotate (-1,-1), then add
> the rotated values to the center point of the rotated image. Maybe
> that's all wrong, I don't know.
>
>> but... should not the player always stay in the middle of the screen? If
>> so, you need not to translate anything, but just rotate the original
>> image. Or, perhaps, you want to reduce scrolling, so the player is not
>> always in the middle? If there is not a true motivation, due to some
>> game concept, to have different x/y positions of the player inside the
>> screen, then it is much simpler to always keep the player in the middle.
>> I try to explain in other words. Suppose that you can't get enough
>> framerate when you rotate the world, so you try to minimize this, and
>> let the player move around the screen. When the player reaches the
>> boundary of the screen, you update the whole screen. Doing so, you speed
>> up considerably. Nevertheless, when the player reaches a boundary, you
>> must invoke anyway the "slow" routines to update the world. The net
>> result is a stiffy game, which alternates fast movements with slow ones.
>
> That is exactly what I'm doing because this is a tile-based game that
> uses a complex method of drawing and blending the tiles. Here's how it
> works, using real numbers this time.
>
> First the camera is detached from the player, so the player's position
> for the sake of this discussion isn't important. The camera loosely
> follows the player using an algorithm to simulate natural camera
> movement. So the camera position is all that matters.
>
> The landscape is broken into three progressively smaller chunks: the
> game world (data on server), the cell grid (data on client) and the
> tile grid (image on client). The world for testing purposes is
> currently 4096x4096 tiles. The cell grid is a block of 96x96 tiles
> (3x3 cells of 32x32 tiles), and is all the game client is aware of at
> any given time. Finally the tile grid is an image containing the
> rendered tile data of a subset of the cell grid, with the camera
> always being in the center tile. At 1280x720 the tile grid is 13x13
> tiles, or 1664x1664 pixels, with the camera always being somewhere in
> tile (7,7).
>
> When the camera moves out of the center tile of the tile grid, the
> tile grid is shifted one tile (128 pixels) in any of eight directions
> and a new row and/or column of tiles are drawn into it. The tile grid
> image is what's being rotated, and the camera never is farther than 64
> pixels in any direction from the center of the tile grid image.
>
> I've attached the relevant, abbreviated code. The function
> CellGrid2TileGrid() is being called to convert the camera's cell grid
> coordinates to tile grid coordinates. I believe the conversion
> function is working properly (scrolling works fine until the screen is
> rotated), but it may be worth a look. I've also recorded a video
> showing what is currently happening when the screen is rotated:
>
> http://www.youtube.com/watch?v=iw64jcdNJY4
>
>> I am also confused by our previous thread, where you rotated the player
>> instead of the world. Not knowing enough, I can only say that you can,
>> perhaps, gain some speed by doing calculations in the dead times
>> (delays, if you have/use them). I have read that you reach speeds as
>> high as 200 FPS or similar... if you reduce FPS to 25, you gain a lot of
>> spare time to calculate ahead the new scenes (or perhaps not). If you
>> explain better your ideas, may be I can try to give some advice.
>
> That's a good idea, I will definitely consider doing that.
In a half-drunken stupor I managed to correct the issue by trial and
error. Hell of a miracle. Here's the abbreviated working code:
Public Sub Screen_Client()
' Main client loop.
' General declarations.
Dim newcx As Single ' Translated and rotated camera
coordinates in the rotated tile grid.
Dim newcy As Single ' Translated and rotated camera
coordinates in the rotated tile grid.
Dim cxoffset As Single ' Distance of the camera from the center
of the tile grid.
Dim cyoffset As Single ' Distance of the camera from the center
of the tile grid.
' Update the camera.
Camera
' Composite the landscape layer.
bworkspace.Draw(blandscape, 0, 0)
' Rotate the workspace.
brotated = bworkspace.Rotate(Rad(- Client.orientation))
' Convert camera coordinates to tile grid pixel coordinates.
newcx = Convert.CellGrid2TileGrid(cx, cx) * 128
newcy = Convert.CellGrid2TileGrid(cy, cy) * 128
' Calculate camera distance from the center of the tile grid.
cxoffset = newcx - (bworkspace.Width / 2)
cyoffset = newcy - (bworkspace.Height / 2)
' Rotate camera about the center of the tile grid using its offset
values.
newcx = Cos(Rad(- Client.orientation)) * cxoffset - Sin(Rad(-
Client.orientation)) * cyoffset
newcy = Sin(Rad(- Client.orientation)) * cxoffset + Cos(Rad(-
Client.orientation)) * cyoffset
' Draw the rotated workspace centered on the camera and cropped by
the render window size.
Draw.Image(brotated, 0, 0, swidth, sheight, (brotated.Width / 2) -
(swidth / 2) + newcx, (brotated.Height / 2) - (sheight / 2) + newcy,
swidth, sheight)
End
I tried about 100 things before it started working, so I don't really
know what I did wrong (or right), but at least it's working now. :) Too
bad my frame rate is at 6 FPS due to the rotation function. I think I
may need to follow Benoit's advice about cropping the image first.
Thanks Doriano.
--
Kevin Fishburne
Eight Virtues
www: http://sales.eightvirtues.com
e-mail: sales at ...1887...
phone: (770) 853-6271
More information about the User
mailing list