I'm currently developing a simple multiplayer game with Slick2D in Java. It's going to be a little more complex with the menu structure because I need several textfields to get the information which server address to connect, how many players are allowed to play, nickname and so on.
I reproduced my problem in 3 classes: The main class (ExampleGame) extends from StateBasedGame, Play and Menu from BasicGameState.
The classes Play and Menu have each one textfield and one button. My problem is I can only type in one of these classes into a textfield. The other textfield doesn't show any cursor responses when you click into the textfield.
This is the main class ExampleGame:
public class ExampleGame extends StateBasedGame {
public static final int MAIN_MENU_STATE = 0;
public static final int GAME_PLAY_STATE = 1;
public ExampleGame(String name) {
super(name);
this.addState(new Menu(MAIN_MENU_STATE));
this.addState(new Play(GAME_PLAY_STATE));
this.enterState(MAIN_MENU_STATE);
}
/**
* #param args
*/
public static void main(String[] args) {
AppGameContainer appgc;
try{
appgc = new AppGameContainer(new ExampleGame("ExampleGame"));
appgc.setDisplayMode(640, 360, false);
appgc.setTargetFrameRate(50);
appgc.start();
}catch(SlickException e){
e.printStackTrace();
}
}
#Override
public void initStatesList(GameContainer arg0) throws SlickException {
// TODO Auto-generated method stub
this.getState(GAME_PLAY_STATE);
this.getState(MAIN_MENU_STATE);
System.out.println(this.getStateCount() + ", " + this.getCurrentStateID());
this.enterState(MAIN_MENU_STATE);
}
}
ExampleGame automatically calls the MainMenu (Menu.java):
public class Menu extends BasicGameState {
private int stateID;
private Image background;
private UnicodeFont font;
private TextField textfield;
private Image createGameOption;
private int menuX = 50;
private int menuY = 250;
public Menu(int stateID) {
this.stateID = stateID;
}
#Override
public void init(GameContainer arg0, StateBasedGame arg1) throws SlickException {
System.out.println("StateID: " + arg1.getState(this.getID()) + " , State: " + arg1.getCurrentState());
background = new Image("images/background_1024x640_v1.jpg");
createGameOption = new Image("images/btn_CreateGame_for_1024x640_v1.png");
textfield = new TextField(arg0, arg0.getDefaultFont(), 100, 100, 200, 30);
}
#Override
public void render(GameContainer arg0, StateBasedGame arg1, Graphics arg2) throws SlickException {
// TODO Auto-generated method stub
background.draw(0, 0);
createGameOption.draw(menuX, menuY);
textfield.render(arg0, arg2);
}
#Override
public void update(GameContainer arg0, StateBasedGame arg1, int arg2) throws SlickException {
Input input = arg0.getInput();
int mouseX = input.getMouseX();
int mouseY = input.getMouseY();
// if mouse is over a button
if ((mouseX >= menuX && mouseX <= menuX + createGameOption.getWidth()) && (mouseY >= menuY && mouseY <= menuY + createGameOption.getHeight())) {
if (input.isMouseButtonDown(Input.MOUSE_LEFT_BUTTON)) {
// fx.play();
arg1.enterState(ExampleGame.GAME_PLAY_STATE);
}
}
}
#Override
public int getID() {
// TODO Auto-generated method stub
return stateID;
}
}
Here I can write in the textfield. So far so good. By clicking on the button I call the next page (Play.java):
public class Play extends BasicGameState {
private int stateID;
private Image background;
private UnicodeFont font;
private TextField textfield;
private Image createGameOption;
private int menuX = 350;
private int menuY = 250;
public Play (int stateID) {
this.stateID = stateID;
}
#Override
public void init(GameContainer arg0, StateBasedGame arg1) throws SlickException {
System.out.println("StateID: " + arg1.getCurrentStateID() + " , State: " + arg1.getCurrentState());
arg1.inputStarted();
background = new Image("images/background_1024x640_v1.jpg");
createGameOption = new Image("images/btn_CreateGame_for_1024x640_v1.png");
textfield = new TextField(arg0, arg0.getDefaultFont(), 150, 100, 200, 30);
}
#Override
public void render(GameContainer arg0, StateBasedGame arg1, Graphics arg2) throws SlickException {
// TODO Auto-generated method stub
background.draw(0,0);
createGameOption.draw(menuX, menuY);
textfield.render(arg0, arg2);
}
#Override
public void update(GameContainer arg0, StateBasedGame arg1, int arg2) throws SlickException {
Input input = arg0.getInput();
int mouseX = input.getMouseX();
int mouseY = input.getMouseY();
if ((mouseX >= menuX && mouseX <= menuX + createGameOption.getWidth())
&& (mouseY >= menuY && mouseY <= menuY + createGameOption.getHeight())) {
if (input.isMouseButtonDown(Input.MOUSE_LEFT_BUTTON)) {
arg1.enterState(ExampleGame.MAIN_MENU_STATE);
}
}
}
#Override
public int getID() {
// TODO Auto-generated method stub
return stateID;
}
}
The class Play has almost the same code as Menu but it seems that the textfield in Play doesn't response to the mouse and key. It seems to be inactive because you can't see any changes. But that's actually not true. If I click in the textfield, type something and go back to the Menu by clicking the button, you can see the text you typed in. It seems that both textfields (the one from Menu and from Play) are connected to somehow. But I have no idea where the problem is from.
Has anyone any suggestions how I can fix that?
Thanks in advance!
Slick TextField not working
This is the exact answer you're looking for that I answered not too long ago. This user had the same problem as you, and resolved it by following my wiki link by example of how to use StateBasedGame's
Related
I am designing a picture lab project for school and I can't figure out how to modify the rgb of pixels. My project is an eye test game where players choose the one color that is different from the rest. Should I modify the pixels of the background or of a blank photo? Also, how do I implement mouseClickedAction (given method that runs when mouse is clicked)?
Here's some bare stuff I have so far:
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.Point;
import java.awt.image.ImageObserver;
import java.util.ArrayList;
public class EagleEye extends FlexiblePictureExplorer {
public static Picture background = new Picture(1003,1003);
//settings
private int gameDimensions = 4;
private int difficulty = 30;
private final int statsHeight = 80;
public EagleEye(DigitalPicture Picture) {
super(background);
setTitle("Eagle Eye");
int xGrid = gameDimensions;
int yGrid = gameDimensions;
int r1 = (int)(Math.random() * gameDimensions + 1);
int r2 = (int)(Math.random() * gameDimensions + 1);
colorSetter(xGrid,yGrid);
}
private void colorSetter(int x,int y) {
for (int i=0;i<x;i++) {
for (int j=0;j<y;j++) {
fillBox(i,j);
}
}
}
private void fillBox(int x, int y) {
int r = (int)(Math.random() * 255 + 1);
int g = (int)(Math.random() * 255 + 1);
int b = (int)(Math.random() * 255 + 1);
int x1;
int x2;
if (x==0) {
x1 = 0;
x2 = 250;
}
else if (x==1) {
x1 = 252;
x2 = 501;
}
else if (x==2) {
x1 = 503;
x2 = 752;
}
else {
x1 = 754;
x2 = 1003;
}
int y1;
int y2;
if (y==0) {
y1 = 0;
y2 = 250;
}
else if (y==1) {
y1 = 252;
y2 = 501;
}
else if (y==2) {
y1 = 503;
y2 = 752;
}
else {
y1 = 754;
y2 = 1003;
}
int rgb = calculateColors(r,g,b);
for (int i=x1;i<=x2;i++) {
for (int j=y1;j<=y2;j++) {
background.setBasicPixel(x1,y1,rgb);
}
}
setImage(background);
}
private int calculateColors(int r, int g, int b) {
int r1 = r * 65536;
int g1 = g * 256;
int b1 = b;
return r1 + g1 + b1;
}
private void drawStats(Picture img){
Picture statsImg = new Picture(statsHeight, imageWidth);
Graphics g = statsImg.getGraphics();
g.setFont(new Font("Times New Roman", Font.PLAIN, 16));
g.setColor(Color.blue);
}
private void updateImage() {
}
public void mouseClickedAction(DigitalPicture pict, Pixel pix) {
}
private void endGame() {
}
public boolean imageUpdate(Image arg0, int arg1, int arg2, int arg3, int arg4, int arg5) {
// TODO Auto-generated method stub
return false;
}
public static void main(String[] args) {
Picture white = new Picture(100,100);
EagleEye game = new EagleEye(white);
}
}
I think the easiest way that you will find for drawing and graphics will not be drawing to an image, but instead drawing directly to the JPanel. If you have a class that extends JPanel, you can implement
public void paintComponent(Graphics g) {
//Code to draw whatever you like, e.g.
g.setColor(new Color(255, 255, 255));
g.drawRect(0, 0, width, height);
}
With this, you will not have to worry about handling images,
If you would still like to use images, you can use the BufferedImage, which has great docs explaining how to use it:
https://docs.oracle.com/javase/tutorial/2d/images/drawonimage.html
(You will still need to display these images, most likely using the paintComponent method above anyways, and if you want to draw in a loop, you will have to put that loop on another thread, be aware)
As for the mouseClicked, you will need to implement a MouseListener, which is quite simple:
Create a MouseListener object in your class, you will have to implement a number of methods inside it, most of which will likely go unused.
Somewhere in your code (probably the constructor) you will need to add the MouseListener to whatever component you want to wait for the clicks (probably the panel you are drawing on)
When that component is clicked on, the mouseClicked method will be called and from there you can do whatever you need to, like calling the other methods you have there to handle mouse clicks.
The MouseEvent object in the listener has all the useful information yu will need, like it's position (relative to the component you added the listener to)
public class YourClass {
public YourClass() {
this.addMouseListener(ml);
}
//code
private MouseListener ml = new MouseListener() {
#Override
public void mouseClicked(MouseEvent arg0) {
// TODO Auto-generated method stub
System.out.println(arg0.getX() + ", " + arg0.getY());
}
#Override
public void mouseEntered(MouseEvent arg0) {
// TODO Auto-generated method stub
}
#Override
public void mouseExited(MouseEvent arg0) {
// TODO Auto-generated method stub
}
#Override
public void mousePressed(MouseEvent arg0) {
// TODO Auto-generated method stub
}
#Override
public void mouseReleased(MouseEvent arg0) {
// TODO Auto-generated method stub
}
}
}
I am trying to make a message based collision system for a game test, where all objects are stored in an ArrayList that is iterated through and all objects are checked against all other objects. If two objects collide a Message is sent to both of them and currently it does a sysout (print) when this happens. My code so far is below, I have included the classes I think are relevant but if another class is involved I can post that as well. (I am using Slick2D and LWJGL)
public class MyGame extends BasicGame {
private ArrayList<GameObject> objects = new ArrayList<GameObject>();
MessageQueue messageQueue = new MessageQueue();
CollisionSystem collisionSystem = new CollisionSystem(objects, messageQueue);
public MyGame() {
super("My Game");
}
public static void main(String[] arguments) {
// Start up the game window
try {
AppGameContainer app = new AppGameContainer(new MyGame());
app.setDisplayMode(500, 400, false);
app.start();
app.setVSync(false);
app.setTargetFrameRate(60);
} catch (SlickException e) {
e.printStackTrace();
}
}
#Override
public void init(GameContainer container) throws SlickException {
Image img = new Image("myimage.png", false, Image.FILTER_NEAREST);
objects.add(new ObjSpriteObject(20, 20, img));
objects.add(new ObjSpriteObject(15, 20, img));
}
#Override
public void update(GameContainer container, int delta) throws SlickException {
collisionSystem.update();
messageQueue.update();
for (GameObject object : objects) {
object.update(container, delta);
}
}
#Override
public void render(GameContainer container, Graphics g) throws SlickException {
g.scale(3, 3);
for (GameObject object : objects) {
object.render(container, g);
}
}
}
MessageQueue
public class MessageQueue {
public ArrayList<Message> messages;
public MessageQueue() {
messages = new ArrayList<Message>();
}
public void update() {
while (messages.iterator().hasNext()) {
Message m = messages.iterator().next();
process(m);
}
}
private void process(Message m) {
switch (m.getType()) {
case 'p':
System.out.println("MESSAGE: " + m.getData());
break;
case 'c':
m.getReciever().processMessage(m);
}
}
}
ObjSpriteObject
public class ObjSpriteObject extends GameObject {
private Image sprite;
protected float vspeed = 0f;
protected float hspeed = 0f;
public boolean hasBB = true;
public ObjSpriteObject(int x, int y, Image sprite) {
super(x, y);
this.sprite = sprite;
this.boundingBox = new BoundingBox(this, x, y, 16, 16);
}
#Override
public void update(GameContainer container, int delta) {
super.update(container, delta);
}
#Override
public void render(GameContainer container, Graphics g) {
sprite.draw(x, y);
g.setColor(Color.red);
g.draw(getBoundingBox());
}
#Override
public void processMessage(Message m) {
if (m.getType() == 'c') {
delete = true;
}
}
}
CollisionSystem
public class CollisionSystem {
private ArrayList<GameObject> objects;
private MessageQueue messageQueue;
public CollisionSystem(ArrayList<GameObject> objects, MessageQueue messageQueue) {
this.objects = objects;
this.messageQueue = messageQueue;
}
public void update() {
// Iterate through each BB with each BB
for (int i = 0; i < objects.size(); i++) {
// If object has bounding box
GameObject ob1 = objects.get(i);
if (ob1.getBoundingBox() != null) {
for (int k = 0; k < objects.size(); k++) {
// If second object has bounding box
GameObject ob2 = objects.get(i);
if (ob2.getBoundingBox() != null) {
// Check both bounding boxes and send messages if they collide
BoundingBox bb1 = objects.get(i).getBoundingBox();
BoundingBox bb2 = objects.get(k).getBoundingBox();
// System.out.println(bb1 + " " + bb2);
if (bb1.collides(bb2) && bb1 != bb2) {
messageQueue.messages.add(new Message(bb1.getParent(), bb2.getParent(), 'p', "Collision!"));
}
}
}
}
}
}
}
When I run this code the game freezes. I feel like it has something to do with it running like a while loop that never exits, but I don't see why it would be doing that if the main game loop is making sure things run on a timer. Why is this code freezing the program?
These are the specific instruction but they are kind of confusing to me (are the instructions confusing/ambiguous or am I just not getting it?)
write a method public static void draw shooter(Graphics g, Color c);
call draw shooter using the shooter color as the last parameter in drawAll(?)
test the program you should see a red disk centered near the bottom of the screen(?)
import java.awt.*;
public class Project2{
public static final int PANEL_WIDTH = 300;
public static final int PANEL_HEIGHT = 300;
public static final int SLEEP_TIME = 50;
public static Color SHOOTER_COLOR = Color.RED;
public static Color BACKGROUND_COLOR = Color.WHITE;
public static final int SHOOTER_SIZE = 20; //diameter of the shooter
public static final int GUN_SIZE = 10; //length og the gun
public static final int SHOOTER_POSITION_Y = PANEL_HEIGHT - SHOOTER_SIZE;
public static final int SHOOTER_INITIAL_POSITION_X = 150;
int shooterPosition;
public static void initialize(){
int shooterPositionX = SHOOTER_INITIAL_POSITION_X;
}
public static void main(String[] args) {
DrawingPanel panel = new DrawingPanel(PANEL_WIDTH, PANEL_HEIGHT);
Graphics g = panel.getGraphics( );
initialize();
startGame(panel, g);
drawShooter(g, SHOOTER_COLOR);
}
public static void drawShooter(Graphics g, Color C){
g.setColor(Color);
g.fillOval(shooterPosition, SHOOTER_POSITION_Y, SHOOTER_SIZE, SHOOTER_SIZE);
}
public static void drawAll(Graphics g){
g.drawString("Project 2 by Jasmine Ramirez", 10, 15);
}
public static void startGame(DrawingPanel panel, Graphics g) {
for (int i = 0; i <= 10000; i++) {
panel.sleep(SLEEP_TIME);
drawAll(g);
}
}
}
this is my code I guessed that I needed to draw and color in a circle inside the method but I am getting errors with the g.setColor inside the method and I'm not sure what the second step means. Thanks just started learning to program.
Drawing Panel
import java.awt.*;
import java.awt.event.*;
import java.awt.image.*;
import javax.swing.*;
import javax.swing.event.*;
import java.util.ArrayList;
public class DrawingPanel implements ActionListener {
private static final String versionMessage =
"Drawing Panel version 1.1, January 25, 2015";
private static final int DELAY = 100; // delay between repaints in millis
private static final boolean PRETTY = false; // true to anti-alias
private static boolean showStatus = false;
private static final int MAX_KEY_BUF_SIZE = 10;
private int width, height; // dimensions of window frame
private JFrame frame; // overall window frame
private JPanel panel; // overall drawing surface
private BufferedImage image; // remembers drawing commands
private Graphics2D g2; // graphics context for painting
private JLabel statusBar; // status bar showing mouse position
private volatile MouseEvent click; // stores the last mouse click
private volatile boolean pressed; // true if the mouse is pressed
private volatile MouseEvent move; // stores the position of the mouse
private ArrayList<KeyInfo> keys;
// construct a drawing panel of given width and height enclosed in a window
public DrawingPanel(int width, int height) {
this.width = width;
this.height = height;
keys = new ArrayList<KeyInfo>();
image = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
statusBar = new JLabel(" ");
statusBar.setBorder(BorderFactory.createLineBorder(Color.BLACK));
statusBar.setText(versionMessage);
panel = new JPanel(new FlowLayout(FlowLayout.CENTER, 0, 0));
panel.setBackground(Color.WHITE);
panel.setPreferredSize(new Dimension(width, height));
panel.add(new JLabel(new ImageIcon(image)));
click = null;
move = null;
pressed = false;
// listen to mouse movement
MouseInputAdapter listener = new MouseInputAdapter() {
public void mouseMoved(MouseEvent e) {
pressed = false;
move = e;
if (showStatus)
statusBar.setText("moved (" + e.getX() + ", " + e.getY() + ")");
}
public void mousePressed(MouseEvent e) {
pressed = true;
move = e;
if (showStatus)
statusBar.setText("pressed (" + e.getX() + ", " + e.getY() + ")");
}
public void mouseDragged(MouseEvent e) {
pressed = true;
move = e;
if (showStatus)
statusBar.setText("dragged (" + e.getX() + ", " + e.getY() + ")");
}
public void mouseReleased(MouseEvent e) {
click = e;
pressed = false;
if (showStatus)
statusBar.setText("released (" + e.getX() + ", " + e.getY() + ")");
}
public void mouseEntered(MouseEvent e) {
// System.out.println("mouse entered");
panel.requestFocus();
}
};
panel.addMouseListener(listener);
panel.addMouseMotionListener(listener);
new DrawingPanelKeyListener();
g2 = (Graphics2D)image.getGraphics();
g2.setColor(Color.BLACK);
if (PRETTY) {
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2.setStroke(new BasicStroke(1.1f));
}
frame = new JFrame("Drawing Panel");
frame.setResizable(false);
try {
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); // so that this works in an applet
} catch (Exception e) {}
frame.getContentPane().add(panel);
frame.getContentPane().add(statusBar, "South");
frame.pack();
frame.setVisible(true);
toFront();
frame.requestFocus();
// repaint timer so that the screen will update
new Timer(DELAY, this).start();
}
public void showMouseStatus(boolean f) {
showStatus = f;
}
public void addKeyListener(KeyListener listener) {
panel.addKeyListener(listener);
panel.requestFocus();
}
// used for an internal timer that keeps repainting
public void actionPerformed(ActionEvent e) {
panel.repaint();
}
// obtain the Graphics object to draw on the panel
public Graphics2D getGraphics() {
return g2;
}
// set the background color of the drawing panel
public void setBackground(Color c) {
panel.setBackground(c);
}
// show or hide the drawing panel on the screen
public void setVisible(boolean visible) {
frame.setVisible(visible);
}
// makes the program pause for the given amount of time,
// allowing for animation
public void sleep(int millis) {
panel.repaint();
try {
Thread.sleep(millis);
} catch (InterruptedException e) {}
}
// close the drawing panel
public void close() {
frame.dispose();
}
// makes drawing panel become the frontmost window on the screen
public void toFront() {
frame.toFront();
}
// return panel width
public int getWidth() {
return width;
}
// return panel height
public int getHeight() {
return height;
}
// return the X position of the mouse or -1
public int getMouseX() {
if (move == null) {
return -1;
} else {
return move.getX();
}
}
// return the Y position of the mouse or -1
public int getMouseY() {
if (move == null) {
return -1;
} else {
return move.getY();
}
}
// return the X position of the last click or -1
public int getClickX() {
if (click == null) {
return -1;
} else {
return click.getX();
}
}
// return the Y position of the last click or -1
public int getClickY() {
if (click == null) {
return -1;
} else {
return click.getY();
}
}
// return true if a mouse button is pressed
public boolean mousePressed() {
return pressed;
}
public synchronized int getKeyCode() {
if (keys.size() == 0)
return 0;
return keys.remove(0).keyCode;
}
public synchronized char getKeyChar() {
if (keys.size() == 0)
return 0;
return keys.remove(0).keyChar;
}
public synchronized int getKeysSize() {
return keys.size();
}
private synchronized void insertKeyData(char c, int code) {
keys.add(new KeyInfo(c,code));
if (keys.size() > MAX_KEY_BUF_SIZE) {
keys.remove(0);
// System.out.println("Dropped key");
}
}
private class KeyInfo {
public int keyCode;
public char keyChar;
public KeyInfo(char keyChar, int keyCode) {
this.keyCode = keyCode;
this.keyChar = keyChar;
}
}
private class DrawingPanelKeyListener implements KeyListener {
int repeatCount = 0;
public DrawingPanelKeyListener() {
panel.addKeyListener(this);
panel.requestFocus();
}
public void keyPressed(KeyEvent event) {
// System.out.println("key pressed");
repeatCount++;
if ((repeatCount == 1) || (getKeysSize() < 2))
insertKeyData(event.getKeyChar(),event.getKeyCode());
}
public void keyTyped(KeyEvent event) {
}
public void keyReleased(KeyEvent event) {
repeatCount = 0;
}
}
}
1st Error
In your drawShooter() method you do:
g.setColor(Color)
This is incorrect, since you need to pass an instance of the class Color not the class itself.
So instead use this:
g.setColor(C);
2nd Error
change the shooterPosition to static so that it can be accessed by a static method.
I assume that the method initialize() is also wrong because you are declaring a new shooterPosition int for no reason so do these changes:
int shooterPosition;
To:
public static int shooterPosition;
And
public static void initialize(){
int shooterPositionX = SHOOTER_INITIAL_POSITION_X;
}
To:
public static void initialize() {
shooterPosition = SHOOTER_INITIAL_POSITION_X;
}
3rd Error
In startGame() you are looping for 10000 times and each time you are waiting for a bit more than 1/20th of a second, which means that you will have to wait for almost 10 minutes until the red circle is drawn. So you have two options.
1st option: decrease the amount of iterations or even better remove the loop.
public static void startGame(DrawingPanel panel, Graphics g) {
for (int i = 0; i <= 10000; i++) {
panel.sleep(SLEEP_TIME);
drawAll(g);
}
}
To:
public static void startGame(DrawingPanel panel, Graphics g) {
for (int i = 0; i <= 1; i++) {
panel.sleep(SLEEP_TIME);
drawAll(g);
}
}
or
public static void startGame(DrawingPanel panel, Graphics g) {
panel.sleep(SLEEP_TIME);
drawAll(g);
}
2nd option: execute the drawShooter() method before the startGame() method or don't execute the startGame() at all.
startGame(panel, g); drawShooter(g, SHOOTER_COLOR);
To:
drawShooter(g, SHOOTER_COLOR);
startGame(panel, g);
or
drawShooter(g, SHOOTER_COLOR);
Didn't you ask this same question or something similar to it yesterday? And you're passing in the class name to g.setColor(Color) method and need to pass in the parameter which holds the object: g.setColor(C)
Your use of Graphics is not good, as you shouldn't use a Graphics obtained from a component via getGraphics(), but I'm guessing that it's because that's what your instructor told you to do. Same for use of a while (true) loop. Instead you should use a Swing Timer.
Like stated before g.setcolor(c) is required
check your error msgs since it allows you to gather that error and the shooterPosition error(its not public so cant be used inside a method)
I'm fairly new to Game development and to Libgdx as well. I'have looked around other similar topics in the forum but often I'm confused trying to understanding their content, therefore I decided to write down my problem here.
My problem is all about creating a minimap in the left bottom corner of the game screen showing the entire world with actors. I'd like to use the scene2d concept as much as possible.
For now I'm concentrating on the desktop version of the game.
I have a windows screen ... saying width = 800, height = 600
The top class of the game, MyOp0Game, is like this:
public class MyOp0Game extends Game {
MyScreen0 my_screen_0;
#Override
public void create() {
// allocate screen
my_screen_0 = new MyScreen0(this);
// set current screen
setScreen(my_screen_0);
}
#Override
public void render() {
super.render();
}
}
The MyScreen0 class is like this:
public class MyScreen0 implements Screen{
protected final Stage stage0;
protected final MyOp0Game game;
protected final MyActor0 actor0;
protected final MyActor0 actor1;
public MyScreen0(MyOp0Game game) {
// link screen to game
this.game = game;
// allocate stage; viewport size maps screen size
this.stage0 = new Stage( Gdx.graphics.getWidth(),Gdx.graphics.getHeight(), true );
// allocate actor0 and add to stage
this.actor0 = new MyActor0();
this.actor0.setPosition(0, 0);
this.stage0.addActor(this.actor0);
// allocate actor1 and add to stage, actor1 is placed next to actor0
this.actor1 = new MyActor0();
this.actor1.setPosition(1000, 0);
this.stage0.addActor(this.actor1);
}
#Override
public void render(float delta) {
// the following code clears the screen with the given RGB color (green)
Gdx.gl.glClearColor( 0f, 1f, 0f, 1f );
Gdx.gl.glClear( GL20.GL_COLOR_BUFFER_BIT );
// translate stage camera to go from actor0 to actor1
//this.stage0.getCamera().translate(1, 0, 0);
// draw stage -> draw actors
this.stage0.draw();
}
#Override
public void resize(int width, int height) {
// TODO Auto-generated method stub
}
#Override
public void show() {
// not required as no abstract screen for now
//super.show();
}
#Override
public void hide() {
// TODO Auto-generated method stub
}
#Override
public void pause() {
// TODO Auto-generated method stub
}
#Override
public void resume() {
// TODO Auto-generated method stub
}
#Override
public void dispose() {
this.stage0.dispose();
}
}
Finally the MyActor0 class is like this :
public class MyActor0 extends Actor {
SpriteBatch batch;
Texture texture;
public MyActor0() {
batch = new SpriteBatch();
texture = new Texture(Gdx.files.internal("data/libgdx.png"));
}
public void draw(SpriteBatch batch, float alpha){
batch.draw(texture,this.getX(),this.getY());
}
}
The stage viewport is of the same size as the window screen.
The actor texture is smaller than the viewport and therefore the first actor is visible and the second actor is not visible as it is next to the viewport.
I would like to insert in the bottom left a minimap showing the two actors (or equivalent markers).
I've tried several options but it never works, using two cameras and switching between them, two stages?
I think one fundamental question I have is : does the viewport always fills the windows screen?
I have seen your comment but i could not find a Minimap Actor in the libgdx documentations. But i found this link, which may help you out: Minimap. Tell me if this works (:
here is the first prototype of the minimap, it will be enough for the first step of the game dev.
public class Main {
public static void main(String[] args) {
LwjglApplicationConfiguration cfg = new LwjglApplicationConfiguration();
cfg.title = "my-op0-game";
cfg.useGL20 = false;
cfg.width = MyOp0Game.MY_APP_WINDOW_WIDTH;
cfg.height = MyOp0Game.MY_APP_WINDOW_HEIGHT;
new LwjglApplication(new MyOp0Game(), cfg);
}
}
public class MyOp0Game extends Game {
public static int MY_APP_WINDOW_WIDTH = 512;
public static int MY_APP_WINDOW_HEIGHT = 512;
public static int MY_WORLD_WIDTH = 2048;
public static int MY_WORLD_HEIGHT = 2048;
public static int MY_MINIMAP_WIDTH = 256;
public static int MY_MINIMAP_HEIGHT = 256;
public static int MY_MINIMAP_SCALE_FACTOR = MY_WORLD_WIDTH / MY_MINIMAP_WIDTH;
public static int MY_ORIGINAL_CAMERA_POSITION_X = MY_APP_WINDOW_WIDTH/2;
public static int MY_ORIGINAL_CAMERA_POSITION_Y = MY_APP_WINDOW_HEIGHT/2;
public static final String LOG = "MyOp0Game";
MyScreen0 my_screen_0;
#Override
public void create() {
// allocate screen
my_screen_0 = new MyScreen0(this);
// set current screen
setScreen(my_screen_0);
}
#Override
public void render() {
super.render();
}
}
public class MyScreen0 implements Screen{
protected final Stage stage0;
protected final MyOp0Game game;
protected final MyActor0 actor0_0;
protected final MyActor0 actor0_1;
protected final MyActor1 actor1_0;
public MyScreen0(MyOp0Game game) {
// link screen to game
this.game = game;
// allocate stage; viewport size maps game window size
this.stage0 = new Stage( Gdx.graphics.getWidth(),Gdx.graphics.getHeight(), true );
// allocate actor0_0 and add to stage
this.actor0_0 = new MyActor0();
this.actor0_0.setPosition(0, 0);
this.stage0.addActor(this.actor0_0);
// allocate actor0_1 and add to stage, actor1 is placed next to actor0
this.actor0_1 = new MyActor0();
this.actor0_1.setPosition(512, 256);
this.stage0.addActor(this.actor0_1);
// allocate actor1_0 and add to stage
this.actor1_0 = new MyActor1();
this.actor1_0.setPosition(0, MyOp0Game.MY_APP_WINDOW_HEIGHT - MyOp0Game.MY_MINIMAP_HEIGHT);
this.stage0.addActor(this.actor1_0);
}
#Override
public void render(float delta) {
int lvTranslateX = 0;
int lvTranslateY = 0;
// the following code clears the screen with the given RGB color (green)
Gdx.gl.glClearColor( 0f, 1f, 0f, 1f );
Gdx.gl.glClear( GL20.GL_COLOR_BUFFER_BIT );
/* check if mouse pressed */
if (Gdx.input.isTouched())
{
//Gdx.app.log( MyOp0Game.LOG, " mouse X = "+ Gdx.input.getX() +
// " Camera.x = " + this.stage0.getCamera().position.x +
// " mouse Y = "+ (MyOp0Game.MY_APP_WINDOW_HEIGHT - Gdx.input.getY()) +
// " Camera.y = " + this.stage0.getCamera().position.y);
if (Gdx.input.getX() >= MyOp0Game.MY_ORIGINAL_CAMERA_POSITION_X)
{
if (this.stage0.getCamera().position.x - MyOp0Game.MY_ORIGINAL_CAMERA_POSITION_X < MyOp0Game.MY_WORLD_WIDTH - MyOp0Game.MY_APP_WINDOW_WIDTH)
lvTranslateX = 3;
}
else if (Gdx.input.getX() < MyOp0Game.MY_ORIGINAL_CAMERA_POSITION_X)
{
if (this.stage0.getCamera().position.x - MyOp0Game.MY_ORIGINAL_CAMERA_POSITION_X > 0)
lvTranslateX = -3;
}
if (MyOp0Game.MY_APP_WINDOW_HEIGHT - Gdx.input.getY() >= MyOp0Game.MY_ORIGINAL_CAMERA_POSITION_Y)
{
if (this.stage0.getCamera().position.y - MyOp0Game.MY_ORIGINAL_CAMERA_POSITION_Y < MyOp0Game.MY_WORLD_HEIGHT - MyOp0Game.MY_APP_WINDOW_HEIGHT)
lvTranslateY = 3;
}
else if (MyOp0Game.MY_APP_WINDOW_HEIGHT - Gdx.input.getY() < MyOp0Game.MY_ORIGINAL_CAMERA_POSITION_Y)
{
if (this.stage0.getCamera().position.y - MyOp0Game.MY_ORIGINAL_CAMERA_POSITION_Y > 0)
lvTranslateY = -3;
}
if (lvTranslateX != 0 || lvTranslateY != 0)
{
// translate stage camera to go from actor0 to actor1
this.stage0.getCamera().translate(lvTranslateX, lvTranslateY, 0);
// update actor1_0 (minimap) location to move with camera
this.actor1_0.translate(lvTranslateX,lvTranslateY);
}
};
// draw stage -> draw actors
this.stage0.draw();
}
#Override
public void resize(int width, int height) {
// TODO Auto-generated method stub
}
#Override
public void show() {
// not required as no abstract screen for now
//super.show();
}
#Override
public void hide() {
// TODO Auto-generated method stub
}
#Override
public void pause() {
// TODO Auto-generated method stub
}
#Override
public void resume() {
// TODO Auto-generated method stub
}
#Override
public void dispose() {
this.stage0.dispose();
}
}
public class MyActor0 extends Actor {
SpriteBatch batch;
public Texture texture;
public MyActor0() {
batch = new SpriteBatch();
texture = new Texture(Gdx.files.internal("data/libgdx_256_256.png"));
}
public void draw(SpriteBatch batch, float alpha){
batch.draw(texture,this.getX(),this.getY());
}
}
public class MyActor1 extends Actor {
SpriteBatch batch;
Texture texture;
Texture blackMarkerTexture;
Texture yelloCameraMinimapTexture;
public MyActor1() {
this.batch = new SpriteBatch();
this.texture = new Texture(Gdx.files.internal("data/blueBg_256_256.png"));
this.blackMarkerTexture = new Texture(Gdx.files.internal("data/blackMarker_32_32.png"));
this.yelloCameraMinimapTexture = new Texture(Gdx.files.internal("data/yelloCameraMinimap_64_64.png"));
this.setName("minimap");
}
public void draw(SpriteBatch batch, float alpha){
// draw actor
batch.draw(texture,this.getX(),this.getY());
// draw game window in minimap
batch.draw( this.yelloCameraMinimapTexture,
this.getX() + (this.getStage().getCamera().position.x - MyOp0Game.MY_ORIGINAL_CAMERA_POSITION_X)/MyOp0Game.MY_MINIMAP_SCALE_FACTOR,
this.getY() + (this.getStage().getCamera().position.y - MyOp0Game.MY_ORIGINAL_CAMERA_POSITION_Y)/MyOp0Game.MY_MINIMAP_SCALE_FACTOR);
// retrieve actors from stage
Array<Actor> lvActorArray = this.getStage().getActors();
for ( int lvIdx = 0; lvIdx < lvActorArray.size; lvIdx++ )
{
Actor lvActor = lvActorArray.get(lvIdx);
if (lvActor.getName() != "minimap")
{
batch.draw( this.blackMarkerTexture,
this.getX() + (lvActor.getX()/MyOp0Game.MY_MINIMAP_SCALE_FACTOR),
this.getY() + (lvActor.getY()/MyOp0Game.MY_MINIMAP_SCALE_FACTOR));
}
}
}
}
my problem is that whenever I try to change an image when a mouse is hovered over it, it doesn't change, and when I do playgame.destroy(); it just shows a white screen behind it, not the other image. Heres my code:
import org.lwjgl.input.Mouse;
import org.newdawn.slick.*;
import org.newdawn.slick.state.*;
public class Menu extends BasicGameState {
Image playgame;
Image exitgame;
Image playgame_hover;
Image exitgame_hover;
public String mouse = "No Input Yet!";
public Menu(int state) {
}
#Override
public void init(GameContainer gc, StateBasedGame sbg) throws SlickException {
playgame = new Image("res/playgame.png");
exitgame = new Image("res/exitgame.png");
playgame_hover = new Image("res/playgame_hover.png");
exitgame_hover = new Image("res/exitgame_hover.png");
}
#Override
public void render(GameContainer gc, StateBasedGame sbg, Graphics g) throws SlickException {
g.drawString(mouse, 590, 10);
playgame.draw(100,100);
exitgame.draw(100, 200);
}
#Override
public void update(GameContainer gc, StateBasedGame sbg, int delta) throws SlickException {
Input input = gc.getInput();
int mousex = Mouse.getX();
int mousey = Mouse.getY();
mouse = "Mouse coordinate x: " + mousex + " y: " + mousey;
// x-min:105 x-max:300 y-min: y-max:300
if(input.isMouseButtonDown(0)) {
if((mousex>100 && mousex<600) && (mousey>357 && mousey<437)) {
sbg.enterState(1);
}
if((mousex>100 && mousex<600) && (mousey>257 && mousey <337)) {
System.exit(0);
}
}
if((mousex>100 && mousex<600) && (mousey>357 && mousey<437)) {
playgame.destroy();
playgame_hover.draw(100, 100);
}
if((mousex>100 && mousex<600) && (mousey>257 && mousey <337)) {
exitgame.destroy();
exitgame_hover.draw(100, 200);
}
}
#Override
public int getID() {
return 0;
}
}
You can only draw things in the render method. You have to save the state changed in the update method and then read those states in the render method.