package io.vivarium.visualizer;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import com.badlogic.gdx.ApplicationAdapter;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.InputProcessor;
import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.graphics.GL20;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.graphics.glutils.ShapeRenderer;
import com.badlogic.gdx.graphics.glutils.ShapeRenderer.ShapeType;
import com.badlogic.gdx.scenes.scene2d.Actor;
import com.badlogic.gdx.scenes.scene2d.Stage;
import com.badlogic.gdx.scenes.scene2d.ui.Label;
import com.badlogic.gdx.scenes.scene2d.ui.SelectBox;
import com.badlogic.gdx.scenes.scene2d.ui.Skin;
import com.badlogic.gdx.scenes.scene2d.ui.Table;
import com.badlogic.gdx.scenes.scene2d.utils.ChangeListener;
import com.badlogic.gdx.utils.viewport.ScreenViewport;
import com.google.common.collect.Lists;
import io.vivarium.core.Action;
import io.vivarium.core.Creature;
import io.vivarium.core.CreatureBlueprint;
import io.vivarium.core.DynamicBalancer;
import io.vivarium.core.GridWorld;
import io.vivarium.core.GridWorldBlueprint;
import io.vivarium.core.ItemType;
import io.vivarium.core.TerrainType;
import io.vivarium.core.processor.NeuralNetworkBlueprint;
import io.vivarium.core.processor.Processor;
import io.vivarium.visualizer.enums.CreatureRenderMode;
import io.vivarium.visualizer.enums.MouseClickMode;
import io.vivarium.visualizer.enums.SimulationSpeed;
public class Vivarium extends ApplicationAdapter implements InputProcessor
{
private static final int SIZE = 30;
private static final int RENDER_BLOCK_SIZE = 32;
private static final int SOURCE_BLOCK_SIZE = 32;
// Simulation information
private GridWorldBlueprint _gridWorldBlueprint;
private GridWorld _gridWorld;
// Simulation + Animation
private int framesSinceTick = 0;
private boolean _enableInterpolation = false;
private Map<Integer, GridCreatureDelegate> _animationCreatureDelegates = new HashMap<>();
private Creature _selectedCreature;
// Low Level Graphics information
private SpriteBatch _batch;
private Texture _img;
// Graphical settings
private CreatureRenderMode _creatureRenderMode = CreatureRenderMode.GENDER;
private int _ticks = 1;
private int _overFrames = 1;
private MouseClickMode _mouseClickMode = MouseClickMode.SELECT_CREATURE;
// High Level Graphics information
private Stage stage;
private Skin skin;
private Label fpsLabel;
private Label populationLabel;
private Label generationLabel;
private Label foodSupplyLabel;
private Label foodSpawnRateLabel;
private Label breedingCostLabel;
private Label creatureIdLabel;
private Label creatureAgeLabel;
private Label creatureFoodLabel;
private Label creatureGestationLabel;
private Label creatureHealthLabel;
// Input tracking
private int _xDownWorld = -1;
private int _yDownWorld = -1;
public Vivarium()
{
}
@Override
public void create()
{
// Create simulation
_gridWorldBlueprint = GridWorldBlueprint.makeDefault();
CreatureBlueprint creatureBlueprint = CreatureBlueprint.makeDefault(0, 0, 0);
NeuralNetworkBlueprint nnBlueprint = (NeuralNetworkBlueprint) creatureBlueprint.getProcessorBlueprints()[0];
// nnBlueprint.setRandomInitializationProportion(1);
nnBlueprint.setMutationRateExponent(-6);
nnBlueprint.setNormalizeAfterMutation(0);
_gridWorldBlueprint.setCreatureBlueprints(Lists.newArrayList(creatureBlueprint));
// _blueprint.setSignEnabled(true);
_gridWorldBlueprint.setSize(SIZE);
_gridWorldBlueprint.setInitialWallGenerationProbability(0);
_gridWorld = new GridWorld(_gridWorldBlueprint);
_gridWorld.setDynamicBalancer(DynamicBalancer.makeDefault());
// Start with selected creature
LinkedList<Creature> creatures = _gridWorld.getCreatures();
if (creatures.size() > 41)
{
_selectedCreature = creatures.get(41);
}
// Setup Input Listeners
Gdx.input.setInputProcessor(this);
// Low level grahpics
_batch = new SpriteBatch();
_img = new Texture("sprites.png");
buildSidebarUI();
}
private void buildSidebarUI()
{
skin = new Skin(Gdx.files.internal("data/uiskin.json"));
// stage = new Stage(Gdx.graphics.getWidth(), Gdx.graphics.getHeight(), false, new PolygonSpriteBatch());
stage = new Stage(new ScreenViewport());
// Gdx.input.setInputProcessor(stage);
// Render Mode
final Label renderModeLabel = new Label("Render Mode: ", skin);
final SelectBox<String> renderModeSelectBox = new SelectBox<>(skin);
renderModeSelectBox.addListener(new ChangeListener()
{
@Override
public void changed(ChangeEvent event, Actor actor)
{
_creatureRenderMode = CreatureRenderMode.valueOf(renderModeSelectBox.getSelected());
}
});
String[] creatureRenderModeStrings = new String[CreatureRenderMode.values().length];
for (int i = 0; i < CreatureRenderMode.values().length; i++)
{
creatureRenderModeStrings[i] = CreatureRenderMode.values()[i].toString();
}
renderModeSelectBox.setItems(creatureRenderModeStrings);
renderModeSelectBox.setSelected(_creatureRenderMode.toString());
// Click Mode
final Label clickModeLabel = new Label("Click Mode: ", skin);
final SelectBox<String> clickModeSelectBox = new SelectBox<>(skin);
clickModeSelectBox.addListener(new ChangeListener()
{
@Override
public void changed(ChangeEvent event, Actor actor)
{
_mouseClickMode = MouseClickMode.valueOf(clickModeSelectBox.getSelected());
_xDownWorld = -1;
_yDownWorld = -1;
}
});
String[] clickModeStrings = new String[MouseClickMode.values().length];
for (int i = 0; i < MouseClickMode.values().length; i++)
{
clickModeStrings[i] = MouseClickMode.values()[i].toString();
}
clickModeSelectBox.setItems(clickModeStrings);
clickModeSelectBox.setSelected(_mouseClickMode.toString());
// Simulation speed
final Label simulationSpeedLabel = new Label("Simulation Speed: ", skin);
final SelectBox<String> simulationSpeedSelectBox = new SelectBox<>(skin);
simulationSpeedSelectBox.addListener(new ChangeListener()
{
@Override
public void changed(ChangeEvent event, Actor actor)
{
SimulationSpeed simulationSpeed = SimulationSpeed.valueOf(simulationSpeedSelectBox.getSelected());
_ticks = simulationSpeed.getTicks();
_overFrames = simulationSpeed.getPerFrame();
_enableInterpolation = simulationSpeed.getEnableInterpolation();
}
});
String[] simulationSpeedStrings = new String[SimulationSpeed.values().length];
for (int i = 0; i < SimulationSpeed.values().length; i++)
{
simulationSpeedStrings[i] = SimulationSpeed.values()[i].toString();
}
simulationSpeedSelectBox.setItems(simulationSpeedStrings);
simulationSpeedSelectBox.setSelected(SimulationSpeed.getDefault().toString());
// FPS Display
fpsLabel = new Label("fps:", skin);
// World Stats
populationLabel = new Label("population:", skin);
generationLabel = new Label("generation:", skin);
foodSupplyLabel = new Label("food:", skin);
foodSpawnRateLabel = new Label("food spawn rate:", skin);
breedingCostLabel = new Label("breeding cost:", skin);
// Layout
Table worldTable = new Table();
worldTable.setPosition(200, getHeight() - 150);
worldTable.add(renderModeLabel).colspan(2);
worldTable.add(renderModeSelectBox).maxWidth(100);
worldTable.row();
worldTable.add(clickModeLabel).colspan(2);
worldTable.add(clickModeSelectBox).maxWidth(100);
worldTable.row();
worldTable.add(simulationSpeedLabel).colspan(2);
worldTable.add(simulationSpeedSelectBox).maxWidth(100);
worldTable.row();
worldTable.add(fpsLabel).colspan(4);
worldTable.row();
worldTable.add(populationLabel).colspan(4);
worldTable.row();
worldTable.add(generationLabel).colspan(4);
worldTable.row();
worldTable.add(foodSupplyLabel).colspan(4);
worldTable.row();
worldTable.add(foodSpawnRateLabel).colspan(4);
worldTable.row();
worldTable.add(breedingCostLabel).colspan(4);
stage.addActor(worldTable);
// Creature Stats
creatureIdLabel = new Label("creature id:", skin);
creatureAgeLabel = new Label("age:", skin);
creatureFoodLabel = new Label("food:", skin);
creatureGestationLabel = new Label("gestation:", skin);
creatureHealthLabel = new Label("health:", skin);
Table creatureTable = new Table();
creatureTable.setPosition(200, getHeight() - 500);
creatureTable.add(creatureIdLabel).colspan(4);
creatureTable.row();
creatureTable.add(creatureAgeLabel).colspan(4);
creatureTable.row();
creatureTable.add(creatureFoodLabel).colspan(4);
creatureTable.row();
creatureTable.add(creatureGestationLabel).colspan(4);
creatureTable.row();
creatureTable.add(creatureHealthLabel).colspan(4);
stage.addActor(creatureTable);
}
@Override
public void render()
{
Gdx.gl.glClearColor(0, 0, 0, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
_batch.begin();
_batch.setColor(Color.WHITE);
float interpolationFraction = _enableInterpolation ? (float) framesSinceTick / _overFrames : 1;
drawTerrain(interpolationFraction);
drawFood();
drawCreatures(interpolationFraction);
_batch.end();
setLabels();
drawCreatureMultiplexer();
stage.act(Gdx.graphics.getDeltaTime());
stage.draw();
framesSinceTick++;
if (framesSinceTick >= _overFrames)
{
for (int i = 0; i < _ticks; i++)
{
_gridWorld.tick();
updateCreatureDelegates();
}
framesSinceTick = 0;
}
mouseBrush();
}
private void drawCreatureMultiplexer()
{
if (_selectedCreature != null)
{
ShapeRenderer sr = new ShapeRenderer();
sr.begin(ShapeType.Filled);
for (int j = 0; j < _selectedCreature.getInputs().length; j++)
{
drawMultiplexerCell(sr, 0, j, (float) _selectedCreature.getInputs()[j]);
}
for (int i = 0; i < _selectedCreature.getProcessors().length; i++)
{
Processor p = _selectedCreature.getProcessors()[i];
for (int j = 0; j < p.outputs().length; j++)
{
drawMultiplexerCell(sr, i + 1, j, (float) p.outputs()[j]);
}
}
sr.end();
}
}
private void drawMultiplexerCell(ShapeRenderer sr, int x, int y, float color)
{
sr.setColor(Color.WHITE);
sr.rect(50 + x * 10, 500 - y * 10, 9, 9);
sr.setColor(color, color, color, 1);
sr.rect(51 + x * 10, 501 - y * 10, 7, 7);
}
private void mouseBrush()
{
if (this._xDownWorld > -1 && this._yDownWorld > -1)
{
if (this._mouseClickMode.isPaintbrushMode())
{
applyMouseBrush(_xDownWorld, _yDownWorld);
}
}
}
private void removeTerrain(int r, int c)
{
_gridWorld.setTerrain(null, r, c);
}
private void applyMouseBrush(int x, int y)
{
Creature creature;
// Check bounds, don't let the user change terrain near the edge of the world
if (x < 1 || x >= _gridWorld.getWidth() - 1 || y < 1 || y >= _gridWorld.getHeight() - 1)
{
return;
}
// Apply brush modes
switch (this._mouseClickMode)
{
case ADD_WALL:
if (_gridWorld.squareIsEmpty(y, x))
{
_gridWorld.setTerrain(TerrainType.WALL, y, x);
}
break;
case ADD_WALL_BRUTALLY:
creature = _gridWorld.getCreature(y, x);
if (creature != null)
{
this._animationCreatureDelegates.remove(creature.getID());
_gridWorld.removeCreature(y, x);
}
_gridWorld.removeFood(y, x);
_gridWorld.setTerrain(TerrainType.WALL, y, x);
break;
case REMOVE_TERRAIN:
removeTerrain(y, x);
break;
case REMOVE_ANYTHING:
creature = _gridWorld.getCreature(y, x);
if (creature != null)
{
this._animationCreatureDelegates.remove(creature.getID());
_gridWorld.removeCreature(y, x);
}
_gridWorld.removeFood(y, x);
_gridWorld.setTerrain(null, y, x);
break;
case ADD_FLAMETHROWER:
if (_gridWorld.squareIsEmpty(y, x))
{
_gridWorld.setTerrain(TerrainType.FLAMETHROWER, y, x);
}
break;
case ADD_FOODGENERATOR:
if (_gridWorld.squareIsEmpty(y, x))
{
_gridWorld.setTerrain(TerrainType.FOOD_GENERATOR, y, x);
}
break;
case SELECT_CREATURE:
throw new IllegalStateException("" + MouseClickMode.SELECT_CREATURE + " is not a brush mode");
}
}
private void setLabels()
{
fpsLabel.setText("fps: " + Gdx.graphics.getFramesPerSecond());
populationLabel.setText("population: " + _gridWorld.getCreatureCount());
LinkedList<Creature> creatures = _gridWorld.getCreatures();
double generation = 0;
for (Creature creature : creatures)
{
generation += creature.getGeneration();
}
generation /= creatures.size();
generationLabel.setText("generation: " + ((int) (generation * 100) / 100.0));
foodSupplyLabel.setText("food: " + _gridWorld.getItemCount());
foodSpawnRateLabel
.setText("food spawn rate: " + _gridWorld.getGridWorldBlueprint().getFoodGenerationProbability());
breedingCostLabel.setText("breeding cost: "
+ (-1 * _gridWorld.getGridWorldBlueprint().getCreatureBlueprints().get(0).getBreedingFoodRate()));
if (_selectedCreature != null)
{
creatureIdLabel.setText("creature id: " + _selectedCreature.getID());
creatureAgeLabel.setText("age: " + _selectedCreature.getAge());
creatureFoodLabel.setText("food: " + _selectedCreature.getFood());
creatureGestationLabel.setText("gestation: " + _selectedCreature.getGestation());
creatureHealthLabel.setText("health: " + _selectedCreature.getHealth());
}
}
private void drawSprite(VivariumSprite sprite, float xPos, float yPos, float angle)
{
drawSprite(sprite, xPos, yPos, angle, 1);
}
private void drawSprite(VivariumSprite sprite, float xPos, float yPos, float angle, float scale)
{
float x = SIZE / 2 * RENDER_BLOCK_SIZE + xPos * RENDER_BLOCK_SIZE;
float y = getHeight() - yPos * RENDER_BLOCK_SIZE - RENDER_BLOCK_SIZE;
float originX = RENDER_BLOCK_SIZE / 2;
float originY = RENDER_BLOCK_SIZE / 2;
float width = RENDER_BLOCK_SIZE;
float height = RENDER_BLOCK_SIZE;
float rotation = angle; // In degrees
int srcX = sprite.x * SOURCE_BLOCK_SIZE;
int srcY = sprite.y * SOURCE_BLOCK_SIZE;
int srcW = SOURCE_BLOCK_SIZE;
int srcH = SOURCE_BLOCK_SIZE;
boolean flipX = false;
boolean flipY = false;
_batch.draw(_img, x, y, originX, originY, width, height, scale, scale, rotation, srcX, srcY, srcW, srcH, flipX,
flipY);
}
private void drawTerrain(float interpolationFraction)
{
for (int c = 0; c < _gridWorld.getWorldWidth(); c++)
{
for (int r = 0; r < _gridWorld.getWorldHeight(); r++)
{
if (_gridWorld.getTerrain(r, c) == TerrainType.WALL)
{
drawSprite(VivariumSprite.WALL, c, r, 0);
}
if (_gridWorld.getTerrain(r, c) == TerrainType.FOOD_GENERATOR)
{
drawSprite(VivariumSprite.FOOD_GENERATOR_ACTIVE, c, r, 0);
}
if (_gridWorld.getTerrain(r, c) == TerrainType.FLAMETHROWER)
{
drawSprite(VivariumSprite.FLAMETHROWER_ACTIVE, c, r, 0);
}
if (_gridWorld.getTerrain(r, c) == TerrainType.FLAME)
{
if (interpolationFraction < 1f / 3f)
{
drawSprite(VivariumSprite.FLAME_1, c, r, 0);
}
else if (interpolationFraction < 2f / 3f)
{
drawSprite(VivariumSprite.FLAME_2, c, r, 0);
}
else
{
drawSprite(VivariumSprite.FLAME_3, c, r, 0);
}
}
}
}
}
private void drawFood()
{
for (int c = 0; c < _gridWorld.getWorldWidth(); c++)
{
for (int r = 0; r < _gridWorld.getWorldHeight(); r++)
{
if (_gridWorld.getItem(r, c) == ItemType.FOOD)
{
drawSprite(VivariumSprite.FOOD, c, r, 0);
}
}
}
}
private void drawCreatures(float interpolationFraction)
{
for (GridCreatureDelegate delegate : _animationCreatureDelegates.values())
{
drawCreature(delegate, interpolationFraction);
}
}
private void drawCreature(GridCreatureDelegate delegate, float interpolationFraction)
{
Creature creature = delegate.getCreature();
switch (_creatureRenderMode)
{
case GENDER:
setColorOnGenderAndPregnancy(delegate, interpolationFraction);
break;
case HEALTH:
setColorOnHealth(creature);
break;
case AGE:
setColorOnAge(creature);
break;
case HUNGER:
setColorOnFood(creature);
break;
case MEMORY:
setColorOnMemory(creature);
break;
case SIGN:
setColorOnSignLanguage(creature);
break;
}
float scale = delegate.getScale(interpolationFraction);
VivariumSprite creatureSprite = getCreatureSpriteFrame(interpolationFraction, creature);
drawSprite(creatureSprite, delegate.getC(interpolationFraction), delegate.getR(interpolationFraction),
delegate.getRotation(interpolationFraction), scale);
if (creature == _selectedCreature)
{
_batch.setColor(Color.WHITE);
VivariumSprite creatureHaloSprite = getCreatureHaloSpriteFrame(interpolationFraction, creature);
drawSprite(creatureHaloSprite, delegate.getC(interpolationFraction), delegate.getR(interpolationFraction),
delegate.getRotation(interpolationFraction), scale);
}
}
private void updateCreatureDelegates()
{
// Find creatures that are dying and mark them as such. These creatures will no longer
// be present in the world, but it's expensive to check this. Fortunately, a creature
// will use the die action as its last act in the world. Any existing delegate
// with a creature that has used dye either needs to animate its death, or has
// already done so.
Set<Integer> creatureIDsToRemove = new HashSet<>();
for (Entry<Integer, GridCreatureDelegate> delegatePair : _animationCreatureDelegates.entrySet())
{
if (delegatePair.getValue().isDying())
{
creatureIDsToRemove.add(delegatePair.getKey());
}
else if (delegatePair.getValue().getCreature().getAction() == Action.DIE)
{
delegatePair.getValue().die();
}
}
// Remove creatures that have finished dying from the animation delegates.
for (Integer creatureID : creatureIDsToRemove)
{
_animationCreatureDelegates.remove(creatureID);
}
// For all other creatures, update their animation delegate, or add a new one if they
// don't have an animation delegate yet.
for (int c = 0; c < _gridWorld.getWorldWidth(); c++)
{
for (int r = 0; r < _gridWorld.getWorldHeight(); r++)
{
Creature creature = _gridWorld.getCreature(r, c);
if (creature != null)
{
if (_animationCreatureDelegates.containsKey(creature.getID()))
{
_animationCreatureDelegates.get(creature.getID()).updateSnapshot(r, c);
}
else
{
_animationCreatureDelegates.put(creature.getID(), new GridCreatureDelegate(creature, r, c));
}
}
}
}
}
public void setColorOnGenderAndPregnancy(GridCreatureDelegate delegate, float interpolationFraction)
{
if (delegate.getCreature().getIsFemale())
{
float pregnancyFraction = delegate.getPregnancy(interpolationFraction);
float red = (0.4f - 0) * pregnancyFraction + 0.0f;
float green = (0 - 0.8f) * pregnancyFraction + 0.8f;
float blue = (0.4f - 0.8f) * pregnancyFraction + 0.8f;
_batch.setColor(new Color(red, green, blue, 1));
}
else
{
_batch.setColor(new Color(0.8f, 0, 0, 1));
}
}
public void setColorOnFood(Creature creature)
{
float food = ((float) creature.getFood()) / creature.getBlueprint().getMaximumFood();
_batch.setColor(new Color(1, food, food, 1));
}
public void setColorOnHealth(Creature creature)
{
float health = ((float) creature.getHealth()) / creature.getBlueprint().getMaximumHealth();
_batch.setColor(new Color(1, health, health, 1));
}
public void setColorOnAge(Creature creature)
{
float age = ((float) creature.getAge()) / creature.getBlueprint().getMaximumAge();
_batch.setColor(new Color(age, 1, age, 1));
}
public void setColorOnMemory(Creature creature)
{
double[] memories = creature.getMemoryUnits();
float[] displayMemories = { 1, 1, 1 };
for (int i = 0; i < memories.length && i < displayMemories.length; i++)
{
displayMemories[i] = (float) memories[i];
}
_batch.setColor(new Color(displayMemories[0], displayMemories[1], displayMemories[2], 1));
}
public void setColorOnSignLanguage(Creature creature)
{
double[] signs = creature.getSignOutputs();
float[] displaySigns = { 1, 1, 1 };
for (int i = 0; i < signs.length && i < displaySigns.length; i++)
{
displaySigns[i] = (float) signs[i];
}
_batch.setColor(new Color(displaySigns[0], displaySigns[1], displaySigns[2], 1));
}
private VivariumSprite getCreatureSpriteFrame(float cycle, Creature creature)
{
int offset = (int) (cycle * 100 + creature.getRandomSeed() * 100) % 100;
if (offset < 25)
{
return VivariumSprite.CREATURE_1;
}
else if (offset < 50)
{
return VivariumSprite.CREATURE_2;
}
else if (offset < 75)
{
return VivariumSprite.CREATURE_3;
}
else
{
return VivariumSprite.CREATURE_2;
}
}
private VivariumSprite getCreatureHaloSpriteFrame(float cycle, Creature creature)
{
int offset = (int) (cycle * 100 + creature.getRandomSeed() * 100) % 100;
if (offset < 25)
{
return VivariumSprite.HALO_CREATURE_1;
}
else if (offset < 50)
{
return VivariumSprite.HALO_CREATURE_2;
}
else if (offset < 75)
{
return VivariumSprite.HALO_CREATURE_3;
}
else
{
return VivariumSprite.HALO_CREATURE_2;
}
}
public static int getHeight()
{
return SIZE * RENDER_BLOCK_SIZE;
}
public static int getWidth()
{
return SIZE * RENDER_BLOCK_SIZE;
}
@Override
public boolean keyDown(int keycode)
{
stage.keyDown(keycode);
return false;
}
@Override
public boolean keyUp(int keycode)
{
stage.keyUp(keycode);
return false;
}
@Override
public boolean keyTyped(char character)
{
stage.keyTyped(character);
return false;
}
@Override
public boolean touchDown(int screenX, int screenY, int pointer, int button)
{
stage.touchDown(screenX, screenY, pointer, button);
if (screenX > SIZE / 2 * RENDER_BLOCK_SIZE)
{
this._xDownWorld = (screenX - SIZE / 2 * RENDER_BLOCK_SIZE) / RENDER_BLOCK_SIZE;
this._yDownWorld = screenY / RENDER_BLOCK_SIZE;
}
else
{
this._xDownWorld = -1;
this._yDownWorld = -1;
}
return true;
}
@Override
public boolean touchUp(int screenX, int screenY, int pointer, int button)
{
stage.touchUp(screenX, screenY, pointer, button);
if (screenX > SIZE / 2 * RENDER_BLOCK_SIZE)
{
int xUpWorld = (screenX - SIZE / 2 * RENDER_BLOCK_SIZE) / RENDER_BLOCK_SIZE;
int yUpWorld = screenY / RENDER_BLOCK_SIZE;
if (_xDownWorld == xUpWorld && _yDownWorld == yUpWorld)
{
if (_mouseClickMode == MouseClickMode.SELECT_CREATURE)
{
if (_gridWorld.getCreature(yUpWorld, xUpWorld) != null)
{
this._selectedCreature = _gridWorld.getCreature(yUpWorld, xUpWorld);
}
this._xDownWorld = -1;
this._yDownWorld = -1;
}
}
}
return true;
}
@Override
public boolean touchDragged(int screenX, int screenY, int pointer)
{
stage.touchDragged(screenX, screenY, pointer);
if (screenX > SIZE / 2 * RENDER_BLOCK_SIZE)
{
int xDragWorld = (screenX - SIZE / 2 * RENDER_BLOCK_SIZE) / RENDER_BLOCK_SIZE;
int yDragWorld = screenY / RENDER_BLOCK_SIZE;
if (this._mouseClickMode.isPaintbrushMode())
{
applyMouseBrush(xDragWorld, yDragWorld);
}
}
return false;
}
@Override
public boolean mouseMoved(int screenX, int screenY)
{
stage.mouseMoved(screenX, screenY);
return false;
}
@Override
public boolean scrolled(int amount)
{
stage.scrolled(amount);
return false;
}
}