I'm creating a puzzle game where the player can choose a picture and then the program splits it into multi-parts.
I tried to search on many posts answers for my problem, but all of them are talking about BufferedImage or Graphic components. I'm coding on android studio to export my application later, and BufferedImage, Graphics, and others are not known by android. So I think that I should use BitmapDrawable to manipulate my images.
public void initImage(int image) {
this.base = setImage(puzzle.getApplicationContext(), image, 800, 800);
}
public BitmapDrawable setImage(final Context c, final int ressource, final int w, final int h)
{
try {
Drawable dr = c.getResources().getDrawable(ressource);
Bitmap bitmap = ((BitmapDrawable) dr).getBitmap();
return new BitmapDrawable(c.getResources(), Bitmap.createScaledBitmap(bitmap, w, h, true));
} catch(ClassCastException cce) { cce.printStackTrace(); return null; }
}
#Override
public void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawBitmap(this.base.getBitmap(), 0, 0, null);
}
I draw my first image, and now I want to split it into multi parts.
If anyone could help me, I would be very grateful. :)
Related
I'm working on a 2D game on Android / Java.
During each frame, I use a fixed size Back Buffer bitmap (1024x768) to draw all the game's assets (background, sprites, ...).
Then at the end of the onDraw(), I draw this back buffer on the screen with the right size :
Rect Source = new Rect(0, 0, 1024, 768);
Rect Dest = new Rect(0, 0, m_ScreenWidth, m_ScreenHeight);
canvas.drawBitmap(BackBufferBitmap, Source, Dest, null);
The problem is that when I use this engine to just draw a simple 1024x768 image on the screen (the simplest I can do), the operation takes between 35 and 40 milliseconds on a LG G4 phone (i.e. approx 25fps). Is it possible to get a better fps with another way of managing 2D graphics?
I turn on hardware acceleration, thread's max priority.
I don't have this problem on phones with lower pixel count. I guess my problem is linked to the high number of pixels on a LG G4 (2560x1440).
Is it possible to do the drawing faster?
Or, otherwise, is it possible to just run my game on such high-definition devices with a lower definition (like we do on PC)?
EDIT : here is the full code :
1) my View
public class ElementaryView extends SurfaceView implements SurfaceHolder.Callback
{
private ElementaryThread m_Thread;
private SurfaceHolder m_Holder;
private Bitmap m_SimpleBitmap=null;
private Bitmap m_BackBuffer =null;
private Canvas m_BackBufferCanvas =null;
public ElementaryView(Context context)
{
super (context);
m_Holder =getHolder();
m_Holder.addCallback(this);
setFocusable(true);
}
#Override
public void surfaceCreated(SurfaceHolder holder)
{
m_Thread =new ElementaryThread(m_Holder,this);
m_Thread.setPriority(Thread.MAX_PRIORITY);
m_BackBuffer =Bitmap.createBitmap(1024,768,Config.ARGB_8888);
m_BackBufferCanvas =new Canvas(m_BackBuffer);
m_SimpleBitmap =BitmapFactory.decodeResource(this.getResources(), R.drawable.splashscreen);
//"splashscreen" is a 1024x768 jpg image
m_Thread.setRunning(true);
m_Thread.start();
}
#Override
protected void onDraw(Canvas canvas)
{
m_BackBufferCanvas.drawBitmap(m_SimpleBitmap, 0, 0, null);
Rect Source =new Rect(0,0,1024,768);
Rect Dest =new Rect(0,0,this.getWidth(),this.getHeight());
canvas.drawBitmap(m_BackBuffer,Source,Dest,null);
}
}
2) my thread :
public class ElementaryThread extends Thread
{
private SurfaceHolder m_SurfaceHolder;
private ElementaryView m_View;
private boolean m_Running;
public ElementaryThread(SurfaceHolder sh, ElementaryView view)
{
super();
m_SurfaceHolder = sh;
m_View = view;
}
public void setRunning(boolean r) { m_Running = r; }
#SuppressLint("WrongCall") #Override
public void run()
{
Canvas canvas;
while (m_Running)
{
canvas =null;
try
{
canvas =this.m_SurfaceHolder.lockCanvas();
this.m_View.onDraw(canvas);
}
finally
{
if (canvas!=null) m_SurfaceHolder.unlockCanvasAndPost(canvas);
}
}
}
}
And this gives a frame rate lower than 30fps on a LG G4. Yet, a lot of 2D games run with a better fps on my G4. Does anybody knows how they do that ?
By default, the LG G4 will always run at a res. of 2560x1440, which of course is going to make it difficult for the phone to render any graphics. This is also why the lesser res. phones will run much more smoothly. So, the only solution to this problem would be to change the resolution dependent on the number of pixels and processing power of the device.
First, for this (for games) is better to use SurfaceView
Second, show the method onDraw entirely. Most likely, you have a resource-intensive operation there. (scale etc.)
I have onDraw takes about 3ms with a similar task.
I'm not sure that you are properly working. What do you want? "this.m_View.onDraw(canvas);"
Remove
#Override
protected void onDraw(Canvas canvas)
From ElementaryView
And move code into Thread. Something like this:
#SuppressLint("WrongCall") #Override
public void run()
{
Canvas canvas;
while (m_Running)
{
canvas =null;
try
{
canvas =this.m_SurfaceHolder.lockCanvas();
Rect Source =new Rect(0,0,1024,768);
Rect Dest =new Rect(0,0,m_View.getWidth(),m_View.getHeight());
canvas.drawBitmap(m_SimpleBitmap, 0, 0, null);
canvas.drawBitmap(m_BackBuffer,Source,Dest,null);
}
finally
{
if (canvas!=null) m_SurfaceHolder.unlockCanvasAndPost(canvas);
}
}
}
}
When I set the background on my view.
//background
Bitmap back_bmp = BitmapFactory.decodeResource(context.getResources(), R.drawable.background);
BitmapDrawable backTiled = new BitmapDrawable(back_bmp);
backTiled.setTileModeXY(Shader.TileMode.REPEAT, Shader.TileMode.REPEAT);
backTiled.setBounds(0, 0, this.getWidth(), this.getHeight());
this.setBackgroundDrawable(backTiled);
My animated object doesn't render at all
public void render(Canvas canvas) {
elaine.draw(canvas);
}
public void update() {
elaine.update(System.currentTimeMillis());
}
Though without the background set it draws fine.
I called the background in my view, and although it may have worked it really didn't work out well.
After re factoring and giving up I went back to how I thought it should work. I should have check if something that didn't work(Only because when I first tried it the code didn't set boundaries or load image efficiently.) might work again.
I did and realized that everything works perfectly if loaded within render.
public void render(Canvas canvas) {
//background
Bitmap _back_bmp = BitmapFactory.decodeResource(mainContext.getResources(), R.drawable.background);
backTiled = new BitmapDrawable(_back_bmp);
backTiled.setTileModeXY(Shader.TileMode.REPEAT, Shader.TileMode.REPEAT);
backTiled.setBounds(0, 0, this.getWidth(), this.getHeight());
backTiled.draw(canvas);
elaine.draw(canvas);
}
I'm trying to make custom brushes for my Android painting app. I started with Michael's code (found here) and I have managed to get .png brushes and use that as a bitmap and redraw it. It works fine but I can't change the colour. Tried using the setcolorfilter and colormatrixfilter but it doesn't seem to be working. Anyone knows how I can do this?
private Bitmap mBitmapBrush;
private Vector2 mBitmapBrushDimensions;
private List<Vector2> mPositions = new ArrayList<Vector2>(100);
private Paint mPanit;
public MyView(Context c) {
super(c);
mPath = new Path();
mBitmapPaint = new Paint(Paint.DITHER_FLAG);
mBitmapBrush = BitmapFactory.decodeResource(c.getResources(),R.drawable.brush1);
mBitmapBrushDimensions = new Vector2(mBitmapBrush.getWidth(), mBitmapBrush.getHeight());
}
#Override
protected void onDraw(Canvas canvas) {
canvas.drawColor(0xFFAAAAAA);
canvas.drawBitmap(mBitmap, 0, 0, mBitmapPaint);
for (Vector2 pos : mPositions) {
canvas.drawBitmap(mBitmapBrush, pos.a, pos.b, mPanit);
}
invalidate();
}
When I tried using the Colormatrixfilter, the .set function was giving an error.
I had the same issue. In order to change the bitmap color you need to add color to your paint object and apply it into bitmap. See the working example here,
for (Vector2 pos : customBrushMap.get(p)) {
Paint paint = new Paint();
ColorFilter filter = new PorterDuffColorFilter(R.Color.GREEN, PorterDuff.Mode.SRC_IN);
paint.setColorFilter(filter);
canvas.drawBitmap(mBitmapBrush, pos.x, pos.y, paint);
}
Result,
I am trying to use Painter to make a certain jpg become my background.
mapScreen = new Form("Map");
try
{
Image image = Image.createImage("/res/try.jpg");
map = new Map(image);
mapScreen.addComponent(map);
} catch (Exception e)
{
System.out.print("Error\n\n"+e.getMessage());
mapScreen.addComponent(new Label(e.getMessage()));
}
And for the map class,
public Map(Image image)
{
this.mapImage = image;
painter = new Painter()
{
public void paint(Graphics g, Rectangle clippingRect)
{
g.clipRect(0, 0, getWidth(), getHeight());
g.drawImage(mapImage, getX(), getY());
}
};
}
public void initComponent()
{
setX(0);
setY(0);
getSelectedStyle().setBgTransparency(0);
getSelectedStyle().setBgPainter(painter);
getUnselectedStyle().setBgTransparency(0);
getUnselectedStyle().setBgPainter(painter);
}
The problem with this is that the image doesn't show up at all and when I try to debug, It doesn't even enter the paint(Graphics g, Rectangle clippingRect)...
The code
try
{
Image image = Image.createImage("/res/try.jpg");
map = new Map(image);
mapScreen.addComponent(map);
}
is successful.
Can anyone tell me how to do it properly?
And also, if anyone know how to do panning on an image larger than the size of the screen, Can you help me with that also? Thanks.
Use setBgTransparency to 255 and don't call the clipRect method.
You can look at the bg painter code within Component.java which is pretty flexible.
I am doing a small project for college and wondering if someone can tell me how I would go about doing a scratch card app. This app should have one image overlaying another. The one on top should allow the user to remove the image depending on where they rub on the image and thus part of the image that was removed revealing the image underneath. Pretty much like a scratch card. Any help would be great!
This is the code im using at the moment .
public class workinggraphics extends Activity
{
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
//setContentView(R.layout.main);
setContentView(new Panel(this));
LinearLayout l1 = (LinearLayout) findViewById(R.id.LAYOUTTEST1);
Panel p1 = new Panel(null);
}
class Panel extends View{
private Bitmap mBitmap;
private Canvas mCanvas;
private Path mPath;
private Paint mPaint;
// private Paint nPaint;
Bitmap bitmap;
Canvas pcanvas ;
int x = 0;
int y =0;
int r =0;
public Panel(Context context) {
super(context);
Log.v("Panel", "STROKE");
setFocusable(true);
setBackgroundColor(Color.TRANSPARENT);
/*
WallpaperManager wallpaperManager = WallpaperManager.getInstance(context);
//WallpaperDrawable wallpaperDrawable=wallpaperManager.getDrawable();
try {
wallpaperManager.setBitmap(bmp);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}*/
//setBackgroundDrawable(bmp);
// setting paint
/* nPaint = new Paint();
nPaint.setStyle(Paint.Style.FILL);*/
mPaint = new Paint();
mPaint.setAlpha(0);
mPaint.setStyle(Paint.Style.FILL_AND_STROKE);
mPaint.setStrokeCap(Paint.Cap.BUTT);
mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_IN));//.Mode.DST_IN));
mPaint.setAntiAlias(false);
// getting image from resources
Resources r = this.getContext().getResources();
Bitmap bm = BitmapFactory.decodeResource(getResources(), R.drawable.mainscreen_background);
Bitmap bm1 = BitmapFactory.decodeResource(getResources(),R.drawable.foreground_image);
// converting image bitmap into mutable bitmap
bitmap = bm.createBitmap(bm.getWidth(), bm.getHeight(), Config.ARGB_8888);
//bitmap = bm1.createBitmap(bm1.getWidth(),bm1.getHeight(),Config.ARGB_8888);
pcanvas = new Canvas();
pcanvas.setBitmap(bitmap); // drawXY will result on that Bitmap
pcanvas.drawBitmap(bm, 0, 0, null);
pcanvas.drawBitmap(bm1,0,0,null);
}
#Override
protected void onDraw(Canvas canvas) {
Rect cBK = new Rect();
//canvas.set
cBK.set(0,0,canvas.getWidth(),canvas.getHeight());
//pcanvas.drawRect(cBK, nPaint);
// draw a circle that is erasing bitmap
pcanvas.drawCircle(x, y, r, mPaint);
//pcanvas.drawLine(x, y, 0, 0, mPaint);
canvas.drawBitmap(bitmap, 0, 0,null);
super.onDraw(canvas);
}
#Override
public boolean onTouchEvent(MotionEvent event) {
// set paramete to draw circle on touch event
x = (int) event.getX();
y = (int) event.getY();
r =20;
// Atlast invalidate canvas
invalidate();
return true;
}
}
}
Now as you can see above there is a lot of comments for things we have tried. Ideally I would like to be able to create an instance of the Panel class, set the workinggraphics class contextview to a XML LinearLayout (OR SurfaceView w/e would be used I dont really know), and then just set a background image on the defined LinearLayout in XML to be revealed when the canvas erases the bitmap image we have set.
Anyway any suggestions would be appricated thanks alot in advanced!
I created a library call WScrarchView where you can implement scratch view just few lines in layout xml. Hope this can help those who still looking for the solution https://github.com/winsontan520/Android-WScratchView