Gif Image only playing once. Need it to replay each time - java

I don't want to post the entire program on here because that would be too much, but I will post snippets of it and detail where they came from so you have an idea.
Problem: For my class project, I am making a typical space invaders game. When a missile hits a ship an explosion gif is played. The gif only loops once (not continuous). The when the missile hits the alien craft, the gif plays just fine for the first spaceship. However, when I shoot a missile at the second or third,etc, ship the gif does not play again. I believe that it is just playing the last frame of the gif from what I have researched. Is there a way to either reload the gif image to play each time the missile is hits or is there another way to do this?
Here is the link to the image: http://postimg.org/image/v2lljr7cb/
Here is some code:
I have a class called Boom, where the explosion is happening. Here is the code in that class:
public void draw(Graphics2D g2d) {
g2d.drawImage(getEnemyImg(), x, y, null);
}
public Image getEnemyImg() {
ImageIcon ic = new ImageIcon("src/Boom.gif");
return ic.getImage();
}
I then have another class called GameFrame where everything happens. In it, there are these lines of code specially for the explosion. Here is the code from this class:
static ArrayList<Boom> booms = new ArrayList<Boom>();
public void paint(Graphics g) {
super.paint(g);
Graphics2D g2d = (Graphics2D) g;
ImageIcon ic = new ImageIcon("src/BackGround.jpg");
g2d.drawImage(ic.getImage(), 0, 0, null);
player.draw(g2d);
for (int i = 0; i < booms.size(); i++) {
Boom bm = booms.get(i);
bm.draw(g2d);
}
Enemy e = new Enemy(200, 400);
}
#Override
public void actionPerformed(ActionEvent arg0) {
// TODO Auto-generated method stub
player.update();
for (int i = 0; i < booms.size(); i++) {
Boom bm = booms.get(i);
bm.update();
}
checkEnd();
repaint();
}
public static void addBoom(Boom bm) {
booms.add(bm);
}
public static void removeBoom(Boom bm) {
booms.remove(bm);
}
public static ArrayList<Boom> getBoomList() {
return booms;
}
Finally, here is where the explosion is being added. This happens when the missile hits the alien space craft. This is happening in the Enemy class. Here is the code:
public void checkCollisions() {
for (int i = 0; i < GameFrame.getMissileList().size(); i++) {
Missile m = GameFrame.getMissileList().get(i);
if (getBounds().intersects(m.getBounds())) {
GameFrame.removeEnemy(this);
GameFrame.removeMissile(m);
GameFrame.addBoom(new Boom(m.getX() -40, m.getY()- 60));
for(int j = 0; i <GameFrame.getBoomList().size(); i++){
Boom bm = GameFrame.getBoomList().get(j);
}
}
}
}
I apologize for the wall of text. My professor was unsure of how to do this so I was hoping to get some help from here.
If you have any time to spare, your ideas would be helpful. Thank you.

Related

Java 2D game: repaint

I am creating a very simple game for my homework and right now I am solving the following problem:
in this game when you click on the shape (for now it is just a circle) it should dissapear and render a new one somewhere else (you are collecting points when you hit that shapes, that´s the point) and my problem is in the mouseClicked method, i think. I put some control System.out.println() there and everytime when the program reach this method it displays as many prints as there was circles. I mean, if you click on the first circle it displays one print, if you click on the second circle it diplays two prints and so on. Can you help me pls? I just started with the swing and awt and I don´t have much time for thorough study. Thank you so much.
public class Shape extends JPanel implements ActionListener{
Graphics2D g2;
Ellipse2D circle;
Timer t = new Timer(2000, this);
int x, y, count;
JLabel counting;
public Shape(JLabel counting){
this.counting = counting;
}
public void paintComponent(Graphics g){
super.paintComponent(g);
g2 = (Graphics2D)g;
ListenForMouse lForMouse = new ListenForMouse();
addMouseListener(lForMouse);
Random ran = new Random();
int green = ran.nextInt(256);
int red = ran.nextInt(256);
int blue = ran.nextInt(256);
Color randomColor = new Color(green, red, blue);
int wid = ran.nextInt(101) + 50;
x = ran.nextInt(650);
if(x > wid)
x = x - wid;
y = ran.nextInt(600);
if(y > wid)
y = y - wid;
circle = new Ellipse2D.Double(x,y,wid,wid);
t.start();
g2.setColor(randomColor);
g2.fill(circle);
}
#Override
public void actionPerformed(ActionEvent arg0) {
repaint();
}
private class ListenForMouse implements MouseListener{
#Override
public void mouseClicked(MouseEvent e) {
System.out.println("Control before");
if(circle.contains(e.getPoint())){
count++;
counting.setText(Integer.toString(count));
t.stop();
repaint();
System.out.println("Control in");
}
System.out.println("Control out");
}
}
}
This happens, because you add a new mouse listener every time paintComponent is called. You should do this once, inside the constructor.

JAVA: background rendeing over the player?

I'm building my first very basic game in JAVA without using any other external libraries.
The problem I got is
You can see that the background is rendered over player how can I fix that
The player rendering code is as follows
#Override
public void render(Graphics g) {
int bulletcount = 0;
//render player
g.setColor(color);
g.fillRect(x,y,32,32);
if(shooting) {
handler.add(new bullet(x + 8, y - 24, ID.bullet, handler));
bulletcount++;
}
}
and the background render code is as follows.
public class background extends GameObject{
private int width;
private Random random = new Random();
public background(int x, int y , ID id,Handler handler){
super(x,y,id,handler);
valy = 2;
width = getWidth(x,800);
}
public void tick() {
y += valy;
if(y>650)
handler.remove(this);
}
public void render(Graphics g) {
g.setColor(Color.white);
g.fillRoundRect(x,y,width,10,1,1);
}
public int getWidth(int x,int width1){
int wid;
while(true){
if((width - x) > 35) {
wid = random.nextInt((width-x-35));
break;
}
else{
x -= 10;
}
}
return wid;
}
}
the main class of game can see the order of flow of execution.
private void render() {
// render the Game
BufferStrategy bs = this.getBufferStrategy();
if(bs == null)
{
this.createBufferStrategy(3);
return;
}
Graphics g = bs.getDrawGraphics();
g.setColor(Color.black);
g.fillRect(0,0,WIDTH,HEIGHT);
handler.render(g);
hod.render(g); //handler is rendering every object in game
g.dispose();
bs.show();
}
private void tick() {
//update Game
handler.tick();
hod.tick();
spawner.tick(); // background is generating in spawner class.
}
I know that telling the problem with this much less code is hard for you all. But I have complete faith in this large and powerful community.
Thanks in advance. Don't hesitate to edit and point out my mistakes Thanks!
If I get the code right, the background is being generated after rendering the player which leads to the background being on top of the player. I would try calling spawner.tick() (where I guess the background is coming from given your code comment) before calling hod.tick(). Hopefully that should resolve this issue.
private void tick() { //update Game
spawner.tick();
handler.tick();
hod.tick();
}
I just had solution!
The problem was in handler.render(g); method:- which is a follows;
private void render(Graphics g){
for(int i =0; i<gameobj.size(); i++){//gameobj is linkedlist of GameObject
GameObject tempobj = gameobj.get(i);
tempobj.render(g);//getting every object and rendering them!
}
The problem was in loop the first object added in the game is player.So , it was getting render first after that the background was getting rendered.
It was a silly mistake.which got right by following change.->
private void render(Graphics g){
for(int i = gameobj.size()-1; i > 0; i--){//gameobj is linkedlist of GameObject
GameObject tempobj = gameobj.get(i);
tempobj.render(g);//getting every object and rendering them! from reverse
}
so, the last object renders first and the first object renders last.
Peace!

Why does this attempt to animate my moving sprite work?

I'm trying to animate the sprite in my game when a button is pressed, but when I press the button, it skips the animation. Its supposed to go one pixel, change sprites, and then go one more pixel and change back. Here is the code
//for all
import java.nio.file.*;
import javax.imageio.ImageIO;
import java.io.IOException;
import java.awt.image.*;
import java.net.*;
import java.awt.*;
import javax.swing.*;
import static java.lang.invoke.MethodHandles.*;
import java.awt.event.*;
//my Mario class (cut down a lot)
class Mario {
// all numbers multiplied by 2 from OG game
protected Direction dir;
protected int x, y;
protected BufferedImage sprite;
protected String currentSpriteName;
public Mario() {
this.x = 54;
this.y = 808;
dir = Direction.RIGHT;
setSprite(MVCE.SMALLSTANDFACERIGHT);
currentSpriteName = MVCE.SMALLSTANDFACERIGHT;
}
public void moveRight(){
if(this.dir == Direction.LEFT){
this.dir = Direction.RIGHT;
}
else if(this.dir == Direction.RIGHT){
this.x+=1;
}
}
public void animateMoveRight(){
if (currentSpriteName.equals(MVCE.SMALLSTANDFACERIGHT)){
setSprite(MVCE.SMALLWALKFACERIGHT);
}
else if (currentSpriteName.equals(MVCE.SMALLWALKFACERIGHT)){
setSprite(MVCE.SMALLSTANDFACERIGHT);
}
}
public void jump() {
this.y -= 46;
}
public void setSprite(String spriteName) {
URL spriteAtLoc = MVCE.urlGenerator(spriteName);
this.sprite = MVCE.generateAndFilter(sprite, spriteAtLoc);
}
public void getSprite(){
System.out.println(this.currentSpriteName);
}
public void paint(Graphics g) {
Graphics2D g2 = (Graphics2D) g;
g2.drawImage(sprite, 0, 0, null); // DO NOT SET x and y TO ANYTHING,
// this sets 0,0 to top left!!
}
}
// my MarioRender class:
class MarioRender extends JLabel {
protected Mario marioSprite;
public MarioRender() {
marioSprite = new Mario();
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
marioSprite.paint(g2);
setBounds(marioSprite.x, marioSprite.y, marioSprite.sprite.getWidth(), marioSprite.sprite.getHeight());
}
public void moveMarioRight(){
marioSprite.moveRight();
marioSprite.animateMoveRight();
setLocation(this.marioSprite.getX(), this.marioSprite.getY());
repaint();
//this is my attempt to make it animate
marioSprite.moveRight();
marioSprite.animateMoveRight();
setLocation(this.marioSprite.getX(), this.marioSprite.getY());
repaint();
}
public void jumpMario() {
marioSprite.jump();
setLocation(this.marioSprite.x, this.marioSprite.y);
repaint();
}
}
// direction class, solely for moving
enum Direction {
LEFT, RIGHT
}
// my calling class, which I called MVCE where I make the frame
public class MVCE extends JFrame {
MarioRender m = new MarioRender();
JLabel bg;
public MVCE() {
bg = new JLabel();
this.setSize(868, 915);
this.setVisible(true);
this.add(bg, BorderLayout.CENTER);
bg.setLayout(null);
bg.add(m);
m.setBounds(m.marioSprite.x, m.marioSprite.y, m.marioSprite.sprite.getWidth(),
m.marioSprite.sprite.getHeight());
KeyListener kl = new MoveListener();
this.addKeyListener(kl);
this.setFocusable(true);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
public static final String SMALLSTANDFACERIGHT = "SmallStandFaceRight.bmp"; // 30
// x
// 32
public static final String SMALLJUMPFACERIGHT = "SmallJumpFaceRight.bmp"; // 32
// x
// 32
// generate URL
public static URL urlGenerator(String name) {
URL u = lookup().lookupClass().getResource(name);
return u;
}
// return image with filtered color
public static BufferedImage generateAndFilter(BufferedImage b, URL u) {
try {
b = ImageIO.read(u);
int width = b.getWidth();
int height = b.getHeight();
int[] pixels = new int[width * height];
b.getRGB(0, 0, width, height, pixels, 0, width);
for (int i = 0; i < pixels.length; i++) {
// System.out.println(pixels[i]);
if (pixels[i] == 0xFFff00fe) {
pixels[i] = 0x00ff00fe;
}
}
BufferedImage newSprite = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
newSprite.setRGB(0, 0, width, height, pixels, 0, width);
b = newSprite;
} catch (IOException e) {
System.out.println("sprite not found");
e.printStackTrace();
}
return b;
}
// key listener
class MoveListener implements KeyListener {
public void keyPressed(KeyEvent k) {
if ((k.getKeyCode() == 39)) {
m.moveMarioRight();
///THIS IS SUPPOSED TO MOVE HIM 1, change sprite, and automatically move him back, it moves 2 pixels but no animation
}
if (k.getKeyCode() == 83) { // S key
m.marioSprite.setSprite(SMALLJUMPFACERIGHT);
m.jumpMario();
}
}
public void keyReleased(KeyEvent k) {
}
public void keyTyped(KeyEvent k) {
}
}
public static void main(String[] args) {
MVCE m = new MVCE();
}
}
I tried putting this between the calls to marioMoveRight():
try {
Thread.sleep(200);
} catch(InterruptedException ex) {
Thread.currentThread().interrupt();
}
but it just delays the whole thing. I had also tried using an ActionListener, but I don't know how to make it react only when the key is pushed. as I had it,
I had this class inside of MVCE:
class TickListener implements ActionListener{
public void actionPerformed(ActionEvent a){
m.marioSprite.setSprite(Constants.SMALLWALKFACERIGHT);
repaint();
}
}
and this at the end of the MVCE constructor:
ActionListener ac = new TickListener();
final int DELAY = 1000;
Timer t = new Timer(DELAY, ac);
t.start();
but then, the Mario just moves automatically. I do not want to use a sprite sheet for this project, I am trying to do it as this guy did for SMB1.
Many problems, don't know which one or if any will fix the problem:
Don't use a KeyListener. If a component doesn't have focus the component won't receive the event. Instead use Key Bindings.
Don't use "==" to compare Objects. Instead you should be using the equals(...) method.
Don't override paintComponent. A painting method is for painting only. You should not be changing the bounds of the component in the painting method.
Do basic debugging (problem solving) before asking a question. A simple System.out.println(...) added to various methods will determine if the code is executing as you expect. Then when you ask a question you can ask a specific question telling us which block of code does not execute as you expect.
You never actually call the method animateMoveRight(), and if I understand correcly, that's what's changing the sprite. Also, I doubt that you see the sprite change when calling the same method twice in a row without any delay.
Try putting the animateMoveRight() method into the moveRight() or the moveMarioRight() method and, if neccessary because the animation is too fast, add your delay code back where you had it. Be careful not to let the main thread sleep, as this causes everything to freeze, so start another one or use a timer etc.
EDIT: Good timers
I'm not too familiar with the Timer class, so I end up using the Thread variant. There are many tutorials for that out there, just search for "java threads" or "java multithreading". This is IMO a solid tutorial you can check out.

Why does my ball keep flashing?

I am still a student. I am trying to learn how to draw a ball and move by myself.
Here is the code :
import javax.swing.*;
import java.awt.*;
public class Ball extends JFrame
{
int x = 50;
int y = 50;
int rad = 30;
Ball(){
setSize(500,500);
setTitle("Ball");
setVisible(true);
}
void move()
{
if (x < getWidth() - rad){
x = x + 1 ;
}
try
{
Thread.sleep(100);
}
catch( Exception e)
{
}
}
public void paint( Graphics g)
{
super.paint(g);
g.fillOval(x,y,rad,rad);
}
public static void main(String args[])
{
Ball b = new Ball();
while(true){
b.move();
b.repaint();
}
}
}
I would say this code work 60% of it because
when i run the program the ball is moving to the right, but it keep flashing for some reason and i dont know why.
it is my computer problem , or the code or some kind of bug?
i am using eclipse luna
This is a very classic problem you see when the screen updates with only parts of the data you want it to show.
In this case, the JFrame's update(Graphics) clears the screen with a fillRect, then calls your paint(Graphics) which draws the ball with a fillOval.
If the screen updates between the fillRect and the fillOval, the ball will briefly disappear, causing the flashing (aka flickering).
The solution is double buffering, where all the graphics operations are drawn to an offscreen image, and then drawn to the window in one operation.
This is something you get for free with JPanel, so just modify your code to inherit from that instead of JFrame (this is good practice in any case). Here it is with minimal code changes:
import javax.swing.*;
import java.awt.*;
public class Ball extends JPanel
{
int x = 50;
int y = 50;
int rad = 30;
void move()
{
if (x < getWidth() - rad){
x = x + 1 ;
}
try
{
Thread.sleep(100);
}
catch( Exception e)
{
}
}
public void paint( Graphics g)
{
super.paint(g);
g.fillOval(x,y,rad,rad);
}
public static void main(String args[])
{
Ball b = new Ball();
JFrame frame = new JFrame();
frame.add(b);
frame.setSize(500,500);
frame.setVisible(true);
while(true){
b.move();
b.repaint();
}
}
}
This should be flicker free, but may still be jerky.
For smoother animation, you'd typically account for inter-frame timing and framedrops instead of just updating every 100ms and hoping it makes it into a timely repaint.

Loading a subimage from a tile map

I'm trying to develop my first game. I have serious issues with loading Tiles extracted from a map.
Here's what I've coded so far, just willing to display the first tile.
public class TileMap {
//FIELDS
public int Tilemapx;
public int Tilemapy;
private int nRows = 8;
private int nColumns = 8;
public int TileWidth = Panel.WIDTH / nColumns;
public int TileHeight = Panel.HEIGHT / nRows;
public BufferedImage EntireMap;
public BufferedImage SingleTile;
public TileMap (){
String EntireMappath = "res/Tiles.png";
try {
EntireMap = ImageIO.read(new File (EntireMappath));
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public void drawTile (){
for (int Tilemapx = 0; Tilemapx < Panel.WIDTH / nColumns; Tilemapx++){
for (int Tilemapy = 0; Tilemapy < Pannel.HEIGHT / nRows; Tilemapy++){
BufferedImage SingleTile = EntireMap.getSubimage(100, 100, Tilemapx, Tilemapy);
}
}
}
}
and, in the Panel class, I'm trying to draw the tile, but nothing appears (the first two images work as intended)
public void draw() {
BufferStrategy bs = getBufferStrategy();
if (bs == null) {
createBufferStrategy(3);
return;
}
Graphics g = bs.getDrawGraphics();
g.drawImage(bg, 0, 0, getWidth(), getHeight(), null);
g.drawImage(heroImg1, hero.cordX, hero.cordY, hero.diameter, hero.diameter, null);
g.drawImage(tiles.SingleTile, 100, 200, tiles.Tilemapx, tiles.Tilemapx, null);
g.dispose();
bs.show();
}
You should provide a method in TileMap that returns the appropriate sub image for a given tile. Then, in draw, you can call that method, obtain an image, and draw it on the graphics. If you would like to draw the whole board, simply use a loop.
public void drawTile (){
// THIS IMAGE SingleTile SHOULD BE GLOBAL AND THIS IMAGE SHOULD BE RETURNED GLOBAL FROM A METHOD
BufferedImage SingleTile = EntireMap.getSubimage(100, 100, Tilemapx, Tilemapy);
// get the graphics context from what you want to paint onto
Graphics ga = OTHERIMAGE_OR_BUFFERSTRATEGY_OR_PANEL.getGraphics(); //or getDrawGraphics() for bufferstrategy
//then draw on it ga.drawImge(....................
}//END METHOD

Categories

Resources