I have a custom object list field with implemented scrolling routine.
public int moveFocus(int amount, int status, int time) {
invalidate(getSelectedIndex());
int unused = super.moveFocus(amount, status, time);
return Math.abs(unused) + 1;
}
public boolean navigationMovement(int dx, int dy, int status, int time) {
if (dy > 0) {
if (selectedIndex < getSize() - 1) {
setSelectedIndex(selectedIndex + 1);
}
} else if (dy < 0) {
if (selectedIndex > 0) {
setSelectedIndex(selectedIndex - 1);
}
}
return true;
}
Scrolling works fine when I scroll with trackwheel, but gets broken when app is launched on a device with trackball. I figured out that problem lays in framework method moveFocus which is not called at all when I scroll with trackball.
Issue has been resolved by changing return true; to return false; in navigationMovement method.
This makes a good example of a buggy api design. When you see some gui event handling method like this returning boolean your first and only suggestion is that the return value means the event has been consumed. But in case of navigationMovement method you're wrong. Here's an extract from JDE 4.2.1 javadoc
Parameters:
dx - Magnitude of navigational motion: negative for a move left and
postive for a move right.
dy - Magnitude of navigational motion: negative for an upwards move,
and positive for a downwards move.
status - Bitfield of values defined by KeypadListener.
time - Number of milliseconds since the device was turned on.
Returns:
False (classes that extend Field must override this method to provide
specific handling).
Bravo RIM!
Related
The task at hand is to add a band selection tool to a Dart WebGL application.
The tool will be used to draw a rectangle over multiple objects by dragging the mouse.
Thus multiple objects can be selected/picked in a single user action.
I'm currently using gl.readPixels() to read colors from an off-screen renderbuffer.
Problem is, when a large area is band-selected, gl.readPixels() issues millions of pixels.
Scanning such a big amount of colors wastes precious seconds just to locate few objects.
Please anyone point possibly faster methods for band-selecting multiple objects with Dart+WebGL.
For reference, I show below the current main portion of the band selection tool.
Uint8List _color = new Uint8List(4);
void bandSelection(int x, y, width, height, PickerShader picker, RenderingContext gl, bool shift) {
if (picker == null) {
err("bandSelection: picker not available");
return;
}
int size = 4 * width * height;
if (size > _color.length) {
_color = new Uint8List(size);
}
gl.bindFramebuffer(RenderingContext.FRAMEBUFFER, picker.framebuffer);
gl.readPixels(x, y, width, height, RenderingContext.RGBA, RenderingContext.UNSIGNED_BYTE, _color);
if (!shift) {
// shift is released
_selection.clear();
}
for (int i = 0; i < size; i += 4) {
if (_selection.length >= picker.numberOfInstances) {
// selected all available objects, no need to keep searching
break;
}
PickerInstance pi = picker.findInstanceByColor(_color[i], _color[i+1], _color[i+2]);
if (pi == null) {
continue;
}
_selection.add(pi);
}
debug("bandSelection: $_selection");
}
// findInstanceByColor is method from PickerShader
PickerInstance findInstanceByColor(int r, g, b) {
return colorHit(_instanceList, r, g, b);
}
PickerInstance colorHit(Iterable<Instance> list, int r,g,b) {
bool match(Instance i) {
Float32List f = i.pickColor;
return (255.0*f[0] - r.toDouble()).abs() < 1.0 &&
(255.0*f[1] - g.toDouble()).abs() < 1.0 &&
(255.0*f[2] - b.toDouble()).abs() < 1.0;
}
Instance pi;
try {
pi = list.firstWhere(match);
} catch (e) {
return null;
}
return pi as PickerInstance;
}
Right now I can see small solutions that might speed up your algorithm to limit as much as possible iterating over all of your elements,
The first thing you can do is have a default colour. When you see that colour, you know you don't need to iterate all over your array of elements.
It will accelerate large poorly populated areas.
It's very easy to implement, just adding a if.
For more dense areas you can implement some kind of colour caching. That means you store an array of colour you encountered. When you check a pixel, you first check the cache and then go over the entire list of elements, and if you find the element, add it to the cache.
It should accelerate cases with few big elements but will be bad if you have lots of small elements, which is very unlikely if you have picking...
You can accelerate your cache buy sorting your cached elements by last hit or/and by number of hits, it's very likely to find the same element in a continuous raw of pixels.
It's more work but stays relatively easy and short to implement.
Last optimisation would be to implement a space partitioning algorithm to filter the elements you want to check.
That would be more work but will pay better of on the long run.
edit :
I'm not a dart guy but this is how it would look like to implement in a basic way the first two optimisations:
var cache = new Map<UInt32, PickerInstance>();
for (int i = 0; i < size; i += 4) {
UInt32 colour = _color[i] << 24 | _color[i+1] << 16 | _color[i+2] << 8 | 0; // I guess we can just skip transparency.
if (_selection.length >= picker.numberOfInstances) {
// selected all available objects, no need to keep searching
break;
}
// black is a good default colour.
if(colour == 0) {
// if the pixel is black we didn't hit any element :(
continue;
}
// check the cache
if(cache[colour] != null) {
_selection.add(cache[colour]);
continue;
}
// valid colour and cache miss, we can't avoid iterating the list.
PickerInstance pi = picker.findInstanceByColor(_color[i], _color[i+1], _color[i+2]);
if (pi == null) {
continue;
}
_selection.add(pi);
// update cache
cache[colour] = pi;
}
Here is the code for a project im working on, where an enemy moves back and forth at the bottom of the screen.
class enemy1
{
Texture2D texture;
public Vector2 position;
bool isAlive = false;
Random rand;
int whichSide;
public enemy1(Texture2D texture, Vector2 position)
{
this.texture = texture;
this.position = position;
}
public void Update()
{
if (isAlive)
{
if (whichSide == 1)
{
position.X += 4;
if (position.X > 1000 + texture.Width)
isAlive = false;
}
if (whichSide == 2)
{
position.X -= 4;
if (position.X < 0)
isAlive = false;
}
}
else
{
rand = new Random();
whichSide = rand.Next(1, 3);
SetInStartPosition();
}
}
private void SetInStartPosition()
{
isAlive = true;
if (whichSide == 1)
position = new Vector2(0 - texture.Width, 563 - texture.Height);
if (whichSide == 2)
position = new Vector2(1000 + texture.Width, 563 - texture.Height);
}
public void Draw(SpriteBatch spriteBatch)
{
spriteBatch.Draw(texture, position, Color.White);
}
}
Now i want there to be a few enemys going back and forth but they start at differant positions so it looks like there is a few enemys going back and forth at the bottom of the screen. I have managed to draw a few other enemies on the screen, except they do not behave like the first enemy. They just are pictures on a screen not moving anywhere. So now all i have is the hero moving around and one enemy at the bottom of the screen, along with 5 other enemys sitting at the top of the screen doing nothing. How do i easily add a new sprite from a class that has the same behavior, at any time, while not making a billion variables to store them in?
Generally it's a good idea to have similar logic contained within the proper class, so if all Sprites where to do the same thing, then all you would need to do is put your movement code inside a public method and then call that method inside Update().
So, if your Sprite class looks something like this:
public class Sprite
{
private Vector2 Position;
public Sprite(Texture2D texture, Vector2 position)
{
Position = position;
}
//then just add this
public void MoveSprite(int amount)
{
position.X += amount;
}
}
Now, the object name "Sprite" is pretty generic, you will more than likely have many "Sprites" in your game.
So you're going to want to follow good OOP practices and maybe name this specific sprite something different and then have it derive from this class we're looking at right now. (But i'm not going to make design decisions for you)
This was a vague question, but that's my best shot at an answer for you.
been fighting with this problem for a good 3 hours now, and i figured it was finally time to ask some professionals.
My problem is that i want to make a scrollbar, and I've figured out that i want to make it by using two integers and then give every item in the list an ID, and then say that all the items that has an ID thats in between the two integers are going to be shown, and then afterwards make 2 buttons that will + or - the integers so you can "scroll" though the items.
So to realize this i decided to make dummy code, to see how i could work it out.
And for most part its working, however i have the problem now, that it seems that my draw function is refreshing the screen constantly (Even though I've put in a bool to make sure it woulden), and by doing that it keeps erasing the numbers I'm listing on the screen.
Heres the code:
List<int> test = new List<int>() {1,2,3,4,5,6,7 };
int low = 0;
int high = 3;
int count;
bool isDone = false;
public override void Draw(GameTime gameTime)
{
spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.AlphaBlend, SamplerState.PointClamp, null, null, null);
if (!isDone)
{
int posX = 20;
foreach (int nr in test)
{
if (count == high)
{
isDone = true;
break;
}
else
{
count++;
}
if (count >= low && count <= high)
{
posX += 20;
spriteBatch.DrawString(gameFont, nr.ToString(), new Vector2(posX, 20), Color.White);
}
}
}
spriteBatch.End();
}
Hopefully some of you clever folks can eye the mistake I've been missing.
Thanks in advance
~Etarnalazure.
You never reset your counter. Therefore, the numbers will be only visible in the first frame. Add
count = 0;
before the for-loop.
Furthermore, you might want to revise your structure. If you use a List<>, then every item already has its index. And you don't have to iterate over each and every item, if you use a for loop:
for(int i = low; i <= high; ++i)
{
var currentItem = list[i];
}
I am building a news ticker that needs to be implemented on Blackberry 5. When transitioning from one element to the next, I am looking at a fade out/fade in transition. Mostly because I am having trouble finding resources on creating animations in the Blackberry 5 reference.
the basic flow I am looking at is:
public void updateUI() {
//fade out
//set values
//fade in
}
So far I have all the UI elements contained inside a HorizontalFieldManager. I have tried digging through the Field and Graphics documents, but did not find what I was looking for.
Keep in mind, supporting Blackberry 5 is the client's requirement, not mine.
You need to handle animations explicitly, using a timer for transitions.
My typical solution is something like this (inside the paint() method):
final long time = System.currentTimeMillis();
final int alpha;
if (startFadeIn != 0) {
alpha = (int) Math.min((time - startFadeIn) / SPEED, 255);
if (alpha < 255) {
invalidate();
}
} else if (startFadeOut != 0) {
alpha = (int) Math.max(255 + (startFadeOut - time) / SPEED, 0);
if (alpha > 0) {
invalidate();
}
} else {
alpha = 255;
}
graphics.setGlobalAlpha(alpha);
It burns some CPU cycles (for a short time), but it works.
I have custom field with volume slider (just color line),
I want to update slider on trackpad movement, is there some other way
then invoking invalidate? Because this is realy slow for me,
a tried also invalidating only region but whit same result. So is there
some way how to repaint part of field without invalidate?
protected boolean navigationMovement(int dx, int dy, int status, int time) {
if (dx >0) {
if (value < maxValue) {
value++;
invalidate(xPosSlider + value*sliderStep, getHeight()/2 - SLIDER_HEIGHT/2, sliderStep, SLIDER_HEIGHT);
return true;
}
} else if (dx < 0) {
if (value > 0) {
value--;
invalidate();
return true;
}
}
return super.navigationMovement(dx, dy, status, time);
}
The first place to look is at your own code. Are you doing something time-consuming on the even thread that is preventing the paint operations from occurring in a timely manner? That's the likely problem.
Otherwise, you can try calling the paint method directly as shown here. But the best solution is to ensure that your event thread is not tied up doing work that should be done on a separate thread.