HaxeFlixel Tutorial – Camera Zoom Revisited

In the previous post, I wrote a tutorial on how to zoom the camera in a hack-ish way. Turns out the original author of Bullet Time Ninja article, Greg Lieberman, already fixed that with a haxeflixel-addon class, the FlxZoomCamera. If you look at the API page, you’ll notice that it doesn’t say much, so let’s explore that today.

Setup

I learned from a recent HaxeFlixel tweet that you can create a new HaxeFlixel “barebones” project template, which has minimal files/folders, and also excludes all the config and comments:

Notice that the usual MenuState.hx file is now missing — the entry point is now PlayState.hx, which makes more sense. We’ll be using the barebones template for tutorials from now on. 🙂

Before we proceed, let’s change some configs — notice the difference of Main.hx (between barebones and non-barebones). The config variables and comments are now missing, and entry point (the last line) relies on the default values (Refer to the API):

Anyway, to change the resolution of the screen, do it in Main.hx :

… and to change the size of the window screen, do it in Project.xml :

To use the FlxZoomCamera class, which belongs to the flixel-addons haxelib, we need to enable it in the Project.xml, by uncommenting the line below:

And now we can start coding!

Code

Let’s set up the code similar to the previous tutorial:

And when you run with lime test neko , you will get a player that moves in a placeholder map:

licecap-zoomcamera2

Now let’s use the FlxZoomCamera addon:

And when we test :

licecap-zoomcamera2-2

Hmm, when you zoom out, the camera behaves in a peculiar way — the camera moves along with the player’s movement.

If you refer to the FlxZoomCamera API, there doesn’t seem to be anything you can modify that can change the way the camera moves when you’re zoomed out.

However, if you look into the FlxZoomCamera.hx file (on OSX, it’s located at /usr/lib/haxe/lib/flixel-addons/1,1,0/flixel/addons/display), you’ll notice there are actually two private variables that seem better off as public:

You can just make these public , and you can now play around with the value in your game, perhaps like this:

And the result:

licecap-zoomcamera2-3

Note the zoom speed has reduced greatly. Also, when zoomed out, the camera doesn’t seem to move around too much when the player moves.

_zoomSpeed  sounds self-explanatory, but what exactly is _zoomMargin ? I don’t really know. I don’t understand what value it should be, but after some tinkering, it seems to be a range between -1.6 to 1.6. So if you want the camera to not move when zoomed out, just set _zoomMargin  to a big value (e.g. 1.7) and it will probably work.

Otherwise, you may need to extend or rewrite the FlxZoomCamera.hx‘s  alignCamera()  function to suit your needs.

This concludes the revisited tutorial on zooming the camera.

HaxeFlixel Tutorial – Fullscreen/Window & Scale Modes

Each game may have different screen resolutions, to cater for different physical screen sizes. The most obvious example is the mobile device — there’s just too many screen sizes to worry about. We’ll explore this in today’s tutorial.

Full Screen / Windowed Mode

If you want to toggle between windowed and full-screen mode in HaxeFlixel, you can just use this code snippet:

As noted in the FlxG API, this only works on cpp and flash (and neko) targets. Android and iOS targets naturally don’t need this because they’re already full screen.

Screen Scale Modes

The HaxeFlixel’s ScaleModes demo indicates that this is possible.

To illustrate the a potential problem with screen scale modes, first let’s take a look at an example of a game screen without problem:haxeflixel-scalemodeThe above image assumes that when you make a game at 4:3 ratio, it would fit snugly when you upscale it. However, if we were to enter full-screen, how would it look like — especially on Android devices, where their screen sizes and resolutions differ greatly?

haxeflixel-scalemode-2

In most cases, we want the game’s resolution to be independent from the physical screen size, or at least have it scale gracefully with correct ratio.

By default, HaxeFlixel’s game resolution scales by ratio. This means, if you resize your window, the game maintains ratio rather than stretching to fit the screen, like this:

haxeflixel-scalemode-3

This scale mode is sufficient for most cases, but HaxeFlixel has a few other scale modes we can apply, through flixel.system.scaleModes  (Refer to API).

I’ve written a sample HaxeFlixel project below for you to explore and experiment with the scaleModes.

Create a new HaxeFlixel template project:

Create a map data file “sample-large-map.csv” in /assets/data  folder:

Add the following code in MenuState.hx:

Test the game:

Here’s a GIF to demonstrate the test:

licecap-scalemode

Notes:

  • There is a BaseScaleMode , which can be extended into subclasses, as seen in the API page. The default behaviour of BaseScaleMode seems to be the same as FillScaleMode .
  • Using StageSizeScaleMode  will cause all the other scale modes to break. We could dive into the code to fix it, but to avoid any issues, it’s best to avoid StageSizeScaleMode.
  • FixedScaleMode  and PixelPerfectScaleMode  are similar. The difference is, FixedScaleMode maintains a fixed 1:1 pixel ratio, whereas PixelPerfectScaleMode will upscale to 2:1 or even 3:1 if the screen size is big enough.

This concludes the tutorial on screen sizes.

HaxeFlixel Tutorial: Mask

Announcement: I’m entering crunch-time for a game project I’m working on. Hopefully it’ll finish by early August. I may not be able to update on the regular weekends, but I will try.

I’m a fan of image manipulation, but I can’t comprehend the math behind it all. In fact, before writing this tutorial, I spent about 4 hours researching and troubleshooting masking in HaxeFlixel.

We’re going to cover image masking today. I apologise in advance if the information below are inaccurate or inefficient. I’d appreciate any corrections or suggestions — just comment below this post and I’ll get back to you.

Introduction

There are two scenarios I could think of, when masking is necessary:

  • Taking an image and masking it with another image
  • Cutting a hole with a mask image (reverse masking)

As such, we shall proceed with the tutorial with the above two methods as our goal.

Setup

Let’s setup our HaxeFlixel project, as usual:

As for placeholder assets, we shall be using the images included in the Flixel Power Tool Test Suite Github page (Note: cloning didn’t work for me, so I had to download the ZIP file instead).

Masking with two images

PhotonStorm’s Power Flixel Tools allows image masking, as demonstrated in the demo page (specifically, the FlxDisplay page). Thankfully, it was ported to HaxeFlixel under the  flixel.util.FlxSpriteUtil  library.

Let’s start off with loading the two images in MenuState.hx:

And if you build with lime test neko , you’ll get this:

Screen Shot 2015-05-24 at 8.01.12 PM

The output is straight-forward — there’s no masking yet. To mask the two images, you need to merge them into a result FlxSprite, and add that to the stage, like this:

The above code produces this result:

Screen Shot 2015-05-24 at 8.04.15 PM

Note two issues with the output:

  • The x/y position of the base  and mask  FlxSprites doesn’t seem to affect the result  FlxSprite. It merges at the origin top-left point (0,0) by default.
  • The base  image’s transparency isn’t preserved after merging (note the pink background for the character)

As of writing, I couldn’t figure out how to easily fix the above issues. If you need a solution for the issues mentioned, my only suggestion for now is to use your favorite image editor (e.g. Photoshop) and create your desired masked/transparent PNG instead.

Reverse masking

This example seems to be most common. Let’s rewrite the existing code in MenuState.hx:

And the result is as follows:

Screen Shot 2015-05-24 at 8.24.32 PM

Note the curtain  is a semi-transparent black rectangle that covers the whole screen. Let’s say we want to cut a hole where the player and dummy is, perhaps we’d do it like this:

But the result doesn’t seem to be as expected:

Screen Shot 2015-05-24 at 8.34.26 PM

There are three problems with the above output:

  • The circle mask has the same issue as mentioned in “Masking with two images” section above — the base image (the curtain) lost its transparency, which results in a solid white circle.
  • The circle is supposed to be transparent, not opaque.
  • The circle mask does not follow the player’s movement.

Luckily, I managed to find a solution for the above mentioned. First, let’s fix the circle mask:

Note the  invertedAlphaMaskFlxSprite  function, which is a little hack based on the existing  FlxSpriteUtil.alphaMaskFlxSprite  function, as explained from the forum page here. The result is as follows:

Screen Shot 2015-05-24 at 9.03.32 PM

Now let’s make the circle follow the player:

But the result is undesired (or perhaps desired, depending on your intention):

licecap-mask

What exactly is happening? After I did some tinkering, here’s the explanation I could come up with:

  • All FlxSprite images are cached, whether it’s created with makeGraphic  or loaded with loadGraphic .
  • When an image is cached, doing a  makeGraphic  (using the same shape and color) or loadGraphic  (using the same image path) will result in the cached image being used, instead of a new image.
  • In the above code, we tried to create a newMask  FlxSprite, then load the _curtain ‘s image data into it. We assumed the _curtain ‘s image is uncut, which is true. However, the _mask ‘s bitmap data has been cached, so the cached image is used, resulting in the _mask  being continuously re-cut and updated instead.

The first solution I would think of, was to do a clone of the bitmapData instead, which means we don’t use the cached image:

Now, if you test the game, it works as expected; The circle mask now follows the player. However, this is actually a bad idea:

Screen Shot 2015-05-24 at 9.35.43 PM

Note the deteriorating FPS (green chart) and increased memory usage (blue chart).

From what I can tell, the newMask  FlxSprite ends up caching the unique _curtain ‘s bitmapData. This means, with every update()  cycle, a new image is created and cached — eventually, memory will run out and the game will freeze.

To fix this issue, we have to dive deeper into the bitmapData — this is where newbies like me start getting uncomfortable for using image-manipulating API:

Now if you run the game, the performance no longer deteriorates:

Screen Shot 2015-05-24 at 9.51.30 PM

And to wrap things up, we could draw more circles to the single mask, which allows for custom-shaped cut-outs, as demonstrated below:

licecap-mask-2

Note the above GIF, where the circles do not end up overlapping one another.

I also found and article that says the code doesn’t work for flash target as noted here. However, I just tested it with lime test flash -web  and it seems to work fine.

This concludes the tutorial on masking. If I discover a solution for the issues mentioned in the “Masking with two images” section above, I’ll update this post.

Addendum: I found an amazing tutorial that may be relevant, and I highly recommend you check it out:

Sight & Light: how to create 2D visibility/shadow effects for your game

HaxeFlixel Tutorial – Camera Zoom

@mikeevmm tweeted me early this month and noted that there are some problems with FlxCamera.

Here are some known issues I could identify:

  1. Camera doesn’t follow well when zoomed.
  2. Objects start disappearing when zoom is less than 1.

The problems above are apparent (as of writing) even in the FlxCamera demo.

There’s an article by Bullet Time Ninja that discusses and resolves the camera issue, but it’s from 2011 and uses Flixel (not HaxeFlixel), so the result may differ.

Today’s tutorial will attempt to resolve the first problem stated above. If there is a solution for the second problem, I’ll write a tutorial to address that next time. 🙂

Setup

As usual, let’s setup a new HaxeFlixel template project for testing:

Code

First, let’s set an arbitrary resolution of the game in the Main.hx file:

Now, let’s go into MenuState.hx (the default entry point for the game) and create a large-enough level with a movable character:

Now if you run the game with lime test neko , you’ll get a player that can move around a placeholder map, and the camera follows it, within the map’s bounds (btw, yes, there is no collision logic):

licecap-cam-1

Now let’s add some debug controls to recreate the problems mentioned at the beginning of the article above:

Now if you test the game — Zooming in and out will only zoom the camera’s viewport. The camera still “follows the player”, but not in a way you would expect:

licecap-cam-2

When we use  camera.zoom , it seems we’re actually resizing the camera’s viewport. So how can we fix this? With my limited knowledge, I’d assume the solution is to reposition and resize the camera every time its zoom is changed.

Before we do that, let’s add more debug input into the code so we can later understand what needs to be used to fix the problem:

Now if you play around with the debug keys above, you’ll notice the following points:

  • Changing the camera’s x  or y  value will move the viewport’s origin (top-left corner).
  • Changing the camera’s width  or height  value will increase/decrease the viewport’s size.
  • Changing the viewport size doesn’t seem to update the tilemap’s size, until we use level.updateBuffers() (by pressing P).
  • The camera’s deadzone (when following the player) isn’t updated, until we re-follow the player (by pressing O).

Resolving Camera Zoom issue

After some testing with the debug keys above, it seems we can combine the techniques and resolve the zoom issue, by writing the following code:

Now when you zoom in or out, the camera is centered and the player’s deadzone is updated:

licecap-cam-3

Notice that the player will get cropped when moving out of the map’s bounds. That’s because we used  FlxG.camera.setBounds() . If you modify the following lines:

The player can now freely move around in the camera without being cropped, at the expense of not having any map boundaries:

licecap-cam-4

To top things off, let’s use Bullet Time Ninja’s technique in lerping the camera’s zoom:

And the result:

licecap-cam-5

It’s not perfect, but I think this should be enough for most camera-zooming issues. This concludes the tutorial on zooming the camera.

HaxeFlixel Tutorial – Image Trail / Blur effect

Trails are more like after-images of a parent image. Some may refer to this as a blur effect. The HaxeFlixel FlxTrailArea demo demonstrates this.

An example usage would be in a Breakout clone, as demonstrated in this video Juice it or lose it (at the 11:50 mark). It’s not relevant, but I recommend watching this video on how to improve your game’s overall feel. 🙂

Setup

Let’s create a new HaxeFlixel template project, as usual:

And let’s assume we’re using the same image from the previous tutorial, the sparkle.png, and it’s located in the /assets/images  folder.

To use the FlxTrail and FlxTrailArea classes, you need to enable them in the Project.xml file:

And finally, for visibility sake, let’s set the screen resolution in Main.hx:

Code

And now let’s quickly write the code in MenuState.hx:

This gives you the result when built in lime test neko :

licecap-trail-1

Would FlxTrail have performance issues if we had hundreds of balls that bounce around in a screen, and each of them has a trail? This is where FlxTrailArea can be used:

If you test the game now, you’ll see no difference. But at least now you know, that you can add  as many sprites as you like to be trailed in the FlxTrailArea, rather than individually creating attaching a trail using FlxTrail.

Minor note: Referring to the FlxTrailArea API, if no parameters were given in new() , the size of the trail images will  be the full screen.