How to keep generating rectangles and update them AnimationTimer? - java

The following code draws an intersection and adds a car, the car keeps moving until the end of its lane (since the light is red). I added the car in an ArrayList in order to keep generating cars and update them (to move). If I do cars.add(new Car()); inside the animation timer, it does not work. The car code generates a car at a random side (N,S,E,W) and with a random size. My question is, what can I write to let the code keep generating cars in an arraylist and updating them?
Simulator:
import java.util.ArrayList;
import javafx.animation.AnimationTimer;
import javafx.application.Application;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.canvas.Canvas;
import javafx.scene.canvas.GraphicsContext;
import javafx.stage.Stage;
public class Simulator extends Application {
ArrayList<Car> cars;
TrafficLight[] trafficLights;
TrafficLight northTrafficLight, westTrafficLight, eastTrafficLight, southTrafficLight;
Group root;
Canvas canvas;
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage primaryStage) {
primaryStage.setTitle("Simulator");
root = new Group();
cars = new ArrayList<Car>();
cars.add(new Car());
canvas = new Canvas(800, 800);
trafficLights = new TrafficLight[4];
// TrafficLights
trafficLights[0] = new TrafficLight(185, 135, 100, 200, true, "N");
trafficLights[1] = new TrafficLight(135, 565, 200, 100, true, "W");
trafficLights[2] = new TrafficLight(565, 185, 200, 100, false, "E");
trafficLights[3] = new TrafficLight(565, 565, 100, 200, false, "S");
GraphicsContext gc = canvas.getGraphicsContext2D();
drawShapes(gc);
update();
root.getChildren().add(canvas);
Scene scene = new Scene(root, 800, 800);
primaryStage.setScene(scene);
primaryStage.show();
}
private void drawShapes(GraphicsContext gc) {
// Draw Intersection
gc.setLineWidth(10.0);
gc.strokeLine(250, 0, 250, 250);
gc.strokeLine(0, 250, 250, 250);
gc.strokeLine(550, 0, 550, 250);
gc.strokeLine(550, 250, 800, 250);
gc.strokeLine(250, 550, 250, 800);
gc.strokeLine(250, 550, 0, 550);
gc.strokeLine(550, 550, 550, 800);
gc.strokeLine(550, 550, 800, 550);
// Draw Cars
for (int i = 0; i < cars.size(); i++) {
root.getChildren().add(cars.get(i).drawCar());
}
// Draw Traffic light
for (int i = 0; i < trafficLights.length; i++) {
root.getChildren().add(trafficLights[i].drawTL());
root.getChildren().add(trafficLights[i].drawRedCircle());
root.getChildren().add(trafficLights[i].drawGreenCircle());
}
}
private void update() {
AnimationTimer timer = new AnimationTimer() {
#Override
public void handle(long arg0) {
// TODO Auto-generated method stub
for (int i = 0; i < cars.size(); i++) {
String side = cars.get(i).getSide();
if (side == "N") {
if (cars.get(i).getYPosition() > 224) {
cars.get(i).stopCar();
} else {
// car = new Car(trafficLights[0]);
cars.get(i).incrementYPosition();
cars.get(i).drawCar();
}
} else if (side == "S") {
if (cars.get(i).getYPosition() < 550) {
cars.get(i).stopCar();
} else {
// car = new Car(trafficLights[0]);
cars.get(i).decrementYPosition();
cars.get(i).drawCar();
// System.out.println(car.getYPosition());
}
} else if (side == "W") {
if (cars.get(i).getXPosition() > 224) {
cars.get(i).stopCar();
} else {
// car = new Car(trafficLights[0]);
cars.get(i).incrementXPosition();
cars.get(i).drawCar();
}
} else {
if (cars.get(i).getXPosition() < 555) {
cars.get(i).stopCar();
} else {
// car = new Car(trafficLights[0]);
cars.get(i).decrementXPosition();
cars.get(i).drawCar();
// System.out.println(car.getXPosition());
}
}
}
System.out.println(cars.size());
}
};
timer.start();
}
}
Car:
import java.util.concurrent.ThreadLocalRandom;
import javafx.scene.shape.Rectangle;
public class Car {
int size;
int xposition;
int yposition;
int position;
TrafficLight TrfcLight;
String side;
Rectangle car;
public Car() {
car = new Rectangle();
size = ThreadLocalRandom.current().nextInt(25, 75 + 1);
position = ThreadLocalRandom.current().nextInt(0, 3 + 1);
switch(position) {
case 0: side = "N";
break;
case 1: side = "S";
break;
case 2: side = "W";
break;
case 3: side = "E";
break;
default: side = "N";
break;
}
if(side =="N") {
xposition = ThreadLocalRandom.current().nextInt(250-size, 550 -size + 1);
yposition = 0;
}else if(side =="S"){
xposition = ThreadLocalRandom.current().nextInt(250-size, 550 -size + 1);
yposition = 800-size/2;
}else if(side == "W") {
xposition = 0;
yposition = ThreadLocalRandom.current().nextInt(250-size, 550 -size + 1);
}else {
xposition = 800-size/2;
yposition = ThreadLocalRandom.current().nextInt(250-size, 550 -size + 1);
}
}
public Rectangle drawCar() {
car.setX(xposition);
car.setY(yposition);
car.setWidth(size/2);
car.setHeight(size/2);
return car;
}
public void stopCar() {
car.setX(xposition);
car.setY(yposition);
}
public int getXPosition() {
return xposition;
}
public int getYPosition() {
return yposition;
}
public int getSize() {
return size;
}
public String getSide() {
return side;
}
public void incrementXPosition() {
xposition+=2;
}
public void incrementYPosition() {
yposition+=2;
}
public void decrementXPosition() {
xposition-=2;
}
public void decrementYPosition() {
yposition-=2;
}
}
TrafficLight:
import javafx.scene.paint.Color;
import javafx.scene.shape.Circle;
import javafx.scene.shape.Rectangle;
public class TrafficLight {
int x, y, width, height;
Rectangle trafficLight;
Circle red, green;
Color color;
boolean solution;
String side;
public TrafficLight() {
trafficLight = new Rectangle();
red = new Circle();
green = new Circle();
}
public TrafficLight(int x, int y, int width, int height, boolean solution, String side) {
this.x = x;
this.y = y;
this.width = width;
this.height = height;
this.solution = solution;
this.side = side;
trafficLight = new Rectangle();
red = new Circle();
green = new Circle();
}
public Rectangle drawTL() {
trafficLight.setX(x);
trafficLight.setY(y);
trafficLight.setWidth(width/2);
trafficLight.setHeight(height/2);
trafficLight.setFill(Color.TRANSPARENT);
trafficLight.setStroke(Color.BLACK);
trafficLight.setStrokeWidth(5);
return trafficLight;
}
public Circle drawRedCircle() {
if(width < height) {
red.setCenterX(trafficLight.getX()+(trafficLight.getHeight()/4));
red.setCenterY(trafficLight.getY()+(trafficLight.getHeight()/4));
red.setRadius(trafficLight.getHeight()/7);
if(solution) {
red.setFill(Color.TRANSPARENT);
red.setStroke(Color.BLACK);
red.setStrokeWidth(2);
side = "N";
color = Color.TRANSPARENT;
}else {
red.setFill(Color.RED);
red.setStroke(Color.BLACK);
red.setStrokeWidth(2);
side ="S";
color = Color.RED;
}
}else{
red.setCenterX(trafficLight.getX()+(trafficLight.getHeight()/2));
red.setCenterY(trafficLight.getY()+(trafficLight.getHeight()/2));
red.setRadius(trafficLight.getWidth()/7);
if(solution) {
red.setFill(Color.TRANSPARENT);
red.setStroke(Color.BLACK);
red.setStrokeWidth(2);
side = "W";
color = Color.TRANSPARENT;
}else {
red.setFill(Color.RED);
red.setStroke(Color.BLACK);
red.setStrokeWidth(2);
side = "E";
color = Color.RED;
}
}
return red;
}
public Circle drawGreenCircle() {
if(width < height) {
green.setCenterX(red.getCenterX());
green.setCenterY(red.getCenterY()+50);
green.setRadius(trafficLight.getHeight()/7);
if(solution) {
green.setFill(Color.RED);
green.setStroke(Color.BLACK);
green.setStrokeWidth(2);
color = Color.RED;
}else {
green.setFill(Color.TRANSPARENT);
green.setStroke(Color.BLACK);
green.setStrokeWidth(2);
color = Color.TRANSPARENT;
}
}else {
green.setCenterX(red.getCenterX()+50);
green.setCenterY(red.getCenterY());
green.setRadius(trafficLight.getWidth()/7);
if(solution) {
green.setFill(Color.RED);
green.setStroke(Color.BLACK);
green.setStrokeWidth(2);
color = Color.RED;
}else {
green.setFill(Color.TRANSPARENT);
green.setStroke(Color.BLACK);
green.setStrokeWidth(2);
color = Color.TRANSPARENT;
}
}
return green;
}
public String getSide() {
return side;
}
public Color getColor() {
return color;
}
}

To add cars dynamically to your array list, you can place the below code at the end of your start() method. The below code adds a new car (for 10 times) every 3 seconds. I verified with your demo and it is working.
Timeline tl = new Timeline(new KeyFrame(Duration.millis(3000), ae -> {
Car car=new Car();
cars.add(car);
root.getChildren().add(car.drawCar());
}));
tl.setCycleCount(10);
tl.play();

Related

How to make Java game more efficient?

I have been working on a flappy bird clone so I can get more practice programming. Everything in the game works, however the game has frame skips and lag drops, and I do not know how to make Java programs run more smoothly. Am I supposed to measure the amount of time a method takes and try to shorten that, or do I do something else? I have seen people explain how to program Java games, but there is hardly anything on improving the performance. Any advice would be helpful. Thank you.
Hazards class
package entity;
import java.util.ArrayList;
public class Hazards {
public ArrayList<Horizontal> hors;
public ArrayList<Vertical> verts;
public Hazards(int width, int height, int thickness) {
hors = new ArrayList<Horizontal>();
hors.add(new Horizontal(0, 0, width, thickness));
hors.add(new Horizontal(0, height-thickness, width, thickness));
verts = new ArrayList<Vertical>();
}
}
Horizontal class
package entity;
import java.awt.Rectangle;
public class Horizontal {
public int xPos, yPos, width, height;
public Rectangle bounds;
public Horizontal(int x, int y, int w, int h) {
this.xPos = x;
this.yPos = y;
this.width = w;
this.height = h;
this.bounds = new Rectangle(x, y, w, h);
}
public void updateBounds(int x, int y, int w, int h) {
this.xPos = x;
this.yPos = y;
this.width = w;
this.height = h;
this.bounds = new Rectangle(x, y, w, h);
}
}
Vertical class
package entity;
import java.awt.Rectangle;
import java.util.Random;
public class Vertical {
public int xPos, width, gapSize, gapPos;
public boolean scoredOn = false;
public Rectangle top, bottom;
public Vertical(int xPos, int width, int roofHeight, int floorHeight, int gapSize) {
this.xPos = xPos;
this.width = width;
this.gapPos = new Random().nextInt(floorHeight - gapSize) + roofHeight;
this.top = new Rectangle();
this.bottom = new Rectangle();
this.top.setBounds(xPos, 0, width, gapPos);
this.bottom.setBounds(xPos, gapPos + gapSize, width, floorHeight - roofHeight + top.height + gapSize);
}
}
Content class
package main;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Rectangle;
import javax.swing.JPanel;
public class Content extends JPanel {
private static final long serialVersionUID = 1L;
private Engine e;
private Rectangle bounds;
public Content(Engine engine) {
e = engine;
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.clearRect(0, 0, this.getWidth(), this.getHeight());
// Roof and floor
g.setColor(Color.black);
for (int x = 0; x < e.e.hors.size(); x++) {
bounds = e.e.hors.get(x).bounds;
g.fillRect(bounds.x, bounds.y, bounds.width, bounds.height);
}
// Pipes
g.setColor(Color.black);
for(int x = 0; x < e.e.verts.size(); x++) {
bounds = e.e.verts.get(x).top;
g.fillRect(bounds.x, bounds.y, bounds.width, bounds.height);
bounds = e.e.verts.get(x).bottom;
g.fillRect(bounds.x, bounds.y, bounds.width, bounds.height);
}
// Player
g.setColor(Color.black);
g.fillRect((int) e.p.xPos, (int) e.p.yPos, e.p.size, e.p.size);
// Score
g.setColor(Color.blue);
g.setFont(new Font("Monospaced", Font.PLAIN, 40));
g.drawString(Integer.toString(e.p.score), e.width/2, 80);
}
}
Engine class
package main;
import java.awt.Dimension;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import entity.Hazards;
import entity.Vertical;
import screen.TitleScreen;
public class Engine implements Runnable {
public JFrame f;
public String title = "Flappy Bird";
public int width = 500, height = 500;
public Content c;
public boolean running = false;
public boolean playing = false;
public Thread t;
public Player p;
public Hazards e;
public TitleScreen ts;
public JPanel mainPanel;
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
Engine e = new Engine();
e.execute();
}
});
}
public void execute() {
ts = new TitleScreen(width, height);
e = new Hazards(width, height, 30);
p = new Player(this);
c = new Content(this);
c.setPreferredSize(new Dimension(width, height));
c.setLayout(null);
c.addKeyListener(p);
mainPanel = new JPanel();
mainPanel.setPreferredSize(new Dimension(width, height));
mainPanel.setLayout(null);
f = new JFrame();
f.setTitle(title);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setResizable(false);
f.add(c);
// f.add(mainPanel);
f.pack();
f.createBufferStrategy(2);
f.setLayout(null);
f.setLocationRelativeTo(null);
f.setVisible(true);
c.requestFocus();
//ts.setScreen(mainPanel);
start();
}
public synchronized void start() {
if (running)
return;
running = true;
t = new Thread(this);
t.start();
}
public synchronized void stop() {
if (!running)
return;
running = false;
try {
t.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public void run() {
long lastime = System.nanoTime();
double AmountOfTicks = 60;
double ns = 1000000000 / AmountOfTicks;
double delta = 0;
int tick = 0;
while (running) {
long now = System.nanoTime();
delta += (now - lastime) / ns;
lastime = now;
if (delta >= 1) {
// Call all updates here
if (playing) {
p.updatePos();
tick++;
if (tick == 60) {
tick = 0;
p.distance += p.speed;
System.out.println(p.distance);
if ((p.distance % 4) == 0) {
System.out.println("Making new pipes-----------------------------------------------------");
e.verts.add(new Vertical(600, 10, 30, height - 30, 100));
}
}
for (int x = 0; x < e.verts.size(); x++) {
e.verts.get(x).top.x -= p.speed;
e.verts.get(x).bottom.x -= p.speed;
if(e.verts.get(x).top.x<-50) {
e.verts.remove(x);
System.out.println("removed a pipe");
}
if(p.xPos>e.verts.get(x).top.x && !e.verts.get(x).scoredOn) {
e.verts.get(x).scoredOn = true;
p.score++;
}
}
}
mainPanel.revalidate();
mainPanel.repaint();
f.revalidate();
f.repaint();
delta--;
}
}
}
}
Player class
package main;
import java.awt.Rectangle;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
public class Player implements KeyListener {
public int size = 10;
public double xPos = 50;
public double yPos = 240;
public double gravity = 3.4;
public double jumpForce = 16.6;
public double weight = 1;
public int speed = 2;
public int score = 0;
public int distance = 0;
public boolean jumping = false;
public double jumpTime = 10;
public int timed = 0;
public Rectangle bounds, temp, top, bottom;
public Engine en;
public Player(Engine engine) {
en = engine;
bounds = new Rectangle((int)xPos, (int)yPos, size, size);
}
public void keyTyped(KeyEvent e) {
}
public void keyPressed(KeyEvent e) {
if (e.getKeyCode() == KeyEvent.VK_W && en.playing) {
jumping = true;
} else if (e.getKeyCode() == KeyEvent.VK_SPACE) {
en.playing = !en.playing;
}
if(jumping) {
timed = 0;
jumpForce = 16.6;
}
}
public void keyReleased(KeyEvent e) {
}
public void updatePos() {
// collide with floor or ceiling
for(int x = 0; x < en.e.hors.size(); x++) {
temp = en.e.hors.get(x).bounds;
if(bounds.intersects(temp)) {
en.playing = false;
jumping = false;
timed = 0;
jumpForce = 0;
yPos = 240;
score = 0;
en.e.verts.clear();
distance = 0;
gravity = 3.8;
}
}
// collide with pipe
for(int x =0; x <en.e.verts.size();x++) {
top = en.e.verts.get(x).top;
bottom = en.e.verts.get(x).bottom;
if(bounds.intersects(top)||bounds.intersects(bottom)) {
en.playing = false;
jumping = false;
timed = 0;
jumpForce = 0;
yPos = 240;
score = 0;
gravity =3.4;
en.e.verts.clear();
distance = 0;
}
}
if (jumping && en.playing) {
gravity = 3.4;
yPos -= jumpForce;
jumpForce -= weight;
if (jumpForce == 0) {
jumping = false;
jumpForce = 16.6;
}
}
//if(!jumping && en.playing) {
gravity += 0.1;
//}
System.out.println(gravity);
yPos += gravity;
bounds.setBounds((int)xPos, (int)yPos, size, size);
}
}

How do I make the enemies of my game follow my character?

So I'm making a game where the enemies follow the player and the player kills them. How do I make the enemies' ImageViews follow the player.
I have tried some if sentences but I actually have no idea. I also searched everywhere but I only find other people doing it with Swing and I get really confused with a lot of things. I use Javafx btw.
public class Main extends Application{
private static final int HEIGHT = 720;
private static final int WIDTH = 1280;
Scene scene;
BorderPane root, htpLayout;
VBox buttons, paragraphs, images;
Button startButton, htpButton, htpReturnButton, leaderboardButton, exitButton;
Text gameName, paragraph1, paragraph2, paragraph3;
Pane gameLayout;
ImageView background;
Game game = new Game();
Player player = new Player();
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage window) throws Exception {
root = new BorderPane();
background = new ImageView("stick mob slayer background.png");
background.fitWidthProperty().bind(window.widthProperty());
background.fitHeightProperty().bind(window.heightProperty());
root.getChildren().add(background);
htpLayout = new BorderPane();
buttons = new VBox(15);
scene = new Scene(root, WIDTH, HEIGHT);
scene.getStylesheets().add("mobslayer/style.css");
gameName = new Text("Mob Slayer Unlimited");
gameName.setFont(Font.font("Complex", 50));
gameName.setFill(Color.WHITE);
root.setAlignment(gameName, Pos.CENTER_LEFT);
root.setTop(gameName);
startButton = new Button("Start Game");
startButton.setOnAction(e -> window.setScene(game.getScene()));
htpButton = new Button("How To Play");
htpButton.setOnAction(e -> scene.setRoot(htpLayout));
leaderboardButton = new Button("Leaderboard");
exitButton = new Button("Exit");
exitButton.setOnAction(e -> Platform.exit());
buttons.getChildren().addAll(startButton, htpButton, leaderboardButton, exitButton);
root.setCenter(buttons);
buttons.setAlignment(Pos.CENTER);
paragraphs = new VBox(30);
paragraph1 = new Text("Objektive\nNär spelet börjar kommer huvudkaraktären möta monster.\n"
+ "Ju längre in i spelet du kommer, ju fler och svårare monster dyker upp.\n"
+ "Ditt mål är att överleva så länge som möjligt.");
paragraph1.setFont(Font.font("Dubai", 13));
paragraph1.setFill(Color.BLACK);
paragraph2 = new Text("Movement\nAlla monster dras imot dig, så du måste akta dig.\n"
+ "Detta gör du med hjälp av piltangenterna.");
paragraph2.setFont(Font.font("Dubai", 13));
paragraph2.setFill(Color.BLACK);
paragraph3 = new Text("Special Effects\nDu kan också attackera tillbaka med en lätt attack(c)\n"
+ "eller med en specialattack(space) som dödar alla monster på skärmen.\n"
+ "Du kan dasha(x) för att röra dig snabbare åt ett håll.");
paragraph3.setFont(Font.font("Dubai", 13));
paragraph3.setFill(Color.BLACK);
paragraphs.getChildren().addAll(paragraph1, paragraph2, paragraph3);
htpReturnButton = new Button("Return");
htpReturnButton.setOnAction(e->scene.setRoot(root));
htpLayout.setBottom(htpReturnButton);
htpLayout.setAlignment(htpReturnButton,Pos.TOP_CENTER);
images = new VBox(30);
// Image image1 = new Image(new FileInputStream("resources\\cod zombies.jpg"));
// final ImageView image11 = new ImageView(image1);
// image11.setFitHeight(100);
// image11.setFitWidth(100);
// image11.setPreserveRatio(true);
//
// Image image2 = new Image(new FileInputStream("resources\\arrowkeys.png")) ;
// final ImageView image22 = new ImageView(image2);
// image22.setFitHeight(100);
// image22.setFitWidth(100);
// image22.setPreserveRatio(true);
//
// Image image3 = new Image(new FileInputStream("resources\\keys.png")) ;
// final ImageView image33 = new ImageView(image3);
// image33.setFitHeight(100);
// image33.setFitWidth(100);
// image33.setPreserveRatio(true);
//
// images.getChildren().addAll(image11, image22, image33);
//
paragraphs.setAlignment(Pos.TOP_LEFT);
htpLayout.setLeft(paragraphs);
htpLayout.setRight(images);
window.setTitle("Mob Slayer Unlimited");
window.setScene(scene);
window.setResizable(false);
window.show();
}
}
public class Game {
private static final int HEIGHT = 720;
private static final int WIDTH = 1280;
private Scene scene;
Pane root;
Text health, stamina, wave, kills;
int waveCounter = 1, killCounter = 0;
Button restartButton, pauseButton;
Line limitUp;
Player player = new Player();
Enemies enemy = new Enemies();
public Game() {
health = new Text(50, 30, "HP: " + player.getHealth());
health.setFont(Font.font("BankGothic Lt BT", 30));
health.setFill(Color.WHITE);
stamina = new Text(50, 80, "STAMINA: " + player.getStamina());
stamina.setFont(Font.font("BankGothic Lt BT", 30));
stamina.setFill(Color.WHITE);
wave = new Text(1050, 30, "WAVE: " + waveCounter);
wave.setFont(Font.font("BankGothic Lt BT", 30));
wave.setFill(Color.WHITE);
kills = new Text(1050, 80, "KILLS: " + killCounter);
kills.setFont(Font.font("BankGothic Lt BT", 30));
kills.setFill(Color.WHITE);
restartButton = new Button("RESTART");
restartButton.setFont(Font.font("BankGothic Lt BT", 30));
restartButton.setOnAction(e -> restart());
restartButton.setLayoutX(350);
restartButton.setLayoutY(20);
pauseButton = new Button("PAUSE");
pauseButton.setFont(Font.font("BankGothic Lt BT", 30));
pauseButton.setOnAction(e -> restart());
pauseButton.setLayoutX(650);
pauseButton.setLayoutY(20);
limitUp = new Line(0, 100, 1280, 100);
limitUp.setStroke(Color.WHITE);
root = new Pane(player.getSlayer(), limitUp, player.getSlayerHitbox(), health, stamina, wave, kills, restartButton, pauseButton, enemy.getEnemy());
root.setStyle("-fx-background-color: black");
enemy.enemyMovement();
movePlayerTo(WIDTH / 2, HEIGHT / 2);
scene = new Scene(root, WIDTH, HEIGHT);
scene.setOnKeyPressed(new EventHandler<KeyEvent>() {
#Override
public void handle(KeyEvent event) {
switch (event.getCode()) {
case W: player.goUp = true; break;
case S: player.goDown = true; break;
case A: player.goLeft = true; break;
case D: player.goRight = true; break;
case K: player.running = true; break;
}
}
});
scene.setOnKeyReleased(new EventHandler<KeyEvent>() {
#Override
public void handle(KeyEvent event) {
switch (event.getCode()) {
case W: player.goUp = false; break;
case S: player.goDown = false; break;
case A: player.goLeft = false; break;
case D: player.goRight = false; break;
case K: player.running = false; break;
}
}
});
AnimationTimer timer = new AnimationTimer() {
#Override
public void handle(long now) {
int dx = 0, dy = 0;
if (player.goUp) dy -= 2;
if (player.goDown) dy += 2;
if (player.goRight) dx += 2;
if (player.goLeft) dx -= 2;
if (player.running) { dx *= 2; dy *= 2; }
enemy.enemyMovement();
movePlayerBy(dx, dy);
}
};
timer.start();
}
public Scene getScene() {
return scene;
}
// I took this methods for movement from Github
public void movePlayerBy(int dx, int dy) {
if (dx == 0 && dy == 0) return;
final double cx = player.getSlayer().getBoundsInLocal().getWidth() / 2;
final double cy = player.getSlayer().getBoundsInLocal().getHeight() / 2;
double x = cx + player.getSlayer().getLayoutX() + dx;
double y = cy + player.getSlayer().getLayoutY() + dy;
movePlayerTo(x, y);
}
public void movePlayerTo(double x, double y) {
final double cx = player.getSlayer().getBoundsInLocal().getWidth() / 2;
final double cy = player.getSlayer().getBoundsInLocal().getHeight() / 2;
if (x - cx >= 0 &&
x + cx <= WIDTH &&
y - cy >= 0 &&
y + cy <= HEIGHT) {
player.getSlayer().relocate(x - cx, y - cy);
player.getSlayerHitbox().relocate(x - cx + 37, y - cy + 35);
}
}
public class Player {
private int health;
private int damage;
private int stamina;
private Image slayerImage;
private ImageView slayer;
private Rectangle slayerHitbox;
boolean running, goUp, goDown, goRight, goLeft;
public Player () {
health = 5;
damage = 1;
stamina = 5;
slayerImage = new Image("stick mob slayer.png", 100, 100, true, true);
slayer = new ImageView(slayerImage);
slayerHitbox = new Rectangle(10, 50);
}
public int getDamage() {
return damage;
}
public void setDamage(int damage) {
this.damage = damage;
}
public int getHealth() {
return health;
}
public void setHealth(int health) {
this.health = health;
}
public int getStamina() {
return stamina;
}
public void setStamina(int stamina) {
this.stamina = stamina;
}
public ImageView getSlayer() {
return slayer;
}
public Rectangle getSlayerHitbox() {
slayerHitbox.setFill(Color.TRANSPARENT);
return slayerHitbox;
}
}
public class Enemies {
private int health;
private int speed;
private Image enemyImage;
private ImageView enemy;
private Rectangle enemyHitbox;
Player player = new Player();
public Enemies () {
health = 1;
speed = 1;
enemyImage = new Image("stick enemy.png", 100, 100, true, true);
enemy = new ImageView(enemyImage);
enemyHitbox = new Rectangle(10, 50);
}
public int getHealth() {
return health;
}
public void setHealth(int health) {
this.health = health;
}
public int getSpeed() {
return speed;
}
public void setSpeed(int speed) {
this.speed = speed;
}
public ImageView getEnemy () {
return enemy;
}
public Rectangle getEnemyHitbox() {
enemyHitbox.setFill(Color.YELLOW);
return enemyHitbox;
}
}
This is everything I have done so far. I would appreciate any help. If possible I would like to know how to make the enemies appear from random spots of the borders of the screen as well. Thanks in advance.
you should try first something more simple like implementing A* path search algo or some grid with some units on it before trying todo a game and having such questions

repaint only happens at the end of my loop - java

basically I'm making TRON and my first step is to make a basic snake game and my first step is to make a square move down the screen and then implement key listeners. i want to see the square moving down at every stage stage but i just seem to get the final paint image, so i think it does move, i just don't see the frame being updated, can anyone help?
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.util.*;
public class Multiplayer extends JPanel { //implements ActionListener {
public static Multiplayer multiplayer;
public static ArrayList<Point> bikeParts = new ArrayList<>();
public static final int UP = 0, DOWN = 1, LEFT = 2, RIGHT = 3, SCALE = 10;
public static int ticks = 0, direction = DOWN;
public static Point bike;
public boolean over = false;
public JFrame frame;
public renderPanel rp;
public Multiplayer() {
frame = new JFrame();
//JPanel panel = new JPanel();
rp = new renderPanel();
//add(panel, BorderLayout.CENTER);
frame.getContentPane().add(rp, BorderLayout.CENTER);
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
frame.setSize(900, 700);
frame.setVisible(true);
frame.setResizable(false);
bike = new Point(0, 0);
for (int i = 0; i < 1000; i++) {
animate(null);
rp.repaint();
}
}
//#Override
public void animate(ActionEvent ef) {
rp.repaint();
ticks++;
System.out.println("yw");
if (ticks % 10 == 0 && bike != null && over != true) {
System.out.println("did");
rp.repaint();
bikeParts.add(new Point(bike.x, bike.y));
if (direction == UP) {
if (bike.y - 1 > 0) {
bike = new Point(bike.x, bike.y - 1);
} else {
over = true;
}
}
if (direction == DOWN) {
if (bike.y + 1 < 700) {
bike = new Point(bike.x, bike.y + 1);
} else {
over = true;
}
}
if (direction == LEFT) {
if (bike.x - 1 > 0) {
bike = new Point(bike.x - 1, bike.y);
} else {
over = true;
}
bike = bikeParts.get(bikeParts.size() - 1);
bikeParts.remove(0);
}
if (direction == RIGHT) {
if (bike.x + 1 < 900) {
bike = new Point(bike.x + 1, bike.y);
} else {
over = true;
}
}
}
}
}
and then:
import javax.swing.*;
import java.awt.*;
public class renderPanel extends JComponent {
#Override
public void paintComponent(Graphics g) {
// super.paintComponent(g);
System.out.println("painting");
Multiplayer mp = Multiplayer.multiplayer;
g.setColor(Color.black);
g.drawRect(0, 0, 900, 700);
g.fillRect(0, 0, 900, 700); //arena
g.setColor(Color.WHITE);
for (Point point : mp.bikeParts) {
g.fillRect(point.x * Multiplayer.SCALE, point.y * Multiplayer.SCALE, Multiplayer.SCALE, Multiplayer.SCALE);
}
g.fillRect(mp.bike.x * Multiplayer.SCALE, mp.bike.y * Multiplayer.SCALE, Multiplayer.SCALE, Multiplayer.SCALE);
}
}

can't make geometric shapes to move in Java

I'm all new to this site and to Java, so please be lenient.
I'm writing a program that allows to draw different type of shapes with a button click and after hitting another button move/stop/reset them.
I've made already the most part I think (the shapes are correctly creating and storing in an arraylist, the same with the reset, which clear the screen), but I can't figure out how to make them move.I got a function for movement but can't find a way to make the shapes form the arraylist to move. Can anyone give me a little advise.
Thanks
P.S. If there is something wrong/bad coding and needs to be fixed I'll be grateful if you will point at them.
Here is my code:
MyShape class is for creating different shapes.
import java.awt.*;
import java.util.Random;
public abstract class MyShape extends Component {
protected Color color;
private int x, y, dimX, dimY;
public Random random = new Random();
public MyShape(int x, int y, int dimX, int dimY){
this.x = x;
this.y = y;
this.dimX = dimX;
this.dimY = dimY;
color = new Color(random.nextInt(255), random.nextInt(255), random.nextInt(255));
}
public abstract void draw(Graphics g);
public int getX() {
return x;
}
public void setX(int x) {
this.x = x;
}
public int getY() {
return y;
}
public void setY(int y) {
this.y = y;
}
public int getDimX() {
return dimX;
}
public void setDimX(int dimX) {
this.dimX = dimX;
}
public int getDimY() {
return dimY;
}
public void setDimY(int dimY) {
this.dimY = dimY;
}
}
CircleShape - creating circles.
import java.awt.*;
public class CircleShape extends MyShape {
public CircleShape(int x, int y, int dimX, int dimY) {
super(x, y, dimX, dimY);
}
#Override
public void draw(Graphics g) {
g.setColor(color);
g.fillOval(getX(), getY(), getDimX(), getDimY());
}
}
RectangleShape - rectangles
import java.awt.*;
public class RectangleShape extends MyShape {
public RectangleShape(int x, int y, int dimX, int dimY) {
super(x, y, dimX, dimY);
}
#Override
public void draw(Graphics g) {
g.setColor(color);
g.fillRect(getX(), getY(), getDimX(), getDimY());
}
}
and the DrawShape class which handles pretty much everything
public class DrawShapes extends JPanel {
private JButton addButton, resumeAllButton, stopAllButton, resetButton;
private final int FRAME_WIDTH = 800;
private final int FRAME_HEIGHT = 530;
private int x, y, dimX, dimY;
private Random random = new Random();
public List<MyShape> myShapeList = new CopyOnWriteArrayList<MyShape>();
private Timer timer = null;
public boolean move = false;
public DrawShapes() {
this.setLayout(null);
addButton = new JButton("Add Shape");
resumeAllButton = new JButton("Resume Shapes");
stopAllButton = new JButton("Stop All Shapes");
resetButton = new JButton("Reset");
addButton.setBounds(40, 20, 150, 30);
resumeAllButton.setBounds(230, 20, 150, 30);
stopAllButton.setBounds(420, 20, 150, 30);
resetButton.setBounds(610, 20, 150, 30);
this.add(addButton);
this.add(resumeAllButton);
this.add(stopAllButton);
this.add(resetButton);
stopAllButton.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
move = false;
}
});
resumeAllButton.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
move = true;
}
});
addButton.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
Thread thread = new Thread() {
public void run() {
init();
}
};
thread.start();
}
});
resetButton.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
for (int i = 0; i < myShapeList.size(); i++) {
myShapeList.clear();
repaint();
}
}
});
}
public void moveIt() {
boolean directionUp = random.nextBoolean();
boolean directionLeft = random.nextBoolean();
boolean directionDown = !directionUp;
boolean directionRight = !directionLeft;
while (move) {
if (x <= 0) {
directionRight = true;
directionLeft = false;
}
if (x >= FRAME_WIDTH - dimX) {
directionRight = false;
directionLeft = true;
}
if (y <= 70) {
directionUp = false;
directionDown = true;
}
if (y >= FRAME_HEIGHT + 50 - dimY) {
directionUp = true;
directionDown = false;
}
if (directionUp)
y--;
if (directionDown)
y++;
if (directionLeft)
x--;
if (directionRight)
x++;
}
}
public void init() {
x = 0;
y = 0;
dimX = (random.nextInt(FRAME_WIDTH) + 100) / 2;
dimY = (random.nextInt(FRAME_HEIGHT) + 100) / 2;
while (x <= 0)
x = (random.nextInt(FRAME_WIDTH) - dimX);
while (y <= 70)
y = (random.nextInt(FRAME_HEIGHT) - dimY);
int choice = 0;
choice = random.nextInt(2) + 1;
switch (choice) {
case 1:
RectangleShape rectangleShape = new RectangleShape(x, y, dimX, dimY);
myShapeList.add(rectangleShape);
timer.start();
repaint();
break;
case 2:
CircleShape circleShape = new CircleShape(x, y, dimX, dimY);
myShapeList.add(circleShape);
repaint();
break;
}
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.WHITE);
g.fillRect(0, 70, 800, 530);
for (MyShape aMyShapeList : myShapeList) {
aMyShapeList.draw(g);
}
}
public static void main(String args[]) {
JFrame jFrame = new JFrame();
jFrame.add(new DrawShapes());
jFrame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
jFrame.setSize(800, 600);
jFrame.setResizable(false);
Dimension dim = Toolkit.getDefaultToolkit().getScreenSize();
jFrame.setLocation(dim.width / 2 - jFrame.getSize().width / 2, dim.height / 2 - jFrame.getSize().height / 2);
jFrame.setLocationRelativeTo(null);
jFrame.setVisible(true);
}
}
From the code you posted I can see that you are not calling your moveIt() method anywhere.
You have the right idea of how to move things around. The basic algorithm is:
Calculate new positions
Repaint the view
I can recommend you do the following:
You are currently calling your init method in a thread. I am not sure this is needed. Remove the thread logic and just call the method on the main thread.
Introduce another button tho start the actual animation. When clicking, create a thread that will call your moveIt() method.

SnakeGame how to make the tail follow the head?

I am making a snake game, and I am stuck at where making the tails follow the head. And I heard using an add and remove on the head and tails could make that happen, but I have no idea where to start with that.
Here's my code so far:
Screen.java
public class Screen extends JPanel implements ActionListener, KeyListener {
public static final JLabel statusbar = new JLabel("Default");
public static final int WIDTH = 800, HEIGHT = 800;
Timer t = new Timer(100, this);
int x = 400;
int y = 400;
int size = 5; //increase size if eat
private boolean right = false, left = false, up = false, down = false;
int head = 0;
private LinkedList<BodyPart> snake = new LinkedList<BodyPart>();
private BodyPart b;
public Screen(){
initSnake();
t.start();
addKeyListener(this);
setFocusable(true);
setFocusTraversalKeysEnabled(false);
}
public void update(){
}
public void direction(){
if(right) x+=10;
if(left) x-=10;
if(up) y-=10;
if(down) y+=10;
}
public void trackOutBound(){
if(x < 0 || x > 800 || y < 0 || y > 800) {
x = 400;
y = 400;
}
}
public void initSnake(){
if(snake.size() == 0){
b = new BodyPart(x, y);
for(int i = 0; i < size; i++) {
snake.add(b);
}
System.out.println(snake);
}
}
public static void main(String[] args) {
}
#Override
public void paintComponent(Graphics g){
super.paintComponent(g);
g.setColor(new Color(10, 50, 0));
g.fillRect(0, 0, WIDTH, HEIGHT);
g.setColor(Color.BLACK);
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, WIDTH, i * 10);
}
int tempx = 0, tempy = 0;
int temp = 0;
for(int i = 0; i < size; i++){
if(i == head) {
snake.get(i).x = x;
snake.get(i).y = y;
snake.get(i).draw(g);
g.setColor(Color.blue);
g.fillRect(x, y, 10, 10);
g.setColor(Color.white);
g.drawRect(x, y, 10, 10);
} else if(i > 0 && up) {
snake.get(i).x = x;
snake.get(i).y = y + temp;
snake.get(i).draw(g);
} else if(i > 0 && down) {
snake.get(i).x = x;
snake.get(i).y = y - temp;
snake.get(i).draw(g);
} else if(i > 0 && left) {
snake.get(i).x = x + temp;
snake.get(i).y = y;
snake.get(i).draw(g);
} else if(i > 0 && right) {
snake.get(i).x = x - temp;
snake.get(i).y = y;
snake.get(i).draw(g);
}
temp += 10;
}
/*
if(snake.size() == 5){
snake.add(b);
size += 1;
}
*/
}
#Override
public void actionPerformed(ActionEvent e) {
direction();
trackOutBound();
repaint();
// System.out.println(snake);
statusbar.setText("(" + x + " , " + y + ")");
}
#Override
public void keyTyped(KeyEvent e) {}
#Override
public void keyPressed(KeyEvent e) {
int key = e.getKeyCode();
if(key == KeyEvent.VK_RIGHT && !left) {
up = false;
down = false;
right = true;
}
if(key == KeyEvent.VK_LEFT && !right) {
up = false;
down = false;
left = true;
}
if(key == KeyEvent.VK_UP && !down) {
left = false;
right = false;
up = true;
}
if(key == KeyEvent.VK_DOWN && !up) {
left = false;
right = false;
down = true;
}
}
#Override
public void keyReleased(KeyEvent e) {}
}
BodyPart.java
public class BodyPart {
int x;
int y;
public BodyPart(int x, int y) {
this.x = x;
this.y = y;
}
public void draw(Graphics g) {
this.x = x;
this.y = y;
g.setColor(Color.red);
g.fillRect(x, y, 10, 10);
g.setColor(Color.white);
g.drawRect(x, y, 10, 10);
}
}
Frame.java
public class Frame extends JPanel {
private static JLabel statusbar = new JLabel("Default");
public void statusbar(){
statusbar = Screen.statusbar;
}
public static void main(String[] args) {
JFrame f = new JFrame();
Screen s = new Screen();
f.add(s);
f.add(statusbar, BorderLayout.SOUTH);
f.setSize(800, 800);
f.setVisible(true);
f.setLocationRelativeTo(null);
f.setResizable(false);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
}
Now this code would only make the tails flip to the horizontal or vertical, is it possible to make the tails follow the head by using this code? or I need to change my code?
Thank you
The basic idea is, you need some kind of List which contains ALL the points of the snake. Conceptually, the List would contain virtual coordinates, that is 1x1 would represent a coordinate in virtual space, which presented a place on a virtual board (which would have some wide and height).
You could then translate that to the screen, so this would allow each part of the snake to be larger then a single pixel. So, if each part was 5x5 pixels, then 1x1 would actually be 5x5 in the screen.
Each time the snake moves, you add a new value to the head and remove the last value from tail (assuming it's not growing). When you needed to paint the snake, you would simply iterate over the List, painting each point of the snake.
The following is a simple example, which uses a LinkedList, which pushes a new Point onto the List, making a new head, and removing the last element (the tail) on each cycle.
Which basically boils down to...
snakeBody.removeLast();
snakeBody.push(new Point(xPos, yPos));
As a runnable concept
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.util.LinkedList;
import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.ActionMap;
import javax.swing.InputMap;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.KeyStroke;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class Snake {
public static void main(String[] args) {
new Snake();
}
public Snake() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public static class TestPane extends JPanel {
public enum Direction {
UP, DOWN, LEFT, RIGHT
}
private int xPos, yPos;
private Direction direction = Direction.UP;
private LinkedList<Point> snakeBody = new LinkedList<>();
public TestPane() {
xPos = 100;
yPos = 100;
for (int index = 0; index < 50; index++) {
snakeBody.add(new Point(xPos, yPos));
}
bindKeyStrokeTo("up.pressed", KeyStroke.getKeyStroke(KeyEvent.VK_UP, 0, false), new MoveAction(Direction.UP));
bindKeyStrokeTo("down.pressed", KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, 0, false), new MoveAction(Direction.DOWN));
bindKeyStrokeTo("left.pressed", KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, 0, false), new MoveAction(Direction.LEFT));
bindKeyStrokeTo("right.pressed", KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, 0, false), new MoveAction(Direction.RIGHT));
Timer timer = new Timer(40, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
switch (direction) {
case UP:
yPos--;
break;
case DOWN:
yPos++;
break;
case LEFT:
xPos--;
break;
case RIGHT:
xPos++;
break;
}
if (yPos < 0) {
yPos--;
} else if (yPos > getHeight() - 1) {
yPos = getHeight() - 1;
}
if (xPos < 0) {
xPos--;
} else if (xPos > getWidth() - 1) {
xPos = getWidth() - 1;
}
snakeBody.removeLast();
snakeBody.push(new Point(xPos, yPos));
repaint();
}
});
timer.start();
}
public void bindKeyStrokeTo(String name, KeyStroke keyStroke, Action action) {
InputMap im = getInputMap(WHEN_IN_FOCUSED_WINDOW);
ActionMap am = getActionMap();
im.put(keyStroke, name);
am.put(name, action);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
g2d.setColor(Color.RED);
for (Point p : snakeBody) {
g2d.drawLine(p.x, p.y, p.x, p.y);
}
g2d.dispose();
}
public class MoveAction extends AbstractAction {
private Direction moveIn;
public MoveAction(Direction direction) {
this.moveIn = direction;
}
#Override
public void actionPerformed(ActionEvent e) {
direction = this.moveIn;
}
}
}
}
Now, this has no collision detection or other functionality, but you can move the snake around and it will follow itself
For snake style movement, you can, from the tail to the head, move each BodyPart position to the position of the BodyPart ahead of it. For the head there is no part ahead so you have to write decision code whether to simply move the same direction as the part before it or a new direction based on input. Then update the screen.

Categories

Resources