Bitmap.getPixel in SurfaceView - java

I have this code where there is a Backgroung under an Hand, both a Bitmap images. Now, i have to control with an onClick method if the click touches the hand or not. For this, i wrote here and some guys tell me to use a method called "bitmap.getPixel(int x, int y)" that gives the color of pixel touched. For control if the click doesn't touch the hand, i write "bitmap.getPixel(x, y) != Color.TRASPARENT", but doesn't work perfectly. Under this i write the code of SurfaceView.
P.S. The bitmap "Hand" is a picture of a central Hand with parts trasparent around.
public class GamePanel extends SurfaceView implements SurfaceHolder.Callback{
private long missileStartTime;
private ThreadLv1 thread;
private OggettiLv1 hand;
private int conto=0;
private Sfondo sfondo;
MediaPlayer ouch;
public GamePanel(Context context){
super(context);
getHolder().addCallback(this);
thread = new ThreadLv1(getHolder(), this);
setFocusable(true);
}
#Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height){}
#Override
public void surfaceDestroyed(SurfaceHolder holder){
boolean retry = true;
while(retry)
{
try{thread.setRunning(false);
thread.join();
}catch(InterruptedException e){e.printStackTrace();}
retry = false;
}
}
#Override
public void surfaceCreated(SurfaceHolder holder){
hand = new OggettiLv1(BitmapFactory.decodeResource(getResources(), R.drawable.mano5));
sfondo = new Sfondo(BitmapFactory.decodeResource(getResources(), R.drawable.sfondo));
ouch= MediaPlayer.create(getContext(), R.raw.ouch);
knifesong.start();
thread.setRunning(true);
thread.start();
}
public void update() {
}
#Override
public void draw(Canvas canvas)
{
if(canvas!=null) {
final int savedState = canvas.save();
background.draw(canvas);
hand.draw(canvas);
drawText(canvas);
canvas.restoreToCount(savedState);
}
}
#Override
public boolean onTouchEvent(MotionEvent event)
{
float x = event.getX();
float y = event.getY();
switch(event.getAction())
{
case MotionEvent.ACTION_DOWN:
int c = hand.sprite.getPixel((int) event.getX(), (int) event.getY());
if(c!=Color.TRANSPARENT){
conto++;
}
return true;
}
return false;
}
}
Someone know the problem and the solution in this code? Thanks in advance.

I think this might be the problem:
int c = hand.sprite.getPixel((int) event.getX(), (int) event.getY());
I think you are getting the value of a pixel at the x,y location on the sprite, you should get the value of the pixel on canvas.
EDIT:
Since your canvas is static, I suggest doing the following:
add a Bitmap to your class
private Bitmap canvasState;
In the draw function, initialize canvasState before anything else
canvasState = Bitmap.createBitmap(canvas.getWidth(), canvas.getHeight(), Bitmap.Config.RGB_565));
canvas.setBitmap(canvasState);
after that, every change that you make to the canvas will be made to the canvasState, and you can use that in your event handler like so:
int c = canvasState.getPixel((int) event.getX(), (int) event.getY());
I'm not sure if the code I wrote will compile (I wrote them from the top of my head) but I think you can work out compile errors yourself.

Related

How to use onClickListener on two CanvasView Objects?

I am trying make a game such that when user click on shooter it changes its position and and shoots and if user click on shooted balls (or shoots as named in project) they disappear CODE HERE
Shooter.JAVA
public class shooter extends View {
//Consider all variables are declared
public shooter(int color, Context c) {
super(c);
paint = new Paint();
paint.setColor(color);
mContext = c;
}
public void move() {
//Moves Cannon On Click (CODE NOT SHOWN PURPOSELY)
invalidate();
}
public float getPosition()
{
return shootPoint;
}
public void draw(Canvas canvas)
{
super.draw(canvas);
// simply draws a rectangle (shooter)
cW=getWidth();
cH=getHeight();
center=new Point(cW/2,cH);
left=0; right=center.x; shootPoint=right/2;
canvas.drawRect(left,top,right,bottom,paint);
}
}
Another Java Class Named shoot.java is also there to make shoot balls when shootbutton is clicked
but I want that when user click on those balls(drawn on canvas ) they should reset
Main Game View Class
public class GameView extends FrameLayout implements View.OnClickListener {
//Consider all objects and variables are declared as used
public GameView(Context context, AttributeSet attrs) {
super(context,attrs);
//CONTAIN INITIALIZATION OF OBJECTS AS USED OF OTHER CLASSES
bullets = new ArrayList<shoot> ();
addView(cannon);
for (int i = 0; i < bullets.size(); i++ ) {
addView(bullets.get(i));
bullets.get(i).setOnClickListener(this);// an arrays of objects of shoot class
}
cannon.setOnClickListener(this);
level=3;level++;
}
#Override
public void onClick(View view) {
switch()// Here is the MAIN PROBLEM HOW SHOULD I DIFFERENTIATE THAT CANNON IS CLICKED OR //BULLETS LIKE USING VIEW.GETTAG()
{
case ----1:// WHAT CASE SSHOULD I WRITE
cannon.move();
break;
case ----2: // HERE ALSO
bullets.remove();
break;
}
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
drawGameBoard(canvas);
try
{
Thread.sleep(5);
} catch (InterruptedException e) {
}
invalidate();
}
#Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
width = w;
height = h;
aliens.setBounds(0,0,width,height);
for (int i = 0; i < bullets.size(); i++ ) {
bullets.get(i).setBounds(0,0,width,height);
}
}
public void drawGameBoard(Canvas canvas) {
cannon.draw(canvas);
for ( int i = bullets.size() - 1; i >= 0; i--) {
if (bullets.get(i) != null) {
bullets.get(i).draw(canvas);
}
}
for (int i = explosions.size() - 1; i >= 0; i--) {
if (explosions.get(i) != null) {
if (!explosions.get(i).draw(canvas)) {
explosions.remove(i);
}
}
}
if (aliens != null) {
aliens.draw(canvas);
RectF guyRect = aliens.getRect();
for (int i = bullets.size() - 1; i >= 0; i--) {
if (RectF.intersects(guyRect, bullets.get(i).getRect())) {
explosions.add(new explosion(Color.RED,mContext, aliens.getX()-aliens.dst, aliens.getY()-aliens.dst));
aliens.reset();
bullets.remove(i);
break;
}
}
if (!aliens.move()) {
aliens = null;
}
}
}
// Whenever the user shoots a bullet, create a new bullet moving upwards
public void shootCannon() {
bullets.add(new shoot(Color.RED, mContext, cannon.getPosition(), (float) (height-100)));
}
}
I have showed the part of the code where I am having the problem that is the overridden function ONCLICK in GAMEVIEW.JAVA by comments like how to know what is clicked so todo their respected functions
please notify me if you didn't understand my question
If I understand the question correctly, you want to use one onClickListener function to handle the click events for both your cannon and your bullets.
Since both are different classes you may differentiate between them via '''instanceof'''.
That means your onClickListener would look something like this:
#Override
public void onClick(View view) {
if(view instanceof shooter) {
cannon.move();
}
else if(view instanceof shoot) {
bullets.remove();
}
}
I hope this helps you. If anything remains unclear I'll gladly response :)
If you want to know the coordinates of the touch which you can use to figure out, if an item is tapped,
consider using View.OnTouchListener instead of View.OnClickListener.
View.OnTouchListener has this function:
onTouch(View v, MotionEvent event)
How to use:
check if event is a tap: event.getAction() ==
MotionEvent.ACTION_DOWN
get the coordinates: event.getX() and event.getY()
And after that, replace cannon.setOnClickListener(this); with cannon.setOnTouchListener(this);
If there are any questions, do not hesitate to ask them!

Java LibGDX sprite moving twice as fast as camera

So I've got a class which extends ApplicationAdapter implements InputProcessor and does the following when you drag around on the screen.
#Override
public boolean touchDragged(int screenX, int screenY, int pointer) {
float x = Gdx.input.getDeltaX();
float y = Gdx.input.getDeltaY();
if (Store.isGameState) {
Store.Entity.player.setxMove(x);
Store.Entity.player.setyMove(-y);
}
return true;
}
In my player class I have a update method which does the following:
#Override
public void update() {
x += xMove;
y += yMove;
Store.Camera.Camera.position.set(Store.Entity.player.getXPos() + Store.Entity.player.getWidth() / 2, Store.Entity.player.getYPos() + Store.Entity.player.getHeight() / 2, 0);
Store.Camera.Camera.update();
}
and a render method which is:
public void render(SpriteBatch SB) {
SB.begin();
Store.Entity.sprite.setPosition(Store.Entity.player.getXPos(), Store.Entity.player.getYPos());
Store.Entity.sprite.draw(SB);
SB.end();
}
Which all-in-all works, the camera will move around as will my sprite. However my sprite does not move at the same speed as my camera and I can't for the life of me figure out why this is the case. The sprite moves roughly twice as fast as the camera does, and isn't centered on the player which I'd like ideally.
EDIT:
So in my GameState I have the following:
package com.imjoshscott.dataria.states;
import com.imjoshscott.dataria.Game;
import com.imjoshscott.dataria.Store;
public class GameState extends State {
public GameState(Game game) {
super(game);
Store.isGameState = true;
Store.Entity.getPlayer(game, Store.Entity.getSprite());
Store.Graphics.getSpriteBatch();
Store.Graphics.getTiledMap();
Store.Graphics.getTiledMapRenderer();
Store.Camera.getCamera();
Store.Camera.getHudCamera();
Store.Camera.Camera.setToOrtho(false, Game.GAME_WIDTH, Game.GAME_HEIGHT);
Store.Camera.HudCamera.setToOrtho(false, Game.GAME_WIDTH, Game.GAME_HEIGHT);
Store.Camera.Camera.viewportHeight = Game.GAME_HEIGHT / 2.5f;
Store.Camera.Camera.viewportWidth = Game.GAME_WIDTH / 2.5f;
}
#Override
public void update() {
Store.Graphics.tiledMapRenderer.setView(Store.Camera.Camera);
Store.Entity.player.update();
}
#Override
public void render() {
Store.Graphics.tiledMapRenderer.render();
Store.Entity.player.render(Store.Graphics.SB);
}
}
The Camera stuff in the Store class:
public static class Camera {
public static OrthographicCamera Camera;
public static OrthographicCamera HudCamera;
public static OrthographicCamera getCamera() {
if(Camera == null)
Camera = new OrthographicCamera();
return Camera;
}
public static OrthographicCamera getHudCamera() {
if(HudCamera == null)
HudCamera = new OrthographicCamera();
return HudCamera;
}
}
EDIT: Showing update & render methods
public void update() {
moveCreature();
Store.Entity.sprite.setPosition(Store.Entity.player.getXPos(), Store.Entity.player.getYPos());
Store.Camera.Camera.position.set(Store.Entity.player.getXPos(), Store.Entity.player.getYPos(), 0);
Store.Camera.Camera.update();
xMove = 0f;
yMove = 0f;
}
public void render(SpriteBatch SB) {
SB.begin();
Store.Entity.sprite.draw(SB);
SB.end();
}
Updated My previous answer is not correct, upon seeing and checking the project I saw this render() method for GameState class (after looked around for several places but no dice, if ever found this very weird problem again I would direct to this).
public void render() {
Store.Graphics.tiledMapRenderer.render();
Store.Entity.player.render(Store.Graphics.SB);
}
Just one thing we need to add to fix very weird problem is to add the following code
Store.Graphics.SB.setProjectionMatrix(Store.Camera.Camera.combined);
so we would have
public void render() {
Store.Graphics.SB.setProjectionMatrix(Store.Camera.Camera.combined);
Store.Graphics.tiledMapRenderer.render();
Store.Entity.player.render(Store.Graphics.SB);
}
That means we need to set projection matrix to current active SpriteBatch to properly render stuff. It's also safe to set it before even render the tile as it uses the same camera as of player.

When someone touches a red circle on my app nothing happens

I am making an app that displays circles randomly on the screen. The circles are either red or green. The purpose of the app is so that when someone touches a green circle something good happens, like they get points added to their score. When a red circle is clicked something bad happens like a new activity is started and the page says you failed or something. Here is my code for this app. In this code i receive no errors, nothing in logcat, everything works just fine. The circles display randomly on the screen as well as the score which is by default 0. The problem i am having with this app is that when a red or a green circle is clicked nothing happens.
public DrawingView(Context context) {
super(context);
// TODO Auto-generated constructor stub
}
RectF rectf = new RectF(0, 0, 200, 0);
private static final int w = 100;
public static int lastColor = Color.BLACK;
private final Random random = new Random();
private final Paint paint = new Paint();
private final int radius = 230;
private final Handler handler = new Handler();
public static int redColor = Color.RED;
public static int greenColor = Color.GREEN;
int randomWidth = 0;
int randomHeight = 0;
public static int addPoints = 0;
private final Runnable updateCircle = new Runnable() {
#Override
public void run() {
lastColor = random.nextInt(2) == 1 ? redColor : greenColor;
paint.setColor(lastColor);
invalidate();
handler.postDelayed(this, 1000);
}
};
#Override
protected void onAttachedToWindow() {
super.onAttachedToWindow();
handler.post(updateCircle);
}
#Override
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
handler.removeCallbacks(updateCircle);
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
// your other stuff here
if(random == null){
randomWidth =(int) (random.nextInt(Math.abs(getWidth()-radius/2)) + radius/2f);
randomHeight = (random.nextInt((int)Math.abs((getHeight()-radius/2 + radius/2f))));
}else {
randomWidth =(int) (random.nextInt(Math.abs(getWidth()-radius/2)) + radius/2f);
randomHeight = (random.nextInt((int)Math.abs((getHeight()-radius/2 + radius/2f))));
}
canvas.drawCircle(randomWidth, randomHeight, radius, paint);
paint.setColor(Color.BLACK);
paint.setTextSize(150);
canvas.drawText("Score: " + addPoints, 120, 300, paint);
}
public boolean onTouch(View v, MotionEvent event) {
int x = (int) event.getX();
int y = (int) event.getY();
if(isInsideCircle(x, y) == true){
//Do your things here
if(redColor == lastColor){
Intent i = new Intent(v.getContext(), YouFailed.class);
v.getContext().startActivity(i);
} else {
addPoints++;
}
}else {
}
return true;
}
public boolean isInsideCircle(int x, int y){
if ((((x - randomWidth)*(x - randomWidth)) + ((y - randomHeight)*(y - randomHeight))) < ((radius)*(radius))){
return true;
}
return false;
}
}
Your view might not be implementing the View.OnTouchListener interface, hence it not calling the onTouch() method.
Your view is not being set a View.OnTouchListener via the view's View.setOnTouchListener(View.OnTouchListener) method.
Android Developer Reference - View.OnTouchListener
Either way it feels wrong to make a view implement this interface to listen to itself. Instead you may want to take a look at the View.onTouchEvent(MotionEvent event) method; perhaps it serves your purpose (or it should in this case). Listener interfaces are supposed to be implemented by external components. Say, for example, if you wanted to make your TextView listen every time a Button or ImageView is touched, you could extend TextView/Button and make them implement the Listener interface then pass it to you view as a parameter of its setOnTouchListener(View.OnTouchListener).
However, all views have a method called onTouchEvent(). This View.onTouchEvent() method should be used if you want to listen to events within the view itself, as it is by default called whenever the view is, well touched. Should you need a reference to the view itself with this approach, you call this since the view itself would be your current scope.
Android Developer Reference - View.onTouchEvent(MotionEvent event)
If you do it like this, all you would need to do in order to make your code work is change your onTouch() method to an override of onTouchEvent() like this: (Also added verification of touch action as suggested by Pooja and Tom so you don't take into account MOVE or UP events. Change DOWN for UP depending on when you want to trigger the event)
#Override
public boolean onTouchEvent(MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_DOWN) {
int x = (int) event.getX();
int y = (int) event.getY();
if(isInsideCircle(x, y) == true) {
//Do your things here
if(redColor == lastColor){
Intent i = new Intent(v.getContext(), YouFailed.class);
this.getContext().startActivity(i);
} else {
addPoints++;
}
} else {
//Handle case not inside the circle
}
}
return true;
}
The onTouch method is meant to be used with OnTouchListener and would normally be defined outside your custom view class. For example:
this.setOnTouchListener(new OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
// touch handling code
return true;
}
});
In the case where you are looking for touch events inside your custom view, you should implement the onTouchEvent method. You may also want to check for either ACTION_UP or ACTION_DOWN or you will be processing multiple touch events.
#Override
public boolean onTouchEvent(MotionEvent event) {
boolean result = false;
if (event.getAction() == MotionEvent.ACTION_DOWN) {
int x = (int) event.getX();
int y = (int) event.getY();
if(isInsideCircle(x, y) == true) {
//Do your things here
if(redColor == lastColor){
Intent i = new Intent(v.getContext(), YouFailed.class);
v.getContext().startActivity(i);
} else {
addPoints++;
}
result = true;
}
}
return result;
}
See the following for more details:
Input Events

2D Moving player with canvas

So I was told to create a simple game in android using canvas only for a school project (meaning I can't use any extensions or game engines beside the ones that come with android), and I wanted to create a simple 2d game with a player walking around.
I did it like that:
public GameView(Context c) {
// TODO Auto-generated constructor stub
super(c);
this.c=c;
this.Sprite=BitmapFactory.decodeResource(getResources(), R.drawable.walk1);
this.Sprite=Bitmap.createScaledBitmap(Sprite, Sprite.getWidth()*2, Sprite.getHeight()*2, false);
sprite2=new Sprite("Spicy",Sprite);
this.requestFocus();
this.setFocusableInTouchMode(true);
animate1();
}
I created a view class, loaded a simple player sprite, created sprite class and an handler -
public void animate1(){
handlerAnimation100 = new Handler();
final Runnable r = new Runnable() {
public void run() {
invalidate();
handlerAnimation100.postDelayed(this, 1);
}
};
handlerAnimation100.postDelayed(r, 1);
}
that does invalidate every 0.001 seconds for the game time and animation.
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
sprite2.Draw(canvas);
}
#Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
sprite2.Update(keyCode);
invalidate();
return false;
}
on onDraw i called the draw function in the sprite class and onkeydown I sent the key pressed to the update function in the sprite class.
Now for the sprite class there isn't something special:
public class Sprite {
enum State
{
Walking
}
State mCurrentState = State.Walking;
int mDirection = 0;
int mSpeed = 0;
int mPreviousKeyboardState;
private String spriteName;
Bitmap sprite;
int SPRITE_SPEED = 5;
int MOVE_LEFT = -1;
int MOVE_RIGHT = 1;
private float mScale = 1.0f;
Point Position;
public Sprite(String name,Bitmap sprite) {
this.sprite=sprite;
this.spriteName=name;
Position=new Point(150,150);
}
public void Update(int keyboard)
{
int aCurrentKeyboardState = keyboard;
UpdateMovement(aCurrentKeyboardState);
mPreviousKeyboardState = aCurrentKeyboardState;
}
private void UpdateMovement(int aCurrentKeyboardState)
{
if (mCurrentState == State.Walking)
{
mSpeed = 0;
mDirection = 0;
if (aCurrentKeyboardState==KeyEvent.KEYCODE_A)
{
mSpeed = SPRITE_SPEED;
mDirection = MOVE_LEFT;
}
else if(aCurrentKeyboardState==KeyEvent.KEYCODE_D)
{
mSpeed = SPRITE_SPEED;
mDirection= MOVE_RIGHT;
}
Position.x += mDirection * mSpeed;
}
}
public void Draw(Canvas c)
{
c.drawBitmap(sprite, Position.x,Position.y, null);
}
}
I just change the position of the image and move it depending on the key pressed.
Now here is the problem:
Using handler and invalidate was the only option I was able to find to replace "Game time" that appears in game engines, and although it works, it works very choppily, if the speed of the player is high it looks like it jumps pixels and if its low the animation is blurry and very slow, it looks like the invalidate takes more time and it happens not every 0.001 seconds but 0.5 seconds or so.
Here is how it looks like:
Slow speed (blurry and very slow):
Faster Speed (choppy not smooth):
Is there a better way to do it, again with only using what android offers?
Threads! However the handler is not the root of your problem judging by how slow your animation is running and how choppy the fast one is, you are probably using a canvas tied into an ImageView? This is not very fast at all. You should look into using a SurfaceView (works with lower APIs but not the fastest) or into TextureView (super fast, I had to delay my thread cause the animation was just a blur). Both of these rely on canvas at their core.
There are lots of examples out there on in internets on how to code these and you can adapt them for your purposes. To give you a place to start you can look HERE at some samples I wrote.

Simple Android Live Wallpaper with sequence of images - Updated with code

I would like to develop a simple Live Wallpaper with a sequence of images. The only animation required is for each image to fade in and fade out.
All the tutorials I have found online for LWP demonstrate how to use the Draw canvas for fancy animations and drawing. This is not necessary for my app, I only want to iterate through a collection of images.
Being a novice programmer, I need some help learning how to loop through an array of images and how to display them as a wallpaper.
Can anyone share some code or point me towards a good tutorial for this?
UPDATE
The LWP loads on my device but the wallpaper does not change. It is stuck on image3, ironman
Here is the code I have so far. I assume I am doing something wrong in draw()
public class Wallpaper extends WallpaperService {
public void onCreate() {
super.onCreate();
}
public void onDestroy() {
super.onDestroy();
}
public Engine onCreateEngine() {
return new CercleEngine();
}
class CercleEngine extends Engine {
private final Handler handler = new Handler();
private final Runnable drawRunner = new Runnable() {
#Override
public void run() {
draw();
}
};
private boolean visible = true;
public Bitmap image1, image2, image3;
CercleEngine() {
image1 = BitmapFactory.decodeResource(getResources(),
R.drawable.batman);
image2 = BitmapFactory.decodeResource(getResources(),
R.drawable.captainamerica);
image3 = BitmapFactory.decodeResource(getResources(),
R.drawable.ironman);
}
public void onCreate(SurfaceHolder surfaceHolder) {
super.onCreate(surfaceHolder);
}
#Override
public void onVisibilityChanged(boolean visible) {
this.visible = visible;
if (visible) {
handler.post(drawRunner);
} else {
handler.removeCallbacks(drawRunner);
}
}
#Override
public void onSurfaceDestroyed(SurfaceHolder holder) {
super.onSurfaceDestroyed(holder);
this.visible = false;
handler.removeCallbacks(drawRunner);
}
public void onOffsetsChanged(float xOffset, float yOffset, float xStep,
float yStep, int xPixels, int yPixels) {
draw();
}
void draw() {
final SurfaceHolder holder = getSurfaceHolder();
Canvas c = null;
try {
c = holder.lockCanvas();
if (c != null) {
c.drawBitmap(image1, 0, 0, null);
c.drawBitmap(image2, 0, 0, null);
c.drawBitmap(image3, 0, 0, null);
}
} finally {
if (c != null)
holder.unlockCanvasAndPost(c);
}
handler.removeCallbacks(drawRunner);
if (visible)
{
handler.postDelayed(drawRunner, 1000); // delay 1 sec
}
}
}
There is no easy way around the looping through an array of images. It would have to be done manually.
One approach that you could adopt is to keep your images in the /res/drawable
and then use an int[] array to store the resid's of the images and then loop through it.
A well explained tutorial on Live Wallpapers may be found here:
http://www.vogella.com/articles/AndroidLiveWallpaper/article.html
Good Luck

Categories