Opencv Image Overlaying to ROI Java - java

I am trying to overlay an image inside the rectangular region after detection of face and eyes. But I am unable to do so. Can you please guide me how to proceed.
I have searched a lot on google and tried Mat copy to src file but no result. Please help me in solving this issue.
public class FXController {
// FXML buttons
#FXML
private Button cameraButton;
// the FXML area for showing the current frame
#FXML
private ImageView originalFrame;
// checkboxes for enabling/disabling a classifier
#FXML
private CheckBox haarClassifier;
#FXML
private CheckBox lbpClassifier;
// a timer for acquiring the video stream
private ScheduledExecutorService timer;
// the OpenCV object that performs the video capture
private VideoCapture capture;
// a flag to change the button behavior
private boolean cameraActive;
// face cascade classifier
private CascadeClassifier faceCascade;
private int absoluteFaceSize;
/**
* Init the controller, at start time
*/
protected void init()
{
this.capture = new VideoCapture();
this.faceCascade = new CascadeClassifier();
this.absoluteFaceSize = 0;
// set a fixed width for the frame
originalFrame.setFitWidth(600);
// preserve image ratio
originalFrame.setPreserveRatio(true);
}
/**
* The action triggered by pushing the button on the GUI
*/
#FXML
protected void startCamera()
{
if (!this.cameraActive)
{
// disable setting checkboxes
this.haarClassifier.setDisable(true);
this.lbpClassifier.setDisable(true);
// start the video capture
this.capture.open(0);
// is the video stream available?
if (this.capture.isOpened())
{
this.cameraActive = true;
// grab a frame every 33 ms (30 frames/sec)
Runnable frameGrabber = new Runnable() {
#Override
public void run()
{
// effectively grab and process a single frame
Mat frame = grabFrame();
// convert and show the frame
Image imageToShow = Utils.mat2Image(frame);
updateImageView(originalFrame, imageToShow);
}
};
this.timer = Executors.newSingleThreadScheduledExecutor();
this.timer.scheduleAtFixedRate(frameGrabber, 0, 33, TimeUnit.MILLISECONDS);
// update the button content
this.cameraButton.setText("Stop Camera");
}
else
{
// log the error
System.err.println("Failed to open the camera connection...");
}
}
else
{
// the camera is not active at this point
this.cameraActive = false;
// update again the button content
this.cameraButton.setText("Start Camera");
// enable classifiers checkboxes
this.haarClassifier.setDisable(false);
this.lbpClassifier.setDisable(false);
// stop the timer
this.stopAcquisition();
}
}
/**
* Get a frame from the opened video stream (if any)
*
* #return the {#link Image} to show
*/
private Mat grabFrame()
{
Mat frame = new Mat();
// check if the capture is open
if (this.capture.isOpened())
{
try
{
// read the current frame
this.capture.read(frame);
// if the frame is not empty, process it
if (!frame.empty())
{
// face detection
this.detectAndDisplay(frame);
}
}
catch (Exception e)
{
// log the (full) error
System.err.println("Exception during the image elaboration: " + e);
}
}
return frame;
}
/**
* Method for face detection and tracking
*
* #param frame
* it looks for faces in this frame
*/
private void detectAndDisplay(Mat frame)
{
MatOfRect faces = new MatOfRect();
//Mat grayFrameSrc = new Mat();
Mat grayFrameDest=Imgcodecs.imread("images/face.png");
// convert the frame in gray scale
//Imgproc.cvtColor(frame, grayFrameSrc, Imgproc.COLOR_BGR2GRAY);
Imgproc.cvtColor(frame, grayFrameDest, Imgproc.COLOR_BGR2GRAY);
// equalize the frame histogram to improve the result
//Imgproc.equalizeHist(grayFrameSrc, grayFrameSrc);
Imgproc.equalizeHist(grayFrameDest, grayFrameDest);
//int height = grayFrameSrc.rows();
//int width = grayFrameSrc.width();
int height = grayFrameDest.rows();
// compute minimum face size (20% of the frame height, in our case)
if (this.absoluteFaceSize == 0)
{
//System.out.println("The height = "+width);
if (Math.round(height * 0.1f) > 0)
{
this.absoluteFaceSize = Math.round(height * 0.1f);
}
}
// detect faces
this.faceCascade.detectMultiScale(grayFrameDest, faces, 1.1, 2, 0 | Objdetect.CASCADE_SCALE_IMAGE,
new Size(this.absoluteFaceSize, this.absoluteFaceSize), new Size());
// each rectangle in faces is a face: draw them!
Rect[] facesArray = faces.toArray();
for (int i = 0; i < facesArray.length; i++){
int x=facesArray[i].x;
int y=facesArray[i].y;
int h=facesArray[i].height;
int w=facesArray[i].width;
Rect rect=facesArray[i];
Imgproc.rectangle(frame, facesArray[i].tl(), facesArray[i].br(), new Scalar(0, 255, 0), 3);
//Imgproc.putText(frame, "Hi Ankit", new Point(x, y), 0, 0, new Scalar(0, 255, 0));
Imgcodecs.imwrite("/home/ankit-mathur/Desktop/mask.png", frame);
Mat temp = new Mat();
Imgproc.cvtColor(grayFrameDest, temp, Imgproc.COLOR_BGRA2GRAY,0);
Mat temp_rgba = new Mat();
Imgproc.cvtColor(temp, temp_rgba, Imgproc.COLOR_GRAY2BGRA,0);
temp_rgba.copyTo(grayFrameDest);
}
}
#FXML
protected void haarSelected(Event event)
{
// check whether the lpb checkbox is selected and deselect it
if (this.lbpClassifier.isSelected())
this.lbpClassifier.setSelected(false);
this.checkboxSelection("resources/haarcascades/haarcascade_frontalface_alt.xml");
}
/**
* The action triggered by selecting the LBP Classifier checkbox. It loads
* the trained set to be used for frontal face detection.
*/
#FXML
protected void lbpSelected(Event event)
{
// check whether the haar checkbox is selected and deselect it
if (this.haarClassifier.isSelected())
this.haarClassifier.setSelected(false);
this.checkboxSelection("resources/lbpcascades/lbpcascade_frontalface.xml");
}
/**
* Method for loading a classifier trained set from disk
*
* #param classifierPath
* the path on disk where a classifier trained set is located
*/
private void checkboxSelection(String classifierPath)
{
// load the classifier(s)
//System.out.println(classifierPath);
if (this.faceCascade.load(classifierPath)) {
this.faceCascade.load(classifierPath);
}
else{
System.out.println("Unable To Load FaceCascade");
}
// now the video capture can start
this.cameraButton.setDisable(false);
}
/**
* Stop the acquisition from the camera and release all the resources
*/
private void stopAcquisition()
{
if (this.timer!=null && !this.timer.isShutdown())
{
try
{
// stop the timer
this.timer.shutdown();
this.timer.awaitTermination(33, TimeUnit.MILLISECONDS);
}
catch (InterruptedException e)
{
// log any exception
System.err.println("Exception in stopping the frame capture, trying to release the camera now... " + e);
}
}
if (this.capture.isOpened())
{
// release the camera
this.capture.release();
}
}
/**
* Update the {#link ImageView} in the JavaFX main thread
*
* #param view
* the {#link ImageView} to update
* #param image
* the {#link Image} to show
*/
private void updateImageView(ImageView view, Image image)
{
Utils.onFXThread(view.imageProperty(), image);
}
/**
* On application close, stop the acquisition from the camera
*/
protected void setClosed()
{
this.stopAcquisition();
}
}

I am working on the same thing on iOS. Here is how I am doing it
Mat image = imread("path/to/image");
//center.x and center.y are the location in the screen
cv::Rect roi( cv::Point( center.x, center.y), image.size() );
//if you want to save it in a Mat
image.copyTo( source( roi ));
//or if you want to write it on a file
imwrite("image.jpg", image);

Related

Running out of ways to add a sound file in java

The trouble I'm having now is that I want to insert a sound within the explosion class, specifically in the run function. I have tried a number of ways to get the .WAV sound file to play but all of them failed.
Explosion:
import javax.swing.ImageIcon;
import javax.swing.JLabel;
public class Explosion implements Runnable {
ColoredBallPanel myPanel;
private JLabel img_label;
private ImageIcon imageIcon; // The explosion GIF
private int x_position; // The x position of the GIF.
private int y_position; // The Y position of the GIF.
private final int img_display_time = 650;
public Explosion(ColoredBallPanel panel, int x, int y) {
super();
myPanel = panel;
x_position = x;
y_position = y;
my_GIF();
}
/**
* Adds the GIF to the panel relative to where the balls have collided.
*/
public void my_GIF() {
imageIcon = new ImageIcon(
"C:\\Users\\Oscar\\Desktop\\Bangor Uni Y2 S1\\ICP-2150-0 Advanced Java Programming 201819\\Lab9\\explo.gif"); // sets
// the
// image
// icon
img_label = new JLabel();
img_label.setBounds(x_position, y_position, 200, 200);// Add image at position x_position, y_position
img_label.setIcon(imageIcon);
myPanel.add(img_label);
}
/**
* runs the thread on completion deletes the image
*/
#Override
public void run() {
try {
Thread.sleep(img_display_time); // Sleeps for a set amount of time.
} catch (InterruptedException e) {
}
img_label.setIcon(null); // Deletes the image.
img_label = null;
}
}
Try this:
Clip clip = AudioSystem.getClip();
AudioInputStream inputStream = AudioSystem.getAudioInputStream(
Explosion.class.getResourceAsStream("/path/to/sounds/" + url));
clip.open(inputStream);
clip.start();
There is a pretty good explanation here: https://stackoverflow.com/tags/javasound/info

How to capture an RTSP livestream via Java?

I know, there are several posts handling with this problem here on Stackoverflow, but I didnĀ“t get a solution for my problem. I have an ipcam and I want to capture the livestream using java. The problem is, that I can only access the cam via RTSP. There is no normal http://xxx.xxx.xxx:xx access.
I use the OpenCv library but unfortunately my program only works with the webcam of my laptop because it is the default device.
protected void init()
{
this.capture = new VideoCapture();
this.faceCascade = new CascadeClassifier();
this.absoluteFaceSize = 0;
}
/**
* The action triggered by pushing the button on the GUI
*/
#FXML
protected void startCamera()
{
// set a fixed width for the frame
originalFrame.setFitWidth(600);
// preserve image ratio
originalFrame.setPreserveRatio(true);
if (!this.cameraActive)
{
// disable setting checkboxes
this.haarClassifier.setDisable(true);
this.lbpClassifier.setDisable(true);
// start the video capture
//String URLName = "rtsp://username:password#rtsp:554/h264/ch1/main/av_stream";
this.capture.open("rtsp://192.168.178.161:554/onvif1");
// is the video stream available?
if (this.capture.isOpened())
{
this.cameraActive = true;
// grab a frame every 33 ms (30 frames/sec)
Runnable frameGrabber = new Runnable() {
#Override
public void run()
{
Image imageToShow = grabFrame();
originalFrame.setImage(imageToShow);
}
};
this.timer = Executors.newSingleThreadScheduledExecutor();
this.timer.scheduleAtFixedRate(frameGrabber, 0, 33, TimeUnit.MILLISECONDS);
// update the button content
this.cameraButton.setText("Stop Camera");
}
else
{
// log the error
System.err.println("Failed to open the camera connection...");
}
}

Libgdx: How can I load assets after screen has already rendered?

I have implemented the loading screen from this example on my Loading Screen that is a child of Game. This is how my asset init method and Screen class looks like. My init method in assets loads classes that contain my AtlasRegion. I have tested that this method is what makes my screen load a black screen as it loads a lot of resources.
public void init (AssetManager assetManager) {
this.assetManager = assetManager;
// set asset manager error handler
assetManager.setErrorListener(this);
assetManager.load(Constants.TEXTURE_ATLAS_OBJECTS, TextureAtlas.class);
assetManager.load(Constants.TEXTURE_ATLAS_UI, TextureAtlas.class);
assetManager.finishLoading();
TextureAtlas atlas = assetManager.get(Constants.TEXTURE_ATLAS_OBJECTS);
TextureAtlas atlasUi = assetManager.get(Constants.TEXTURE_ATLAS_UI);
//font = new BitmapFont(Gdx.files.internal("data/font.fnt"), Gdx.files.internal("data/font.png"), false);
clickSound = Gdx.audio.newSound(Gdx.files.internal("data/sounds/click.wav"));
// create game resource objects
fonts = new AssetFonts(assetManager);
skins = new AssetSkins();
background = new AssetBackgroundImage();
cards = new AssetCards(atlas);
cardimages = new AssetImages(atlas);
cardsjson = new AssetList();
suitimages = new AssetSuitImages(atlas);
}
This is my Loading Screen class:
public class LoadingScreen extends AbstractGameScreen implements Disposable {
private Stage stage;
private Image logo;
private Image loadingFrame;
private Image loadingBarHidden;
private Image screenBg;
private Image loadingBg;
private float startX, endX;
private float percent;
private Actor loadingBar;
public LoadingScreen(CardGame game) {
super(game);
}
public InputProcessor getInputProcessor () {
return (null);
}
#Override
public void show() {
// Tell the manager to load assets for the loading screen
game.manager.load("data/images-ui/loading/loading.pack", TextureAtlas.class);
// Wait until they are finished loading
game.manager.finishLoading();
// Initialize the stage where we will place everything
stage = new Stage();
// Get our textureatlas from the manager
TextureAtlas atlas = game.manager.get("data/images-ui/loading/loading.pack", TextureAtlas.class);
// Grab the regions from the atlas and create some images
logo = new Image(atlas.findRegion("libgdx-logo"));
loadingFrame = new Image(atlas.findRegion("loading-frame"));
loadingBarHidden = new Image(atlas.findRegion("loading-bar-hidden"));
screenBg = new Image(atlas.findRegion("screen-bg"));
loadingBg = new Image(atlas.findRegion("loading-frame-bg"));
// Add the loading bar animation
Animation anim = new Animation(0.05f, atlas.findRegions("loading-bar-anim") );
anim.setPlayMode(Animation.PlayMode.LOOP_REVERSED);
loadingBar = new LoadingBar(anim);
// Or if you only need a static bar, you can do
// loadingBar = new Image(atlas.findRegion("loading-bar1"));
// Add all the actors to the stage
stage.addActor(screenBg);
stage.addActor(loadingBar);
stage.addActor(loadingBg);
stage.addActor(loadingBarHidden);
stage.addActor(loadingFrame);
stage.addActor(logo);
// Add everything to be loaded, for instance:
Assets.instance.init(game.manager);
}
#Override
public void resize(int width, int height) {
// Set our screen to always be XXX x 480 in size
//width = 480 * width / height;
//height = 480;
stage.getViewport().update(width, height, false);
// Make the background fill the screen
screenBg.setSize(width, height);
// Place the logo in the middle of the screen and 100 px up
logo.setX((width - logo.getWidth()) / 2);
logo.setY((height - logo.getHeight()) / 2 + 100);
// Place the loading frame in the middle of the screen
loadingFrame.setX((stage.getWidth() - loadingFrame.getWidth()) / 2);
loadingFrame.setY((stage.getHeight() - loadingFrame.getHeight()) / 2);
// Place the loading bar at the same spot as the frame, adjusted a few px
loadingBar.setX(loadingFrame.getX() + 15);
loadingBar.setY(loadingFrame.getY() + 5);
// Place the image that will hide the bar on top of the bar, adjusted a few px
loadingBarHidden.setX(loadingBar.getX() + 35);
loadingBarHidden.setY(loadingBar.getY() - 3);
// The start position and how far to move the hidden loading bar
startX = loadingBarHidden.getX();
endX = 440;
// The rest of the hidden bar
loadingBg.setSize(450, 50);
loadingBg.setX(loadingBarHidden.getX() + 30);
loadingBg.setY(loadingBarHidden.getY() + 3);
}
#Override
public void render(float delta) {
// Clear the screen
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
if (game.manager.update()) { // Load some, will return true if done loading
if (Gdx.input.isTouched()) { // If the screen is touched after the game is done loading, go to the main menu screen
game.setScreen(new MainMenuScreen(game));
}
}
// Interpolate the percentage to make it more smooth
percent = Interpolation.linear.apply(percent, game.manager.getProgress(), 0.1f);
// Update positions (and size) to match the percentage
loadingBarHidden.setX(startX + endX * percent);
loadingBg.setX(loadingBarHidden.getX() + 30);
loadingBg.setWidth(450 - 450 * percent);
loadingBg.invalidate();
// Show the loading screen
stage.act();
stage.draw();
}
#Override
public void pause () {}
#Override
public void resume () {}
#Override
public void hide() {
// Dispose the loading assets as we no longer need them
game.manager.unload("data/images-ui/loading/loading.pack");
}
}
I need to load the screen then load my assets on this Assets.instance.init(new AssetManager()) since it is what is causing a black screen. The problem is my screen loads after loading the assets hence this makes my loading screen to be of no use. How can I load this method after the screen has rendered?
Remove the finishLoading call from your init method. That should do it. finishLoading forces the assets to finish loading immediately which is not what you want here. Calling update on it repeatedly, which you are already doing is the way to load assets asynchronously.
Here's a general structure for how it could be done. Call all the load methods on the asset manager before it ever gets to the render method. Then call update repeatedly until everything is loaded. Then get references to the assets before continuing.
private boolean loadComplete;
public void show(){
//...
loadComplete = false;
}
private void init(AssetManager assetManager){
this.assetManager = assetManager;
assetManager.load(/*whatever*/);
assetManager.load(/*whatever*/);
assetManager.load(/*whatever*/);
}
private void onAssetsLoaded(){
loadComplete = true;
myAtlas = assetManager.get("myAtlas.json", TextureAtlas.class);
//and so on
}
public void render(float delta){
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
//load one asset at a time per frame until loading is complete
if (assetManager == null || !assetManager.update()){
//maybe draw a load screen image that's not a texture that's being managed
//by the assetManager. You could even play an animation. Otherwise,
//you can leave the screen blank.
return;
}
//will only get here when asset manager is done. The first time, you still
//need to get references to its assets
if (!loadComplete)
onAssetsLoaded();
//the rest of you render method. Everything below here only happens after assets are loaded and asset references have been aquired
}
After trying so many recommended solutions, I finally managed to fix this problem thanks to this blog post
I used a callback which displays an android framelayout with an image as the assets load asynchronously.

How do i cycle through different images, Java

My code is used to draw an image onto the screen by g.draw(img);. Is there a way to make the image cycle through different images instead of being static? I've tried .gif files but they don;t work. Here is my code:
static BufferedImage img = null;
{
try {
img = ImageIO.read(new File("assets/textures/bird.png"));
} catch (IOException e) {
System.out.println(e.getMessage();
}
}
Is there a way to animate the textures?
You can create a small class to do this for you:
public class SimpleImageLoop {
private final BufferedImage[] frames;
private int currentFrame;
public SimpleImageLoop(BufferedImage[] frames) {
this.frames = frames;
this.currentFrame = 0;
}
/**
* Moves the loop to the next frame.
* If we are on the last frame, this loops back to the first
*/
public void nextFrame() {
this.currentFrame++;
if (this.currentFrame >= frames.length) {
this.currentFrame = 0;
}
}
/**
* Draws the current frame on the provided graphics context
*/
public void draw(Graphics g) {
g.draw(this.frames[this.currentFrame];
}
}
Then you need a simple animation loop to call through update() and draw():
final SimpleImageLoop imageLoop = new SimpleImageLoop(frames);
while (true) {
imageLoop.nextFrame();
imageLoop.draw(g);
}
If you need to smooth out the result, you can include additional parameters like how many loops should you perform, the time duration of the frames, etc.

Erase an image after its been moved to a new location

I am making the game Asteroids. Everything functionally works properly, but originally I set the background color to black and had the objects represented by shapes that moved around on a Canvas. I've since changed the background to an Image and am working on changing the objects to be represented by images.
However, regardless of the background, I am having trouble repainting the image in a new location. You can see the path of each object after its been moved to each new location. I've been mostly focusing on the shot fired and I noticed if I fire shots all around the screen, the background is refreshed, but it almost seems to be completely at random. If anyone could help guide me in the right direction, that would be great! I've read several documents, textbooks, and watched several videos to try to understand.
package comets;
import java.awt.*;
import java.awt.event.*;
import java.awt.geom.AffineTransform;
import java.awt.image.AffineTransformOp;
import java.awt.image.BufferedImage;
import javax.imageio.ImageIO;
import javax.sound.sampled.*;
import javax.swing.*;
import java.util.*;
import java.io.*;
import java.net.URL;
// This class is primarily responsible for organizing the game of Comets
public class CometsMain extends JPanel implements KeyListener
{
// GUI Data
private JFrame frame; // The window itself
private JPanel playArea; // The area where the game takes place
private final int playWidth = 500; // The width of the play area (in pixels)
private final int playHeight = 500; // The height of the play area (in pixels)
// Game Data
private SpaceObject spaceObject;
private Ship ship; // The ship in play
private Shot s = new Shot(0, 0, 0, 0);
private LargeComet large = new LargeComet(0, 0, 0, 0);
private MediumComet medium = new MediumComet(0, 0, 0, 0);
private SmallComet small = new SmallComet(0, 0, 0, 0);
private Vector<Shot> shots; // The shots fired by the player
private Vector<Comet> comets; // The comets floating around
private boolean shipDead; // Whether or not the ship has been blown up
private long shipTimeOfDeath; // The time at which the ship blew up
// Keyboard data
// Indicates whether the player is currently holding the accelerate, turn
// left, or turn right buttons, respectively
private boolean accelerateHeld = false;
private boolean turnLeftHeld = false;
private boolean turnRightHeld = false;
private boolean slowDownHeld = false;
// Indicates whether the player struck the fire key
private boolean firing = false;
// Create Images
private Image background; // background image
private BufferedImage spaceShip = null;
private BufferedImage largeComet = null;
private BufferedImage mediumComet = null;
private BufferedImage smallComet = null;
private BufferedImage bullet = null;
private int type = AlphaComposite.SRC_OVER;
private float alpha = 0;
// Set up the game and play!
public CometsMain()
{
// Get everything set up
configureGUI();
configureGameData();
// Display the window so play can begin
frame.setVisible(true);
//Use double buffering
frame.createBufferStrategy(2);
//play music
playMusic();
// Start the gameplay
playGame();
}
private void playMusic(){
try {
URL url = this.getClass().getClassLoader().getResource("BackgroundMusic.wav");
AudioInputStream audioIn = AudioSystem.getAudioInputStream(url);
Clip clip = AudioSystem.getClip();
clip.open(audioIn);
clip.start();
clip.loop(5);
} catch (Exception e) {
e.printStackTrace();
}
}
// Set up the initial positions of all space objects
private void configureGameData()
{
// Configure the play area size
SpaceObject.playfieldWidth = playWidth;
SpaceObject.playfieldHeight = playHeight;
// Create the ship
ship = new Ship(playWidth/2, playHeight/2, 0, 0);
// Create the shot vector (initially, there shouldn't be any shots on the screen)
shots = new Vector<Shot>();
// Read the comets from comets.cfg
comets = new Vector<Comet>();
try
{
Scanner fin = new Scanner(new File("comets.cfg"));
// Loop through each line of the file to read a comet
while(fin.hasNext())
{
String cometType = fin.next();
double xpos = fin.nextDouble();
double ypos = fin.nextDouble();
double xvel = fin.nextDouble();
double yvel = fin.nextDouble();
if(cometType.equals("Large"))
comets.add(new LargeComet(xpos, ypos, xvel, yvel));
else if(cometType.equals("Medium")){
comets.add(new MediumComet(xpos, ypos, xvel, yvel));
}
else
comets.add(new SmallComet(xpos, ypos, xvel, yvel));
}
}
// If the file could not be read correctly for whatever reason, abort
// the program
catch(FileNotFoundException e)
{
System.err.println("Unable to locate comets.cfg");
System.exit(0);
}
catch(Exception e)
{
System.err.println("comets.cfg is not in a proper format");
System.exit(0);
}
}
// Set up the game window
private void configureGUI()
{
// Load Images & Icons
// Background Image
try {
background = ImageIO.read(this.getClass().getClassLoader().getResource("galaxy.jpg"));
} catch (IOException e) {
}
// Space Ship Image
try {
spaceShip = ImageIO.read(this.getClass().getClassLoader().getResource("ship.png"));
} catch (IOException e) {
}
// Large Comet Image
try {
largeComet = ImageIO.read(this.getClass().getClassLoader().getResource("largecomet.png"));
} catch (IOException e) {
}
// Medium Comet Image
try {
mediumComet = ImageIO.read(this.getClass().getClassLoader().getResource("mediumcomet.png"));
} catch (IOException e) {
}
// Medium Comet Image
try {
smallComet = ImageIO.read(this.getClass().getClassLoader().getResource("smallcomet.png"));
} catch (IOException e) {
}
// bullet Image
try {
bullet = ImageIO.read(this.getClass().getClassLoader().getResource("bullet.png"));
} catch (IOException e) {
}
// Create the window object
frame = new JFrame("Comets");
frame.setSize(playWidth+20, playHeight+35);
frame.setResizable(false);
// The program should end when the window is closed
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(playWidth, playHeight);
// Set the window's layout manager
frame.setLayout(new FlowLayout());
// Create background
JLabel bgLabel = new JLabel( new ImageIcon(background.getScaledInstance(playWidth, playHeight, 0) ) );
bgLabel.setSize(playWidth, playHeight);
frame.setContentPane(bgLabel);
frame.pack();
// Create the play area
playArea = new JPanel();
playArea.setSize(playWidth, playHeight);
playArea.setFocusable(false);
playArea.setOpaque(false);
frame.add(playArea);
// Make the frame listen to keystrokes
frame.addKeyListener(this);
}
// The main game loop. This method coordinates everything that happens in
// the game
private void playGame()
{
while(true)
{
// Measure the current time in an effort to keep up a consistent
// frame rate
long time = System.currentTimeMillis();
// If the ship has been dead for more than 3 seconds, revive it
if(shipDead && shipTimeOfDeath + 3000 < time)
{
shipDead = false;
ship = new Ship(playWidth/2, playHeight/2, 0, 0);
}
// Process game events, move all the objects floating around,
// and update the display
if(!shipDead)
handleKeyEntries();
handleCollisions();
moveSpaceObjects();
// Sleep until it's time to draw the next frame
// (i.e. 32 ms after this frame started processing)
try
{
long delay = Math.max(0, 32-(System.currentTimeMillis()-time));
Thread.sleep(delay);
}
catch(InterruptedException e)
{
}
}
}
// Deal with objects hitting each other
private void handleCollisions()
{
// Anything that is destroyed should be erased, so get ready
// to erase stuff
Graphics g = playArea.getGraphics();
Graphics2D g2d = (Graphics2D) g;
g2d.setComposite(AlphaComposite.getInstance(type, alpha));
// Deal with shots blowing up comets
for(int i = 0; i < shots.size(); i++)
{
Shot s = shots.elementAt(i);
for(int j = 0; j < comets.size(); j++)
{
Comet c = comets.elementAt(j);
// If a shot has hit a comet, destroy both the shot and comet
if(s.overlapping(c))
{
// Erase the bullet
shots.remove(i);
i--;
repaint((int)shots.elementAt(i).getXPosition(), (int)shots.elementAt(i).getYPosition(), (int)(2*shots.elementAt(i).getRadius()), (int)(2*shots.elementAt(i).getRadius()));
// If the comet was actually destroyed, replace the comet
// with the new comets it spawned (if any)
Vector<Comet> newComets = c.explode();
if(newComets != null)
{
paintComponent(g);
comets.remove(j);
j--;
comets.addAll(newComets);
}
break;
}
}
}
// Deal with comets blowing up the ship
if(!shipDead)
{
for(Comet c : comets)
{
// If the ship hit a comet, kill the ship and mark down the time
if(c.overlapping(ship))
{
shipTimeOfDeath = System.currentTimeMillis();
shipDead = true;
spaceObject=ship;
paintComponent(g);
}
}
}
}
// Check which keys have been pressed and respond accordingly
private void handleKeyEntries()
{
// Ship movement keys
if(accelerateHeld)
ship.accelerate();
if(slowDownHeld)
ship.slowDown();
// Shooting the cannon
if(firing)
{
firing = false;
shots.add(ship.fire());
}
}
// Deal with moving all the objects that are floating around
private void moveSpaceObjects()
{
Graphics g = playArea.getGraphics();
// Handle the movements of all objects in the field
if(!shipDead)
updateShip(g);
updateShots(g);
updateComets(g);
}
// Move all comets and draw them to the screen
private void updateComets(Graphics g)
{
for(Comet c : comets)
{
spaceObject=c;
paintComponent(g);
// Move the comet to its new position
c.move();
paintComponent(g);
}
}
// Move all shots and draw them to the screen
private void updateShots(Graphics g)
{
for(int i = 0; i < shots.size(); i++)
{
Shot s = shots.elementAt(i);
// Erase the shot at its old position
paintComponent(g);
// Move the shot to its new position
s.move();
// Remove the shot if it's too old
if(s.getAge() > 180)
{
shots.remove(i);
i--;
}
// Otherwise, draw it at its new position
else
{
moveImage(g, s, (int)s.getXPosition(), (int)s.getYPosition());
paintComponent(g);
}
}
}
// Moves the ship and draws it at its new position
private void updateShip(Graphics g)
{
// Erase the ship at its old position
paintComponent(g);
// Ship rotation must be handled between erasing the ship at its old position
// and drawing it at its new position so that artifacts aren't left on the screen
if(turnLeftHeld)
ship.rotateLeft();
if(turnRightHeld)
ship.rotateRight();
ship.move();
// Draw the ship at its new position
moveImage(g, ship, (int)ship.getXPosition(), (int)ship.getYPosition());
paintComponent(g);
}
// Draws this ship s to the specified graphics context
private void drawShip(Graphics g, Ship s)
{
Graphics2D ship = (Graphics2D) spaceShip.getGraphics();
double x = Math.sin(s.getAngle());
double y = Math.cos(s.getAngle());
AffineTransform transformsave = AffineTransform.getRotateInstance(x, y, spaceShip.getWidth()/2, spaceShip.getHeight()/2);
AffineTransformOp transform = new AffineTransformOp( transformsave, AffineTransformOp.TYPE_BILINEAR );
// Figure out where the ship should be drawn
int xCenter = (int)s.getXPosition();
int yCenter = (int)s.getYPosition();
// Draw the ship body
g.drawImage(transform.filter(spaceShip, null), xCenter-10, yCenter-20, null);
ship.setTransform(transformsave);
}
public void setSpaceObject(SpaceObject s){
spaceObject=s;
}
public SpaceObject getSpaceObject(){
return spaceObject;
}
#Override
protected void paintComponent( Graphics g ){
super.paintComponent(g);
spaceObject=getSpaceObject();
int radius = (int)s.getRadius();
int xCenter = (int)s.getXPosition();
int yCenter = (int)s.getYPosition();
// Draw the object
if(spaceObject==s)
g.drawImage( bullet, xCenter-radius, yCenter-radius, this );
else if(spaceObject==large)
g.drawImage( largeComet, xCenter-radius, yCenter-radius, this );
else if(spaceObject==medium)
g.drawImage( mediumComet, xCenter-radius, yCenter-radius, this );
else if(spaceObject==small)
g.drawImage( smallComet, xCenter-radius, yCenter-radius, this );
else if(spaceObject==ship)
drawShip(g, ship);
}
public void moveImage(Graphics g, SpaceObject s, int x, int y){
int radius = (int)s.getRadius();
int xCenter=0, yCenter=0;
if(xCenter!=x || yCenter!=y){
xCenter= (int)s.getXPosition();
yCenter = (int)s.getYPosition();
repaint(xCenter, yCenter, radius*2, radius*2);
}
}
// Deals with keyboard keys being pressed
public void keyPressed(KeyEvent key)
{
// Mark down which important keys have been pressed
if(key.getKeyCode() == KeyEvent.VK_UP)
this.accelerateHeld = true;
if(key.getKeyCode() == KeyEvent.VK_LEFT)
this.turnLeftHeld = true;
if(key.getKeyCode() == KeyEvent.VK_RIGHT)
this.turnRightHeld = true;
if(key.getKeyCode() == KeyEvent.VK_SPACE)
this.firing = true;
//ADD DOWN TO SLOW DOWN SHIP!!!
if(key.getKeyCode() == KeyEvent.VK_DOWN)
this.slowDownHeld = true;
}
// Deals with keyboard keys being released
public void keyReleased(KeyEvent key)
{
// Mark down which important keys are no longer being pressed
if(key.getKeyCode() == KeyEvent.VK_UP)
this.accelerateHeld = false;
if(key.getKeyCode() == KeyEvent.VK_LEFT)
this.turnLeftHeld = false;
if(key.getKeyCode() == KeyEvent.VK_RIGHT)
this.turnRightHeld = false;
//ADD DOWN TO SLOW DOWN SHIP!!!
if(key.getKeyCode() == KeyEvent.VK_DOWN)
this.slowDownHeld = false;
}
// This method is not actually used, but is required by the KeyListener interface
public void keyTyped(KeyEvent arg0)
{
}
public static void main(String[] args)
{
// A GUI program begins by creating an instance of the GUI
// object. The program is event driven from that point on.
new CometsMain();
}
}
Don't use getGraphics. The problem with this, is it's simply a snap shot of what was last painted.
This is like taking a sheet of paper and repeatedly drawing on top of it, it makes a real mess real quick.
getGraphics can also return null.
In Swing painting is controlled by the RepaintManager which makes decisions about what and when things should be painted.
The basic concept you should be trying to follow is to...
Update the state of the game model
Update the view of the game model
Render the view to the screen
This can be achieved in a few different ways, but to start with, if you want to make updates to the UI, you should override the paintComponent method of a component that extends from something like JComponent.
When called, call super.paintComponent which will automatically prepare the Graphics context for painting.
To update the view...
You Could...
In a background thread, update the game model and request that the view be repainted
In the view's paintComponent method, re-draw the model
This is a relatively simple approach, but can, if not controlled well, can get the view and the model out of sync. You also need to ensure that the model is not changed while the view is been updated...
Or, You Could...
Create two (or more) BufferedImages
In a background thread, update the game model
In the background thread, update the "offscreen" buffer to represent the current game model state
Switch the buffered images (moving the "offscreen" buffer to the "active screen" and the "active screen" to the "offscreen")
Request that the view be updated
In the view's paintComponent method, simply draw the "active screen"
This is a more complex process, which will require you to ensure that the buffer's are the same size as the view, but means that the model can be updated independently of the view repaints. There is still the danger that you could change the "off" and "active" screen buffers while the view is been painted.
You could elevate this process slightly by using some kind of queue, where you place BufferedImages that can be used for rendering to (by popping them off the queue) and having the "view" push them back again once it has rendered it...
Or some combination of these, where you lock the switching of the "active" and "off" screen buffers to ensure that that "active" buffer isn't being painted.
Take a look at Performing Custom Painting and Painting in AWT and Swing for more details
For example...
Java Bouncing Ball
the images are not loading
Swing animation running extremely slow
Modern graphics applications use following approach:
For every frame repeat these steps
erase screen
draw background
draw your objects in proper order
do anything else
With this approach you don't need to track previous locations of your objects that can be very tricky because object may overlap.
Of course this will cause flickering, due to lack of performance. Various algorithms to prevent this are exists, take a look on this Documentation and this Question
you can just use getContentPane().repaint() every time you use repaint().

Categories

Resources