All you need is LÖVE. LÖVE 0.9 released

13. December 2013

 

Sorry for the bad pun, I really am.  Not sorry enough not to make it mind you!

Anyways… Love 0.9.0 was released today.  In case you haven’t heard of it, Love is a 2D Lua based game development framework that was previously featured in the Battle of the Lua Game Engines post.  From the release notes:

 

After a very long year-and-eight-months since the previous version’s release, LÖVE 0.9.0 is out at last!


The full changelog is massive, easily the biggest in LÖVE’s history (when counting by number of individual changes listed). It can be viewed down below as well as in the Wiki. Here are some of the more noteworthy items:
LuaJIT is now being used by LÖVE by default for most operating systems. Depending on what’s bottlenecking your game’s performance right now, your framerate could skyrocket just by updating to 0.9.0!


ENet: real-time networking in games is a complicated topic. Thankfully, people have created libraries to help deal with some of the lower-level nuts and bolts. One such library is ENet. LÖVE 0.9.0 includes the lua-enet wrapper for the ENet library (alongside the existing general-purpose LuaSocket library), so you can easily use ENet’s features in your games with require("enet").


love.joystick: previous versions of LÖVE had support for joysticks and gamepads, but the love.joystick module was lacking in some key areas.
Version 0.9.0’s joystick module has been completely revamped – Joysticks are now actual LÖVE objects, they can be hot-plugged and removed at will (with event callbacks to match), gamepad motor vibration is now supported, and issues with differences in gamepad buttons and axes across operating systems and gamepad models is now much easier to deal with thanks to the new abstracted Gamepad API.


Windows (not the Microsoft variety): functions for dealing with LÖVE’s window have been split from love.graphics into the brand-new love.windowmodule. The new module also includes new functionality (and better handling of the window in general, thanks to SDL 2): it’s now possible to use resizable, borderless, and “fullscreen-desktop” / “fullscreen-windowed” windows, as well as to choose which monitor the window will use.


love.graphics: Along with some general house-cleaning of this module and performance improvements to love.graphics.print, ParticleSystems, and SpriteBatches, lots of new graphics functionality has been added. Arbitrarily textured and colored polygons can be created thanks to Mesh objects.Shader objects (renamed from PixelEffects) can now be vertex shaders as well as pixel shaders. Mipmapping support has been added to images, compressed texture formats can be used now, and that’s only a handful of the new features in love.graphics.


love.math: Another new module! This one includes mathematical functionality relevant to games: a PRNG (and random number generator objects), polygon triangulation, Bézier curve objects, a Simplex noise generator, and more goodies.


love.thread: The thread module has an entirely new way to communicate between threads: Channel objects. It's much more flexible than the old API.
There are many more new features, but reading paragraphs about them can get tedious. Check them out on the wiki!


LÖVE 0.9.0 breaks compatibility with nearly every 0.8.0 game.


Several functions have been renamed (and some functionality has been changed or removed) in order to provide a more consistent and clean API experience. Often this will mean simply renaming some functions your game uses, but it will be rare for a game to work completely in both 0.8.0 and 0.9.0 unless it is written to do so.
Check the wiki! It will tell you what the new name of a renamed function is.


0.9.0’s Mac OS X system requirements are higher than 0.8.0’s: it now requires Mac OS 10.6+ and at least an Intel Core 2 CPU (~september 2006 or newer).

 

Full change log available here

Head on over here to get started.

News




OpenFL 1.2 released. Adds Tizen support

12. December 2013

 

OpenFL, the popular cross platform gaming library formerly known as NME have recently released version 1.2.  The biggest addition is Tizen support.  Full releaseimage notes are below:

 

We are happy to announce that OpenFL 1.2 is now available, and includes a brand-new platform target, Tizen!

Tizen is a new device platform, supported by Intel, Samsung, The Linux Foundation and other members of the Tizen Association. Through partnership with OpenFL Technologies, Tizen is helping support our development, so we can continue to create free and open-source software for you.

OpenFL 1.2 marks a transition, we have a brand-new library we are co-developing called “lime”, which we will speak more about in the future. We want to open our codebase to a wider audience, both to collaborate and to also enable further innovation in game frameworks and APIs. As we continue to invest into OpenFL, we are also opening doors to share the build tools and platform support of OpenFL across multiple frameworks.

In addition to Tizen support, we have made specific investment in streaming audio support, as well as other fixes and improvements. You will need some new libraries (“lime” and “lime-tools”) for this release, so run “openfl setup” again to be sure that you have everything you need to get going.

Other fixes include better multi-core support for parallel C++ builds, improved support for error output on mobile, we added “Assets.getMusic” for specifically requesting streaming audio (regardless of what is set in your project file), context lost events for Android when using OpenGLView (other platforms retain the GL context during a resize) and other audio fixes.

 

run ‘haxelib upgrade’ to get the newest version, otherwise head on over to the OpenFL webpage.

News




LibGDX Tutorial 3C: Scene management

11. December 2013

 

So far we’ve look at what Scene2D provides in terms of Actors, Actions as well as handling input, now we will look at some of the scene management functionality it provides.  One of the very powerful capabilities of Scene2D is grouping.  Let’s jump right in with an example.  In this example I used these two graphics:

jet(look, there is a space here!)flame

 

By the way, those are two different images.  One is a jet and the second is the engine exhaust.  Let,s take a look at grouping them together in a scene as a single transformable entity, a pretty common game development task.

 

 

package com.me.mygdxgame;

import com.badlogic.gdx.ApplicationListener;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.graphics.GL10;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.g2d.Batch;
import com.badlogic.gdx.graphics.g2d.TextureRegion;
import com.badlogic.gdx.scenes.scene2d.Actor;
import com.badlogic.gdx.scenes.scene2d.Group;
import com.badlogic.gdx.scenes.scene2d.Stage;
import static com.badlogic.gdx.scenes.scene2d.actions.Actions.*;


public class SceneManagementDemo implements ApplicationListener {
    
    private Stage stage;
    private Group group;
    
    @Override
    public void create() {        
        stage = new Stage(Gdx.graphics.getWidth(),Gdx.graphics.getHeight(),true);
        final TextureRegion jetTexture = new TextureRegion(new Texture("data/jet.png"));
        final TextureRegion flameTexture = new TextureRegion(new Texture("data/flame.png"));
        
        final Actor jet = new Actor(){
            public void draw(Batch batch, float alpha){
                batch.draw(jetTexture, getX(), getY(), getOriginX(), getOriginY(), getWidth(), getHeight(), 
                        getScaleX(), getScaleY(), getRotation());
            }
        };
        jet.setBounds(jet.getX(), jet.getY(), jetTexture.getRegionWidth(), jetTexture.getRegionHeight());
    
        final Actor flame = new Actor(){
            public void draw(Batch batch, float alpha){
                batch.draw(flameTexture, getX(), getY(), getOriginX(), getOriginY(), getWidth(), getHeight(),
                        getScaleX(), getScaleY(), getRotation());
            }
        };
        flame.setBounds(0, 0, flameTexture.getRegionWidth(), flameTexture.getRegionHeight());
        flame.setPosition(jet.getWidth()-25, 25);
        
        group = new Group();
        group.addActor(jet);
        group.addActor(flame);
        
        group.addAction(parallel(moveTo(200,0,5),rotateBy(90,5)));
        
        stage.addActor(group);
        
        
    }

    @Override
    public void dispose() {
        stage.dispose();
    }

    @Override
    public void render() {    
        Gdx.gl.glClear(GL10.GL_COLOR_BUFFER_BIT);
        stage.act(Gdx.graphics.getDeltaTime());
        stage.draw();
    }

    @Override
    public void resize(int width, int height) {
    }

    @Override
    public void pause() {
    }

    @Override
    public void resume() {
    }
}

 

When you run it, you will see:

SceneManagementCompressed

 

As you can see, once grouped, the attached actors inherit any transformations applied to the group.  The code in this example should be pretty straight forward at this point, not much new here.  First we load our two images as TextureRegions.  We then create an actor for each, in both cases setting it’s boundaries with setBounds() or it wont render correctly.  For each Actor we implement the full batch.draw() function to make sure rotation and scaling are properly rendered.  Finally for the flame texture, we set it’s position relative to the jet Actor.

 

Then we create a new Group object, this is the secret sauce behind Scene2D grouping.  Then instead of adding our two Actors to the Scene, we instead add them to the Group, which is then added to the Scene.  So that we can actually see something happening in this example, we apply a moveTo and rotateBy Action to our group.  We covered Actions in the last tutorial post if you want more details.  One important thing I didn’t show here is, it is possible to translate the individual Actors within the Group.

 

One other aspect of Scene2D is determining if a hit occurred.  Back in Scene2D Tutorial Part 1 we saw the touchDown function, which is called when an Actor within a Scene is touched.  Now we will briefly look at the logic driving this process.  The Stage’s hit() method is called, which in turn calls the hit() method of every Actor within the stage.  hit() passes in un-translated coordinates, making the process easier on the developer.  The default hit() method simply checks the bounding box of the Actor…  the following example instead checks the bounding circle… in case you had a say… circular object! Smile

 

package com.me.mygdxgame;

import com.badlogic.gdx.ApplicationListener;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.graphics.GL10;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.g2d.Batch;
import com.badlogic.gdx.graphics.g2d.TextureRegion;
import com.badlogic.gdx.scenes.scene2d.Actor;
import com.badlogic.gdx.scenes.scene2d.InputEvent;
import com.badlogic.gdx.scenes.scene2d.InputListener;
import com.badlogic.gdx.scenes.scene2d.Stage;
import com.badlogic.gdx.scenes.scene2d.Touchable;

import java.util.Random;

public class SceneManagementDemo implements ApplicationListener {
    
    // Create an Actor "Jet" that displays the TextureRegion passed in
    class Jet extends Actor {
        private TextureRegion _texture;
        
        public Jet(TextureRegion texture){
            _texture = texture;
            setBounds(getX(),getY(),_texture.getRegionWidth(), _texture.getRegionHeight());
            
            this.addListener(new InputListener(){
                public boolean touchDown(InputEvent event, float x, float y, int pointer, int buttons){
                    System.out.println("Touched" + getName());
                    setVisible(false);
                    return true;
                }
            });
        }

        // Implement the full form of draw() so we can handle rotation and scaling.
        public void draw(Batch batch, float alpha){
            batch.draw(_texture, getX(), getY(), getOriginX(), getOriginY(), getWidth(), getHeight(),
                    getScaleX(), getScaleY(), getRotation());
        }
        
        // This hit() instead of checking against a bounding box, checks a bounding circle.
        public Actor hit(float x, float y, boolean touchable){
            // If this Actor is hidden or untouchable, it cant be hit
            if(!this.isVisible() || this.getTouchable() == Touchable.disabled)
                return null;
            
            // Get centerpoint of bounding circle, also known as the center of the rect
            float centerX = getWidth()/2;
            float centerY = getHeight()/2;
            
            // Square roots are bad m'kay. In "real" code, simply square both sides for much speedy fastness
            // This however is the proper, unoptimized and easiest to grok equation for a hit within a circle
            // You could of course use LibGDX's Circle class instead.
            
            // Calculate radius of circle
            float radius = (float) Math.sqrt(centerX * centerX +
                    centerY * centerY);

            // And distance of point from the center of the circle
            float distance = (float) Math.sqrt(((centerX - x) * (centerX - x)) 
                    + ((centerY - y) * (centerY - y)));
            
            // If the distance is less than the circle radius, it's a hit
            if(distance <= radius) return this;
            
            // Otherwise, it isnt
            return null;
        }
    }
    
    private Jet[] jets;
    private Stage stage;
    
    @Override
    public void create() {        
        stage = new Stage(Gdx.graphics.getWidth(),Gdx.graphics.getHeight(),true);
        final TextureRegion jetTexture = new TextureRegion(new Texture("data/jet.png"));
        
        jets = new Jet[10];
        
        // Create/seed our random number for positioning jets randomly
        Random random = new Random();
        
        // Create 10 Jet objects at random on screen locations
        for(int i = 0; i < 10; i++){
            jets[i] = new Jet(jetTexture);
            
            //Assign the position of the jet to a random value within the screen boundaries
            jets[i].setPosition(random.nextInt(Gdx.graphics.getWidth() - (int)jets[i].getWidth())
                    , random.nextInt(Gdx.graphics.getHeight() - (int)jets[i].getHeight()));
            
            // Set the name of the Jet to it's index within the loop
            jets[i].setName(Integer.toString(i));
            
            // Add them to the stage
            stage.addActor(jets[i]);
        }
        
        Gdx.input.setInputProcessor(stage);
    }

    @Override
    public void dispose() {
        stage.dispose();
    }

    @Override
    public void render() {    
        Gdx.gl.glClear(GL10.GL_COLOR_BUFFER_BIT);
        stage.act(Gdx.graphics.getDeltaTime());
        stage.draw();
    }

    @Override
    public void resize(int width, int height) {
    }

    @Override
    public void pause() {
    }

    @Override
    public void resume() {
    }
}

 

 

When you run this app, 10 randomly located jet images will be drawn on screen. 

 

SceneManagement2Compressed

 

As you click each, it will disappear.  One important thing to realize is hit() is evaluated in reverse order objects are created.  So, the last object you add to the stage will be the first one hit() if more than one object occupy the same space.  The determining function whether a Jet has been touched or not is hit().  hit() works by creating a bounding circle to fit the image within, then checking to see if the mouse pointer is within the bounds of that circle.  When a hit occurs, we return the object hit, otherwise we return null.

 

The nice thing about this system is the user doesn’t have to worry about any translations applied to it’s parent or other translations that have occurred.  It’s also important to realize this is a pretty derived example.  If you removed the overriden hit() method, the default implementation would actually work better.  You do NOT need to provide a hit() method in your derived Actor classes unless the default doesn’t fit your needs.  This example is merely to show how the Scene2D hit detection works, and how to implement a custom detector.  Should you wish to say, implement pixel-perfect detection, you could do it this way.  I commented this example a bit more than I regularly do, to explain the bits I’ve glossed over.

Programming , ,




Learning Scala, found a great book

10. December 2013

 

So lately I’ve been working on my LibGDX tutorial series and I am certainly a fan of the library.  Java on the other hand, after years of using C#, just seems flawed.  Not that it is a bad language, just that it’s a bit kludgy.  Fortunately there are a number of languages built over top of the Java Virtual Machine, allowing you to make use of most of the Java eco-system, while working in a different language.  Some of the more popular options are Groovy, a scripting language that targets the JVM and Clojure, a functional LISP like language.  I don’t personally want a fully dynamic language ( I like typed languages for large projects ) so Groovy is out, while LISP might as well be Klingon.  I like some functional programming, but my brain just doesn’t work that way… to warped by years of procedural programming.

 

Fortunately there is Scala.

 

I’ve only just started playing with it but I am already impressed.  It’s almost as if someone took all the aspects of Java I dont like and set out to fix them.  Things I like:

  • runs on the Java VM, so can use libraries like LibGDX without issue but still feels familiar
  • type inference.  Feel like a dynamic language while staying dynamically typed.  I miss var from C#!
  • Functional programming lite.  High Order functions.
  • It’s got REPL ( command line programmability ) even if it’s faked.  Great way to learn the language.
  • Everything is an object, one of Java’s biggest warts
  • Pattern matching… it’s like an uber switch statement and looks to be a huge time saver
  • traits and sealed… I think.  Basically a trait is an interface with codability, while sealed allows a class to define which classes can extend it.  It will take some use, but both seem to solve commonly encountered problems, but both may have huge downsides.
  • makes the language much more compact while still feeling like Java.
  • operator overloading.  This was simply a stupid Java mistake.
  • best conditional expression evaluation I have ever seen.  Optional semi colons.

 

I'm still just at the beginner phase, but I have to say I’ve already had a ton of AHAH moments.  There are a few annoyances, at least initially.  For example, I dont like the variable coming after the variable name… there might be a huge win here somewhere, but it feels very unnatural coming from Java. 

 

Anyway, back when I started looking to catch up on Java I looked for a book that taught Java but did so making certain assumptions about the programmers experiences.  For example, I know what a class is, how a loop works, etc…  Sadly I never found such a book.  This time however, for learning Scala, I did.

 

Scala for the Impatient

cover This book is exactly what I was looking for when I was looking for a Java book for experienced programmers.  In the authors own words:

I wrote this book for impatient readers who want to start programming in Scala right away. I assume you know Java, C#, or C++, and I don’t bore you with explaining variables, loops, or classes. I don’t exhaustively list all the features of the language, I don’t lecture you about the superiority of one paradigm over another, and I don’t make you suffer through long and contrived examples. Instead, you will get the information that you need in compact chunks that you can read and review as needed.

From what I have read this is exactly true.  I have no prior Scala experience, but I have never found myself once struggling with any concepts presented in this book.  Nor frankly have I been bored, something I often struggle with for programming books.

I need to make something extremely clear.  If you do not have a solid prior programming foundation in C# or Java ( or possibly C++ ), this is not the book for you!  The book basically covers how Scala deviates from other languages, so if you don't know the fundamentals, you will struggle.  It is also not a language reference.  If you are new to programming or want a language reference, Programming in Scala is probably the book you want.

One other thing I really appreciate about this book is the authors writing style.  It’s an easy read and he has a sense of humour.  Here for example is his tip on operating overloading:

In Java, you cannot overload operators, and the Java designers claimed this is a good thing because it stops you from inventing crazy operators like !@$&* that would make your program impossible to read. Of course, that’s silly; you can make your programs just as hard to read by using crazy method names like qxywz. Scala allows you to define operators, leaving it up to you to use this feature with restraint and good taste.

That paragraph is pretty typical of how the book goes.

So I’m heading off on this Scala adventure in my spare time.  Expect a few related posts here and there as I go.

Programming ,




LibGDX Tutorial 3B: Simple Animation

9. December 2013

 

Back in Tutorial 3 I created a simple animation using a Timer and setting the frame manually from a TextureAtlas.  This is not the ideal way to perform animation using LibGDX and was done to illustrate how to use a TextureAtlas, not how to perform animation.  Instead the better way to perform animations is using the Animation class.  Here is an example using the same spritesheet from tutorial 3, remember you need to add it to the Android project assets folder.

 

package com.gamefromscratch;

import com.badlogic.gdx.ApplicationListener;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.graphics.GL10;
import com.badlogic.gdx.graphics.g2d.Animation;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.graphics.g2d.TextureAtlas;

public class AnimationDemo implements ApplicationListener {
    private SpriteBatch batch;
    private TextureAtlas textureAtlas;
    private Animation animation;
    private float elapsedTime = 0;
    
    @Override
    public void create() {        
        batch = new SpriteBatch();
        textureAtlas = new TextureAtlas(Gdx.files.internal("data/spritesheet.atlas"));
        animation = new Animation(1/15f, textureAtlas.getRegions());
    }

    @Override
    public void dispose() {
        batch.dispose();
        textureAtlas.dispose();
    }

    @Override
    public void render() {        
        Gdx.gl.glClearColor(0, 0, 0, 1);
        Gdx.gl.glClear(GL10.GL_COLOR_BUFFER_BIT);
        
        batch.begin();
        //sprite.draw(batch);
        elapsedTime += Gdx.graphics.getDeltaTime();
        batch.draw(animation.getKeyFrame(elapsedTime, true), 0, 0);
        batch.end();
    }

    @Override
    public void resize(int width, int height) {
    }

    @Override
    public void pause() {
    }

    @Override
    public void resume() {
    }
}

When you run it, you should see:

Animation

 

The key here is the Animation, created here:

animation = new Animation(1/15f, textureAtlas.getRegions());

When creating an animation you pass in the amount of time per frame ( 15 frames per second in this case ) and an array of TextureRegions.  These represent the individual frames of animation within the TextureAtlas.  In this particular example we are simply using all of the frames available within the Atlas as a single animation.  The next key change is:

elapsedTime += Gdx.graphics.getDeltaTime();

batch.draw(animation.getKeyFrame(elapsedTime, true), 0, 0);

Here we are simply drawing the current frame from the animation to the screen.  We pass in the amount of time that has elapsed so the animation knows where it is in the sequence.  The true parameter is telling it to loop the animation.

 

Of course, you can have multiple animations from a single texture Atlas.  Consider the spritesheet we are currently working with.  If you take a look at the .atlas file, you will see each individual frame is named:

image

 

Looking at the spritesheet, you will see the animations are organized like such:

spritesheet

 

What we want to do is treat this as two sepeate animations.  Frames 1 through 10 represent an upward roll, while 11-20 are a downward roll.  Let’s take a look at how we do that:

public void create() {        
    batch = new SpriteBatch();
    textureAtlas = new TextureAtlas(Gdx.files.internal("data/spritesheet.atlas"));
    
    TextureRegion[] rotateUpFrames = new TextureRegion[10];
    
    // Rotate Up Animation
    // Create an array of TextureRegions
    rotateUpFrames[0] = (textureAtlas.findRegion("0001"));
    rotateUpFrames[1] = (textureAtlas.findRegion("0002"));
    rotateUpFrames[2] = (textureAtlas.findRegion("0003"));
    rotateUpFrames[3] = (textureAtlas.findRegion("0004"));
    rotateUpFrames[4] = (textureAtlas.findRegion("0005"));
    rotateUpFrames[5] = (textureAtlas.findRegion("0006"));
    rotateUpFrames[6] = (textureAtlas.findRegion("0007"));
    rotateUpFrames[7] = (textureAtlas.findRegion("0008"));
    rotateUpFrames[8] = (textureAtlas.findRegion("0009"));
    rotateUpFrames[9] = (textureAtlas.findRegion("0010"));

    rotateUpAnimation = new Animation(0.1f,rotateUpFrames);
    
    // Rotate Down Animation
    // Or you can just pass in all of the regions to the Animation constructor
    rotateDownAnimation = new Animation(0.1f,
            (textureAtlas.findRegion("0011")),
            (textureAtlas.findRegion("0012")),
            (textureAtlas.findRegion("0013")),
            (textureAtlas.findRegion("0014")),
            (textureAtlas.findRegion("0015")),
            (textureAtlas.findRegion("0016")),
            (textureAtlas.findRegion("0017")),
            (textureAtlas.findRegion("0018")),
            (textureAtlas.findRegion("0019")),
            (textureAtlas.findRegion("0020")));

    Gdx.input.setInputProcessor(this);
}

 

As you can see, it’s easy to create multiple animations from a single TextureAtlas.  Keep in mind, when creating a TextureAtlas using TexturePacker, it was the filename that you passed in that created the region names.  So what you would generally do is name your separate animations accordingly, such as WalkLeft, WalkRight, etc. 

Programming , ,