Android: How can I rotate an image from the center? - java

I'm trying to rotate this bitmap in the very center by "R0" degrees. But it doesn't rotate in the center. It rotates from the upper left corner.
Here's my code:
public class MainActivity extends Activity{
Player ourView;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ourView = new Player(this);
setContentView(ourView);
}
protected void onPause() {
super.onPause();
ourView.pause();
}
protected void onResume() {
super.onResume();
ourView.resume();
}
}
Here's the other class:
public class Player extends SurfaceView implements Runnable {
Canvas canvas = new Canvas();
SurfaceHolder ourHolder;
Thread ourThread = null;
boolean isRunning = true;
public Player(Context context) {
super(context);
ourHolder = getHolder();
ourThread = new Thread(this);
ourThread.start();
}
public void pause() {
isRunning = false;
while(true){
try{
ourThread.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
break;
}
ourThread = null;
}
public void resume() {
isRunning = true;
}
public void run() {
while(isRunning) {
if(!ourHolder.getSurface().isValid())
continue;
canvas = ourHolder.lockCanvas();
canvas.drawRGB(30, 30, 200);
MainPlayer player = new MainPlayer();
player.execute();
ourHolder.unlockCanvasAndPost(canvas);
}
}
}
And this is the class in which the bitmap gets rotated:
public class MainPlayer{
Canvas canvas = new Canvas();
Context context;
float x=160;
float y=455;
float k=160;
float l=455;
float R0 = 150;
public void execute(){
draw();
}
public void draw(){
Matrix matrix = new Matrix();
Bitmap bitmap = (Bitmap) BitmapFactory.decodeResource(getResources(), R.drawable.ic_launcher);
matrix.setRotate(R0);
Bitmap b = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);
canvas.drawBitmap(b, x, y, null);
}
}
Thanks very much.

Related

libGDX manager.update() blocking animations

I successfully implemented a gifdecoder in my project and wrote a gifloader for it to use it with the assetmanager. I am able to load the gif in the assetmanager and I am also able to draw it. But everytime I try to load gifs in my assetmanager with manager.update() I can not draw animations anymore, only non animated textures.
Here is my code I hope somebody has an idea
public class Load implements Screen {
private SpriteBatch batch;
private Animation<TextureRegion> loadingAnimation;
private TextureAtlas atlasLoading = new TextureAtlas(Gdx.files.internal("atlas/loadingAnimation.atlas"));
float stateTime;
MainExecute lr;
public FileHandleResolver resolver = new InternalFileHandleResolver();
public AssetManager manager = new AssetManager();
private final Animation animation = GifDecoder.loadGIFAnimation(Animation.PlayMode.NORMAL, Gdx.files.internal("data/loading.gif").read());
public Load(MainExecute lr){
this.lr = lr;
}
public Texture Bg1;
#Override
public void show() {
Bg1 = new Texture(Gdx.files.internal("bggamescreen.png"));
batch = new SpriteBatch();
manager.setLoader(GIF.class,new Gifloader(resolver));
manager.load("data/BackgroundAnim.gif",GIF.class);
stateTime = 0f;
}
#Override
public void render(float delta) {
if (manager.update())
{
lr.setScreen(new MainMenu(lr));
}
stateTime += delta;
// loadingAnimation = new Animation<TextureRegion>(0.5f, atlasLoading.findRegions("loading"),Animation.PlayMode.LOOP);
TextureRegion currentFrame = (TextureRegion) animation.getKeyFrame(stateTime, true);
batch.begin();
batch.draw(Bg1,0,0,Gdx.graphics.getWidth(),Gdx.graphics.getHeight());
batch.draw(currentFrame, 0, 0, 200, 200);
batch.end();
}
#Override
public void resize(int width, int height) {
}
#Override
public void pause() {
}
#Override
public void resume() {
}
#Override
public void hide() {
}
#Override
public void dispose() {
}
}
Strange code, you are drawing animation before it finish loading. You need to waiting to load your animation, try smth like this.
if (manager.update())
{
loadingAnimation = new Animation<TextureRegion>(0.5f, atlasLoading.findRegions("loading"),Animation.PlayMode.LOOP);
TextureRegion currentFrame = (TextureRegion) animation.getKeyFrame(stateTime, true);
lr.setScreen(new MainMenu(lr));
}

Trying to create a moving sprite on a scrolling background

I got interested on Android, I'm new at it so I created a scrolling background and I want to put a sprite on it I already created a character class and the scroll background. I want to make the sprite move to the right but I'm getting error on my GamePanel.
The error is Non-static method(android.graphics.Canvas) cannot be referenced from a static context, what does it mean and How am I going to fix this and my make the sprite look like running to the right?
Here's my code:
public class GamePanel extends SurfaceView implements SurfaceHolder.Callback {
public static final int WIDTH = 856;
public static final int HEIGHT = 480;
public static int Score =0;
public static int Highscore;
private MainThread thread;
private Background bg;
private Bitmap bmp;
public GamePanel(Context context) {
super(context);
getHolder().addCallback(this);
thread = new MainThread(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) {
bg = new Background(BitmapFactory.decodeResource(getResources(), R.drawable.gamebg));
bmp = BitmapFactory.decodeResource(getResources(), R.drawable.deer);
bg.setVector(-5);
thread.setRunning(true);
thread.start();
}
#Override
public boolean onTouchEvent(MotionEvent event) {
return super.onTouchEvent(event);
}
public void update() {
Score += 2;
if (Score > Highscore) {
Highscore = Score;
}
bg.update();
}
#SuppressLint("MissingSuperCall")
#Override
public void draw(Canvas canvas) {
final float scaleFactorX = (float)getWidth()/WIDTH;
final float scaleFactorY = (float)getHeight()/HEIGHT;
if(canvas !=null) {
final int savedState = canvas.save();
canvas.scale(scaleFactorX, scaleFactorY);
bg.draw(canvas);
canvas.restoreToCount(savedState);
Paint textpaint = new Paint();
textpaint.setTextSize(30);
canvas.drawText("Score:" +String.valueOf(Score), 0, 32, textpaint);
canvas.drawText("High Score: "+String.valueOf(Highscore), 0, 64, textpaint);
}
}
#Override
protected void onDraw(Canvas canvas) {
Character.onDraw(canvas);
}
}
You cannot access non static methods from a static context. So if you want to access a function or an object of the GamePanel class, you need to call this member by using the object instance of GamePanel class.
Just an example:
wrong:
GamePanel.draw(canvas);
correct:
GamePanel gamePanel = new GamePanel(this);
gamePanel.draw(canvas);

Need help to animate a moving line with onDraw() - JAVA

I made a line via the drawLine method that starts from the bottom and goes to half the screen size.
So far so good. Now I wanted to "tilt" the line to the left or right when the screen is pressed.
Something like this in the picture:
And when pressed again have it tilt back to the other side and so on.
The problem I have now is that when I tilt the line, its "trail" is visible, because I call the drawLine method multiple times.
This is my code:
public class MainGamePanel extends SurfaceView implements SurfaceHolder.Callback {
private static final String TAG = MainGamePanel.class.getSimpleName();
private MainThread thread;
private Paint paint;
private GameLine gameLine;
public MainGamePanel(Context context){
super(context);
getHolder().addCallback(this);
setFocusable(true);
paint = new Paint();
paint.setStrokeWidth(50);
paint.setColor(Color.WHITE);
gameLine = new GameLine(getWidth()/2,getHeight(),getWidth()/2, getHeight()/2,paint);
thread = new MainThread(getHolder(), this);
}
#Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {}
#Override
public void surfaceCreated(SurfaceHolder holder) {
thread.setRunning(true);
thread.start();
gameLine = new GameLine(getWidth()/2,getHeight(),getWidth()/2, getHeight()/2,paint);
}
#Override
public void surfaceDestroyed(SurfaceHolder holder) {
...}
#Override
public boolean onTouchEvent(MotionEvent event) {
if(event.getAction() == MotionEvent.ACTION_DOWN){
gameLine.setTapped(true);
}
return super.onTouchEvent(event);
}
public void render(Canvas canvas) {
gameLine.drawTheLine(canvas);
}
public void update(){
gameLine.update();
}}
public class MainThread extends Thread {
private boolean running;
private MainGamePanel gamePanel;
private SurfaceHolder surfaceHolder;
public MainThread(SurfaceHolder surfaceHolder, MainGamePanel gamePanel){
super();
this.gamePanel=gamePanel;
this.surfaceHolder = surfaceHolder;
}
public void setRunning(boolean running){
this.running = running;
}
#Override
public void run(){
Canvas canvas;
while (running){
canvas = null;
try {
canvas = this.surfaceHolder.lockCanvas();
synchronized (surfaceHolder){
this.gamePanel.update();
this.gamePanel.render(canvas);
}
}finally {
if(canvas != null){
surfaceHolder.unlockCanvasAndPost(canvas);
}
}
}
}}
public class GameLine {
private float startX;
private float startY;
private float stopX;
private float stopY;
private Paint paint;
private boolean tapped = false;
public GameLine(float startX, float startY, float stopX, float stopY, Paint paint) {
Normal Constructor
}
public boolean getTapped(){
return tapped;
}
public void setTapped(boolean tapped){
this.tapped = tapped;
}
public void update(){
if(tapped){
this.stopX -=1;
}
}
public void drawTheLine(Canvas canvas){
canvas.drawLine(startX, startY,stopX, stopY,paint);
}}
I'm looking for any ideas. Did I attempt this the wrong way?
How can I make the trail invisible?
I'm grateful for any help. Thank you.
In order to eliminate the trail, you need to throw away the old canvas (to be more precise the old bitmap) and create a new one.
In your example i would suggest:
#Override
public void run(){
Canvas canvas;
while (running){
canvas = null;
try {
canvas = this.surfaceHolder.lockCanvas();
synchronized (surfaceHolder){
this.gamePanel.update();
canvas = gameLine.drawTheLine();
}
}finally {
if(canvas != null){
surfaceHolder.unlockCanvasAndPost(canvas);
}
}
}
}
and
public Canvas drawTheLine(){
Canvas canvas = new Canvas();
canvas.drawLine(startX, startY,stopX, stopY,paint);
return canvas;
}

Drawing shapes one after another on Android's Canvas

Sorry if this question was asked before but I looked around and couldn't really find an answer.
So I'm drawing things onto a SurfaceView using a thread to update any changes made to the screen, and I also have an array of rectangles. How can I draw the rectangles, one after another, and by the end of it, have all of them on the screen? I thought a for loop in the run() method where everything's drawn would've worked, but it just ends up drawing them all at once (which I can understand why). Then, I tried to put a Thread.sleep after every draw in the for loop, but it just waits until after all the rects are drawn before drawing to the canvas. (again, makes sense since the canvas isn't unlocked until after the for loop). If I wanted, say, a two second pause between drawing rects, how could I do that?
Thanks
Edit: Here is the SurfaceView. the pause() and resume() methods are called in the onPause and onResume methods of the activity for which it is the view.
class TestView extends SurfaceView implements Runnable{
SurfaceHolder holder;
Thread t;
Rect[] rectArray;
public TestView(Context context) {
super(context);
holder = getHolder();
rectArray = shapes.getRectArray();
}
#Override
public void run() {
while(true){
if(!holder.getSurface().isValid())
continue;
Paint p = new Paint();
p.setColor(Color.BLACK);
p.setStrokeWidth(10)
Canvas c = holder.lockCanvas(null);
c.drawARGB(255, 255, 255, 255);
for(int i = 0; i<rectArray.length; i++){
c.drawRect(i,p);
}
holder.unlockCanvasAndPost(c);
}
}
public void pause(){
}
public void resume(){
t = new Thread(this);
t.start();
}
}
I'd probably abstract the thread and SurfaceView and do a basic "game loop" so I have full control over what gets drawn when.
Below is the game loop part:
public class GameLoopThread extends Thread
{
private TestView view;
private boolean running = false;
public GameLoopThread(TestView view)
{
this.view = view;
}
public void setRunning(boolean run)
{
running = run;
}
#SuppressLint("WrongCall")
#Override
public void run()
{
long startTime = System.currentTimeMillis();
while (running)
{
Canvas c = null;
//call update with the number of milliseconds that have passed since the last loop iteration
view.update(System.currentTimeMillis() - startTime);
startTime = System.currentTimeMillis();
try
{
c = view.getHolder().lockCanvas();
synchronized (view.getHolder())
{
//call onDraw so my surface draws the rectangles
view.onDraw(c);
}
}
finally
{
if (c != null)
{
view.getHolder().unlockCanvasAndPost(c);
}
}
}
}
}
Here is my new surface view:
public class TestView extends SurfaceView
{
private long totalElapsedTime = 0;
private Rect[] rectArray;
private int rectCount = 0;
private Paint p;
private GameLoopThread gameLoopThread;
public TestView(Context context)
{
super(context);
rectArray = shapes.getRectArray();
p = new Paint();
p.setColor(Color.BLACK);
p.setStrokeWidth(10)
gameLoopThread = new GameLoopThread(this);
holder = getHolder();
holder.addCallback(new SurfaceHolder.Callback()
{
#Override
public void surfaceDestroyed(SurfaceHolder holder)
{
boolean retry = true;
gameLoopThread.setRunning(false);
while (retry)
{
try
{
gameLoopThread.join();
retry = false;
}
catch (InterruptedException e)
{
}
}
}
#Override
public void surfaceCreated(SurfaceHolder holder)
{
gameLoopThread.setRunning(true);
gameLoopThread.start();
}
#Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height)
{
}
}
public void update(long elapsedTime)
{
totalElapsedTime += elapsedTime;
//increase the rectCount every second
rectCount = totalElapsedTime / 1000;
if(rectCount > rectArray.length)
{
rectCount = rectArray.length;
}
}
#Override
public void onDraw(Canvas canvas)
{
canvas.drawARGB(255, 255, 255, 255);
//draw my rectangles here
for(int i = 0; i < rectCount; i++)
{
canvas.drawRect(i,p);
}
}

Why can't I multiply an object?

I'm working with Android (Java), and what I want is to take a class, and make 3 instances out of it, but with some variables set to random.
public class MainActivity extends Activity{
Player ourView;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ourView = new Player(this);
setContentView(ourView);
}
protected void onPause() {
super.onPause();
ourView.pause();
}
protected void onResume() {
super.onResume();
ourView.resume();
}
}
The other class...
public class Player extends SurfaceView implements Runnable {
Canvas canvas = new Canvas();
SurfaceHolder ourHolder;
Thread ourThread = null;
boolean isRunning = true;
public Player(Context context) {
super(context);
ourHolder = getHolder();
ourThread = new Thread(this);
ourThread.start();
}
public void pause() {
isRunning = false;
while(true){
try{
ourThread.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
break;
}
ourThread = null;
}
public void resume() {
isRunning = true;
}
public void run() {
while(isRunning) {
if(!ourHolder.getSurface().isValid())
continue;
canvas = ourHolder.lockCanvas();
canvas.drawRGB(30, 30, 200);
Enemy[] enemy = new Enemy[3];
for(int i = 0; i<enemy.length; i++){
enemy[i] = new Enemy();
enemy[i].draw();
}
ourHolder.unlockCanvasAndPost(canvas);
}
}
}
And the "Enemy" class:
public class Enemy{
Canvas canvas = new Canvas();
float x = (float) (Math.random()*200);
float y = (float) (Math.random()*200);
public void draw(){
Bitmap bitmap = (Bitmap) BitmapFactory.decodeResource(getContext(), R.drawable.ic_launcher);
canvas.drawBitmap(bitmap, x, y, null);
}
}
I can see that there are 3 bitmaps created, which is cool. But they don't stay still, it's like if the for loop never stops even though the condition is no longer satisfied.
I've asked the question before but I couldn't find any answer. Hope you can help me, thanks.
You are creating a new array of 3 enemies every cycle of the while loop, once the while loop completes execution, the enemy array will leave the scope and be destroyed and a new array will be created. If you want to keep these enemies you will need to store them outside of the scope of the loop.
** EDIT ** - Try this
public class Player extends SurfaceView implements Runnable {
Canvas canvas = new Canvas();
SurfaceHolder ourHolder;
Thread ourThread = null;
boolean isRunning = true;
Enemy[] enemy;
public Player(Context context) {
super(context);
ourHolder = getHolder();
ourThread = new Thread(this);
ourThread.start();
enemy = new Enemy[3];
for(int i = 0; i<enemy.length; i++){
enemy[i] = new Enemy();
}
}
public void pause() {
isRunning = false;
while(true){
try{
ourThread.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
break;
}
ourThread = null;
}
public void resume() {
isRunning = true;
}
public void run() {
while(isRunning) {
if(!ourHolder.getSurface().isValid())
continue;
canvas = ourHolder.lockCanvas();
canvas.drawRGB(30, 30, 200);
for(int i = 0; i<enemy.length; i++){
enemy[i].draw();
}
ourHolder.unlockCanvasAndPost(canvas);
}
}
}
exactly as you said, it is like if the for loop never stops.
because that for loop is in while(isrunning) loop that never stops and triggers your for loop over and over.
you need to reorganize your code.

Categories