I want to change background image of a menu every x-amount of seconds. I'm using libGDX scene2D.ui for making the menu. The TestScreen class extends the AbstractScreen which is a abstract class that implements libGDX's Screen class.
Problem: After I load the Image to the stage through a Table object on a stack, changing the image reference to a different image does nothing. Stage.draw() gives no cares as if it made a copy of my original image. I would like to keep the background as Image class and render through stage.draw().
To further complicate things, if I do change the image to another in render() method, then image.setVisible(false) also stops working.
public class TestScreen extends AbstractScreen {
private Stage stage;
private Image background;
private boolean ChangeBackground = true;
private final float refreshTime = 2.0f; // refresh to new image every 2 seconds.
private float counter = refreshTime;
public TestScreen(Game game) {
super(game);
}
#Override
public void render(float deltaTime) {
Gdx.gl.glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
Gdx.gl.glClear(GL10.GL_COLOR_BUFFER_BIT);
if(ChangeBackground){
counter -= deltaTime;
if(counter < 0){
counter = refreshTime;
// Assets class has the 12 images loaded as "Image" objects already.
// I simple want to change the reference to other (already loaded in memory images) ...
// and make stage render the new image.
background = Assets.instance.wallpapers[(int) (Math.random()*12)]; // The image should change.
//background.setVisible(false);
}
}
stage.act(deltaTime);
stage.draw();
}
#Override
public void resize(int width, int height) {
stage.setViewport(Constants.VIEWPORT_GUI_WIDTH, Constants.VIEWPORT_GUI_HEIGHT, false);
}
#Override
public void show() {
stage = new Stage();
Gdx.input.setInputProcessor(stage);
makeStage();
}
#Override
public void hide() {
stage.dispose();
}
#Override
public void pause() {
}
// Builds the Background later and adds it to a stage through a stack.
// This is how it's done in my game. I made this test bench to demonstrate.
private void makeStage() {
Table BackGroundLayer = new Table();
background = Assets.instance.wallpapers[(int) (Math.random()*12)];
BackGroundLayer.add(background);
Stack layers = new Stack();
layers.setSize(800, 480);
layers.add(BackGroundLayer);
stage.clear();
stage.addActor(layers);
}
}
Image is a subclass of Actor. The main difference is, that Image has a Drawable inside. This Drawable gets drawn if you call stage.draw(), which calls the draw() of Image. Instead of changing Image you can change the Drawable by using setDrawable(Drawable param);.
What is a Drawable? It is any class, which implements the Drawable interface, for example the TextureRegionDrawable. If you are using TextureRegions you can use this constructor: TextureRegionDrawable(TextureRegion region);. Maybe it would be better to store your background images in a Drawable Array so you don't have to call a construcor each time you set a new Drawable. Example code:
TextureRegionDrawable[] images = new TextureRegionDrawable[12];
for (int i = 0; i<12; i++) {
images[i] = new TextureRegionDrawable(Assets.instance.textureRegions[i]);
}
Then in your render:
if(changeBackground) {
counter -= delta;
if (counter < 0) {
counter = refreshtime
background.setDrawable(images[(int)(Math.random()*12)]);
}
}
This should work
Related
Objective: to rotate an image in the center of the screen with movement equal to left or right touchDragged event.
Right now I have a basic Stage that is created and adds an actor (centerMass.png) to the stage. it is created and rendered like this:
public class Application extends ApplicationAdapter {
Stage stageGamePlay;
#Override
public void create () {
//setup game stage variables
stageGamePlay = new Stage(new ScreenViewport());
stageGamePlay.addActor(new CenterMass(new Texture(Gdx.files.internal("centerMass.png"))));
Gdx.input.setInputProcessor(stageGamePlay);
}
#Override
public void render () {
Gdx.gl.glClearColor(255f/255, 249f/255, 236f/255, 1f);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
//before drawing, updating actions that have changed
stageGamePlay.act(Gdx.graphics.getDeltaTime());
stageGamePlay.draw();
}
}
I then have a separate class file that contains the CenterMass class, extending Image. I am familiar enough to know I could extend Actor, but I am not sure the benefit I would gain using Actor vs Image.
In the CenterMass class I create the texture, set bounds, set touchable and center it on the screen.
Inside CenterMass class I also have an InputListener listening for events. I have an override set for touchDragged where I am trying to get the X and Y of the drag, and use that to set the rotate actions accordingly. That class looks like this:
//extend Image vs Actor classes
public class CenterMass extends Image {
public CenterMass(Texture centerMassSprite) {
//let parent be aware
super(centerMassSprite);
setBounds(getX(), getY(), getWidth(), getHeight());
setTouchable(Touchable.enabled);
setPosition(Gdx.graphics.getWidth()/2, Gdx.graphics.getHeight()/2);
setRotation(90f);
addListener(new InputListener(){
private int dragX, dragY;
private float duration;
private float rotateBy = 30f;
#Override
public void touchDragged(InputEvent event, float x, float y, int pointer) {
//get
float dX = (float)(x-dragX)/(float)Gdx.graphics.getWidth();
float dY = (float)(dragY-y)/(float)Gdx.graphics.getHeight();
duration = 1.0f; // 1 second
Actions.sequence(
Actions.parallel(
Actions.rotateBy(rotateBy, duration),
Actions.moveBy( dX, dY, duration)
)
);
}
});
}
#Override
protected void positionChanged() {
//super.positionChanged();
}
#Override
public void draw(Batch batch, float parentAlpha) {
//draw needs to be available for changing color and rotation, I think
batch.setColor(this.getColor());
//cast back to texture because we use Image vs Actor and want to rotate and change color safely
((TextureRegionDrawable)getDrawable()).draw(batch, getX(), getY(),
getOriginX(), getOriginY(),
getWidth(), getHeight(),
getScaleX(), getScaleY(),
getRotation());
}
#Override
public void act(float delta) {
super.act(delta);
}
}
The Problem:
I have not been able to get it to rotate the way I would like. I have been able to get it to shift around in unpredictable ways. Any guidance would be much appreciated.
As from you code it seems everything is good. except you don't set any origin of the image. without setting the origin it is by default set to 0,0.(bottom left of your image)
So if yow want to rotate the image with origin to centre you have to set the origin to imageWidth/2. imageHeight/2.
setOrigin(imageWidth/2,imageHeight/2)// something like this
I want to make in my app simple line plot with real time drawing. I know there are a lot of various libraries but they are too big or don't have right features or licence.
My idea is to make custom view and just extend View class. Using OpenGL in this case would be like shooting to a duck with a canon. I already have view that is drawing static data - that is first I am putting all data in float array of my Plot object and then using loop draw everything in onDraw() method of PlotView class.
I also have a thread that will provide new data to my plot. But the problem now is how to draw it while new data are added. The first thought was to simply add new point and draw. Add another and again. But I am not sure what will happen at 100 or 1000 points. I am adding new point, ask view to invalidate itself but still some points aren't drawn. In this case even using some queue might be difficult because the onDraw() will start from the beginning again so the number of queue elements will just increase.
What would you recommend to achieve this goal?
This should do the trick.
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.os.Bundle;
import android.support.v4.view.ViewCompat;
import android.support.v7.app.AppCompatActivity;
import android.util.AttributeSet;
import android.view.View;
import java.io.Serializable;
public class MainActivity
extends AppCompatActivity
{
private static final String STATE_PLOT = "statePlot";
private MockDataGenerator mMockDataGenerator;
private Plot mPlot;
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
if(savedInstanceState == null){
mPlot = new Plot(100, -1.5f, 1.5f);
}else{
mPlot = (Plot) savedInstanceState.getSerializable(STATE_PLOT);
}
PlotView plotView = new PlotView(this);
plotView.setPlot(mPlot);
setContentView(plotView);
}
#Override
protected void onSaveInstanceState(Bundle outState)
{
super.onSaveInstanceState(outState);
outState.putSerializable(STATE_PLOT, mPlot);
}
#Override
protected void onResume()
{
super.onResume();
mMockDataGenerator = new MockDataGenerator(mPlot);
mMockDataGenerator.start();
}
#Override
protected void onPause()
{
super.onPause();
mMockDataGenerator.quit();
}
public static class MockDataGenerator
extends Thread
{
private final Plot mPlot;
public MockDataGenerator(Plot plot)
{
super(MockDataGenerator.class.getSimpleName());
mPlot = plot;
}
#Override
public void run()
{
try{
float val = 0;
while(!isInterrupted()){
mPlot.add((float) Math.sin(val += 0.16f));
Thread.sleep(1000 / 30);
}
}
catch(InterruptedException e){
//
}
}
public void quit()
{
try{
interrupt();
join();
}
catch(InterruptedException e){
//
}
}
}
public static class PlotView extends View
implements Plot.OnPlotDataChanged
{
private Paint mLinePaint;
private Plot mPlot;
public PlotView(Context context)
{
this(context, null);
}
public PlotView(Context context, AttributeSet attrs)
{
super(context, attrs);
mLinePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mLinePaint.setStyle(Paint.Style.STROKE);
mLinePaint.setStrokeJoin(Paint.Join.ROUND);
mLinePaint.setStrokeCap(Paint.Cap.ROUND);
mLinePaint.setStrokeWidth(context.getResources()
.getDisplayMetrics().density * 2.0f);
mLinePaint.setColor(0xFF568607);
setBackgroundColor(0xFF8DBF45);
}
public void setPlot(Plot plot)
{
if(mPlot != null){
mPlot.setOnPlotDataChanged(null);
}
mPlot = plot;
if(plot != null){
plot.setOnPlotDataChanged(this);
}
onPlotDataChanged();
}
public Plot getPlot()
{
return mPlot;
}
public Paint getLinePaint()
{
return mLinePaint;
}
#Override
public void onPlotDataChanged()
{
ViewCompat.postInvalidateOnAnimation(this);
}
#Override
protected void onDraw(Canvas canvas)
{
super.onDraw(canvas);
final Plot plot = mPlot;
if(plot == null){
return;
}
final int height = getHeight();
final float[] data = plot.getData();
final float unitHeight = height / plot.getRange();
final float midHeight = height / 2.0f;
final float unitWidth = (float) getWidth() / data.length;
float lastX = -unitWidth, lastY = 0, currentX, currentY;
for(int i = 0; i < data.length; i++){
currentX = lastX + unitWidth;
currentY = unitHeight * data[i] + midHeight;
canvas.drawLine(lastX, lastY, currentX, currentY, mLinePaint);
lastX = currentX;
lastY = currentY;
}
}
}
public static class Plot
implements Serializable
{
private final float[] mData;
private final float mMin;
private final float mMax;
private transient OnPlotDataChanged mOnPlotDataChanged;
public Plot(int size, float min, float max)
{
mData = new float[size];
mMin = min;
mMax = max;
}
public void setOnPlotDataChanged(OnPlotDataChanged onPlotDataChanged)
{
mOnPlotDataChanged = onPlotDataChanged;
}
public void add(float value)
{
System.arraycopy(mData, 1, mData, 0, mData.length - 1);
mData[mData.length - 1] = value;
if(mOnPlotDataChanged != null){
mOnPlotDataChanged.onPlotDataChanged();
}
}
public float[] getData()
{
return mData;
}
public float getMin()
{
return mMin;
}
public float getMax()
{
return mMax;
}
public float getRange()
{
return (mMax - mMin);
}
public interface OnPlotDataChanged
{
void onPlotDataChanged();
}
}
}
Let me try to sketch out the problem a bit more.
You've got a surface that you can draw points and lines to, and you know how to make it look how you want it to look.
You have a data source that provides points to draw, and that data source is changed on the fly.
You want the surface to accurately reflect the incoming data as closely as possible.
The first question is--what about your situation is slow? Do you know where your delays are coming from? First, be sure you have a problem to solve; second, be sure you know where your problem is coming from.
Let's say your problem is in the size of the data as you imply. How to address this is a complex question. It depends on properties of the data being graphed--what invariants you can assume and so forth. You've talked about storing data in a float[], so I'm going to assume that you've got a fixed number of data points which change in value. I'm also going to assume that by '100 or 1000' what you meant was 'lots and lots', because frankly 1000 floats is just not a lot of data.
When you have a really big array to draw, your performance limit is going to eventually come from looping over the array. Your performance enhancement then is going to be reducing how much of the array you're looping over. This is where the properties of the data come into play.
One way to reduce the volume of the redraw operation is to keep a 'dirty list' which acts like a Queue<Int>. Every time a cell in your array changes, you enqueue that array index, marking it as 'dirty'. Every time your draw method comes back around, dequeue a fixed number of entries in the dirty list and update only the chunk of your rendered image corresponding to those entries--you'll probably have to do some scaling and/or anti-aliasing or something because with that many data points, you've probably got more data than screen pixels. the number of entries you redraw in any given frame update should be bounded by your desired framerate--you can make this adaptive, based on a metric of how long previous draw operations took and how deep the dirty list is getting, to maintain a good balance between frame rate and visible data age.
This is particularly suitable if you're trying to draw all of the data on the screen at once. If you're only viewing a chunk of the data (like in a scrollable view), and there's some kind of correspondence between array positions and window size, then you can 'window' the data--in each draw call, only consider the subset of data that is actually on the screen. If you've also got a 'zoom' thing going on, you can mix the two methods--this can get complicated.
If your data is windowed such that the value in each array element is what determines whether the data point is on or off the screen, consider using a sorted list of pairs where the sort key is the value. This will let you perform the windowing optimization outlined above in this situation. If the windowing is taking place in both dimensions, you most likely will only need to perform one or the other optimization, but there are two dimensional range query structures that can give you this as well.
Let's say my assumption about a fixed data size was wrong; instead you're adding data to the end of the list, but existing data points don't change. In this case you're probably better off with a linked Queue-like structure that drops old data points rather than an array, because growing your array will tend to introduce stutter in the application unnecessarily.
In this case your optimization is to pre-draw into a buffer that follows your queue along--as new elements enter the queue, shift the whole buffer to the left and draw just the region containing the new elements.
If it's the /rate/ of data entry that's the problem, then use a queued structure and skip elements--either collapse them as they're added to the queue, store/draw every nth element, or something similar.
If instead it's the rendering process that is taking up all of your time, consider rendering on a background thread and storing the rendered image. This will let you take as much time as you want doing the redraw--the framerate within the chart itself will drop but not your overall application responsiveness.
What I did in a similar situation is to create a custom class, let's call it "MyView" that extends View and add it to my layout XML.
public class MyView extends View {
...
}
In layout:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<com.yadayada.MyView
android:id="#+id/paintme"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
/>
</LinearLayout>
Within MyView, override method "onDraw(Canvas canv)". onDraw gets a canvas you can draw on. In onDraw, get a Paint object new Paint() and set it up as you like. Then you can use all the Canvas drawing function, e.g., drawLine, drawPath, drawBitmap, drawText and tons more.
As far as performance concerns, I suggest you batch-modify your underlying data and then invalidate the view. I think you must live with full re-draws. But if a human is watching it, updating more than every second or so is probably not profitable. The Canvas drawing methods are blazingly fast.
Now I would suggest you the GraphView Library. It is open source, don't worry about the license and it's not that big either (<64kB). You can clean up the necessary files if you wish to.
You can find a sample of usages for real time plots
in the official samples - https://github.com/jjoe64/GraphView-Demos/
Balanduino project - https://github.com/TKJElectronics/BalanduinoAndroidApp/blob/master/src/com/tkjelectronics/balanduino/GraphFragment.java
From the official samples:
public class RealtimeUpdates extends Fragment {
private final Handler mHandler = new Handler();
private Runnable mTimer1;
private Runnable mTimer2;
private LineGraphSeries<DataPoint> mSeries1;
private LineGraphSeries<DataPoint> mSeries2;
private double graph2LastXValue = 5d;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_main2, container, false);
GraphView graph = (GraphView) rootView.findViewById(R.id.graph);
mSeries1 = new LineGraphSeries<DataPoint>(generateData());
graph.addSeries(mSeries1);
GraphView graph2 = (GraphView) rootView.findViewById(R.id.graph2);
mSeries2 = new LineGraphSeries<DataPoint>();
graph2.addSeries(mSeries2);
graph2.getViewport().setXAxisBoundsManual(true);
graph2.getViewport().setMinX(0);
graph2.getViewport().setMaxX(40);
return rootView;
}
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
((MainActivity) activity).onSectionAttached(
getArguments().getInt(MainActivity.ARG_SECTION_NUMBER));
}
#Override
public void onResume() {
super.onResume();
mTimer1 = new Runnable() {
#Override
public void run() {
mSeries1.resetData(generateData());
mHandler.postDelayed(this, 300);
}
};
mHandler.postDelayed(mTimer1, 300);
mTimer2 = new Runnable() {
#Override
public void run() {
graph2LastXValue += 1d;
mSeries2.appendData(new DataPoint(graph2LastXValue, getRandom()), true, 40);
mHandler.postDelayed(this, 200);
}
};
mHandler.postDelayed(mTimer2, 1000);
}
#Override
public void onPause() {
mHandler.removeCallbacks(mTimer1);
mHandler.removeCallbacks(mTimer2);
super.onPause();
}
private DataPoint[] generateData() {
int count = 30;
DataPoint[] values = new DataPoint[count];
for (int i=0; i<count; i++) {
double x = i;
double f = mRand.nextDouble()*0.15+0.3;
double y = Math.sin(i*f+2) + mRand.nextDouble()*0.3;
DataPoint v = new DataPoint(x, y);
values[i] = v;
}
return values;
}
double mLastRandom = 2;
Random mRand = new Random();
private double getRandom() {
return mLastRandom += mRand.nextDouble()*0.5 - 0.25;
}
}
If you already have a view that draws static data then you're close to your goal.
The only thing you then have to do is:
1) Extract the logic that retrieves data
2) Extract the logic that draws this data to screen
3) Within the onDraw() method, first call 1) - then call 2) - then call invalidate() at the end of your onDraw()-method - as this will trigger a new draw and view will update itself with the new data.
I am not sure what will happen at 100 or 1000 points
Nothing, you do not need to worry about it. There are already a lot of points being plot every time there is any activity on the screen.
The first thought was to simply add new point and draw. Add another and again.
This is the way to go I feel. You may want to take a more systematic approach with this:
check if the plot will be on the screen or off the screen.
if they will be on the the screen simply add it to your array and that should be good.
if the data is not on the screen, make appropriate coordinate calculations considering the following: remove the first element from the array, add the new element in the array and redraw.
After this postinvalidate on your view.
I am adding new point, ask view to invalidate itself but still some points aren't drawn.
Probably your points are going off the screen. Do check.
In this case even using some queue might be difficult because the onDraw() will start from the beginning again so the number of queue elements will just increase.
This should not be a problem as the points on the screen will be limited, so the queue will hold only so many points, as previous points will be deleted.
Hope this approach helps.
currently I am trying to make an animation where some fish move around. I have successfully add one fish and made it animate using canvas and Bitmap. But currently I am trying to add a background that I made in Photoshop and whenever I add it in as a bitmap and draw it to the canvas no background shows up and the fish starts to lag across the screen. I was wondering if I needed to make a new View class and draw on a different canvas or if I could use the same one? Thank you for the help!
Here is the code in case you guys are interested:
public class Fish extends View {
Bitmap bitmap;
float x, y;
public Fish(Context context) {
super(context);
bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.fish1);
x = 0;
y = 0;
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawBitmap(bitmap, x, y, null);
if (x < canvas.getWidth())
{
x += 7;
}else{
x = 0;
}
invalidate();
}
}
You can draw as many bitmaps as you like. Each will overlay the prior. Thus, draw your background first, then draw your other images. Be sure that in your main images, you use transparent pixels where you want the background to show through.
In your code, don't call Invalidate() - that's what causes Android to call onDraw() and should only be called from somewhere else when some data has changed and needs to be redrawn.
You can do something like this, where theView is the view containing your animation:
In your activity, put this code in onCreate()
myAnimation();
Then
private void myAnimation()
{
int millis = 50; // milliseconds between displaying frames
theView.postDelayed (new Runnable ()
{
#Override public void run()
{
theView.invalidate();
myAnimation(); // you can add a conditional here to stop the animation
}
}, millis);
}
I have taken some code from a book on LibGDX, and adapted it for my own project, unfortunately, I have got a little stuck.
I have a class called MenuScreen (see below) which of course displays the Menu Screen. It is basically the same as the original code, just adapted for the Images I am using. In the project that was in the book, the Background image used for the Menu displayed correctly, filling an 800x480 Window on the Desktop, and filling the Screen of my Nexus 7.
With my project, the Image displays fine on the Desktop, but much smaller on the Nexus 7. I have a recent build for this project, and I understand that there has been some changes regarding the Viewport. I assume it is displaying now at actual size on the screen, but it is in fact now a lot smaller than is should be anyway... I have a 2012 N7, which has a resolution of 1280 x 800, but is displaying at about 550 x 300, even though the image itself is 800 x 480.
Could someone please point me in the right direction to get this image displaying correctly ?
public class MenuScreen extends AbstractGameScreen {
private static final String TAG = MenuScreen.class.getName();
private Stage stage;
private Skin demoSkin;
private Skin skinLibGdx;
private Viewport viewport;
private Image imgBackground;
// options
private Window winOptions;
private TextButton btnWinOptSave;
private TextButton btnWinOptCancel;
private TextButton optionsButton;
private TextButton startButton;
private Slider numBlocks;
private CheckBox chkShowFpsCounter;
public MenuScreen (Game game)
{
super(game);
}
#Override
public void render(float deltaTime) {
Gdx.gl.glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
stage.act(deltaTime);
stage.draw();
Table.drawDebug(stage);
}
#Override
public void resize(int width, int height) {
stage.getViewport().update((int)Constants.VIEWPORT_GUI_WIDTH, (int)Constants.VIEWPORT_GUI_HEIGHT, false);
}
#Override
public void show() {
stage = new Stage();
rebuildStage();
}
private void rebuildStage() {
demoSkin = new Skin(Gdx.files.internal(Constants.SKIN_PHYSICSDEMO_UI), new TextureAtlas(Constants.TEXTURE_ATLAS_UI));
skinLibGdx = new Skin(Gdx.files.internal(Constants.SKIN_LIBGDX_UI), new TextureAtlas(Constants.TEXTURE_ATLAS_LIBGDX_UI));
// build all layers
Table layerBackground = buildBackgroundLayer();
Table layerControls = buildControlsLayer();
Table layerOptionsWindow = buildOptionsWindowLayer();
// assemble stage for menu screen
stage.clear();
Stack stack = new Stack();
stage.addActor(stack);
stack.setSize(Constants.VIEWPORT_GUI_WIDTH, Constants.VIEWPORT_GUI_HEIGHT);
stack.add(layerBackground);
stack.add(layerControls);
//stage.addActor(layerOptionsWindow);
}
private Table buildOptionsWindowLayer() {
winOptions = new Window("Options", skinLibGdx);
// Make options window slightly transparent
winOptions.setColor(1, 1, 1, 0.8f);
// Hide options window by default
winOptions.setVisible(false);
//showOptionsWindow(false, false);
// Let TableLayout recalculate widget sizes and positions
winOptions.pack();
// Move options window to bottom right corner
winOptions.setPosition(Constants.VIEWPORT_GUI_WIDTH - winOptions.getWidth() - 50, 50);
return winOptions;
}
private void showOptionsWindow (boolean visible, boolean animated) {
float alphaTo = visible ? 0.8f : 0.0f;
float duration = animated ? 1.0f : 0.0f;
Touchable touchEnabled = visible ? Touchable.enabled : Touchable.disabled;
winOptions.addAction(sequence(touchable(touchEnabled), alpha(alphaTo, duration)));
}
private Table buildControlsLayer() {
Table layer = new Table();
startButton = new TextButton("Start Simulation", skinLibGdx);
optionsButton = new TextButton("Options", skinLibGdx);
layer.add(startButton);
layer.row();
layer.add(optionsButton);
return layer;
}
private Table buildBackgroundLayer() {
Table layer = new Table();
imgBackground = new Image(demoSkin, "background");
layer.add(imgBackground);
return layer;
}
#Override
public void hide() {
stage.dispose();
skinLibGdx.dispose();
demoSkin.dispose();
}
#Override
public void pause() {
// TODO Auto-generated method stub
}
#Override
public InputProcessor getInputProcessor() {
return stage;
}
}
You need to set size of the background image separately.
imgBackground.setSize(imageWidth, imageHeight);
Since you are changing Viewport size in resize method, for a screen with higher resolution, image will become even smaller. So image size must be set to be large enough.
You can calculate required image size by multiplying original image size by scaling factor (ratio of actual resolution and assumed resolution).
Good luck.
I'm trying to draw a shape on a Canvas and get information about the clicks that the user performs on that Canvas.
I created a class which extends the Button class.
class CustomDrawableButton extends Button {
private final ShapeDrawable mDrawable;
int x = 50;
int y = 50;
int width = 30;
int height = 30;
public CustomDrawableButton (Context context) {
super(context);
mDrawable = new ShapeDrawable (new OvalShape ());
mDrawable.getPaint().setColor(Color.GREEN);
mDrawable.setBounds(x, y, x + width, y + height);
}
protected void onDraw(Canvas canvas) {
mDrawable.draw(canvas);
}
}
Then, in a class which also extends View, I added the instantiation and a listener:
CustomDrawableButton mCustomDrawableButton = new CustomDrawableButton(getBaseContext());
layout.addView(mCustomDrawableButton);
mCustomDrawableButton.draw(canvas);
mCustomDrawableButton.setOnClickListener(new View.OnClickListener() {
public void onClick(View view) {
System.out.println("Yey clicked");
Toast.makeText(view.getContext(), "Yey", Toast.LENGTH_LONG).show();
}});
When this is executed, it is not able to detect the clicks on the image / button. I have read that ShapeDrawable objects can't be "clickable", but I was expecting this to work since I'm extending the Button (which is a View and is "clickable").
Is this possible? If not this way, can you direct me to some way to get information about the screen coordinates that were pressed on a Canvas or a View ?
Thanks in advance.
After some searching here's a tutorial that shows how to do it using by getting the touched screen position.
http://marakana.com/tutorials/android/2d-graphics-example.html
Still don't know how to do it by automatically binding the touched event to a button. If anyone knows how to do it, please say so.
Thanks.