[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