Subscribe to GameFromScratch on YouTube Support GameFromScratch on Patreon
15. February 2015

 

LÖVE, a Lua based game engine I covered wayyyyy back in Battle of the Lua Game Engines and also featured in the game development for kids article, just announced release 0.9.2 just in time for Valentines day.  The announcement follows:

 

Here are a few big changes and highlights, and the full changelog, as well as download links can of course be found below, and on the wiki and front page respectively.


The full changelog is listed here:
  * Added Lua 5.3's UTF-8 module (via utf8 = require("utf8")).
  * Added Shader:getExternVariable.
  * Added several new canvas texture formats.
  * Added love.graphics.getCanvasFormats.
  * Added love.graphics.getCompressedImageFormats.
  * Added ParticleSystem:setQuads.
  * Added ParticleSystem:setLinearDamping.
  * Added SpriteBatch:flush.
  * Added love.graphics.getStats.
  * Added "mirroredrepeat" wrap mode.
  * Added love.audio.setDopplerScale and love.audio.getDopplerScale.
  * Added optional duration argument to Joystick:setVibration.
  * Added love.joystick.loadGamepadMappings and love.joystick.saveGamepadMappings.
  * Added Joint:setUserData and Joint:getUserData.
  * Added Joint:getBodies.
  * Added GearJoint:getJoints.
  * Added Contact:getFixtures and Body:getContactList.
  * Added Body:getWorld.
  * Added Body:getJointList.
  * Added Body/Contact/Fixture/Joint/World:isDestroyed.
  * Added love.mousemoved event callback.
  * Added love.mouse.setRelativeMode and love.mouse.getRelativeMode.
  * Added Scancode enums, love.keyboard.getKeyFromScancode, and love.keyboard.getScancodeFromKey.
  * Added love.window.getDisplayName.
  * Added love.window.minimize.
  * Added love.window.maximize.
  * Added love.window.showMessageBox.
  * Added 'refreshrate' field to the table returned by love.window.getMode.
  * Added love.window.toPixels and love.window.fromPixels.
  * Added love.window.setPosition and love.window.getPosition, and 'x' and 'y' fields to love.window.setMode and t.window in love.conf.
  * Added love.filesystem.isSymlink, love.filesystem.setSymlinksEnabled, and love.filesystem.areSymlinksEnabled.
  * Added love.filesystem.getRealDirectory.
  * Deprecated SpriteBatch:bind and SpriteBatch:unbind.
  * Deprecated all uses of the name 'FSAA' in favor of 'MSAA'.
  * Deprecated the 'hdrcanvas' graphics feature enum in favor of getCanvasFormats.
  * Deprecated the 'dxt' and 'bc5' graphics feature enums in favor of getCompressedImageFormats.
  * Fixed crashes when love objects are used in multiple threads.
  * Fixed love.filesystem.setIdentity breaking in some situations when called multiple times.
  * Fixed the default love.filesystem identity when in Fused mode in Windows.
  * Fixed love.system.openURL sometimes blocking indefinitely on Linux.
  * Fixed love.joystick.setGamepadMapping.
  * Fixed the order of vertices in ChainShapes.
  * Fixed love.mouse.getPosition returning outdated values if love.mouse.setPosition is used in the same frame.
  * Fixed love.graphics.newFont to error when given an invalid size argument.
  * Fixed the filename and backtrace given when love.graphics.print errors.
  * Fixed a small memory leak if love.graphics.newCanvas errors.
  * Fixed shader:getWarnings returning unnecessary information.
  * Fixed some cases of noncompliant shader code not properly erroring on some nvidia drivers.
  * Fixed a potential crash when Shader objects are garbage collected.
  * Fixed a potential small memory leak triggered when love.graphics.newShader errors.
  * Fixed love.graphics.newMesh(vertexcount, ...) causing the Mesh to do instanced rendering.
  * Fixed Mesh:getVertexMap.
  * Fixed Image:refresh generating mipmaps multiple times if mipmap filtering is enabled.
  * Fixed Image:setMipmapFilter to not keep bad state around if it errors.
  * Fixed Mesh:setDrawRange when the Mesh has a vertex map set.
  * Fixed internal detection of the 'position' and 'effect' shader functions.
  * Fixed Texture memory leak when Meshes are garbage collected.
  * Fixed the default line join mode to be 'miter' instead of an undefined value.
  * Fixed the default error handler text size when highdpi mode is enabled on a Retina monitor.
  * Fixed the default error handler background color when sRGB mode is enabled for the window.
  * Fixed love.window.setMode to fall back to the largest available mode if a width or height greater than the largest supported is specified and fullscreen is used.
  * Fixed the state of wireframe mode when love.window.setMode is called.
  * Fixed Canvas:getPixel to error if the coordinates are not within the Canvas' size.
  * Fixed detection of compressed textures to work regardless of the file's extension.
  * Renamed all cases of FSAA to MSAA. The FSAA names still exist for backward-compatibility.
  * Updated the Windows executable to automatically prefer the higher performance GPU on nvidia Optimus systems.
  * Updated the --console command-line argument in Windows to open the console before conf.lua is loaded.
  * Updated t.console and the --console command-line argument in Windows to use the existing Console window,if love was launched from one.
  * Updated the love executable to verify that the love library's version matches.
  * Updated the Lua wrapper code for modules to avoid crashes when the module's instance is created, deleted, and recreated.
  * Updated internal code for handling garbage collection of love objects to be more efficient.
  * Updated love's initialization code to trigger a Lua error if love.conf has an error in it.
  * Updated the paths returned by love.filesystem.getSaveDirectory and friends to strip double-slashes from the string.
  * Updated the error message when love.filesystem.write or File:open fails because the directory doesn'texist.
  * Updated the error message when love.math.setRandomseed(0) is attempted.
  * Updated the error message when invalid UTF-8 strings are used in love functions that expect UTF-8.
  * Updated love.physics.newPolygonShape and love.physics.newChainShape to accept a table of vertices.
  * Updated love.physics.newChainShape to error if the number of arguments is invalid.
  * Updated love.thread.newThread to accept a literal string of code directly.
  * Updated love-created threads to use names visible in external debuggers.
  * Updated SpriteBatch:unbind to use less VRAM if the SpriteBatch has the static usage hint.
  * Updated love.graphics.newImage, love.image.newImageData, etc. to leave less Lua-owned memory around.
  * Updated love.graphics.push to accept different stack types to push. Current types are "transform" and "all".
  * Updated love shaders to accept GLSL ES precision qualifiers on variables, although they do nothing.
  * Updated the error message for love.graphics.newShader to be less cryptic if an invalid filename is given.
  * Updated compressed texture loading code to allow BC6 and BC7 compressed textures (if the graphics driver supports them.)

And our downloads, also available on the home page are here:

 

The entire announcement is available on their forums here.  Perhaps most exciting is the 0.10 release, which adds official Android and iOS support.  Features I know many people have been waiting for.  For the record, there are unofficial Android and iOS ports already available.  This move will just make them part of the main distro.  Still a huge development when it happens.

News


13. February 2015

 

Nvidia just released version 4.5 of their NSight Visual Studio Edition graphics programming toolkit that I mentioned in the OpenGL resource roundup.

 

The follow are the major points of this new release:

New NVIDIA® Nsight™ Visual Studio Edition 4.5 Features:

Graphics Debugging and Profiling

  • Expanded OpenGL API support to include the 4.3 core profile features.

  • Added the capability for OpenGL applications to generate source code to replay captured frames outside of the original application. Allows users to compile and rerun the captured frame and share and modify generated code. 

  • Improved performance in Frame Debugger and Analysis Tracing modes by reduction of interception overhead, resulting in better interactivity and improved accuracy of data measurement.

  • Added a new Frame Statistics View that includes call counts for draw calls, dispatches, clears, etc.

  • Added a histogram control to the Resources View to visualize color channels and perform range remapping for visualization.

  • The Memory View can now export data to CSV or binary files.

Compute Debugging and Profiling

  • CUDA 7.0 RC

  • Several bug fixes

     

     

 

NVida Insight is completely free and can be downloaded here.  Obviously Visual Studio is required, but as it is now free that shouldn’t be a big problem.

News


12. February 2015
THIS POST IS A WORK IN PROGRESS!

 

 

If you are doing C++ development these days there are a number of IDEs available to make your life a great deal simpler.  Some are cross platform, some are required to supported certain targets.  But not all IDEs are created equal, and opinions differ on whats good and what isn’t.  Since we spend so much of our time buried in our IDEs, its worthwhile finding the one that fits you best.

 

What follows is a roundup of the available C++ IDEs.  Please keep in mind, an IDE and a Compiler aren’t the same thing.  Many of these IDEs use the same compilers behind the scenes.  Or often, such as with the Android NDK, a different compiler all together.  IDE is all about productivity… code editing, debugging, refactor, project management, etc.

 

 

No IDE

 

Of course, you don’t need an IDE.  This is a bit more appealing on CLI focused operating systems like Linux or even MacOS.  While on Windows, even with Cygwin or Powershell, the command line just isn’t as nice of a place to live.  Of course even on Windows you can download gcc or another free C++ compiler and work however you wish.  Visual Studio also has a command line option.  It is important to realize you do not NEED an IDE at all, although I personally wouldn’t want to live without one, especially when it comes to debugging.

 

If you go the no IDE route, you are going to need to provide your own C++ compiler.  If you are on Linux or Mac, you most certainly already have gcc installed.  The following is a list of common available C++ compilers that are available outside of an IDE.

 

gcc -  Gnu C Compiler - The daddy, the heart of open source. — https://gcc.gnu.org

cygwin — Cygwin — Not a C++ compiler, but a Unix like distro for Windows.  Contains gcc mentioned above but for Windows

mingw — MingW — Mininmal Gcc for Windows.  As the name suggests, it’s a gcc port for Windows.

clang — Clang — Increasingly more popular than gcc.  This is the C/C++ front end for...

llvm — LLVM — think of LLVM like a compiler provider.  You generally, won’t work at this level.  See clang :)

Digital Mars — Digital Mars — They make D now, but before they made C++ compilers for a very long time.  Not sure why you’d pick though

Intel C++ — Intel C++ — Paid product, pretty specialized

Visual C++ — Used to be available stand alone, or in Platform SDK.  Sadly it is no longer, so 10GB download for you!

 

There are more, but those are the common compilers.  The majority use gcc or clang on MacOS and Visual C++ on Windows in case you were wondering.

 

Now, if you go the IDE-less route, you are probably going to want an editor of some form.  Here are a few of the more commonly chosen options:

Emacs — Want a text editor with a learning curve as high as a mountain but with functionality to match?

Vim — Because you can’t have a war without two sides!  Vim vs Emacs, fight! 

(Truth is, I personally recommend neither of the above, too steep learning curve, too archaic… but I aint going down that road!)

Sublime Text — It’s simply Sublime.  It actually is, incredibly well named and one of the first installs on a new system for me.

Notepad++  — Windows only, but a potent editor with great plugin support.  Not quite sublime, more of a swiss army knife

Notepad — ‘cause back in my day we walked 20 miles in the snow, uphill, in both directions!  Seriously, just don’t.

 

 

C++ IDE List


 

AppCode

 

https://www.jetbrains.com/objc/

Platforms

Mac Os

Price

$199

AppCode is an IDE from JetBrains, the maker of IntelliJ as well as the popular ReSharper refactoring software.  This isn’t strictly a C++ IDE, it’s more a better Xcode which in my humble opinion was desperately needed.  It’s for Objective C, Swift and C++ development.  C++ is certainly not the focus, however there is very good C++ support.  On top as you might expect there is good refactoring support.  There is also a nicely integrated debugger, good code completion and more.  If you are familiar with IntelliJ, AppCode will be immediately comfortable.  Jetbrain have also started making a C++ IDE, which we will discus momentarily.

Screenshots

 

CLion

 

https://confluence.jetbrains.com/display/CLION/Early+Access+Program

Platforms

Linux

Mac OS

Windows

 

Price

None yet.

 

NOTE!  Lion is currently an EAP — Early Access Preview.  Basically it’s a beta.

Another IDE from JetBrains, this one is dedicated 100% to C++ development.  This product is in early release and eventually will be commercial paid software.  The basic idea behind CLion is to provide a C++ IDE that works equally across all platforms. If you are familiar with out JetBrain products, CLion will be instantly comfortable.  CLion is built over top of the popular CMake build system, this can present some challenges when trying to import projects that do not use CMake as their build system.  Of course once again you can expect excellent refactoring support.  CLion is expected to hit v1.0 release in early Q1 2015.

Screenshots

Programming


6. February 2015

 

This tutorial is available as an HD video here.

Today we are going to look at using audio with Godot.  If you’ve used other game engines you will find the process is probably quite a bit different and perhaps a little unintuitive but in the end rather simple and quite power.  It is a bit of a multistep process so let’s jump right in.

 

For this example you are going to need a couple audio files.  Personally I get most of the audio files for my tutorials from a site called http://www.freesound.org/.  Now a moment about audio formats.

 

The Two Kinds of Audio

 

There are two audio types in Godot ( and many other game engines ).  Samples and Streams.  A sample is an uncompressed piece of sound that is loaded into memory.  Samples take up more memory but a great deal less processing power.  In Godot you create samples by importing them as WAV files.  Streams on the other hand are instead compressed audio files (think MP3), often much longer in duration.  These you simply copy into your project, Godot supports MPC and Ogg Vorbis formats. 

 

Generally samples are used for in game quick sound effects, while streams are used for background music.  There is a pretty good chance your audio isn’t in WAV, Ogg or MPC format.  If it isn’t, I highly recommend the free program Audacity for converting between formats.

 

Playing an Audio Sample

 

As I said earlier, samples are uncompressed audio files generally used for sound effects and it’s a multistep process loading and playing one.  Its also quite common to play multiple of the sample sample at once.  Ok, let’s look at that process.

 

First you need to create a SamplePlayer.  This is a node you can add to your scene.  There are 3 kinds of players, SamplePlayer, SamplePlayer2D and SpatialSamplePlayer.  They all accomplish the same thing, however 2D has additional stereo support and can be positioned in your 2D world, while Spatial enables you to position your audio source in 3D to simulate positional audio.  In this tutorial we are just going to use the simple SamplePlayer.  We may cover the other two in later tutorials.

 

Creating the SamplePlayer Node

Add a new SamplePlayer node to your scene:

image

 

 

Creating a new SampleLibrary

 

Now we need to create a Sample library.  With your SamplePlayer selected in the Scene panel, in Inspector locate Samples, drop in down and select New SampleLibrary:

image

 

Now drop it down again and select Edit:

image

 

This will change your active view to the samples library view.  Note, the tabs above ( 2d, 3d, etc ) will not navigate you out of this screen currently.  To get back to your 2D scene view, select a different node in the Scene panel to the right.

image

 

Importing an Audio Sample

 

We can now use this window to add our samples to the library… guess we need a sample.  For that you use the Import menu.  Select Import->Audio Sample:

image

 

This will bring up an Import Audio Samples dialog like so:

image

Under source, navigate to the WAV file you want to import.  For target path select the location within your project you want it to reside.  Under options you have several configuration settings, such as changing the amount of data used/fidelity of your sound ( Max Rate Hz ), making it Mono vs Stereo or forcing it to be 8bit, which is a really low fidelity, single channel but tiny audio file.  For now just use the default settings.  When you click Import a new “smp” file will be added to your project:

image

 

Adding Sample to Audio Library

 

Now that we have our sample, we need to add it to our library.  You can use the same sample in multiple libraries.  In the Edit Sample window select the open icon:

image

 

Select your newly imported sample.  It should now appear in the list like so:

image

Here you can preview the sample, change it’s default volume using dB (decibel) or change it’s pitch using the PScale value.  You can add multiple samples to the sample library.  The yellow blob you see in the middle of the screen is the waveform of the audio… there are two of them because this is a stereo example.  As you can see by the fact they are identical waveforms, this is actually really wasteful, so you would be best to save the file size and import this as a mono sample instead!

 

Playing an Audio Sample using SamplePlayer

 

Now that we have an SampleLibrary with a sample in it, we can now go ahead and play it.  Let’s add a script to our SamplePlayer node that will automatically play the sound when we begin.  It’s incredibly simple, like so:

extends SamplePlayer


func _ready():
   play("siren")

Yeah... that's it.  You simply call the play method of SamplePlayer and pass in the name as defined in the Sample Library.

 

Of course, rarely are you going to have a SamplePlayer play it’s own sounds.  What is much more likely is you would add a SamplePlayer to the base of your scene tree, then call it from child nodes within the scene.  Don’t worry, that is equally simple… let’s do it!

 

Add a Button Node to your scene, attach a script to it, then hit the Connections icon and create a default handler for the “pressed()” connection.

image 

image

 

Generally you wouldn’t use the SamplePlayer as the root scene node, but that’s what I’ve got so I went with it…  Now in your button handler, you can get a reference to the SamplePlayer using:

 

extends Button

func _ready():
   pass


func _on_Button_pressed():
    get_tree().get_root().get_node("SamplePlayer").play("siren")

 

One important thing to be aware of…  the value passed into play() is case sensitive!  So if I passed in “Siren” it wouldn’t play anything!  So basically playing a sample is simply a matter of getting a reference to the SamplePlayer node and calling the play method.

 

So… that’s how you play a single sound… how do you play multiple at once… well, that’s a matter of voices.  A Voice can be thought of as a playing instance of a single sound.  If you want multiple sounds to play at once, you need multiple voices in your SamplePlayer.  You can set that value in the Inspector of the player, like so:

image

 

Now when you run the application, each time you click the button a new version of your sound effect will start playing concurrent to the previous version.  What if you only want a single instance of a sound effect to play at a time?  Well that can be done too…  when you call play() there is an optional second parameter that tells Godot wether the sound is unqiue or not.  Set it to true, like so:

 

get_tree().get_root().get_node("SamplePlayer").play("siren",true)

And each time your press the button the sound effect will instead start over.

 

One final critical thing to understand is how to manipulate ( stop, pause, change volume, etc… ) a single instance of a sound playing.  This is done using Voice IDs, once of which is returned when you play a sample.  So the following example plays a sound and immediately sets it’s volume to 50%:

 

func _on_Button_pressed():
   var player = get_tree().get_root().get_node("SamplePlayer")
   var voiceID = player.play("siren")
   player.set_volume(voiceID, 0.5)
   

 

So you used the voice ID to interact with already running samples.  These only last as along as the sample is playing.

 

Playing Music

 

Now let’s look at streaming a file instead.  The process is very similar, but instead you add a StreamPlayer node:

image

 

Now copy an MPC or OGG file into your project file folder using Windows Explorer or Mac Finder.  Now in Inspector with StreamPlayer selected, locate the Stream property and select the appropriate type, I’m using AudioStreamOGGVorbis:

image

Now drop it down again and select Load:

image

 

Select the file you copied into your project.  Attach a script to a Node in your Scene… for demo reasons I’m just adding it to the StreamPlayer itself.  Then you can use the code:


extends StreamPlayer


func _ready():
   self.play()

 

You don’t actually need code to accomplish this.  If you want the StreamPlayer to play it’s song automatically, you can simply set the Autoplay property:

image

 

Now one really common thing to do in games is to play a different song after the current song finished playing… let’s take a look at how you can accomplish this:

 

extends StreamPlayer

var song1
var song2
var currentSong = song1

func _ready():
   set_process(true)
   song2 = load("song2.ogg")
   
func _process(delta):
   if(self.is_playing() != true):
      if(self.get_stream() == song1):
         self.set_stream(song2)
      else:
         self.set_stream(song1)
      self.play()

 

 

The Video Version

 

Programming


3. February 2015

 

In this next part in the ongoing LibGDX Video tutorial series, we take our final look at the Scene2D library.  Specifically we look at using Scene2D to provide a UI, including buttons, windows, layout containers and more.  We also look at how to mix “normal” and Scene2D games together. 

 

The video is available in full HD here.  The source code from the examples is below the video:

 

Example 1

package com.gamefromscratch;

import com.badlogic.gdx.ApplicationAdapter;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.graphics.GL20;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.scenes.scene2d.InputEvent;
import com.badlogic.gdx.scenes.scene2d.Stage;
import com.badlogic.gdx.scenes.scene2d.ui.Dialog;
import com.badlogic.gdx.scenes.scene2d.ui.Skin;
import com.badlogic.gdx.scenes.scene2d.ui.TextButton;
import com.badlogic.gdx.scenes.scene2d.utils.ClickListener;
import com.badlogic.gdx.utils.Timer;
import com.badlogic.gdx.utils.viewport.ScreenViewport;

public class Scene2DUiDemo1 extends ApplicationAdapter {
   private Skin skin;
   private Stage stage;
   
   @Override
   public void create () {
      skin = new Skin(Gdx.files.internal("uiskin.json"));
      stage = new Stage(new ScreenViewport());

      final TextButton button = new TextButton("Click Me",skin,"default");
      button.setWidth(200);
      button.setHeight(50);

      final Dialog dialog = new Dialog("Click Message",skin);

      button.addListener(new ClickListener(){
         @Override
         public void clicked(InputEvent event, float x, float y) {
            dialog.show(stage);
            Timer.schedule(new Timer.Task() {
               @Override
               public void run() {
                  dialog.hide();
               }
            }, 10);
         }
      });
      stage.addActor(button);

      Gdx.input.setInputProcessor(stage);
   }

   @Override
   public void render () {
      Gdx.gl.glClearColor(0, 0, 0, 1);
      Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
      stage.act(Gdx.graphics.getDeltaTime());
      stage.draw();
   }


}

Example 2

package com.gamefromscratch;

import com.badlogic.gdx.ApplicationAdapter;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.graphics.GL20;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.scenes.scene2d.InputEvent;
import com.badlogic.gdx.scenes.scene2d.Stage;
import com.badlogic.gdx.scenes.scene2d.ui.*;
import com.badlogic.gdx.scenes.scene2d.utils.Align;
import com.badlogic.gdx.scenes.scene2d.utils.ClickListener;
import com.badlogic.gdx.utils.Timer;
import com.badlogic.gdx.utils.viewport.ScreenViewport;

public class Scene2DUiDemo1 extends ApplicationAdapter {
   private Skin skin;
   private Stage stage;

   private Table table;
   private TextButton startButton;
   private TextButton quitButton;
   
   @Override
   public void create () {
      skin = new Skin(Gdx.files.internal("uiskin.json"));
      stage = new Stage(new ScreenViewport());
      table = new Table();
      table.setWidth(stage.getWidth());
      table.align(Align.center | Align.top);

      table.setPosition(0,Gdx.graphics.getHeight());
      startButton = new TextButton("New Game",skin);
      quitButton = new TextButton("Quit Game",skin);

      table.padTop(30);

      table.add(startButton).padBottom(30);

      table.row();
      table.add(quitButton);

      stage.addActor(table);
      Gdx.input.setInputProcessor(stage);
   }

   @Override
   public void render () {
      Gdx.gl.glClearColor(0, 0, 0, 1);
      Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
      stage.act(Gdx.graphics.getDeltaTime());
      stage.draw();
   }


}

 

Example 3

package com.gamefromscratch;

import com.badlogic.gdx.ApplicationAdapter;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.InputMultiplexer;
import com.badlogic.gdx.InputProcessor;
import com.badlogic.gdx.graphics.GL20;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.g2d.Sprite;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.scenes.scene2d.InputEvent;
import com.badlogic.gdx.scenes.scene2d.Stage;
import com.badlogic.gdx.scenes.scene2d.actions.RepeatAction;
import com.badlogic.gdx.scenes.scene2d.ui.*;
import com.badlogic.gdx.scenes.scene2d.utils.Align;
import com.badlogic.gdx.scenes.scene2d.utils.ClickListener;
import com.badlogic.gdx.utils.Timer;
import com.badlogic.gdx.utils.viewport.ScreenViewport;

public class Scene2DUiDemo1 extends ApplicationAdapter implements InputProcessor {
   private Skin skin;
   private Stage stage;

   private Table table;
   private TextButton startButton;
   private TextButton quitButton;

   private SpriteBatch batch;
   private Sprite sprite;
   
   @Override
   public void create () {
      skin = new Skin(Gdx.files.internal("uiskin.json"));
      stage = new Stage(new ScreenViewport());
      table = new Table();
      table.setWidth(stage.getWidth());
      table.align(Align.center | Align.top);

      table.setPosition(0,Gdx.graphics.getHeight());
      startButton = new TextButton("New Game",skin);
      quitButton = new TextButton("Quit Game",skin);

      startButton.addListener(new ClickListener() {
         @Override
         public void clicked(InputEvent event, float x, float y) {
            Gdx.app.log("Clicked button","Yep, you did");
            event.stop();
         }
      });

      table.padTop(30);

      table.add(startButton).padBottom(30);

      table.row();
      table.add(quitButton);

      stage.addActor(table);



      batch = new SpriteBatch();
      sprite = new Sprite(new Texture(Gdx.files.internal("badlogic.jpg")));
      sprite.setSize(Gdx.graphics.getWidth(),Gdx.graphics.getHeight());

      Timer.schedule(new Timer.Task() {
         @Override
         public void run() {
            sprite.setFlip(false,!sprite.isFlipY());
         }
      },10,10,10000);


      // ORDER IS IMPORTANT!
      InputMultiplexer im = new InputMultiplexer(stage,this);
      Gdx.input.setInputProcessor(im);
   }

   @Override
   public void render () {
      Gdx.gl.glClearColor(0, 0, 0, 1);
      Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);

      batch.begin();
      sprite.draw(batch);
      batch.end();

      stage.act(Gdx.graphics.getDeltaTime());
      stage.draw();
   }


   @Override
   public boolean keyDown(int keycode) {
      return false;
   }

   @Override
   public boolean keyUp(int keycode) {
      return false;
   }

   @Override
   public boolean keyTyped(char character) {
      return false;
   }

   @Override
   public boolean touchDown(int screenX, int screenY, int pointer, int button) {
      sprite.setFlip(!sprite.isFlipX(),sprite.isFlipY());
      return true;
   }

   @Override
   public boolean touchUp(int screenX, int screenY, int pointer, int button) {
      return false;
   }

   @Override
   public boolean touchDragged(int screenX, int screenY, int pointer) {
      return false;
   }

   @Override
   public boolean mouseMoved(int screenX, int screenY) {
      return false;
   }

   @Override
   public boolean scrolled(int amount) {
      return false;
   }
}

 

uiskin.json

// @formatter:off
{
  com.badlogic.gdx.graphics.g2d.BitmapFont: { default-font: { file: Razer.fnt } },
  com.badlogic.gdx.scenes.scene2d.ui.TextButton$TextButtonStyle: {
   default: { down: default-round-down, up: default-round, font: default-font },
  },
  com.badlogic.gdx.scenes.scene2d.ui.Window$WindowStyle: {
    default:  {
      titleFont: default-font
     }
   }
}

Programming


AppGameKit Studio

See More Tutorials on DevGa.me!

Month List