Monday 27 May 2013

Fitting the game to in any screen resolution.

For my Beekyr Android game it all started as 720p as it would be a Flash game,  but then I realized that the game needed to work in 800x480  for my smartphone... After that, I realized I needed to make it work in more resolutions for the rest of all Android phones out there. I had to think a way to scale the game and assets.... Turned out that is wasn't that hard!
 
Basically, I had to work always with 720p in mind.

When the game loads I need to work out a conversion rate for the resolution. So first lines of code executed, even before the engine :

        public static const ORIGINAL_X:int= 1280;
        public static const ORIGINAL_Y:int = 720;
        public static var SCREEN_X:int;
        public static var SCREEN_Y:int;
      
        public static var REDUCTION_RATIO:Number;
    

   private function getReductionRatio():void
        {
           &nbspSCREEN_X = Capabilities.screenResolutionX;
           &nbspSCREEN_Y = Capabilities.screenResolutionY;
            var ratioX:Number = SCREEN_X / ORIGINAL_X;
            var ratioY:Number = SCREEN_Y / ORIGINAL_Y;

            if (ratioX < ratioY) {
                REDUCTION_RATIO = ratioX;
            }else {
                REDUCTION_RATIO = ratioY;  
            }
        }

Then apply this REDUCTION_RATIO variable to every loaded asset, positions,speeds and basically everything that involved pixels.

Examples:
params.height = size.w*REDUCTION_RATIO;
params.width = size.h*REDUCTION_RATIO;
_bulletSpeed = 38*REDUCTION_RATIO;


If using AssetManager, all the stretching will be done for you if you initialize it like this:
assetsManager = new AssetManager (1 / GameVars.REDUCTION_RATIO, false);

But if you are converting textures manually then convert them like this:
Texture.fromBitmap(bitmap,false,true,1/GameVars.REDUCTION_RATIO);
This will still use same amounts of Texture Memory in 720 than 480 or 320. If you have troubles with that , load different assets that are smaller and change the REDUCTION RATIO.

In my case, load / unload assets between stages, works well too.
I never reached 128MB of VRAM (more or less, the minimum memory these days: ipad1).

It takes time and real concentration to make it work well but when is done it works flawlessly.

Enjoy.

Tuesday 21 May 2013

Career Shift : from Flash websites to AIR apps

I have been developing websites since 2004, I immediately jumped into Flash when I knew about it. This plug-in let me do really amazing things when you compared it with the HTML3-4 limits...

I worked for years as Flash developer along with very few PHP jobs. But Flash was becoming stronger. It was a solid OOP language and very tested plug-in without hardly any flaws.... until Steve Jobbs told otherwise and everyone believed him, they didn't realize it was all a war between Apple and Adobe, and everybody lost. Only the apple man won his own personal fight.

With all of this in mind I tried to make a game in Flash 10. I wanted to add many graphics and effects but I couldn't get anything very complex working due the lack of GPU acceleration. So I left the game in a playable state, but it was too simple. I had to discard the idea of making complex flash games.

Meanwhile Adobe didn't know how to handle the fight with Apple. Nevertheless Adobe released the best update ever made for flash: molehill - Stage3D. It was the beginning of triple A games in Flash. But it was all obscured with the war.

I realized about this and knew I was finally able to make complex games in flash... but flash sites were starting to die, all iProducts didn't accept flash so the world had to adapt to this (instead of the other way).

I didn't see the GPU acceleration happening in mobile phones until very late 2012. By then market almost already shifted back to old HTML. I was sure that didn't like this backwards step. In fact it was a waste of time for me, I lost all interest in the web: coding with JavaScript (no OOP) is a total nightmare when you add browsers variety to the equation.
So I had no choice other than leaving the web scene and move into apps/games.

I wanted to make games, I didn't mind what language so I researched into some of them: coronaSDK, Unity3D, phoneGap. But a friend told me about CitrusEngine framework for flash Stage3D. So I started working heavily for a month or two to get a demo that looked and and was responsive in Flash at very high frame rates... I was impressed as that was exactly what I had in mind a year back...
Only then,  I decided to make a real game. I got in touch with two friends that were able to work with me: Diego Gangl (amazing artist) and Mete Burch (modern musician). I ended up leading a team making the awesome game I always wanted and playable in most Android phones:
Beekyr

I made it in adobe AIR to be able to get to android devices. It was a really good decision. In the other hand it was also difficult to make the app perform well in these low powered devices. I was used to powerful PCs but I had to work hard to optimize everything and learn some very interesting techniques to make it run smooth everywhere.

So now, in 2013, the history carries on as Indie Developer.
I hope I can manage it well and live from making good quality games!

Friday 17 May 2013

TouchPad class for AS3 + Starling (Rev.2)

A month ago I shared a touch class that was pretty useful to play games in smart-phones but after some testing I realized that didn't work well when moving (with left thumb) + shooting (with right thumb) and pressing them alternatively.

After a bit of thinking, I have improved the class and now it will use always the left thumb to move and the right to shoot keeping the previous functionality. (But you can invert this easily, it have upgrade my class but it is still not public as I want to add more features before posting about it again!)

There is some tap functionality I need to implement, that will be in an future release: Ver.3....

Here it is, enjoy (for AIR or AS3):
(feel free to contribute to the class commenting here or in Starling Forum).



Class: TouchPad.as

package beekyr.controllers
{
    import flash.geom.Point;
    import starling.display.Quad;
    import starling.events.Touch;
    import starling.events.TouchEvent;
    import starling.events.TouchPhase;
    public class TouchPad extends Quad
    {
    /**
     * ...
     * @author Jaime Dominguez for Beekyr (2013)
     * http://www.jaimedominguez.com
     */
       
        private var _moveVector:Point = new Point();
        private var _tapVector:Point = new Point();
        private var _latestVector:TouchData = new TouchData();
        private var _sensitivity:Number;
        private var _touching:Boolean;
        private var _dualTouching:Boolean;
        private const TAP_SENSITIVITY:Number = 2;
        private var _tap:Boolean;
        private var _justTapped:Boolean;
       
       
        public function TouchPad(width:int, height:int, sensitivity:Number = 1) {
           
            super(width,height,0xff0000);
            _latestVector = new TouchData();
            _moveVector = new Point();
            _sensitivity = sensitivity;
            _touching = false;
            alpha = 0.05;
            addEventListener(TouchEvent.TOUCH , _handleTouch);
        }
       
        public function getLatestMovement():TouchData     {
            _latestVector._vX = _moveVector.x * _sensitivity;
            _latestVector._vY = _moveVector.y * _sensitivity;
            _latestVector.touching = _touching;
            _latestVector.dualTouching = _dualTouching;
            _latestVector.tap = _tap;
            resetValues();
            return _latestVector;
        }
       
        private function resetValues():void
        {
            _moveVector.x = 0 ;
            _moveVector.y = 0 ;
           
            _tap = false;
        }
       
        public function setWidth(w:Number):void {
            width = w;
        }
       
        public function setHeight(h:Number):void {
            height = h;
        }
       
        public function updateSensitivity(s:Number):void {
            _sensitivity = s;
        }
       
        private function _handleTouch(e:TouchEvent):void {
            e.stopImmediatePropagation()
            var touchArray:Vector. = e.getTouches(this);
            //var _wasDualTouch:Boolean = _dualTouching;
           
            _dualTouching = false;
            dispatchEventWith(TouchPhase.BEGAN);
            if (touchArray.length>0){
                var touch:Touch = touchArray[0];
                if (touchArray.length>1){
                    _dualTouching = true;

                   //If you want to move with the right thumb then edit the next line.
                    if (touchArray[0].getLocation(this).x > touchArray[1].getLocation(this).x) {
                        touch = touchArray[1];
                    }
                }
               
                switch (touch.phase){
                    case TouchPhase.BEGAN:
                        _justTapped = true;
                        storeThisPos(touch);
                    break;
                   
                    case TouchPhase.ENDED:
                        //checkForTap();
                        //stopMovement();
                        _tap = _justTapped;
                        _touching = false;
                    break;
                   
                    case TouchPhase.MOVED:
                        _justTapped = false;
                        getMovementVector(touch);
                    break;
                }
           
               
            }
           
        }
   
               
        private function getMovementVector(touch:Touch):void
        {
            _moveVector = touch.getMovement(this);
       
        }
       
        private function storeThisPos(touch:Touch):void
        {
            _touching = true;
            _tapVector = touch.getMovement(this);
        }
   
    }

}

Class:  TouchData.as 
package beekyr.controllers
{
    /**
     * ...
     * @author Jaime Dominguez
     */
    public class TouchData
    {
        public var _vX:Number;
        public var _vY:Number;

        public var touching:Boolean;
        public var dualTouching:Boolean;
        public var tap:Boolean;
           
        public function TouchData()
        {
           
        }
       
    }

}



Used in Beekyr for Android.