package com.ftloverdrive.ui.screen;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.InputMultiplexer;
import com.badlogic.gdx.assets.loaders.FileHandleResolver;
import com.badlogic.gdx.files.FileHandle;
import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.graphics.GL10;
import com.badlogic.gdx.graphics.g2d.BitmapFont;
import com.badlogic.gdx.graphics.g2d.Sprite;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.g2d.Animation;
import com.badlogic.gdx.graphics.g2d.NinePatch;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.graphics.g2d.TextureAtlas;
import com.badlogic.gdx.graphics.g2d.TextureRegion;
import com.badlogic.gdx.math.Matrix4;
import com.badlogic.gdx.scenes.scene2d.Group;
import com.badlogic.gdx.scenes.scene2d.Stage;
import com.badlogic.gdx.scenes.scene2d.ui.Label;
import com.badlogic.gdx.scenes.scene2d.ui.Window;
import com.badlogic.gdx.scenes.scene2d.utils.Align;
import com.badlogic.gdx.scenes.scene2d.utils.NinePatchDrawable;
import com.badlogic.gdx.utils.Array;
import com.badlogic.gdx.utils.Disposable;
import com.badlogic.gdx.utils.Logger;
import com.badlogic.gdx.utils.Pools;
import com.ftloverdrive.blueprint.ship.TestShipBlueprint;
import com.ftloverdrive.core.OverdriveContext;
import com.ftloverdrive.event.OVDEventManager;
import com.ftloverdrive.event.TickEvent;
import com.ftloverdrive.event.TickListener;
import com.ftloverdrive.event.game.GamePlayerShipChangeEvent;
import com.ftloverdrive.event.game.GamePlayerShipChangeListener;
import com.ftloverdrive.event.handler.GameEventHandler;
import com.ftloverdrive.event.handler.ShipEventHandler;
import com.ftloverdrive.event.handler.TickEventHandler;
import com.ftloverdrive.event.ship.ShipPropertyEvent;
import com.ftloverdrive.event.ship.ShipPropertyListener;
import com.ftloverdrive.model.DefaultGameModel;
import com.ftloverdrive.model.DefaultPlayerModel;
import com.ftloverdrive.model.GameModel;
import com.ftloverdrive.model.PlayerModel;
import com.ftloverdrive.model.ship.ShipModel;
import com.ftloverdrive.model.ship.TestShipModel;
import com.ftloverdrive.script.OVDScriptManager;
import com.ftloverdrive.ui.ShatteredImage;
import com.ftloverdrive.ui.hud.PlayerShipHullMonitor;
import com.ftloverdrive.ui.screen.OVDScreen;
import com.ftloverdrive.ui.screen.OVDStageManager;
import com.ftloverdrive.ui.ship.ShipActor;
import com.ftloverdrive.util.OVDConstants;
public class TestScreen implements Disposable, OVDScreen {
protected static final String BKG_ATLAS = "img/stars/bg-dullstars-bigcols5.atlas";
protected static final String ROOT_ATLAS = "img/pack.atlas";
protected static final String MISC_ATLAS = "img/misc/pack.atlas";
protected static final String PEOPLE_ATLAS = "img/people/pack.atlas";
protected static final String PLOT_FONT = "fonts/JustinFont12Bold.ttf?size=13";
private Logger log;
private TextureAtlas bgAtlas;
private TextureAtlas rootAtlas;
private TextureAtlas miscAtlas;
private TextureAtlas peopleAtlas;
private SpriteBatch batch;
private boolean renderedPreviousFrame = false;
private float elapsed = 0;
private OVDStageManager stageManager = null;
private OVDEventManager eventManager = null;
private OVDScriptManager scriptManager = null;
private InputMultiplexer inputMultiplexer;
private Stage mainStage;
private Stage hudStage;
private Stage popupStage;
private Sprite driftSprite = null;
private Animation walkAnim = null;
private PlayerShipHullMonitor playerShipHullMonitor;
private ShipActor shipActor;
private OverdriveContext context;
public TestScreen( OverdriveContext srcContext ) {
this.context = Pools.get( OverdriveContext.class ).obtain();
this.context.init( srcContext );
this.context.setScreen( this );
log = new Logger( TestScreen.class.getCanonicalName(), Logger.DEBUG );
stageManager = new OVDStageManager();
eventManager = new OVDEventManager();
scriptManager = new OVDScriptManager();
mainStage = new Stage();
stageManager.putStage( "Main", mainStage );
hudStage = new Stage();
stageManager.putStage( "HUD", hudStage );
popupStage = new Stage();
stageManager.putStage( "Popup", popupStage );
// These layers are mainly notes. Many will probably be moved inside
// actors.
Array<String> mainLayerNames = new Array<String>();
mainLayerNames.add( "Background" );
mainLayerNames.add( "BackgroundAccent" ); // Planet.
mainLayerNames.add( "ShipShield" );
mainLayerNames.add( "ShipGib" );
mainLayerNames.add( "ShipWeapon" );
mainLayerNames.add( "ShipBase" );
mainLayerNames.add( "ShipFloor" );
mainLayerNames.add( "ShipFloorSheen" ); // Oxygen stripes.
mainLayerNames.add( "ShipRoomDecor" );
mainLayerNames.add( "ShipRoomAccent" ); // Terminal.
mainLayerNames.add( "ShipBreach" );
mainLayerNames.add( "ShipFire" );
mainLayerNames.add( "ShipSystemIcon" );
mainLayerNames.add( "ShipPersonnelDot" ); // Sensor blip or walk target.
mainLayerNames.add( "ShipPersonnel" );
mainLayerNames.add( "ShipWall" );
mainLayerNames.add( "ShipDoor" );
mainLayerNames.add( "Satellite" ); // Flying drones.
mainLayerNames.add( "Debris" ); // Crystal lockdown chunks. Explosions.
for ( String layerName : mainLayerNames ) {
Group tmpGroup = new Group();
tmpGroup.setName( layerName );
mainStage.getRoot().addActor( tmpGroup );
}
Array<String> hudLayerNames = new Array<String>();
hudLayerNames.add( "Warning" ); // "Danger", "Intruders Detected" and "O2 Low".
hudLayerNames.add( "UnitStatus" ); // Health bars over crew.
hudLayerNames.add( "ShipDoorHighlight" );
hudLayerNames.add( "FloatyDamageNumber" ); // When hit.
hudLayerNames.add( "Beam" );
hudLayerNames.add( "Reticle" );
hudLayerNames.add( "CtrlPanel" );
for ( String layerName : hudLayerNames ) {
Group tmpGroup = new Group();
tmpGroup.setName( layerName );
hudStage.getRoot().addActor( tmpGroup );
}
// Layers can be looked up with stage.getRoot().findActor( layerName );
// A layer can be inserted like this...
// Group stageRoot = stage.getRoot();
// Group lowerLayer = (Group)stageRoot.findActor( layerName );
// stageRoot.addActorAfter( lowerLayer, newGroup );
context.getAssetManager().load( BKG_ATLAS, TextureAtlas.class );
context.getAssetManager().load( ROOT_ATLAS, TextureAtlas.class );
context.getAssetManager().load( MISC_ATLAS, TextureAtlas.class );
context.getAssetManager().load( PEOPLE_ATLAS, TextureAtlas.class );
context.getAssetManager().load( PLOT_FONT, BitmapFont.class );
context.getAssetManager().finishLoading();
bgAtlas = context.getAssetManager().get( BKG_ATLAS, TextureAtlas.class );
ShatteredImage bgImage = new ShatteredImage( bgAtlas.findRegions( "bg-dullstars" ), 5 );
bgImage.setFillParent( true );
bgImage.setPosition( 0, 0 );
((Group)mainStage.getRoot().findActor( "Background" )).addActor( bgImage );
textWindowDemo();
movingSpriteDemo();
walkAnimDemo();
batch = new SpriteBatch();
int playerRefId = context.getNetManager().requestNewRefId();
PlayerModel playerModel = new DefaultPlayerModel();
context.getReferenceManager().addObject( playerModel, playerRefId );
context.getNetManager().setLocalPlayerRefId( playerRefId );
int gameRefId = context.getNetManager().requestNewRefId();
GameModel gameModel = new DefaultGameModel();
context.getReferenceManager().addObject( gameModel, gameRefId );
context.setGameModelRefId( gameRefId );
playerShipHullMonitor = new PlayerShipHullMonitor( context );
playerShipHullMonitor.setPosition( 0, hudStage.getHeight()-playerShipHullMonitor.getHeight() );
hudStage.addActor( playerShipHullMonitor );
shipActor = new ShipActor( context );
shipActor.setPosition( 200, 100 ); // TODO: Magic numbers (~200x200 on 1280x768).
mainStage.addActor( shipActor );
inputMultiplexer = new InputMultiplexer();
inputMultiplexer.addProcessor( popupStage );
inputMultiplexer.addProcessor( hudStage );
inputMultiplexer.addProcessor( mainStage );
// Wire up the event manager...
TickEventHandler tickHandler = new TickEventHandler();
for ( Class c : tickHandler.getEventClasses() )
eventManager.setEventHandler( c, tickHandler );
GameEventHandler gameHandler = new GameEventHandler();
for ( Class c : gameHandler.getEventClasses() )
eventManager.setEventHandler( c, gameHandler );
ShipEventHandler shipHandler = new ShipEventHandler();
for ( Class c : shipHandler.getEventClasses() )
eventManager.setEventHandler( c, shipHandler );
eventManager.addEventListener( playerShipHullMonitor, GamePlayerShipChangeListener.class );
eventManager.addEventListener( playerShipHullMonitor, ShipPropertyListener.class );
eventManager.addEventListener( shipActor, GamePlayerShipChangeListener.class );
eventManager.addEventListener( shipActor, ShipPropertyListener.class );
// When there's a ship, increment its hull after every tick.
eventManager.addEventListener(new TickListener() {
@Override
public void ticksAccumulated( TickEvent e ) {
//System.out.println( "Tick ("+ e.getTickCount() +")" );
GameModel gameModel = context.getReferenceManager().getObject( context.getGameModelRefId(), GameModel.class );
int shipRefId = gameModel.getPlayerShip( context.getNetManager().getLocalPlayerRefId() );
if ( shipRefId != -1 ) {
ShipModel shipModel = context.getReferenceManager().getObject( shipRefId, ShipModel.class );
int hull = shipModel.getProperties().getInt( OVDConstants.HULL );
int hullMax = shipModel.getProperties().getInt( OVDConstants.HULL_MAX );
if ( hull < hullMax ) {
ShipPropertyEvent event = Pools.get( ShipPropertyEvent.class ).obtain();
event.init( shipRefId, ShipPropertyEvent.INT_TYPE, ShipPropertyEvent.INCREMENT_ACTION, OVDConstants.HULL, 1 );
context.getScreenEventManager().postDelayedEvent( event );
}
}
// Eventually a PropertyEvent would have an INC_IF_LESS_THAN flag
// or something. Or maybe a sentinel event listener - set to watch
// certain property names - vetoing attempts to increment beyond
// the names' associated maxes?
}
}, TickListener.class);
// Create a test ship.
int shipRefId = new TestShipBlueprint().createShip( context );
// Set it as the player's ship.
GamePlayerShipChangeEvent shipChangeEvent = Pools.get( GamePlayerShipChangeEvent.class ).obtain();
shipChangeEvent.init( gameRefId, playerRefId, shipRefId );
eventManager.postDelayedEvent( shipChangeEvent );
try {
FileHandleResolver resolver = context.getFileHandleResolver();
//scriptManager.eval( resolver.resolve( "script.java" ) );
}
catch ( Exception e ) {
log.error( "Error evaluating script.", e );
}
}
private void textWindowDemo() {
BitmapFont plotFont = context.getAssetManager().get( PLOT_FONT, BitmapFont.class );
String loremIpsum = "Lorem ipsum dolor sit amet, consectetur adipisicing elit, ";
loremIpsum += "sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.";
loremIpsum += "\n\nThis window is draggable.";
rootAtlas = context.getAssetManager().get( ROOT_ATLAS, TextureAtlas.class );
TextureRegion plotDlgRegion = rootAtlas.findRegion( "box-text1" );
NinePatchDrawable plotDlgBgDrawable = new NinePatchDrawable( new NinePatch( plotDlgRegion, 20, 20, 35, 20 ) );
Window plotDlg = new Window( "", new Window.WindowStyle( plotFont, new Color( 1f, 1f, 1f, 1f ), plotDlgBgDrawable ) );
plotDlg.setKeepWithinStage( true );
plotDlg.setMovable( true );
plotDlg.setSize( 200, 250 );
plotDlg.setPosition( 765, 60 );
plotDlg.row().top().expand().fill();
Label plotLbl = new Label( loremIpsum, new Label.LabelStyle( plotFont, new Color( 1f, 1f, 1f, 1f ) ) );
plotLbl.setAlignment( Align.top|Align.left, Align.center|Align.left );
plotLbl.setWrap( true );
plotDlg.add( plotLbl );
// setKeepWithinStage() only applies if added to the stage root. :/
popupStage.addActor( plotDlg );
}
private void movingSpriteDemo() {
miscAtlas = context.getAssetManager().get( MISC_ATLAS, TextureAtlas.class );
driftSprite = miscAtlas.createSprite( "crosshairs-placed" );
}
private void walkAnimDemo() {
peopleAtlas = context.getAssetManager().get( PEOPLE_ATLAS, TextureAtlas.class );
TextureRegion crewRegion = peopleAtlas.findRegion( "human-player-yellow" );
// FTL's animations.xml counts 0-based rows from the bottom.
TextureRegion[][] tmpFrames = crewRegion.split( 35, 35 );
TextureRegion[] walkFrames = new TextureRegion[ 4 ];
int walkStart = 4;
for ( int i=0; i < walkFrames.length; i++ ) {
walkFrames[i] = tmpFrames[0][ walkStart + i ];
}
walkAnim = new Animation( .3f, walkFrames );
}
@Override
public void resize( int width, int height ) {
hudStage.setViewport( width, height, true );
// TODO: Re-layout Stages.
// SpriteBatches get resized to match the new aspect ratio,
// need to counteract this.
// http://stackoverflow.com/questions/14085212/libgdx-framebuffer-scaling
playerShipHullMonitor.setPosition( 0, hudStage.getHeight()-playerShipHullMonitor.getHeight() );
Matrix4 matrix = new Matrix4();
matrix.setToOrtho2D( 0, 0, width, height );
batch.setProjectionMatrix( matrix );
}
@Override
public void show() {
Gdx.input.setInputProcessor( inputMultiplexer );
}
@Override
public void hide() {
Gdx.input.setInputProcessor( null );
renderedPreviousFrame = false;
}
@Override
public void render( float delta ) {
if ( renderedPreviousFrame )
eventManager.secondsElapsed( delta );
eventManager.processEvents( context );
Gdx.gl.glClearColor( 0, 0, 0, 0 );
Gdx.gl.glClear( GL10.GL_COLOR_BUFFER_BIT );
if ( renderedPreviousFrame )
elapsed += delta;
mainStage.act( delta );
mainStage.draw();
batch.begin();
if ( driftSprite != null ) {
driftSprite.setPosition( 100+100*(float)Math.cos(elapsed), 100+25*(float)Math.sin(elapsed) );
driftSprite.draw( batch );
}
if ( walkAnim != null ) {
TextureRegion walkFrame = walkAnim.getKeyFrame( elapsed, true );
batch.draw( walkFrame, 50, 50 );
}
batch.end();
hudStage.act( delta );
hudStage.draw();
popupStage.act( delta );
popupStage.draw();
renderedPreviousFrame = true;
}
@Override
public void pause() {
renderedPreviousFrame = false;
}
@Override
public void resume() {
}
@Override
public void dispose() {
hudStage.dispose();
playerShipHullMonitor.dispose();
shipActor.dispose();
context.getAssetManager().unload( BKG_ATLAS );
context.getAssetManager().unload( ROOT_ATLAS );
context.getAssetManager().unload( MISC_ATLAS );
context.getAssetManager().unload( PEOPLE_ATLAS );
context.getAssetManager().unload( PLOT_FONT );
Pools.get( OverdriveContext.class ).free( context );
}
@Override
public OVDStageManager getStageManager() {
return stageManager;
}
@Override
public OVDEventManager getEventManager() {
return eventManager;
}
@Override
public OVDScriptManager getScriptManager() {
return scriptManager;
}
}