Subscribe to GameFromScratch on YouTube Support GameFromScratch on Patreon

17. June 2011

 

So there is a blog post up on Unity3d.com showing what’s coming down the pipeline.  There’sunityLogo some pretty interesting stuff on there.  Apparently Unity 3.4 is at the release candidate stage and there are a few major announcements.  Terrain support in iOS and Android is a biggy, execution order on scripts, procedural texture support and 2-3x improvement in skinning speed are all very nice new features.

 

The post goes on to describe what is in the upcoming 3.5 release, with tons of new features but perhaps the most interesting to me are the new UI framework, pathfinding and LoD support.  Some really interesting stuff coming up, I highly recommend you check out the full post.

General

15. June 2011

 

Earlier this week I described the process of building Blender for Windows using CMake and Visual Studio.  While I was doing I actually did a series of screen captures for the more visual learners amongst us.  Problem is, my machine decided editing 1080p video was a crime against humanity, so I wasn’t able to get them posted.  I can happily say, the problems have been rectified.

 

Compiling Blender ‘Avocado’ on Windows

 

 

Of course a great deal of the video will be unreadable in this resolution.  I recommend using an HD version on YouTube.  Or for the Vimeo inclined click here.

Programming

11. June 2011

 

EDIT: Now with video!

 

After yesterday’s post, I noticed there wasn’t a recent build of Avocado available so I got to wondering how much work it would be to build a Blender branch.  In the end the answer is “not much”, with a bunch of caveats.  Frankly the hardest part is configuring your environment.  This guide shows but one way, there of course are other options.

 

First of all, I already have Visual Studio 2010 Professional installed, but many of you may not have professional and there is a big snag with Express C++ in that there is no command line 64bit compiler.  At this point you have one of three options, build for 32bit, download and install the Platform SDK which includes a 64bit cross compiler or you can download and use mingw.  The last two options are beyond the scope of this post and the instructions will assume you are using VC++.

 

Next up you need SVN, which is what you use to get the code from Blender’s repository.  In my case, I am using Cygwin from the command line.  For those of you with a command line aversion, you can use a GUI tool like Tortoise SVN.  Again, my instructions are going to assume you went the Cygwin route, but should still make sense a different SVN.

 

Now, to get Cygwin, run the Setup.exe ( from here ) and choose the default ( install to a directory without spaces! ).  You can add other features, but don’t do this now as some download locations don’t have all the packages, so it could result in your install failing.  Once setup.exe has completed, run it again and search for svn, if it is not installed ( as pictured below ), in the New column, instead of keep it will say “Skip”, click this and it will set it to download.  Then click next and it will figure all of the requisites and dependencies, download and install them.

 

image

 

Assuming all went well, you now have svn.  Only one more file to install, CMake, a cross platform make tool.  The install process is pretty straight forward, now time to grab the sources.  You are going to need to make two directories on your local computer, one where the code is going to be downloaded, then one where the code is going to be built.  In my case ( and in the instructions ) I used C:\Temp\Blendersource and c:\temp\BlenderBuild but you can of course use whatever you want.

 

Now its time to get the source.  Launch “Cygwin Bash Shell”, it should be located in your Start Menu.  Otherwise you can run it from [Cygwin Install Directory]\Cygwin.bat.  Now you need to choose which repository you want to build.  The list of branches is available here.  In your browser navigate to the one you want to build, then into the blender directory and copy this address.  In this case I am building Avocado, so I copied https://svn.blender.org/svnroot/bf-blender/branches/ to my clipboard.

SVN works in the form of:

svn checkout [ paste your clipboard ] [where to copy to]

 

One gotcha is you need to point BASH to a directory on your computer, in this case C:\temp\blendersource.  In order to do this, we use the /cygdrive link.  So, the actual command looks like:

 

$ svn checkout https://svn.blender.org/svnroot/bf-blender/branches/soc-2011-avacado /cygdrive/c/temp/blendersource/

 

That will go ahead and download all the blender code.  You will probably get an error stating server certificate isn’t trusted, check type “t” or “p”.  Later on you are going to need the precompiled binaries from the trunk repository.  They are located at https://svn.blender.org/svnroot/bf-blender/trunk/lib/ in the windows/ and win64/ folders.  Warning! This takes a long time, like go make and drink a pot of tea long time.  We want them copied into the /lib/windows directory of the newly downloaded source.  The command for this is:

 

$ svn checkout https://svn.blender.org/svnroot/bf-blender/trunk/lib/windows /cygdrive/c/temp/lib/windows

followed by:

 

$ svn checkout https://svn.blender.org/svnroot/bf-blender/trunk/lib/win64 /cygdrive/c/temp/lib/win64

 

At this point, you have all the sources and libraries you need.

 

Now fire up trusty CMake you downloaded earlier.  In the “where is the source code:” text field put C:/Temp/blendersource/ ( or the location of CMakeLists.txt if you are using a different path).  In the “Where to build the binaries:” text field put c:/temp/BlenderBuild.  Now click “Configure”, the following window will appear, select your compiler:

 

image

 

 

Click Finish once your compiler is selected from the list.  Now your CMake window should look like this:

image

 

Now you can optionally enable/disable features.  If building Avocado, disable WITH_IMAGE_OPENEXR! It will currently cause your build to fail. Once you finalized your selections click Configure again, then Generate.

Now if you look in C:\Temp\BlenderBuild, you will see that CMake has built the proper native build files, in my case for Visual C++ 2010.  There is even a solution file if you want to build using the VC IDE.  In this case I am going to use the command line, launch the Visual Studio X64 64 Bit Command Line.  Now type:

cd \temp\blenderbuild

msbuild Blender.sln /property:Configuration=Release

 

And off to the races…   See, nothing to it! Open-mouthed smile

 

After 5 to 20 minutes later, copy your new Blender.exe ( from bin\release ) into a Blender install and…

 

image

 

AHHHH crap, seriouslyjQuery152044251238950528204_1314637985251?  Well, we apparently have a very streamlined version, perhaps a bit too streamlined.  What exactly is going on here?  Well, truth of the matter is, if you followed along at home and aren’t using Windows 7, nothing, it probably works perfectly fine.  However, if you are like me and are running Windows 7, this post is very interesting.

 

There is some annoying permissions issue with Win 7, depending on who/how/where you install as. A known problem, being worked on. Maybe already fixed. (can you tell I'm not a windows guy?)
Easiest work-around for now is to download the .zip version, unzip it and run from that folder.

 

Welcome to life on the bleeding edge!  It’s called the “bleeding edge” for a very good reason!  Anyways, head over here and download the 64bit ZIP install, extract it and copy your new Blender.exe file over.   Voila!

 

image

 

 

A fresh new 64Bit version of Blender—Avocado, bmesh tools and all.  It may have looked difficult, but in the end, it really isn’t, with the exception of figuring out the most recent bug ( thanks Google ).

 

Seem like too much work?  You can download the blender.exe I generated.  Simply download and install the current 2.57b ZIP from Blender, extract it then extract my Blender.zip over top.

Art, Programming

10. June 2011

 

One of the nicest features of going with Blender is the fact that it is open source.  One of the nicest facts of open source is you don’t have to wait for a vendor to release a new version, you can go get the cutting edge version at any time.  That said, building Blender from scratch is a non-trivial task, but nicely for that we have graphicall.org.

 

Basically graphicall allows people to post and share their builds.  You go on the site andBlogEngineLogo choose a build to download.  You can choose by OS, bit-ness or the various features included in the build. Why the heck would you want to do this?  Well, frankly some of these features are incredibly interesting, but perhaps most interesting of all, is the new BMesh tool.  Remember how I said earlier that the weakest link in Blender was the modeling tools, and the one feature it was missing the most was the lack of n-gons?  Well, bmesh addresses this shortcoming.  It is rumoured that it will be part of Blender 2.8, but it as been in development for a very very very long time, so don’t hold your breath. I will hopefully have a demonstration up shortly that illustrates this powerful tool.

 

But bmesh is by no means the only thing to look forward to.  Another area graphicall builds cover is Google Summer of Code builds.  If you have never heard of it, instead of getting a summer job, students instead propose a project in the open source world and if approved, get paid by Google to implement it.  This year, Blender is a pretty big winner on the number of projects sponsored.  About half of the projects on that list will be a huge boon for game development.  The various branches can be viewed here.

 

A quick trip to GraphicAll is going to confuse the hell out of you though…  Avacodo? Radish? Cucumber?  WTF?  Well lets just say the Blender group like their code names!  Last time it was fruit, this time, it’s veggies.  Anyways, this infographic that I brazenly stole from here which in turn they stole from here.  Anyways, it’s a good image, so here goes(click image for original).

 

Gsoc-2011-branches

 

 

Anyways, probably of most interest from a game perspective are the Avocado, Onion and Pepper branches.  Of most interest to game dev work is the Avocado branch, which is the only one based off the BMesh branch instead of the main trunk fork ( Salad branch ).

 

But by no means are we confined to the Summer of Code builds, lots of other stuff is available as well.  There is Blender Cycles a GPU based render, LuxBlend interface for LuxRender, Yafaray as well as builds using OpenMP for better multicore CPU support.

 

So, if you are willing to take a walk on the wild side and put up with a few more bugs and glitches, Graphicall is very much worth checking out!

Art

5. June 2011

 

When I was starting out, I was just dying to earn my “real programmer badge™”.  At the time “real programmers” used assembly and I was taking the lazy easy way out using C.  So, in my quest to earn my real programmer badge I taught myself assembly.  Now it took me 10 times as long to write my code and it sure was more difficult; no doubt my badge would be in the mail!  Sadly… no, it didn’t arrive.

 

 

The years went by and assembly became more and more niche.  In the meanwhile, higher level languages came to the fore.  There were even languages that hacks and simpletons could rapidly create programs in, like Delphi ( pascal ) and Visual Basic.  Of course real programmers looked down upon these amateurs, everybody knew that this wasn’t real programming.  Hell even C++ was looked down upon, it was way too high level and slow for real programmers to use, so being a real programmer I kept using C.  Things sure were slow and painful, lots and lots of work, no doubt my real programmer badge was on it’s way! 

 

 

Another generation of languages came along, new pretenders like Java and C# rose in popularity and the lazy and weak flocked to them like mad.  Real programmers of course knew that C++ was the one true language.  Sure, those class libraries and the freedom from memory management sure looked tempting, but I am a real programmer damn it, so I continued working in C++.  My god was it difficult so I truly must be getting close to getting my real programmer badge.  When it didn’t arrive I decide their surely must be a mistake at the post office!

 

 

Then the current generation of languages came to the forefront.  Scripting languages had risen in popularity, to the point that it seemed more people were “scripting” than programming these days!  Scripting?  What real programmer in their right mind would ever work in a lowly scripting language?  I am a real programmer, I will leave scripting for the hacks and newbies, thank you very much!  Real programmers work in C++!  Oddly enough, I still haven’t received my badge…?

 

 

Recently a funny thing happened… I took to a project under a tight deadline, it absolutely had to ship on a given date.  There was no way I could possibly succeed in time using a real programming language, so I took to using the plebian tools.  Working in C#, the wonderful class libraries sure did make development fast.  At times I actually slunk to the lowest of the low and used scripting languages!  It felt so dirty but I have to admit the rapid turn around and interactive tools sure did things quick.  In the end, it was a challenge and I had to prostitute my pride, but I shipped on time!  The following day, a FedEx truck pulled up to my front door and delivered my prized Real Programmers Badge™!

 

 

 

Official-Seal-of-Awesome

 

( Image totally stolen from a middle aged drama queen. )

Of course, this story is completely full of crap but the moral is completely true.  When I was starting out C was truly looked down upon as being a tool of “fake” programmers. Through the years the language has changed but there has always been an “IT” language that new programmers to the field think they have to work in to be a real programmer.  It sadly often takes years of experience to realize how stupid this mindset actually is.  Can you imagine a carpenter that wouldn’t use a drill because “real carpenters” use screw drivers, would you hire this person?

 

 

A real programmer uses the right tool for the job.  For those of you just starting out, “the job” very much includes “learning to program”.  In the end a real programmer makes the best product they can, as efficiently as they can, using whatever tool works best.  Sometimes, that tool might even be C++!

Programming ,

Month List

Popular Comments

Moai Tutorial Part 6: Who put the bomp in the Moai, Moai, Moai. Playing audio in… you guessed it… Moai
Subscribe to GameFromScratch on YouTube Support GameFromScratch on Patreon


17. September 2012

 

In this tutorial, we are going to look at how to play audio using Moai.  This is going to make heavy use of moaigui, so if you haven’t already, you may want to check the prior tutorial in this series.

 

As always, let’s jump right in to the code.  You may notice that the code order is starting to seem a little… odd. This is because I am grouping code mostly in order of newness, as opposed to how it would logically be laid out.  If you are thinking “I wouldn’t order things this way!”, well.. neither would I, normally.

 

screenWidth = MOAIEnvironment.screenWidth
screenHeight = MOAIEnvironment.screenHeight
if screenWidth == nil then screenWidth =1280 end
if screenHeight == nil then screenHeight = 800 end


MOAISim.openWindow("Window",screenWidth,screenHeight)

viewport = MOAIViewport.new()
viewport:setSize(screenWidth,screenHeight)
viewport:setScale(screenWidth,screenHeight)

package.path = './moaigui/?.lua;' .. package.path
require "gui/support/class"
local moaigui = require "gui/gui"
local resources = require "gui/support/resources"
local filesystem = require "gui/support/filesystem"
local inputconstants = require "gui/support/inputconstants"
local layermgr = require "layermgr"


local gui = moaigui.GUI(screenWidth,screenHeight)


gui:addToResourcePath(filesystem.pathJoin("moaigui/resources", "fonts"))
gui:addToResourcePath(filesystem.pathJoin("moaigui/resources", "gui"))
gui:addToResourcePath(filesystem.pathJoin("moaigui/resources", "media"))
gui:addToResourcePath(filesystem.pathJoin("moaigui/resources", "themes"))

layermgr.addLayer("gui",99999, gui:layer())
gui:setTheme("basetheme.lua")
gui:setCurrTextStyle("default")

function onPointerEvent(x, y)
    gui:injectMouseMove(x, y)
end

function onMouseLeftEvent(down)
    if(down) then
        gui:injectMouseButtonDown(inputconstants.LEFT_MOUSE_BUTTON)
    else
        gui:injectMouseButtonUp(inputconstants.LEFT_MOUSE_BUTTON)
    end
end

function onTouchEvent(eventType,idx,x,y,tapCount)
    --gui:injectTouch(eventType,idx,x,y,tapCount)
    onPointerEvent(x, y)
    if (MOAITouchSensor.TOUCH_DOWN == eventType) then
        onMouseLeftEvent(true)
    elseif (MOAITouchSensor.TOUCH_UP == eventType) then
        onMouseLeftEvent(false)
    end
end


if MOAIInputMgr.device.pointer then
    MOAIInputMgr.device.pointer:setCallback(onPointerEvent)
    MOAIInputMgr.device.mouseLeft:setCallback(onMouseLeftEvent)
else
    MOAIInputMgr.device.touch:setCallback(onTouchEvent)
end


function onButtonClick(event,data)
    if(string.find(buttonPlay:getText(),"Play") ==1) then
        song1:play()
        buttonPlay:setText("Stop, that's creeping me out!")

        function checkSongDone()
            local song = song1
            while song1:isPlaying() do coroutine:yield() end

            song1:stop()
            buttonPlay:setText("Play Audio File using Untz")
        end

        if not checkLoop:getChecked() then
            songPlayingThread = MOAICoroutine.new()
            songPlayingThread:run(checkSongDone)
        end
    else
        song1:stop()
        buttonPlay:setText("Play Audio File using Untz")
    end
end

function onButtonRewind(event,data)
    if song1:isPlaying() then
        local pos = song1:getPosition()
        local length = song1:getLength()
        local tenPercent = (length * 1.10) - length
        pos = pos - tenPercent
        if(pos > 0) then
            song1:setPosition(pos)
        end
    end
end

function onButtonFastForward(event,data)
    if song1:isPlaying() then
        local pos = song1:getPosition()
        local length = song1:getLength()
        local tenPercent = (length * 1.10) - length
        pos = pos + tenPercent
        if(pos < length) then
            song1:setPosition(pos)
        end
    end
end

function onCheckboxChanged()
    song1:setLooping(checkLoop:getChecked())
end

function onVolumeChanged()
    MOAIUntzSystem.setVolume(sliderVolume:getCurrValue() / 100)
end



buttonPlay = gui:createButton()
buttonPlay:setPos(0,0)
buttonPlay:setDim(100,25)
buttonPlay:setText("Play Audio File using Untz")
buttonPlay:registerEventHandler(buttonPlay.EVENT_BUTTON_CLICK,nil,onButtonClick)

checkLoop = gui:createCheckBox()
checkLoop:setPos(0,26)
checkLoop:setDim(100,10)
checkLoop:setText("Loop?")
checkLoop:registerEventHandler(checkLoop.EVENT_CHECK_BOX_STATE_CHANGE,nil,onCheckboxChanged)

labelVolume = gui:createLabel()
labelVolume:setText("Volume")
labelVolume:setPos(0,36)
labelVolume:setDim(30,10)

sliderVolume = gui:createHorzSlider()
sliderVolume:setPos(30,36)
sliderVolume:setDim(70,10)
sliderVolume:setRange(0,100)
sliderVolume:setCurrValue(50)
sliderVolume:setValueDisplayLoc(sliderVolume.VALUE_DISPLAY_RIGHT)
sliderVolume:registerEventHandler(sliderVolume.EVENT_SLIDER_VALUE_CHANGED,nil,onVolumeChanged)

buttonRewind = gui:createButton()
buttonRewind:setPos(0,50)
buttonRewind:setDim(50,10)
buttonRewind:setText("Rewind")
buttonRewind:registerEventHandler(buttonRewind.EVENT_BUTTON_CLICK,nil,onButtonRewind)

buttonFastForward = gui:createButton()
buttonFastForward:setPos(51,50)
buttonFastForward:setDim(50,10)
buttonFastForward:setText("Fast Forward")
buttonFastForward:registerEventHandler(buttonFastForward.EVENT_BUTTON_CLICK,nil,onButtonFastForward)

MOAIUntzSystem.initialize ()
MOAIUntzSystem.setVolume(0.5)
song1 = MOAIUntzSound.new()
song1:load("demongirls.ogg")

 

If we run the application( in the Moai-untz host ), we see:

 

image

 

Click the “Play Audio File using Untz” button and the song will play, the slider increases and decreases the volume, the loop check box I bet you can guess what it does.  Rewind and Fast Forward change the playback position by 10% at a time.

 

This looks like a wall of code, but don’t worry, it’s not all that bad.  In reality, most of it is maoigui code that we covered earlier.  We use a couple of new controls ( the check box and slider ), but nothing in the UI code should be all together new.  Most of our new logic is in the click handler methods, so let’s start there.

 

function onButtonClick(event,data)
    if(string.find(buttonPlay:getText(),"Play") ==1) then
        song1:play()
        buttonPlay:setText("Stop, that's creeping me out!")

        function checkSongDone()
            local song = song1
            while song1:isPlaying() do coroutine:yield() end

            song1:stop()
            buttonPlay:setText("Play Audio File using Untz")
        end

        if not checkLoop:getChecked() then
            songPlayingThread = MOAICoroutine.new()
            songPlayingThread:run(checkSongDone)
        end
    else
        song1:stop()
        buttonPlay:setText("Play Audio File using Untz")
    end
end

This is the code that is executed if the brilliantly named buttonPlay button is clicked.  The first thing we do is check to see if the button’s text starts with “Play”, which if it does, that means we are currently not playing a song.  Therefore we start playing our song ( aptly named song1 ) with a call to the play() method.  We then update our button’s text to indicate it’s new status.  The next little bit of code might seem a bit confusing at first, but it is pretty powerful.

 

First we are declaring a nested function checkSongDone().  The next line is where the magic happens.  It’s a while loop that loops until the condition isPlaying() becomes false.  Each pass through the loop we call coroutine:yield().  So, what the heck was that all about? Well… this is going to be a bit tricky to explain, but I will do my best.

 

If you are an old fart like me, you may remember multitasking in the pre-Win95 pre-emptive multitasking days.  Essentially you ran multiple programs at the same time by giving each one a chunk of processing time and a well behaved program was supposed to yield control when it wasn’t busy.  Essentially the operating system switched between running programs and said “ok, your turn” and a well behaved program would quickly exit if it was done doing whatever it needed to do.  Well, in a nutshell that is what is happening here.

 

A coroutine is sort of the Moai version of a thread.  Using coroutines, you are able to run code in parallel, so while our game loop is still running, the function checkSongDone is blissfully churning away in the background checking to see if the song is done.  Thing is, until the song is actually done, the coroutine doesn’t really have anything else to do, so it calls yield().  It is not until that condition is true ( isSongPlaying returns false ) will the function continue execution.  Once this happens we (somewhat redundantly) call song1:stop() then update the button’s text to “Play Audio…”.  The end result of this whole chunk of code is, we essentially created an on song end handler, so when the song is done playing, the text of the button will update.

 

The next chunk of code checks the checkbox checkLoop, which if checked indicates that we want the song to loop continuously.  If it is not checked, that means we want to run our coroutine, which we create with a call to MOAICoroutine.new(), then run with the run() method, passing in the function to run.

 

If the button’s text however indicates that the song is playing, in which case the button acts like a STOP button, simply stopping playback ( even if loop is checked ) and resetting back to the “Play…” text.  I encourage you to look deeper in to Coroutines, they are a very powerful feature of Lua. MOAICoroutine itself is only a thin wrapper over Lua’s coroutine abilities.

 

Also, you may have noticed MOAIThread in the examples and wondered when to using MOAIThread instead of MOAICoroutine.  The short answer is, you dont!  The more accurate and useful short answer is, MOAIThread *IS* MOAICoroutine.  It was renamed and the documentation just hasn’t caught up yet.  Well at least, it hadn’t at the point I wrote this.

 

TL;DR, coroutines are cool, learn about them, use them, love them.

 

function onButtonRewind(event,data)
    if song1:isPlaying() then
        local pos = song1:getPosition()
        local length = song1:getLength()
        local tenPercent = (length * 1.10) - length
        pos = pos - tenPercent
        if(pos > 0) then
            song1:setPosition(pos)
        end
    end
end

function onButtonFastForward(event,data)
    if song1:isPlaying() then
        local pos = song1:getPosition()
        local length = song1:getLength()
        local tenPercent = (length * 1.10) - length
        pos = pos + tenPercent
        if(pos < length) then
            song1:setPosition(pos)
        end
    end
end

This is the code that executes if you hit the Fast Forward or Rewind buttons.  Basically it gets the current position of the song ( playback-wise ) using getPosition() and the length of the song using getLength().  Next we calculate what 10% of the length is, and either add or subtract that amount from the current position depending if we are fast forwarding or rewinding.  Next we check sure to make sure the position is valid after being modified and if it is, we change the position of the song using setPosition().  End result, pressing Fast forward advances the song by 10% of it’s length, while hitting rewind moves it back 10%.

 

function onCheckboxChanged()
    song1:setLooping(checkLoop:getChecked())
end

This is the code that executes if the checkbox checkLoop is checked or unchecked.  It simply toggles the value of setLooping based off the if the checkbox is checked, using getChecked().

 

function onVolumeChanged()
    MOAIUntzSystem.setVolume(sliderVolume:getCurrValue() / 100)
end

This is the code that is executed if the slider sliderVolume is changed.  This uses the MOAIUntzSystem singleton to change the global volume level using setVolume().  setVolume takes a value from 0.0 to 1.0, while the sliders value returned by getCurrValue() is from 0 to 100, so we divide it by 100.

 

So then, what the heck is an Untz?  It’s the included cross platform audio system.  You also have the option to use FMOD, a commercial audio solution.  Untz does the trick though, works on Android and iOS.  There is a very important caveat… if you are going to be running using the UNTZ audio library you need to use the Moai-untz host!!! when running on the PC.  You will get exceptions if you try to call MOAIUntzSystem from the normal Moai host.  The Moai-untz host is in the same directory as the Moai host.

 

Most of the UI code is pretty much identical to what you’ve seen already, so I wont really go into it, that leaves:

 

MOAIUntzSystem.initialize ()
MOAIUntzSystem.setVolume(0.5)
song1 = MOAIUntzSound.new()
song1:load("demongirls.ogg")

This code first initializes the MOAIUntzSystem singleton.  Then it sets the global volume to 50%.  Next we create our song song1 with a call to MOAIUntzSound.new().  Finally load the song ( in the same directory as main.lua ) with a call to load().

 

You might be asking yourself “what sound formats does Untz support?”.  That’s a good question with a tricky answer.  Basically the safe answer is ogg and wav.  The not so safe answer is, it depends on the platform.  For example, iOS, Mac and Windows will work with mp3, but Android wont.  Beyond WAV and OGG, the file is just passed to the native system for handling, so if the platform supports it, Moai supports it.

 

But if you really want to be cross platform, just encode everything in to ogg.  In this day of increasingly wealthy lawyers, the last thing we want to do is deal with a patent encumbered format like mp3!

 

Oh yeah, and the music… it’s seriously creepy stuff and I downloaded it from here.  Obviously you can substitute any song you want from your Justin Beiber collection, just make sure it’s not an MP3 if you are running on Android.  Of course, you can convert from just about any audio format to just about any other audio format using the free and amazing Audacity.  I do get 10% of all proceeds for saying that.  I may need a new business model.

 

Programming , ,

blog comments powered by Disqus

Month List

Popular Comments