TLDR Version:
Don't store position value and states of objects directly in the game / state class. Create classes for game objects and only store, update and render those objects. When you press you build key, simply remove the building material from the player and create a new game object on the respective position.
Long Version:
Ok, from looking at your code I think you have to learn a bit more about object oriented design and how to apply it for problems as yours. Maybe I drift a bit offtopic concerning your question. If so sorry about that, but I think you should get the idea, how this can help you.
In your code, you have a variable that tracks, if you are building something. Now imagine, you want to have 10 other building options, then you would need 10 variables to track the state. Try to grasp the concept of classes and objects.
So maybe start reading the concepts of OOP or read the Wikipedia article to get used to the subject.
So, back to your question. First of all I would think of what classes you will have in your game. Assuming from your question I would start by implementing a class GameObject. This class holds some basic information, that are used for all game objects. I put a vector in the class, that represents the position of the object, and an image, that is the graphical representation of that object.
public abstract class GameObject{
public Vector2f position;
public Image image;
public GameObject(Image image){
this.position = new Vector2f();
this.image = image;
}
public void render(Graphics g, float xOffset, float yOffset)
{
if(this.image == null) return;
g.drawImage(this.image, this.position.x + xOffset, this.position.y + yOffset);
}
public abstract void update(int d);
}
Maybe you noticed that the class is marked abstract. This means, that this class is not meant to be instanciated, but other classes need to extend from it. It already implements a basic render methodThe method update is defined here in the base class without any implementation.
So now lets look on how to implement another game object. One thing you will need is the player class and this could look something like this:
public class PlayerObject extends GameObject {
public final static int STATE_NONE = -1;
public final static int STATE_BUILDING_ROCK = 0;
public final static int STATE_BUILDING_WOOD = 1;
public final static int INDEX_ROCK = 0;
public final static int INDEX_WOOD = 1;
public final static float MOVE_SPEED = 0.1f;
public int state;
public Vector2f velocity;
public Image[] objectImages;
//Because we want to display objects, that can be built, we need to provide the sprites /
//images of the objects.
public PlayerObject(Image image, Image[] objectImages){
super(image);
this.velocity = new Vector2f();
}
@Override
public void render(Graphics g, float xOffset, float yOffset)
//First of all we call the render method of the base class
//This calls the code defined in the GameObject.render method.
super.render(g, xOffset, yOffset);
//Now in the player implementation of the render method, we want to
//know, if the player holds an object, that also should be rendered
if(this.state == STATE_BUILDING_ROCK){
g.drawImage(this.objectImages[INDEX_ROCK], this.position.x + xOffset, this.position.y + yOffset);
}
else if(this.state == STATE_BUILDING_WOOD){
g.drawImage(this.objectImages[INDEX_WOOD], this.position.x + xOffset, this.position.y + yOffset);
}
}
@Override
public void update(int d){
this.position.x += this.velocity.x * MOVE_SPEED;
this.position.y += this.velocity.y * MOVE_SPEED;
}
}
If you look at the code, you can see that two things were implemented. The update method changes the position of the GameObject according to the defined velocity. And the render method first simply calls the render method of the base class and then checks, if it has to draw the building material.
Some comments to this. The entities do not manage their state themselves (besides the position), but you would handle all game objects in the game loop and depending on the state you would change the fields of the entity, for example like this:
if(container.getInput().isKeyPressed(Input.KEY_2)){
player.state = PlayerObject.STATE_BUILDING_ROCK;
}
With this, you would have the display functionality capsuled in the GameObject and extend that functionality in the PlayerObject class by updating the players position and rendering the building materials, if the player is currently in a building state.
Now to the second part, building the object and leaving it there. To accomplish this, I would create another class StaticObject or something like that.
public class StaticGameObject extends GameObject{
public StaticGameObject(Image i){
super(i);
}
@Override
public void update(int d){
//Does not do anything in update
}
}
To make things a bit more interesting, we add the logic to spawn a static game object to the player object (this is maybe not the best solution, but it should do the work). So we add this code to the PlayerObject class:
public StaticObject build()
{
Image i = null;
if(this.state == STATE_BUILDING_ROCK){
i = materials[INDEX_ROCK];
}
else if(this.state == STATE_BUILDING_WOOD){
i = materials[INDEX_GRASS];
}
//If no image has been found for the material, the thing is not built.
if(i == null) return null;
StaticObject obj = new StaticObject(i);
obj.position.set(this.position);
//Reset the state
this.state = MODE_NONE;
return obj;
}
Now, when the player presses a key to build the object, you have to do 2 things. First set the players state back to MODE_NONE, because he completed the action. As second, you create a StaticObject with the building material and add it to your GameObject list. This object is now independent from your player and stays at its place, even if you move around.
A short abstract, how (parts) of my Game or GameState class would look like, using the examples from above:
public class TestGame extends BasicGame
{
private Image playerImage;
private Image[] materials;
private PlayerObject player;
private List<GameObject> objects;
public TestGame(){
super("Test Game");
objects = new ArrayList<GameObject>();
}
[...]
public void init(GameContainer container){
playerImage = new Image("PlayerImage.png");
materials = new Image[2];
materials[0] = new Image("Rock.png");
materials[1] = new Image("Wood.png");
player = new PlayerObject(playerImage, materials);
player.position.set(100, 100);
objects.add(player);
[...]
}
public void update(GameContainer container, int d){
//First do input handling and update the player objects state, if needed
Input i = container.getInput();
if(i.isKeyPressed(Input.KEY_1)){
player.state = PlayerObject.STATE_BUILDING_ROCK;
}
if(i.isKeyPressed(Input.KEY_2)){
player.state = PlayerObject.STATE_BUILDING_WOOD;
}
if(i.isKeyPressed(Input.KEY_ENTER) )
{
//If the build key is pressed, we try to build with the player
GameObject obj = player.build();
//If an object could have been built, it is added to the global game object list
if(obj != null){
objects.add(obj);
}
}
//Now update all objects
for(GameObject object : objects){
object.update(d);
}
}
public void render(Graphics g, GameContainer container, int d){
for(GameObject object : objects){
//The x and y offset parameters are used, when the map scrolls
object.render(d, 0, 0);
}
}
}
Keep in mind, it is not the ultimately best solution and I scribbled it down without any IDE, so no warranties that the code actually works ;)
Sooo, I hope it isn't too much. As you can see, we try to capsule functionality to the respective actors. Also, like this you can implement very easily computer controlled characters, that also can use the same build mechanics (just instead of receiving its state from the keyboard input, an AI component would change the state). And also, you can add 10 objects, and you don't have to create all the boolean and position variables for all of them, but only an GameObject per object.