Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
This question does not appear to be about programming within the scope defined in the help center.
Closed 3 years ago.
Improve this question
I am getting a NullPointerException for no reason. Please don't redirect me to another post. I have looked at all of them. I am making a game with LibGDX.
Here is the Error
Exception in thread "LWJGL Application" java.lang.NullPointerException
at net.hasanbilal.pr.entities.Entity.getWeight(Entity.java:88)
at net.hasanbilal.pr.entities.Entity.update(Entity.java:25)
at net.hasanbilal.pr.entities.Porter.update(Porter.java:34)
at net.hasanbilal.pr.world.GMap.update(GMap.java:28)
at net.hasanbilal.pr.world.TiledGMap.update(TiledGMap.java:40)
at net.hasanbilal.pr.PrisonRevelations.render(PrisonRevelations.java:59)
at com.badlogic.gdx.backends.lwjgl.LwjglApplication.mainLoop(LwjglApplication.java:215)
at com.badlogic.gdx.backends.lwjgl.LwjglApplication$1.run(LwjglApplication.java:120)
I will be showing each class that the error points too.
This is the Entity Class.
package net.hasanbilal.pr.entities;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.math.Vector2;
import net.hasanbilal.pr.world.GMap;
public abstract class Entity {
protected Vector2 pos;
protected EntityType t;
protected float velocityY = 0;
protected GMap m;
protected boolean grounded = false;
public void create (EntitySnapshot snapshot, EntityType type, GMap map) {
this.pos = new Vector2(snapshot.getX(),snapshot.getY());
this.t = t;
this.m = m;
}
public void update (float delta, float g) {
float newY = pos.y;
this.velocityY += g * delta * getWeight();
newY += this.velocityY * delta;
if (m.doesRectCollideWithMap(pos.x, newY, getWidth(), getHeight())) {
if (velocityY < 0) {
this.pos.y = (float) Math.floor(pos.y);
grounded = true;
}
this.velocityY = 0;
} else {
this.pos.y = newY;
grounded = false;
}
}
public abstract void render (SpriteBatch b);
protected void moveX(float amount) {
float newX = this.pos.x + amount;
if (!m.doesRectCollideWithMap(newX, pos.y, getWidth(), getHeight()))
this.pos.x = newX;
}
public EntitySnapshot getSaveSnapshot(){
return new EntitySnapshot(t.getId(), pos.x, pos.y);
}
public Vector2 getPos() {
return pos;
}
public float getX() {
return pos.x;
}
public float getY() {
return pos.y;
}
public EntityType getT() {
return t;
}
public float getVelocityY() {
return velocityY;
}
public boolean isGrounded() {
return grounded;
}
public int getWidth() {
return t.getWidth();
}
public int getHeight() {
return t.getHeight();
}
public float getWeight() {
return t.getWeight();
}
}
This is the Porter Class.
package net.hasanbilal.pr.entities;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.Input.Keys;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import net.hasanbilal.pr.world.GMap;
public class Porter extends Entity {
private static final int SPEED = 80;
private static final int JUMP_VELOCITY = 5;
Texture img;
public void create (EntitySnapshot snapshot, EntityType type, GMap map) {
super.create(snapshot, type, map);
img = new Texture("porter.png");
}
#Override
public void render(SpriteBatch b) {
b.draw(img, pos.x, pos.y, getWidth(), getHeight());
}
public void update(float delta, float g) {
if (Gdx.input.isKeyPressed(Keys.SPACE) && grounded)
this.velocityY += JUMP_VELOCITY * getWeight();
else if (Gdx.input.isKeyPressed(Keys.SPACE) && !grounded && this.velocityY > 0)
this.velocityY += JUMP_VELOCITY * getWeight() * delta;
super.update(delta, g);
if (Gdx.input.isKeyPressed(Keys.LEFT))
moveX(-SPEED * delta);
if (Gdx.input.isKeyPressed(Keys.RIGHT))
moveX(SPEED * delta);
}
}
This is the GMap
package net.hasanbilal.pr.world;
import java.util.ArrayList;
import com.badlogic.gdx.graphics.OrthographicCamera;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import net.hasanbilal.pr.entities.Entity;
import net.hasanbilal.pr.entities.EntityLoader;
import net.hasanbilal.pr.entities.Porter;
public abstract class GMap {
protected ArrayList<Entity> entities;
public GMap() {
entities = new ArrayList<Entity>();
entities.addAll(EntityLoader.loadEntities("basic", this, entities));
}
public void render (OrthographicCamera c, SpriteBatch b) {
for (Entity entity : entities) {
entity.render(b);
}
}
public void update (float deltaTime) {
for (Entity entity : entities) {
entity.update(deltaTime, -9.8f);
}
}
public void dispose () {
EntityLoader.saveEntities("basic", entities);
}
/**
* Gets a tile by location
* #param layer
* #param x
* #param y
* #return
*/
public TileType getByLocation(int layer, float x, float y) {
return this.getByCoordinate(layer, (int) (x / TileType.TILE_SIZE), (int) (y / TileType.TILE_SIZE));
}
/**
* Gets Tile by coordinate
* #param layer
* #param col
* #param row
* #return
*/
public abstract TileType getByCoordinate(int layer, int col, int row);
public boolean doesRectCollideWithMap(float x, float y, int width, int height) {
if (x<0 || y < 0 || x + width > getPixelWidth() || y + height > getPixelHeight())
return true;
for (int row = (int) (y / TileType.TILE_SIZE); row < Math.ceil((y + height) / TileType.TILE_SIZE); row++) {
for (int col = (int) (x / TileType.TILE_SIZE); col < Math.ceil((x + width) / TileType.TILE_SIZE); col++) {
for (int layer = 0; layer < getLayers(); layer++) {
TileType type = getByCoordinate(layer, col, row);
if (type != null && type.isCollidable())
return true;
}
}
}
return false;
}
public abstract int getWidth();
public abstract int getHeight();
public abstract int getLayers();
public int getPixelWidth() {
return this.getWidth() * TileType.TILE_SIZE;
}
public int getPixelHeight() {
return this.getHeight() * TileType.TILE_SIZE;
}
}
This is the class for the TiledGMap
package net.hasanbilal.pr.world;
import com.badlogic.gdx.graphics.OrthographicCamera;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.maps.tiled.TiledMap;
import com.badlogic.gdx.maps.tiled.TiledMapTile;
import com.badlogic.gdx.maps.tiled.TiledMapTileLayer;
import com.badlogic.gdx.maps.tiled.TiledMapTileLayer.Cell;
import com.badlogic.gdx.maps.tiled.TmxMapLoader;
import com.badlogic.gdx.maps.tiled.renderers.OrthogonalTiledMapRenderer;
import net.hasanbilal.pr.entities.Entity;
import net.hasanbilal.pr.entities.Porter;
public class TiledGMap extends GMap {
TiledMap lvl1;
OrthogonalTiledMapRenderer otmr;
public TiledGMap() {
lvl1 = new TmxMapLoader().load("level1.tmx");
otmr = new OrthogonalTiledMapRenderer(lvl1);
}
#Override
public void render(OrthographicCamera c, SpriteBatch b) {
otmr.setView(c);
otmr.render();
b.setProjectionMatrix(c.combined);
b.begin();
super.render(c, b);
b.end();
}
#Override
public void update(float deltaTime) {
super.update(deltaTime);
}
#Override
public void dispose() {
lvl1.dispose();
}
#Override
public TileType getByCoordinate(int layer, int col, int row) {
Cell cell = ((TiledMapTileLayer) lvl1.getLayers().get(layer)).getCell(col, row);
if (cell !=null) {
TiledMapTile t = cell.getTile();
if (t != null) {
int id = t.getId();
return TileType.getTileTypeById(id);
}
}
return null;
}
#Override
public int getWidth() {
return ((TiledMapTileLayer) lvl1.getLayers().get(0)).getWidth();
}
#Override
public int getHeight() {
return ((TiledMapTileLayer) lvl1.getLayers().get(0)).getHeight();
}
#Override
public int getLayers() {
return lvl1.getLayers().getCount();
}
}
This is the Prison Revelations class
package net.hasanbilal.pr;
import com.badlogic.gdx.ApplicationAdapter;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.graphics.GL20;
import com.badlogic.gdx.graphics.OrthographicCamera;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.math.Vector3;
import net.hasanbilal.pr.world.GMap;
import net.hasanbilal.pr.world.TileType;
import net.hasanbilal.pr.world.TiledGMap;
public class PrisonRevelations extends ApplicationAdapter {
OrthographicCamera c;
SpriteBatch b;
GMap gm;
#Override
public void create () {
b = new SpriteBatch();
c = new OrthographicCamera();
c.setToOrtho(false, Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
c.update();
gm = new TiledGMap();
}
#Override
public void render () {
Gdx.gl.glClearColor(255, 255, 255, 1);
Gdx.gl.glBlendFunc(GL20.GL_SRC_ALPHA, GL20.GL_ONE_MINUS_SRC_ALPHA);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
if (Gdx.input.isTouched()) {
c.translate(-Gdx.input.getDeltaX(), Gdx.input.getDeltaY());
c.update();
}
if (Gdx.input.justTouched()) {
Vector3 pos = c.unproject(new Vector3(Gdx.input.getX(), Gdx.input.getY(), 0));
TileType t = gm.getByLocation(1, pos.x, pos.y);
if (t != null) {
System.out.println("You clicked on tile with id" + t.getId() + " " + t.getName()+ " " + t.isCollidable() + " " + t.getDamage());
}
}
c.update();
gm.update(Gdx.graphics.getDeltaTime());
gm.render(c, b);
}
#Override
public void dispose () {
b.dispose();
gm.dispose();
}
}
Please help. Im gonna die. This is due soon.
Looks like you made a mistake with parameters names on your create, change to this:
public void create (EntitySnapshot snapshot, EntityType type, GMap map) {
this.pos = new Vector2(snapshot.getX(),snapshot.getY());
this.t = type;
this.m = map;
}
Related
package abdclient.gui.hud;
import org.lwjgl.input.Keyboard;
import org.newdawn.slick.opengl.renderer.Renderer;
import com.google.common.base.Predicate;
import java.io.IOException;
import java.util.Collection;
import java.util.HashMap;
import java.util.Optional;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.GuiScreen;
import net.minecraft.client.gui.ScaledResolution;
public class HUDConfigScreen extends GuiScreen {
private final HashMap<IRenderer, ScreenPosition> renderers = new HashMap<IRenderer, ScreenPosition>();
private Optional<IRenderer> selectedRenderer = Optional.empty();
private int prevX, prevY;
public HUDConfigScreen(HUDManager api) {
Collection<IRenderer> registeredRenderers = api.getRegisteredRenderers();
for(IRenderer ren : registeredRenderers) {
if(!ren.isEnabled()) {
continue;
}
ScreenPosition pos = ren.load();
if(pos == null) {
pos = ScreenPosition.fromRelativePosition(0.5, 0.5);
}
adjustBounds(ren, pos);
this.renderers.put(ren, pos);
}
}
#Override
public void drawScreen(int mouseX, int mouseY, float partialTicks) {
super.drawDefaultBackground();
final float zBackup = this.zLevel;
this.zLevel =200;
this.drawHollowRect(0, 0, this.width - 1, this.height - 1, 0xFF0000FF);
for(IRenderer renderer : renderers.keySet()) {
ScreenPosition pos = renderers.get(renderer);
renderer.renderDummy(pos);
this.drawHollowRect(pos.getAbsoluteX(), pos.getAbsoluteY(), renderer.getWidth(), renderer.getHeight(), 0xFF00FFFF);
}
this.zLevel = zBackup;
}
private void drawHollowRect(int x, int y, int w, int h, int color) {
this.drawHorizontalLine(x, x + w, y, color);
this.drawHorizontalLine(x, x + w, y + h, color);
this.drawVerticalLine(x, y + h, y, color);
this.drawVerticalLine(x + w, y + h, y, color);
}
#Override
protected void keyTyped(char typedChar, int keyCode) throws IOException {
if(keyCode == Keyboard.KEY_ESCAPE) {
renderers.entrySet().forEach((entry) ->{
entry.getKey().save(entry.getValue());
});
this.mc.displayGuiScreen(null);
}
}
#Override
protected void mouseClickMove(int x, int y, int bButton, long time) {
if(selectedRenderer.isPresent()) {
moveSelectedRendererBy(x - prevX, y - prevY);
}
this.prevX = x;
this.prevY = y;
}
private void moveSelectedRendererBy(int offsetX, int offsetY) {
IRenderer renderer = selectedRenderer.get();
ScreenPosition pos = renderers.get(renderer);
pos.setAbsolute(pos.getAbsoluteX() + offsetX, pos.getAbsoluteY() + offsetY);
adjustBounds(renderer, pos);
}
#Override
public void onGuiClosed() {
for(IRenderer renderer : renderers.keySet()) {
renderer.save(renderers.get(renderer));
}
}
#Override
public boolean doesGuiPauseGame() {
return true;
}
private void adjustBounds(IRenderer renderer, ScreenPosition pos) {
ScaledResolution res = new ScaledResolution(Minecraft.getMinecraft());
int screenWidth = res.getScaledWidth();
int screenHeight = res.getScaledHeight();
int absoluteX = Math.max(0, Math.min(pos.getAbsoluteX(), Math.max(screenWidth - renderer.getWidth(),0)));
int absoluteY = Math.max(0, Math.min(pos.getAbsoluteY(), Math.max(screenHeight - renderer.getHeight(),0)));
pos.setAbsolute(absoluteX, absoluteY);
}
#Override
protected void mouseClicked(int x, int y, int button) throws IOException {
this.prevX = x;
this.prevY = y;
loadMouseOver(x, y);
}
private void loadMouseOver(int x, int y) {
this.selectedRenderer = renderers.keySet().stream().filter(new MouseOverFinder(x, y)).findFirst();
}
private class MouseOverFinder implements Predicate<IRenderer> {
private int mouseX, mouseY;
public MouseOverFinder(int x, int y) {
this.mouseX = x;
this.mouseY = y;
}
public boolean test(IRenderer renderer) {
ScreenPosition pos = renderers.get(renderer);
int absoluteX = pos.getAbsoluteX();
int absoluteY = pos.getAbsoluteY();
if(mouseX >= absoluteX && mouseX <= absoluteX + renderer.getWidth()) {
if(mouseY >= absoluteY && mouseY <= absoluteY + renderer.getHeight()) {
return true;
}
}
return false;
}
#Override
public boolean apply(IRenderer arg0) {
// TODO Auto-generated method stub
return false;
}
}
}
The main issue is on line 146
Sorry if the format is bad, I just have little experence with Java and StackOverflow
The game would boot as normal, open the gui as normal but the moment I clicked my game (with my mouse) to interact with the draggable GUI it would instantly crash. These are the logs; This is a minecraft 1.8.9 PVP client containing optifine. I am making it on eclipse IDE.
Time: 2023-02-07, 11:10 p.m.
Description: Updating screen events
java.lang.ClassCastException: class abdclient.gui.hud.HUDConfigScreen$MouseOverFinder cannot be cast to class java.util.function.Predicate (abdclient.gui.hud.HUDConfigScreen$MouseOverFinder is in unnamed module of loader 'app'; java.util.function.Predicate is in module java.base of loader 'bootstrap')
at abdclient.gui.hud.HUDConfigScreen.loadMouseOver(HUDConfigScreen.java:146)
at abdclient.gui.hud.HUDConfigScreen.mouseClicked(HUDConfigScreen.java:142)
at net.minecraft.client.gui.GuiScreen.handleMouseInput(GuiScreen.java:530)
at net.minecraft.client.gui.GuiScreen.handleInput(GuiScreen.java:502)
at net.minecraft.client.Minecraft.runTick(Minecraft.java:1666)
at net.minecraft.client.Minecraft.runGameLoop(Minecraft.java:1025)
at net.minecraft.client.Minecraft.run(Minecraft.java:354)
at net.minecraft.client.main.Main.main(Main.java:113)
at Start.main(Start.java:11)
A detailed walkthrough of the error, its code path and all known details is as follows:
---------------------------------------------------------------------------------------
-- Head --
Stacktrace:
at abdclient.gui.hud.HUDConfigScreen.loadMouseOver(HUDConfigScreen.java:146)
at abdclient.gui.hud.HUDConfigScreen.mouseClicked(HUDConfigScreen.java:142)
at net.minecraft.client.gui.GuiScreen.handleMouseInput(GuiScreen.java:530)
at net.minecraft.client.gui.GuiScreen.handleInput(GuiScreen.java:502)
-- Affected screen --
Details:
Screen name: abdclient.gui.hud.HUDConfigScreen
I have implemented a Player class which handles collision between the player and the objects in game. When I run it, he falls through the floor. I have followed a tutorial step by step but it is not working.
Below I have added the Player class and GameScreen class.
I have tried making rectangles around my Player to interact with, but it wasnt a fix.
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.Screen;
import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.graphics.GL30;
import com.badlogic.gdx.graphics.OrthographicCamera;
import com.badlogic.gdx.graphics.g2d.BitmapFont;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.maps.MapObjects;
import com.badlogic.gdx.maps.objects.RectangleMapObject;
import com.badlogic.gdx.maps.tiled.TiledMap;
import com.badlogic.gdx.maps.tiled.TiledMapTileLayer;
import com.badlogic.gdx.maps.tiled.TmxMapLoader;
import com.badlogic.gdx.maps.tiled.renderers.OrthogonalTiledMapRenderer;
import com.badlogic.gdx.math.Intersector;
import com.badlogic.gdx.math.Rectangle;
import com.badlogic.gdx.utils.viewport.Viewport;
import inf112.skeleton.app.AGame;
import inf112.skeleton.app.entities.Player;
import inf112.skeleton.app.scenes.Hud;
public class GameScreen implements Screen {
public AGame game;
public TiledMap map;
private OrthogonalTiledMapRenderer mapRenderer;
private OrthographicCamera camera;
public Player player;
private BitmapFont font;
public Viewport gameport;
private Hud hud;
public GameScreen (AGame game) {
this.game = game;
hud = new Hud(game.batch);
}
#Override
public void show() {
font = new BitmapFont();
font.setColor(Color.RED);
font.setColor(Color.RED);
map = new TmxMapLoader().load("assets/data/GameBoard2.tmx");
camera = new OrthographicCamera();
camera.setToOrtho(false, 10, 10);
mapRenderer = new OrthogonalTiledMapRenderer(map, (float)0.015625);
mapRenderer.setView(camera);
player = new Player((TiledMapTileLayer) map.getLayers().get("Player"));
player.setPosition(11 * player.getCollisionLayer().getTileWidth(), (player.getCollisionLayer().getHeight() - 14) * player.getCollisionLayer().getTileHeight());
}
#Override
public void render(float delta) {
Gdx.gl.glClearColor(0, 0, 0, 1);
Gdx.gl.glClear(GL30.GL_COLOR_BUFFER_BIT);
mapRenderer.setView(camera);
mapRenderer.render();
mapRenderer.getBatch().begin();
player.draw((SpriteBatch) mapRenderer.getBatch());
mapRenderer.getBatch().end();
game.batch.setProjectionMatrix(hud.stage.getCamera().combined);
hud.stage.draw();
}
#Override
public void resize(int width, int height) {
camera.viewportHeight = height;
camera.viewportWidth = width;
}
#Override
public void pause() {
// TODO Auto-generated method stub
}
#Override
public void resume() {
// TODO Auto-generated method stub
}
#Override
public void hide() {
// TODO Auto-generated method stub
}
#Override
public void dispose() {
font.dispose();
mapRenderer.dispose();
map.dispose();
game.dispose();
}
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.Input;
import com.badlogic.gdx.InputProcessor;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.g2d.Sprite;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.maps.tiled.TiledMapTileLayer;
import com.badlogic.gdx.math.Rectangle;
import com.badlogic.gdx.math.Vector2;
public class Player extends Sprite implements InputProcessor {
private String blockedKey = "blocked";
private Vector2 velocity = new Vector2();
private float speed = 60 * 2, gravity = 60 * 1.8f, increment;
private boolean canJump;
private TiledMapTileLayer collisionLayer;
public Player(TiledMapTileLayer collisionLayer) {
this.collisionLayer = collisionLayer;
//setScale((float)0.1);
}
public void draw(SpriteBatch spriteBatch) {
update(Gdx.graphics.getDeltaTime());
super.draw(spriteBatch);
}
public void update(float delta) {
// apply gravity
velocity.y -= gravity * delta;
// clamp velocity
if(velocity.y > speed)
velocity.y = speed;
else if(velocity.y < -speed)
velocity.y = -speed;
// save old position
float oldX = getX(), oldY = getY();
boolean collisionX = false, collisionY = false;
// move on x
setX(getX() + velocity.x * delta);
// calculate the increment for step in #collidesLeft() and #collidesRight()
increment = collisionLayer.getTileWidth();
increment = getWidth() < increment ? getWidth() / 2 : increment / 2;
if(velocity.x < 0) // going left
collisionX = collidesLeft();
else if(velocity.x > 0) // going right
collisionX = collidesRight();
// react to x collision
if(collisionX) {
setX(oldX);
velocity.x = 0;
}
// move on y
setY(getY() + velocity.y * delta * 5f);
// calculate the increment for step in #collidesBottom() and #collidesTop()
increment = collisionLayer.getTileHeight();
increment = getHeight() < increment ? getHeight() / 2 : increment / 2;
if(velocity.y < 0) // going down
canJump = collisionY = collidesBottom();
else if(velocity.y > 0) // going up
collisionY = collidesTop();
// react to y collision
if(collisionY) {
setY(oldY);
velocity.y = 0;
}
// update animation
}
private boolean isCellBlocked(float x, float y) {
TiledMapTileLayer.Cell cell = collisionLayer.getCell((int) (x / collisionLayer.getTileWidth()), (int) (y / collisionLayer.getTileHeight()));
return cell != null && cell.getTile() != null && cell.getTile().getProperties().containsKey(blockedKey);
}
public boolean collidesRight() {
for(float step = 0; step <= getHeight(); step += increment)
if(isCellBlocked(getX() + getWidth(), getY() + step))
return true;
return false;
}
public boolean collidesLeft() {
for(float step = 0; step <= getHeight(); step += increment)
if(isCellBlocked(getX(), getY() + step))
return true;
return false;
}
public boolean collidesTop() {
for(float step = 0; step <= getWidth(); step += increment)
if(isCellBlocked(getX() + step, getY() + getHeight()))
return true;
return false;
}
public boolean collidesBottom() {
for(float step = 0; step <= getWidth(); step += increment)
if(isCellBlocked(getX() + step, getY()))
return true;
return false;
}
public Vector2 getVelocity() {
return velocity;
}
public void setVelocity(Vector2 velocity) {
this.velocity = velocity;
}
public float getSpeed() {
return speed;
}
public void setSpeed(float speed) {
this.speed = speed;
}
public float getGravity() {
return gravity;
}
public void setGravity(float gravity) {
this.gravity = gravity;
}
public TiledMapTileLayer getCollisionLayer() {
return collisionLayer;
}
public void setCollisionLayer(TiledMapTileLayer collisionLayer) {
this.collisionLayer = collisionLayer;
}
#Override
public boolean keyDown(int keycode) {
switch(keycode) {
case Input.Keys.W:
if(canJump) {
velocity.y = speed / 1.8f;
canJump = false;
}
break;
case Input.Keys.A:
velocity.x = -speed;
break;
case Input.Keys.D:
velocity.x = speed;
}
return true;
}
#Override
public boolean keyUp(int keycode) {
switch(keycode) {
case Input.Keys.A:
case Input.Keys.D:
velocity.x = 0;
}
return true;
}
#Override
public boolean keyTyped(char character) {
return false;
}
#Override
public boolean touchDown(int screenX, int screenY, int pointer, int button) {
return false;
}
#Override
public boolean touchUp(int screenX, int screenY, int pointer, int button) {
return false;
}
#Override
public boolean touchDragged(int screenX, int screenY, int pointer) {
return false;
}
#Override
public boolean mouseMoved(int screenX, int screenY) {
return false;
}
#Override
public boolean scrolled(float amountX, float amountY) {
return false;
}
The position of a libGDXSprite is bottom left so you need to make a distinction between position as far as your render is concerned, and as far as collision is concerned.
So if you add a half tile width to the x position when checking for the collision that would match what you see, being the base of the sprite.
Imagine a tilewidth of 4f and a position of 7f. As you look the sprite is rendered mainly on the third tile, but the collision is tested against the second one.
I am trying to make an Asteroids game clone in JavaFX. So far, I have been able to draw the ship and asteroids onto the screen (where Rectangles represent them, for now). I have also implemented movement for the ship, and randomized movements for the asteroids.
I am having trouble implementing the code needed to bounce the asteroids off each other. The current method that does the collision checking (called checkAsteroidCollisions) is bugged in that all asteroids start stuttering in place. They don't move, but rather oscillate back and forth in place rapidly. Without the call to this method, all asteroids begin moving normally and as expected.
Instead, I want each asteroid to move freely and, when coming into contact with another asteroid, bounce off each other like in the actual Asteroids game.
MainApp.java
import java.util.ArrayList;
import java.util.HashSet;
import javafx.animation.AnimationTimer;
import javafx.application.Application;
import javafx.event.EventHandler;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.canvas.Canvas;
import javafx.scene.canvas.GraphicsContext;
import javafx.scene.input.KeyEvent;
import javafx.scene.layout.StackPane;
import javafx.scene.paint.Color;
import javafx.stage.Stage;
public class MainApp extends Application {
private static final int WIDTH = 700;
private static final int HEIGHT = 900;
private static final int NUM_OF_ASTEROIDS = 12;
private static final Color ASTEROID_COLOR = Color.GRAY;
private static final Color PLAYER_COLOR = Color.BLUE;
private Player player;
private ArrayList<Entity> asteroids;
long lastNanoTime; // For AnimationTimer
HashSet<String> inputs; // For inputs
private static final int MAX_SPEED = 150;
private static final int SPEED = 10;
private static final int ASTEROID_SPEED = 150;
private StackPane background;
/*
* Generates a random number between min and max, inclusive.
*/
private float genRandom(int min, int max) {
return (float) Math.floor(Math.random() * (max - min + 1) + min);
}
/*
* Initializes the asteroids
*/
private void initAsteroids() {
this.asteroids = new ArrayList<Entity>();
for (int i = 0; i < NUM_OF_ASTEROIDS; i++) {
Entity asteroid = new Entity(50, 50, ASTEROID_COLOR, EntityType.ASTEROID);
float px = (float) genRandom(200, WIDTH - 50);
float py = (float) genRandom(200, HEIGHT - 50);
asteroid.setPos(px, py);
// Keep recalculating position until there are no collisions
while (asteroid.intersectsWith(this.asteroids)) {
px = (float) genRandom(200, WIDTH - 50);
py = (float) genRandom(200, HEIGHT - 50);
asteroid.setPos(px, py);
}
// Randomly generate numbers to change velocity by
float dx = this.genRandom(-ASTEROID_SPEED, ASTEROID_SPEED);
float dy = this.genRandom(-ASTEROID_SPEED, ASTEROID_SPEED);
asteroid.changeVelocity(dx, dy);
this.asteroids.add(asteroid);
}
}
/*
* Initializes the player
*/
private void initPlayer() {
this.player = new Player(30, 30, PLAYER_COLOR, EntityType.PLAYER);
this.player.setPos(WIDTH / 2, 50);
}
/*
* Checks collisions with screen boundaries
*/
private void checkOffScreenCollisions(Entity e) {
if (e.getX() < -50)
e.setX(WIDTH);
if (e.getX() > WIDTH)
e.setX(0);
if (e.getY() < -50)
e.setY(HEIGHT);
if (e.getY() > HEIGHT)
e.setY(0);
}
/*
* Controls speed
*/
private void controlSpeed(Entity e) {
if (e.getDx() < -MAX_SPEED)
e.setDx(-MAX_SPEED);
if (e.getDx() > MAX_SPEED)
e.setDx(MAX_SPEED);
if (e.getDy() < -MAX_SPEED)
e.setDy(-MAX_SPEED);
if (e.getDy() > MAX_SPEED)
e.setDy(MAX_SPEED);
}
/*
* Controls each asteroid's speed and collision off screen
*/
private void controlAsteroids(ArrayList<Entity> asteroids) {
for (Entity asteroid : asteroids) {
this.checkOffScreenCollisions(asteroid);
this.controlSpeed(asteroid);
}
}
/*
* Checks an asteroid's collision with another asteroid
*/
private void checkAsteroidCollisions() {
for (int i = 0; i < NUM_OF_ASTEROIDS; i++) {
Entity asteroid = this.asteroids.get(i);
if (asteroid.intersectsWith(this.asteroids)){
float dx = (float) asteroid.getDx();
float dy = (float) asteroid.getDy();
asteroid.setDx(0);
asteroid.setDy(0);
asteroid.changeVelocity(-dx, -dy);
}
}
}
#Override
public void start(Stage primaryStage) throws Exception {
primaryStage.setTitle("Hello World!");
this.initAsteroids();
this.initPlayer();
background = new StackPane();
background.setStyle("-fx-background-color: pink");
this.inputs = new HashSet<String>();
Group root = new Group();
Scene scene = new Scene(root);
primaryStage.setScene(scene);
scene.setOnKeyPressed(new EventHandler<KeyEvent>() {
#Override
public void handle(KeyEvent e) {
String code = e.getCode().toString();
inputs.add(code);
}
});
scene.setOnKeyReleased(new EventHandler<KeyEvent>() {
#Override
public void handle(KeyEvent e) {
String code = e.getCode().toString();
inputs.remove(code);
}
});
Canvas canvas = new Canvas(WIDTH, HEIGHT);
GraphicsContext gc = canvas.getGraphicsContext2D();
background.getChildren().add(canvas);
root.getChildren().add(background);
lastNanoTime = System.nanoTime();
new AnimationTimer() {
#Override
public void handle(long currentNanoTime) {
float elapsedTime = (float) ((currentNanoTime - lastNanoTime) / 1000000000.0);
lastNanoTime = currentNanoTime;
/* PLAYER */
// Game Logic
if (inputs.contains("A"))
player.changeVelocity(-SPEED, 0);
if (inputs.contains("D"))
player.changeVelocity(SPEED, 0);
if (inputs.contains("W"))
player.changeVelocity(0, -SPEED);
if (inputs.contains("S"))
player.changeVelocity(0, SPEED);
// Collision with edge of map
checkOffScreenCollisions(player);
// Control speed
controlSpeed(player);
player.update(elapsedTime);
/* ASTEROIDS */
gc.setFill(ASTEROID_COLOR);
for(int i = 0; i < NUM_OF_ASTEROIDS; i++) {
checkAsteroidCollisions(i); // BUGGY CODE
}
controlAsteroids(asteroids);
gc.clearRect(0, 0, WIDTH, HEIGHT);
for (Entity asteroid : asteroids) {
asteroid.update(elapsedTime);
asteroid.render(gc);
}
gc.setFill(PLAYER_COLOR);
player.render(gc);
}
}.start();
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
Entity.java:
import java.util.ArrayList;
import javafx.geometry.Rectangle2D;
import javafx.scene.canvas.GraphicsContext;
import javafx.scene.paint.Color;
public class Entity {
private Color color;
private double x, y, width, height, dx, dy;
private EntityType entityType; // ID of this Entity
public Entity(float width, float height, Color color, EntityType type) {
this.x = this.dx = 0;
this.y = this.dy = 0;
this.width = width;
this.height = height;
this.color = color;
this.entityType = type;
}
/*
* Getters and setters
*/
public Color getColor() {
return color;
}
public void setColor(Color color) {
this.color = color;
}
public double getX() {
return x;
}
public void setX(float x) {
this.x = x;
}
public double getY() {
return y;
}
public void setY(float y) {
this.y = y;
}
public double getDx() {
return dx;
}
public void setDx(float dx) {
this.dx = dx;
}
public double getDy() {
return dy;
}
public void setDy(float dy) {
this.dy = dy;
}
public EntityType getEntityType() {
return entityType;
}
/*
* Adds to dx and dy (velocity)
*/
public void changeVelocity(float dx, float dy) {
this.dx += dx;
this.dy += dy;
}
/*
* Sets position
*/
public void setPos(float x, float y) {
this.setX(x);
this.setY(y);
}
/*
* Gets new position of the Entity based on velocity and time
*/
public void update(float time) {
this.x += this.dx * time;
this.y += this.dy * time;
}
/*
* Used for collisions
*/
public Rectangle2D getBoundary() {
return new Rectangle2D(this.x, this.y, this.width, this.height);
}
/*
* Checks for intersections
*/
public boolean intersectsWith(Entity e) {
return e.getBoundary().intersects(this.getBoundary());
}
/*
* If any of the entities in the passed in ArrayList
* intersects with this, then return true;
*/
public boolean intersectsWith(ArrayList<Entity> entities) {
for(Entity e : entities) {
if(e.getBoundary().intersects(this.getBoundary()))
return true;
}
return false;
}
/*
* Draws the shape
*/
public void render(GraphicsContext gc) {
gc.fillRoundRect(x, y, width, height, 10, 10);
}
#Override
public String toString() {
return "Entity [x=" + x + ", y=" + y + ", width=" + width + ", height=" + height + ", entityType=" + entityType
+ "]";
}
}
I think you will need to change the position of the two colliding asteroids slightly so their state is not on collision anymore.
What happens right now is that you change their movement after the collision but I guess that your algorithm notices that they are still touching, so it will try to change the movement again with the same result as before.
What you need to implement now is a change in the position of the two asteroids so your collision detection won´t act up again immediately after it´s first call.
I hope I could help you.
I'm trying to make it print out "Game over" when the Green Square(Cuboid) runs over/into the blue(CuboidKiller) one.
GAME class:
package plugin.dev.wristz;
import java.awt.Graphics;
import java.awt.Image;
import java.util.ArrayList;
import java.util.Random;
import javax.swing.JFrame;
public class Game extends JFrame {
private static final long serialVersionUID = 294623570092988970L;
public static ArrayList<CuboidKiller> killers;
public static int h = 1024, w = 768;
public static Game game;
public static Graphics graphics, g2;
public static Image image;
public static Cuboid cuboid;
public Game(String title) {
setTitle(title);
setSize(1024, 768);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setResizable(true);
setVisible(true);
setLocationRelativeTo(null);
addKeyListener(new KeyHandler(cuboid));
g2 = getGraphics();
paint(g2);
}
public static void main(String[] args) {
cuboid = new Cuboid();
Thread cubi = new Thread(cuboid);
cubi.start();
killers = new ArrayList<CuboidKiller>();
CuboidKiller a = new CuboidKiller(new Random().nextInt(h), new Random().nextInt(w), new Random().nextInt(50) + 20);
killers.add(a);
game = new Game("Killer Cuboids");
}
#Override
public void paint(Graphics g) {
image = createImage(getWidth(), getHeight());
graphics = image.getGraphics();
paintComponent(graphics);
g.drawImage(image, 0, 0, this);
}
public void paintComponent(Graphics g) {
checkGameOver();
cuboid.draw(g);
for (CuboidKiller killer : killers)
killer.draw(g);
repaint();
}
public void checkGameOver() {
for (CuboidKiller killer : killers)
if (killer.isTouching(cuboid))
System.out.println("Game over!");
}
public int getH() {
return h;
}
public void setH(int wh) {
h = wh;
}
public int getW() {
return w;
}
public void setW(int ww) {
w = ww;
}
}
Cuboid class:
package plugin.dev.wristz;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.event.KeyEvent;
#SuppressWarnings("static-access")
public class Cuboid implements Runnable {
private int x, y, xDirection, zDirection;
public Cuboid() {
this.x = 799;
this.y = 755;
}
public void draw(Graphics g) {
g.setColor(Color.GREEN);
g.fillRect(x, y, 25, 25);
}
public void move() {
x += xDirection;
y += zDirection;
if (x <= 10)
x = 0 + 10;
if (y <= 35)
y = 0 + 35;
if (x >= 1024 - 35)
x = 1024 - 35;
if (y >= 768 - 35)
y = 768 - 35;
}
public void keyPressed(KeyEvent ev) {
int keyCode = ev.getKeyCode();
if (keyCode == ev.VK_LEFT) {
setXDirection(-5);
}
if (keyCode == ev.VK_RIGHT) {
setXDirection(5);
}
if (keyCode == ev.VK_UP) {
setZDirection(-5);
}
if (keyCode == ev.VK_DOWN) {
setZDirection(5);
}
}
public void keyReleased(KeyEvent ev) {
int keyCode = ev.getKeyCode();
if (keyCode == ev.VK_LEFT) {
setXDirection(0);
}
if (keyCode == ev.VK_RIGHT) {
setXDirection(0);
}
if (keyCode == ev.VK_UP) {
setZDirection(0);
}
if (keyCode == ev.VK_DOWN) {
setZDirection(0);
}
}
#Override
public void run() {
try {
while (true) {
move();
Thread.sleep(5);
}
} catch (Exception e) {
System.err.println(e.getMessage());
}
}
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 getXDirection() {
return xDirection;
}
public void setXDirection(int xDirection) {
this.xDirection = xDirection;
}
public int getZ() {
return y;
}
public void setZ(int z) {
this.y = z;
}
public int getZDirection() {
return zDirection;
}
public void setZDirection(int zDirection) {
this.zDirection = zDirection;
}
}
Cuboid Killer:
package plugin.dev.wristz;
import java.awt.Color;
import java.awt.Graphics;
import java.util.HashMap;
public class CuboidKiller {
private int x, y, radius;
private HashMap<Integer, Integer> points;
public CuboidKiller(int x, int y, int radius) {
this.points = new HashMap<Integer, Integer>();
setPoints();
this.x = x;
this.y = y;
this.radius = radius;
}
public void draw(Graphics g) {
g.setColor(Color.blue);
g.fillRect(x, y, radius, radius);
}
public void setPoints() {
this.points.put(x, y);
this.points.put(x + radius, y);
this.points.put(x + radius, y - radius);
this.points.put(x, y - radius);
}
public boolean isTouching(Cuboid cuboid) {
boolean result = true;
//int a = cuboid.getX(), b = cuboid.getZ();
result = true;
return result;
}
public int getRadius() {
return radius;
}
public void setRadius(int radius) {
this.radius = radius;
}
public int getY() {
return y;
}
public void setY(int y) {
this.y = y;
}
public int getX() {
return x;
}
public void setX(int x) {
this.x = x;
}
public HashMap<Integer, Integer> getPoints() {
return points;
}
public void setPoints(HashMap<Integer, Integer> points) {
this.points = points;
}
}
Well, there are two approaches. Either you write it yourself, or you just use what Java 8 provides.
This guy has a very nice explanation on how to detect collision between two rectangles: Java check if two rectangles overlap at any point
But if I were the one writing it, I would just have both classes contain a Rectangle object (http://docs.oracle.com/javase/8/docs/api/java/awt/Rectangle.html), and just call the intersects() function provided by Rectangle. :-)
I have been having some issues with loading Textures in LWJGL/Slick Util. I am receiving this error in the texture.bind() method. I would also like advice as to how to improve my code if improvement is needed. Here it is:
The Sprite Class:
package geniushour.engine.animation;
import static org.lwjgl.opengl.GL11.*;
import java.io.IOException;
import org.newdawn.slick.opengl.Texture;
public class Sprite {
private float sx;
private float sy;
private Texture texture;
public Sprite(float sx, float sy, Texture texture) throws IOException{
this.texture = texture;
this.sx = sx;
this.sy = sy;
}
public void render(){
texture.bind();
glBegin(GL_QUADS);
glTexCoord2f(0,0);
glVertex2f(0,0);
glTexCoord2f(1,0);
glVertex2f(0,sy);
glTexCoord2f(1,1);
glVertex2f(sx,sy);
glTexCoord2f(0,1);
glVertex2f(sx,0);
glEnd();
}
public float getSX(){
return sx;
}
public float getSY(){
return sy;
}
public Texture getTexture(){
return texture;
}
public void setSX(float sx){
this.sx = sx;
}
public void setSY(float sy){
this.sy = sy;
}
/*public void setSpriteTexture(String key) throws IOException{
this.texture = TextureLoader.getTexture("PNG", ResourceLoader.getResourceAsStream("img/"+key+".png"));
}*/
}
The GameObject Class:
package geniushour.gameobject;
import static org.lwjgl.opengl.GL11.glPopMatrix;
import static org.lwjgl.opengl.GL11.glPushMatrix;
import static org.lwjgl.opengl.GL11.glTranslatef;
import java.io.IOException;
import org.newdawn.slick.opengl.Texture;
import geniushour.engine.animation.Sprite;
public abstract class GameObject {
protected float x;
protected float y;
protected float sx;
protected float sy;
protected Sprite spr;
protected int type;
protected static final int PLAYER_ID = 0;
protected static final int ENEMY_ID = 1;
protected static final int ITEM_ID = 2;
protected static final int ENTITY_SIZE = 64;
protected static final int ITEM_SIZE = 16;
protected boolean[] flags = new boolean[1];
public void update(){}
public void render(){
glPushMatrix();
glTranslatef(x,y,0);
spr.render();
glPopMatrix();
}
public float getX(){
return x;
}
public float getY(){
return y;
}
public float getSX(){
return spr.getSX();
}
public float getSY(){
return spr.getSY();
}
public int getType(){
return type;
}
public boolean getRemove(){
return flags[0];
}
public void remove(){
flags[0] = true;
}
/*protected void setTexture(String key) throws IOException{
spr.setSpriteTexture(key);
}*/
public Texture getTexture(){
return spr.getTexture();
}
protected void init(float x, float y, float sx, float sy,Texture texture,int type) throws IOException{
this.x = x;
this.y = y;
this.type = type;
this.spr = new Sprite(sx,sy,texture);
}
}
The Player Class:
package geniushour.gameobject.entity;
import java.io.IOException;
import org.lwjgl.input.Keyboard;
import org.newdawn.slick.opengl.Texture;
import geniushour.game.Inventory;
import geniushour.game.Stats;
import geniushour.gameobject.GameObject;
import geniushour.gameobject.item.Item;
public class Player extends GameObject {
private Stats stats;
private Inventory inv;
private int stamina;
private int maxStamina = 150;
public Player(float x, float y, Texture texture) throws IOException{
init(x,y,ENTITY_SIZE,ENTITY_SIZE,texture,PLAYER_ID);
stats = new Stats(0,true);
inv = new Inventory(9);
stamina = maxStamina;
}
public void update(){
if(Keyboard.isKeyDown(Keyboard.KEY_LSHIFT) && stamina > 0){
stamina--;
}
else if(!Keyboard.isKeyDown(Keyboard.KEY_LSHIFT)){
stamina++;
if(stamina > maxStamina){
stamina = maxStamina;
}
}
}
public void getInput(){
if(Keyboard.isKeyDown(Keyboard.KEY_W)){
if(Keyboard.isKeyDown(Keyboard.KEY_LSHIFT) && stamina > 0){
move(0,1.5);
}
else{
move(0,1);
}
}
if(Keyboard.isKeyDown(Keyboard.KEY_S)){
if(Keyboard.isKeyDown(Keyboard.KEY_LSHIFT) && stamina > 0){
move(0,-1.5);
}
else{
move(0,-1);
}
}
if(Keyboard.isKeyDown(Keyboard.KEY_A)){
if(Keyboard.isKeyDown(Keyboard.KEY_LSHIFT) && stamina != 0){
move(-1.5,0);
}
else{
move(-1,0);
}
}
if(Keyboard.isKeyDown(Keyboard.KEY_D)){
if(Keyboard.isKeyDown(Keyboard.KEY_LSHIFT) && stamina != 0){
move(1.5,0);
}
else{
move(1,0);
}
}
}
public Texture getTexture(){
return getTexture();
}
private void move(double magX, double magY){
x += getSpeed() * magX;
y += getSpeed() * magY;
}
private int getSpeed(){
return stats.getPlayerSpeed();
}
#SuppressWarnings("unused")
private int getLevel(){
return stats.getLevel();
}
#SuppressWarnings("unused")
private int getXP(){
return stats.getXP();
}
public int getMaxHP(){
return stats.getMaxHP();
}
public int getCurrentHealth(){
return stats.getCurrentHealth();
}
public int getStrength(){
return stats.getStrength();
}
public int getMagic(){
return stats.getMagic();
}
public void addXP(int amt){
stats.addXP(amt);
}
public void addHP(int amt){
stats.addHP(amt);
}
public void addItem(Item item){
inv.add(item);
}
}
The Game Class:
package geniushour.game;
import java.io.IOException;
import java.util.ArrayList;
import org.newdawn.slick.opengl.Texture;
import geniushour.gameobject.*;
import geniushour.gameobject.entity.*;
import geniushour.gameobject.item.*;
public class Game {
private ArrayList<GameObject> obj;
private ArrayList<GameObject> remove;
private Player p; private Texture pTexture;
private ItemEssence essence; private Texture eTexture;
private EnemyBlob blob; private Texture bTexture;
public Game() throws IOException{
obj = new ArrayList<GameObject>();
remove = new ArrayList<GameObject>();
setTexture(pTexture,"raptor");
setTexture(eTexture,"essence");
setTexture(bTexture,"blob");
p = new Player(250,250,pTexture);
essence = new ItemEssence(400, 400, eTexture, p);
blob = new EnemyBlob(300,500,bTexture, 1);
obj.add(essence);
obj.add(p);
obj.add(blob);
}
public void getInput(){
p.getInput();
}
public void update(){
for(GameObject go : obj){
if(!go.getRemove()){
go.update();
}
else{
remove.add(go);
}
}
for(GameObject go : remove){
obj.remove(go);
}
}
public void render(){
for(GameObject go : obj){
go.render();
}
}
public ArrayList<GameObject> sphereCollide(float x, float y, float radius){
ArrayList<GameObject> res = new ArrayList<GameObject>();
for(GameObject go : obj){
if(Util.dist(go.getX(),x,go.getY(),y) < radius){
res.add(go);
}
}
return res;
}
private void setTexture(Texture texture, String key){
}
}
The error occurs in the Sprite class, the first block of code.