Java/Android bullet object flow - java

Wonder if anyone could point me in the right direction.
I want to be able to animate an object like a bullet from a static position to any area on the screen.
I have no problem with simple horizontal and vertical movements. I.e. x +/- 1 or y +/- 1.
But when it comes to an object like a bullet could move/animate at any degree I'm not quite sure how to do this by making the animation look smooth. For example at 18, 45, or 33 degree angle an algorithm like y+1, x+1, y+1..... Is not going to make the animation very smooth.
Thanks in advance
P.s maybe there is some documentation out there already?
Update
Thanks to everyone who has replied.
This is the code I have so far based on your comments.
package com.bullet;
//imports go here
public class canvas extends SurfaceView implements OnTouchListener, SurfaceHolder.Callback{
private Bitmap bullet;
private int bulletStartX, bulletStartY;
private int bulletX, bulletY;
private int bulletEndX = -1;
private int bulletEndY = -1;
private int incX = 0;
private int incY = 0;
private SurfaceHolder holder;
private Thread t;
public canvas(Context context) {
super(context);
this.setBackgroundColor(Color.WHITE);
setFocusable(true);
setFocusableInTouchMode(true);
setOnTouchListener(this);
bulletStartX = 0;
bulletStartY = 0;
bulletX = bulletStartX;
bulletY = bulletStartY;
bullet = BitmapFactory.decodeResource(getResources(), R.drawable.bullet);
holder = getHolder();
holder.addCallback(this);
}
public void onDraw(Canvas canvas){
if(bulletEndX != -1 && bulletEndY != -1){
Log.e("here", "drawing bullet");
Log.e("here", "x: " + bulletX + ", y: " + bulletY);
canvas.drawBitmap(bullet, bulletX, bulletY, null);
}
}
public void updateBullet(){
Log.e("here", "inc bullet");
bulletX += incX;
bulletY += incY;
if(bulletX > bulletEndX){
bulletEndX = -1;
}
if(bulletY > bulletEndY){
bulletEndY = -1;
}
}
#Override
public boolean onTouch(View v, MotionEvent event) {
int[] coordinates = {(int) event.getX(), (int) event.getY()};
int motion = event.getAction();
switch(motion){
case MotionEvent.ACTION_DOWN:
break;
case MotionEvent.ACTION_MOVE:
break;
case MotionEvent.ACTION_UP:
bulletX = bulletStartX;
bulletY = bulletStartY;
bulletEndX = (int) event.getX();
bulletEndY = (int) event.getY();
incX = (int) bulletEndX / 50;
incY = (int) bulletEndY / 50;
Log.e("here", "touch up");
break;
}
return true;
}
#Override
public void surfaceChanged(SurfaceHolder holder, int format, int width,
int height) {
// TODO Auto-generated method stub
}
#Override
public void surfaceCreated(SurfaceHolder holder) {
t = new GameThread(this, holder);
t.start();
}
#Override
public void surfaceDestroyed(SurfaceHolder holder) {
// TODO Auto-generated method stub
}
//Thread class
class GameThread extends Thread{
private canvas canvas;
private SurfaceHolder holder;
private boolean run = false;
long delay = 70;
public GameThread(canvas canvas, SurfaceHolder holder){
this.holder = holder;
this.canvas = canvas;
startThread(true);
}
public boolean isRunning(){
return this.run;
}
private void startThread(boolean run){
this.run = run;
}
public void stopThread(){
this.run = false;
}
#Override
public void run(){
while(run){
Canvas c = null;
try {
//lock canvas so nothing else can use it
c = holder.lockCanvas(null);
synchronized (holder) {
//clear the screen with the black painter.
//This is where we draw the game engine.
//Log.e("drawthread", "running");
if(bulletEndX != -1 && bulletEndY != -1){
updateBullet();
canvas.postInvalidate();
}
canvas.onDraw(c);
//Log.e("drawthread", "ran");
try {
sleep(32);
//Log.e("slept", "sleeping");
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
} finally {
// do this in a finally so that if an exception is thrown
// during the above, we don't leave the Surface in an
// inconsistent state
if (c != null) {
holder.unlockCanvasAndPost(c);
}
}
}
}
}
}
The drawing works pretty well, however there are two problems.
1. the drawing is fairly slow and jumpy... compared to something like this java example http://www.youtube.com/watch?v=-g5CyPQlIo4
2. If the click is on a position to close to Y = 0 then due to the value of ENDY / FRAME being less that 1, means that the round up is to 0 and the bullet travels across the top of the screen, rather than the ocassionaly increment in Y.
#SyntaxT3rr0r your right, that is prob the best way to go about it. But do you know of any documentation for implementing something like this?
Thanks again to everyone who replied

My understanding is that you're asking how to determine how many x&y pixels to move the bullet per frame, as opposed to asking about implementation details specific to animating on Android.
The short answer: Attack it with Math :P
With the example of the bullet:
-You can either chop up the animation as "divide up the animation into 100 frames, play them as fast as we can" or "Play the animation in about 2 seconds, smash as many frames in those 2 seconds as you can." I'm going to explain the former, because that sounds like what you're trying to do.
Start out with a starting X & Y, and an ending X & Y: Let's pretend you want to move from 0,0 to 200,400, and you want to do it in about 100 frames of animation.
Divide up the total distance travelled along the X axis by the number of frames. Do the same with total distance along Y axis. Now you have the distance to travel x & y for each frame. For this example, you want the bullet to move 2 pixels per frame (200 pixels / 100 frames) sideways, and 4 pixels per frame (400 pixels / 100 frames) vertically. So every frame, add x +=2, y+=4.

I suggest you to read the following articles:
View Animation and Property Animation

I don't think this can be answered in it's current form. First how are you animating? are you using the graphics API? GL? AndEngine?
If is graphics API I would rotate the canvas the appropriate degree and move the bullet up the y axis.
For GL you can do the same thing.
For and engine, refer to the tutorials.

Related

Add multiple continuously rotated images to the image

hi guys as title,
I want to add multiple images(red fan) that are continuously rotated on an existing image (about 10~40),I have implemented it by using View "onDraw", but the system resource consumption is very serious, the CPU usage is 30%~40%.
Is there any better way? Like using a game framework or surfaceview?
Thanks in advance.
onDraw
#Override
protected void onDraw(Canvas canvas) {
int j=1;
final int viewHeight =610;
for (final Fan fan : mFans) {
j = j+1;
final float fanSize = 8;
// // Save the current canvas state
final int save = canvas.save();
if(XArray.size()>0){
y = (int) YArray.get(j);
x = (int) XArray.get(j);
// Move the canvas to the center of the fan
canvas.translate(x, y);
// Rotate the canvas based on how far the fan has moved
final float progress = (fan.y + fanSize) / viewHeight;
canvas.rotate(360 * progress);
// Prepare the size and alpha of the drawable
final int size = (int) fanSize;
mDrawable.setBounds(-size, -size, size, size);
// Draw the fan to the canvas
mDrawable.draw(canvas);
// Restore the canvas to it's previous position and rotation
canvas.restoreToCount(save);
}}
}
onAttachedToWindow()
#Override
protected void onAttachedToWindow() {
super.onAttachedToWindow();
mTimeAnimator = new TimeAnimator();
mTimeAnimator.setTimeListener(new TimeAnimator.TimeListener() {
#Override
public void onTimeUpdate(TimeAnimator animation, long totalTime, long deltaTime) {
if (!isLaidOut()) {
// Ignore all calls before the view has been measured and laid out.
return;
}
updateState(deltaTime);
invalidate();
}
});
mTimeAnimator.start();
}
/**
* Pause the animation if it's running
*/
public void pause() {
if (mTimeAnimator != null && mTimeAnimator.isRunning()) {
// Store the current play time for later.
mCurrentPlayTime = mTimeAnimator.getCurrentPlayTime();
mTimeAnimator.pause();
}
}
/**
* Resume the animation if not already running
*/
public void resume() {
if (mTimeAnimator != null && mTimeAnimator.isPaused()) {
mTimeAnimator.start();
// Why set the current play time?
// TimeAnimator uses timestamps internally to determine the delta given
// in the TimeListener. When resumed, the next delta received will the whole
// pause duration, which might cause a huge jank in the animation.
// By setting the current play time, it will pick of where it left off.
mTimeAnimator.setCurrentPlayTime(mCurrentPlayTime);
}
}
/**
* Progress the animation by moving the Fans based on the elapsed time
* #param deltaMs time delta since the last frame, in millis
*/
private void updateState(final float deltaMs) {
// Converting to seconds since PX/S constants are easier to understand
new Thread(new Runnable(){
#Override
public void run() {
final float deltaSeconds = deltaMs / 1000f;
final int viewWidth = getWidth();
final int viewHeight = getHeight();
for (final Fan fan : mFans) {
// Move the Fan based on the elapsed time and it's speed
fan.y -= fan.speed * deltaSeconds;
// If the Fan is completely outside of the view bounds after
// updating it's position, recycle it.
final float size = fan.scale * mBaseSize;
// if (fan.y + size < 0) {
// initializeFan(fan, viewWidth, viewHeight);
// }
} // long run job
}
}).start();
}

How can i get my "Enemy" to chase the "goal" - Java

I have been trying to code a half built simple java game i was given to by a friend (I wanted to try learning coding so he gave me this old assignment from his 1st year of programming class).
He told me to try and build a game using the 2 classes he gave me, a main class and a sub class.
So far I have got everything to work as intended except for finding a way to get my enemy class to move towards the goal regardless of its position. I can get it to always move in a fixed direction towards the goal if I set it up perfectly but I want to be able to find the position of the goal regardless and make its way towards it.
The code need to be written in the peformAction method under Enemy.
If anyone would be kind enough to explain how I can go about this, it would be much appropriated, or even if you can just link me to another post that explains how to do what I'm trying to do.
Thank you in advance.
GameManager (main) Class:
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Toolkit;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.image.BufferedImage;
import java.util.Random;
import javax.swing.JFrame;
public class GameManager extends JFrame implements KeyListener {
private int canvasWidth;
private int canvasHeight;
private int borderLeft;
private int borderTop;
private BufferedImage canvas;
private Stage stage;
private Enemy[] enemies;
private Player player;
private Goal goal;
private Graphics gameGraphics;
private Graphics canvasGraphics;
private int numEnemies;
private boolean continueGame;
public static void main(String[] args) {
// During development, you can adjust the values provided in the brackets below
// as needed. However, your code must work with different/valid combinations
// of values.
GameManager managerObj = new GameManager(1920, 1280, 30);
}
public GameManager(int preferredWidth, int preferredHeight, int maxEnemies) {
this.borderLeft = getInsets().left;
this.borderTop = getInsets().top;
Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
if (screenSize.width < preferredWidth)
this.canvasWidth = screenSize.width - getInsets().left - getInsets().right;
else
this.canvasWidth = preferredWidth - getInsets().left - getInsets().right;
if (screenSize.height < preferredHeight)
this.canvasHeight = screenSize.height - getInsets().top - getInsets().bottom;
else
this.canvasHeight = preferredHeight - getInsets().top - getInsets().bottom;
setSize(this.canvasWidth, this.canvasHeight);
setResizable(false);
setDefaultCloseOperation(EXIT_ON_CLOSE);
setVisible(true);
addKeyListener(this);
Random rng = new Random(2);
this.canvas = new BufferedImage(this.canvasWidth, this.canvasHeight, BufferedImage.TYPE_INT_RGB);
// Create a Stage object to hold the background images
this.stage = new Stage();
// Create a Goal object with its initial x and y coordinates
this.goal = new Goal(this.canvasWidth / 2, Math.abs(rng.nextInt()) % this.canvasHeight);
// Create a Player object with its initial x and y coordinates
this.player = new Player(this.canvasWidth - (Math.abs(rng.nextInt()) % (this.canvasWidth / 2)),
(Math.abs(rng.nextInt()) % this.canvasHeight));
// Create the Enemy objects, each with a reference to this (GameManager) object
// and their initial x and y coordinates.
this.numEnemies = maxEnemies;
this.enemies = new Enemy[this.numEnemies];
for (int i = 0; i < this.numEnemies; i++) {
this.enemies[i] = new Enemy(this, Math.abs(rng.nextInt()) % (this.canvasWidth / 4),
Math.abs(rng.nextInt()) % this.canvasHeight);
}
this.gameGraphics = getGraphics();
this.canvasGraphics = this.canvas.getGraphics();
this.continueGame = true;
while (this.continueGame) {
updateCanvas();
}
this.stage.setGameOverBackground();
updateCanvas();
}
public void updateCanvas() {
long start = System.nanoTime();
// If the player is alive, this should move the player in the direction of the
// key that has been pressed
// Note: See keyPressed and keyReleased methods in the GameManager class.
this.player.performAction();
// If the enemy is alive, the enemy must move towards the goal. The goal object
// is obtained
// via the GameManager object that is given at the time of creating an Enemy
// object.
// Note: The amount that the enemy moves by must be much smaller than that of
// the player above
// or else the game becomes too hard to play.
for (int i = 0; i < this.numEnemies; i++) {
this.enemies[i].performAction();
}
if ((Math.abs(this.goal.getX() - this.player.getX()) < (this.goal.getCurrentImage().getWidth() / 2))
&& (Math.abs(this.goal.getY() - this.player.getY()) < (this.goal.getCurrentImage().getWidth() / 2))) {
for (int i = 0; i < this.numEnemies; i++) {
// Sets the image of the enemy to the "dead" image and sets its status to
// indicate dead
this.enemies[i].die();
}
// Sets the image of the enemy to the "dead" image and sets its status to
// indicate dead
this.goal.die();
// Sets the background of the stage to the finished game background.
this.stage.setGameOverBackground();
this.continueGame=false;
}
// If an enemy is close to the goal, the player and goal die
int j=0;
while(j<this.numEnemies) {
if ((Math.abs(this.goal.getX() - this.enemies[j].getX()) < (this.goal.getCurrentImage().getWidth() / 2))
&& (Math.abs(this.goal.getY() - this.enemies[j].getY()) < (this.goal.getCurrentImage().getWidth()/ 2))) {
this.player.die();
this.goal.die();
this.stage.setGameOverBackground();
j=this.numEnemies;
this.continueGame=false;
}
j++;
}
try {
// Draw stage
this.canvasGraphics.drawImage(stage.getCurrentImage(), 0, 0, null);
// Draw player
this.canvasGraphics.drawImage(player.getCurrentImage(),
this.player.getX() - (this.player.getCurrentImage().getWidth() / 2),
this.player.getY() - (this.player.getCurrentImage().getHeight() / 2), null);
// Draw enemies
for (int i = 0; i < this.numEnemies; i++) {
this.canvasGraphics.drawImage(this.enemies[i].getCurrentImage(),
this.enemies[i].getX() - (this.enemies[i].getCurrentImage().getWidth() / 2),
this.enemies[i].getY() - (this.enemies[i].getCurrentImage().getHeight() / 2), null);
}
// Draw goal
this.canvasGraphics.drawImage(this.goal.getCurrentImage(),
this.goal.getX() - (this.goal.getCurrentImage().getWidth() / 2),
this.goal.getY() - (this.goal.getCurrentImage().getHeight() / 2), null);
} catch (Exception e) {
System.err.println(e.getMessage());
}
// Draw everything.
this.gameGraphics.drawImage(this.canvas, this.borderLeft, this.borderTop, this);
long end = System.nanoTime();
this.gameGraphics.drawString("FPS: " + String.format("%2d", (int) (1000000000.0 / (end - start))),
this.borderLeft + 50, this.borderTop + 50);
}
public Goal getGoal() {
return this.goal;
}
public void keyPressed(KeyEvent ke) {
// Below, the setKey method is used to tell the Player object which key is
// currently pressed.
// The Player object must keep track of the pressed key and use it for
// determining the direction
// to move.
if (ke.getKeyCode() == KeyEvent.VK_LEFT)
this.player.setKey('L', true);
if (ke.getKeyCode() == KeyEvent.VK_RIGHT)
this.player.setKey('R', true);
if (ke.getKeyCode() == KeyEvent.VK_UP)
this.player.setKey('U', true);
if (ke.getKeyCode() == KeyEvent.VK_DOWN)
this.player.setKey('D', true);
if (ke.getKeyCode() == KeyEvent.VK_ESCAPE)
this.continueGame = false;
}
#Override
public void keyReleased(KeyEvent ke) {
// Below, the setKey method is used to tell the Player object which key is
// currently released.
// The Player object must keep track of the pressed key and use it for
// determining the direction
// to move.
if (ke.getKeyCode() == KeyEvent.VK_LEFT)
this.player.setKey('L', false);
if (ke.getKeyCode() == KeyEvent.VK_RIGHT)
this.player.setKey('R', false);
if (ke.getKeyCode() == KeyEvent.VK_UP)
this.player.setKey('U', false);
if (ke.getKeyCode() == KeyEvent.VK_DOWN)
this.player.setKey('D', false);
}
#Override
public void keyTyped(KeyEvent ke) {
}
}
My Enemy (sub) Class:
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
public class Enemy {
//variables
private BufferedImage imageRunning;
private BufferedImage imageOver;
private BufferedImage imageCurrent;
int valX = 200;
int valY = 200;
public Enemy (GameManager gameManager, int x, int y) {
try {
this.imageRunning = ImageIO.read(new File("C:/Users/HUS/Desktop/Assigment222/images/enemy-alive.png"));
this.imageOver = ImageIO.read(new File("C:/Users/HUS/Desktop/Assigment222/images/enemy-dead.png"));
} catch (IOException e) {
e.printStackTrace();
}
this.imageCurrent = this.imageRunning;
}
public BufferedImage getCurrentImage() {
return this.imageCurrent;
}
public void performAction() {
valX += 1;
valY += 1;
return;
}
public void die() {
// TODO Auto-generated method stub
this.imageCurrent = this.imageOver;
}
public int getX() {
// TODO Auto-generated method stub
return this.valX;
}
public int getY() {
// TODO Auto-generated method stub
return this.valY;
}
}
My Goal (sub) class:
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
public class Goal {
private BufferedImage imageRunning;
private BufferedImage imageOver;
private BufferedImage imageCurrent;
int posX = 500;
int poxY = 500;
public Goal(int x, int y) {
try {
this.imageRunning = ImageIO.read(new File("C:/Users/HUS/Desktop/Assigment222/images/goal-alive.png"));
this.imageOver = ImageIO.read(new File("C:/Users/HUS/Desktop/Assigment222/images/goal-dead.png"));
} catch (IOException e) {
e.printStackTrace();
}
this.imageCurrent = this.imageRunning;
}
public BufferedImage getCurrentImage() {
return this.imageCurrent;
}
public int getX() {
return this.posX;
}
public int getY() {
return this.poxY;
}
public void die() {
this.imageCurrent = this.imageOver;
}
}
It's impossible with the current code if you want to restrict the modifications only to the performAction method.
1) The Enemy has no way of accessing (seeing) the coordinates of the goal. This means the code can't figure out the way to the goal because it doesn't have the X and Y of where the destination is.
2) To fix that you would need Enemy to be able to see the X and Y of the Goal. The quickest way would be to use getters and setters in the GameManager class to return the stored Goal object. Then you can modify your Enemy constructor to store the reference to the GameManager that created it.
GameManager:
public Goal getGoal() {
return goal;
}
Enemy:
private GameManager gameManager;
public Enemy (GameManager gameManager, int x, int y) {
...
this.gameManager = gameManager;
}
The last step would be getting the Goal object from the stored gameManager, and using its X and Y to do some logic (this would be performed inside the performAction method):
int goalX = gameManager.getGoal().getX();
int goalY = gameManager.getGoal().getY();
...some logic to calculate the direction here...
I'm sure you'll know what to do with the numbers and figure out how to move towards the goal from there.
#Edit
If not - one way would be comparing Xs and Ys of both the Enemy and the Goal and then incrementing/decrementing valX and/or valY accordingly.
A very simple implementation:
public void performAction()
{
valX += Math.signum(gameManager.getGoal().getX() - valX);
valY += Math.signum(gameManager.getGoal().getX() - valX);
}
In your method performAction you are currently changing the x and y position respectively by incrementing them by 1 each time the method gets called.
This will move your enemy exactly 1 unit in direction x and 1 unit in direction y.
You instead want to move your character in the direction of the Goal. That's more of a math problem than a programming issue but let's give it a go:
You have 2 positions:
Your Enemy has a position of form and the same goes for your goal with position
You now want to move your Enemy in the direction of the goal. So you calculate a vector connecting these two points with
You then change the length of the vector to the speed your enemy can move with (maybe define this with a field?) by normalizing the vector and doing a scalar multiplication with your speed.
So with a given speed S this gives you the full formula:
Now let us transform this into code. In the constructor of your Enemy class save the GameManager as a field so you can call the getGoal method on it.
So we add a field private GameManager gameManager and in the Constructor we do this.gameManager = gameManager to store the reference.
Also we adda field private double speed = 2 for our calculation.
And then we change the performAction method to implement our formula. Something like this:
public void performAction()
{
// Calculate our P_g - P_e
double dX = gameManager.getGoal().getX() - valX;
double dY = gameManager.getGoal().getX() - valX;
// Calculate its length to normalize it
double divider = Math.sqrt(dX * dX + dY * dY);
// Normalize it
dX /= divider;
dY /= divider;
// Do a scalar multiplication with our speed
dX *= speed;
dY *= speed;
valX += dX;
valY += dY;
}
The only problem we are running into here is that we are adding double values to our integer values valX and valY so probably change those to double values generally or else you might run into problems where your enemy will never move at all.

Shape increases in size instead of moving - Java (GUI applet)

I am trying to change the y position of the rectangle, however, whenever I try to, it expands/gets bigger vertically.
public class PlayerPaddle implements Paddle {
double yVelocity;
final double GRAVITY = 0.94;
//move up/down faster (if not accelerating = slow down)
boolean upAccel, downAccel;
//determines if player 1 or player 2 (on left or on right)
int player;
//position of actual paddle
int x;
double y;
Rectangle panel;
public PlayerPaddle(int player) {
upAccel = false;
downAccel = false;
y = 210; //not moving initially
yVelocity = 0;
if (player == 1) {
//left side
x = 20;
} else {
//right side
x = 660;
}
}
#Override
public void draw(Graphics g) {
//draw paddle
g.setColor(Color.WHITE);
g.fillRect(x, (int) y, 20, 80);
}
#Override
public void move() {
if (upAccel) {
yVelocity -= 2;
} else if (downAccel) {
yVelocity += 2;
} else if ((!upAccel) && (!downAccel)) {
yVelocity *= GRAVITY;
}
y += yVelocity; //changes y position of paddle
}
public void setUpAccel(boolean input) {
upAccel = input;
}
public void setDownAccel(boolean input) {
downAccel = input;
}
#Override
public int getY() {
return (int) y;
}
}
I want to know how to make the rectangle move up and down vertically. A similar question had only one answer which said that the previously painted rectangle was not being cleared and as a result is expanding. But even when I say g.clearRect(...) it still expands and does not move.
I am new to Swing and Awt but I am really committed to learning. Thanks for the help.
A similar question had only one answer which said that the previously painted rectangle was not being cleared and as a result is expanding
And that is still probably the problem here.
Somewhere, not in the code presented here, you need to invoke the draw(...) method of this class.
So in that code you need to make sure the background of the component is cleared before you draw the paddle. Since you should be overriding the paintComponent(...) method of a panel to do custom painting your code should look something like:
#Override
protected void paintComponent(Graphics g)
{
super.paintComponent(g);
// draw the paddle
}
Read the section from the Swing tutorial on Custom Painting for more information and working examples.
I am new to Swing and Awt but I am really committed to learning.
Then keep a link to the tutorial handy for all Swing basics.

Java swing animation

I'm trying to make a flip effect with java swing, but my flip method doesn't look like a real flip.In my method I change the width with the x var and the xspeed, making the image smaller and then check if the x is >= as half of my image. hope somebody could help me improve it thanks in advance.
Animation Class
public class Animation extends JPanel implements MouseListener {
private static final long serialVersionUID = 3264508834913061718L;
public Timer timer;
public int x = 0;
public int xspeed = 2;
public boolean turning = true;
public String pic = "/images/image.jpg";
public URL url = this.getClass().getResource(pic);
public ImageIcon im = new ImageIcon(url);
public String rev = "/images/image2.jpg";
public URL url2 = this.getClass().getResource(rev);
public ImageIcon reverse = new ImageIcon(url2);
public Animation(){
this.setPreferredSize(new Dimension(128,128));
this.setBackground(Color.BLACK);
this.setFocusable(true);
this.addMouseListener(this);
}
public void paintComponent(Graphics g){
super.paintComponent(g);
g.drawImage(im.getImage(), 0 , 0, im.getIconWidth() - x, im.getIconHeight(), null);
}
public void flipAnimation(){
ActionListener actionListener = new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
// TODO Auto-generated method stub
//
if (turning) {
x = x + xspeed;
}
repaint();
// x in the middle paint new image & set turning to false to stop animation
if(x >= im.getIconWidth()/2){
turning = false;
x = 0;
im = reverse;
}
}
};
if (turning) {
if (timer != null)timer.stop();
timer = new Timer(30, actionListener);
timer.start();
}
}
#Override
public void mouseClicked(MouseEvent e) {
// TODO Auto-generated method stub
e.getSource();
flipAnimation();
}
First, I’m guessing you want your image to “fold in” from both sides, so you’ll want to increase the image’s left edge along with its right edge:
g.drawImage(im.getImage(), x / 2 , 0, im.getIconWidth() - x, im.getIconHeight(), this);
Notice the first int argument has been changed from 0 to x / 2. Also, it is good practice to pass this as the ImageObserver argument when drawing images in a paintComponent method, since the component itself is the object which is interested in repainting itself when the image has finished loading in the background.
Second, change this:
if (turning) {
x = x + xspeed;
}
to this:
x = x + xspeed;
You don’t need a flag to control the animation. (The correct way to stop the animation is to call timer.stop(), which I’ll get to in a moment.)
Third, change this:
if(x >= im.getIconWidth()/2){
turning = false;
x = 0;
to this:
if(x >= im.getIconWidth()){
xspeed = -xspeed;
As I said, the turning flag is not needed.
The reason for comparing x to the image’s width, instead of half of the width, is that we want to change the image only when the first image has completely “folded in.”
The negation of xspeed reverses the animation.
Finally, at the end of your actionPerformed method, you’ll want to add this:
if (x <= 0) {
timer.stop();
}
This halts the animation when the reverse image reaches its full size, which is why the turning flag is not needed.

How-to and Understanding of drag and zoom event with GLSurfaceView

I had everything working with this test app I made that displays a 3D object using the standard vertex, color, and point buffer.
I can..
rotate the object with touch events
render object with openGL ES 1.0 using GL10
everything works great
Now I want to be able to zoom in and out using two fingers for a "pinch" motion. I found some good tutorials and sample code, but it is mostly for ImageViews. I am still semi-new to Android and I do not fully understand how to make this zoom function work for GLSurfaceView.
Below is the code I have so far for the Activity class. The first touch handler is for the zoom event I found through a Tutorial designed for ImageView(I used this because I thought it would be an easy conversion). The second handler is for the rotation event, which works just fine.
Thank you ahead of time and I hope this post will help others with the same issue.
I will be standing by for any edits or additions needed.
// Activity for rendering 3D object openGL ES 1.0
public class GL_ExampleActivity extends Activity
{
private GLSurfaceView surface;
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
surface = new GL_ExampleSurfaceView(this);
setContentView(surface);
}
#Override
protected void onPause()
{
// TODO Auto-generated method stub
super.onPause();
surface.onPause();
}
#Override
protected void onResume()
{
// TODO Auto-generated method stub
super.onResume();
surface.onResume();
}
}
class GL_ExampleSurfaceView extends GLSurfaceView
{
private static final String TAG = "Touch";
Matrix matrix_new = new Matrix();
Matrix last_matrix = new Matrix();
static final int NONE = 0;
static final int DRAG = 1;
static final int ZOOM = 2;
int mode = NONE;
PointF start = new PointF();
PointF mid = new PointF();
float oldDist = 1f;
private final float SCALE_FACTOR = 180.0f / 320;
private GLRenderer renderer;
private float previous_x;
private float previous_y;
public GL_ExampleSurfaceView(Context context)
{
super(context);
renderer = new GLRenderer();
setRenderer(renderer);
setRenderMode(GLSurfaceView.RENDERMODE_WHEN_DIRTY);
}
#Override
public boolean onTouchEvent(MotionEvent e)
{
// handler for drag and zoom events
switch (e.getAction() & MotionEvent.ACTION_MASK)
{
case MotionEvent.ACTION_DOWN:
last_matrix.set(matrix_new);
start.set(e.getX(), e.getY());
Log.d(TAG, "mode=DRAG");
mode = DRAG;
//requestRender();
break;
case MotionEvent.ACTION_POINTER_DOWN:
oldDist = finger_distance(e);
Log.d(TAG, "oldDist=" + oldDist);
if (oldDist > 10f)
{
last_matrix.set(matrix_new);
finger_distance_midpoint(mid, e);
mode = ZOOM;
Log.d(TAG, "mode=ZOOM");
}
//requestRender();
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_POINTER_UP:
mode = NONE;
Log.d(TAG, "mode=NONE");
//requestRender();
break;
case MotionEvent.ACTION_MOVE:
if (mode == DRAG)
{
matrix_new.set(last_matrix);
matrix_new.postTranslate(e.getX() - start.x, e.getY() - start.y);
}
else if (mode == ZOOM)
{
float newDist = finger_distance(e);
Log.d(TAG, "newDist=" + newDist);
if (newDist > 10f)
{
matrix_new.set(last_matrix);
float scale = newDist / oldDist;
matrix_new.postScale(scale, scale, mid.x, mid.y);
}
}
//requestRender();
break;
}
//view.setImageMatrix(matrix_new);
// handler for rotation event, y and x axis
float x = e.getX();
float y = e.getY();
switch (e.getAction())
{
case MotionEvent.ACTION_MOVE:
float dx = x - previous_x;
float dy = y - previous_y;
if (y > getHeight() / 2)
{
dx = dx * -1 ;
}
if (x < getWidth() / 2)
{
dy = dy * -1 ;
}
renderer.angle_x += dx * SCALE_FACTOR;
renderer.angle_y += dy * SCALE_FACTOR;
requestRender();
}
previous_x = x;
previous_y = y;
return true;
}
private float finger_distance(MotionEvent e)
{
float x = e.getX(0) - e.getX(1);
float y = e.getY(0) - e.getY(1);
return FloatMath.sqrt(x * x + y * y);
}
private void finger_distance_midpoint(PointF point, MotionEvent e)
{
float x = e.getX(0) + e.getX(1);
float y = e.getY(0) + e.getY(1);
point.set(x / 2, y / 2);
}
}
Thanks again...
There are two obvious ways to approach this. If you just want to increase the size of an individual object, you can use glScalef when drawing the object. Using scalef is easy and relatively straightforward but it isn't exactly what you're asking for.
Another solution is to apply a scaling factor to your projection matrix which will produce the desired effect. To accomplish this, just multiply the left, right, top, and bottom distances of your projection matrix by a scale like so before drawing.
gl.glFrustumf(width/2 * zoom, width/2 * zoom, height/2 * zoom, height/2 * zoom, 1, -1);
(Note, if you're using an orthogonal matrix you will be using glOrthof instead)
If you're interested, you can find more information about the projection matrix here

Categories

Resources