Android openGL oddity, resetting variables - android

I'm building an Android app with a simple 3D engine. It was working earlier, but was incredibly messy. I've refactored the heck out of it, but I did little to the 3D engine. Now I'm running into a very strange problem where calling translatef within the draw() method (which itself is called from within onDrawFrame within the class that implements GLSurfaceView.Renderer) does not use the current value of the x/z float variables, which are scoped to the class. I cannot explain it. There is zero code that would reset them to their initial values, but that's what is happening. The only time these variables are touched are when the class is instantiated (done once, never touched again), when they change due to user input (verified as accurate with the debugger at every point possible), and when translatef is called, at which point they are only read.
The thing is, they are always the initial value that was passed to the constructor when read by the translatef method, but are accurate otherwise at any other point in the class when they are used or altered. If, say, we set z to z + 1, it remains at that value regardless of the value read by translatef. What gives? I'm at a loss as to why the draw() and/or translatef() methods are somehow sticking to the original values and not reading the modified values. I'm utilizing GL ES 1.0 and Android 2.2 as my testing platform.
There's too much to just dump it all here, but this should be sufficient to get the problem across:
private float movex, movez;
public GLEngine(){
//The values are set in the constructor and are accurate at this point.
movex = Controller.getX();
movey = Controller.getZ();
}
public void move(float x, float z){
//Again, debugging in here shows that the values are being set properly.
movex = x;
movez = z;
}
public void onDrawFrame(GL10 gl){
//Debugging anywhere within this method shows only the values for movex and
//movez that were set in the constructor.
...
gl.translatef(movex, .5f, movez);
...
I got a tip to make movex and movez volatile as this was likely related to threading issues (although I have not explicitly declared any threads here), but that didn't help.
As both values are held outside the class, I was able to make this work by pulling them from the controller in the onDrawFrame method, but this requires the variables to be pulled and additional operations to be performed on them on every draw, which is costly. There has to be a better way...

Since x and z are private variables, it should be easy to track down.
You are only ever setting them via your move method. To find this out, delete or comment out your move method (temporarily) and do a save. Eclipse will highlight any code that is now broken as a result.
Once you are sure that all changes for x and z are going through the move method, set a breakpoint there. (You can set conditional breakpoints as well).
If you stop at a breakpoint, you can can see which method called move.
This should let you track the problem down.

Related

Android: canvas keeps alternating between previous and current drawing commands

So, I'm developing a game and I'm using Canvas with SurfaceHolder to update the screen every time an object is supposed to move. That much is working fine so far. Now, the problem happens when I want to stop drawing to the Canvas and just leave it as it is based on the last drawing commands.
So one way that I tried was to simply return from the function that I call when drawing when the end condition is met. However, when I do this, the canvas starts rapidly alternating between the commands sent right when the condition was met and the commands sent one iteration before. I have no idea how or why this is happening since the drawing function is not executing any of its draw commands after the condition is met. Can anyone explain how the canvas can keep refreshing itself when it doesn't get any draw commands?
The code in the thread for locking and unlocking is pretty simple:
public void run() {
Canvas c = null;
try {
c = sh.lockCanvas(null);
synchronized(sh) {
drawCan(c);
}
}
finally {
if(c!=null) {
sh.unlockCanvasAndPost(c);
}
}
}
and the drawCan function is structured like this:
public void drawCan(Canvas c) {
/* Check if user's health is greater than 0. Don't draw anything if it is less */
if(userHealth<=0) {
return;
}
/* Drawing commands - drawRect(), drawBitmap(), etc are run here */
}
Now normally, this runs fine. But when the userHealth condition is met, the Canvas constantly alternates between the last commands sent and the commands right before that. I know that the draw functions are not being called because I used Log.d() in that area of the code and no messages appeared on LogCat after the condition was met. Can someone explain why this is happening and what the solution would be?
The Canvas is double- or triple- buffered and not erased between frames. When you call lock/unlock, you're switching between previously-rendered buffers.
If you move your if(userHealth<=0) test into run() and use it to avoid calling lock/unlock, you should get the desired effect.
For a much longer explanation about what's going on, see this post.
Update: I realized today that I'd omitted a detail (from the answer and ensuing comments). It doesn't change the answer but it may be useful to know.
The lockCanvas() method takes an optional "dirty" rect that allows you to do partial updates. If you use this, and Surface is able to keep track of the "front" buffer you just rendered, the system will copy the non-dirty contents of the front buffer to the back buffer as part of locking the Surface (see copyBlt() in Surface.cpp).
The system doesn't guarantee that this will work, which is why the "dirty" rect is an in-out parameter. If the front buffer isn't available to copy from, the lock method will just expand the dirty rect to cover the entire screen. In either case, your app is responsible for updating every pixel in the "dirty" rect; if you don't, you get the effects you observed.
This does mean that the Surface is explicitly trying to be double-buffered when used with a Canvas, which would explain why you're seeing two frames alternating rather than three even though SurfaceView is generally triple-buffered. (Which is the thing that has been nagging at me since I wrote this up.) It's also possible to be double-buffered if you're just not generating frames fast enough to require triple-buffering.

Android shoot-em-up game. Robust enemy patterns for complex group behaviour

I'm working on an arcade shoot-em-up game for Android similar to Ikaruga. The problem I'm facing is that it's proving quite difficult to robustly create move and shoot patterns for the enemies. At the moment I've created two abstract classes EnemyShip and FlightPath from which each different enemy and move pattern derive from respectively. When the World
is created it instantiates a LevelManager which stores level info in the form of:
waveInfos.add(new WaveInfo(3, 3f)); // new WaveInfo(NumberOfGroups, spawn interval)
enemyGroups.add(new EnemyGroup(8, EnemyGroup.TYPE_SCOUT_SHIP, EnemyGroup.F_PATH_INVADERS));
enemyGroups.add(new EnemyGroup(1, EnemyGroup.TYPE_QUAD_SPHERE, EnemyGroup.F_PATH_QUAD_SPHERE_L, World.BLACK));
enemyGroups.add(new EnemyGroup(8, EnemyGroup.TYPE_SCOUT_SHIP, EnemyGroup.F_PATH_INVADERS));
// new EnemyGroup(NumberOfEnemies, EnemyType, FlightPathType)
// new EnemyGroup(NumberOfEnemies, EnemyType, FlightPathType, ShipColour)
waveInfos.add(new WaveInfo(2, 0.33f));
enemyGroups.add(new EnemyGroup(1, EnemyGroup.TYPE_QUAD_SPHERE, EnemyGroup.F_PATH_QUAD_SPHERE_L, World.WHITE));
enemyGroups.add(new EnemyGroup(1, EnemyGroup.TYPE_QUAD_SPHERE, EnemyGroup.F_PATH_QUAD_SPHERE_R, World.WHITE));
totalWaves = waveInfos.size();
The levels are split into waves of groups of enemies and right now the EnemyGroup class takes care instantiating, adding the specified FlightPath to the newly created enemy and passing that enemy to the ArrayList in LevelManager for storage until spawned into the world at the time needed.
Once spawned the FlightPath componant takes over and starts giving instructions based on it's own stateTime and since each FlightPath has a reference field to its EnemyShip owner it can access the ship's functions and members it's controlling.
The EnemyShip class has a few functions for easy instruction such as moveTo(float x, float y, float duration) and shoot() but even with these the FlightPath derivatives are diffcult to make especially when I want different enemies in the same group to have slightly different paths and slightly different time arrivals.
I created a few fields in the FlightPath to keep track of keyFrames:
public int currentKeyFrame = 0;
public int totalKeyFrames;
public KeyFrame[] keyFrames; // Stores duration of instruction to be done, the spreadTime, totalFrameTime and enemyIntervalTime
public int shipNumber; // Stores which ship out of group this FlightPath is attached to
public int totalShips; // Stores total number of ships in this EnemyShip's group
public float stateTime = 0;
KeyFrame.spreadTime is my attempt to control the time between the first enemy in group to begin moving/shooting and the last.
KeyFrame.totalFrameTime = KeyFrame.duration + KeyFrame.spreadTime
KeyFrame.enemyIntervalTime = KeyFrame.spreadTime / Number of enemies in this group
While this setup works great for very simple linear movement, it feels quite cumbersome.
Thanks for reading this far. My question is how do I implement a more streamlined pattern control which would allow for complex movement without hordes of if() statements to check what other enemies in the group are doing and the like.
I hope I've provided enough information for you to understand how the enemies are handled. I'll provide any source code to anyone interested. Thanks in advance for any light you can shed on the subject.
Marios Kalogerou
EDIT: I found a page which very much describes the kind of system which would be perfect for what I want but I'm unsure how to correctly implement it with regards to overall group keyFrames
http://www.yaldex.com/games-programming/0672323699_ch12lev1sec3.html
FlightPath should not control any objects. It's a path, not a manager. However, it should be able to give coordinates given any keyframe or time. For example: flightPath.getX(1200) -> where should I be in the X-coordinate at 1200ms?
Each EnemyShip should maintain a possession of a FlightPath instance. EnemyShip checks where it should be in the path every frame.
EnemyGroup then controls the spawning of each EnemyShip. If you have 8 EnemyShips in one EnemyGroup, all possess the same FlightPath type, then you can imagine that EnemyGroup would spawn each ship around 500ms apart to create the wave.
Finally, you translate all the EnemyShip coordinates relative to the world/screen coordinate, which traditionally moves slowly in the vertical direction.
There are different approaches:
You can add random intervals before shooting, and set slightly random arrival times. Like currentEnemyArrivalTime += (X - rand(2*X)).
You can control movement of group of enemies. Each enemy in the group tries to maintain it's position relative to the center of the group.
For really complex patterns may be better to develop some simple scripting engine. It can be very simple (like array of coefficients for spline), or something more complex. I believe, in such games behavior is done by scripts.

asyncTask update a static value which is used by OpenGL ES

I m writing an app containing an asyncTask which continuously (every seconds or so) adds a value to an ArrayList<Float> (declared static).
The value is a measure in inches that I want to plot.
In order to do that I have implemented a solution with OpenGL ES.
And every time I add a new value my AsynTask calls the requestRender() method.
Then the drawRenderer() take the ArrayList<Float> and draw lines with it.
At this point everything works perfectly fine.
I also want that the user can pinch-zoom and move the plot. So I have a TouchsurfaceView which also calls requestRender() when needed.
Most of the time it works, but time to time I get an error because of concurrent requests for the ArrayList<Float> (almost sure of that).
Any ideas How can I solve this ? I see lock and synchronized stuff, but can t find how to properly use them for my case.
Thanks for reading me.
put all the updates to the static variable in a synchronized static method and use only that for making updates.

Android implement undo stack in drawing app

I started working on the sample Finger Paint app in the Android SDK to get more familiar with graphics. Lately I've been trying to implement undo/redo, and I've ran into road blocks every way I've tried. I've found a few threads about this, but none have gotten me past these issues. Here are my main 2 trials:
Strategy 1:
Save a stack of the paths (or canvases) and on undo clear the screen and redraw each path except the last one (or reinstate the most recent canvas).
The problem here is likely simple, but I just can't get the view to redraw anything. How do I draw saved paths (or restore a saved canvas)?
Strategy 2:
Save a stack of Bitmaps using getDrawingCache() after each touch. On undo, put the last bitmap back.
The saving has to be ran via post() from a runnable so it executes after onDraw() finishes (post adds it to the system message line after invalidate()). The issue is that when ran from the runnable getDrawingCache() always returns the initial version of the painting, like it can't see any changes after the first.
Why does getDrawingCache(), when called from a runnable, not see the current state of the view?
I've been fighting with this a while. Thanks.
case MotionEvent.ACTION_UP:
touch_up();
invalidate();
Runnable r = new Runnable(){
#Override
public void run() {
myView.storeView();
}
};
myView.post(r);
}
public void storeView(){
historyCount++;
if(historyCount > historySize) historyCount = 6; //We don't want more than 6
history.add(Bitmap.createBitmap(myView.getDrawingCache()),historyCount);
}
For strategy 1, you need to define a data structure that represents all the information needed to render a part of the drawing. So, for instance, if you draw a segment of the drawing by tracking the user's touch position, define a data structure that consists of the current color, drawing shape, and an ArrayList of coordinates used generated by one user gesture. As you follow the user's touch, drawing to the screen, also append the touch coordinates to the ArrayList for the current gesture. When the touch ends, push the data structure onto the undo stack and wait for the next user gesture to create the next structure instance and start populating it.
If you have various gestures (fill, freehand trace, straight line, etc.), you can have a separate structure for each. They can all inherit from an abstract class so they can all go on the stack.
The second strategy strikes me as a horrible memory hog. I think we'd have to see your code to understand why it isn't working as intended.

Android synchronizing?

I am not fully understanding what the synchronization block is doing nor why it is necessary.
Can someone explain in a "synchronizing for dummies" kind of way?
In a book I am reading, the author tells me "The synchronization is necessary, since the members we manipulate within the
synchronized block could be manipulated in the onPause() method on the UI thread."
He creates an Object named stateChanged and instantiates it as a new object.
Then, in the synchronization block he uses the stateChanged object as the argument.
This whole thing is throwing me off and I do not like to move on until I have a pretty good understanding of what is going on.
The classic example is: Imagine you have two threads of operation, and both of them reference the same method:
public void addToGlobalVar(int y) {
int x = globalVar; //what if a thread stops right after this line?
x += y;
globalVar = y;
}
where globalVar is some other predefined number that this method can interact with and set. Lets say globalVar is 50.
Threads get computing time on a somewhat arbitrary basis, so you never fully know the precise nanosecond one stops and the other gets CPU time.
In this example, if you launched an AsyncTask in addition to the UI thread, and both at some point use addToGlobalVar(10), what can happen is that one thread might be interrupted at line 2 of that code block. If the other thread goes through while that one is sleeping, it will successfully set globalVar to 60. But when the other one wakes up, it still thinks x = 50, and its going to then set it to 60. So in essence you just made 50+10+10 = 60. Hopefully you can see how this becomes a problem.
You can fix this simple example by making the calculation atomic (skip declaring x, 1 line, all calcs done) or if the logic wasn't able to be condensed to 1 line, you make a block of code atomic by using synchronized.
The book to read is Java Concurrency in Practice.
You should really just segregate this idea from Android, although your code is going to be running on Dalvik this is a Java concept. Not an Android one.
The synchronized block takes an object as a parameter, any object, and when flow enters the body of the synchronized block, any other thread that runs in to a synchronized block with the same instance (object) as the parameter has to wait for the previous one to complete. That's a very basic description.
This is an entire sub-field of computer science and without serious study you will probably not understand it.
You have to fully understand it before you use it. It is standard android synchronization using object-oriented monitors. You have to understand it to write multi-threaded programs, however it is somehow dated (better use java.util.concurrent for anything thread/synchronisation related instead).
Anyhow - you need to know what it is about - read the related java tutorial part:
http://download.oracle.com/javase/tutorial/essential/concurrency/sync.html

Categories

Resources