Drawing new Graphics in ArrayList - java

I have an application, in which a car is moving on a panel and it creates sound waves - circles. I want to :
1) have a few circles at the moment of opening the frame
2) when the Start button is selected I want them to move and I want more circles to be created, one after another, until the stop button is selected
the problem is:
1) when the frame is opened there are 5 circles, but they totally do not move
2) 5 new circles appears, but from the same XY position, they are just bigger - I want one circle after another, it grows, and next one appears
here is my code, I would appreciate some helpful sample or could you tell me where my mistake is. I used amount of 5 just to have some samples of waves.
public class WaveParameters {
int xPos=0;
int yPos = 375;
int width=60;
int height=60;
int velX = 0 ;
private Color color = Color.WHITE;
public int getVelX() {
return velX;
}
public void setVelX(int velX) {
this.velX = velX;
}
public int getX() {
return xPos;
}
public void setX(int xPos) {
this.xPos = xPos;
}
public int getWidth(){
return width;}
public int getHeight(){
return height;}
public void setWidth(int width) {
this.width = width;
}
public void setHeight(int height) {
this.height = height;
}
public Color getColor() {
return color;
}
public void setColor(Color color) {
this.color = color;
}
public void paint(Graphics g){
g.setColor(getColor());
g.drawOval(xPos,yPos,width/2,height/2);
}
}
Here is the panel of animation:
public class PanelAnimation extends JPanel implements ActionListener{
List<WaveParameters> waves = new ArrayList<WaveParameters>();
public PanelAnimation(ResourceBundle bundle) {
super();
resourceBundle = bundle;
t.start();
try {
imageBackground = ImageIO.read(newFile("bg.png"));
} catch (IOException ex) {
// handle exception...
}
}
CarParametrs pAuto = new CarParametrs();
HumanParametrs pHuman = new HumanParametrs() ;
Timer t = new Timer(60,this);
//WaveParameters pWave = new WaveParameters();
private BufferedImage imageBackground;
MainFrame mf;
public void addAuto(){
CarParametrs ap = new CarParametrs();
ap.setX(0);
pAuto = ap;
}
public void addHuman(){
HumanParametrs acz = new HumanParametrs();
acz.setX(0);
pHuman = acz;
}
public void addWave() {
for (int i=0; i<5; i++) {
WaveParameters wave = new WaveParameters();
// wave.setX(pAuto.xPos);
wave.setColor(Color.white);
wave.setWidth(wave.width*i);
wave.setHeight(wave.height*i);
waves.add(wave);
}
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawImage(imageBackground, 0, 0, null);
pAuto.paint(g);
pHuman.paint(g);
//if(mf.buttonStart.isSelected()) {
addWave();
//for (int i=0; i<5; i++) {
for (WaveParameters w : waves) {
// waves.add(new WaveParameters());
w.setX(pAuto.xPos);
w.paint(g);
//}
}
//}
}
public void actionPerformed(ActionEvent e) {
CarParametrs pa = pAuto;
pa.xPos += pa.velX;
/*//WaveParameters wp = pWave;
wp.xPos = pa.xPos;
wp.xPos+=wp.velX;
wp.height+=wp.velX;
wp.width+=wp.velX;
wp.yPos-=wp.velX/5 ;*/
for (WaveParameters w : waves) {
w.xPos = pa.xPos;
w.xPos+=w.velX;
w.height+=w.velX;
w.width+=w.velX;
w.yPos-=w.velX/5 ;
}
repaint();
}
and here is a wave-part of action listener for Start Button:
List<WaveParameters> wave = panelAnimation.waves;
for (WaveParameters w : wave) {
for (int i=0;i<5;i++) {
wave.add(new WaveParameters());
w.velX = Integer.parseInt(button2.getName());
w.xPos += w.velX;
w.width++;
w.height++;
w.yPos-=w.velX/5;
}
}
panelAnimation.repaint();

The five new bigger circles that appear are likely due to the last chunk of code where you iterate through all the waves in panel animation.
The "wave.add(new WaveParameters());" seems unnecessary, and may be the reason why your old waves are staying. Delete that line, and it may work.

Related

How to implement MouseMotionListener in Java Swing for list of objects to follow mouse?

My question is how can i implement the MouseMotionListener for list of objects can follow my mouse? I guess, I couldn't get the idea so far. I tried to do that my second part of the worm will follow the head. So it will become like a train. But in first second seems like Ok but all objects suddenly converge to a point.
Basically my code is above;
My Worm.class is like that;
public class Worm {
Random rd = new Random();
int xWorm;
int yWorm;
int Speed = 100;
int size = 10; // default
Worm()
{
xWorm = rd.nextInt(250);
yWorm = rd.nextInt(250);
}
Worm(int xNew, int yNew){
xWorm = xNew;
yWorm = yNew;
}
public int getxWorm() {
return xWorm;
}
public void setxWorm(int xWorm) {
this.xWorm = xWorm;
}
public int getyWorm() {
return yWorm;
}
public void setyWorm(int yWorm) {
this.yWorm = yWorm;
}
public int getSpeed() {
return Speed;
}
public void setSpeed(int speed) {
Speed = speed;
}
public void move (int dx, int dy) {
xWorm+=dx;
yWorm+=dy;
}
public void setPosition(int x,int y) {
this.xWorm = x;
this.yWorm = y;
}
public void paint(Graphics g) {
Graphics2D g2 = (Graphics2D) g;
Ellipse2D Ellipse= new Ellipse2D.Double(xWorm,yWorm,10,10);
g2.setColor(Color.GREEN);
g2.draw(Ellipse);
g2.fill(Ellipse);
// g.fillOval(this.xWorm, this.yWorm, 30, 30);
}
public boolean iscollision(Food f) {
Rectangle2D RectangleforFood = new Rectangle2D.Double(f.xFood,f.yFood,5,5);
Rectangle2D RectangleforWormHead = new Rectangle2D.Double(this.xWorm,this.yWorm,10,10);
if (RectangleforWormHead.intersects(RectangleforFood)) {
return true;
}
else {
return false;
}
}
}
and my Panel.class the tracker function like that ;
public void createlongworm() {
for(int i = 0; i < 100 ; i++) {
wormBody.add(new Worm(wormBody.get(i).xWorm+10,wormBody.get(i).yWorm));
}}
public void tracker(ArrayList <Worm> TracktheWorm) {
for(int i = 0; i < TracktheWorm.size()-1 ; i++) {
TracktheWorm.get(i+1).xWorm = TracktheWorm.get(i).xWorm;
TracktheWorm.get(i+1).yWorm = TracktheWorm.get(i).yWorm;
}
repaint();
}

Graphics Stuttering in Java (Space Invaders)

I am creating a Space Invaders Game with just one Invader. The images are stuttering and are only visible ~10% of the time. What is wrong with my code?
package spaceinvader;
import javax.swing.*;
import java.awt.event.*;
import java.awt.*;
public class spaceInvaders extends JApplet implements KeyListener, ActionListener
{
//Declare components and variables
JPanel mainPanel = new JPanel();
ImageIcon carImage = new ImageIcon("ship.png");
ImageIcon invaderImage = new ImageIcon("invader.png");
int intPosX = 240;
int intPosY = 330;
int intXAmount = 15;
boolean shipMoveLeft = false;
boolean shipMoveRight = false;
Timer shipTimer = new Timer(100,this);
int intBulletX = -50;
int intBulletY = -50;
boolean bulletMove = false;
boolean bulletActive = false;
Timer bulletTimer = new Timer(50,this);
int intInvaderX = 0;
int intInvaderY = 0;
int invaderXAmount = 10;
boolean invaderMove = true;
Timer invaderTimer= new Timer(1000,this);
public void init()
{
addKeyListener(this);
setFocusable(true);
resize(600,400);
setContentPane(mainPanel);
shipTimer.start();
bulletTimer.start();
invaderTimer.start();
}
public void actionPerformed(ActionEvent e)
{
requestFocus();
if(shipMoveLeft)
intPosX += intXAmount;
else if(shipMoveRight)
intPosX -= intXAmount;
if(bulletMove && bulletActive){
intBulletY -= 15;
if(intBulletY <= -50){
bulletMove = false;
bulletActive = false;
}
}
if(invaderMove){
intInvaderX += invaderXAmount;
if(intInvaderX > getWidth() - 60 || intInvaderX < 0){
intInvaderY += 40;
invaderXAmount *= -1;
}
}
repaint();
}
public void keyPressed(KeyEvent e)
{
int key = e.getKeyCode();
if (key == 37){
shipMoveRight = true;
}
else if (key == 39){
shipMoveLeft = true;
}
else if (key == 32){
if(bulletActive == false){
intBulletX = intPosX;
intBulletY = intPosY;
}
bulletMove = true;
bulletActive = true;
}
}
public void keyReleased(KeyEvent e)
{
shipMoveLeft = false;
shipMoveRight = false;
}
public void keyTyped(KeyEvent e)
{
}
public void paint(Graphics gr)
{
super.paint(gr);
gr.setColor(Color.red);
gr.fillOval(intBulletX, intBulletY, 10, 25);
carImage.paintIcon(this,gr, intPosX, intPosY); //Draw image in new spot
invaderImage.paintIcon(this,gr, intInvaderX, intInvaderY);
}
}
So there are a number of issues which jump out immediately...
Applets are a dead end, most browsers will actively block them and/or have dropped support for the plugin
You're adding a JPanel to the applet, but overriding the applet's paint method, because of the way painting can work, the panel can be painted independently of the applet, causing it to paint over whatever you might have painted
You don't need multiple timers, you just need to have better delta values (smaller been faster)
KeyListener is a poor choice for detecting keyboard input, it's rather low level and has focus related issues which are easily overcome by using the Key Bindings API
I'd start by having a look at Performing Custom Painting, Painting in AWT and Swing and How to Use Key Bindings for more details.
So how would you start fixing it? Start by using a JPanel as you basic container, override it's paintComponent and place all your paint logic here.
Use a single Timer to manage the updates
There are any number of approaches you can take, but I'd start with defining some contracts that define what can go on in the game
public interface GameSpace extends ImageObserver {
public Dimension getGameSpace();
public boolean hasInput(Input input);
}
public interface Entity {
public void paint(GameSpace gameSpace, Graphics2D g2d);
public boolean update(GameSpace gameSpace);
public Rectangle getBounds();
}
public abstract class AbstractEntity implements Entity {
private int x;
private int y;
public int getX() {
return x;
}
public int getY() {
return y;
}
public void setX(int x) {
this.x = x;
}
public void setY(int y) {
this.y = y;
}
protected abstract int getWidth();
protected abstract int getHeight();
public Rectangle getBounds() {
return new Rectangle(getX(), getY(), getWidth(), getHeight());
}
}
public abstract class AbstractImageEntity extends AbstractEntity {
protected abstract BufferedImage getImage();
#Override
protected int getWidth() {
return getImage().getWidth();
}
#Override
protected int getHeight() {
return getImage().getHeight();
}
}
This separates some of management of key elements, allowing for a more flexible design. You might have a lot more entities, one's which could move, ones which could not, some which are painted, some which are not, but all which provide support for the core engine to get work done.
Once you have that you can start defining some core entities you need
public class ShipEntity extends AbstractImageEntity {
private BufferedImage ship;
public ShipEntity(GameSpace gameSpace) throws IOException {
ship = ImageIO.read(getClass().getResource("/resources/ship.png"));
setY(gameSpace.getGameSpace().height - getBounds().height);
setX((gameSpace.getGameSpace().width - getBounds().width) / 2);
}
#Override
public BufferedImage getImage() {
return ship;
}
#Override
public void paint(GameSpace gameSpace, Graphics2D g2d) {
g2d.drawImage(ship, getX(), getY(), gameSpace);
}
#Override
public boolean update(GameSpace gameSpace) {
int x = getX();
if (gameSpace.hasInput(Input.LEFT)) {
x -= 2;
}
if (gameSpace.hasInput(Input.RIGHT)) {
x += 2;
}
if (x < 0) {
x = 0;
} else if (x + getWidth() > gameSpace.getGameSpace().width) {
x = gameSpace.getGameSpace().width - getWidth();
}
setX(x);
return true;
}
}
public class InvaderEntity extends AbstractImageEntity {
private BufferedImage invader;
public InvaderEntity() throws IOException {
invader = ImageIO.read(getClass().getResource("/resources/Invader.png"));
}
#Override
protected BufferedImage getImage() {
return invader;
}
#Override
public void paint(GameSpace gameSpace, Graphics2D g2d) {
g2d.drawImage(invader, getX(), getY(), gameSpace);
}
#Override
public boolean update(GameSpace gameSpace) {
return true;
}
}
public class ProjectileEntity extends AbstractEntity {
private int delta;
public ProjectileEntity(int delta) {
this.delta = delta;
}
#Override
protected int getWidth() {
return 10;
}
#Override
protected int getHeight() {
return 10;
}
#Override
public void paint(GameSpace gameSpace, Graphics2D g2d) {
g2d.setColor(Color.RED);
int width = getWidth();
int height = getHeight();
g2d.fillOval(getX() - width / 2, getY() - height / 2, width, height);
}
#Override
public boolean update(GameSpace gameSpace) {
int y = getY() + delta;
setY(getY() + delta);
return y + getHeight() >= 0 && y + getHeight() <= gameSpace.getGameSpace().height;
}
}
Basically, they contain the logic required for getting their jobs done.
Finally, you need to setup the actual game UI
public class GamePane extends JPanel implements GameSpace {
private Set<Input> inputs;
private Entity playerEntity;
private List<Entity> projectileEntities;
private List<Entity> invaderEntities;
private long timeOfLastProjectile = -1;
public GamePane() throws IOException {
setBackground(Color.BLACK);
inputs = new HashSet<>(2);
playerEntity = new ShipEntity(this);
projectileEntities = new ArrayList<>(25);
invaderEntities = new ArrayList<>(25);
InvaderEntity invader = new InvaderEntity();
invader.setX((getGameSpace().width - invader.getBounds().width) / 2);
invader.setY((getGameSpace().height - invader.getBounds().height) / 2);
invaderEntities.add(invader);
addKeyBinding(Input.LEFT, "left", KeyEvent.VK_LEFT);
addKeyBinding(Input.RIGHT, "right", KeyEvent.VK_RIGHT);
addKeyBinding(Input.SPACE, "space", KeyEvent.VK_SPACE);
Timer timer = new Timer(15, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
updateState();
processCollisions();
repaint();
}
});
timer.start();
}
#Override
public Dimension getPreferredSize() {
return new Dimension(800, 800);
}
protected void updateState() {
playerEntity.update(this);
if (hasInput(Input.SPACE)) {
long time = System.currentTimeMillis() - timeOfLastProjectile;
if (time < 0 || time > 1000) {
timeOfLastProjectile = System.currentTimeMillis();
Rectangle bounds = playerEntity.getBounds();
ProjectileEntity projectile = new ProjectileEntity(-1);
int x = bounds.x + ((bounds.width - projectile.getWidth()) / 2);
int y = bounds.y - projectile.getHeight();
projectile.setX(x);
projectile.setY(y);
projectileEntities.add(projectile);
}
}
for (Entity entity : invaderEntities) {
entity.update(this);
}
List<Entity> outOfBounds = new ArrayList<>(25);
for (Entity entity : projectileEntities) {
if (!entity.update(this)) {
outOfBounds.add(entity);
}
}
projectileEntities.removeAll(outOfBounds);
}
protected void processCollisions() {
Set<Entity> hitInvaders = new HashSet<>(25);
Set<Entity> hitProjectiles = new HashSet<>(25);
for (Entity invader : invaderEntities) {
for (Entity projectile : projectileEntities) {
if (projectile.getBounds().intersects(invader.getBounds())) {
// Maybe lots of cool explosiions
hitInvaders.add(invader);
hitProjectiles.add(projectile);
}
}
}
invaderEntities.removeAll(hitInvaders);
projectileEntities.removeAll(hitProjectiles);
}
protected void addKeyBinding(Input input, String name, int virtualKey) {
ActionMap am = getActionMap();
InputMap im = getInputMap(WHEN_IN_FOCUSED_WINDOW);
im.put(KeyStroke.getKeyStroke(virtualKey, 0, false), name + ".pressed");
im.put(KeyStroke.getKeyStroke(virtualKey, 0, true), name + ".released");
am.put(name + ".pressed", new KeyAction(inputs, input, true));
am.put(name + ".released", new KeyAction(inputs, input, false));
}
#Override
public Dimension getGameSpace() {
return getPreferredSize();
}
#Override
public boolean hasInput(Input input) {
return inputs.contains(input);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
playerEntity.paint(this, g2d);
g2d.dispose();
for (Entity entity : invaderEntities) {
g2d = (Graphics2D) g.create();
entity.paint(this, g2d);
g2d.dispose();
}
for (Entity entity : projectileEntities) {
g2d = (Graphics2D) g.create();
entity.paint(this, g2d);
g2d.dispose();
}
}
}
public class KeyAction extends AbstractAction {
private Input input;
private Set<Input> inputs;
private boolean pressed;
public KeyAction(Set<Input> inputs, Input input, boolean pressed) {
this.input = input;
this.inputs = inputs;
this.pressed = pressed;
}
#Override
public void actionPerformed(ActionEvent e) {
if (pressed) {
inputs.add(input);
} else {
inputs.remove(input);
}
}
}
Now you could go a little further and generate an "engine" class which controls the entities and performs all the required updating, but I'm lazy ;)
That's a really rough idea of some the basic concepts you need to develop to be able to move forward, hope it helps

Load a sprites image in java

I want to ask if why am getting error loading any sprite images into the object
here is how I get the image in.
import java.awt.image.BufferedImage;
import java.io.IOException;
public class SpriteSheet {
public BufferedImage sprite;
public BufferedImage[] sprites;
int width;
int height;
int rows;
int columns;
public SpriteSheet(int width, int height, int rows, int columns, BufferedImage ss) throws IOException {
this.width = width;
this.height = height;
this.rows = rows;
this.columns = columns;
this.sprite = ss;
for(int i = 0; i < rows; i++) {
for(int j = 0; j < columns; j++) {
sprites[(i * columns) + j] = ss.getSubimage(i * width, j * height, width, height);
}
}
}
}
here is how I'm implementing it
public BufferedImage[] init(){
BufferedImageLoader loader = new BufferedImageLoader();
BufferedImage spriteSheet = null;
SpriteSheet ss = null;
try {
spriteSheet = loader.loadImage("planet.png");
ss = new SpriteSheet(72,72,4,5,spriteSheet);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return ss.sprites;
}
I also want to ask about my way of using the sprites array. I want to use in the timer by changing the image drawn by action event by changing the current sprite image
tmr = new Timer(20, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
for(Rock r:rocks){
r.move();
r.changeSprite();
}
repaint();
}
});
with the method
public void changeSprite(){
if(ds==12)
ds=0;
ds++;
currentSprite = sprite[ds];
}
Each rock object has a sprite array full of Buffered image received from the sprite image loaded in and a current image which get drawn. the timer will change the current image and redrawn it on the object so that the whole sprite get drawn but it doesn't seem to work. So it is my loadingSpriteImage that have the problem or my way of drawing it causing the problem?
Okay, so there a lots of things we need to know.
How many images make up the sprite sheet, how they are laid out (rows/cols), if there is an uneven number of images (count != rows * cols) and possibly even the size of each sprite
How far we are through a given cycle (let's say a second)
So based on your image from a previous question...
we know there are 5 columns, 4 rows but only 19 images. Now you could spend a lot of time, write lots of code for each possible sprite sheet, or you could try and commensalism some of those problems...
public class SpriteSheet {
private final List<BufferedImage> sprites;
public SpriteSheet(List<BufferedImage> sprites) {
this.sprites = new ArrayList<>(sprites);
}
public int count() {
return sprites.size();
}
public BufferedImage getSprite(double progress) {
int frame = (int) (count() * progress);
return sprites.get(frame);
}
}
So, this is pretty basic, it's simply a list of images. The special part is the getSprite method, which takes a progression through the current animation cycle and returns an image based on the number of images you have available. This basically decouples the concept of time from the sprite and allows you to define the meaning of a "cycle" externally.
Now, because the actual process of building a SpriteSheet involves a lot of possible variables, a builder would be a good idea...
public class SpriteSheetBuilder {
private BufferedImage spriteSheet;
private int rows, cols;
private int spriteWidth, spriteHeight;
private int spriteCount;
public SpriteSheetBuilder withSheet(BufferedImage img) {
spriteSheet = img;
return this;
}
public SpriteSheetBuilder withRows(int rows) {
this.rows = rows;
return this;
}
public SpriteSheetBuilder withColumns(int cols) {
this.cols = cols;
return this;
}
public SpriteSheetBuilder withSpriteSize(int width, int height) {
this.spriteWidth = width;
this.spriteHeight = height;
return this;
}
public SpriteSheetBuilder withSpriteCount(int count) {
this.spriteCount = count;
return this;
}
protected int getSpriteCount() {
return spriteCount;
}
protected int getCols() {
return cols;
}
protected int getRows() {
return rows;
}
protected int getSpriteHeight() {
return spriteHeight;
}
protected BufferedImage getSpriteSheet() {
return spriteSheet;
}
protected int getSpriteWidth() {
return spriteWidth;
}
public SpriteSheet build() {
int count = getSpriteCount();
int rows = getRows();
int cols = getCols();
if (count == 0) {
count = rows * cols;
}
BufferedImage sheet = getSpriteSheet();
int width = getSpriteWidth();
int height = getSpriteHeight();
if (width == 0) {
width = sheet.getWidth() / cols;
}
if (height == 0) {
height = sheet.getHeight() / rows;
}
int x = 0;
int y = 0;
List<BufferedImage> sprites = new ArrayList<>(count);
for (int index = 0; index < count; index++) {
sprites.add(sheet.getSubimage(x, y, width, height));
x += width;
if (x >= width * cols) {
x = 0;
y += height;
}
}
return new SpriteSheet(sprites);
}
}
So, again, based on your sprite sheet, this means I could build a SpriteSheet using something like...
spriteSheet = new SpriteSheetBuilder().
withSheet(sheet).
withColumns(5).
withRows(4).
withSpriteCount(19).
build();
but it gives me the power to build any number of SpriteSheets, all of which might be made up of different matrices
But now that we have a SpriteSheet, we need some way to animate them, but what we really need is some way to calculate the progression through a given cycle (let's say a second is a cycle), we could use a simple "engine", something like...
public class SpriteEngine {
private Timer timer;
private int framesPerSecond;
private Long cycleStartTime;
private TimerHandler timerHandler;
private double cycleProgress;
private List<ActionListener> listeners;
public SpriteEngine(int fps) {
framesPerSecond = fps;
timerHandler = new TimerHandler();
listeners = new ArrayList<>(25);
}
public int getFramesPerSecond() {
return framesPerSecond;
}
public double getCycleProgress() {
return cycleProgress;
}
protected void invaldiate() {
cycleProgress = 0;
cycleStartTime = null;
}
public void stop() {
if (timer != null) {
timer.stop();
}
invaldiate();
}
public void start() {
stop();
timer = new Timer(1000 / framesPerSecond, timerHandler);
timer.start();
}
public void addActionListener(ActionListener actionListener) {
listeners.add(actionListener);
}
public void removeActionListener(ActionListener actionListener) {
listeners.remove(actionListener);
}
protected class TimerHandler implements ActionListener {
#Override
public void actionPerformed(ActionEvent e) {
if (cycleStartTime == null) {
cycleStartTime = System.currentTimeMillis();
}
long diff = (System.currentTimeMillis() - cycleStartTime) % 1000;
cycleProgress = diff / 1000.0;
ActionEvent ae = new ActionEvent(SpriteEngine.this, ActionEvent.ACTION_PERFORMED, e.getActionCommand());
for (ActionListener listener : listeners) {
listener.actionPerformed(ae);
}
}
}
}
Now, this is basically just a wrapper class for a Swing Timer, but what it does is it calculates the cycle progression for us. It also has nice ActionListener support, so we can be notified when a tick occurs
Okay, but how does that all work together?
Basically, given one or more SpriteSheets and a SpriteEngine, we can paint the sheets doing something like...
public class TestPane extends JPanel {
private SpriteSheet spriteSheet;
private SpriteEngine spriteEngine;
public TestPane() {
try {
BufferedImage sheet = ImageIO.read(...);
spriteSheet = new SpriteSheetBuilder().
withSheet(sheet).
withColumns(5).
withRows(4).
withSpriteCount(19).
build();
spriteEngine = new SpriteEngine(25);
spriteEngine.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
repaint();
}
});
spriteEngine.start();
} catch (IOException ex) {
ex.printStackTrace();
}
}
#Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
BufferedImage sprite = spriteSheet.getSprite(spriteEngine.getCycleProgress());
int x = (getWidth() - sprite.getWidth()) / 2;
int y = (getHeight() - sprite.getHeight()) / 2;
g2d.drawImage(sprite, x, y, this);
g2d.dispose();
}
}
Now, okay, that's pretty basic, but it gives an idea.
For entities you want to move (or rotate), I would create another class which contained that information AND the spriteSheet. This might contain a "paint" method or you could use the properties of the object to then paint the individual frames...
Something like...
public interface PaintableEntity {
public void paint(Graphics2D g2d, double progress);
}
public class AstroidEntity implements PaintableEntity {
private SpriteSheet spriteSheet;
private Point location;
private double angel;
public AstroidEntity(SpriteSheet spriteSheet) {
this.spriteSheet = spriteSheet;
location = new Point(0, 0);
angel = 0;
}
public void update() {
// Apply movement and rotation deltas...
}
public void paint(Graphics2D g2d, double progress) {
g2d.drawImage(
spriteSheet.getSprite(progress),
location.x,
location.y,
null);
}
}
Which could be created using something like...
private List<PaintableEntity> entities;
//...
entities = new ArrayList<>(10);
try {
BufferedImage sheet = ImageIO.read(new File("..."));
SpriteSheet spriteSheet = new SpriteSheetBuilder().
withSheet(sheet).
withColumns(5).
withRows(4).
withSpriteCount(19).
build();
for (int index = 0; index < 10; index++) {
entities.add(new AstroidEntity(spriteSheet));
}
} catch (IOException ex) {
ex.printStackTrace();
}
Note, I only created the sprite sheet once. This might require you to supply a random "offset" to the AstroidEntity which will change which frame it returns for a given progress value...
A simple way might be to add...
public SpriteSheet offsetBy(int amount) {
List<BufferedImage> images = new ArrayList<>(sprites);
Collections.rotate(images, amount);
return new SpriteSheet(images);
}
to SpriteSheet, then in AstroidEntity you could create an offset SpriteSheet using something like...
public AstroidEntity(SpriteSheet spriteSheet) {
this.spriteSheet = spriteSheet.offsetBy((int) (Math.random() * spriteSheet.count()));
Painting might be done using something like...
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
for (PaintableEntity entity : entities) {
entity.paint(g2d, spriteEngine.getCycleProgress());
}
g2d.dispose();
}
Basically, the key factor here is, try and decouple your code from a concept of "time".
For example, I changed the frames-per-second the engine was using to 60 and saw no change in the animation of the sprites, because it was working on the concept of a single cycle of time been 1 second. This would, however allow you to change the speed at which the objects moved relatively simply.
You could also set the engine up to have a concept of "cycle-length" and make it half a second or 5 seconds which would then affect the animation speed - but the rest of you code would remain unchanged!

BackGround in my JPanel, how can I resolve this?

Well my problem is that I'm making the stars move with a thread, they move verticaly and it works good but i do a random X for the star and sometimes it intersecs other stars like this :
This is my code for the JPanel:
class Backgroundmoving
public class Backgroundmoving extends JPanel {
ArrayList<starmoving> star;
public Backgroundmoving() {
this.setSize(650, 501);
star = new ArrayList<>();
for (int i = 0; i < 20; i++)
this.addStar();
}
public void addStar() {
int x, y;
x = (int) (Math.random() * 625);
y = (int) (Math.random() * 476);
starmoving e = new starmoving(x, y);
star.add(e);
Thread t = new Thread(e);
t.start();
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
draw(g);
}
public void draw(Graphics g) {
g.drawImage(new ImageIcon("background.png").getImage(), 0, 0, 650, 501, null);
for (int i = 0; i < star.size(); i++) {
star.get(i).draw(g);
}
repaint();
}
public static void main(String[] args) {
// TODO code application logic here
JFrame gui = new JFrame();
gui.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
gui.setSize(650, 510);
gui.setResizable(false);
gui.add(new Backgroundmoving());
gui.setVisible(true);
}
}
class starmoving
public class starmoving implements Runnable {
int x;
int y;
int yVel;
public starmoving(int x, int y) {
this.x = x;
this.y = y;
yVel = 1;
}
public int getX() {
return x;
}
public void setX(int x) {
this.x = x;
}
public int getY() {
return y;
}
public void setY(int y) {
this.y = y;
}
private void move() {
y += yVel;
if (y > 476) {
y = 0;
x = (int) (Math.random() * 625);
}
}
private boolean isOffScreen() {
if (y <= 476)
return false;
return true;
}
public void draw(Graphics g) {
g.drawImage(new ImageIcon("star.png").getImage(), x, y, 12, 12, null);
}
#Override
public void run() {
while (true) {
move();
try {
Thread.sleep(7);
} catch (InterruptedException ex) {
System.out.println(ex.getMessage());
}
}
}
}
i don't want stars intersecting, was thinking in a if before the random X but how can i know if other star is in that X ?
You have an ArrayList that contains all your "StarMoving" objects. So you need to iterate through that list to make sure that none of the object intersect.
On top of that you have other problems.
Use proper Java class names. Java classes SHOULD start with an upper case character. (ie. "starmoving" is wrong)
Don't use multiple Threads for the animation. You current code starts 20 Threads. You should have a single Thread and then iterate through your ArrayList to move all the stars.
Don't read the image in the draw() method. Currently you code is reading the image every 7ms. This is not very efficient. The image should be read once and then stored as a property of your class.

Why does this not draw my Polygon? (Java game)

Basically, all that shows up is a JFrame with the black JPanel inside but no Ball/polygon anywhere. It's really annoying me now and I can't see the reason why. Any help greatly appreciated.
EDIT: Added code. Sorry for posting to Github, didn't know it was frowned upon.
public class Board extends JFrame {
private int width = 800;
private int height = 1000;
private int currentKeyCode = 0;
private boolean keyHeldDown = false;
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
Board b = new Board();
b.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
public Board() {
setSize(width, height);
setTitle("Drop");
setBackground(Color.BLACK);
setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
addKeyListener(new KeyAdapter() {
#Override
public void keyPressed(KeyEvent e) {
if (e.getKeyCode() == KeyEvent.VK_RIGHT) {
currentKeyCode = KeyEvent.VK_RIGHT;
keyHeldDown = true;
System.out.println("Right + 10");
}
if (e.getKeyCode() == KeyEvent.VK_LEFT) {
currentKeyCode = KeyEvent.VK_LEFT;
keyHeldDown = true;
System.out.println("Left + 10");
}
if (e.getKeyCode() == KeyEvent.VK_P) {
currentKeyCode = KeyEvent.VK_P;
keyHeldDown = true;
System.out.println("Pause");
}
}
#Override
public void keyReleased(KeyEvent e) {
keyHeldDown = false;
}
});
setContentPane(new Panel(this));
ScheduledThreadPoolExecutor executor = new ScheduledThreadPoolExecutor(5);
executor.scheduleAtFixedRate(new RepaintBoard(this), 0L, 20L, TimeUnit.MILLISECONDS);
}
#Override
public int getWidth() {
return width;
}
public void setWidth(int width) {
this.width = width;
}
#Override
public int getHeight() {
return height;
}
public void setHeight(int height) {
this.height = height;
}
private class RepaintBoard implements Runnable {
final Board board;
public RepaintBoard(Board board) {
this.board = board;
}
#Override
public void run() {
board.repaint();
}
}
}
class Panel extends JComponent {
Ball ball;
private Board board;
public Panel(Board board) {
this.board = board;
ball = new Ball();
}
#Override
public void paint(Graphics g1) {
Graphics2D g = (Graphics2D) g1;
g.setColor(Color.BLACK);
g.drawRect(0, 0, board.getWidth(), board.getHeight());
g.drawPolygon(ball);
}
}
class Ball extends Polygon {
private int radius = 5;
private Point loc;
private int[] xPos = new int[radius * 2 + 1];
private int[] yPos = new int[radius * 2 + 1];
public Ball() {
for (int i = -radius, j = 0; i <= radius; i++, j++) {
xPos[j] = i;
yPos[j] = i;
}
new Ball(xPos, yPos, radius * 2 + 1, 100, 100);
}
public Ball(int[] xPos, int[] yPos, int points, int x, int y) {
super(xPos, yPos, points);
loc = new Point(x, y);
for (int i : xPos) {
System.out.println(i);
}
}
}
Don't have Ball extends Polygon
Put a drawBall(Grapchics g) {} method in the Ball class, and do your ball painting in there.
call the drawBall method in the paint
ball.drawBall(g);
Don't override paint, instead override paintComponent on the panel, and don't forget to call super.paintComponent
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
}
This new Ball(xPos, yPos, radius * 2 + 1, 100, 100); in your constructor does absolutely nothing. You should instead just use the second constructor, and create the ball with that constructor. Each ball should be different, so a no-arg constructor is pointless

Categories