How to update and move object with pathfinding? - java

I've implemented some pathfinding in my 2d game, but I don't know how to move my 'Zombie' character.
I'm using slick2d and everything gets put on the screen in the render method, however I want to update the zombies movement in the Zombie class.
Here is the method in the zombie class:
public void findPrey(){
Pathfinder pf = new Pathfinder();
pf.setStartNode(xPosition,yPosition);
for(PathCoordinates p: pf.calculatePath()){
if(p.getXPosition() > xPosition){
moveRight(2);
}if(p.getXPosition() < xPosition){
moveLeft(2);
}if(p.getYPosition() > yPosition){
moveUp(2);
}if(p.getYPosition() < yPosition){
moveDown(2);
}
}
}
So I want to loop through the List of x and y coordinates and move the zombie.
However nothings happens- the zombie doesnt move at all.
In my 'world' class I have the render method, which loops through the zombies and renders them, the code has been edited slightly:
public void render(GameContainer gc, StateBasedGame sbg, Graphics g)
throws SlickException {
for (Zombie z : zombies) {
if (!z.isDead()) {
z.render(gc, sbg, g);
z.findPrey();
}
}
}
So, basically my question is how - do I make my zombie character move?! Thanks for any help or guidance

You should first move the zombie, then render it.
There's another problem: you allow to move the zombie all the way it should with one findPrey() (using updatePosition() in code below) method call.
Zombie class:
public void updatePosition() {
Pathfinder pf = new Pathfinder();
pf.setStartNode(xPosition,yPosition);
PathCoordinates p = pf.calculatePath()[0];
if(p.getXPosition() > xPosition) {
moveRight(2);
} if(p.getXPosition() < xPosition) {
moveLeft(2);
} if(p.getYPosition() > yPosition) {
moveUp(2);
} if(p.getYPosition() < yPosition) {
moveDown(2);
}
}
World class:
public void render(GameContainer gc, StateBasedGame sbg, Graphics g) throws SlickException {
for(Zombie z : zombies) {
if(!(z.isDead())) {
z.updatePosition();
z.render(gc, sbg, g);
}
}
}

Related

Custom Java game engine is rendering spaces between tiles when the character moves

So I've been trying to figure out what's wrong with my code, but I've had basically no luck when it comes to finding what's wrong. I've seen plenty of folks who had similar issues but none of the fixes that were suggested helped with my problem.
I've made a video showcasing my problem, but I'll give an explanation here too: whenever I move on the screen, the tiles in my game engine don't sync up with each other in terms of positioning, and it seems to be only on the rendering end. When I do any sort of checks to see if the distance between two tiles changes, I don't get any sort of errors. I get these gaps between the tiles specifically when I'm moving up or left, and they instead merge slightly when I move down or right, as if some of the tiles are updating faster than the others.
I don't want to just start dumping my couple thousand lines of code here since that won't really help anyone, but I'm also not well versed in the game development world, so I'm not entirely sure what pieces of code are super relevant here. If there's anything that y'all would like to see, let me know and I'll happily provide it.
The main method and postInit looks like this:
public static void main (String[] args)
{
EventQueue.invokeLater(() ->{
ex = new ShootyGame();
ex.dispose();
ex.setLayout(null);
ex.setUndecorated(Settings.isFullscreen);
ex.setVisible(true);
ex.setCursor(ex.getToolkit().createCustomCursor(
new BufferedImage(1, 1, BufferedImage.TYPE_INT_ARGB), new Point(), null)); //hides the system cursor
ex.createBufferStrategy(2);
postInit();
});
}
private static void postInit()
{
//add a window listener to the main JFrame
ex.addWindowListener(new WindowAdapter()
{
/**
* Autosaves when the window is closed, then kills the game.
*/
#Override
public void windowClosing(WindowEvent e)
{
//TODO autosaving
kill();
}
});
render.start(); //these are just the two threads being started
run.start();
}
My two threads, which basically just run the step and render methods in my game class:
private static class Running extends Thread
{
boolean stop = false;
int fps = TickManager.fromFPS(Settings.FPS);
public void run()
{
while (!stop)
{
try
{
Running.sleep(fps);
}
catch(InterruptedException e)
{
System.err.println("B");
}
game.step();
}
}
}
private static class Render extends Thread
{
boolean stop = false;
int fps = TickManager.fromFPS(Settings.FPS);
public void run()
{
while (!stop)
{
try
{
Running.sleep(fps);
}
catch(InterruptedException e)
{
System.err.println("A");
}
game.render();
}
}
}
The run method in my Game class just calls the current character's step method (it'll call more later), which is what's directly used to move the Camera class' x and y position. The character step looks like this:
public void step()
{
this.calculateMove(); //gets info on which keys are being pressed, adds or subtracts an integer from dx and dy (which are also ints) based on which are being pressed
Game.cam.update(-this.dx, -this.dy); //sends the opposite movement to the camera
//change the position of the player character by the appropriate x and y amounts
this.changeX(this.dx);
this.changeY(this.dy);
this.reset(); //just sets dx and dy back to 0 after moving
}
And now to the rendering stuff here's the entire camera class since it's probably the most relevant class:
public class Camera
{
private int x;
private int y;
public Camera(int x, int y)
{
this.x = x;
this.y = y;
}
public void update(int dx, int dy)
{
moveX(dx);
moveY(dy);
}
public void moveX(int dx)
{
this.x += dx;
}
public void moveY(int dy)
{
this.y += dy;
}
/**
* Gets the top left corner of the camera's x position.
* #return The x position of the top left corner of the camera
*/
public int getCamX()
{
return this.x;
}
/**
* Gets the top left corner of the camera's y position.
* #return The y position of the top left corner of the camera
*/
public int getCamY()
{
return this.y;
}
}
And finally, the relevant code for the actual painting of the tiles:
public void render() //this is the part that the render thread calls initially
{
Toolkit.getDefaultToolkit().sync();
repaint();
}
public void paint(Graphics g) //the paint method, mostly handled in doDrawing
{
super.paint(g);
doDrawing(g);
}
private void doDrawing(Graphics g)
{
Graphics2D g2d = (Graphics2D) g;
//stuff that happens if the game isn't paused
if(!GameStates.isPaused)
{
currentMap.drawMap(g2d, this);
currentChar.draw(g2d, this);
}
}
public void drawMap(Graphics2D g2d, ImageObserver observer)
{
//for each tile in the map, call its draw method
for(int i = 0; i < this.tileArray.length; i++)
{
for(int j = 0; j < this.tileArray[0].length; j++)
{
this.tileArray[i][j].draw(g2d, observer);
}
}
}
public void draw(Graphics2D g2d, ImageObserver observer, BufferedImage image)
{
g2d.drawImage(image, this.getX() + Game.cam.getCamX(), this.getY() + Game.cam.getCamY() observer);
}
Sorry for the long winded post, I've just tried everything I can think of (and that my Googling abilities can help me think of) and I'm throwing this out as a last-ditch effort before I just move to an actual game engine. I wanted to make my own engine from scratch for the sake of getting more experience in Java, but if I can't figure this out I'd rather just move to a proper engine and actually make a game. Any help is massively appreciated :)
EDIT: capitalization

Slick2d how to check if a shape contains any object? Java

i'm new to Slick2d and to this page too, i tried asking the slick forums, but there aren't many people so i couldn't get an answer
Anyway, i've been trying to create a platformer engine in Slick2d java game library, and i was thinking of using the contains and intersects methods of the Shape class.
The thing is, if I want to check if a shape contains any object of any kind (or any object from a specific class), Is there a way to do that? all tutorials i've found explain how to test collision with one single shape, but what if i want to check for any object?
package juegoconslick;
import java.util.ArrayList;
import org.newdawn.slick.*;
import org.newdawn.slick.geom.Rectangle;
import org.newdawn.slick.geom.Shape;
public class JuegoConSlick extends BasicGame {
Jugador player;
Input entrada;
Shape hitbox;
bloque bloq;
ArrayList<bloque> bloques = new ArrayList<>();
public JuegoConSlick(){
super("Mi prueba");
}
public static void main(String[] args) {
AppGameContainer juegito;
try{
juegito = new AppGameContainer(new JuegoConSlick());
juegito.setDisplayMode(630,400,false);
juegito.setMaximumLogicUpdateInterval(60);
juegito.setMaximumLogicUpdateInterval(50);
juegito.setAlwaysRender(true);
juegito.setVSync(true);
juegito.start();
}catch(Exception ex){
System.exit(0);
}
}
#Override
public void init(GameContainer gc) throws SlickException {
player = new Jugador();
hitbox = new Rectangle(player.X, player.Y, 10, 10);
bloq = new bloque(50,50,50,50);
}
#Override
public void update(GameContainer gc, int i) throws SlickException {
intersecta();
Input entrad = gc.getInput();
if(entrad.isKeyDown(Input.KEY_RIGHT) && player.X<600){
player.X+=3;
player.sprite.update(1);
hitbox.setX(player.X);
}
if(entrad.isKeyDown(Input.KEY_LEFT) && player.X>0){
player.X-=3;
player.sprite.update(1);
hitbox.setX(player.X);
}
if(entrad.isKeyDown(Input.KEY_UP) && player.Y>0){
player.Y-=3;
player.sprite.update(1);
hitbox.setY(player.Y);
}
if(entrad.isKeyDown(Input.KEY_DOWN) && player.Y<370){
player.Y+=3;
player.sprite.update(1);
hitbox.setY(player.Y);
}
}
#Override
public void render(GameContainer gc, Graphics grphcs) throws SlickException {
grphcs.draw(bloq.bloque);
grphcs.draw(hitbox);
}
public void intersecta(){
try{
if(hitbox.contains(null)){//i tried checking if it didnt contain any object,
}else{
System.exit(0);
}
}catch(Exception ex){
}
}
}
EDIT: i think i have found a solution, though im not sure if its the most efficient.
basiaclly, i'll save all objects of the same class in an ArrayList:
ArrayList<bloque> bloques = new ArrayList<>();
bloques.add(new bloque(50,50,100,100));
bloques.add(new bloque(100,100,100,100));
Then, what im going to do is check the entire arraylist each time i call the intersects method:
public boolean intersecta(){
boolean devuelve=false;
for(int i=0; i<bloques.size(); i++){
if(hitbox.intersects(bloques.get(i).bloque)){
devuelve=true;
}
}
return devuelve;
}
then im going to use the value i get from intersects to decide whether the player can move or not
public void update(GameContainer gc, int i) throws SlickException {
Input entrad = gc.getInput();
if(entrad.isKeyDown(Input.KEY_RIGHT) && player.X<600 && intersecta()==false){
player.X+=3;
player.sprite.update(1);
hitbox.setX(player.X);
}
and so on with the other keys....
so im not sure if its the best solution, but as far as i have seen it seems to be working. I hope this results useful for others.
I recommend to create a new Class.
This class Needs to inherit an Slick2d Shape, so for instance:
public class ShapeWithReference extends Rectangle{}
This class can have a list or a single object reference:
public class ShapeWithReference Rectangle{
Object reference = new String("hello"); //This is dirty and can be replaced by any object.
}
Since your new class is a Slick2D shape you can now find out whether it is contained by another shape:
Rectangle rec = new Rectangle();
if(rec.contains(ShapeWithReference)){
if(ShapeWithReference.reference instanceof String){
System.out.println((String)ShapeWithReference.reference);
}
}
Contains checks whether the shape really contains another shape. So they are not just intersecting. So that's the first part you check, the second one is whether the reference Attribute of the Shape is for e.g. a String. So if our first rectangle contains our new class and the reference of this class is type of a String this String is supposed to be written in to the console.
Hope this helps or gives you a hint.
EDIT:
public class SlickGame extends BasicGame {
static AppGameContainer appgc;
Rectangle rec;
ShapeWithReference swr;
public SlickGame(String title) {
super(title);
}
#Override
public void render(GameContainer container, Graphics g) throws SlickException {
}
#Override
public void init(GameContainer container) throws SlickException {
rec = new Rectangle(0, 0, 64, 64);
swr = new ShapeWithReference(0, 0, 1, 1);
}
#Override
public void update(GameContainer container, int delta) throws SlickException {
if(rec.intersects(swr)){
if(swr.reference instanceof String){
System.out.println((String)swr.reference);
}
else if(swr.reference instanceof Integer){
System.out.println((Integer)swr.reference);
}
else if(swr.reference instanceof Shape){
Shape temp = (Shape)swr.reference;
System.out.println(temp.getWidth());
}
}
}
public static void main(String[] args) {
try {
appgc = new AppGameContainer(new SlickGame("title"));
appgc.setDisplayMode(800, 600, false);
appgc.setTargetFrameRate(60);
appgc.setFullscreen(false);
appgc.start();
} catch (SlickException ex) {
ex.printStackTrace();
}
}
}
This is the code you should be able to copy & paste directly.
It does work for me, I'm not sure if I got your problem right but after the instanceof Operator you can just add the Class Name and check for it, I added some examples with an Integer and a Shape.
This is the 2nd class:
public class ShapeWithReference extends Rectangle {
private static final long serialVersionUID = 1L;
public ShapeWithReference(float x, float y, float width, float height) {
super(x, y, width, height);
}
Object reference = new String("hello");
}
Does this work for you?

Slick2D NullPointerException

I am making a game in Slick2D for Java, but when I tried to display an Image(the Slick2D type) it gives me this error:
java.lang.NullPointerException
at org.newdawn.slick.Graphics.drawImage(Graphics.java:1384)
at org.newdawn.slick.Graphics.drawImage(Graphics.java:1433)
at luke_r.games.java.broadway.states.M.render(M.java:21)
at org.newdawn.slick.state.StateBasedGame.render(StateBasedGame.java:199)
at org.newdawn.slick.GameContainer.updateAndRender(GameContainer.java:688)
at org.newdawn.slick.AppGameContainer.gameLoop(AppGameContainer.java:411)
at org.newdawn.slick.AppGameContainer.start(AppGameContainer.java:321)
at luke_r.games.java.broadway.C.main(C.java:21)
Here is the for the M class (excluding imports and class declaration, they are unneeded):
#Override
public void init(GameContainer gc, StateBasedGame sbg) throws SlickException
{
PL.x = 100;
PL.y = 100;
}
#Override
public void render(GameContainer gc, StateBasedGame sbg, Graphics g) throws SlickException
{
g.drawImage(I.title, 0, 0); //Line 21, the error
PL.render(g);
}
#Override
public void update(GameContainer gc, StateBasedGame sbg, int delta) throws SlickException
{}
#Override
public int getID()
{
return 0;
}
The problem is that I.title == null. Set it to a correct value.
In init function set the url to the image into I.title, i mean => I.title = new Image("-your URL-");
Slick2D works in this form: first of all he is init all params in method init , then until somthing happend that change the current state "he" render => update => render => update =>render => update ... You can set how much the update will occurs in the SetUpClass by using SetTargetFrameRate method.

How do you toggle an image with a button event in Slick?

So I am trying to get a simple GUI setup for my teams game we are starting and I'm trying to make a drop down inventory using "I" as the hot key for it and it drops fine but I can't seem to figure out a way without using a different key to make it retract or in essence "un" draw the image'
public void render(GameContainer gc, StateBasedGame sbg, Graphics g) throws
SlickException {
mapHud.draw(440, 1);
hotBar.draw(160, 454);
if(inv){
inventory.draw(-40, 1);
}
}
#Override
public void update(GameContainer gc, StateBasedGame sbg, int delta) throws SlickException {
Input input = gc.getInput();
if(input.isKeyPressed(Input.KEY_I)){
inv = true;
}
if(input.isKeyPressed(Input.KEY_ESCAPE)) {
sbg.enterState(0);
}
}
Try something like this:
if(input.isKeyPressed(Input.KEY_I)){
inv = !inv;
}

How to use double Buffered AWT Animations in Java

I have recently begun working with double buffering in Java. I have read tutorials that have shown me how to display images and move them using mouse and keyboard events. However this is where I become confused. My program is simple, there is a rectangle at the bottom of my window that is movable by LEFT and RIGHT key events. However I can not figure out for the life of my how to draw another shape onto the screen by an event and continue buffering it.
I would like to be able to push a key to draw a "missile" (which in my case would be a small Oval) at the X and Y position of the rectangle I have drawn already, and have it fire upwards. Much like any classic space shooter.
This however is not as much of a specific, concrete problem of mine, but a concept I do not understand. I learned how to do many of the similar things in Lua, however when it came to drawing new images after initialization or an image upon key events, I was stumped.
My question is this: In what order of Java's init(), stop(), destroy(), start(), run(), paint(), and update() cycle do I use to buffer a new shape/image onto the screen from a key event?
I have searched many tutorials with example code, but with no avail. I have been learning Java for nearly 8 months now, but no matter how basic or simple I try to understand something, it's as if even the most primordial tutorial requires prerequisite knowledge.
My code is as follows.
import java.applet.*;
import java.awt.*;
public class SquareApplet extends Applet implements Runnable
{
int x_pos = 10;
int y_pos = 400;
int rectX = 50;
int rectY = 20;
int x_speed = 5;
private Image dbImage;
private Graphics dbg;
public void init( ) { }
//public void start() { }
public void stop( ) { }
public void destroy( ) { }
//public void run ( ) { }
//public void paint (Graphics g) { }
public void start()
{
// define a new thread
Thread th = new Thread (this);
// start this thread
th.start ();
}
public void run ()
{
// lower ThreadPriority
Thread.currentThread().setPriority(Thread.MIN_PRIORITY);
// run a long while (true) this means in our case "always"
while (true) //Runtime
{
if (x_pos > this.getSize().width - rectX) {x_pos = this.getSize().width - rectX;}
if (x_pos < 0) {x_pos = 0 ;}
// repaint the applet
repaint();
try
{
// Stop thread for 20 milliseconds
Thread.sleep (20);
}
catch (InterruptedException beepis)
{
// do nothing
}
// set ThreadPriority to maximum value
Thread.currentThread().setPriority(Thread.MAX_PRIORITY);
}
}
public void paint (Graphics g)
{
// set background color
g.setColor(Color.black);
g.fillRect(0,0,this.getSize().width,this.getSize().height);
// set player color
g.setColor (Color.white);
// paint a filled colored rectangle
g.fillRect(x_pos, y_pos, rectX,rectY );
}
public void update (Graphics g)
{
// initialize buffer
if (dbImage == null)
{
dbImage = createImage (this.getSize().width, this.getSize().height);
dbg = dbImage.getGraphics ();
}
// clear screen in background
dbg.setColor (getBackground ());
dbg.fillRect (0, 0, this.getSize().width, this.getSize().height);
// draw elements in background
dbg.setColor (getForeground());
paint (dbg);
// draw image on the screen
g.drawImage (dbImage, 0, 0, this);
}
//KEY EVENTS
public boolean keyDown(Event e, int key)
{
//Up Down Left Right
if (key == Event.LEFT)
{
x_pos -= x_speed;
}
if (key == Event.RIGHT)
{
x_pos += x_speed;
}
return true;
}
}

Categories