Subscribe to GameFromScratch on YouTube Support GameFromScratch on Patreon

2. January 2017

 

Mike Fricker, UE4 Technical Director at Epic Games, just released a new plugin for Unreal Engine that enables you to utilize OpenStreetMap data directly in Unreal Engine.  Keep in mind this is just a hobby project and isn’t directly supported by Epic.  OpenStreetMap.org is a crowd sourced (think Wikipedia) map of the world.  This plugin enables you to take data from OSM and use it directly in your game, quickly creating real world accurate cityscapes like the one shown to the right.OSM  Additionally all of the location information is retained upon import, so if you are creating an Alternate Reality based game like Pokemon Go, the data is available to you.  Keep in mind however that OpenStreetMap data is released under the Open Data Commons Open Database License (ODbL).  I am no lawyer, but I believe the license enables you to create closed source projects using the data so long as you give proper attribute, share any modifications you make to the database and make sure that the data itself (not your game code) remains available and open.

 

Details of the plugin from the Readme:

Street Map Assets

When you import an OSM file, the plugin will create a new Street Map asset to represent the map data in UE4. You can assign these to Street Map Components, or directly interact with the map data in C++ code.

Roads are imported with full connectivity data! This means you can design your own navigation algorithms pretty easily.

OpenStreetMap positional data is stored in geographic coordinates (latitude and longitude), but UE4 doesn't support that coordinate system natively. That is, we can't easily deal with spherical worlds in UE4 currently. So during the import process, we project all map coordinates to a flat 2D plane.

The OSM data is imported at double precision, but we truncate everything to single precision floating point before saving our UE4 street map asset. If you're planning to work with enormous map data sets at runtime, you'll need to modify this.

Street Map Components

An example implementation of a Street Map Component is included that generates a renderable mesh from loaded street and building data. This is a very simple component that you can use as a starting point.

The example implementation creates a custom primitive component mesh instead of a traditional static mesh. The reason for this was to allow for more flexible rendering behavior of city streets and buildings, or even dynamic aspects.

All mesh data is generated at load time from the cartographic data in the map asset, including colorized road strips and simple building meshes with triangulated roof polygons. No spline interpolation is performed on the roads.

The generated street map mesh has vertex colors and normals, and you can assign a custom material to it. If you want to use the built-in colors, make sure your material multiplies Vertex Color with Base Color. The mesh is setup to render very efficiently in a single draw call. Roads are represented as simple quad strips (no tesselation). Texture coordinates are not supported yet.

There are various "tweakable" variables to control how the renderable mesh is generated. You can find these at the top of the UStreetMapComponent::GenerateMesh() function body.

(Street Map Component also serves as a straightforward example of how to write your own primitive components in UE4.)

OSM Files

While importing OpenStreetMap XML files, we store all of the data that's interesting to us in an FOSMFile data structure in memory. This contains data that is very close to raw representation in the XML file. Coordinates are stored as geographic positions in double precision floating point.

After loading everything into FOSMFile, we digest the data and convert it to a format that can be serialized to disk and loaded efficiently at runtime (the UStreetMap class.)

Depending on your use case, you may want to heavily customize the UStreetMap class to store data that is more close to the raw representation of the map. For example, if you wanted to perform large-scale GPS navigation, you'd want higher precision data available at runtime.

 

The plugin and it’s source code is hosted on Github available here.  The plugin is released under the very liberal MIT open source license.

GameDev News

30. December 2016

 

After almost a year of running silently, it’s not to see regular updates to the Atomic Game Engine.  The Atomic Game Engine is an open source 2D/3D game engine with a comprehensive editor.  You can learn more about AGE in our Closer Look at review.  Atomic just released build 2 which focused on C# quality of life improvements, custom editor resource plugins , improved API documentation and various TypeScript improvements. 

Update Highlights:

  • [Editor] Custom file resource inspector plugins (with example)Atomic-Game-Engine-512

  • [Editor] Added TmxFile2D resource type for inspector fields

  • [Docs] Added new C#, C++, and updated JavaScript/TypeScript API references

  • [Network] Restored functionality for master server and client

  • [Web] Added Web subsystem events and convenience methods for post data and responses

  • [C#] Output dev project assemblies to Lib, so when modifying AtomicNET sources, changes are used properly

  • [C#] CSComponent cleanups for instantiation from script/serialized from scene (also cleans up nativeOverride hack)

  • [C#] Fix for exception when instantiating any RefCounted derived instance during a CSComponent default constructor

  • [C#] Better error reporting for CSComponent load issues

  • [C#] Added Material.SetShaderParameter API

  • [C#] Added Vector4/String to ScriptVariant

  • [C#] On demand project assembly compilation from within the Atomic Editor

  • [C#] Inspector attribute can now be used to set inspector tooltips

  • [TypeScript] Upgraded to TypeScript 2.1

  • [TypeScript] Removed deprecated allowNonTsExtensions

  • [TypeScript] Automatically generate a tasks.json for VSCode

  • [TypeScript] Updated tsconfig with rootUrl properly for non-relative imports

  • [TypeScript] Strongly typed native event interfaces and subscription

  • [Examples] Fixed exception with virtual dpad in JavaScript examples

  • [Desktop] Fixed issues with engine configuration json parsing in deployed applications

  • [Windows] Fixed issue with Visual Studio 2017 detection

  • [Windows] Fixed UI pixel offset issue when rendering with OpenGL

  • [macOS] Added NSHighResolutionCapable flag to Atomic Editor

  • [General] Updated About dialog with contributor and build vendor information

  • [General] Misc bug fixes and optimizations

  • [Maintenance] Removed CurlManager from ToolCore as duplicated Web subsystem

 

You can read more about this release on their blog.  Sorry, no direct link is currently available so you might have to do a bit of scrolling.

GameDev News

29. December 2016

 

Postal, a controversial video game from the 1990s, just released their source code under the the GPL 2 license. p1_screen_02  The code is primarily written in C++ and is hosted on BitBucket.  Sadly the release is source only and doesn’t appear to include any assets, so you will have to hunt down a copy to actually run it.  Details of the source release by the developer:

 

The remake – POSTAL Redux – was an especially big step for us; a passion project to make the original POSTAL again, but do it better this time, rebuilding it from scratch and focusing on making the most fun and exhilarating twin-stick shooter that we could by patching up the unfortunately outdated design decisions, and improve the game where we could. We even used the opportunity to bring old content, which was exclusive to the Japanese release of the game, to the west for the first time! For anyone who really wants to see how far POSTAL has come in the last two decades, there is no better way than by comparing the original to Redux.

It’s definitely been a wild ride for us all, and POSTAL means a lot to us – it’s our baby… But now we’re ready to hand the future of ‘the little shooter that could’ to the public at large. People have been asking, and we have been promising this for years now, but today we are proud to announce that the source code for POSTAL is officially released to the public on Bitbucket, under the GPL2 license. Everyone now has ‘under the hood’ access, to see what makes POSTAL tick, and anyone with the time and skills can now tweak/change/update/modify anything in the game at all! And hey, if anyone feels the urge to port the game to other platforms (The Dreamcast, for example *wink* *wink*), then they absolutely can!

This has been a long time coming, and we are tickled pink to see what the community will be able to put together from this (no seriously, someone get on that Dreamcast port. We’re not joking.).

GameDev News

28. December 2016

 

The Humble group are running another GameDev bundle.  The Humble Bundle is a collection of software with a pay what you want pricing structure where the proceeds go towards variousimage charities, this particular bundle is in support of the EFF (Electronic Freedom Foundation) and Child’s Play charity.  By paying more you can access higher and higher tiers which include even more software.  Currently the bundle consist of:

  • Clickteam Fusion (our review
    • HTML5 Exporter
  • Pyxel Edit
  • Spriter
    • Game Effects Art Pack
    • Basic Platformer, Adventure and Run N Gun Art Packs
    • RPG Heroes and SHMUP Sprite Packs
  • Marmoset
  • Todoist (1 year subscription)
  • PICO-8
  • Sprite Illuminator
  • Voxatron
  • 1Password (1 year subscription)

 

 

 

image

GameDev News

22. December 2016

 

Leadwerks 4.2 was just released.  Leadwerks is a 3D game engine that claims to be “the easiest way to create 3D games”.  Leadwerks runs on Windows and Linux and is scripted using Lua (while the Professional edition offers C++ support as well).  The 4.2 release is a free upgrade for existing customers.  The 4.2 release brings several new fixes and features including gameanalytics.com integration, graphics improvements like ray traced reflections, heat haze and soft particles and more.  A major character animation bug on Linux has finally been resolved as well.  The following is the official press release from Leadwerks:

Leadwerks Game Engine 4.2 Released

Leadwerks Game Engine 4.2 is now available on Steam.  This update adds new features to make game development easier than ever.  The free update goes out today to over 10,000 paid users on Steam.
Version 4.2 integrates analytics into Leadwerks games with a free gameanalytics.com account.  This allows developers to view statistics on player behavior and identify any trouble spots their game might have as players progress through levels.  By viewing a summary of all playerAttached Image behavior, developers can make data-driven decisions and get real-time information instead of relying solely on written feedback.

New graphical features make Leadwerks games more beautiful, including fast ray-traced reflections with a new post-processing effect called screen-space reflection (SSR).  Easy heat haze, glass refraction, and soft particles can now be Attached Imageadded to games just by dragging a prefab into the scene.  Textures can now be added to spotlights to project an image onto walls.

New animation commands and a built-in animation management system make it easier to display game characters with fluid movements.  Just set the sequence to play, add a transition time, and the engine will automatically manage and play a queue of blended animations.  A bug that sometimes caused animated characters to render incorrectly on Linux has also been fixed.
It's now easier to purchase items in the Leadwerks Workshop Store.  Clicking on the buy button in the editor will open the selected item in the Steam client, instead of requiring you to log into the Steam website through a web browser.
The professional edition has been upgraded to Visual Studio 2015, and is now compatible with the latest version of GCC with C++11 support.
The Leadwerks Winter Games Tournament is running until January 15th, and there’s still time to create a mini-game and publish to Steam Workshop.  All participants receive a prize, including stickers, posters, shirts, hoodies, and even Steam controllers.
Leadwerks Game Engine and the Professional Edition DLC are both on sale during the Steam Winter Sale with an 80% discount.  Leadwerks Game Launcher can be downloaded for free on Steam.

 

 

Leadwerks Professional is currently heavily discounted on Steam, available for 80% off.

GameDev News

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