Android OpenGL change setContentView or setRenderer? - android

I'm working on a game for Android, it uses OpenGL 1.0. I have created a Menu, which was a simple activity with layout, but I didn't liked it, so I decided to create that too in OpenGL, which works, but I don't know how to switch to the actual game. I would like to do it in another GLSurfaceView, because creating everything in one then I must load all textures at the start which could be slow.
My question is that it is possible to change the setContentView or setRenderer somehow?
The basic of the app is like here: http://developer.android.com/resources/tutorials/opengl/opengl-es10.html#creating where setContentView is where I control Touch and Key events, and there I set the setRenderer to GLSurfaceView.

If you have just one activity and one GLSurfaceView, you can switch what you render by manipulating the renderer object.
public class MyRenderer implements Renderer {
Vector<String> modelsToLoad;
HashMap<String, Model> models;
String[] modelsToDraw;
Context context;
#Override
public void onDrawFrame(GL10 gl) {
// load models ahead of time
while(modelsToLoad.size()>0){
String modelFilename = modelsToLoad.remove(0);
models.put(modelFilename, new Model(modelFilename,context,gl));
}
// keep drawing current models
for(int i = 0;i<modelsToDraw.length;i++){
models.get(modelsToDraw[i]).draw(gl);
}
}
// queue models to be loaded when onDraw is called
public void loadModel(String filename){
modelsToLoad.add(filename);
}
// switch to in-game scene
public void drawGame(){
modelsToDraw = new String[]{"tank.mdl", "soldier.mdl"};
}
// switch to menu scene
public void drawMenuBackground(){
modelsToDraw = new String[]{"bouncingBall.mdl", "gun.mdl"};
}
}
Then in onCreate:
MyRenderer myRenderer;
public void onCreate(Bundle bundle){
super.onCreate(bundle);
// set layout which has everything in it
setContentView(R.layout.main);
myRenderer = new Renderer(this);
// load menu models
myRenderer.loadModel("bouncingBall.mdl");
myRenderer.loadModel("gun.mdl");
// set up the glsurfaceview
GLSurfaceView mGLView = findViewById(R.id.glsurfaceview1);
mGLView.setRenderer(myRenderer);
// set the renderer to draw menu background objects
myRenderer.drawMenuBackground();
// set the new game button to start the game
ImageButton newGameButton = findViewById(R.id.new_game_button1);
newGameButton.setOnClickListener(new OnClickListener(){
public void onClick(View v){
// make menu invisible
findViewById(R.id.menu_linearLayout1).setVisibility(View.GONE);
// tell renderer to render game scene
myRenderer.drawGame();
}
});
// make the menu visible
findViewById(R.id.menu_linearLayout1).setVisibility(View.VISIBLE);
// finally we have some time whilst the user decides on their menu option
// use it to load game models in anticipation of the user clicking new game
myRenderer.loadModel("tank.mdl");
myRenderer.loadModel("soldier.mdl");
}
So rather than messing around with two renderer objects or multiple GLSurfaceViews, you instead have a single renderer object, and you just tell it what to render and when. You can manage it so that it loads models and textures only when you need it to or in anticipation of some need. Also it makes things easier if you decide to use the same model in more than one place. If you wanted to put a model in your menu that also features in game, you can just load it once and reuse as many times as you like!

Related

What method within view is notified when view is displayed on ui

I'm trying to create a custom surfaceview where every time the view is on the screen the view will start playing a video on its own. I was wondering what method within View is notified when a view is displayed on the UI and seen by the user. I'm using a viewpager so the SurfaceCreated doesn't work because views are created before they are displayed on the screen.
How to start a video automatically in a view pager when it comes on the screen
This was the underlying problem. The OP, wisely, wanted to try and isolate the point where it, in a sense "comes on to the screen". Problem is that this can mean many things:
When I first heard the question, I thought a good case would be onAttachedToWindow - see the docs. For people reading this question based on its original title, this is what you want.
The view is inflated and created in the Activity's onCreate in most cases (e.g. if you've used setContentView).
The OP had had no luck with surfaceCreated callbacks either. So we considered in the comments above whether the OP would be interested in the three draw stages layout, measure and draw. There are two stages to actually "putting a view on the screen" in android - the measuring, and the layout pass- see here.
Problem would be that it turned out that the OP was animating his view onto the screen, so the question became how do you tell when a view "arrives" on the screen after animation.
The important point is: you actually wanted to detect a stage much much later in the drawing process, which is understandable! Animation works by many calls to invalidate which in turn require many draws for that view's Canvas - so the stage at which you want to play the video is by no means when the view is first displayed in the UI.
Solution for this particular scenario.
Use animation listeners on your ViewAnimator instances (e.g. ViewPager). To not have to bother with them in teh activity, I would roll your own view, and then use the Adapter type patterns Android is so fond of to manage constantly changing data:
a very hastily written implementation would be:
public class VideoStartingViewFliper extends ViewFlipper {
private final Animation fromRight;
private final Animation toLeft;
private final Animation fromLeft;
private final Animation toRight;
private VideoViewAdapter mAdapter;
public VideoStartingViewFliper(final Context context, final AttributeSet attrs) {
super(context, attrs);
fromRight = new YourChoiceOfAnimation();
fromRight.setAnimationListener(videoStartingAnimationListener);
toLeft = new YourChoiceOfAnimation();
toLeft.setAnimationListener(videoStartingAnimationListener);
fromLeft = new YourChoiceOfAnimation();
fromLeft.setAnimationListener(videoStartingAnimationListener);
toRight = new YourChoiceOfAnimation();
toRight.setAnimationListener(videoStartingAnimationListener);
}
static interface VideoViewAdapter {
public String getVideoPath(int childId);
}
public void setVideoViewAdapter(final VideoViewAdapter adapter) {
mAdapter = adapter;
}
// or even call this showNextVideo and don't override!
#Override
public void showNext() {
setInAnimation(fromRight);
setOutAnimation(toLeft);
super.showNext();
}
#Override
public void showPrevious() {
setInAnimation(fromLeft);
setOutAnimation(toRight);
super.showPrevious();
}
private final AnimationListener videoStartingAnimationListener = new AnimationListener() {
#Override
public void onAnimationStart(final Animation animation) {
final VideoView video = ((VideoView) getCurrentView());
video.stopPlayback();
}
#Override
public void onAnimationRepeat(final Animation animation) {
}
#Override
public void onAnimationEnd(final Animation animation) {
final VideoView video = ((VideoView) getCurrentView());
// check null here!
video.setVideoPath(mAdapter.getVideoPath(getCurrentView().getId()));
video.start();
}
};
}
Hope this helps.

How to connect button actions with surfaceview canvas drawables?

My problem is that I don't know how to change position of a canvas drawable on click of
my button that it's located in the main activity and not to surfaceview so the code to work should be on surfaceview here is what I've got
public class JumpOnClick extends Activity implements OnClickListener{
DrawingSurface ds;
FrameLayout frm;
Button btnC;
int color=0xfff00000;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ds=new DrawingSurface(this);
setContentView(R.layout.activity_jump_on_click);
frm=(FrameLayout)findViewById(R.id.frameLayout);
frm.addView(ds);
btnC=(Button)findViewById(R.id.buttonColor);
btnC.setOnClickListener(this);
}
#Override
public void onClick(View v) {
// how to connect actions in here for my sprites on my surfaceview
// for example AnimatedSprite a = new AnimatedSprite();
// if(b == null)
//b=BitmapFactory.decodeStream(res.openRawResource(R.drawable.explosion));
// a.Initialize(b, 120, 159, 7, 20, true);
// mSprites.add(a);
}
}
if I understand correctly,
define two static float variables in your surfaceview class respectively x and y, and when you do your drawing in your surfaceview just use this variables as position parameters in your surfaceview's draw method. And then back in your activity in your onClick method of the button just change these x,y variables, as you can access them without any need to create object.
I believe that you need to add layout rules to your button to place it in the Surfaceview (Actually a button cant be added to a SurfaceView, you need to create an illusion with a Layout in your Activity and place the button to this Layout).
You can check this simple solution at this video https://www.youtube.com/watch?v=8qE9TQjQ5no&t=31s
that is placing buttons to a SurfaceView at the top and bottom using a Relativelayout. My opinion is with that technique you wont need the ontouchevent method neither the x,y position, you will need that if you create a button in the ondraw method (then wont be a button but a bitmap image)...My opinion is to stick with the first solution if the position is the problem so it can act as a button with the onclicklistener.

Gesture recognizer and AndEngine (Android)

In the game I'm developing I need this function: being able to draw on the screen and to establish if the drawing is a determined shape (let's say a rectangle, triangle or whatever).
So I wanted to use gestures, which are the easier way to do that; with the gesture builder I made a few shapes and I use them as models. The thing is, I can't make it work with the AndEngine.
I need the GestureOverlayView, which is basically the drawing board, to be placed ON TOP of the scene of the game, so that I can see the scene itself with all the entities attached and I can also draw gesture.
Right now what I tried didn't work, either the AndEngine stuff is shown on screen or the GestureOverlayView is, not both.
I'm new both with android developing and the AndEngine, so I'm kinda stuck here... do you have any ideas on how could I make it work? I looked everywhere but I can't find anything useful...
I'll leave the code of the gesture part below just for example, it won't really work obviously if you don't have any pre-made gestures in the path res/raw of the project:
public class ProvaGesture extends Activity implements GestureOverlayView.OnGesturePerformedListener
{
private GestureLibrary gestureLib;
public GestureOverlayView gestureOverlayView;
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
gestureOverlayView = new GestureOverlayView(this);
gestureOverlayView.addOnGesturePerformedListener(this);
gestureLib = GestureLibraries.fromRawResource(this, R.raw.gestures);
if (!gestureLib.load())
{
finish();
}
setContentView(gestureOverlayView);
}
public void onGesturePerformed(GestureOverlayView overlay, Gesture gesture)
{
ArrayList<Prediction> predictions = gestureLib.recognize(gesture);
for (Prediction prediction : predictions)
{
if (prediction.score > 1.0)
{
Toast.makeText(this, prediction.name, Toast.LENGTH_SHORT).show();
}
}
}
}
I didn't see AndEngine part in your demo code. Your ProvaGesture activity should be extended from AndEgine's SimpleBaseGameActivity or BaseGameActivity then implements IOnSceneTouchListener.
Base on your idea, I guessed that you try to create a separated overlay view which handles only the gesture, so you must consider:
You have only one activity running at a time in android.
If you want to create an User-defined view overlaping the AndEgine's surface view, you should see Andengine's example: XMLLayoutExample.
The solution may be [suggested]:
public class OverlapLayoutExample extends SimpleLayoutGameActivity {
#Override
protected int getLayoutID() {
//your layout id (xml file in layout folder)
return R.layout.overlaplayout;
}
#Override
protected int getRenderSurfaceViewID()
{
//overlaplayout will contain a SurfaceView with following ID
//this surface is where you render Andgine
return R.id.overlaplayout_rendersurfaceview;
}
}
Don't forget to create your own layout: overlaplayout containing surfaceView and OverlayView

Need assistance in OpenGL in android

I've created 3 Java classes.
one that has a glsurfaceview object and this calls the renderer class.
this is the renderer class and this calls the cube class.
this is the cube class.
If I run the app then the screen shows a rotating cube (did rotation in the rendering class) which is fine. But I want to control the direction of rotation of the cube and for that I've set 2 buttons. This is where I need help because I don't know to to make the buttons control the movement of the cube. I'm new to Android so if you could leave some code for me to examine then that would be just great.
Your Activity class (or your class that extends Activity) should look like this:
public class stackoverflowTest extends Activity {
GLSurfaceView glSurface;
MyRenderer myRenderer;
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
myRenderer = new MyRenderer(this);
//Create an instance of the Renderer with this Activity
glSurface = (GLSurfaceView) findViewById(R.id.graphics_glsurfaceview1);
//Set our own Renderer and hand the renderer this Activity Context
glSurface.setEGLConfigChooser(true);
glSurface.setRenderer(myRenderer);
//Set the GLSurface as View to this Activity
}
/**
* this is the method the button click calls
*/
public void changeRotationDirection(View v){
myRenderer.changeRotationDirection();
}
}
Then in your renderer:
public class MyRenderer implements Renderer {
private float rotationDirection = 1.0f;
public MyRenderer(Context context){
this.context = context;
}
public void setRotationDirection(){
if(rotationDirection==1.0f){
rotationDirection=-1.0f;
} else {
rotationDirection=1.0f;
}
}
#Override
public void onDrawFrame(GL10 gl) {
// GL calls
gl.glRotatef(angle, rotateDirection, 0.0f, 0.0f);
// draw cube
gl.glDrawArrays( etc );
}
}
Basically, you use glRotatef to rotate the cube just before you draw it. Use -ve vales for either the angle parameter (the first) or the x,y,z amount parameters to rotate in the opposite direction. Use method calls to the Renderer to communicate with it and update the scene. Use this approach with caution as the Renderer thread and Main/UI thread (from where the button call is made) can have synchronisation issues
To make a button call the changeRotationDirection method, simply add android:onClick="changeRotationDirection" into the XML layout (of any view. Doesn't have to be just a button view). Any button methods declared in the XML layout have to be of the form public void [methodname](View [paramname]) and have to be in the Activity class from where the button is pressed
For more advanced touch control, check as Erik suggested and also check out OnTouchListeners
(Note: if you're using openGL-ES 2.0 or above (android 2.2+) then use GLES20.glRotatef())
You might want to check out the TouchRotateActivity example from the sdk. If I'm not mistaken its located in the samples/platform/api-demos folder.

invalidate() on custom View does not cause onDraw(Canvas c) to be called

For my activity i use 3 custom views stacked.
the lower one is a SurfaceView fullscreen, the middle one is derived from GridView and overrides onDraw to add custom graphic.
The top one is derived directly from View, sits in a corner of the screen and act as a knob to control the others two views (this is the problematic view).
to add a custom animation to this view, i used this pattern:
public class StubKnobView extends View{
private Drawable knob;
private Point knobPos;
private float rotation;
private boolean needsToMove;
public void moveKnob(){
/* ...various calculations... */
this.needsToMove=true;
invalidate(); //to notify the intention to start animation
}
private void updateAnimation(){
/* ........... */
this.needsToMove= !animationComplete;
invalidate();
}
#Override
protected void onDraw(Canvas canvas) {
int saveCount=canvas.getSaveCount();
canvas.save();
canvas.rotate(this.rotation, this.knobPos.x, this.knobPos.y );
this.knob.draw(canvas);
canvas.restoreToCount(saveCount);
if(this.needsToMove){
updateAnimation();
}
}
}
ideally, if there is an animation pending, after each drawing cycle the view should auto invalidate.
right now this doesn't work, to force the animation i have to touch the screen to cause a onDraw cycle.
Using "show screen updates" of Dev tools I see that no screen invalidate/update cycle happen , apart when i click the screen.
specifying the dirty rect also ha no effect.
So, any idea where to look to know why this invalidate/draw cycle does not work the way is intended?
I encontered this situation, and also doubted that invalidate() doesn't make onDraw() called again.
After simplified the business codes, it's turn out that there is a dead loop - exactly too much iterations, which blocks the UI thread.
So, my advice is that make sure the UI thread going smoothly first.
Try something like this with a private class in your View. The idea is not to call invalidate() from within onDraw(). Instead, post it on the running queue. Instantiate the private class in your View constructor and then just call animateKnob.start() when you want the animation. The onDraw() can then just focus on drawing.
public void moveKnob(){
// update the state to draw... KnobPos, rotation
invalidate()
}
private class AnimateKnob{
public void start(){
// Do some calculations if necessary
// Start the animation
MyView.this.post( new Runnable() {
stepAnimation()
});
}
public void stepAnimation(){
// update the animation, maybe use an interpolator.
// Here you could also determine if the animation is complete or not
MyView.this.moveKnob();
if( !animationComplete ){
// Call it again
MyView.this.post( new Runnable() {
stepAnimation()
});
}
}
}

Categories

Resources