Java: game slowing down while using affine transform - java

I want to create a game similar to SpaceInvaders, but instead of getting to the bottom of the screen, the aliens shoot projectiles. One type of aliens I wanted to create(in the code below), turns
to 45 degree and back. I tried it with affine transform, but everytime they turn the game slows down to half of the speed. The player and the projectiles are moving at half the speed then. The code below is the class that creates a JPanel
and draws everything.
import javax.swing.Timer;
import java.awt.event.*;
import java.awt.geom.*;
import java.awt.*;
import java.util.*;
import javax.swing.JPanel;
import javax.imageio.*;
import java.awt.image.BufferedImage;
import java.net.URL;
import java.io.IOException;
import javax.swing.*;
public class WELTZEICHNER2 extends JPanel implements ActionListener ,
KeyListener
{
Player p;
Timer t = new Timer (5, this);
ArrayList<ANGRIFF> ziele = new ArrayList<ANGRIFF>();
ArrayList<ANGRIFF> ziele2 = new ArrayList<ANGRIFF>();
ArrayList<ALIEN1> aliens1 = new ArrayList<ALIEN1>();
private boolean left,right,space;
private int lastshot = 100;
private int score =0;
BufferedImage image;
BufferedImage image2;
BufferedImage image3;
BufferedImage image4;
int count = 0;
int count2 = 0;
int d = 0;
public WELTZEICHNER2()
{
setDoubleBuffered(true);
p = new Player(500,900,100000);
t.start();
addKeyListener(this);
setFocusable(true);
URL resource = getClass().getResource("alien2.png");
URL resource2 = getClass().getResource("background.png");
URL resource3 = getClass().getResource("raumschifftest.png");
URL resource4 = getClass().getResource("kreislertest.png");
try {
image = ImageIO.read(resource);
} catch (IOException e) {
e.printStackTrace();
}
try {
image2 = ImageIO.read(resource2);
} catch (IOException e) {
e.printStackTrace();
}
try {
image3 = ImageIO.read(resource3);
} catch (IOException e) {
e.printStackTrace();
}
try {
image4 = ImageIO.read(resource4);
} catch (IOException e) {
e.printStackTrace();
}
for (int i= 0;i < 20;i++)
{
for (int j =0;j <5;j++)
{
aliens1.add(new ALIEN1(70+i*90,80+j*70,1));
}
}
}
public void erzeugeANGRIFF()
{
ANGRIFF b = new ANGRIFF(p.getxN() + 11, p.getyN(),true);
ziele2.add(b);
}
public void paintComponent(Graphics g)
{
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
g.drawImage(image2,1,1,this); //background image
g.drawImage(image3,p.getxN(),p.getyN(),this); //player image
for (ANGRIFF b : ziele)
{
g2.setColor(Color.RED);
g2.fill( new Ellipse2D.Double(b.getxN(),b.getyN(),5,10)); //alien´s projectiles
}
for (ANGRIFF b : ziele2)
{
g2.setColor(Color.GREEN);
g2.fill( new Ellipse2D.Double(b.getxN(),b.getyN(),5,10)); // player´s projectiles
}
for (ALIEN1 i : aliens1) //draw alien images
{
if(count2 > 10000)
{
AffineTransform trans = new AffineTransform();
trans.rotate(Math.toRadians(45), image4.getWidth() / 2, image4.getHeight() / 2);
BufferedImage rotated = new BufferedImage(image4.getWidth(),
image4.getHeight(), BufferedImage.TYPE_4BYTE_ABGR);
Graphics2D g3 = rotated.createGraphics();
g3.drawImage(image4, trans, null);
g2.drawImage(rotated,i.getxN(),i.getyN(),null);
}
else
{
g.drawImage(image4,i.getxN(),i.getyN(),this);
}
}
g2.setColor(Color.RED);
g2.drawString("Score:"+ score,5,15);
g2.drawString("Health:"+ p.health,5,30);
g2.drawString("Count:"+ count,5,45);
if(p.health == 0) //Game Over screen
{
g2.setColor(Color.BLACK);
g2.fill(new Rectangle2D.Double(1,1,1920,1080));
g2.setColor(Color.RED);
String text = "Game Over";
Font endtext = new Font("TimesNewRoman",Font.PLAIN, 200 );
g2.setFont(endtext);
g2.drawString(text,450,540);
}
}
public void actionPerformed(ActionEvent e)
{
if ( right == true)
{
p.right();
}
if (left == true)
{
p.left();
}
if(space == true && lastshot < 0)
{
erzeugeANGRIFF();
lastshot = 100;
}
lastshot -=1;
int bulletCount =ziele.size();
int bulletCount2 =ziele2.size();
int Alien1Count = aliens1.size();
ArrayList<Integer> remANGRIFF= new ArrayList<Integer>();
ArrayList<Integer> remANGRIFF2= new ArrayList<Integer>();
ArrayList<Integer>remAlien1=new ArrayList<Integer>();
for( int i = 0; i < bulletCount2;i++)
{
ANGRIFF b = ziele2.get(i);
b.bewegeANGRIFF();
if (b.getyN() >1000 )
{
remANGRIFF2.add(i);
}
for (int j =0;j< Alien1Count;j++ )
{
ALIEN1 n = aliens1.get(j);
if (b.checkCollision(n) && b.player == true)
{
n.health -=1;
score +=50;
if (n.health <= 0)
{
remAlien1.add(j);
score +=100;
}
remANGRIFF2.add(i);
}
}
}
for( int i = 0; i < bulletCount;i++)
{
ANGRIFF b = ziele.get(i);
b.bewegeANGRIFF();
if (b.getyN() < -100 )
{
remANGRIFF.add(i);
}
if (b.checkCollision(p) && b.player == false)
{
p.health -=50;
if (p.health <= 0)
{
p.health = 0;
}
remANGRIFF.add(i);
}
}
for (ALIEN1 i : aliens1)
{
// i.Bewegungsmuster();
count2++;
if(count2 > 20000)
{
count2 = 0;
}
if (i.newANGRIFF())
{
ziele.add(new ANGRIFF(i.getxN()+50,i.getyN()+50,false));
}
}
for (int i: remANGRIFF)
{
if(i < ziele.size())
{
ziele.remove(i);
}
}
for (int i: remANGRIFF2)
{
if(i < ziele2.size())
{
ziele2.remove(i);
}
}
for (int i: remAlien1)
{
if (i<aliens1.size())
{
aliens1.remove(i);
}
}
repaint();
}
public void keyPressed(KeyEvent e)
{
int code = e.getKeyCode();
if ( code == KeyEvent.VK_RIGHT)
{
right = true;
}
if ( code == KeyEvent.VK_LEFT)
{
left = true;
}
if ( code == KeyEvent.VK_SPACE)
{
space = true;
}
}
public void keyReleased(KeyEvent e)
{
int code = e.getKeyCode();
if ( code == KeyEvent.VK_RIGHT)
{
right = false;
}
if ( code == KeyEvent.VK_LEFT)
{
left = false;
}
if ( code == KeyEvent.VK_SPACE)
{
space = false;
lastshot =0;
}
}
public void keyTyped(KeyEvent e)
{
int code = e.getKeyCode();
if ( code == KeyEvent.VK_SPACE)
{
erzeugeANGRIFF();
}
}
}
This is the class that starts the game.
import javax.swing.*;
public class start
{
public static void main(String[] args)
{
//System.setProperty("sun.java2d.d3d", "true");
//System.setProperty("sun.java2d.noddraw", "false");
//-Dsun.java2d.noddraw=false;
JFrame f = new JFrame();
WELTZEICHNER2 d = new WELTZEICHNER2();
f.setSize(1920,1080);
f.setTitle("BlueJ Space Invader");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.add(d);
f.setVisible(true);
}
}
Any help is appreciated.

You're "core" problem is here...
if(count2 > 10000)
{
AffineTransform trans = new AffineTransform();
trans.rotate(Math.toRadians(45), image4.getWidth() / 2, image4.getHeight() / 2);
BufferedImage rotated = new BufferedImage(image4.getWidth(),
image4.getHeight(), BufferedImage.TYPE_4BYTE_ABGR);
Graphics2D g3 = rotated.createGraphics();
g3.drawImage(image4, trans, null);
g2.drawImage(rotated,i.getxN(),i.getyN(),null);
}
This is creating a number of short lived objects on every paint cycle, which is putting extra strain one the GC, slowing down your program - not to mention the time it takes to create a BufferedImage
A better solution is to simply rotate the current Graphics context. The problem with this is, it can become very complex very quickly.
So, basically what I would do, is I would use the AffineTransform to translate the origin point/offset to the position of the object you are painting. The rotation then becomes as simple as rotating about the centre point of the image and then painting the image at 0x0.
The trick is reseting the transform when you're finished. This is where creating another copy of the Graphics context before hand, applying the transform to it, painting the image and then disposing of the copy comes in very, very handy.
if (count2 > 10000) {
AffineTransform trans = new AffineTransform();
trans.translate(i.getxN(), i.getyN());
trans.rotate(Math.toRadians(45), image4.getWidth() / 2, image4.getHeight() / 2);
//BufferedImage rotated = new BufferedImage(image4.getWidth(),
//image4.getHeight(), BufferedImage.TYPE_4BYTE_ABGR);
Graphics2D g3 = (Graphics2D) g2.create();
g3.setTransform(trans);
//g3.drawImage(image4, trans, null);
g3.drawImage(image4, 0, 0, null);
g3.dispose();
}
When I was testing your code, I had witnessed an uneven frame rate. The ActionListener was been called at intervals in far greater values of 5 milliseconds. By the time it had performed 30, 000 cycles, it was already at an average of 75 milliseconds and slowly increasing, which suggest that you have some more issues to deal with.
Focus on the ArrayList and the creation/disposal of your objects and consider using "pools" of objects to further reduce the GC overhead where possible
You could have a look at Swing animation running extremely slow for an example.
PS # about 300, 000 cycles, the update cycle is up to an average of 200 milliseconds per update :P

Related

Java | How can I make one of the threads sleep while the other ones are still running?

I'm currently working on an application which uses the draw function to animate "bouncing images" in a JPanel. To accomplish it I had to learn to use threads. When I used them in my code someone recommended that instead of using threads directly I can use stuff like Executor framework and ExecutorService.
Right now my problem is that when adding new images I need to make sure that they don't get created inside each other. When the program detects that they would be intersecting it should wait some amount of time, while all the other threads keep running, so images are still getting moved and drawn in current positions.
What happens however is that when I make one of the threads sleep to wait for a spot to be empty the whole program seems to freeze. The only thing that seems to be running is the image moving function.
Code in a Github Gist
Here is the code:
This is the BouncingImages class
/* NOTE: requires MyImage.java */
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import javax.swing.*;
public class BouncingImages extends JFrame implements ActionListener {
public static void main(String[] args) {
new BouncingImages();
}
static boolean imagesLoaded = true;
JPanel resetPanel = new JPanel();
JPanel runningPanel = new JPanel();
JPanel pausedPanel = new JPanel();
JPanel btnPanel = new JPanel();
public static AnimationPanel animationPanel;
ArrayList <MyImage> imageList = new ArrayList <MyImage>();
private volatile boolean stopRequested = false; //maybe should use AtomicBoolean
boolean isRunning = false;
boolean isReset = true;
ExecutorService service = Executors.newCachedThreadPool();
Future f;
//here is the part of the code responsible for creating a JFrame
BouncingImages() {
//set up button panel
JButton btnStart = new JButton("Start");
JButton btnResume = new JButton("Resume");
JButton btnAdd = new JButton("Add");
JButton btnAdd10 = new JButton("Add 10");
JButton btnStop = new JButton("Stop");
JButton btnReset = new JButton("Reset");
JButton btnExit = new JButton("Exit");
btnStart.addActionListener(this);
btnResume.addActionListener(this);
btnAdd.addActionListener(this);
btnAdd10.addActionListener(this);
btnStop.addActionListener(this);
btnReset.addActionListener(this);
btnExit.addActionListener(this);
resetPanel.add(btnStart);
runningPanel.add(btnAdd);
runningPanel.add(btnAdd10);
runningPanel.add(btnStop);
pausedPanel.add(btnResume);
pausedPanel.add(btnReset);
animationPanel = new AnimationPanel();
resetButtons();
this.add(btnPanel, BorderLayout.SOUTH);
this.add(animationPanel);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.pack(); //since the JPanel is controlling the size, we need pack() here.
this.setLocationRelativeTo(null); //after pack();
this.setVisible(true);
}
//I use different JPanels with designated buttons to make them display different buttons when the program is running, paused or completely restarted.
public void resetButtons() {
btnPanel.updateUI();
if (isReset) {
btnPanel.removeAll();
btnPanel.add(resetPanel, BorderLayout.SOUTH);
} else {
if (isRunning) {
btnPanel.removeAll();
btnPanel.add(runningPanel, BorderLayout.SOUTH);
}
if (!isRunning) {
btnPanel.removeAll();
btnPanel.add(pausedPanel, BorderLayout.SOUTH);
}
}
}
//ActionListener for Buttons
#Override
public void actionPerformed(ActionEvent e) {
if (e.getActionCommand().equals("Start")) {
startAnimation();
isRunning = true;
isReset = false;
resetButtons();
}
if (e.getActionCommand().equals("Resume")) {
startAnimation();
isRunning = true;
resetButtons();
}
if (e.getActionCommand().equals("Add")) {
addImage();
}
if (e.getActionCommand().equals("Add 10")) {
for(int i = 0; i <10; i++) {
addImage();
startAnimation();
}
}
if (e.getActionCommand().equals("Stop")) {
pauseAnimation();
isRunning = false;
resetButtons();
}
if (e.getActionCommand().equals("Reset")) {
imageList.clear();
repaint();
isReset = true;
resetButtons();
}
if (e.getActionCommand().equals("Exit")) {
System.exit(0);
}
}
//This function starts all the animations using the Runnable AnimationThread
void startAnimation() {
//this starts the program
if (f == null) {
f = service.submit(new AnimationThread());
}
//this starts the program after it got paused
else if (f.isCancelled()) {
f = service.submit(new AnimationThread());
}
}
//this pauses all the animations
void pauseAnimation() {
f.cancel(true);
}
//here is the part of the code that I have problems with. I'm not sure how to make the program wait for a spot to be empty while all the other threads are running rather than pausing them all.
void addImage(){
int i = 0;
MyImage image;
while (true) {
image= new MyImage("image.png");
if (checkCollision(image)) {
if(i > 100){
System.out.println("Something went wrong");
System.exit(0);
}
try {
i++;
Thread.sleep(50);
} catch (InterruptedException e) {}
} else {
System.out.println("image added");
break;
}
}
imageList.add(image);
}
//this part of the program does all the image moving. It uses the function move image from the MyImage class and a checkCollision function from this class.
void moveAllImages() {
for (MyImage image : imageList) {
image.moveImage(animationPanel);
image.calculatePoints();
checkCollision(image);
}
}
//this checks all the collisions with other images. It can be used for checking if a image can be created in some spot and also for all the bouncing callculations
boolean checkCollision(MyImage currentImage){
if(imageList.isEmpty()) return false;
for(MyImage im : imageList){
if(currentImage == im) continue;
if(currentImage.intersects(im)){
if(im.contains(currentImage.ml) || im.contains(currentImage.mr)){
currentImage.undoMove();
currentImage.vx = -currentImage.vx;
return true;
}
}
if(im.contains(currentImage.mt) || im.contains(currentImage.mb)){
currentImage.undoMove();
currentImage.vy = - currentImage.vy;
return true;
}
if(currentImage.contains(im.ml) || currentImage.contains(im.mr)){
currentImage.undoMove();
currentImage.vx = -currentImage.vx;
return true;
}
if (im.contains(currentImage.tl) || im.contains(currentImage.tr) || im.contains(currentImage.bl) || im.contains(currentImage.br)) {
currentImage.undoMove();
currentImage.vx *= -1;
currentImage.vy *= -1;
return true;
}
}
return false;
}
//This class does drawing graphics and nothing else
public class AnimationPanel extends JPanel {
AnimationPanel() {
this.setBackground(Color.BLACK);
Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
this.setPreferredSize(new Dimension((int) screenSize.getWidth() / 2, (int) screenSize.getHeight() / 2));
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
for (MyImage im : imageList) {
g.drawImage(im.image, im.x, im.y, im.width, im.height, null);
}
}
}
//this is the Runnable AnimationThread which does all the image moving and repainting.
private class AnimationThread implements Runnable {
#Override
public void run() {
while (!f.isCancelled()) {
moveAllImages();
animationPanel.repaint();
try {
Thread.sleep(5);
}
catch (InterruptedException e) {
System.out.println(e.getMessage());
f.cancel(true);
}
}
}
}
}
This is the MyImage class
package bouncer;
import java.awt.Color;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
//NOTE: This class requires BouncingImages.java
/* This class combines an image with a rectangle
* which allows for easy movement and collision detection
*/
class MyImage extends Rectangle {
//this gives it an x,y,width,height
static int biggestDim = 0;
BufferedImage image;
Color color = Color.RED;
//these are the speeds of movement
int vx = 1;
int vy = 1;
int lastx = -1;
int lasty = -1;
Point ctr, tl, tr, bl, br, ml, mr, mt, mb;
MyImage(String filename) {
vx = (int) (Math.random() * 5 + 1);
vy = (int) (Math.random() * 5 + 1);
//load the image
try {
image = ImageIO.read(new File(filename));
width = image.getWidth(null);
height = image.getHeight(null);
}
catch (IOException e) {
System.out.println("ERROR: image file \"" + filename + "\" not found");
//e.printStackTrace();
BouncingImages.imagesLoaded = false;
width = 100 + (int) (Math.random() * 100);
height = width - (int) (Math.random() * 70);
color = Color.getHSBColor((float) Math.random(), 1.0f, 1.0f); // a quick way to get random colours
//System.exit(0);
}
//update the variable containing the biggest dimension
if (width > biggestDim) biggestDim = width;
if (height > biggestDim) biggestDim = height;
calculatePoints();
}
void calculatePoints() {
//Calculate points
//corners
tl = new Point(x, y);
tr = new Point(x + width, y);
bl = new Point(x, y + height);
br = new Point(x + width, y + height);
//center
ctr = new Point(x + width / 2, y + height / 2);
//mid points of sides
ml = new Point(x, y + height / 2);
mr = new Point(x + width, y + height / 2);
mt = new Point(x + width / 2, y);
mb = new Point(x + width / 2, y + height);
}
void moveImage(BouncingImages.AnimationPanel panel) {
lastx = x;
lasty = y;
x += vx;
y += vy;
if (x < 0 && vx < 0) {
x = 0;
vx = -vx;
}
if (y < 0 && vy < 0) {
y = 0;
vy = -vy;
}
if (x + width > panel.getWidth() && vx > 0) {
x = panel.getWidth() - width;
vx = -vx;
}
if (y + height > panel.getHeight() && vy > 0) {
y = panel.getHeight() - height;
vy = -vy;
}
}
void undoMove() {
if (lastx > 0) {
x = lastx;
y = lasty;
}
lastx = lasty = -1;
}
}
You are blocking the main thread in method addImage in Thread.sleep(50). Instead, you could ensure that you call method addImage asynchronously, e.g.
if (e.getActionCommand().equals("Add")) {
CompletableFuture.runAsync(this::addImage);
}
if (e.getActionCommand().equals("Add 10")) {
CompletableFuture.runAsync(() -> addImages(10));
}
with
private void addImages(int numberOfImages) {
for(int i = 0; i < numberOfImages; i++) {
addImage();
startAnimation();
}
}
If you want to experiment a bit more with threads, then you can think about how to do it "by hand".

How can I create a start screen for my java game? [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 7 years ago.
Improve this question
How can I make my applet so it goes to a start page and then to the game? So there is a Start Button, a Exit Button, and when I click the Start only then the game starts. Please answer in simple terms if possible since I am a beginner. Thanks :)
Main.java
import java.awt.Graphics;
public class Main extends GameLoop {
/**
*
*/
private static final long serialVersionUID = 1L;
public void init(){
setSize(960,540);
Thread th = new Thread(this);
th.start();
offscreen = createImage(960,540);
c = offscreen.getGraphics();
addKeyListener(this);
}
public void paint(Graphics g)
{
c.clearRect(0,0,960,480);
c.drawImage(background, 0, 0, this);
c.drawImage(mario, x, y, 100, 100, this);
c.drawImage(goomba, ax, ay, 30, 30, this);
c.drawImage(foreground, 0, 0 , this );
c.drawImage(pipes, 0, 0, this);
c.drawImage(block1, 0, 0, this);
c.drawImage(block2, 0, 0, this);
c.drawImage(block3, 0, 0, this);
c.drawImage(block4, 0, 0, this);
c.drawImage(block5, 0, 0, this);
c.drawImage(block6, 0, 0, this);
c.drawImage(block7 , 0, 0, this);
//c.drawImage(blocks, 0, 0, this);
g.drawImage(offscreen, 0 , 0 ,this);
}
#Override
public void update(Graphics g){
paint(g);
}
}
GameLoop.java
import java.applet.Applet;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
public class GameLoop extends Applet implements Runnable, KeyListener {
/**
*
*/
private static final long serialVersionUID = 1L;
public int x,y,ax,ay;
public Image offscreen;
public Graphics c;
public boolean jump,down,right,left;
public BufferedImage background, foreground, pipes, blocks, block1, block2, block3, block4, block5, block6, block7, walk2, walk3, walk4, walk5, walk6, jumpR,jumpL, mario, goomba, deadMario, money, block;
public BufferedImage Bblock1, Bblock2, Bblock3;
public int wow;
public int wow2;
public double counter = 4;
public int MaxH, MidH, MinH, delta;
#Override
public void run() {
x = 60;
y = 440;
ax = x +5;
ay = 493;
MinH = 440;
try {
background = ImageIO.read(new File("resources/background1.png"));
foreground = ImageIO.read(new File("resources/foreground1.png"));
blocks = ImageIO.read(new File("resources/blocks1.png"));
pipes = ImageIO.read(new File("resources/pipes1.png"));
walk2 = ImageIO.read(new File("resources/walk2.png"));
walk3 = ImageIO.read(new File("resources/walk3.png"));
walk4 = ImageIO.read(new File("resources/walk4.png"));
walk5 = ImageIO.read(new File("resources/walk5.png"));
walk6 = ImageIO.read(new File("resources/walk6.png"));
jumpR = ImageIO.read(new File("resources/jumpR.png"));
jumpL = ImageIO.read(new File("resources/jumpL.png"));
goomba = ImageIO.read(new File("resources/goomba.gif"));
deadMario = ImageIO.read(new File("resources/deadmario.png"));
money = ImageIO.read(new File("resources/money.png"));
block = ImageIO.read(new File("resources/Block.png"));
block1 = ImageIO.read(new File("resources/block1.png"));
block2 = ImageIO.read(new File("resources/block2.png"));
block3 = ImageIO.read(new File("resources/block3.png"));
block4 = ImageIO.read(new File("resources/block4.png"));
block5 = ImageIO.read(new File("resources/block5.png"));
block6 = ImageIO.read(new File("resources/blocks6.png"));
block7 = ImageIO.read(new File("resources/block7.png"));
Bblock1 = ImageIO.read(new File("resources/Bblock1.png"));
Bblock2 = ImageIO.read(new File("resources/Bblock2.png"));
Bblock3 = ImageIO.read(new File("resources/Bblock3.png"));
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
mario = walk2;
while(true)
{
if (y <=440&& jump != true){
y += 5;
}
if (y <=175){
y = MinH;
}
if(ax != 475 && ax < 475){
ax++;
}
if(ax >= 475 && ax != 60){
ax = ax - 475;
repaint();
}
if(x >= 468 && x <= 546){
y=385;
}
if(x >= 736 && x <= 826){
y=355;
}
if(x >= 160 && x <= 200 && y < 440 && y > 400){
y = MinH;
block1 = block;
}
if(x >= 264 && x <= 338 && y < 440 && y > 400){
y = MinH;
block3 = Bblock1;
}
if(x >= 339 && x <=410 && y < 440 && y > 400){
y = MinH;
block5 = Bblock2;
}
if (block1 == block && y >= 440){
c.drawImage(money, 210, 332,30,20, this);
}
if (block3 == Bblock1 && y >= 440){
c.drawImage(money, 337, 332,30,30, this);
}
if (block5 == Bblock2 && y >= 440){
c.drawImage(money, 395, 332,30,30, this);
}
wow++;
wow2++;
if(wow >= 20){
wow = 0;
}
if(wow <= 5 && right == true){
mario = walk2;
}
if(wow >= 5 && wow <=10 && right == true){
mario = walk2;
}
if(wow <= 10 && wow >=5 && right == true){
mario = walk5;
}
if(wow >= 10 && wow <=5 &&right == true){
mario = walk2;
}
if(wow2 >= 20){
wow2 = 0;
}
if(wow2 <= 5 && left == true){
mario = walk3;
}
if(wow2 >= 5 && left == true){
mario = walk6;
}
if(wow2 <= 10 && wow >=5 && left == true){
mario = walk6;
}
if(wow2 >= 10 && wow <=5 && left == true){
mario = walk3;
}
if(left == true){
x-=2;
}
if(right == true){
x+=2;
}
if(jump == true){
counter += 0.1;
y = y + (int) ((Math.sin(counter ) + Math.cos(counter))*15.5);
}
if(counter == 7){
counter = 4;
}
if(down == true){
y+=2;
}
if(y >= MinH ){
y = MinH;
}
System.out.println("(" + x + "," + y + ")");
repaint();
try {
Thread.sleep(20);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
#Override
public void keyTyped(KeyEvent e) {
// don't use
}
#Override
public void keyPressed(KeyEvent e) {
if(e.getKeyCode() == 37 ){
left = true;
}
if(e.getKeyCode() == 38){
jump = true;
mario = jumpR;
}
if(e.getKeyCode() == 39){
right = true;
}
if(e.getKeyCode() == 40){
down = true;
}
}
#Override
public void keyReleased(KeyEvent e) {
if(e.getKeyCode() == 37){
left = false;
mario = walk3;
}
if(e.getKeyCode() == 38){
jump = false;
mario = walk2;
counter = 4;
}
if(e.getKeyCode() == 39){
right = false;
mario = walk2;
}
if(e.getKeyCode() == 40){
down = false;
mario = walk2;
}
}
}
You need to keep up with states. For example you would have a START state and a RUNNING state. If the game is in the START state then you would draw the start screen, if it's in the RUNNING state you would draw your game. Later you may have a PAUSE state and a GAME_OVER state so you can show different screens there.
So to do this you will need a State enum like this:
public enum State
{
START, RUNNING, PAUSE, GAME_OVER;
}
Then in your GameLoop class create a variable to hold the current state.
private State state = State.START;
Then in your draw code and anywhere else necessary you can check the current state variable and draw the appropriate screen.
public void run()
{
switch(state)
{
case START:
//DRAW THE START SCREEN
break;
case RUNNING:
//DRAW THE GAME
break;
case PAUSE:
//DRAW THE PAUSE SCREEN
break;
case GAME_OVER:
//DRAW THE GAME OVER SCREEN
break;
default:
throw new RuntimeException("Unknown state: " + state);
}
}
A more clean solution would be to have a Screen class that has a draw method. Then your GameLoop just looks up the Screen associated with a given State and calls the draw method on it. This way your drawing code stays neatly tucked in to each Screen instead of all blobbed into one place. As your number of Screens grow you just add another Screen implementation. Here is some code to show what I mean:
Here is a Screen interface. You will have a Screen implementation for each State.
public interface Screen
{
void update();
void draw();
void handleInput();
}
Here is an empty example of a RunningScreen.
public class RunningScreen implements Screen
{
#Override
public void update()
{
//UPDATE LOGIC, MOVE ENTITIES OR WHATEVER
}
#Override
public void draw()
{
//DRAW THE RUNNING SCREEN
}
#Override
public void handleInput()
{
//CHECK FOR USER INPUT AND UPDATE THE SCREEN STATE
}
}
Here is an empty example of a StartScreen.
public class StartScreen implements Screen
{
#Override
public void update()
{
//UPDATE THE START SCREEN
}
#Override
public void draw()
{
//DRAW THE START SCREEN
}
#Override
public void handleInput()
{
//CHECK FOR INPUT, TRANSITION TO THE RUNNING SCREEN WHEN THE USER CLICKS START
}
}
Your game loop looks up the Screen that is registered to handle the current state, then calls the appropriate methods.
public class GameLoop
{
private State state = State.START;
private Map<State, Screen> screens = new HashMap<>();
public void addScreen(State state, Screen screen)
{
screens.put(state, screen);
}
public void run()
{
Screen screen = screens.get(state);
screen.handleInput();
screen.update();
screen.draw();
}
}
Then your Main might look something like this. It creates a new GameLoop and registers the Screens for each state.
public class Main
{
public static void main(String[] args)
{
GameLoop game = new GameLoop();
game.addScreen(State.START, new StartScreen());
game.addScreen(State.RUNNING, new RunningScreen());
//Add other states here
game.run();
}
}
I hope this gives you some ideas about how to implement the functionality you want.

how can i use an array to make random circles

I have been working on a school assignment and the teacher wants us to make 7 circles appear on a JPanel and move downwards. Once a circle reaches the bottom a new circle should be made to replace the circle that reached the bottom of the JPanel. I decided to use an array to continue to make random circles but I cant get it to work right. I used a for loop to populate the array with circles that have a random radius and color. The code compiles but when I run it I get an exception. I am having a hard time getting the array to work properly. The other thing that I am not sure about is how to draw the circles so that they are space out across the JPanel.
The Code
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.awt.geom.*;
import java.util.Random;
public class keyExample extends JPanel implements ActionListener, KeyListener {
private Circle[] circles = new Circle[7];
Timer t = new Timer(5, this);
//current x and y
double x = 150, y = 200;
double changeX = 0, changeY = 0;
private Circle;
private int circlex = 0, circley = 0; // makes initial starting point of circles 0
private javax.swing.Timer timer2;
public keyExample() {
t.start();
addKeyListener(this);
setFocusable(true);
setFocusTraversalKeysEnabled(false);
}
timer2 = new javax.swing.Timer(33, new MoveListener());
timer2.start();
}
public void NewCircle() {
Random colors = new Random();
Color color = new Color(colors.nextInt(256), colors.nextInt(256), colors.nextInt(256));
Random num = new Random();
int radius = num.nextInt(45);
for (int i = 0; i < circles.length; i++) {
circles[i] = new Circle(circlex, circley, radius, color);
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
g2.setColor(Color.BLUE);
g2.fill(new Rectangle2D.Double(x, y, 40, 40));
NewCircle();
for (int i = 0; i < circles.length; i++)
circles[i].fill(g);
}
public void actionPerformed(ActionEvent e) {
repaint();
x += changeX;
y += changeY;
changeX = 0;
changeY = 0;
}
public void up() {
if (y != 0) {
changeY = -3.5;
changeX = 0;
}
}
public void down() {
if (y <= 350) {
changeY = 3.5;
changeX = 0;
}
}
public void left() {
if (x >= 0) {
changeX = -3.5;
changeY = 0;
}
}
public void right() {
if (x <= 550) {
changeX = 3.5;
changeY = 0;
}
}
private class MoveListener implements ActionListener {
public void actionPerformed(ActionEvent e) {
repaint();
Random speed = new Random();
int s = speed.nextInt(8);
circle.move(0, s);
}
}
public void keyPressed(KeyEvent e) {
int code = e.getKeyCode();
if (code == KeyEvent.VK_UP) {
up();
}
if (code == KeyEvent.VK_DOWN) {
down();
}
if (code == KeyEvent.VK_RIGHT) {
right();
}
if (code == KeyEvent.VK_LEFT) {
left();
}
}
public void keyTyped(KeyEvent e) {
}
public void keyReleased(KeyEvent e) {
}
}
Your problem is that you're trying to paint with the circle variable, a variable that you never assign a valid reference to.
One solution is to give it a valid reference via circle = new Circle(...), but having said that, I'll tell you to ignore it since you shouldn't even be using the variable circle. Just get rid of it. What you want to do is to use your circles array -- that's what you should be painting in your paintComponent method. Use a for loop inside of paintComponent and iterate through the array painting each circle item that the array holds.

Eclipse Indigo bug

I have been running Eclipse Indigo for a few months now, and I have run into a bug that I cannot seem to find an answer to. I am creating a small 2d side-scroller game similar to that of mario, the old zelda, etc.
I was going to show a my dad what new feature I had added into my program. Instead of coming upstairs to see my program on my computer, my dad decided that he could get into it using a sudo screen-viewing thing that I am not sure of. We have used this before, and basically all it does is let you see the screen of another computer in your home (on the same IP interface), and you can use the computer too.
I didn't want to show my program to my dad this way, so I told him to come upstairs. He did, and ever since then, eclipse will not show any graphics inside of your JFrame in your program. It will show things such as words (written on the screen), but will not show ANY graphics. Such as your background image, or your character, or anything else. I am POSITIVE that it isn't some problem with my coding, because I had tested and played the game quite a few times before my dad did the screen-viewing thing (we are both on linux mint 12, BTW).
I think that this bug is related to the screen-viewing thing.
I would love it if I could get some help. any would be great. Thanks.
-This has been solved*
Board
package External;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import javax.swing.*;
public class Board extends JPanel implements ActionListener, Runnable {
Dude p;
Image img;
Timer time;
int v = 172;
Thread animator;
boolean a = false;
boolean done2 = false;
public Board() {
p = new Dude();
addKeyListener(new AL());
setFocusable(true);
ImageIcon i = new ImageIcon ("/home/clark/Desktop/Swindle_test_background.png");
img = i.getImage();
time = new Timer (3, this);
time.start();
}
public void actionPerformed(ActionEvent e) {
p.move();
repaint();
}
public void paint(Graphics g) {
if (p.dy == 1 && done2 == false)
{
done2 = true;
animator = new Thread(this);
animator.start();
}
super.paint(g);
Graphics2D g2d = (Graphics2D) g;
if ((p.getX() - 590) % 2400 == 0)
p.nx = 0;
if ((p.getX() - 1790) % 2400 == 0)
p.nx2 = 0;
g2d.drawImage(img, 985-p.nx2, 0, null);
if (p.getX() >= 921)
g2d.drawImage(img, 985-p.nx, 0, null);
g2d.drawImage(p.getImage(), 75, v, null);
}
private class AL extends KeyAdapter {
public void keyReleased(KeyEvent e) {
p.keyReleased(e);
}
public void keyPressed(KeyEvent e) {
p.keyPressed(e);
}
}
boolean h = false;
boolean done = false;
public void cycle() {
if (h == false)
v--;
if (v == 125)
h = true;
if (h == true && v <= 172 ) {
v++;
if (v == 172) {
done = true;
}
}
}
public void run() {
long beforeTime, timeDiff, sleep;
beforeTime = System.currentTimeMillis();
while (done == false) {
cycle();
timeDiff = System.currentTimeMillis() - beforeTime;
sleep = 10 - timeDiff;
if (sleep < 0)
sleep = 2;
try {
Thread.sleep(sleep);
} catch (InterruptedException e) {
System.out.println("interrupted");
}
beforeTime = System.currentTimeMillis();
}
done = false;
h = false;
done2 = false;
}
}
Dude
package External;
import java.awt.Image;
import java.awt.event.KeyEvent;
import javax.swing.ImageIcon;
public class Dude {
int x, dx, y, nx2, nx, dy;
Image Swindle_Man_Right;
ImageIcon r = new ImageIcon("/home/clark/Desktop/Swindle_Man_Right.png");
ImageIcon l = new ImageIcon("/home/clark/Desktop/Swindle_Man_Left.png");
ImageIcon j = new ImageIcon("/home/clark/Desktop/Swindle_Man_Jump.png");
public Dude() {
Swindle_Man_Right = l.getImage();
x = 75;
nx2 = 685;
nx = 0;
y = 172;
}
public void move() {
x = x + dx;
nx2 = nx2 + dx;
nx = nx + dx;
}
public int getX() {
return x;
}
public int getY() {
return y;
}
public Image getImage() {
return Swindle_Man_Right;
}
public void keyPressed(KeyEvent e) {
int key = e.getKeyCode();
if (key == KeyEvent.VK_LEFT)
{ dx = -1;
Swindle_Man_Right = l.getImage();
}
if (key == KeyEvent.VK_RIGHT)
{dx = 1;
Swindle_Man_Right = r.getImage();
}
if (key == KeyEvent.VK_UP)
{dy = 1;
Swindle_Man_Right= j.getImage();
} }
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;
Swindle_Man_Right= r.getImage();}
}
}
Frame
package External;
import javax.swing.*;
public class Frame {
public Frame() {
JFrame frame = new JFrame("Swindle [version 0.1.9]");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(700,390);
frame.setResizable(false);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
new Frame();
}
}
As near as I can tell, you've not added anything to the frame.
After I replaced the graphics with my own, I was able to get it running...
public class Frame {
public static void main(String[] args) {
new Frame();
}
public Frame() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
}
JFrame frame = new JFrame("Swindle [version 0.1.9]");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
// This is kind of important...
frame.add(new Board());
frame.setSize(700, 390);
frame.setResizable(false);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
}
While I've only given the code quick glance, I would recommend that you don't use ImageIcon to load you images and instead use the ImageIO API. Apart from supporting more image formats, it will throw more errors when it can't load the images.
I would also avoid using KeyListener in favor of key bindings. They don't suffer from the same focus issues as KeyListener

Running Game in a Java Applet

I have written a small 2d scroller with the assistance of different snippets of code I have found on-line. The original package run as a JFrame application but I am trying to convert it into an applet. When I Run the program in Eclipse I do not receive any debugging errors just a blank applet viewer... I don't think I am missing anything from what I have read from different applet creation sources but maybe it is something very simple.
Frame class
package OurGame;
import java.awt.*;
import javax.swing.*;
public class Frame extends JApplet {
public Frame() {
JPanel frame = new JPanel();
frame.add(new Board());
// frame.setTitle("2D PLATFORMER");
// frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(700,365);
frame.setVisible(true);
//frame.setLocationRelativeTo(null);
//setContentPane(frame);
}
// public static void main(String[] args){
public void init() {
new Frame();
}
}
Ive commented out the containers that were only workable in Jframe.
Dude class
package OurGame;
import java.awt.*;
import java.awt.event.KeyEvent;
import javax.swing.ImageIcon;
public class Dude {
int x, dx, y,nx,nx2,left, dy;
Image still,jump,reverse;
ImageIcon s = new ImageIcon("redirect.png");
ImageIcon j= new ImageIcon("redirect.png");
ImageIcon l = new ImageIcon("redirect.png");
public Dude() {
x = 75;
left = 150;
nx = 0;
nx2= 685;
y = 172;
still = s.getImage();
}
public void move() {
if (dx != -1){
if (left + dx <= 150)
left+=dx;
else{
x = x + dx;
nx2= nx2+dx;
nx = nx + dx;
}}
else
{
if (left+dx >0)
left = left + dx;
}
}
public int getX() {
return x;
}
public int getnX() {
return nx;
}
public int getnX2() {
return nx2;
}
public int getdx() {
return dx;
}
public Image getImage() {
return still;
}
public void keyPressed(KeyEvent e) {
int key = e.getKeyCode();
if (key == KeyEvent.VK_LEFT)
{ dx = -1;
still = l.getImage(); }
if (key == KeyEvent.VK_RIGHT)
{dx = 1;
still = s.getImage();
}
if (key == KeyEvent.VK_UP)
{dy = 1;
still = j.getImage();
} }
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;
still = s.getImage();}
}
}
Board Class
package OurGame;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class Board extends JPanel implements ActionListener, Runnable {
Dude p;
public Image img;
Timer time;
int v = 172;
Thread animator;
boolean a = false;
boolean done2 = false;
public Board() {
p = new Dude();
addKeyListener(new AL());
setFocusable(true);
ImageIcon i = new ImageIcon("redirect.jpg");
img = i.getImage();
time = new Timer(5, this);
time.start();
}
public void actionPerformed(ActionEvent e) {
p.move();
repaint();
}
public void paint(Graphics g) {
if (p.dy == 1 && done2 == false) {
done2 = true;
animator = new Thread(this);
animator.start();
}
super.paint(g);
Graphics2D g2d = (Graphics2D) g;
if ((p.getX() - 590) % 2400 == 0)// p.getX() == 590 || p.getX() == 2990)
p.nx = 0;
if ((p.getX() - 1790) % 2400 == 0)// p.getX() == 1790 || p.getX() == 4190)
p.nx2 = 0;
g2d.drawImage(img, 685 - p.getnX2(), 0, null);
if (p.getX() > 590) {
g2d.drawImage(img, 685 - p.getnX(), 0, null);
}
g2d.drawImage(p.getImage(), p.left, v, null);
if (p.getdx() == -1) {
g2d.drawImage(img, 685 - p.getnX2(), 0, null);
g2d.drawImage(p.getImage(), p.left, v, null);
}
}
private class AL extends KeyAdapter {
public void keyReleased(KeyEvent e) {
p.keyReleased(e);
}
public void keyPressed(KeyEvent e) {
p.keyPressed(e);
}
}
boolean h = false;
boolean done = false;
public void cycle() {
if (h == false)
v--;
if (v == 125)
h = true;
if (h == true && v <= 172) {
v++;
if (v == 172) {
done = true;
}
}
}
public void run() {
long beforeTime, timeDiff, sleep;
beforeTime = System.currentTimeMillis();
while (done == false) {
cycle();
timeDiff = System.currentTimeMillis() - beforeTime;
sleep = 10 - timeDiff;
if (sleep < 0)
sleep = 2;
try {
Thread.sleep(sleep);
} catch (InterruptedException e) {
System.out.println("interrupted");
}
beforeTime = System.currentTimeMillis();
}
done = false;
h = false;
done2 = false;
}
}
I am a little stumbled after doing a fair amount of research. I am thinking Eclipse might not recognise that I have multiple class files but I kind of proved that theory wrong by writing a html page to display my applet that runs fine but is completely empty.
why is the applet viewer even in eclipse blank when running it..
At no point is anything added to the applet container. To add something to the applet would require overriding the applet init() method and calling add(new Board());. (That could also be done in the constructor, but it is more common to build an applet GUI within the init() method.)
Other Notes
paint(Graphics)
Since Board is a Swing class that is not a top-level container, custom painting should be done in the paintComponent(Graphics) method, rather than paint(Graphics).
Nomenclature
JPanel frame = new JPanel();
Wow! Poorly chosen attribute name. What do you call your JFrame instances, panel?
Application resources
ImageIcon s = new ImageIcon("redirect.png");
This will not work for an applet, and would not work for a deployed app. It is necessary to access images by URL. The Applet class has a specific method for loading images.
Remaining lines of constructor
JPanel frame = new JPanel();
frame.add(new Board());
frame.setSize(700,365);
frame.setVisible(true);
The first line of the constructor is not needed, the Board created in the next line can be added directly to the applet. That leaves two more lines not commented out.
frame.setSize(700,365);
The size of an applet should be set by the HTML.
frame.setVisible(true);
Anything added to a component that is visible will itself become visible. As such, this is also redundant.
Swing Timer
Since I pointed out so many faults in the code, just thought I should add that the animation seems to be done correctly - using a Swing Timer. :)

Categories

Resources