Pong game is running too fast with FPS counter - java

I have a Pong game with an FPS counter but I have a few problems. I want the FPS counter to NOT be limited at 60 FPS, I want the FPS counter to go as high as it can.
The FPS is currently working but the problem is that the game is running REALLY fast, I want the game to always run at a speed that is playable. I tried adding a timer for 5 ms but that caused the FPS counter to not work properly.
I want the FPS counter to NOT be limited at 60 FPS but at the same time use some sort of timer. Here is my code:
package Game;
import java.awt.*;
import java.awt.event.*;
import java.util.Random;
import javax.swing.*;
public class Main extends JPanel implements KeyListener, ActionListener{
// Lite variabler
JFrame frame;
int windowWidth, windowHeight;
Point bollXY;
int screenWidth, screenHeight;
Image bildPaddel;
Image bildBollen;
int paddelY;
int paddel2Y;
boolean paddelUp, paddelDown;
Random rand;
int score, score2;
boolean bollUp, bollRight, changeDirection;
int fruktDistansRand;
long time;
int fps, newfps;
int fpsTimesCounter;
// Konstruktor
public Main(){
// Definera variabler
frame = new JFrame();
bildPaddel = new ImageIcon("src/images/Player.png").getImage();
bildBollen = new ImageIcon("src/images/Pong.png").getImage();
bollXY = new Point(673, 352);
paddelY = 312;
paddel2Y = 312;
paddelUp = false;
rand = new Random();
score = 0;
score2 = 0;
bollUp = false;
bollRight = false;
changeDirection = false;
fruktDistansRand = 0;
time = System.currentTimeMillis();
fps = 0;
newfps = 0;
fpsTimesCounter = 0;
// Lyssnare
frame.addKeyListener(this);
// Bygga fönstret
frame.add(this);
// Obligatoriska egenskaper
frame.setTitle("Pong");
frame.setSize(1366, 724); // Eftersom spelet inte ska vara helt i fullskärm sätts fönstret på 1366x724 så att aktivitetsfältet syns
frame.setVisible(true);
frame.setLocationRelativeTo(null); // Centrerar fönstret
frame.setResizable(false);
this.setBackground(Color.BLACK);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
bollUp = true;
bollRight = true;
changeDirection = false;
bollXY = new Point();
frame.add(this);
}
// Metoder
public static void main(String[] args) {
new Main();
}
#Override
public void paintComponent(Graphics g){
super.paintComponent(g);
g.drawImage(bildBollen, bollXY.x, bollXY.y, null);
g.drawImage(bildPaddel, 50, paddelY, null);
g.drawImage(bildPaddel, 1300, paddel2Y, null);
g.setFont(new Font("Arial", Font.BOLD, 100));
g.setColor(Color.WHITE);
g.drawString(score2 + "", 1002, 100);
g.drawString(score + "", 314, 100);
if(System.currentTimeMillis() - time >= 1000){
time = System.currentTimeMillis();
fps = newfps;
newfps = 0;
}
else{
newfps++;
}
g.setFont(new Font("Arial", Font.BOLD, 25));
g.drawString(fps + "", 5, 22);
update();
}
public void AI(){
fruktDistansRand = rand.nextInt(200) + 950;
if(bollXY.x > fruktDistansRand && bollXY.x < 1380 && bollRight && paddel2Y > 0 && paddel2Y < 596){
if(paddel2Y + 50 < bollXY.y){
paddel2Y = paddel2Y + 3;
}
else{
paddel2Y = paddel2Y - 3;
}
if(paddel2Y <= 0){
paddel2Y = paddel2Y + 3;
}
if(paddel2Y >= 596){
paddel2Y = paddel2Y - 3;
}
}
}
public void ifUp(){
if(bollUp){
if(changeDirection){
if(bollXY.y < 0){
bollUp = false;
}
else{
bollXY.y = bollXY.y - 3;
}
}
else{
if(bollXY.y < 0){
bollUp = false;
}
else{
bollXY.y = bollXY.y - 3;
}
}
}
else{
if(changeDirection){
if(bollXY.y > 675){
bollUp = true;
}
else{
bollXY.y = bollXY.y + 3;
}
}
else{
if(bollXY.y > 675){
bollUp = true;
}
else{
bollXY.y = bollXY.y + 3;
}
}
}
}
public void update(){
if(paddelUp){
if(paddelY > 0){
paddelY = paddelY - 3;
}
}
if(paddelDown){
if(paddelY < 596){
paddelY = paddelY + 3;
}
}
if(bollRight){
if(bollXY.x > 1290 && bollXY.x < 1300 && bollXY.y < paddel2Y + 100 && bollXY.y > paddel2Y-20){
if(!bollUp && bollXY.y < paddel2Y){
changeDirection = true;
bollUp = true;
}
else if(bollUp && bollXY.y > paddel2Y + 80){
changeDirection = true;
bollUp = false;
}
bollRight = false;
}
else if(bollXY.x > 1600){
score++;
bollXY.y = rand.nextInt(690);
bollXY.x = 678;
}
else
bollXY.x = bollXY.x + 3;
ifUp();
}
else{
if(bollXY.x > 50 && bollXY.x < 60 &&bollXY.y < paddelY + 100 && bollXY.y > paddelY-20){
if(!bollUp && bollXY.y < paddelY){
changeDirection = true;
bollUp = true;
}
else if(bollUp && bollXY.y > paddelY + 80){
changeDirection = true;
bollUp = false;
}
bollRight = true;
}
else if(bollXY.x < -244){
score2++;
bollXY.x = 678;
bollXY.y = rand.nextInt(596);
}
else
bollXY.x = bollXY.x - 3;
ifUp();
}
AI();
repaint();
}
#Override
public void actionPerformed(ActionEvent e) {
update();
}
#Override
public void keyPressed(KeyEvent e) {
if(e.getKeyCode() == KeyEvent.VK_W || e.getKeyCode() == KeyEvent.VK_UP){
paddelUp = true;
}
if(e.getKeyCode() == KeyEvent.VK_S || e.getKeyCode() == KeyEvent.VK_DOWN){
paddelDown = true;
}
}
#Override
public void keyReleased(KeyEvent e) {
if(e.getKeyCode() == KeyEvent.VK_W || e.getKeyCode() == KeyEvent.VK_UP){
paddelUp = false;
}
if(e.getKeyCode() == KeyEvent.VK_S || e.getKeyCode() == KeyEvent.VK_DOWN){
paddelDown = false;
}
}
#Override
public void keyTyped(KeyEvent e) {
}
}

Your game is running really fast, because you use a static increment in each cpu cycle. If you run this program on an slow cpu, your game will run slower. If you run it with a fast cpu your game will run faster.
cpu 1: 100 cycles per second: your ball will move 300 units per second.
cpu 2: 2000 cycles per second: your ball will move 6000 units per second.
When you capped your game at 60 fps, you avoided that issue, because the update will only happen 60 times per second and not 100 or 2000 times.
Another option is to involve time.
This means you measure the time since the last frame and use it as an multiplicator. The faster your cpu runs the lower your time between frames will be. Your ball will move acording to you time. If your your cpu is slower the time between your frames increases and the ball will move further.
float delta = // time between your frames
pulic void update(float delta){
...
bollXY.y -= delta * 3;
Alternatively a great article for game loops: https://gafferongames.com/post/fix_your_timestep/

Related

Why are there two player speeds in my game?

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.

Intersect function stops working after the first intersect

im making a game, but i ran into a problem while working with the function "intersect".
the senario looks like this; i've made a game where the player is a rectangle were the objective is to kill the enemy rectangle. The enemy "boss" rectangle has two "simulations" that simulate a movement and an attack these simulations are driven by vectors. The movement is horizantally back and forth and the attack is in a vertical maner, a charge type of deal. The boss also has a rectangular target area where if itersected the "boss" will charge across the screen.
now the problem comes when i tried to make it so that if the player intersects with the rectangular target area the "boss" will attack/charge. The boss attack/charge the first time the player intersects but not after that. I want the boss to follow the same pantern, is that he should only be able to go from side to side horizantaly and if Target area intersected; attack/charge verticaly.
( i will include some code bellow. sorry if my english is bad. )
first comes the main:
boss b;
Character C;
void setup(){
C = new Character();
b = new boss();
}
void draw(){
if (play) {
b.simulate(); //horizantal movement
}
if (b.start) {
b.sim(); //boss vertical attack
}
if (b.intersects(C)){
play = false;
b.start = true;
}
C.character(); //player
b.bounce(); //makes it bounce if horizantal. and stop if vertical
b.Display(); //boss
b.display(); //boss target area
}
Next comes the boss:
class boss {
int x = 10 ;
int y = 10 ;
boolean start = false;
int RW = 50;
int RH = 700;
boolean up = false;
boolean down = true;
boss() {
Location = new PVector( x+25, y ); //vector for the location of the boss
Velocity = new PVector( 5, 0 ); // vector for horizaltal movement
speed = new PVector( 0, 10 ); // vector for vertical down movement
speed2 = new PVector(0, -10); // vector for vertical up movement
}
void bounce() {
if ((Location.x == width) ||(Location.x == 0)) { //horizantal movement bounce on screen edge
Velocity.x = Velocity.x * -1;
}
if ((Location.y == 650) || (Location.y == 0)) {
start = false; //makes boss stop if reaches botton or top of the screen
play = true;
if (Location.y == 650) {
RH = -700;
up = true;
down = false; //specificly if it reaches top of screen
}
if (Location.y == 0) {
RH = 700;
down = true; //specificly if it reaches bottom of screen
up = false;
}
}
}
void simulate() {
Location.add(Velocity); //simulates horizantal movement
}
void sim() {
if (down) {
Location.add(speed); //simulates up and down attacking movemnet
}
if (up) {
Location.add(speed2);
}
}
boolean intersects(Character C) {
return Location.x < C.x + C.w && C.x < Location.x + RW &&
Location.y < C.y + C.h && C.y < Location.y + RH; //intersect between player and boss targeting area
}
void Display() {
rect( Location.x, Location.y, 50, 50 ); //boss
}
void display() {
rect( Location.x, Location.y+50, RW, RH ); //boss targeting area
}
}
if anything is unclear i will gladly clear up any confusion. :)
Thanks for sharing the code. It made it much easier.
When I comment this piece (not the if-condition the reset of start after the if)
if ((Location.y == 650) || (Location.y == 0)) {
// start = false;
then the boss starts going back up top and still calls intersects the Character when the co-ordinates match. However, post this the boss keeps bouncing up and down.
There is surely more work to be done on this to take account of the bullets fired and the hits to boss.
Hope this helps. :) It was fun debugging this code. I had never used PDE before this.
ok, here is the "edit"..
Now,
Good News: I can make it go in both directions only when it intersects
Bad News: It keeps going to the other side as long as it is intersecting. So if the Character is stationary then boss keeps intersecting and passing to the other side at least 8-10 times in the current speed.
Anyways, here is the summary. I added and isAttacking flag that tells the program to not stop the boss from crossing over if it has reached the bottom of the frame. The other thing I changed was the intersection condition. Now it just checks for intersection on the X-Axis. If you must compare intersection on the Y-Axis too then intersects is where you need to change & test.
After the long explanation :P Here is the code. Hope this is better.
Main
boss b;
Character C;
Inventory I;
Bullet B;
int previousKey = 0;
int lastKey;
int lastKeyCode;
void setup() {
C = new Character();
b = new boss();
I = new Inventory();
background(128, 128, 128);
size( 700, 700 );
strokeWeight( 10 );
frameRate( 30 );
}
void keyPressed() {
if (key == CODED) {
previousKey = keyCode;
if (keyCode == UP) {
C.MoveUP();
}
if (keyCode == LEFT) {
C.MoveLEFT();
}
if (keyCode == DOWN) {
C.MoveDOWN();
}
if (keyCode == RIGHT) {
C.MoveRIGHT();
}
}
if (key == 'w' || key == 'W') {
attack();
}
if ( key == 'q' || key == 'Q' ) {
if (I.Shoot == true) {
B = new Bullet(C.x, C.y);
this.Shoot();
}
} else if (key == 'e' || key == 'E') {
I.changePop();
}
if (keyPressed) {
if (key == 'a' || key == 'A') {
//play = false;
//b.start = true;
}
}
}
void attack() {
if (I.Attack == true) {
if (previousKey == UP) {
C.AttackUP();
}
if (previousKey == LEFT) {
C.AttackLEFT();
}
if (previousKey == DOWN) {
C.AttackDOWN();
}
if (previousKey == RIGHT) {
C.AttackRIGHT();
}
}
}
void Shoot() {
if (I.Shoot == true) {
if (previousKey == UP) {
B.ShootUP();
}
if (previousKey == LEFT) {
B.ShootLEFT();
}
if (previousKey == DOWN) {
B.ShootDOWN();
}
if (previousKey == RIGHT) {
B.ShootRIGHT();
}
}
}
boolean play = true;
void keyReleased() {
lastKey = 0;
lastKeyCode = 0;
}
void draw() {
background(128, 128, 128);
if (play) {
b.simulate();//side to side
}
if (b.start) {
b.sim(); //boss rush
}
if (b.intersects(C)) {
b.isAttacking = true;
play = false;
b.start = true;
} else {
b.isAttacking= false;
}
C.character();
b.bounce();
b.Display();//boss
b.display();//rush area
C.HPbar();
I.popUp();
if ( key == 'q' || key == 'Q' ) {
if (I.Shoot == true) {
B.bullet();
B.Simulate();
}
}
}
Enemies or Boss
class boss {
PVector Location;
PVector Velocity;
PVector speed;
PVector speed2;
int x = 10 ;
int y = 10 ;
boolean start = false;
int RW = 50;
int RH = 700;
boolean up = false;
boolean down = true;
boolean isAttacking = false;
boss() {
Location = new PVector( x+25, y );
Velocity = new PVector( 5, 0 );
speed = new PVector( 0, 10 );
speed2 = new PVector(0, -10);
}
void bounce() {
if ((Location.x == width) ||(Location.x == 0)) {
Velocity.x = Velocity.x * -1;
}
if ((Location.y == 650) || (Location.y == 0)) {
if (!isAttacking) {
start = false;
}
play = true;
if (Location.y == 650) {
RH = -700;
up = true;
down = false;
}
if (Location.y == 0) {
RH = 700;
down = true;
up = false;
}
}
}
void simulate() {
Location.add(Velocity);
}
void sim() {
//print("\n In Sim UP: [" + up + "] Down: [" + down + "] Location [" + Location + "]");
if (down) {
Location.add(speed);
}
if (up) {
Location.add(speed2);
}
}
boolean intersects(Character C) {
//print ("\nUP: [" + up + "] Down: [" + down + "] X: [" + (Location.x < (C.x + C.w) && (Location.x + RW) > C.x)
//+ "] Y: [" + (Location.y < (C.y + C.h) && (Location.y + RH) > C.y) + "]");
return Location.x < (C.x + C.w) && (Location.x + RW) > C.x;
//&&
// Location.y < (C.y + C.h) && (Location.y + RH) > C.y ;
}
void Display() {
pushStyle();
stroke(0);
fill(255, 0, 0);
rect( Location.x, Location.y, 50, 50 );
popStyle();
}
void display() {
pushStyle();
stroke(0);
strokeWeight(0);
fill(255, 0, 0, 20);
rect( Location.x, Location.y+50, RW, RH );
popStyle();
}
}

How do I make my game slower (slower FPS)?

So I wrote this code for a game and now that game is very speeded up. I want to lower the FPS so that the game slows down a bit.
I thought the only way out for me is to make a timer. But I'm finding it difficult to locate where to place the timer? Can anyone help me with this?
So I wrote this code for a game and now that game is very speeded up. I want to lower the FPS so that the game slows down a bit.
I thought the only way out for me is to make a timer. But I'm finding it difficult to locate where to place the timer? Can anyone help me with this?
public class Gamepanel extends JPanel implements Runnable, KeyListener {
private static final long serialVersionUID = 1L;
public static final int WIDTH = 500, HEIGHT = 500;
private Thread thread;
private boolean running;
private boolean right = false, left = false, up = false, down= false;
private BodyPart b;
private ArrayList<BodyPart> snake;
private Apple apple;
private ArrayList<Apple> apples;
private Random r;
private int xCoor = 10, yCoor = 10, size = 1;
private int ticks = 0;
public Gamepanel(){
setFocusable(true);
setPreferredSize(new Dimension(WIDTH, HEIGHT));
addKeyListener(this);
snake = new ArrayList<BodyPart>();
apples = new ArrayList<Apple>();
r = new Random();
start();
}
public void start () {
running = true;
thread = new Thread(this);
thread.start();
}
public void stop() {
running = false;
try {
thread.join();
} catch(InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public void tick() {
if(snake.size()==0) {
b= new BodyPart(xCoor, yCoor, 10);
snake.add(b);
}
ticks++;
if(ticks > 250000) {
if(right) xCoor++;
if(left) xCoor--;
if(up) yCoor--;
if(down) yCoor++;
ticks = 0;
b = new BodyPart(xCoor, yCoor, 10);
snake.add(b);
if(snake.size() > size) {
snake.remove(0);
}
}
if(apples.size()==0) {
int xCoor = r.nextInt(49);
int yCoor = r.nextInt(49);
apple = new Apple(xCoor,yCoor,10);
apples.add(apple);
}
for(int i = 0; i < apples.size(); i++) {
if(xCoor == apples.get(i).getxCoor() && yCoor == apples.get(i).getyCoor()) {
size++;
apples.remove(i);
i++;
}
}
//COLLISION ON SNAKE BODY
for (int i = 0; i < snake.size(); i++) {
if(xCoor == snake.get(i).getxCoor() && yCoor == snake.get(i).getyCoor()) {
if(i != snake.size() - 1) {
System.out.print("Game Over");
stop();
}
}
//COLLISION ON BORDER
if(xCoor < 0 || xCoor > 49 || yCoor < 0 || yCoor > 49) {
System.out.print("Game Over" + '\n');
System.out.println("Your Score is: " + snake.size());
stop();
}
}
}
public void paint(Graphics g) {
g.clearRect(0, 0, WIDTH, HEIGHT);
g.setColor(Color.BLACK);
g.fillRect(0, 0, WIDTH, HEIGHT);
for (int i=0; i< WIDTH/10; i++) {
g.drawLine(i * 10, 0, i * 10, HEIGHT);
}
for (int i=0; i< HEIGHT/10; i++) {
g.drawLine(0, i * 10, HEIGHT, i * 10);
}
for (int i = 0; i< snake.size(); i++) {
snake.get(i).draw(g);
}
for (int i = 0; i< apples.size(); i++) {
apples.get(i).draw(g);
}
}
#Override
public void run() {
while(running) {
tick();
repaint();
}
}
#Override
public void keyTyped(KeyEvent e) {
// TODO Auto-generated method stub
}
#Override
public void keyPressed(KeyEvent e) {
int key = e.getKeyCode();
if(key == KeyEvent.VK_D && !left) {
right = true;
up = false;
down=false;
}
if(key == KeyEvent.VK_A && !right) {
left = true;
up = false;
down = false;
}
if(key == KeyEvent.VK_W && !down) {
up=true;
left=false;
right=false;
}
if(key == KeyEvent.VK_S && !up) {
down=true;
left=false;
right=false;
}
}
#Override
public void keyReleased(KeyEvent e) {
}
}
The problem with your code is that now, game speed won't be the same on different machines, as some computers may execute your code faster and some may execute slower.
If you want your game to execute on every computer with the same speed you need define some kind of speed for your snake (unit per second) and then in game loop update your snake position based on how much time elapsed from last frame (last call of tick method)
// snake speed
double speed = 1.0; // units per second
// in game loop (your tick method)
position = speed * deltaTime;
now your position is not anymore depended on game framerate. On faster devices game will update snake position more often but deltaTime will be smaller as well as changes of position, on the other hand on slower devices tick method will be called less frequent but deltaTime will be higher

Ball going through paddle when increasing velocity

I am trying to create a Pong game and so far I have everything working for me other than the ball. At first I had the ball's x and y axis move up by one space each time. It was working fine until i decided to increase it to 2. I cant figure out what is wrong with my code and I need help.
import java.awt.Graphics;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class Pong extends JPanel implements KeyListener{
int x = 90;
int y = 90;
int rectytop = 30;
int rectytop2 = 30;
int rectybottom = rectytop + 100;
int rectybottom2 = rectytop2 + 100;
int border = 30;
boolean balldown = true;
boolean ballright = true;
boolean playerborderup = false;
boolean playerborderdown = false;
boolean balltouch1 = false;
boolean balltouch2 = false;
private void moveball() {
if (balldown == true){
y = y + 2;
}
if (y == getHeight()-border){
balldown = false;
}
if (balldown == false){
y = y - 2;
}
if (ballright == true){
x = x + 2;
}
if (x == getWidth()-border){
ballright = false;
}
if (ballright == false){
x = x - 2;
}
if (y == 0){
balldown = true;
}
if (x == 0){
ballright = true;
}
if (balltouch1 == false){
if (x == 75){
if(y < rectybottom && y > rectytop){
ballright = true;
}
}
}
if (balltouch2 == false){
if (x == 390 && y < rectybottom2 && y > rectytop2){
ballright = false;
}
}
}
#Override
public void paint(Graphics g){
super.paint(g);
//drawing ball and paddles
g.fillOval(x, y, 30, 30);
g.fillRect(45 , rectytop, 30, 100);
g.fillRect(425, rectytop2, 30, 100);
}
public static void main(String[] args) throws InterruptedException {
//making the window
JFrame f = new JFrame("Pong Game");
Pong game = new Pong();
f.setVisible(true);
f.setSize(500, 500);//1024, 724
f.setResizable(true);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.addKeyListener(game);
//game code
f.add(game);
while (true){
game.repaint();
game.moveball();
Thread.sleep(10);
}
}
#Override
public void keyTyped(KeyEvent e) {
}
#Override
public void keyPressed(KeyEvent e) {
//player one
if (e.getKeyCode() == KeyEvent.VK_W){
if (rectytop == 0){
playerborderup = true;
}
if (rectytop != 0){
playerborderup = false;
}
if (playerborderup == true){
rectytop = rectytop + 0;
rectybottom = rectytop + 100;
repaint();
}
if (playerborderup == false){
rectytop = rectytop - 5;
rectybottom = rectytop + 100;
repaint();
}
}
if (e.getKeyCode() == KeyEvent.VK_S){
if (rectytop == 585){
playerborderdown = true;
}
if (rectytop != 585){
playerborderdown = false;
}
if (playerborderdown == true){
rectytop = rectytop - 0;
rectybottom = rectytop + 100;
repaint();
}
if (playerborderdown == false){
rectytop = rectytop + 5;
rectybottom = rectytop + 100;
repaint();
}
}
//player two
if (e.getKeyCode() == KeyEvent.VK_UP){
if (rectytop2 == 0){
playerborderup = true;
}
if (rectytop2 != 0){
playerborderup = false;
}
if (playerborderup == true){
rectytop2 = rectytop2 + 0;
rectybottom2 = rectytop2 + 100;
repaint();
}
if (playerborderup == false){
rectytop2 = rectytop2 - 5;
rectybottom2 = rectytop2 + 100;
repaint();
}
}
if (e.getKeyCode() == KeyEvent.VK_DOWN){
if (rectytop2 == 585){
playerborderdown = true;
}
if (rectytop2 != 585){
playerborderdown = false;
}
if (playerborderdown == true){
rectytop2 = rectytop2 - 0;
rectybottom2 = rectytop2 + 100;
repaint();
}
if (playerborderdown == false){
rectytop2 = rectytop2 + 5;
rectybottom2 = rectytop2 + 100;
repaint();
}
}
}
#Override
public void keyReleased(KeyEvent e) {
}
}
Since you are moving by 2 every time, it may "skip" over some coordinates. Thus when you say
if (y == getHeight()-border){
balldown = false;
}
y might go from getHeight()-border + 1 to getHeight()-border - 1 and never meet this condition. Thus, change it to a range or a less than. Your new code should be
if (y <= getHeight()-border +1){
balldown = false; //change the +1 and -1 to have difference at least speed number
}
Note that you must do the same for the other ifs with ==, change
if (x == getWidth()-border){
ballright = false;
}
if (y == 0){
balldown = true;
}
if (x == 0){
ballright = true;
}
to
if (x <= getWidth()-border +1){
ballright = false;
}
if (y <= 1){
balldown = true;
}
if (x <= 1){
ballright = true;
}
Note that you can resolve the problem also by saying if the position is eer exactly one away from the border, temporarily decrement position by 1 instead of 2.
You are using if (x == 75) to detect collision with the left paddle. But if speed is 2 than the ball's x is always even and never equals 75. For a quick fix, check x against a range: if (x > 60 && x < 75)

Processing game: Gif images not respawning as intended

I am a diploma student making a game based on processing, it's a tower defense game where a heroine would be shooting arrows at zombies charging towards the castle. I have multiple issues with this.
The charger zombies do not respawn after being shot dead.
All of the charger zombies die together when I shot only one charger zombie.
Supposedly I wanted the zombies to spawn in waves repeatedly after a group of them has been shot down, and then I want the charger zombies to die individually, depending on the one I click on.
Here's my source code:
import processing.opengl.*; // transparency
import gifAnimation.*; // after add gifAnimation library
import ddf.minim.*; // importing music
PImage backgroundImg;
PImage animation;
int counter;
//settings
int score = 50, totalScore = 0;
int titleX = 200, titleY = 200;
boolean shotsFired = false;
PFont scorePoints, castleHealthPoints, font; //font for startingScreen
int chargerKilled;
//Charger class
int maxChargerOnScreen;
Charger[] chargerArr; //chargerArray undefined
int chargerIndex;
final int numCharger = 300;
ArrayList<Charger> onScreen = new ArrayList<Charger>();
boolean chargerReachedTarget = false, chargerShot = false, chargerDive = true;
Gif chargerCharge, chargerAttack, chargerDied, shootingStance;
int chargerMoveX = 800, chargerMoveY = 450;
// CastleWallHealth
int castleHealth = 1000;
// audio
Minim minim;
AudioPlayer song;
AudioSnippet arrowShoot;
//-------------------------------Codes start here --------------------------------------------------//
void setup() {
//ipad mini size
// frameRate(10);
frameRate(60);
size(800, 600);
smooth();
minim = new Minim(this);
// song = minim.loadFile("InGameSoundtrack.mp3");
// song.play();
arrowShoot = minim.loadSnippet("arrowSound1.wav");
backgroundImg = loadImage("GameBackground.jpg");
backgroundImg.resize(800, 600);
chargerCharge = new Gif(this, "ChargerCharge.gif");
chargerAttack = new Gif(this, "ChargerAttack.gif");
chargerDied = new Gif(this, "ChargerDie.gif");
gargoyleFly = new Gif(this, "GargoyleFly.gif");
gargoyleAttack = new Gif(this, "GargoyleAttack.gif");
shootingStance = new Gif(this, "ShootingGif.gif");
scorePoints = createFont("Arial", 16, true);
castleHealthPoints = createFont("Arial", 16, true);
// loopingGif.play() plays the animation without loop
// must make charger
chargerCharge.play();
chargerAttack.play();
chargerDied.play();
resetGames(); // starts with respawning 5 charges
}
void draw() {
// backgroud
background(backgroundImg);
image(shootingStance, 120,200);
// scores and health
textFont(scorePoints, 15);
fill(0);
text("Score: " + totalScore, 100, 100);
displayCastleHealth();
//*********************************************charger settings code********************************************************************
// If there's no more zombies. prompt reset (screen no zombies) , index from 0 add till 300 then game won
if (onScreen.size() == 0 && chargerIndex == numCharger) {
println("Game won! :)");
// gameWon = true;
}
// while onScreen charger less than 5 only and chargerIndex havent reach 300 it will only respawn
while (onScreen.size () < maxChargerOnScreen && chargerIndex <= numCharger - 1) {
if (chargerIndex < chargerArr.length) { // <--- this is the problem chargerArrayLength
Charger chargerMobs = chargerArr[chargerIndex];
// starts from chargerArray[0] to chargerArray[300]
onScreen.add(chargerMobs);
chargerIndex++;
// chargerIndex keeps looping why?
// println("ADDED ZOMBIE TO ONSCREEN Zombs on screen: " + onScreen.size());
}
}
// Adjusts maxZombOnScreen based off the current index Difficulties?
if (chargerIndex == 10)
maxChargerOnScreen++;
else if (chargerIndex == 50)
maxChargerOnScreen++;
else if (chargerIndex == 100)
maxChargerOnScreen += 2;
else if (chargerIndex == 150)
maxChargerOnScreen += 2;
else if (chargerIndex == 190)
maxChargerOnScreen += 3;
else if (chargerIndex == 250)
maxChargerOnScreen += 3;
else if (chargerIndex == 260)
maxChargerOnScreen += 3;
else if (chargerIndex == 270)
maxChargerOnScreen += 5;
// removes dead zombies, living zombies act normally
for(int i = 0; i < onScreen.size(); i++) {
Charger c = onScreen.get(i);
// add money when a zombie is dead
// if (c.getHealth() <= 0)
if (chargerShot==true) {
c.chargerDying();
onScreen.remove(i);
chargerKilled++;
i--;
} else {
c.act(); ///it should just act
// c.displayHealth(); // if gt time only do
// }
}
}
// creating list of predetermined zombies and their characteristics
println("chargerIndex: " + chargerIndex); // debug
println("onScreenSize: " + onScreen.size());
// println("ChargerArray: " + chargerArray.length); chargerArray point null?
// cursor
if (mouseY > height - 500) {
noFill();
stroke(255, 0, 0);
ellipse(mouseX, mouseY, 35, 35);
line(mouseX - 25, mouseY, mouseX + 25, mouseY);
line(mouseX, mouseY - 25, mouseX, mouseY + 25);
}
}
void resetGames() {
// resetting variables
chargerIndex = 0;
maxChargerOnScreen = 5;
chargerKilled = 0;
createNewCharger();
}
void createNewCharger() {
Charger[] temp = new Charger[numCharger];
for (int i = 0; i < numCharger; i++)
temp[i] = new Charger((int) random(800, 1200), chargerMoveY);
chargerArr = temp;
}
//____________________________________________________________________________________________________________-
class Charger {
private int chargerMoveX, chargerMoveY;
Gif chargerGif; // by default
// chargerGif will change based on input (either it reaches the castle or its shot)
// no constructor
Charger() {
chargerMoveX = 0;
chargerMoveY = 450;
}
// overloaded constructor
Charger(int cMoveX,int cMoveY) {
chargerMoveX = cMoveX;
chargerMoveY = cMoveY;
}
void act() { // use
// if reached castle it wont move
if (chargerMoveX <= 180) {
// remove gif images
chargerDive = false;
chargerReachedTarget = true;
}
// if not shot or reached castle it will move
if (chargerDive == true) {
chargerGif = chargerCharge;
image(chargerGif, chargerMoveX, chargerMoveY);
chargerMoveX -= 2;
}
// if reached castle perform attack animation
if (chargerReachedTarget == true) {
chargerGif = chargerAttack;
image(chargerGif, chargerMoveX - 80, chargerMoveY - 120);
}
if (mousePressed &&
mouseX < chargerMoveX + 180
&& mouseX > chargerMoveX
&& mouseY < chargerMoveY + 120
&& mouseY > chargerMoveY) {
// score board
totalScore = totalScore + score ;
float r = random(50);
println(r);
chargerShot = true;
chargerDive = false;
}
}
void chargerDying() {
chargerReachedTarget = false;
chargerGif = chargerDied;
image(chargerGif, chargerMoveX, chargerMoveY);
}
}
void displayCastleHealth() {
if (castleHealth <= 0) {
fill(250, 70, 0);
textFont(castleHealthPoints, 20);
text("HP: 0", 100, 50);
} else {
fill(250, 70, 0);
textFont(castleHealthPoints, 20);
text("HP: " + castleHealth, 100, 50);
}
}
void mousePressed() {
strokeWeight(2);
arrowShoot.rewind();
arrowShoot.play();
for (int i = 0 ; i < 3; i++)
shootingStance.play();
shotsFired = true;
}
void mouseReleased() {
strokeWeight(1);
if (shotsFired == true)
shootingStance.pause();
}
public void stop() {
arrowShoot.close();
}
Majority of the problems from the charger came from here:
if (onScreen.size() == 0 && chargerIndex == numCharger) {
println("Game won! :)");
// gameWon = true;
}
// while onScreen charger less than 5 only and chargerIndex havent reach 300 it will only respawn
while (onScreen.size () < maxChargerOnScreen && chargerIndex <= numCharger - 1) {
if (chargerIndex < chargerArr.length) { // <--- this is the problem chargerArrayLength
Charger chargerMobs = chargerArr[chargerIndex];
// starts from chargerArray[0] to chargerArray[300]
onScreen.add(chargerMobs);
chargerIndex++;
// chargerIndex keeps looping why?
// println("ADDED ZOMBIE TO ONSCREEN Zombs on screen: " + onScreen.size());
}
}
// Adjusts maxZombOnScreen based off the current index Difficulties?
if (chargerIndex == 10)
maxChargerOnScreen++;
else if (chargerIndex == 50)
maxChargerOnScreen++;
else if (chargerIndex == 100)
maxChargerOnScreen += 2;
else if (chargerIndex == 150)
maxChargerOnScreen += 2;
else if (chargerIndex == 190)
maxChargerOnScreen += 3;
else if (chargerIndex == 250)
maxChargerOnScreen += 3;
else if (chargerIndex == 260)
maxChargerOnScreen += 3;
else if (chargerIndex == 270)
maxChargerOnScreen += 5;
// removes dead zombies, living zombies act normally
for(int i = 0; i < onScreen.size(); i++) {
Charger c = onScreen.get(i);
// add money when a zombie is dead
// if (c.getHealth() <= 0)
if (chargerShot==true) {
c.chargerDying();
onScreen.remove(i);
chargerKilled++;
i--;
} else {
c.act(); ///it should just act
// c.displayHealth(); // if gt time only do
// }
}
}
Evaluation and criticism is appreciated.
There are several issues with the code, but for now, I'll ignore the parts that are somewhat "not clean" or "not elegant", and focus on the main problem that was the reason for the question:
The state of all Chargers instances was the same. The fields
boolean chargerReachedTarget = false, chargerShot = false, chargerDive = true;
have been defined globally. Just by moving this line (that is, these 3 fields) into the Charger class, and changing the line
if (chargerShot==true) {
to
if (c.chargerShot==true) {
the game already seemed to be much closer to what you presumably have been looking for. After this modification, it was possible to shoot individual opponents, and new opponents kept coming after the old ones had disappeared.
Again: The code is not really nicely structured, and there are many possible minor improvements. For example, something like if (c.chargerShot==true) { ... } should better be if (charger.isShot()) { ... }. But I'm not so familiar with processing and its best practices, so I'm not sure how the "best" solution would look like in a global sense...

Categories