×

Discussion Board

Page 1 of 2 12 LastLast
Results 1 to 15 of 21
  1. #1
    Registered User
    Join Date
    Mar 2009
    Location
    Gdansk, Poland
    Posts
    139

    Scrolling shooter

    Actually my midlet is not a scrolling shooter, but the problem I am having is exactly what a scrolling shooter has to face - thus the title.

    In my midlet I've got a big offscreen image ( about 5*scrWidth x 5*scrHeight ) - let's call it 'bigImage'. At any given time, I have to show scrHeight x scrWidth part of it on the screen, but first I have to overlay some additional graphics on top of it.

    I do it by having another offscreen image ( scrHeight x scrWidth in size ) - let's call it 'smallImage' . I remember which part of the 'bigImage' I have to show, copy that part to the small image using

    smallImage.getGraphics().drawRegion(bigImage,...)

    then I use smallImage's Graphics object to overlay the additional graphics and I copy the resulting 'smallImage' to the screen with one call to drawImage().

    Now, this works, but I am facing some problems with flickering. Namely, user is able to rapidly scroll the part of the 'bigImage' being shown and when he does it, the whole screen flickers badly.

    The question: isn't there some better way? How do the scrolling shooters avoid the flicker?

  2. #2
    Super Contributor
    Join Date
    Jun 2003
    Location
    Cheshire, UK
    Posts
    7,395

    Re: Scrolling shooter

    First, you could just paint bigImage, and not bother with smallImage at all.

    Most scrolling games don't use a huge image like this, they construct the image from tiles (to avoid having a huge image that would overflow the memory on most devices).

    Not sure why you're gettign flickering... unless you're updating the smallImage on a different thread from the painting, without synchronization.

    Are you using Canvas or GameCanvas?

  3. #3
    Registered User
    Join Date
    Mar 2009
    Location
    Gdansk, Poland
    Posts
    139

    Re: Scrolling shooter

    I am using plain Canvas.

    So you're saying to directly copy part of the bigImage to the screen and then overlay the graphics? Wouldn't that be slower?

    Ok, I exagerrated a bit when I said 'flickers badly'... When I scroll up-down, all the horizontal lines flicker; the rest is bearable. Similarly when scrolling left-right, the vertical lines flicker.

    I only care about S60 5th edition, so memory is hopefully not an issue.
    Last edited by Utumno; 2010-03-25 at 14:25.

  4. #4
    Super Contributor
    Join Date
    Jun 2003
    Location
    Cheshire, UK
    Posts
    7,395

    Re: Scrolling shooter

    No, it should be faster, since you'll be copying each pixel only once, not twice.

    Canvas is a good plan. GameCanvas only adds complication. Not sure how you're structuring things, but you might want to look at my example game structure.

    What are you running this on? Are you seeing flicker only on the emulator, or on a device too?

    Graham.

  5. #5
    Registered User
    Join Date
    Mar 2009
    Location
    Gdansk, Poland
    Posts
    139

    Re: Scrolling shooter

    Ok, let's try doing it without the smallImage.

    But I always thought that painting to an offscreen image is faster than to the screen, so since overlaying the additional graphics takes many calls to drawImage() , fillRect() and friends, it's better to do it with an offscreen image and copy that to the screen in one shot?

    I am sticking to your example game structure pretty slavishly.

    I see the flicker on my N97 mini.

  6. #6
    Super Contributor
    Join Date
    Jun 2003
    Location
    Cheshire, UK
    Posts
    7,395

    Re: Scrolling shooter

    Using an off-screen buffer can only make things faster if you don't repaint the whole buffer each time. On scrolling games, you repaint the whole buffer every time you move, so it doesn't save you anything. It just means there's an extra (width * height * bytes-per-pixel) bytes to copy every time you paint. Some devices (some Sony Ericssons, for example) are optimized for drawing to the screen, so drawing to an in-memory image can be slower. It also costs you a lot of memory, and becomes a big porting problem.

    Buffering can cause flickering, if you update the buffer in the "update thread" (the one going around the loop in the run() method), because it becomes possible to paint the image (on the event thread) while it's only half updated. Unless you add synchronization, but it's best to avoid synchronization in the paint() method. However, it would still be unusual to notice any flickering, because almost all your paint() events should be happening during serviceRepaints().

    Buffering is mainly useful on:

    * some really old devices (where Canvas.isDoubleBuffered() returns false)
    * some kinds of puzzle games, where a small amount of the screen changes each frame (like a board game), on very slow devices
    * to fix one or two bizarre device issues (such as a strange flicker that occurs on some Sagem devices)

    You're already saving a huge amount of time by having the bigImage. Most scrolling games wouldn't do this, and would paint a screen full of tiles each time (possibly two or three layers of them). Most devices don't have enough memory to hold an image of the entire map.

    Graham.

  7. #7
    Registered User
    Join Date
    Mar 2009
    Location
    Gdansk, Poland
    Posts
    139

    Re: Scrolling shooter

    You're saying that the speed mainly depends on the number of pixels one is painting?
    So two calls to fillRect, half a screen each time, would be only marginally slower than one call painting the whole screen in one shot? Hmm...

  8. #8
    Super Contributor
    Join Date
    Jun 2003
    Location
    Cheshire, UK
    Posts
    7,395

    Re: Scrolling shooter

    There are several factors that affect performance of painting.

    1. The number of pixels. No getting around this, every time you update one pixel (whether on the screen or on a mutable image), some quantity of data has to be written, and that will take time.

    2. The number of method calls. Each time you invoke a method, there is an overhead: passing control to the target method, creating and initializing local variables, initial processing of arguments, and so on. For C or (in most cases) C++ programs, this tends to be small, but it can be significant for Java programs. In particular, invoking a non-private, instance method in Java is slow, because of polymorphism. The specific method must be located at run-time, and this takes time. A C function (or a non-virtual C++ method) is located when the program executable is built, so the run-time overhead is much smaller.

    3. The nature of the operation. Some primtive operations are slow (drawArc(), fillArc()). Any operation that involves alpha-blending can be slow. On some devices, transforms (like Sprite.TRANS_MIRROR) can slow things down, though this is unusual.

    4. Other work that has to be done. For example, complex logic in working out what to paint. Trying to avoid updating parts of the screen can sometimes be counter-productive, if the logic required to work out what needs to be painted takes longer than the time you save by not painting part of the screen.

    In your example, two fillRects() to paint the whole screen, rather than one, would run slower than a single fillRect(), but the difference would be so small, I doubt you would notice.

    However, use tiles to paint your screen, rather than a single large image, and you will start to notice a difference. Games that use larger tiles tend to perform better than games that use smaller tiles. Drop your tile-size from 32x32 to 16x16, for example, and the number of drawImage() calls needed to paint a 360x640 screen increases from 225 to 900 (more, actually, since some tiles will be partially off the screen). You probably would notice that.

    Graham.

  9. #9
    Registered User
    Join Date
    Mar 2009
    Location
    Gdansk, Poland
    Posts
    139

    Re: Scrolling shooter

    I see. Thanks for such an in-depth answer.

    My background is not made of tiles; it is pixel-precise, generated by a pseudorandom machine at runtime. So I guess I really need to buffer things up with my bigImage - otherwise I'd have to paint the screen with a scrHeight number of calls to drawLine...

    Now we're also coming back to the problem with transparency we were talking about in another thread: it would be nice if the bigImage was transparent here and there, so I could have a lower, solid blue layer ( water ) where I draw my water effects ( tides, cataracts, waves, etc ) and then just cover it up with the bigImage ( land ) without worrying that my wave would spill over to the land.

    The land is very complicated, pixel-precise; I made sure there's not even a few pixels of a straight line anywhere. Currently, without transparency, I keep water and land both in one layer, so the water effects are computationally very hard to overlay correctly.

    The game area is infinite; the bigImage is periodically (not more often than about once in 15 seconds ) re-created by a background thread. If you, say, keep moving to the left, the thread is going to move the image partly to the right (forgetting about the rightmost part in the process) and compute the new areas to the left you're likely to visit in a few seconds.

    And here we go : I'd like to initialize the 'newly computed' part of the bigImage to transparent.
    Last edited by Utumno; 2010-03-26 at 05:09.

  10. #10
    Registered User
    Join Date
    Mar 2009
    Location
    Gdansk, Poland
    Posts
    139

    Re: Scrolling shooter

    I got rid of the 'smallImage' and indeed, there's no noticeable difference in rendering speed.

    About the transparency: maybe I could remember the buffered land not as an instance of an Image but as some kind of pixel array? I could manipulate the pixels directly and set those that I want to be transparent to 0x00000000.

    But how to copy part of a pixel array to the screen *without* creating new instance of an Image each time?
    Last edited by Utumno; 2010-03-26 at 07:23.

  11. #11
    Super Contributor
    Join Date
    Jun 2003
    Location
    Cheshire, UK
    Posts
    7,395

    Re: Scrolling shooter

    Quote Originally Posted by Utumno View Post
    The game area is infinite; the bigImage is periodically (not more often than about once in 15 seconds ) re-created by a background thread. If you, say, keep moving to the left, the thread is going to move the image partly to the right (forgetting about the rightmost part in the process) and compute the new areas to the left you're likely to visit in a few seconds.
    I understand. I've used a similar process with tile maps, for optimizing performance. As I said, with small tiles, painting can become slow, so using a buffer image can speed things up, provided you don't update the entire buffer each time.

    I think you might have problems rebuilding the map image on a separate thread like this. I'm not saying you can't get it to work, but my concerns would be:

    1. Doing big chunks of work at irregular intervals might cause the game to stutter. If possible, do work in smaller chunks more often (every frame) so that performance is smoother.

    2. Another thread introduces synchronization problems - what happens if you repaint() in the middle of updating the image?

    The technique used for tile maps is described in this post. Drink some coffee before you read it, I'm not sure I explained it well! This doesn't quite apply to your situation, but you might be able to adapt the idea.

    Quote Originally Posted by Utumno View Post
    maybe I could remember the buffered land not as an instance of an Image but as some kind of pixel array?
    An image (640*5) * (360*5) comes to 5,760,000 pixels, which needs 23Mb as an int[]. I think you'll run out of memory trying to do this.

    Quote Originally Posted by Utumno View Post
    But how to copy part of a pixel array to the screen *without* creating new instance of an Image each time?
    That's not such a problem, Graphics has a method drawRGB() for doing exactly this. However, you might find this slows things down a little. Image objects usually store pixel data in a format that matches the device's hardware, so that copying the data to the screen is as fast as possible. Data in an int[] will probably need converting (on the fly, as it's copied) to suit the hardware.

    An alternative is to consider the drawPixels() methods in DirectGraphics (Nokia API), if you match the format you're using to whatever DirectGraphics.getNativePixelFormat() says the phone wants. If, of course, these methods work correctly!

    Graham.

  12. #12
    Registered User
    Join Date
    Mar 2009
    Location
    Gdansk, Poland
    Posts
    139

    Re: Scrolling shooter

    Quote Originally Posted by grahamhughes View Post
    I think you might have problems rebuilding the map image on a separate thread like this. I'm not saying you can't get it to work, but my concerns would be:

    1. Doing big chunks of work at irregular intervals might cause the game to stutter. If possible, do work in smaller chunks more often (every frame) so that performance is smoother.

    2. Another thread introduces synchronization problems - what happens if you repaint() in the middle of updating the image?

    An image (640*5) * (360*5) comes to 5,760,000 pixels, which needs 23Mb as an int[]. I think you'll run out of memory trying to do this.
    It seems to work; sometimes - rarely - I do notice maybe 1/2 sec stutter however. Doing it in smaller chunks is not a problem because I've got 2 constants:

    1. the distance you can be from the side of the precomputed background - if you're closer, the background thread begins its work
    2. the amount of land being created is also another constant.

    So changing those two , in theory will let me generate as much of land as often as I want. BTW, scheduler in Symbian sucks bigtime - looks like I cannot lower the priority of the background thread because then it is simply never scheduled. So why having priority levels at all??

    It is 360x500 as I have a 140 pixel wide status bar on the right ( landscape mode here ) Besides, I don't really need 5width x 5height; I suppose I could lower my constants and have 4x4 only.

    I only ever paint around the middle of the 'bigImage'. It is 5width x 5 height precisely so the background thread can work on the invisible parts; no synchronization here except for the tiny moment when the thread is moving the already computed part of the bigImage.

    Quote Originally Posted by grahamhughes View Post
    That's not such a problem, Graphics has a method drawRGB() for doing exactly this. However, you might find this slows things down a little. Image objects usually store pixel data in a format that matches the device's hardware, so that copying the data to the screen is as fast as possible. Data in an int[] will probably need converting (on the fly, as it's copied) to suit the hardware.

    An alternative is to consider the drawPixels() methods in DirectGraphics (Nokia API), if you match the format you're using to whatever DirectGraphics.getNativePixelFormat() says the phone wants. If, of course, these methods work correctly!

    Graham.
    yes, I figured that one out :

    http://www.forum.nokia.com/info/sw.n..._v1_0.pdf.html
    Last edited by Utumno; 2010-03-26 at 09:33.

  13. #13
    Super Contributor
    Join Date
    Jun 2003
    Location
    Cheshire, UK
    Posts
    7,395

    Re: Scrolling shooter

    Quote Originally Posted by Utumno View Post
    BTW, scheduler in Symbian sucks bigtime - looks like I cannot lower the priority of the background thread because then it is simply never scheduled. So why having priority levels at all??
    This is usual with mobile Java. While threads are essential for blocking operations (to avoid blocking the event thread), it's easy to expect too much from them, and to be disappointed. I encourage developers to avoid multi-threading as much as possible.

    Thread priorities are something to be careful with. A lower-priority thread can only be scheduled if no higher-priority thread is runnable. This is the reason for the "MINIMUM_SLEEP" constant in my example game structure - it's there to take the update thread off the runnable list to give other threads (mainly, the event thread) time to run.

    (I'd avoid the game update thread if I could. In theory, callSerially() should be a better option, but it works very, very badly on too many devices. The thread example I gave in the other post works very reliably across almost all devices, provided you put the right code in the right place, and (on some devices) set a minimum sleep. It's used in dozens of commercially available games.)

    Quote Originally Posted by Utumno View Post
    Besides, I don't really need 5width x 5height; I suppose I could lower my constants and have 4x4 only.
    You could even consider making it only slightly bigger than the screen, unless that causes a problem for your rendering algorithm.

    Graham.

  14. #14
    Registered User
    Join Date
    Mar 2009
    Location
    Gdansk, Poland
    Posts
    139

    Re: Scrolling shooter

    I read up the link you gave me; there's one trick you pointed out that I don't do: when re-creating the background, *don't* move the already computed part but draw the new areas on the opposite side of the buffered image. Good. Off to implementing that.

  15. #15
    Registered User
    Join Date
    Mar 2009
    Location
    Gdansk, Poland
    Posts
    139

    Re: Scrolling shooter

    Quote Originally Posted by grahamhughes View Post
    You could even consider making it only slightly bigger than the screen, unless that causes a problem for your rendering algorithm.
    If the player is moving up-down, it is not a problem for me to generate even 1 line of new land at a time, the algorithm lets me do this; if however left-right, I'd have to still loop through bigImage.getHeight() number of lines to add just a few pixels everywhere - and that looks to me like much more inefficient approach than doing it more rarely , in bigger chunks?

    Having another thread to do background generation seems like a clean solution to me; I'd be hard pressed to do it all in one thread.
    I am a C & Linux kernel-land guy and this is just a hobby which, I figured, would be a nice respite after all that low-level digging. Afterall what can be easier than userspace programming with Java?
    Now looks like I again cannot take for granted any benefits of having an OS under me, and again I have to work around device quirks...

    Another idea: let's put the (strange!) behaviour of the Symbian scheduler to our advantage, lower the priority of the background thread ( so it can never introduce stutters, right? ) and somehow make sure the thread is able to finish it's job within the time the main painting thread sleeps *before* we run out of land and see the turtles that support it

    Currently the main reason why I have a 5x5 is that whenever player is moving within the middle 3x3 block, the background thread does nothing; but when he moves closer than 1 screen to the side, the background thread kicks in, computes another 2 screens of land in appropriate direction. And it has to finish *before* the player, who is constantly moving, sees the turtles. 1 screen size seems like a safe buffer to me because the background thread usually takes less than 100ms to finish its job and the time it takes to move 1 screen is at least 4-5 seconds.
    Last edited by Utumno; 2010-03-26 at 10:25.

Similar Threads

  1. problem with qt4.6 QwebView kinetic scrolling
    By mismael in forum Nokia N9
    Replies: 13
    Last Post: 2010-05-17, 08:32
  2. N97 kinetic scrolling and CustomItem's pointerDragged
    By shockreaction in forum Mobile Java General
    Replies: 4
    Last Post: 2010-03-06, 21:22
  3. Kinetic Scrolling problems with CustomItem
    By SOLIPSIST in forum Mobile Java General
    Replies: 0
    Last Post: 2010-02-16, 21:05
  4. How to implement kinetic scrolling?
    By svdwal in forum Symbian User Interface
    Replies: 8
    Last Post: 2010-01-28, 14:36

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  
×