Related
For some reason there are two player speeds in my game Orange Quest. What I mean by this is when I test my game in eclipse and my headphones are off. The game goes twice as fast as when my headphones are on.
I sent the game to my friend and he also experiences the same problems. I've tried to debug the code to see if there was a something wrong with it, but I didn't see any problem. I also tried to adjust the player speed but that didn't help either, as it was still going twice as fast when my headphones were off.
Here is the code for the game panel
Oh yah, by the way the frame is 700 by 700
import javax.imageio.ImageIO;
import javax.swing.*;
import java.awt.event.*;
import java.awt.image.BufferedImage;
import java.awt.*;
import java.util.*;
import java.util.concurrent.CopyOnWriteArrayList;
public class GamePanel extends JPanel implements ActionListener {
/**
*
*/
private static final long serialVersionUID = 1L;
Player player;
boolean running = true;
CopyOnWriteArrayList<Wall> walls = new CopyOnWriteArrayList<>();
CopyOnWriteArrayList<LavaWall> lavaWalls = new CopyOnWriteArrayList<>();
CopyOnWriteArrayList<Enemy> enemies = new CopyOnWriteArrayList<>();
CopyOnWriteArrayList<Orange> oranges = new CopyOnWriteArrayList<>();
java.util.Timer gameTimer;
int cameraX;
int offset;
int count = 0;
int index = 0;
int set;
int s = 50;
int r = 75;
BufferedImage dirt;
BufferedImage grass;
BufferedImage lava;
BufferedImage cloud;
BufferedImage spike;
BufferedImage undergroundLava;
BufferedImage character;
BufferedImage thumbnail;
JLabel timeLabel = new JLabel();
JLabel orangeLabel = new JLabel(": 0/7");
double orangeCount = 0;
int elapsedTime = 0;
int minutes = 0;
int seconds = 0;
int ms = 0;
String minutesString = String.format("%02d", minutes);
String secondsString = String.format("%02d", seconds);
String msString = String.format("%02d", ms);
java.util.Timer timer = new java.util.Timer();
TimerTask task = new TimerTask() {
#Override
public void run() {
elapsedTime += 10;
minutes = (elapsedTime / 60000);
seconds = (elapsedTime / 1000) % 60;
ms = (elapsedTime / 10) % 100;
minutesString = String.format("%02d", minutes);
secondsString = String.format("%02d", seconds);
msString = String.format("%02d", ms);
timeLabel.setText(minutesString + ":" + secondsString + ":" + msString);
}
};
GamePanel() {
if (running) {
player = new Player(400, 300, this);
reset();
setLayout(null);
gameTimer = new java.util.Timer();
add(player.death);
player.death.setBounds(550, 15, 300, 100);
player.death.setFont(new Font("Verdana", Font.PLAIN, 20));
add(orangeLabel);
orangeLabel.setBounds(320, 15, 200, 50);
orangeLabel.setFont(new Font("Verdana", Font.PLAIN, 20));
gameTimer.schedule(new TimerTask() {
#Override
public void run() {
try {
if (walls.get(walls.size() - 1).x < 800) {
offset += 700;
makeWalls(offset);
}
player.set();
for (Wall wall : walls)
wall.set(cameraX);
for (int i = 0; i < walls.size(); i++) {
if (walls.get(i).x < -800)
walls.remove(i);
}for(Enemy enemy : enemies)
enemy.set(cameraX);
for (LavaWall lava : lavaWalls)
lava.set(cameraX);
for (int i = 0; i < lavaWalls.size(); i++) {
if (lavaWalls.get(i).x < -800)
lavaWalls.remove(i);
}
for(Orange orange : oranges)
orange.set(cameraX);
for(int i = 0; i < oranges.size(); i++) {
if(oranges.get(i).x < -800)
oranges.remove(i);
}
repaint();
} catch (Throwable e) {
e.printStackTrace();
}
}
}, 0, 17);
add(timeLabel);
timeLabel.setText(minutesString + ":" + secondsString + ":" + msString);
timeLabel.setBounds(10, 15, 300, 100);
timeLabel.setFont(new Font("Verdana", Font.PLAIN, 25));
timer.scheduleAtFixedRate(task, 0, 10);
} else if (!running) {
System.exit(0);
}
}
public void makeWalls(int offset) {
Random rnd = new Random();
try {
dirt = ImageIO.read(getClass().getResourceAsStream("/art/dirt block.png"));
grass = ImageIO.read(getClass().getResourceAsStream("/art/grass block.png"));
lava = ImageIO.read(getClass().getResourceAsStream("/art/lava block.png"));
cloud = ImageIO.read(getClass().getResourceAsStream("/art/cloud block.png"));
undergroundLava = ImageIO.read(getClass().getResourceAsStream("/art/underground lava.png"));
thumbnail = ImageIO.read(getClass().getResourceAsStream("/art/thumbnail.png"));
} catch (Exception e) {
e.printStackTrace();
}
if (count == 7) {
oranges.add(new Orange(offset + 50, 500, s, s, thumbnail));
for (int i = 1; i <= 14; i++) {
walls.add(new Wall(offset + i * 50, 600, s, s, grass));
walls.add(new Wall(offset + i * 50, 650, s, s, dirt));
}
}
else if(count != 10) {
if (index == 0) {
for (int i = 1; i <= 14; i++) {
walls.add(new Wall(offset + i * 50, 600, s, s, grass));
walls.add(new Wall(offset + i * 50, 650, s, s, dirt));
if(i == 6) {
enemies.add(new Enemy(offset + 350, 550, r, s));
}
}
set = 0;
} else if (index == 1) {
for (int j = 1; j <= 14; j++) {
for (int i = 650; i >= 350; i -= 50) {
if (i == 350)
walls.add(new Wall(offset, i, s, s, grass));
else
walls.add(new Wall(offset, i, s, s, dirt));
}
offset += 50;
set = 1;
}
} else if (index == 2) {
if(set == 0) {
walls.add(new Wall(offset - 50, 500, s, s, cloud));
walls.add(new Wall(offset - 200, 400, s, s, cloud));
walls.add(new Wall(offset, 300, s, s, cloud));
for (int i = 0; i < 9; i++) {
walls.add(new Wall(offset + 300 + i * 50, 600, s, s, grass));
walls.add(new Wall(offset + 300 + i * 50, 650, s, s, dirt));
}
}else {
for (int i = 1; i <= 14; i++) {
walls.add(new Wall(offset + i * 50, 600, s, s, grass));
walls.add(new Wall(offset + i * 50, 650, s, s, dirt));
if(i == 6) {
enemies.add(new Enemy(offset + 350, 550, r, s));
}
}
}
} else if (index == 3) {
for (int i = 1; i <= 2; i++) {
walls.add(new Wall(offset + i * 50, 600, s, s, grass));
walls.add(new Wall(offset + i * 50, 650, s, s, dirt));
}
lavaWalls.add(new LavaWall(offset + 150, 600, s, s, lava));
lavaWalls.add(new LavaWall(offset + 200, 600, s, s, lava));
lavaWalls.add(new LavaWall(offset + 250, 600, s, s, lava));
lavaWalls.add(new LavaWall(offset + 300, 600, s, s, lava));
lavaWalls.add(new LavaWall(offset + 350, 600, s, s, lava));
lavaWalls.add(new LavaWall(offset + 150, 650, s, s, undergroundLava));
lavaWalls.add(new LavaWall(offset + 200, 650, s, s, undergroundLava));
lavaWalls.add(new LavaWall(offset + 250, 650, s, s, undergroundLava));
lavaWalls.add(new LavaWall(offset + 300, 650, s, s, undergroundLava));
lavaWalls.add(new LavaWall(offset + 350, 650, s, s, undergroundLava));
for (int i = 6; i <= 12; i++) {
walls.add(new Wall(offset + 100 + i * 50, 600, s, s, grass));
walls.add(new Wall(offset + 100 + i * 50, 650, s, s, dirt));
}
}
for(Wall wall : walls) {
for(LavaWall lava : lavaWalls) {
if(lava.hitBox.getBounds() == wall.hitBox.getBounds()) {
lavaWalls.remove(lava);
}
}
}
count++;
index = rnd.nextInt(4);
}
}
public void reset() {
count = 0;
index = 0;
player.x = 200;
player.y = 150;
cameraX = 150;
player.xspeed = 0;
player.yspeed = 0;
walls.clear();
enemies.clear();
lavaWalls.clear();
oranges.clear();
offset = -150;
makeWalls(offset);
player.isDed = false;
}
public void paint(Graphics g) {
try {
super.paint(g);
Graphics2D gtd = (Graphics2D) g;
player.draw(gtd);
for(int i = 0; i < walls.size(); i++) {
try {
walls.get(i).draw(gtd);
} catch (Throwable e) {
}
}for(Enemy enemy : enemies)
enemy.draw(gtd);
for(LavaWall lava : lavaWalls)
lava.draw(gtd);
g.drawImage(thumbnail, 270, 15, 50, 50, null);
for(Orange orange : oranges)
orange.draw(gtd);
} catch (Throwable e) {
e.printStackTrace();
}
}
#Override
public void actionPerformed(ActionEvent e) {
}
public void keyPressed(KeyEvent e) {
if (e.getKeyChar() == 'a')
player.keyLeft = true;
if (e.getKeyChar() == 'w' || e.getKeyCode() == 32)
player.keyUp = true;
if (e.getKeyChar() == 's')
player.keyDown = true;
if (e.getKeyChar() == 'd')
player.keyRight = true;
if (e.getKeyChar() == 'h')
Player.keyGlide = true;
if (e.getKeyChar() == 'j')
player.keyMega = true;
if (e.getKeyChar() == 'l')
player.keyRush = true;
}
public void keyReleased(KeyEvent e) {
if (e.getKeyChar() == 'a')
player.keyLeft = false;
if (e.getKeyChar() == 'w' || e.getKeyCode() == 32)
player.keyUp = false;
if (e.getKeyChar() == 's')
player.keyDown = false;
if (e.getKeyChar() == 'd')
player.keyRight = false;
if (e.getKeyCode() == 27)
System.exit(0);
if (e.getKeyChar() == 'h')
Player.keyGlide = false;
if (e.getKeyChar() == 'j')
player.keyMega = false;
if (e.getKeyChar() == 'l')
player.keyRush = false;
}
}
and here is the player code
import java.awt.*;
import java.awt.event.*;
import java.io.File;
import java.io.IOException;
import java.util.Iterator;
import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.Clip;
import javax.swing.*;
public class Player {
GamePanel panel;
int x;
int y;
int width;
int height;
double xspeed;
double yspeed;
boolean keyLeft;
boolean keyRight;
boolean keyUp;
static boolean keyGlide;
boolean keyDown;
boolean keyMega;
boolean keyRush;
boolean falling;
boolean isDeathSound;
boolean isDed;
Graphics2D gtd;
long time = 0;
Timer timer;
long start;
long stop;
double deaths = 0;
JLabel death = new JLabel("Deaths: 0");
Rectangle hitBox;
long waitTime;
static Clip clip;
static boolean onGround;
Player(){
}
Player(int x, int y, GamePanel panel){
this.panel = panel;
this.x = x;
this.y = y;
width = 50;
height = 100;
hitBox = new Rectangle(x, y, width, height);
}
public void set() throws Throwable{
Iterator<Orange> orangeItr = panel.oranges.iterator();
if(keyLeft && keyRight || !keyLeft && !keyRight) xspeed *= 0.8;
else if(keyLeft && !keyRight)xspeed--;
else if(keyRight && !keyLeft)xspeed++;
if(keyUp && keyGlide) {keyUp = false;}
if(yspeed > 0)onGround = false;
if(keyMega && keyGlide) {keyMega = false;}
if(onGround && keyGlide)keyGlide = false;
if(xspeed > 0 && xspeed < 0.75)xspeed = 0;
if(xspeed < 0 && xspeed > -0.75)xspeed = 0;
if(xspeed > 7 && !keyRush)xspeed = 7;
if(xspeed < -7 && !keyRush)xspeed = -7;
if(xspeed > 12 && keyRush)xspeed = 12;
if(xspeed < -12 && keyRush)xspeed = -12;
if(yspeed < -12.75) yspeed = -12.75;
if(keyUp && onGround) {
jumpSound();
hitBox.y++;
onGround = false;
for(Wall wall : panel.walls) {
if(wall.hitBox.intersects(hitBox)) {
yspeed = -8;
}
}hitBox.y--;
}if(keyMega && onGround) {
megaSound();
onGround = false;
hitBox.y++;
for(Wall wall : panel.walls) {
if(wall.hitBox.intersects(hitBox)) yspeed = -12.75;
}hitBox.y--;
}
yspeed += 0.3;
if(keyGlide && !onGround && yspeed > 1.2) {
glideSound();
yspeed -= 0.25;
}if(keyDown && !onGround) {
yspeed += 0.4;
}
//horizontal collision
hitBox.x += xspeed;
for(Wall wall : panel.walls) {
if(hitBox.intersects(wall.hitBox)) {
hitBox.x -= xspeed;
while(!wall.hitBox.intersects(hitBox))hitBox.x += Math.signum(xspeed);
hitBox.x -= Math.signum(xspeed);
panel.cameraX += x - hitBox.x;
xspeed = 0;
hitBox.x = x;
}
}
for(Orange orange : panel.oranges){
isDed = false;
if(hitBox.intersects(orange.hitBox)) {
isDed = false;
if(panel.orangeCount != 6) {
isDed = false;
keyGlide = false;
hitBox.x -= xspeed;
while(!orange.hitBox.intersects(hitBox))hitBox.x += Math.signum(xspeed);
hitBox.x -= Math.signum(xspeed);
panel.cameraX += x - hitBox.x;
xspeed = 0;
x = hitBox.x;
panel.orangeCount++;
panel.reset();
panel.orangeLabel.setText(": " +(int)panel.orangeCount + "/7");
onGround = true;
isDed = false;
deathSound();
}
else {
keyGlide = false;
hitBox.x -= xspeed;
while(!orange.hitBox.intersects(hitBox))hitBox.x += Math.signum(xspeed);
hitBox.x -= Math.signum(xspeed);
xspeed = 0;
x = hitBox.x;
onGround = true;
panel.orangeCount++;
panel.orangeLabel.setText(": " + (int)panel.orangeCount + "/7");
orangeSound();
System.out.println("Well done");
Thread.sleep(1100);
System.out.print("your time is ");
System.out.println(panel.timeLabel.getText());
System.out.println("you died " + (int)deaths + " time(s)");
System.exit(0);
}
}
}
//vertical collision
hitBox.y += yspeed;
for(Wall wall : panel.walls) {
if(hitBox.intersects(wall.hitBox)) {
keyGlide = false;
hitBox.y -= yspeed;
while(!wall.hitBox.intersects(hitBox))hitBox.y += Math.signum(yspeed);
hitBox.y -= Math.signum(yspeed);
yspeed = 0;
y = hitBox.y;
onGround = true;
}
}
try {
for(LavaWall lava : panel.lavaWalls) {
if(hitBox.intersects(lava.hitBox)) {
isDed = true;
isDeathSound = true;
keyGlide = false;
hitBox.y -= yspeed;
while(!lava.hitBox.intersects(hitBox))hitBox.y += Math.signum(yspeed);
hitBox.y -= Math.signum(yspeed);
yspeed = 0;
y = hitBox.y;
onGround = true;
isDed = true;
die();
}
}
for(Orange orange : panel.oranges){
isDed = false;
if(hitBox.intersects(orange.hitBox)) {
isDed = false;
if(!(panel.orangeCount == 7)) {
keyGlide = false;
hitBox.y -= yspeed;
while(!orange.hitBox.intersects(hitBox))hitBox.y += Math.signum(yspeed);
hitBox.y -= Math.signum(yspeed);
yspeed = 0;
y = hitBox.y;
onGround = true;
panel.orangeCount++;
panel.reset();
panel.orangeLabel.setText(": " +(int)panel.orangeCount + "/7");
isDed = false;
deathSound();
}
else if(panel.orangeCount == 7) {
keyGlide = false;
hitBox.y -= yspeed;
while(!orange.hitBox.intersects(hitBox))hitBox.y += Math.signum(yspeed);
hitBox.y -= Math.signum(yspeed);
yspeed = 0;
y = hitBox.y;
onGround = true;
panel.orangeCount++;
panel.orangeLabel.setText(": " + (int)panel.orangeCount + "/7");
orangeSound();
System.out.println("Well done");
Thread.sleep(1100);
System.out.print("your time is ");
System.out.println(panel.timeLabel.getText());
System.out.println("you died " + (int)deaths + " time(s)");
Thread.sleep(4500);
System.out.println("press v to exit");
}
}
}
}catch(Throwable e) {
}
panel.cameraX -= xspeed;
y += yspeed;
hitBox.x = x;
hitBox.y = y;
//death code
if(y > 800) {
isDed = true;
onGround = true;
die();
}enemyScript();
}void enemyScript() {
for(Enemy enemy : panel.enemies) {
if(hitBox.intersects(enemy.hitBox)) {
isDed = true;
isDeathSound = true;
keyGlide = false;
hitBox.y -= yspeed;
while(!enemy.hitBox.intersects(hitBox))hitBox.y += Math.signum(yspeed);
hitBox.y -= Math.signum(yspeed);
yspeed = 0;
y = hitBox.y;
onGround = true;
isDed = true;
die();
}
}
}
void jumpSound(){
soundEffect("res\\musicAndSoundEffects\\jump.wav");
}void megaSound(){
soundEffect("res\\musicAndSoundEffects\\megajump.wav");
}void glideSound(){
soundEffect("res\\musicAndSoundEffects\\shorterGlide.wav");
}void deathSound(){
if(isDed) {
soundEffect("res\\musicAndSoundEffects\\death.wav");
}else if(!isDed) {
soundEffect("res\\musicAndSoundEffects\\orangeSound.wav");
}
}void notDie(){
stopSound();
}
void orangeSound(){
soundEffect("res\\musicAndSoundEffects\\orangeSound.wav");
}void stopSound(){
clip.stop();
}
void die() {
deathSound();
panel.reset();
deaths++;
death.setText("Deaths: " + (int)deaths);
onGround = true;
}
static void soundEffect(String filePath) {
try {
File file = new File(filePath);
AudioInputStream sound = AudioSystem.getAudioInputStream(file);
clip = AudioSystem.getClip();
if(onGround && !filePath.equals("res\\musicAndSoundEffects\\shorterGlide.wav")) {
clip.open(sound);
clip.setFramePosition(0);
clip.start();
}else if(filePath.equals("res\\musicAndSoundEffects\\shorterGlide.wav")) {
clip.open(sound);
clip.setFramePosition(0);
clip.start();
}
}catch(Exception e) {
JOptionPane.showMessageDialog(null, e.getStackTrace());
}
}
public void draw(Graphics2D g) {
g.setColor(Color.BLACK);
g.fillRect(x, y, width, height);
}
}
for anyone who knows the answer to this. Please comment the problem and not the answer so that I can learn. thanks
In broad strokes:
Because you're using a java.util.Timer and it is just the wrong tool for the job.
Let's say you want a game to run smoothly, but not slam the CPU of even the most powerful machine imaginable, and also to run as well as it can if the system it runs on is insufficient (that last one is important; even if a system is plenty powerful to run the game, sometimes you get a 'blip' of underperformance because of other stuff the computer was doing, such as when you plug in a USB stick and all sorts of driver shenanigans occurs in the background).
To accomplish these things, you need two crucial properties:
Timing related to the gameplay (such as, if one of the players is moving northbound, the amount of movement that occurs) should be based entirely on 'time passed', and be unaffected by the amount of time required to actually redraw parts of the screen, nor should it be affected by how many 'loops' of screen refresh you manage to squeeze into a single second.
Timing related to rendering needs to go fast as possible, but needs a breaking system: BEFORE you begin the task of 'update game state then render the state to the screen', you should calculate the timing at which that should all be done. Then, once you are done with one loop of the game (adjust game state and rendering all that), you check whether you 'beat the clock'. If you did, THEN wait. In other words, instead of asking a timer to wait a fixed amount of time before doing the next game loop, the amount of time to wait needs to take into account you took some time to adjust the game state and render things.
Here's some example code of a basic game loop. Just use it for inspiration, it doesn't fit verbatim into the code you already have.
class Example {
private static final long NANOS_PER_MILLI =
TimeUnit.MILLISECONDS.toNanos(1);
private static final long NANOS_PER_FRAME =
TimeUnit.SECONDS.toNanos(1) / 60;
private static final long ADJUST_EXPECTATIONS_TRESHOLD =
NANOS_PER_FRAME * 5;
private long start = System.nanoTime();
private long frameCounter = 0;
public void run() {
while (running) {
gameLoop();
}
}
void gameLoop() {
frameCounter++;
long target = startTime + NANOS_PER_FRAME * frameCounter;
// target now holds the exact time at which point we should
// be done with this game loop.
recalcGameState();
redrawStuff();
long end = System.nanoTime();
long delta = target - System.nanoTime();
if (delta > 0) {
// We had time to spare!
// Let's sleep most of that away, giving us
// a little bit of leeway (5msec worth) in case the system is
// going to blip on us.
// Also, CPU waiting is generally granularized at millis,
// so let's convert to millis first, and be 5 millis 'early'
long millisToWait = (delta / NANOS_PER_MILLI) - 5;
if (millisToWait > 0) sleep(millisToWait);
else if (-delta > READJUST_EXPECTATIONS_TRESHOLD) {
// Rats - we missed the boat, and by a lot!
// we are over 5 frames behind, let's readjust
// expectations and slow down the game logic, too:
start = end;
frameCounter = 0;
}
}
}
}
The above code will reliably render at 60 gameloops every second, (that 5msec leeway will adjust itself on the next loop, as that would just mean you get there even faster and thus wait longer) - and will 'catch up' on a blip for at most 5 frames (catching up a ton of frames after a long blip is usually not a good idea, so we limit the catchup mechanism).
Usually when you're forced into readjustment you may want to adjust the game logic's clocks as well (it is a bit unfair for a player to slam into a wall that was way ahead of them because their CPU just decided to doze off for a second, unlikely as that is, whilst they couldn't steer or even see anything!) - so, have a ball with gameStart.
NB: nanoTime is used and not System.currentTimeMillis(), because System.CTM represents the system clock, which means it will drastically change when the user resets their time - modern computers update their clocks by way of a network time server, so this happens all the time (heh), and means that looking at it for frame timing is a bad idea. From time to time the game will do mad glitching when the NTP daemon adjusted the clocks. nanoTime is more or less reflecting 'CPU uptime' and does not get modified when the system clock is adjusted.
NB2: If you need 'frameCounter' to represent game turns, you can't just reset it like this; instead, figure out how many frames you want to adjust by, and then add that many NANOS_PER_FRAME to 'start' instead.
I am passing two different times into two different objects and the time is always the same. Any suggestions as to what I should do?
public class TwoTimeClock extends JFrame {
Clock clockFace;
Clock clockFacetwo;
public static void main(String[] args) {
JFrame windo = new TwoTimeClock();
windo.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
windo.setVisible(true);
}
private final Clock clockFaceTwo;
/**
* empty constructor. initializes instance variables, draws the clocks,
* and starts them
*/
public TwoTimeClock() {
Container content = this.getContentPane();
content.setLayout(new BorderLayout());
Time time1 = new Time();
Time time2 = new Time();
clockFace = new Clock(time1);
clockFaceTwo = new Clock(time2);
content.add(clockFace, BorderLayout.WEST); //BorderLayout.WEST and BorderLayout.EAST decide the clocks lie in the left or right of box
//hint if you add another clockFace to the content object above, then the canvas will grow in size
content.add(clockFaceTwo, BorderLayout.EAST);
this.setTitle("Baltimore New Delhi");
this.pack();
clockFace.start();
time2.setHrsOffset(9);
time2.setMinsOffset(30);
clockFaceTwo.start();
}
}
Time time;
private static final int spacing = 10;
private static final float threePi = (float) (3.0 * Math.PI);
// Angles for the trigonometric functions are measured in radians.
// The following in the number of radians per sec or min.
private static final float radPerSecMin = (float) (Math.PI / 30.0);
private int size; // height and width of clock face
private int centerX; // x coord of middle of clock
private int centerY; // y coord of middle of clock
private BufferedImage clockImage;
private javax.swing.Timer t;
/**
* //>>>>>>>>>>>>>>>>> You should modify this constructor to take an object of Time class as parameter
* Constructor. Takes an object of the Time class that it will use for showing the time
* #param
*/
public Clock(Time t1) {
this.time = t1;
this.setPreferredSize(new Dimension(300, 300));
this.setBackground(Color.white);
this.setForeground(Color.black);
t = new javax.swing.Timer(1000,
new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
update();
}
});
}
/**
* Replace the default update so that the plain background doesn't get drawn.
*/
public void update() {
this.repaint();
}
public void start() {
t.start(); // start the timer
}
public void stop() {
t.stop(); // stop the timer
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g); // paint background, borders
Graphics2D g2 = (Graphics2D) g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
// The panel may have been resized, get current dimensions
int w = getWidth();
int h = getHeight();
size = ((w < h) ? w : h) - 2 * spacing;
size -= 50; //reducing size to make space for text below clock face
centerX = size / 2 + spacing;
centerY = size / 2 + spacing;
// Create the clock face background image if this is the first time,
// or if the size of the panel has changed
if (clockImage == null
|| clockImage.getWidth() != w
|| clockImage.getHeight() != h) {
clockImage = (BufferedImage) (this.createImage(w, h));
// now get a graphics context from this image
Graphics2D gc = clockImage.createGraphics();
gc.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
drawClockFace(gc);
}
time.update();
time.updateOffSet();
//>>>>>>>>>>>>>>>>>>>>>>>
// Draw the clock face from the precomputed image
g2.drawImage(clockImage, null, 0, 0);
// Draw the clock hands
drawClockHands(g);
//Print Clock
g2.drawString(Time.toStandard(), 90, h-15);
g2.drawString(Time.toMilitary(), 90, h-30);
}
/**
* The hour, minute, and second hand
* #param g
*/
private void drawClockHands(Graphics g) {
int secondRadius = size / 2;
int minuteRadius = secondRadius * 3 / 4;
int hourRadius = secondRadius / 2;
// second hand
float fseconds = time.getSecs() + (float) time.getMillis()/ 1000;
float secondAngle = threePi - (radPerSecMin * fseconds);
drawRadius(g, centerX, centerY, secondAngle, 0, secondRadius);
// minute hand clock 1
float fminutes = (float) (time.getMins() + fseconds / 60.0);
float minuteAngle = threePi - (radPerSecMin * fminutes);
drawRadius(g, centerX, centerY, minuteAngle, 0, minuteRadius);
// hour hand clock 1
float fhours = (float) (time.getHrs() + fminutes / 60.0);
float hourAngle = threePi - (5 * radPerSecMin * fhours);
drawRadius(g, centerX, centerY, hourAngle, 0, hourRadius);
}
private void drawClockFace(Graphics g) {
// clock face
g.setColor(Color.lightGray);
g.fillOval(spacing, spacing, size, size);
g.setColor(Color.black);
g.drawOval(spacing, spacing, size, size);
// tic marks
for (int sec = 0; sec < 60; sec++) {
int ticStart;
if (sec % 5 == 0) {
ticStart = size / 2 - 10;
} else {
ticStart = size / 2 - 5;
}
drawRadius(g, centerX, centerY, radPerSecMin * sec, ticStart, size / 2);
}
}
private void drawRadius(Graphics g, int x, int y, double angle,
int minRadius, int maxRadius) {
float sine = (float) Math.sin(angle);
float cosine = (float) Math.cos(angle);
int dxmin = (int) (minRadius * sine);
int dymin = (int) (minRadius * cosine);
int dxmax = (int) (maxRadius * sine);
int dymax = (int) (maxRadius * cosine);
g.drawLine(x + dxmin, y + dymin, x + dxmax, y + dymax);
}
}
public class Time {
private static int hrs = 00;
private static int mins = 00;
private static int secs = 00;
private static int millis = 00;
static int copyHrs;
static int copyMins;
static int copySecs;
static int hrsOffset;
static int minsOffset = 30;
//Empty Constructor
public Time() {
Calendar t1 = Calendar.getInstance();
hrs = t1.get(Calendar.HOUR);
mins = t1.get(Calendar.MINUTE);
secs = t1.get(Calendar.SECOND);
millis = t1.get(Calendar.MILLISECOND);
}
//Alternate Constructor
public Time(int hours, int minutes, int seconds, int millisec) {
hrs = hours;
mins = minutes;
secs = seconds;
millis = millisec;
}
//Copy Constructor
public Time(Time otherClock) {
copyHrs = hrs;
copyMins = mins;
copySecs = secs;
millis = millis;
}
public int getHrs() {
return hrs;
}
public void setHrs(int hrs) {
this.hrs = hrs;
}
public int getMins() {
return mins;
}
public void setMins(int mins) {
this.mins = mins;
}
public int getSecs() {
return secs;
}
public void setSecs(int secs) {
this.secs = secs;
}
public int getMillis() {
return millis;
}
public void setMillis(int millis) {
this.millis = millis;
}
public static int getHrsOffset() {
return hrsOffset;
}
public void setHrsOffset(int hrsOffset) {
this.hrsOffset = hrsOffset;
}
public void printOffset(Time clock, int hrsOffset, int minsOffset) {
hrs = Math.abs(clock.hrs + hrsOffset);
mins = Math.abs(clock.mins + minsOffset);
secs = clock.secs;
if (hrs < 12) {
System.out.printf("%02d:%02d:%02d AM%n", hrs, mins, secs);
} else if (hrs == 24) {
System.out.printf("12:%02d:%02d AM%n", mins, secs);
} else if (hrs == 12) {
System.out.printf("12:%02d:%02d PM%n", mins, secs);
} else {
System.out.printf("%02d:%02d:%02d PM%n", hrs - 12, mins, secs);
}
}
public static int getMinsOffset() {
return minsOffset;
}
public void setMinsOffset(int minsOffset) {
this.minsOffset = minsOffset;
}
public static void printMilitary() {
hrs = hrs % 24;
System.out.printf("%02d:%02d:%02d %n", hrs, mins, secs);
}
public static void printStandard() {
hrs = hrs % 24;
if (hrs < 12) {
System.out.printf("%02d:%02d:%02d AM%n", hrs, mins, secs);
} else if (hrs == 24) {
System.out.printf("12:%02d:%02d AM%n", mins, secs);
} else if (hrs == 12) {
System.out.printf("12:%02d:%02d PM%n", mins, secs);
} else {
System.out.printf("%02d:%02d:%02d PM%n", hrs - 12, mins, secs);
}
}
#Override
public String toString() {
return hrs + ":" + mins + ":" + secs;
}
public boolean equals(Time otherClock) {
if (hrs == otherClock.hrs && mins == otherClock.mins && secs == otherClock.secs) {
return true;
} else {
return false;
}
}
public static int getCopy() {
copyHrs = Time.hrs;
copyMins = Time.mins;
copySecs = Time.secs;
return copyHrs + copyMins + copySecs;
}
public static void advanceSecs() {
secs++;
if (secs > 59) {
mins++;
secs = 00;
}
if (mins > 59) {
hrs++;
secs = 00;
mins = 00;
}
}
public boolean lessThan(Time otherClock) {
if ((hrs < otherClock.hrs) && (mins < otherClock.mins) && (secs < otherClock.secs)) {
return true;
} else {
return false;
}
}
public boolean notEquals(Time otherClock) {
if ((hrs == otherClock.hrs) && (mins == otherClock.mins) && (secs == otherClock.secs)) {
return true;
} else {
return false;
}
}
public boolean lessOrEquals(Time otherClock) {
if ((hrs <= otherClock.hrs) && (mins <= otherClock.mins) && (secs <= otherClock.secs)) {
return true;
} else {
return false;
}
}
public boolean greaterThan(Time otherClock) {
if ((hrs > otherClock.hrs) && (mins > otherClock.mins) && (secs > otherClock.secs)) {
return true;
} else {
return false;
}
}
public static String toMilitary() {
hrs = hrs%24;
String str = String.format("%02d:%02d:%02d", hrs, mins, secs);
return str;
}
public static String toStandard() {
String str = String.format("%02d:%02d:%02d PM", hrs, mins, secs);
if (hrs > 12) {
hrs = hrs - 12;
str = String.format("%02d:%02d:%02d AM", hrs, mins, secs);
} else if (hrs == 12) {
str = String.format("%02d:%02d:%02d AM", hrs, mins, secs);
}
return str;
}
public void update() {
Calendar t1 = Calendar.getInstance();
hrs = t1.get(Calendar.HOUR);
mins = t1.get(Calendar.MINUTE);
secs = t1.get(Calendar.SECOND);
millis = t1.get(Calendar.MILLISECOND);
}
public void updateOffSet() {
Calendar t1 = Calendar.getInstance();
hrs = t1.get(Calendar.HOUR) + hrsOffset;
mins = t1.get(Calendar.MINUTE) + minsOffset;
secs = t1.get(Calendar.SECOND);
millis = t1.get(Calendar.MILLISECOND);
}
}
You've got nothing but static fields in Time, and this will guarantee that Time instances will all share the same state. Don't do this. Make those fields instance (i.e., non-static) fields.
Also, your Time copy constructor doesn't, and in fact completely ignores the otherClock parameter that passes into it.
Your Time class should not have the copyHrs, copyMins, etc... fields as they serve no useful purpose.
Your getCopy() method is a bit absurd. What use is adding all the mins, hours, and seconds together? The number has no meaning. Shouldn't that method return a Time instance, one with the same state as the current Time instance?
The way I have set up my code is I have 3 white rectangles that are as tall as the screen and each 1/9 of the screen wide. Each are equally spaced out accross the screen. I also have 3 other black rectangles, 1 on top of each white...same left and right as the white rectangles so to the user it looks like there is a gap in the white rectangle when in reality it is just a black rectangle of lesser height over a white rectangle as tall as the screen. Anyway, the player has to pass a ball through this "gap" in the white rectangle as the rectangles move across the screen. I was wondering how I would detect collision with the "only white region". By that I mean have code where the ball is safe if it is touching both the black and white rectangle but not safe if the player doesn't hit both the black and white rectangle (If I said not safe if it only hit the white rectangle the player would die every time since like I said the white rectangle is as tall as the screen overlapped by a shorter black rectangle). Here is the code for my mainactivity:
public class GameScreen extends ActionBarActivity {
public static final String TAG = "BallActivity";
BallView mBallView = null;
Rectangle rectWhite1 = null
, rectBlack1= null
, rectWhite2 = null
, rectBlack2= null
, rectWhite3 = null
, rectBlack3= null
,collisionRectangle = null;
int mPointMargin = 5; //specifies width of point adding zone when ball passes rectangle's right side
Handler RedrawHandler = new Handler(); //so redraw occurs in main thread
Handler RedrawHandler2 = new Handler();
Timer mTmr , mTmr2 = null;
TimerTask mTsk , mTsk2 = null;
int mScrWidth, mScrHeight;
int mRectSpeed = 7; //Game max speed should be 12!!!
int mBallSpeed = 15;
Scoreboard mScoreboard = new Scoreboard();
android.graphics.PointF mBallPos, mBallSpd;
//Going to be used to check if ball hits only white rectangle...use intersects method
Rect rectObject;
#Override
protected void onCreate(Bundle savedInstanceState) {
requestWindowFeature(Window.FEATURE_NO_TITLE); //hide title bar
//set app to full screen and keep screen on
getWindow().setFlags(0xFFFFFFFF, LayoutParams.FLAG_FULLSCREEN | LayoutParams.FLAG_KEEP_SCREEN_ON);
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_game_screen);
//create pointer to main screen
final FrameLayout mainView = (FrameLayout) findViewById(R.id.main_view);
//get screen dimensions
Display display = getWindowManager().getDefaultDisplay();
mScrWidth = display.getWidth();
mScrHeight = display.getHeight();
mBallPos = new PointF();
mBallSpd = new PointF();
//create variables for ball position and speed
mBallPos.x = mScrWidth / 7;
mBallPos.y = mScrHeight / 2;
mBallSpd.x = 0;
mBallSpd.y = 0;
//create initial ball
mBallView = new BallView(this, mBallPos.x, mBallPos.y, mScrWidth/30);
//**************Create initial 6 rectangles****************
rectWhite1 = new Rectangle(this, ((mScrWidth/9) * 8) + mScrWidth, 0 , ((mScrWidth/9) * 9) + mScrWidth, mScrHeight, 0xFFFFFFFF);
rectBlack1 = new Rectangle(this, ((mScrWidth/9) * 8) + mScrWidth, (mScrHeight/10) * 4 ,((mScrWidth/9) * 9) + mScrWidth ,(mScrHeight/10) * 6, 0xFFFFFF00);
rectWhite2 = new Rectangle(this, ((mScrWidth/9) * 5) + mScrWidth, 0, ((mScrWidth/9) * 6) + mScrWidth, mScrHeight,0xFFFFFFFF);
rectBlack2 = new Rectangle(this, ((mScrWidth/9) * 5) + mScrWidth, (mScrHeight/10) * 4, ((mScrWidth/9) * 6) + mScrWidth, (mScrHeight/10) * 6, 0xFFFFFF00);
rectWhite3 = new Rectangle(this, ((mScrWidth/18) * 3) + mScrWidth, 0, ((mScrWidth/18) * 5) + mScrWidth, mScrHeight, 0xFFFFFFFF);
rectBlack3 = new Rectangle(this, ((mScrWidth/18) * 3) + mScrWidth, (mScrHeight/10) * 4, ((mScrWidth/18) * 5) + mScrWidth, (mScrHeight/10) * 6 , 0xFFFFFF00);
//Add to view
mainView.addView(rectWhite1);
rectWhite1.invalidate();
mainView.addView(rectWhite2);
rectWhite2.invalidate();
mainView.addView(rectWhite3);
rectWhite3.invalidate();
mainView.addView(rectBlack1);
rectBlack1.invalidate();
mainView.addView(rectBlack2);
rectBlack2.invalidate();
mainView.addView(rectBlack3);
rectBlack3.invalidate();
mainView.addView(mBallView); //add ball to main screen
mBallView.invalidate(); //call onDraw in BallView
//listener for accelerometer, use anonymous class for simplicity
((SensorManager) getSystemService(Context.SENSOR_SERVICE)).registerListener(
new SensorEventListener() {
#Override
public void onSensorChanged(SensorEvent event) {
//set ball speed based on phone tilt (ignore Z axis)
mBallSpd.x = -event.values[0] * mBallSpeed;
mBallSpd.y = event.values[1] * mBallSpeed;
//timer event will redraw ball
}
#Override
public void onAccuracyChanged(Sensor sensor, int accuracy) {
} //ignore
},
((SensorManager) getSystemService(Context.SENSOR_SERVICE))
.getSensorList(Sensor.TYPE_ACCELEROMETER).get(0),
SensorManager.SENSOR_DELAY_NORMAL);
} //OnCreate(mScrWidth/10) * 6
//For state flow see http://developer.android.com/reference/android/app/Activity.html
#Override
public void onPause() //app moved to background, stop background threads
{
mTmr.cancel(); //kill\release timer (our only background thread)
mTmr = null;
mTsk = null;
mTmr2.cancel();
mTmr2 = null;
mTsk2 = null;
super.onPause();
}
#Override
public void onResume() //app moved to foreground (also occurs at app startup)
{
final TextView scoreTextView = (TextView)findViewById(R.id.scoreTextView);
final int[] blackRectangleTopHeights = {0, (mScrHeight/10) * 1, (mScrHeight/10) * 2,(mScrHeight/10) * 3,
(mScrHeight/10) * 4,(mScrHeight/10) * 5,(mScrHeight/10) * 6,
(mScrHeight/10) * 7};
final int[] blackRectangleBottomHeights = {(mScrHeight/10) * 3,(mScrHeight/10) * 4,(mScrHeight/10) * 5,
(mScrHeight/10) * 6, (mScrHeight/10) * 7,(mScrHeight/10) * 8,
(mScrHeight/10) * 9,mScrHeight};
final Random randomGenerator = new Random();
runCircle();
//************Set up rectangle moving mechanism and Logic*********************
mTmr2 = new Timer();
mTsk2 = new TimerTask() {
#Override
public void run() {
int randomNumber = randomGenerator.nextInt(blackRectangleTopHeights.length);
int topBlackRectHeight = blackRectangleTopHeights[randomNumber];
int bottomBlackRectHeight = blackRectangleBottomHeights[randomNumber];
//Moves rectangles left across the screen
int rectWhite1Left = rectWhite1.getTheLeft() - mRectSpeed;
int rectWhite1Right = rectWhite1.getTheRight() - mRectSpeed;
rectWhite1.setX(rectWhite1Left, rectWhite1Right);
int rectBlack1Left = rectBlack1.getTheLeft() - mRectSpeed;
int rectBlack1Right = rectBlack1.getTheRight() - mRectSpeed;
rectBlack1.setX(rectBlack1Left, rectBlack1Right);
int rectWhite2Left = rectWhite2.getTheLeft() - mRectSpeed;
int rectWhite2Right = rectWhite2.getTheRight() - mRectSpeed;
rectWhite2.setX(rectWhite2Left, rectWhite2Right);
int rectBlack2Left = rectBlack2.getTheLeft() - mRectSpeed;
int rectBlack2Right = rectBlack2.getTheRight() - mRectSpeed;
rectBlack2.setX(rectBlack2Left, rectBlack2Right);
int rectWhite3Left = rectWhite3.getTheLeft() - mRectSpeed;
int rectWhite3Right = rectWhite3.getTheRight() - mRectSpeed;
rectWhite3.setX(rectWhite3Left, rectWhite3Right);
int rectBlack3Left = rectBlack3.getTheLeft() - mRectSpeed;
int rectBlack3Right = rectBlack3.getTheRight() - mRectSpeed;
rectBlack3.setX(rectBlack3Left, rectBlack3Right);
//Cycles rectangles when they hit left side of the screen
// Randomizes where middle rectangle will be postitoned vertically
if (rectWhite1.getTheRight() > 0 && rectWhite1.getTheRight() < 20) {
rectWhite1.setX(mScrWidth, rectWhite1.getRectWidth() + mScrWidth);
}
if (rectBlack1.getTheRight() > 0 && rectBlack1.getTheRight() < 20) {
rectBlack1.setX(mScrWidth, rectBlack1.getRectWidth() + mScrWidth);
rectBlack1.setY(topBlackRectHeight, bottomBlackRectHeight);
}
if (rectWhite2.getTheRight() > 0 && rectWhite2.getTheRight() < 20) {
rectWhite2.setX(mScrWidth, rectWhite2.getRectWidth() + mScrWidth);
}
if (rectBlack2.getTheRight() > 0 && rectBlack2.getTheRight() < 20) {
rectBlack2.setX(mScrWidth, rectBlack2.getRectWidth() + mScrWidth);
rectBlack2.setY(topBlackRectHeight, bottomBlackRectHeight);
}
if (rectWhite3.getTheRight() > 0 && rectWhite3.getTheRight() < 20) {
rectWhite3.setX(mScrWidth, rectWhite3.getRectWidth() + mScrWidth);
}
if (rectBlack3.getTheRight() > 0 && rectBlack3.getTheRight() < 20) {
rectBlack3.setX(mScrWidth, rectBlack3.getRectWidth() + mScrWidth);
rectBlack3.setY(topBlackRectHeight, bottomBlackRectHeight);
}
//*********Keeps track of score and update TextView with score*************
if (rectWhite1.getTheRight() > Math.round(mBallPos.x) - 5 && rectWhite1.getTheRight() < Math.round(mBallPos.x) + 5) {
runOnUiThread(new Runnable() {
#Override
public void run() {
mScoreboard.addPoint();
scoreTextView.setText(mScoreboard.getScore() + "");
}
});
}
if (rectWhite2.getTheRight() > Math.round(mBallPos.x) - mPointMargin && rectWhite2.getTheRight() < Math.round(mBallPos.x) + mPointMargin) {
runOnUiThread(new Runnable() {
#Override
public void run() {
mScoreboard.addPoint();
scoreTextView.setText(mScoreboard.getScore() + "");
}
});
}
if (rectWhite3.getTheRight() > Math.round(mBallPos.x) - mPointMargin && rectWhite3.getTheRight() < Math.round(mBallPos.x) + mPointMargin) {
runOnUiThread(new Runnable() {
#Override
public void run() {
mScoreboard.addPoint();
scoreTextView.setText(mScoreboard.getScore() + "");
}
});
}
//Speeds up game correspondingly to the score
if (mScoreboard.getScore() == 10) {
mRectSpeed = 8;
mBallSpeed = 16;
}
if (mScoreboard.getScore() == 20) {
mRectSpeed = 9;
mBallSpeed = 17;
}
if (mScoreboard.getScore() == 30) {
mRectSpeed = 10;
mBallSpeed = 18;
}
if (mScoreboard.getScore() == 40) {
mRectSpeed = 11;
mBallSpeed = 19;
}
if (mScoreboard.getScore() == 50) {
mRectSpeed = 12;
mBallSpeed = 20;
}
if (mScoreboard.getScore() == 60) {
mRectSpeed = 13;
mBallSpeed = 21;
}
if (mScoreboard.getScore() == 70) {
mRectSpeed = 14;
mBallSpeed = 22;
}
if (mScoreboard.getScore() == 80) {
mRectSpeed = 15;
mBallSpeed = 23;
}
if (mScoreboard.getScore() == 90) {
mBallSpeed = 24;
}
if (mScoreboard.getScore() == 100) {
mBallSpeed = 25;
}
RedrawHandler2.post(new Runnable() {
public void run() {
rectWhite1.invalidate();
rectWhite2.invalidate();
rectWhite3.invalidate();
rectBlack1.invalidate();
rectBlack2.invalidate();
rectBlack3.invalidate();
}
});
}
};
mTmr2.schedule(mTsk2, 10, 10); //start timer (Timer 2)
super.onResume();
} // onResume
private void runCircle() {
//create timer to move ball to new position
mTmr = new Timer();
mTsk = new TimerTask() {
public void run() {
//move ball based on current speed
mBallPos.x += mBallSpd.y;
mBallPos.y += -mBallSpd.x;
//if ball goes off screen, reposition to opposite side of screen
if (mBallPos.x > mScrWidth) mBallPos.x = 0;
if (mBallPos.y > mScrHeight) mBallPos.y = 0;
if (mBallPos.x < 0) mBallPos.x = mScrWidth;
if (mBallPos.y < 0) mBallPos.y = mScrHeight;
//update ball class instance
mBallView.x = mBallPos.x;
mBallView.y = mBallPos.y;
//redraw ball. Must run in background thread to prevent thread lock.
RedrawHandler.post(new Runnable() {
public void run() {
mBallView.invalidate();
}
});
//If ball hits sides it goes to the redirect screen, YOU LOSE!
if (mBallPos.y == mScrHeight || mBallPos.y == 0 || mBallPos.x == mScrWidth|| mBallPos.x == 0 ) {
goToRedirectScreen();
}
} //run
}; // TimerTask
mTmr.schedule(mTsk, 10, 10); //start timer (Timer)
}
#Override
public void onDestroy() //main thread stopped
{
super.onDestroy();
//wait for threads to exit before clearing app
System.runFinalizersOnExit(true);
//remove app from memory
android.os.Process.killProcess(android.os.Process.myPid());
}
public void goToRedirectScreen()
{
Intent intent = new Intent(this, Redirect.class);
startActivity(intent);
}
}
I need a method that will check if mBallView is only touching the white rectangle and not both the black and white. Or if you have any other solutions I am open to all approaches. Thank you in advance.
I have already referenced:
How to fix circle and rectangle overlap in collision response
and
Circle-Rectangle collision detection
But I did not see how I could apply them to my particular case.
It's the same game that I'm working on and I've come to a problem that I can't understand again. I'm using Key Bindings to move my sprite and it's working great! but since it's a snake game I need the sprite to keep moving without stopping and change direction and keep moving after the player types a key. I know it's possible with KeyListener, but I really don't want to have to change my program entirely. I just need to know what code needs to change, if possible.
On top of that I'm also working on two arrays for the x and y co-ordinates for the snake body so that squares will follow behind the head, but I can't get it to paint. and how to display an integer for the score.
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.util.Random;
import java.util.ArrayList;
public class Snake2 extends JFrame {
/* Sprite: snake head co-ordinates */
int x = 400;
int y = 450;
int width = 10;
int height = 10;
/* Sprite: snake body */
int length = 0;
ArrayList <Integer> bodyX = new ArrayList <Integer>();
ArrayList <Integer> bodyY = new ArrayList <Integer>();
/* Score */
int point = 0;
/* Sprite: mouse co-ordinates */
Random rand = new Random();
int addx = (rand.nextInt(10))*10;
int addy = (rand.nextInt(10))*10;
int mx = ((rand.nextInt(5)+1)*100) + addx;
int my = ((rand.nextInt(6)+2)*100) + addy;
DrawPanel drawPanel = new DrawPanel();
public Snake2() {
addMouseListener(new MouseListener());
System.out.print(mx + " " + my);
/* move snake up */
Action upAction = new AbstractAction(){
public void actionPerformed(ActionEvent e) {
y -=10;
if (y >= my && y <= my+9 && x >= mx && x <= mx+9)
{
addx = (rand.nextInt(10))*10;
addy = (rand.nextInt(10))*10;
mx = ((rand.nextInt(5)+1)*100) + addx;
my = ((rand.nextInt(6)+1)*100) + addy;
point += 100;
length++;
bodyY.add(0, y);
}
if (y <99)
{
new GameOver();
dispose();
}
drawPanel.repaint();
}
};
/* move snake down */
Action downAction = new AbstractAction(){
public void actionPerformed(ActionEvent e) {
y +=10;
if (y >= my && y <= my+9 && x >= mx && x <= mx+9)
{
addx = (rand.nextInt(10))*10;
addy = (rand.nextInt(10))*10;
mx = ((rand.nextInt(5)+1)*100) + addx;
my = ((rand.nextInt(6)+1)*100) + addy;
point += 100;
length++;
bodyY.add(0, y);
}
if (y > 799)
{
new GameOver();
dispose();
}
drawPanel.repaint();
}
};
/* move snake left */
Action leftAction = new AbstractAction(){
public void actionPerformed(ActionEvent e) {
x -=10;
if (x >= mx && x <= mx+9 && y >= my && y <= my+9)
{
addx = (rand.nextInt(10))*10;
addy = (rand.nextInt(10))*10;
mx = ((rand.nextInt(5)+1)*100) + addx;
my = ((rand.nextInt(6)+1)*100) + addy;
point += 100;
length++;
bodyX.add(0, x);
}
if (x <99)
{
new GameOver();
dispose();
}
drawPanel.repaint();
}
};
/* move snake right */
Action rightAction = new AbstractAction(){
public void actionPerformed(ActionEvent e) {
x +=10;
if (x >= mx && x <= mx+9 && y >= my && y <= my+9)
{
addx = (rand.nextInt(10))*10;
addy = (rand.nextInt(10))*10;
mx = ((rand.nextInt(5)+1)*100) + addx;
my = ((rand.nextInt(6)+1)*100) + addy;
point += 100;
length++;
bodyX.add(0, x);
}
if (x > 699)
{
new GameOver();
dispose();
}
drawPanel.repaint();
}
};
InputMap inputMap = drawPanel.getInputMap(JPanel.WHEN_IN_FOCUSED_WINDOW);
ActionMap actionMap = drawPanel.getActionMap();
inputMap.put(KeyStroke.getKeyStroke("RIGHT"), "rightAction");
actionMap.put("rightAction", rightAction);
inputMap.put(KeyStroke.getKeyStroke("LEFT"), "leftAction");
actionMap.put("leftAction", leftAction);
inputMap.put(KeyStroke.getKeyStroke("DOWN"), "downAction");
actionMap.put("downAction", downAction);
inputMap.put(KeyStroke.getKeyStroke("UP"), "upAction");
actionMap.put("upAction", upAction);
add(drawPanel);
pack();
setDefaultCloseOperation(EXIT_ON_CLOSE);
setLocationRelativeTo(null);
setVisible(true);
}//Snake2()
private class GameOver extends JFrame implements ActionListener{
JLabel answer = new JLabel("");
JPanel pane = new JPanel(); // create pane object
JButton pressme = new JButton("Quit");
JButton replay = new JButton("Replay?");
GameOver() // the constructor
{
super("Game Over"); setBounds(100,100,300,200);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Container con = this.getContentPane(); // inherit main frame
con.add(pane); pressme.setMnemonic('Q'); // associate hotkey
pressme.addActionListener(this); // register button listener
replay.addActionListener(this);
pane.add(answer); pane.add(pressme); pane.add(replay); pressme.requestFocus();
answer.setText("You Lose");
setVisible(true); // make frame visible
}//GameOver()
// here is the basic event handler
public void actionPerformed(ActionEvent event)
{
Object source = event.getSource();
if (source == pressme)
System.exit(0);
if (source == replay)
{
dispose();
EventQueue.invokeLater(new Runnable(){
public void run(){
new Snake2();
}
});
}
}//actionPreformed
}//GameOver
private class DrawPanel extends JPanel {
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Font ith = new Font("Ithornît", Font.BOLD, 78);
/* Background: Snake */
g.setColor(Color.darkGray);
g.fillRect(0, 0, getWidth(), getHeight());
g.setColor(Color.gray);
g.fillRect(100,100,600,700);
g.setColor(Color.white);
g.drawRect(99,99,601,701);
g.drawString("Quit",102,86);
g.drawRect(100,70,30,20);
g.drawString("Score: ", 602, 86);
g.setFont(ith);
g.drawString("SNAKE",350,60);
/* Sprite: Mouse */
g.setColor(Color.black);
g.fillRect(mx, my, width, height);
//System.out.print(mx + " " + my);
/* Sprite: Snake Body */
if (length != 0){
for(int i = 0; i >= length; i++)
{
g.setColor(Color.darkGray);
g.fillRect(bodyX.get(i), bodyY.get(i), width, height);
}
}
/* Sprite: Snake head */
g.setColor(Color.white);
g.fillRect(x, y, width, height);
}//Paint Component
public Dimension getPreferredSize() {
return new Dimension(800, 850);
}//Dimension
}//DrawPanel
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable(){
public void run(){
new Snake2();
}
});
}// main
}//Snake Class
/* Tracks where mouse is clicked */
class MouseListener extends MouseAdapter {
public void mouseReleased(MouseEvent me) {
if (me.getX() >= 101 && me.getX() <= 131 && me.getY() >= 94 && me.getY() <= 115){
System.exit(0);
}
String str="Mouse Released at "+me.getX()+","+me.getY();
System.out.println(str);
}
}//MouseAdapter
"but since it's a snake game I need the sprite to keep moving without stopping"
You need to use a javax.swing.Timer. The basic constructor is like this
Timer(int delay, ActionListener listener) // delay is in milliseconds
A basic implementation would be something like this
Timer timer = new Timer(100, new ActionListener(){
public void actionPerformed(ActionEvent e) {
// do something
}
});
timer.start();
Basically what the timer does, is fire an ActionEvent every so many milliseconds. This is how you work animation with swing. So without you pressing any keys, the sprite will move by itself. It works pretty much like a button does. When you press a button an event is fired. But in the case of the timer, the timer is the one that fires the event. You can specify any delay you want. You many even want to change the duration dynamically when a certain level is reached. timer.setDelay(someInt)
UPDATE
I made very few changes to your current code. I did pretty much what I stated in the comment below
Ok so I thought about it, and I would do something like this: Have a direction variable. For the actions, all you should do is change the direction. In the timer actionPerformed thats where all you logic should go. Check for the direction. If if equals "left" then continue going left like you would on a key press. And so on
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.util.Random;
import java.util.ArrayList;
public class Snake2 extends JFrame {
String direction = "right";
//String duration =
/* Sprite: snake head co-ordinates */
int x = 400;
int y = 450;
int width = 10;
int height = 10;
/* Sprite: snake body */
int length = 0;
ArrayList<Integer> bodyX = new ArrayList<Integer>();
ArrayList<Integer> bodyY = new ArrayList<Integer>();
/* Score */
int point = 0;
/* Sprite: mouse co-ordinates */
Random rand = new Random();
int addx = (rand.nextInt(10)) * 10;
int addy = (rand.nextInt(10)) * 10;
int mx = ((rand.nextInt(5) + 1) * 100) + addx;
int my = ((rand.nextInt(6) + 2) * 100) + addy;
DrawPanel drawPanel = new DrawPanel();
Timer timer;
public Snake2() {
addMouseListener(new MouseListener());
timer = new Timer(50, new TimerListener()); ////////////// <<<<<<<<<<<<<<<<<< TIMER
timer.start();
System.out.print(mx + " " + my);
/* move snake up */
Action upAction = new AbstractAction() {
public void actionPerformed(ActionEvent e) {
direction = "up"; ////////////// <<<<<<<<<<<<<<<<<< direction only change
}
};
/* move snake down */
Action downAction = new AbstractAction() {
public void actionPerformed(ActionEvent e) {
direction = "down";
}
};
/* move snake left */
Action leftAction = new AbstractAction() {
public void actionPerformed(ActionEvent e) {
direction = "left";
}
};
/* move snake right */
Action rightAction = new AbstractAction() {
public void actionPerformed(ActionEvent e) {
direction = "right";
}
};
InputMap inputMap = drawPanel
.getInputMap(JPanel.WHEN_IN_FOCUSED_WINDOW);
ActionMap actionMap = drawPanel.getActionMap();
inputMap.put(KeyStroke.getKeyStroke("RIGHT"), "rightAction");
actionMap.put("rightAction", rightAction);
inputMap.put(KeyStroke.getKeyStroke("LEFT"), "leftAction");
actionMap.put("leftAction", leftAction);
inputMap.put(KeyStroke.getKeyStroke("DOWN"), "downAction");
actionMap.put("downAction", downAction);
inputMap.put(KeyStroke.getKeyStroke("UP"), "upAction");
actionMap.put("upAction", upAction);
add(drawPanel);
pack();
setDefaultCloseOperation(EXIT_ON_CLOSE);
setLocationRelativeTo(null);
setVisible(true);
}// Snake2()
private class TimerListener implements ActionListener {
public void actionPerformed(ActionEvent e) { /////////////////// <<<<<<<<<<<<<< All logic here
if ("right".equals(direction)) {
x += 10;
if (x >= mx && x <= mx + 9 && y >= my && y <= my + 9) {
addx = (rand.nextInt(10)) * 10;
addy = (rand.nextInt(10)) * 10;
mx = ((rand.nextInt(5) + 1) * 100) + addx;
my = ((rand.nextInt(6) + 1) * 100) + addy;
point += 100;
length++;
bodyX.add(0, x);
}
if (x > 699) {
new GameOver();
dispose();
}
} else if ("left".equals(direction)) {
x -= 10;
if (x >= mx && x <= mx + 9 && y >= my && y <= my + 9) {
addx = (rand.nextInt(10)) * 10;
addy = (rand.nextInt(10)) * 10;
mx = ((rand.nextInt(5) + 1) * 100) + addx;
my = ((rand.nextInt(6) + 1) * 100) + addy;
point += 100;
length++;
bodyX.add(0, x);
}
if (x < 99) {
new GameOver();
dispose();
}
} else if ("up".equals(direction)) {
y -= 10;
if (y >= my && y <= my + 9 && x >= mx && x <= mx + 9) {
addx = (rand.nextInt(10)) * 10;
addy = (rand.nextInt(10)) * 10;
mx = ((rand.nextInt(5) + 1) * 100) + addx;
my = ((rand.nextInt(6) + 1) * 100) + addy;
point += 100;
length++;
bodyY.add(0, y);
}
if (y < 99) {
new GameOver();
dispose();
}
} else if ("down".equals(direction)) {
y += 10;
if (y >= my && y <= my + 9 && x >= mx && x <= mx + 9) {
addx = (rand.nextInt(10)) * 10;
addy = (rand.nextInt(10)) * 10;
mx = ((rand.nextInt(5) + 1) * 100) + addx;
my = ((rand.nextInt(6) + 1) * 100) + addy;
point += 100;
length++;
bodyY.add(0, y);
}
if (y > 799) {
new GameOver();
dispose();
}
}
drawPanel.repaint();
}
}
private class GameOver extends JFrame implements ActionListener {
JLabel answer = new JLabel("");
JPanel pane = new JPanel(); // create pane object
JButton pressme = new JButton("Quit");
JButton replay = new JButton("Replay?");
GameOver() // the constructor
{
super("Game Over");
timer.stop(); ////////////////////// <<<<<<<<<< Stop TIMER
setBounds(100, 100, 300, 200);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Container con = this.getContentPane(); // inherit main frame
con.add(pane);
pressme.setMnemonic('Q'); // associate hotkey
pressme.addActionListener(this); // register button listener
replay.addActionListener(this);
pane.add(answer);
pane.add(pressme);
pane.add(replay);
pressme.requestFocus();
answer.setText("You Lose");
setVisible(true); // make frame visible
}// GameOver()
// here is the basic event handler
public void actionPerformed(ActionEvent event) {
Object source = event.getSource();
if (source == pressme)
System.exit(0);
if (source == replay) {
dispose();
EventQueue.invokeLater(new Runnable() {
public void run() {
new Snake2();
}
});
}
}// actionPreformed
}// GameOver
private class DrawPanel extends JPanel {
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Font ith = new Font("Ithornît", Font.BOLD, 78);
/* Background: Snake */
g.setColor(Color.darkGray);
g.fillRect(0, 0, getWidth(), getHeight());
g.setColor(Color.gray);
g.fillRect(100, 100, 600, 700);
g.setColor(Color.white);
g.drawRect(99, 99, 601, 701);
g.drawString("Quit", 102, 86);
g.drawRect(100, 70, 30, 20);
g.drawString("Score: ", 602, 86);
g.setFont(ith);
g.drawString("SNAKE", 350, 60);
/* Sprite: Mouse */
g.setColor(Color.black);
g.fillRect(mx, my, width, height);
// System.out.print(mx + " " + my);
/* Sprite: Snake Body */
if (length != 0) {
for (int i = 0; i >= length; i++) {
g.setColor(Color.darkGray);
g.fillRect(bodyX.get(i), bodyY.get(i), width, height);
}
}
/* Sprite: Snake head */
g.setColor(Color.white);
g.fillRect(x, y, width, height);
}// Paint Component
public Dimension getPreferredSize() {
return new Dimension(800, 850);
}// Dimension
}// DrawPanel
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
new Snake2();
}
});
}// main
}// Snake Class
/* Tracks where mouse is clicked */
class MouseListener extends MouseAdapter {
public void mouseReleased(MouseEvent me) {
if (me.getX() >= 101 && me.getX() <= 131 && me.getY() >= 94
&& me.getY() <= 115) {
System.exit(0);
}
String str = "Mouse Released at " + me.getX() + "," + me.getY();
System.out.println(str);
}
}// MouseAdapter
package puzzle;
import java.awt.Color;
import javax.swing.*;
import java.util.*;
public class Puzzle {
Integer x = 50;
Integer y = 50;
int x2 = 100;
int y2 = 100;
int vnotx = 0;
int vnoty = 0;
float t = 0;
float t2 = 0;
JFrame frame = new JFrame();
Move m = new Move(x, y,Color.GREEN);
Move n = new Move(x,y,Color.ORANGE);
java.util.Timer timer = new java.util.Timer();
java.util.Timer timer2 = new java.util.Timer();
public Puzzle() {
frame.setUndecorated(true);
frame.setSize(400, 400);
frame.add(m);
frame.add(n);
frame.addKeyListener(new java.awt.event.KeyAdapter() {
public void keyPressed(java.awt.event.KeyEvent evt) {
formKeyPressed(evt);
}
});
com.sun.awt.AWTUtilities.setWindowOpacity(frame, 1f);
timer.scheduleAtFixedRate(new TimerTask() {
public void run() {
rD();
}
}, 0, 20);
timer2.scheduleAtFixedRate(new TimerTask() {
public void run() {
t2+=.01;
x2 =(int) ((Math.cos(t2)+1)*100);
y2 =(int) ((Math.sin(t2)+1)*100);
System.out.println(x2+", "+y2);
}
}, 0, 2);
}
int z = 0;
public void rD() {
z++;
m = new Move(x, y, Color.GREEN);
n = new Move(x2, y2, Color.ORANGE);
frame.add(n);
frame.add(m);
frame.validate();
}
private void formKeyPressed(java.awt.event.KeyEvent evt) {
int id = evt.getID();
int kC = evt.getKeyCode();
if (kC == 39) {
final java.util.Timer right = new java.util.Timer();
right.scheduleAtFixedRate(new TimerTask() {
public void run() {
t += .01;
int x1 = x;
if (x + 51 < 400) {
x = x1 + (int) (10 * t) + (-1 * ((int) (20 * t * t)));
}
if (t > .5) {
t = 0;
right.cancel();
}
}
}, 0, 10);
}
if (kC == 37) {
final java.util.Timer left = new java.util.Timer();
left.scheduleAtFixedRate(new TimerTask() {
public void run() {
t += .01;
int x1 = x;
if (x - 1 >= 0) {
x = x1 + (int) (-10 * t) - (-1 * ((int) (20 * t * t)));
}
if (t > .5) {
t = 0;
left.cancel();
}
}
}, 0, 10);
}
if (kC == 40) {
final java.util.Timer right = new java.util.Timer();
right.scheduleAtFixedRate(new TimerTask() {
public void run() {
t += .01;
int y1 = y;
if (y + 51 < 400) {
y = y1 + (int) (10 * t) + (-1 * ((int) (20 * t * t)));
}
if (t > .5) {
t = 0;
right.cancel();
}
}
}, 0, 10);
}
if (kC == 38) {
final java.util.Timer left = new java.util.Timer();
left.scheduleAtFixedRate(new TimerTask() {
public void run() {
t += .01;
int y1 = y;
if (y-1 >= 0)
{
y = y1 + (int) (-10 * t) - (-1 * ((int) (20 * t * t)));
}
if (t > .5) {
t = 0;
left.cancel();
}
}
}, 0, 10);
}
if (kC == 32) {
}
if (kC == 67) {
}
if (kC == 77) {
}
}
public static void main(String[] args) {
new Puzzle().frame.setVisible(true);
}
}
why is this not adding both instances of the move class. it only adds the last one called. the class paint is below what should i change in order for it paint both instances of move
package puzzle;
import java.awt.*;
import java.awt.geom.*;
import javax.swing.*;
public class Move extends JPanel{
int x;
int y;
Color kk;
public Move(int x1, int y1, Color k)
{
x=x1;
y=y1;
kk = k;
}
public void paintComponent(Graphics g)
{Graphics2D g2 = (Graphics2D)g;
super.paintComponent(g2);
g2.setColor(kk);
g2.fill(new RoundRectangle2D.Float(x, y, 50, 50,10,10));
g2.drawString(x+", "+y, 200, 200);
}
}
the class move paints a rectangle with the position and color passed from the puzzle class
Are you taking layout managers into consideration? Do you know about JFrame's contentPane using BorderLayout as its default layout manager, and if you add components to this without constants, they are added BorderLayout.CENTER, and only one of these can be visible at a time (the last added).
I think that you might do better disassociating Move from JPanel, yes making it paintable, but making it more of a logical object rather than a gui component and instead of having it extend JPanel, allow a single drawing JPanel to hold one or more Move objects and then draw the Move objects in this JPanel's paintComponent method.
Also, you seem to be using several java.util.Timers in your code, but since it is a Swing application, it would likely be better served by using javax.swing.Timers instead, in fact perhaps just one Swing Timer that functioned as a game loop.
if (kC == 39) {
Don't use magic numbers.
Instead you should be using:
KeyEvent.VK_???