I'm playing around with Slick2D and I'm running into a problem when trying to move a simple rectangle with the cursor keys.
Functionality wise, the code works. However, if you keep one of the cursor keys pressed, every now and then there is a little hick-up in the movement wen looking at the screen.
Can anyone suggest a code improvement to make the rectangle move smoothly?
Here is the test code I used:
public class SlickGame extends BasicGame {
// ==================================================================================
// Fields
// ==================================================================================
private Rectangle mPlayer;
// ==================================================================================
// Constructor
// ==================================================================================
public SlickGame() {
super("SlickGame");
}
// ===========================================================
// Methods for/from SuperClass/Interfaces
// ===========================================================
#Override
public void init(GameContainer pGameContainer) throws SlickException {
// create the player centered on the screen
mPlayer = new Rectangle(pGameContainer.getWidth()/2 - 20, pGameContainer.getHeight()/2 - 20, 40, 40);
}
#Override
public void update(GameContainer pGameContainer, int pDelta) throws SlickException {
Input input = pGameContainer.getInput();
int speed = 200;
float distance = speed * ((float)pDelta/1000);
if (input.isKeyDown(Input.KEY_LEFT)) {
mPlayer.setX(mPlayer.getX() - distance);
}
if (input.isKeyDown(Input.KEY_RIGHT)) {
mPlayer.setX(mPlayer.getX() + distance);
}
if (input.isKeyDown(Input.KEY_UP)) {
mPlayer.setY(mPlayer.getY() - distance);
}
if (input.isKeyDown(Input.KEY_DOWN)) {
mPlayer.setY(mPlayer.getY() + distance);
}
}
#Override
public void render(GameContainer pGameContainer, Graphics pGraphics) throws SlickException {
pGraphics.fill(mPlayer);
}
// ==================================================================================
// Methods
// ==================================================================================
public static void main(String[] args) {
try {
// create the game's container app
AppGameContainer container = new AppGameContainer(new SlickGame());
// adjust the resolution and disable fullscreen
container.setDisplayMode(800, 600, false);
// specify desired FPS
container.setTargetFrameRate(60);
// start the game
container.start();
}
catch (SlickException e ) {
e.printStackTrace();
}
}
}
Thanks, naughty_hacker. Adding container.setVSync(true); did the trick.
Related
I'm struggling to set up monster on the map, but all I get is placing it on the camera coordinate. I tried to use Tiled and finally I set up monster where I wanted, but I don't know how to move this monster.
Link to game map, the dragon in right bottom corner is from Enemy class, and the goblin is from Bot class
Here same code from Enemy class
public Enemy() {
img = new Texture(Gdx.files.internal(path));
sprite = new Sprite(img);
batch = new SpriteBatch();
position = new Vector2();
}
public void update(float delta) {
batch.begin();
batch.draw(img, position.x, position.y);
batch.end();
}
And the Bot class, where I get monster from Tiled
public Bot(TextureMapObjectRenderer tiledMapRenderer, String name) {
this.tiledMapRenderer = tiledMapRenderer;
try {
monsterLayer = tiledMapRenderer.getMap().getLayers().get("monster");
monsterObjects = monsterLayer.getObjects();
monster = monsterObjects.get(name);
} catch (Exception ex) {
}
}
public void update(float delta) {
tiledMapRenderer.renderObject(monster);
}
I use TextureMapObject to get X and Y position of the enemy/monster. Also I create method to render MapObject.
public void renderMonster(MapObject object) {
if (object instanceof TextureMapObject) {
TextureMapObject textureMonster = (TextureMapObject) object;
textureMonsters.add(textureMonster);
batch.begin();
batch.draw(textureMonster.getTextureRegion(), textureMonster.getX(), textureMonster.getY());
batch.end();
// move the monster
textureMonster.setX(randomMove(-1, 1).x + textureMonster.getX());
textureMonster.setY(randomMove(-1, 1).y + textureMonster.getY());
}
}
I know that this method is not prefect, but it works.
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?
Can anyone shed some light on this behaivor of the viewport or ortographic camera? I expect a rectangular viewport to be drawn but what I get instead is everything squeezed up in a square frame. I uploaded a picture to show you what's going on. The center of the green circle is being drawn on to the point(100,100) so clearly , it looks too disproportioned. The size of the red square is supposed to be 400x400 but judging by the way it looks, it isn't . The aspect ratio is completely off. I don't know what's causing this issue. Ignore the little mario in the center. that's being rendered by another camera soewhere else.
Does any one know what could be causing it?
/**
* Created by Omer on 11/24/2015.
*/
public class Play extends GameStateBase {
public static final int CAMERA_TYPE_SCREEN = 0;
public static final int CAMERA_TYPE_MAP = 1;
private Viewport SCREEN_VIEW;
private Viewport MAP_VIEW;
private OrthographicCamera SCREEN_CAM;
private OrthographicCamera MAP_CAM;
AssaultTrooper assaultTrooper;
GamePad GAME_PAD;
public Play(GameStateManager _gameStateManager) {
super(_gameStateManager);
SCREEN_CAM = new OrthographicCamera();
SCREEN_VIEW = new FitViewport(GameGraphics.VIRTUAL_WIDTH,GameGraphics.VIRTUAL_HEIGHT,SCREEN_CAM);
SCREEN_VIEW.apply();
SCREEN_CAM.translate(GameGraphics.VIRTUAL_WIDTH/2,GameGraphics.VIRTUAL_HEIGHT/2);
SCREEN_CAM.update();
MAP_CAM = new OrthographicCamera();
MAP_VIEW = new FitViewport(GameGraphics.VIRTUAL_HEIGHT,GameGraphics.VIRTUAL_HEIGHT,MAP_CAM);
MAP_VIEW.apply();
MAP_CAM.translate(GameGraphics.VIRTUAL_HEIGHT/2,GameGraphics.VIRTUAL_HEIGHT/2);
MAP_CAM.update();
RENDER_STATE.addCamera(CAMERA_TYPE_SCREEN,SCREEN_CAM);
RENDER_STATE.addCamera(CAMERA_TYPE_MAP,MAP_CAM);
GAME_PAD = new GamePad();
RenderStateManager.changeGameRenderState(RENDER_STATE);
GAME_PAD.setCameraType(CAMERA_TYPE_SCREEN);
GAME_PAD.addToRenderState();
assaultTrooper = new AssaultTrooper(GameSettings.TEAM_BLUE,new Location(200,200));
assaultTrooper.setCameraType(CAMERA_TYPE_MAP);
assaultTrooper.addToRenderState();
}
#Override
public void render(SpriteBatch _spriteBatch) {
try {
RenderStateManager.RENDERING_STATE.render(_spriteBatch);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
#Override
public void handleInput() {
}
#Override
public void update(float deltaTime) {
}
#Override
public void dispose() {
}
#Override
public void reSize(int _width, int _height) {
SCREEN_VIEW.update(_width,_height);
MAP_VIEW.update(_width,_height);
}
}
private ConcurrentHashMap<Long,Location> locations;
private ConcurrentHashMap<Long,Sprite> sprites;
private ConcurrentHashMap<Integer,OrthographicCamera> cameras;
private ConcurrentHashMap<Integer,List<Long>> cameraMapping;
public void render(SpriteBatch _spriteBatch) throws InterruptedException {
synchronized (this) {
for (int key : cameras.keySet()) {
_spriteBatch.setProjectionMatrix(cameras.get(key).combined);
_spriteBatch.begin();
if (cameraMapping.get(key) == null) {
_spriteBatch.end();
continue;
}
for (long MAPPER : cameraMapping.get(key)) {
sprites.get(MAPPER).draw(_spriteBatch);
}
_spriteBatch.end();
}
}
}
I am trying to start my game from a Main Menu class that implements NiftyGUI. I am using OpenGL (LWJGL) and Java. The problem is that I am never able to get the main menu to disappear and then start the game class, which is World.java.
The following is what I would usually do when I have no main menu.
package com.dev.voxy;
import com.dev.voxy.utilities.GLScreen;
import com.dev.voxy.world.World;
public class Main extends GLScreen {
public static int WIDTH = 1280;
public static int HEIGHT = 720;
private World world;
public static void main(String[] args) {
Main main = new Main();
main.GLScreen(WIDTH, HEIGHT, false, 60, "Voxy");
}
#Override
public void init() {
world = new World();
}
#Override
public void update() {
world.update();
}
#Override
public void dispose() {
world.dispose();
}
That is my main class and extends GLScreen
import org.lwjgl.LWJGLException;
import org.lwjgl.Sys;
import org.lwjgl.opengl.Display;
import org.lwjgl.opengl.DisplayMode;
import static org.lwjgl.opengl.GL11.*;
import static org.lwjgl.util.glu.GLU.gluPerspective;
public abstract class GLScreen {
protected static int SCREEN_WIDTH;
protected static int SCREEN_HEIGHT;
protected boolean FULL_SCREEN;
protected static int FPS = 60;
protected static String SCREEN_TITLE;
private static long lastFPS;
private static int lfps;
public static int fps;
public void GLScreen(int width, int height, boolean fullscreen, int sync, String title) {
this.SCREEN_HEIGHT = height;
this.SCREEN_WIDTH = width;
this.FULL_SCREEN = fullscreen;
this.FPS = sync;
this.SCREEN_TITLE = title;
InitScreen();
}
public void InitScreen() {
createWindow();
InitGL();
init();
Run();
}
void createWindow() {
try {
Display.setFullscreen(FULL_SCREEN);
Display.setTitle(SCREEN_TITLE);
DisplayMode displayMode = new DisplayMode(SCREEN_WIDTH, SCREEN_HEIGHT);
Display.setDisplayMode(displayMode);
Display.create();
} catch (LWJGLException e) {
e.printStackTrace();
}
}
void InitGL(){
glEnable(GL_TEXTURE_2D);
glShadeModel(GL_SMOOTH);
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
glClearDepth(1.0);
glDepthFunc(GL_LEQUAL);
glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
glViewport(0, 0, Display.getWidth(), Display.getHeight());
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(67.0f, SCREEN_WIDTH / SCREEN_HEIGHT, 0.001f, 1000f); //TODO watch coding universe video
glMatrixMode(GL_MODELVIEW);
glEnable(GL_DEPTH_TEST);
lastFPS = getTime();
}
public abstract void init();
public abstract void update();
public static int getFPS() {
int cfps;
if (getTime() - lastFPS > 1000 && lfps != fps) {
lfps = fps;
fps = 0; //reset the FPS counter
lastFPS += 1000; //add one second
cfps = fps;
} else {
cfps = lfps;
}
fps++;
return cfps;
}
public static long getTime() {
return (Sys.getTime() * 1000) / Sys.getTimerResolution();
}
void Run(){
while(!Display.isCloseRequested()){
try{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glClearColor(0, 0, 0f, 0f);
glLoadIdentity();
update();
Display.update();
Display.sync(FPS);
} catch (Exception e){
e.printStackTrace();
}
}
dispose();
destroy();
}
public abstract void dispose();
public void destroy() {
Display.destroy();
System.exit(0);
}
}
And finally my World Class is below.
import com.dev.voxy.Main;
import org.lwjgl.opengl.Display;
import static org.lwjgl.opengl.GL11.glColor3f;
import static org.lwjgl.opengl.GL11.glLoadIdentity;
public class World extends WorldManager {
private Chunk chunk;
public World() {
super(Main.WIDTH, Main.HEIGHT);
init();
}
#Override
public void init() {
chunk = new Chunk(0, 0, 0);
setRenderStats(true);
}
public void update() {
input();
render();
}
public void render() {
render3D();
Translate();
chunk.render();
glLoadIdentity();
if (isRenderStats()) {
render2D();
glColor3f(1, 1, 1);
renderStats();
}
}
#Override
public void dispose() {
chunk.dispose();
Display.destroy();
System.exit(0);
}
}
The problem is that when I try and incorporate my Menu into this it never works. First I tried GameStates so that whenever the game state is GAME the nifty should no longer render but this causes the Window to close because nifty no longer keeps it open, so then I tried to have the loop be outside the MainMenu Class but that also did not work because I kept running into static/non-static errors which I could not figure out. Then my last idea was why not try and put the gameloop inside the MainMenu Class but try to stop the nifty render while I try to start the game, but that left elements of the nifty on the screen and the rest was blank and the World class did not render. The following are my current Main, MainMenu, GLScreen and MyScreenController and MainMenu.xml files The MyscreenController controls what happens when the respective buttons are pressed and the MainMenu.xml is the nifty xml file that lays out everything.
All relevant files and classes may be found at the following link, they are the current ones where I am trying to get the main menu working. The classes shown above show what I did to get ONLY the game part working in the first place, without a menu.
LINK
To sum up, I can get my game working when there is not main menu and I can get my main menu working when there is no game, I have tried as many things I can think of but after 3 days I'm simply lost and would like any suggestion/recommendation or idea. I think I just can't figure out how to manage game states and the game loop when there is a main menu and a game, I was thinking maybe if there was a way to stop nifty completely then clear the screen then set OpenGL to 3D I can get my game rendered, this is what I was trying to do near the end but could not figure it out.
Thank you.
I've Googled a lot and could not find the answer to this. I know how to load an image, I need to load images that aren't 256 by 256 or a direct power of 2.
Like how could I load an image that's 128 by 384 or something like that.
What I'm using now:
Load an image:
public static Texture cow = loadTexture("res/cow.png");
private static Texture loadTexture(String file){
try {
return TextureLoader.getTexture("JPG", new FileInputStream(new File(file)));
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
Now to draw it on a 3D poly face:
txt.bind();
GL11.glBegin(GL11.GL_QUADS);
{
//GL11.glColor3d(lightLevel, lightLevel, lightLevel);
GL11.glColor3d(l, l, l);
GL11.glTexCoord2f(0,0); GL11.glVertex3f(x1,y1, z1);
GL11.glTexCoord2f(1,0); GL11.glVertex3f(x1+(x2-x1), y1,z1);
GL11.glTexCoord2f(1,1); GL11.glVertex3f(x1+(x2-x1), y1+(y2-y1), z1+(z2-z1));
GL11.glTexCoord2f(0,1); GL11.glVertex3f(x1,y1+(y2-y1), z1+(z2-z1));
}
GL11.glEnd();
Now that works perfectly, I just need to load images that aren't a power of 2.
you could use slick2d, it is way easier to use and works with lwjgl! All you have to do is:
Image title = null;
public static void main(String[] args) {
}
#Override
public void init(GameContainer Gc, StateBasedGame Sbg)
throws SlickException {
/**
* Images
*/
title = new Image("gfx/main_menu/title/new_title.png");
}
#Override
public void render(GameContainer Gc, StateBasedGame Sbg, Graphics G)
throws SlickException {
/**
* Background
*/
G.setColor(Color.white);
G.fillRect(0, 0, w*s, h*s);
/**
* Images
*/
title.draw(titleY*s,titleX*s);
}