Se afișează postările cu eticheta import java animation. Afișați toate postările
Se afișează postările cu eticheta import java animation. Afișați toate postările

Java2 Moving sprites

In this part of the Java 2D games tutorial we will work with sprites.

The term sprite has several meanings. It is used to denote an image or an animation in a scene. It is also used to represent any movable object in a game. Also one of the meanings is the code that encapsulates a character in a game. In our tutorial by using sprite we refer to a movable object or its java class.

R-Type
In the first example we will have a spacecraft. We can move the spacecraft on the board using the cursor keys.

Craft.java
package rtype;

import java.awt.Image;
import java.awt.event.KeyEvent;

import javax.swing.ImageIcon;

public class Craft {

private String craft = "craft.png";

private int dx;
private int dy;
private int x;
private int y;
private Image image;

public Craft() {
ImageIcon ii = new ImageIcon(this.getClass().getResource(craft));
image = ii.getImage();
x = 40;
y = 60;
}


public void move() {
x += dx;
y += dy;
}

public int getX() {
return x;
}

public int getY() {
return y;
}

public Image getImage() {
return image;
}

public void keyPressed(KeyEvent e) {

int key = e.getKeyCode();

if (key == KeyEvent.VK_LEFT) {
dx = -1;
}

if (key == KeyEvent.VK_RIGHT) {
dx = 1;
}

if (key == KeyEvent.VK_UP) {
dy = -1;
}

if (key == KeyEvent.VK_DOWN) {
dy = 1;
}
}

public void keyReleased(KeyEvent e) {
int key = e.getKeyCode();

if (key == KeyEvent.VK_LEFT) {
dx = 0;
}

if (key == KeyEvent.VK_RIGHT) {
dx = 0;
}

if (key == KeyEvent.VK_UP) {
dy = 0;
}

if (key == KeyEvent.VK_DOWN) {
dy = 0;
}
}
}

This class represents a spacecraft. In this class we keep the image of the sprite and the coordinates of the sprite. The keyPressed() and keyReleased() methods control whether the sprite is moving or is in stanstill.

public void move() {
x += dx;
y += dy;
}

The move() method changes the coordinates of the sprite. These x, y values are used in the paint() method to draw the image of the sprite.

if (key == KeyEvent.VK_LEFT) {
dx = 0;
}

When we release the left cursor key, we set the dx variable to zero. The spacecraft will stop moving.

Board.java
package rtype;

import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;

import javax.swing.JPanel;
import javax.swing.Timer;


public class Board extends JPanel implements ActionListener {

private Timer timer;
private Craft craft;

public Board() {

addKeyListener(new TAdapter());
setFocusable(true);
setBackground(Color.BLACK);
setDoubleBuffered(true);

craft = new Craft();

timer = new Timer(5, this);
timer.start();
}


public void paint(Graphics g) {
super.paint(g);

Graphics2D g2d = (Graphics2D)g;
g2d.drawImage(craft.getImage(), craft.getX(), craft.getY(), this);

Toolkit.getDefaultToolkit().sync();
g.dispose();
}


public void actionPerformed(ActionEvent e) {
craft.move();
repaint();
}


private class TAdapter extends KeyAdapter {

public void keyReleased(KeyEvent e) {
craft.keyReleased(e);
}

public void keyPressed(KeyEvent e) {
craft.keyPressed(e);
}
}

}

This is the Board class.

g2d.drawImage(craft.getImage(), craft.getX(), craft.getY(), this);

In the paint() method, we draw the spacecraft. We get the image and the coordinates from the sprite class.

public void actionPerformed(ActionEvent e) {
craft.move();
repaint();
}

The actionPerformed() method is called every 5ms. We move the sprite and repaint the board.

RType.java
package rtype;

import javax.swing.JFrame;

public class RType extends JFrame {

public RType() {

add(new Board());

setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setSize(400, 300);
setLocationRelativeTo(null);
setTitle("R - Type");
setResizable(false);
setVisible(true);
}

public static void main(String[] args) {
new RType();
}
}

This is the main class.



Figure: R-Type
Shooting missiles
In the next example we will add another sprite type to our example. A missile. We can launch missiles with the space key.

Missile.java
package rtype;

import java.awt.Image;

import javax.swing.ImageIcon;

public class Missile {

private int x, y;
private Image image;
boolean visible;

private final int BOARD_WIDTH = 390;
private final int MISSILE_SPEED = 2;

public Missile(int x, int y) {

ImageIcon ii =
new ImageIcon(this.getClass().getResource("missile.png"));
image = ii.getImage();
visible = true;
this.x = x;
this.y = y;
}


public Image getImage() {
return image;
}

public int getX() {
return x;
}

public int getY() {
return y;
}

public boolean isVisible() {
return visible;
}

public void move() {
x += MISSILE_SPEED;
if (x > BOARD_WIDTH)
visible = false;
}
}

Here we have a new sprite called Missile.

public void move() {
x += MISSILE_SPEED;
if (x > BOARD_WIDTH)
visible = false;
}

The missile moves at constant speed. When it hits the right border of the Board, it becomes invisible. It is then removed from the ArrayList of missiles.

Craft.java
package rtype;

import java.awt.Image;
import java.awt.event.KeyEvent;

import java.util.ArrayList;

import javax.swing.ImageIcon;

public class Craft {

private String craft = "craft.png";

private int dx;
private int dy;
private int x;
private int y;
private Image image;

private ArrayList missiles;

private final int CRAFT_SIZE = 20;

public Craft() {
ImageIcon ii = new ImageIcon(this.getClass().getResource(craft));
image = ii.getImage();
missiles = new ArrayList();
x = 40;
y = 60;
}


public void move() {
x += dx;
y += dy;
}

public int getX() {
return x;
}

public int getY() {
return y;
}

public Image getImage() {
return image;
}

public ArrayList getMissiles() {
return missiles;
}

public void keyPressed(KeyEvent e) {

int key = e.getKeyCode();

if (key == KeyEvent.VK_SPACE) {
fire();
}

if (key == KeyEvent.VK_LEFT) {
dx = -1;
}

if (key == KeyEvent.VK_RIGHT) {
dx = 1;
}

if (key == KeyEvent.VK_UP) {
dy = -1;
}

if (key == KeyEvent.VK_DOWN) {
dy = 1;
}
}

public void fire() {
missiles.add(new Missile(x + CRAFT_SIZE, y + CRAFT_SIZE/2));
}

public void keyReleased(KeyEvent e) {
int key = e.getKeyCode();

if (key == KeyEvent.VK_LEFT) {
dx = 0;
}

if (key == KeyEvent.VK_RIGHT) {
dx = 0;
}

if (key == KeyEvent.VK_UP) {
dy = 0;
}

if (key == KeyEvent.VK_DOWN) {
dy = 0;
}
}
}

The Craft.java has changed a bit.

if (key == KeyEvent.VK_SPACE) {
fire();
}

If we press the space key, we fire.

public void fire() {
missiles.add(new Missile(x + CRAFT_SIZE, y + CRAFT_SIZE/2));
}

The fire() method creates a new Missile object and adds it to the missiles ArrayList.

public ArrayList getMissiles() {
return missiles;
}

The getMissiles() method returns the ArrayList of missiles. It is called from the Board class.

Board.java
package rtype;

import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;

import java.util.ArrayList;

import javax.swing.JPanel;
import javax.swing.Timer;


public class Board extends JPanel implements ActionListener {

private Timer timer;
private Craft craft;

public Board() {

addKeyListener(new TAdapter());
setFocusable(true);
setBackground(Color.BLACK);
setDoubleBuffered(true);

craft = new Craft();

timer = new Timer(5, this);
timer.start();
}


public void paint(Graphics g) {
super.paint(g);

Graphics2D g2d = (Graphics2D)g;
g2d.drawImage(craft.getImage(), craft.getX(), craft.getY(), this);

ArrayList ms = craft.getMissiles();

for (int i = 0; i < ms.size(); i++ ) {
Missile m = (Missile) ms.get(i);
g2d.drawImage(m.getImage(), m.getX(), m.getY(), this);
}

Toolkit.getDefaultToolkit().sync();
g.dispose();
}


public void actionPerformed(ActionEvent e) {
ArrayList ms = craft.getMissiles();

for (int i = 0; i < ms.size(); i++) {
Missile m = (Missile) ms.get(i);
if (m.isVisible())
m.move();
else ms.remove(i);
}

craft.move();
repaint();
}


private class TAdapter extends KeyAdapter {

public void keyReleased(KeyEvent e) {
craft.keyReleased(e);
}

public void keyPressed(KeyEvent e) {
craft.keyPressed(e);
}
}
}

This is the Board.java file.

ArrayList ms = craft.getMissiles();

for (int i = 0; i < ms.size(); i++ ) {
Missile m = (Missile) ms.get(i);
g2d.drawImage(m.getImage(), m.getX(), m.getY(), this);
}

In the paint() method we draw all missiles from the array list.

ArrayList ms = craft.getMissiles();
for (int i = 0; i < ms.size(); i++) {
Missile m = (Missile) ms.get(i);
if (m.isVisible())
m.move();
else ms.remove(i);
}

In the actionPerformed() method we parse all missiles from the array list. Depending on the visible flag, we move the missile or remove it from the container.

RType.java
package rtype;

import javax.swing.JFrame;

public class RType extends JFrame {

public RType() {

add(new Board());

setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setSize(400, 300);
setLocationRelativeTo(null);
setTitle("R - Type");
setResizable(false);
setVisible(true);
}

public static void main(String[] args) {
new RType();
}
}

Finally, this is the main class.



Figure: Shooting missiles

Basics java2 tutorial

In this part of the Java 2D games tutorial, we will write about some basics needed to create games. We will create a skeleton of a game. Paint a donut and display a picture.

About
This is Java 2D games tutorial. It is aimed at beginners. This tutorial will teach you basics of programming 2D games in Java programming language and Swing GUI toolkit. All images used in this tutorial can be downloaded here.

Skeleton
We will show the skeleton of each of our Java 2D games.

Board.java
package skeleton;

import javax.swing.JPanel;

public class Board extends JPanel {
public Board() {
}
}

The Board is a panel, where the game takes place.

Skeleton.java
package skeleton;

import javax.swing.JFrame;

public class Skeleton extends JFrame {

public Skeleton() {
add(new Board());
setTitle("Skeleton");
setDefaultCloseOperation(EXIT_ON_CLOSE);
setSize(300, 280);
setLocationRelativeTo(null);
setVisible(true);
setResizable(false);
}
public static void main(String[] args) {
new Skeleton();
}
}

This is the entry point of the game. Here we have the main method.

add(new Board());

Here we put the Board to the center of the JFrame component.

setDefaultCloseOperation(EXIT_ON_CLOSE);

This will close the application when we click on the close button. The window is not closable by default.

setSize(300, 280);

This line sets the size for our window.

setLocationRelativeTo(null);

We center the window.

setVisible(true);

Show the window on the screen.

setResizable(false);

Make the window unresizable.



Figure: Skeleton
Donut
The objects on the Board are either images or are drawn with the painting tools provided by the Java 2D API. In the next example, we draw a Donut. We use the painting API.

Board.java
package donut;

import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.geom.AffineTransform;
import java.awt.geom.Ellipse2D;

import javax.swing.JPanel;


public class Board extends JPanel{

public void paint(Graphics g)
{
super.paint(g);

Graphics2D g2 = (Graphics2D) g;

RenderingHints rh =
new RenderingHints(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);

rh.put(RenderingHints.KEY_RENDERING,
RenderingHints.VALUE_RENDER_QUALITY);

g2.setRenderingHints(rh);

Dimension size = getSize();
double w = size.getWidth();
double h = size.getHeight();

Ellipse2D e = new Ellipse2D.Double(0, 0, 80, 130);
g2.setStroke(new BasicStroke(1));
g2.setColor(Color.gray);


for (double deg = 0; deg < 360; deg += 5) {
AffineTransform at =
AffineTransform.getTranslateInstance(w / 2, h / 2);
at.rotate(Math.toRadians(deg));
g2.draw(at.createTransformedShape(e));
}
}
}

The painting is done inside the paint() method.

Graphics2D g2 = (Graphics2D) g;

The Graphics2D object provides a sophisticated control over painting.

RenderingHints rh =
new RenderingHints(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
rh.put(RenderingHints.KEY_RENDERING,
RenderingHints.VALUE_RENDER_QUALITY);
g2.setRenderingHints(rh);

The rendering hints are used to make the drawing smooth.

Dimension size = getSize();
double w = size.getWidth();
double h = size.getHeight();

We get the height and the width of the window.

Ellipse2D e = new Ellipse2D.Double(0, 0, 80, 130);
g2.setStroke(new BasicStroke(1));
g2.setColor(Color.gray);

Here we create the ellipse.

for (double deg = 0; deg < 360; deg += 5) {
AffineTransform at =
AffineTransform.getTranslateInstance(w / 2, h / 2);
at.rotate(Math.toRadians(deg));
g2.draw(at.createTransformedShape(e));
}

Here the ellispse is rotated 72 times to create a "donut".

Donut.java
package donut;

import javax.swing.JFrame;


public class Donut extends JFrame {


public Donut() {

add(new Board());

setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setSize(360, 310);
setLocationRelativeTo(null);
setTitle("Donut");
setVisible(true);
}

public static void main(String[] args) {
new Donut();
}
}

This is the main class.



Figure: Donut
Image
When we create computer games, we often work with images. In the next example we load an image and display it on the Board. Here you can download the picture used in the example.

Board.java
package bardejov;

import java.awt.Graphics;
import java.awt.Graphics2D;

import java.awt.Image;

import javax.swing.ImageIcon;
import javax.swing.JPanel;

public class Board extends JPanel {

Image bardejov;

public Board() {
ImageIcon ii = new ImageIcon(this.getClass().getResource("bardejov.jpg"));
bardejov = ii.getImage();
}

public void paint(Graphics g) {

Graphics2D g2d = (Graphics2D) g;
g2d.drawImage(bardejov, 10, 10, null);
}
}

We display an image of a town on the Board. The image is drawn inside the paint() method.

ImageIcon ii = new ImageIcon(this.getClass().getResource("bardejov.jpg"));

We create an ImageIcon.

bardejov = ii.getImage();

We get an Image out of the ImageIcon.

g2d.drawImage(bardejov, 10, 10, null);

We draw the image on the window.

Image.java
package bardejov;

import javax.swing.JFrame;


public class Image extends JFrame {

public Image() {

add(new Board());

setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setSize(280, 240);
setLocationRelativeTo(null);
setTitle("Bardejov");
setVisible(true);
}

public static void main(String[] args) {
new Image();
}
}

This is the main class of the example.



Figure: Image

Animation

In this part of the Java 2D games tutorial, we will work with animation.

Animation is a rapid display of sequence of images which creates an illusion of movement. We will animate a star on our Board. We will implement the movement in three basic ways. We will use a Swing timer, a standard utility timer and a thread.

Swing timer
In the first example we will use a Swing timer to create animation. This is the easiest but also the least effective way of animating objects in Java games.

Star.java
package star;

import javax.swing.JFrame;

public class Star extends JFrame {

public Star() {

add(new Board());

setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setSize(280, 240);
setLocationRelativeTo(null);
setTitle("Star");
setResizable(false);
setVisible(true);

}

public static void main(String[] args) {
new Star();
}
}

This is the main class for the code example.

Board.java
package star;

import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;

import java.awt.Toolkit;
import java.awt.event.ActionEvent;

import java.awt.event.ActionListener;

import javax.swing.ImageIcon;
import javax.swing.JPanel;
import javax.swing.Timer;

public class Board extends JPanel implements ActionListener {

Image star;
Timer timer;
int x, y;

public Board() {
setBackground(Color.BLACK);

ImageIcon ii =
new ImageIcon(this.getClass().getResource("star.png"));
star = ii.getImage();

setDoubleBuffered(true);

x = y = 10;
timer = new Timer(25, this);
timer.start();
}


public void paint(Graphics g) {
super.paint(g);

Graphics2D g2d = (Graphics2D)g;
g2d.drawImage(star, x, y, this);
Toolkit.getDefaultToolkit().sync();
g.dispose();
}


public void actionPerformed(ActionEvent e) {

x += 1;
y += 1;

if (y > 240) {
y = -45;
x = -45;
}
repaint();
}
}

setDoubleBuffered(true);

Our JPanel component will use a buffer to paint. This means that all drawing will be done in memory first. Later the offscreen buffer will be copied to the screen. In this example, I didn't notice any differences.

timer = new Timer(25, this);
timer.start();

Here we create a Swing Timer class. We start the timer. Every 25 ms the timer will call the actionPerformed() method. In order to use the actionPerformed() method, we must implement the ActionListener interface.

g2d.drawImage(star, x, y, this);

In the paint() method, we draw the star.

Toolkit.getDefaultToolkit().sync();

We must synchronize the painting on Linux systems. Otherwise, the animation would not be smooth.

public void actionPerformed(ActionEvent e) {
x += 1;
y += 1;

if (y > 240) {
y = -45;
x = -45;
}
repaint();
}

In the actionPerformed() method we increase the x, y values. Than we call the repaint() method. This way we regularly repaint the Board thus making the animation.



Figure: Star
Utility timer
This is very similar to the previous way. We use the java.util.Timer instead of the javax.Swing.Timer. For Java Swing games this way should be more accurate.

Star.java
package star2;

import javax.swing.JFrame;

public class Star extends JFrame {

public Star() {

add(new Board());

setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setSize(280, 240);
setLocationRelativeTo(null);
setTitle("Star");
setResizable(false);
setVisible(true);

}

public static void main(String[] args) {
new Star();
}
}

The main class.

Board.java
package star2;

import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.Toolkit;

import java.util.Timer;
import java.util.TimerTask;

import javax.swing.ImageIcon;
import javax.swing.JPanel;


public class Board extends JPanel {

Image star;
Timer timer;
int x, y;

public Board() {
setBackground(Color.BLACK);

ImageIcon ii = new ImageIcon(this.getClass().getResource("star.png"));
star = ii.getImage();

setDoubleBuffered(true);

x = y = 10;
timer = new Timer();
timer.scheduleAtFixedRate(new ScheduleTask(), 100, 10);
}


public void paint(Graphics g) {
super.paint(g);

Graphics2D g2d = (Graphics2D)g;
g2d.drawImage(star, x, y, this);
Toolkit.getDefaultToolkit().sync();
g.dispose();
}


class ScheduleTask extends TimerTask {

public void run() {
x += 1;
y += 1;

if (y > 240) {
y = -45;
x = -45;
}
repaint();
}
}
}

In this example, the timer will regularly call the run() method of the ScheduleTask class.

timer = new Timer();
timer.scheduleAtFixedRate(new ScheduleTask(), 100, 10);

Here we create a timer. And schedule a task at 10 ms interval. There is 100 ms initial delay.

public void run() {
...
}

Each 10 ms the timer will call this run() method.

Thread

Animating objects using a thread is the most effective way of animation


Star.java
package star3;

import javax.swing.JFrame;

public class Star extends JFrame {

public Star() {

add(new Board());

setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setSize(280, 240);
setLocationRelativeTo(null);
setTitle("Star");
setResizable(false);
setVisible(true);
}

public static void main(String[] args) {
new Star();
}
}

This is the main class.

Board.java
package star2;

import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.Toolkit;

import javax.swing.ImageIcon;
import javax.swing.JPanel;


public class Board extends JPanel implements Runnable {

private Image star;
private Thread animator;
private int x, y;

private final int DELAY = 50;


public Board() {
setBackground(Color.BLACK);
setDoubleBuffered(true);

ImageIcon ii = new ImageIcon(this.getClass().getResource("star.png"));
star = ii.getImage();

x = y = 10;
}

public void addNotify() {
super.addNotify();
animator = new Thread(this);
animator.start();
}

public void paint(Graphics g) {
super.paint(g);

Graphics2D g2d = (Graphics2D)g;
g2d.drawImage(star, x, y, this);
Toolkit.getDefaultToolkit().sync();
g.dispose();
}


public void cycle() {

x += 1;
y += 1;

if (y > 240) {
y = -45;
x = -45;
}
}

public void run() {

long beforeTime, timeDiff, sleep;

beforeTime = System.currentTimeMillis();

while (true) {

cycle();
repaint();

timeDiff = System.currentTimeMillis() - beforeTime;
sleep = DELAY - timeDiff;

if (sleep < 0)
sleep = 2;
try {
Thread.sleep(sleep);
} catch (InterruptedException e) {
System.out.println("interrupted");
}

beforeTime = System.currentTimeMillis();
}
}
}

In the previous examples, we executed a task at specific intervals. In this examle, the animation will take place inside a thread. The run() method is called only once. That's why we have a while loop in the method. From this method, we call the cycle() and the repaint() methods.

public void addNotify() {
super.addNotify();
animator = new Thread(this);
animator.start();
}

The addNotify() method is called after our JPanel has been added to the JFrame component. This method is often used for various initialization tasks.

We want our game run smoothly. At constant speed. Therefore we compute the system time.

timeDiff = System.currentTimeMillis() - beforeTime;
sleep = DELAY - timeDiff;

The cycle() and the repaint() methods might take different time at various while cycles. We calculate the time both methods run and substract it from the DELAY constant. This way we want to ensure that each while cycle runs a constant time. In our case, 50ms each cycle.