Subscribe to GameFromScratch on YouTube Support GameFromScratch on Patreon

14. December 2016

 

Tizen is an open source embedded OS based on the Linux kernel designed to be used in a variety of devices, the most relevant to game developers are Smart TVs and mobile phones.  It came to life out of a home grown OS project at Samsung called Bada.  To date the majority of devices that run Tizen are from Samsung including the Z1 and Z3 smart phones, Gear 2 smart watch and the JU6500 4K smart TV, although other manufacturers are part of the committee.  Basically you can think of Tizen as Samsung’s hedge against Android should something go wrong with that platform.

So… why does this matter to you as game developers?  Well Tizen just announced a contest with some pretty simple rules and $9million in prizes.  Basically over a 9 month period, the top 100 apps in the Tizen app store will get $10,000.  So if you manage to have a top 100 app for the entire duration of the contest, you will make a cool $90,000 on top of any other revenue you make from app sales.  While the Tizen app store may not be the biggest in the world, a $10,000 monthly incentive is sure to draw developer interest.

 

Details of the contest:

HOW TO
PARTICIPATE

  • 1.Develop a Tizen application or game using TIZEN SDK & Tools (http://developer.tizen.org) The target devices should be Samsung Z1, Samsung Z2, Samsung Z3 and further smart phones launch in the 2017.
  • 2.You need to join the Tizen Store seller office
    (http://seller.tizenstore.com) first and follow the instructions on the website to register your applications.
  • 3.Visit the incentive program website, which will be opened on the early of January 2017, and register your app with its basic information.

TIMELINE

Participation Registration Period
Early of Jan, 2017 – Oct 31, 2017 (GMT)
Program Duration
Feb 1, 2017 at 00:00 - Oct 31, 2017 at 23:59(GMT)

INCENTIVE
REWARDS

Prize
$10,000 for top 100 apps every month(The reward can be provided at once per a app)
Judging Criteria
Every month, the 100 eligible applications that have
been downloaded the most times on Tizen Store.(Detailed rules will be released in January 2017)

 

Tizen support is available in several game engines including Unity, Cocos2d-x, GameSalad, OpenFL and GameMaker.

GameDev News

13. December 2016

 

With the release of Unity 5.5 a couple weeks back, we had to know that Unity 5.6 beta would be just around the corner.  Well, we have officially rounded that corner, Unity 5.6 Beta was released today. 

So, what’s new in Beta 5.6 release?

  • Vulkan renderer support (Android, Windows, Linux, Tizen)Unity56
  • Metal Compute support (iOS, Mac OS/X)
  • GPU instancing and particle system performance improvements
  • EncodeToEXR to Texture2D, save HDR textures to EXR on disk
  • 2D Game Dev workflow improvements
    • Axis Distance Sort for Z sorting
    • Outline Editor added to Sprite Editor Window ( automatic tessellation or manual mesh shape editing)
    • 2D Physics casting API and new 2D Contact API
    • CompositeCollider2D, merge multiple colliders
    • 9slice (9patch?) support
  • New video player with 4K and 360 degree support
  • Unity Collaborate improvements (partial publish, ignore files, rollback)
  • iOS added to Unity Performance Reporting
  • Google Daydream and Cardboard support added ( was previously a forked version )
  • Support for Facebook GameRoom
  • Physics Debug Visualization
  • Physics.ComputePenetration and Physics.ClosestPoint functions added

 

They also discussed some upcoming features for 5.6:

  • Progressive Lightmapper for baked lightmaps
  • more light modes
  • redesigned lighting window + new Light Explorer window
  • timeline (cinematics system)
  • multithreaded jobs system
  • new platforms (such as Nintendo Switch)

 

You can read more details about the 5.6 release here as well as more details of their upcoming features here.

GameDev News

13. December 2016

 

The next version of Visual Studio, Visual Studio 2017 is currently in Release Candidate.  I’m pretty excited about this release, I took a preview look available here, as it works to undo a great deal of the bloat that has been creeping into Visual Studio over the years.  While VS2017 isn’t quite ready for release, they have released an update for the Release Candidate (RC) build.  In addition to several bug fixes, it adds a few new command line utilities and greatly streamline the csproj file format.

 

Details from the release announcement:

CLI enhancements

  • Added the dotnet add p2p command, for adding project to project references.
  • Added the dotnet remove p2p command, for removing project to project references from the project file.
  • dotnet new templates are updated to reflect the simplified csproj syntax.
  • Added verbosity control to build, pack, publish, restore & test using –v | –verbosity. The verbosity levels map to MSBuild verbosity levels.

Bug fixes

  • Migration from xproj to csproj
    • Migration of projects that have P2P references is no longer broken.
    • Removed PostPublishScript target.
    • Removed post-migration reference to dotnet-test-mstest.
    • Fixed migration output issues.
    • Migration adds RIDs when migrating projects with .NET Framework TFM.
    • Migration no longer migrates the reference to dotnet-test-xunit if project.json contains it.
  • Project to Project References
    • Referencing from a UWP project is no longer blocked.
    • Referencing from regular csproj no longer gives warnings.
    • TargetFramework dropdown in the project properties page works.
  • NuGet
    • Restore hang fixes and stability improvements.
    • Pack now uses the correct version range for dependency projects.
    • Restore now adds correct project dependency version for command line restore.
  • MSBuild
    • Improvement to incremental builds for C# and VB projects that use wildcards that ensures a rebuild when a source file is deleted.
  • ASP.NET Core Tooling
    • Entity Framework Core commands such as Add-Migration and Update-Database can now be invoked using NuGet Package Manager Console.
    • To successfully restore Bower packages, you no longer need to have Git installed globally or manually reference Git in Tools-Options.
    • Can successfully debug ASP.NET Core Web Applications with Windows Authentication.
  • Docker
    • When provisioning an Azure Docker registry and App Service plan, it no longer requires a new resource group to be created in the same region as the App Service plan.
    • Improved the usability of creating a new Azure resource group.

GameDev News

12. December 2016

 

The PlayCanvas team have just released a “mega” update for the PlayCanvas 3D HTML5 game engine.  If you are interested in learning more about PlayCanvas, we previously featured them in the Closer Look game engine series.  Now back to the update.

 

Calling an update “mega” you’d expect it to be loaded with features, and for the most part it is.  In this update:

  • live camera preview ( a must have! ) with a render preview window showing contents of selected cameracamerapreview
  • interactive asset previews in inspector
  • ability to toggle anti-aliasing off and on
  • place model in front of camera instead of origin by holding Ctrl key
  • switch between large and small thumbnails in asset view
  • up folder navigation option (another must have)
  • hover over asset to see full name
  • Code editor enhancements
    • highlight current line of code
    • highlight errors
    • better cursor visibility
    • fewer disconnection messages

 

The release also contains several optimizations and fixes:

Optimizations

Huge speedups achieved for both loading and rendering of scenes!

  • New thumbnail rendering system reduces VRAM usage in the Editor by up to a factor of two. This makes the Editor more stable and faster to load, especially for larger scenes.
  • Major optimisations for loading and Editor rendering process so projects with thousands of entities and assets can load and render now up to 10 times faster in extreme cases.
  • Asset load operations are now batched rather than performed one by one.
  • All engine assets are loaded only when they are required (when they are enabled), leading to reduced traffic and loading times.
  • Optimisations in internal API of Editor and UI leading to reduced garbage collection (and therefore GC stalls) and speeds up UI templating for Hierarchy and Assets panels.
  • Enabled GZIP on WebSocket traffic, which reduces data transfers for initial loading.
Fixes
  • Fixed up arrow while navigating in the Hierarchy tree.
  • Fixed sorting of folders in the Assets panel tree.
  • Fixed material overrides on the Model Component if the model asset wasn’t loaded.
  • Cubemap faces now update in the Inspector (in the Faces section) if a face texture file is changed.
  • Read-only users can now select text/number field values.
  • Double click or right mouse click on number fields now will select whole content of the field and not just part of number separated by a dot or minus sign.
  • Networking improvements have been made to reduce disconnects.

 

You can learn more about PlayCanvas here.

GameDev News

11. December 2016

 

LibGDX, the cross platform Java powered open source game framework, just released version 1.9.5.  This release is mostly about upgrading under the hood libraries and tooling support including GWT, RoboVM and LWJGL version updates.  The release is also compatible with iOS 10 and Xcode 8.  If you want to learn more about LibGDX we have a comprehensive tutorial series available here as well as a video tutorial series available here.

 

Details of the update from the release announcement:

[1.9.5]
- Upgraded to MobiDevelop's RoboVM fork version 2.3.0, update your[sic] 
- Upgraded to GWT 2.8.0 for faster compiles and better compile output
- Fix NPE swallowing "video driver unsupported" error on LWJGL 2 backend.
- Allow window icons to be set in Lwjgl3ApplicationConfiguration or Lwjgl3WindowConfiguration.
- Allow window icon and title to be changed in Lwjgl3Window
- API Addition: ApplicationLogger interface, allowing easier access to custom logging
- DefaultRenderableSorter accounts for center of Renderable mesh, see https://github.com/libgdx/libgdx/pull/4319
- Bullet: added FilterableVehicleRaycaster, see https://github.com/libgdx/libgdx/pull/4361
- Bullet: updated to 2.85, see: http://bulletphysics.org/wordpress/?p=456
- Updated iOS native build scripts to iOS 10.1 and TVOS 10.0
- API Addition: BitmapFont#blankLineScale.
- Fixed rounding of Drawables in ProgressBar. Allow rounding to be disabled with setRound().
- Updated LWJGL3 backend to LWJGL 3.1.0, see https://blog.lwjgl.org/lwjgl-3-1-0-released/
- LWJGL3 backend now supports non-continuous rendering, see https://github.com/libgdx/libgdx/pull/3772
- API Change: Lwjgl3WindowListener.refreshRequested() is called when the windowing system (GLFW) reports contents of a window are dirty and need to be redrawn.
- API Change: Lwjgl3WindowListener.maximized() is called when a window enters or exits a maximized state.
- API Change: Lwjgl3WindowListener.deiconified() removed, combined with .iconified().
- API Change: Lwjgl3Window.deiconify() renamed to .restore() since it can also be used to de-maximize a window.
- Lwjgl3Window now has a maximize() method, and windows can be started maximized using the window or app configuration's setMaximized() method.
- NinePatch can now be drawn rotated or scaled.
- NinepatchDrawable is now a TransformDrawable.
- API Change: Group add* methods no longer remove and re-add the actor if it is already in the group, instead they do nothing.
- API Change: g2d.Animation is now generic so it can support Drawables, PolygonRegions, NinePatches, etc. To fix existing code, specify the TextureRegion type in animation declarations (and instantiations in Java 6), i.e. Animation myAnimation = new Animation(...);
- TiledDrawable throws unsupported operation if trying to draw rotated/scaled. #4005
- API Change: DragAndDrop now puts default position of drag actor at pointer location. The original default offset from the pointer was (14, -20).
- Added ShaderProgramLoader for AssetManager.
- BoundingBox#isValid now returns also true when min==max, see: https://github.com/libgdx/libgdx/pull/4460
 

For details on updating your LibGDX project to the latest version see here.

GameDev News

Month List

Popular Comments

All posts tagged 'PSSDK'
Subscribe to GameFromScratch on YouTube Support GameFromScratch on Patreon

22. March 2013

 

So, some exciting personal news today, I can finally unveil what I've been working on the last several months, my new book PlayStation Mobile Cookbook!  A special thanks to my reviewers and supporters at Sony and the entire team at Packt, it was a pleasure working with you all on this book.

 

If you have never read one of Packt's "cookbook style" books, its basically composed of a series of recipes illustrating how to perform a particular task

followed by a detailed description of what's happening as well as various tips and tricks.  In this case, its contains over 60 different sample applications illustrating how to do… well, just about everything you want to with the PlayStation Mobile SDK.  If you've run through any of my tutorials, you should have a pretty good idea of what to expect.

 

For a better idea of the contents of the book, here is the Table of Contents:

 

  • Preface

 
  • Chapter 1: Getting Started

    • Introduction
    • Accessing the PlayStation Mobile portal
    • Installing the PlayStation Mobile SDK
    • Creating a simple game loop
    • Loading, displaying, and translating a textured image
    • "Hello World" drawing text on an image
    • Deploying to PlayStation certified Mobile Android devices
    • Deploying to a PlayStation Vita
    • Manipulating an image dynamically
    • Working with the filesystem
    • Handling system events
 
  • Chapter 2: Controlling Your PlayStation Mobile Device

    • Introduction
    • Handling the controller's d-pad and buttons
    • Using the Input2 wrapper class
    • Using the analog joysticks
    • Handling touch events
    • Using the motion sensors
    • Creating onscreen controls for devices without gamepads
    • Configuring an Android application to use onscreen controls
 
  • Chapter 3: Graphics with GameEngine2D

    • Introduction
    • A game loop, GameEngine2D style
    • Creating scenes
    • Adding a sprite to a scene
    • Creating a sprite sheet
    • Using a sprite sheet in code
    • Batching a sprite with SpriteLists
    • Manipulating a texture's pixels
    • Creating a 2D particle system
 
  • Chapter 4: Performing Actions with GameEngine2D

    • Introduction
    • Handling updates with Scheduler
    • Working with the ActionManager object
    • Using predefined actions
    • Transitioning between scenes
    • Simple collision detection
    • Playing background music
    • Playing sound effects
 
  • Chapter 5: Working with Physics2D

    • Introduction
    • Creating a simple simulation with gravity
    • Switching between dynamic and kinematic
    • Creating a (physics!) joint
    • Applying force and picking a physics scene object
    • Querying if a collision occurred
    • Rigid body collision shapes
    • Building and using an external library
 
  • Chapter 6: Working with GUIs

    • Introduction
    • "Hello World" – HighLevel.UI style
    • Using the UI library within a GameEngine2D application
    • Creating and using hierarchies of widgets
    • Creating a UI visually using UIComposer
    • Displaying a MessageBox dialog
    • Handling touch gestures and using UI effects
    • Handling language localization
 
  • Chapter 7: Into the Third Dimension

    • Introduction
    • Creating a simple 3D scene
    • Displaying a textured 3D object
    • Implementing a simple camera system
    • A fragment (pixel) shader in action
    • A vertex shader in action
    • Adding lighting to your scene
    • Using an offscreen frame buffer to take a screenshot
 
  • Chapter 8: Working with the Model Library

    • Introduction
    • Importing a 3D model for use in PlayStation Mobile
    • Loading and displaying a 3D model
    • Using BasicProgram to perform texture and shader effects
    • Controlling lighting using BasicProgram
    • Animating a model
    • Handling multiple animations
    • Using bones to add a sword to our animated model
 
  • Chapter 9: Finishing Touches

    • Introduction
    • Opening and loading a web browser
    • Socket-based client and server networking
    • Accessing (Twitter) data over the network using REST and HttpWebRequest
    • Copying and pasting using Clipboard
    • Embedding and retrieving a resource from the application assembly
    • Configuring your application using PublishingUtility
    • Creating downloadable content (DLC) for your application
 
  • Appendix: Publishing Your Application

    • Introduction
 
  • Index

 

The book is quite literally at the printers right now, I'll post more details once it's available on Amazon, on Safari Books Online or in stores for purchase.  It should be in the next couple of days.  You can of course order the book on the Packt website.

 

Are trying to figure out what to get your grandmother for her birthday?  I have the perfect recommendation! :)

 

Hope you enjoy the book!

, ,

24. February 2013

 

A new beta release of the PlayStation Mobile SDK has just been released.

 

First off, it’s very important to realize this is a *BETA RELEASE*, meaning you can publish with this version.  This version also cannot be installed side by side with the release version.

 

Key changes in this version are:

 

Changes in Version 1.10.00

  • PS3(TM) wireless controller is available on PC Simulator.
  • Screen can be scaled and rendered automatically when actual device screen size is different from specified size in the program.
  • ADPCM format supported in Sound class.
  • New APIs added to SoundPlayer and BgmPlayer.
  • Camera and Location APIs added.
  • Improved CPU performance on PlayStation(R)Vita.
  • Fixed some issues of HTTP/HTTPS connection.
  • Fixed other issues.

 

Some pretty nice changes in this release.  The use of a PS3 controller with the Simulator was a huge missing feature, it’s nice to see it added as you can now test analog controls in the simulator.  Adding GPS and Camera SDKs is also quite nice, as of course are performance fixes.

 

You can read the full details here.

News ,

19. November 2012

 

Over on the PlayStation Mobile forums, a user asked:

For example, if I had a 100 x 100 image, I could use the source rectangle to  draw, say, the left part of the image 50 x 100.  This is useful when I have two images that represent the same object, e.g. a fancy progress meter, one light, the other dark.  SpriteUV has Quad which allows me to stretch and skew the image, but not crop.

Am I missing something? If not, what are my options?

 

My answer wasn’t a short one, so I decided to essentially turn it in to a tutorial post in and of itself.  So, if you want to learn how to do this, or how UV coordinates work in the first place, read on!

 

The answer is, yes, you can very much do this with PSM Studio, but the way might not be completely intuitive.  Each sprite has a TRS set ( Translation/Rotation/Scale ) that represents its UV coordinates within its textures.    Essentially when you work with a SpriteTile, it’s handling all this magic for you.  The good news is, you can manipulate the UV values of a SpriteUV to accomplish exactly the effects described in the question above.  If what you are looking to do is create a sprite sheet animation however, there is a much better way.

 

Alright, let’s jump right in with some code:

 

using System;
using Sce.PlayStation.Core;
using Sce.PlayStation.Core.Graphics;
using Sce.PlayStation.Core.Input;
using Sce.PlayStation.HighLevel.GameEngine2D;
using Sce.PlayStation.HighLevel.GameEngine2D.Base;

namespace Test
{
    public class AppMain
    {
        public static void Main (string[] args)
        {
            Director.Initialize();
            Scene scene = new Scene();
            scene.Camera.SetViewFromViewport();
            
            SpriteUV sprite = new SpriteUV(new TextureInfo("/Application/watch.png"));
            sprite.Scale = new Vector2(Director.Instance.GL.Context.Screen.Width,
                                       Director.Instance.GL.Context.Screen.Height);
            sprite.Schedule((dt) => {
                var g = GamePad.GetData(0);
                if((g.Buttons & GamePadButtons.Up) == GamePadButtons.Up){
                    // Top left
                    sprite.UV.S = new Vector2(0.5f,0.5f);
                    sprite.UV.T = new Vector2(0.0f,0.5f);
                }
                else if((g.Buttons & GamePadButtons.Left) == GamePadButtons.Left){
                    // Bottom left
                    sprite.UV.S = new Vector2(0.5f,0.5f);
                    sprite.UV.T = new Vector2(0.0f,0.0f);
                }
                else if ((g.Buttons & GamePadButtons.Down) == GamePadButtons.Down){
                    // Bottom right                
                    sprite.UV.S = new Vector2(0.5f,0.5f);
                    sprite.UV.T = new Vector2(0.5f,0.0f);
                }
                else if ((g.Buttons & GamePadButtons.Right) == GamePadButtons.Right){
                    // Top right
                    sprite.UV.S = new Vector2(0.5f,0.5f);
                    sprite.UV.T = new Vector2(0.5f,0.5f);
                }
                else if((g.Buttons & GamePadButtons.Cross) == GamePadButtons.Cross){
                    // Back to full screen
                    sprite.UV.S = new Vector2(1.0f,1.0f);
                    sprite.UV.T = new Vector2(0.0f,0.0f);
                }
            },0);
            
            scene.AddChild(sprite);
            Director.Instance.RunWithScene(scene);
        }
    }
}

 

Run this code and you will see:

full

 

Now press an arrow key ( here is the results for UP ) and you will see a fraction of the original texture:

topleft

Press X to go back to the full texture dimensions.

 

So… what’s happening here?

 

First off, we Initialize our Director singleton, create a Scene and set the camera up to match the device screen dimensions.  We then create a SpriteUV and TextureInfo in a single line, loading an image of the famous Watchmen logo.  We then scale the sprite to also match the dimensions of the screen.

 

It’s in the Schedule lambda the bulk of our UV manipulation logic takes place.  As you can see, we get the GamePad state, and handle the user pressing the d-pad or X button ( S key on simulator ).  In the event the user presses a direction button, we manipulate the sprite’s UV.S and UV.T values depending on which direction the user pressed, as indicated by the comment in each if statement.  If the user presses the X button, we set the UV.S and UV.T values back to full size and the origin respectively.  Finally we add the sprite to the scene, then run the scene.

 

The heart of this example is the UV property, which is a TRS object.  If the term UV is unfamiliar to you, they are simply texture coordinates on a face.  They are called UV simply because there are two coordinates, U and V. The UV values  describe how a texture is mapped to a polygon face.  U and V values go from 0 to 1 and start in the bottom left corner of an image.  This means (0,0) is the bottom left corner of the texture, (1,1) is the top right coordinate of the texture while (0.5,0.5) is the very center of the texture.

 

So, using the SpriteUV.UV property, we can alter the Translation ( position ), Rotation and Scale of the selection within SpriteUV’s texture that is going to be drawn.  Think of these values as describing the location of a select box within the texture that are going to be copied and drawn as the texture.  Here is a bad diagram to attempt to explain what’s happening.

 

image

 

The background is our SpriteUV texture.  By default the UV.T is (0,0), meaning drawing will start from the bottom left.  By default the UV.S values will be (1,1), meaning no scaling will occur.  Using these defaults, when we draw our sprite, the entire image will be drawn.

 

Now consider the blue selection rectangle.  This has a UV.T value of (0.3,0.3) and a UV.S value of (0.5,0.5) …. okay… my drawing to scale kind sucked, just imagine that the blue rectange was a quarter of the entire image size.  These values mean that at position 0.3,0.3… or 30% right and 30% up from the origin in the bottom left, we start our selection.  Due to our S(cale) value of (0.5,0.5) it means our selection size is half the height and half the width of the texture.  In this example we are not making use of TR.R(otation).

 

Therefore, assuming the following diagram was to scale, with a Translation UV value of 0.3, 0.3 and Scale UV value of 0.5 and 0.5, when we draw our texture we will see:

image

 

And that is how you can use UV values to draw a portion of a sprite’s texture.  You may notice that SpriteUV has a pair of properties, FlipU and FlipV.  All these do is reverse the direction of the U or V coordinate, for example, flipping U would make (0,0) be at the bottom right of the image instead of the bottom left.

 

You can download the complete archive here.  Obviously the Watchman logo is protected under copyright and cannot be used commercially in any way whatsover, period, ever. For real.

Programming , , ,

19. October 2012

 

Sony, actually… and file this under the category of longest most unwieldy names ever, Sony Computer Entertainment Worldwide Studios Europe External Development Studio (yeah… really) in collaboration with Creative England and Birmingham Science Park have put together a contestimage called PlayStation Pioneers, with a grand prize of £25,000.  That’s about 40K in real money! Smile

 

So, how then do you go about winning this money?  Well, here are the details:

  • The opportunity is open to UK-based developers only
  • The goal is to take a concept/prototype and develop a playable ‘vertical slice’ suitable for consumer trial/user testing in summer 2013.
  • The deadline for submissions is 31st October 2012
  • Five finalists will then be selected to exhibit at this year’s LAUNCH conference taking place at Birmingham Science Park on 13th and 14th November 2012 and present their concepts to a panel.
  • £25,000 will be awarded to the winning entry
  • XDev will have the first right of refusal in regard to publishing the final game.
  • The winner will be announced by the panel at LAUNCH on 14th November 2012.

 

What isn’t explicitly listed in those requirements, your project will be for PlayStation Mobile.

 

That deadline is fast approaching (less than 2 weeks!).  Keep in mind though, you are submitting a *concept* by October 31st, not a complete game. 

 

The other line of note you should be aware of was:

XDev will have the first right of refusal in regard to publishing the final game

In other words, if they like you game, they get first crack at being the publisher.  Given that most indie developers would love to have a publisher, this shouldn’t be a huge deal, but is certainly something you should be aware of.

 

 

If you have never heard of it before, PlayStation Mobile is cross platform game development system based around Mono.  It is C# based, built over OpenGL ES and able to target the PlayStation Vita, as well as select Android mobile devices ( most Sony Android devices, plus select devices from HTC, Asus and a few other manufacturers ).  This site has a series of tutorials you can used to get started.

 

You can read the original announcement thread right here.

 

If you are interested in proceeding, be sure to read this guide (PDF link).  It gives more details of what is involved.  From that document, here is what is recommended in your proposal:

1. Concept summary (ideally one page).
2. A walkthrough/storyboard detailing the proposed ‘vertical slice’ playable.
3. Artwork/Visualisation that is representative of proposed final quality.
4. Design briefs (prototypes where possible) explaining key features.
5. A summary schedule and risk assessment re delivery of the ‘vertical slice’ playable to be delivered for full
consumer trial/user testing in summer 2013.
6. A commercial/financial business model, illustrating market potential for the concept on PS Mobile certified
platforms; (PS Vita, Xperia, Sony Tablet S etc.)
7. Details of relevant prior experience.

 

The PDF however has no more legal issues regarding publishing or IP ownership.

News ,

13. September 2012

 

This post is a simple summary of all the code used in the complete Vita game tutorial series, all on a single page.  Additionally, you can download the complete project here.

 

Here is the end result of all of this code in action:

Vita pong!

 

 

And here is the code:

 

AppMain.cs

using System;
using Sce.PlayStation.HighLevel.UI; 
using Sce.PlayStation.HighLevel.GameEngine2D;

namespace Pong
{
    public class AppMain
    {
        public static void Main (string[] args)
        {
            Director.Initialize();
            UISystem.Initialize(Director.Instance.GL.Context);
            Director.Instance.RunWithScene(new TitleScene());                
        }
    }
}

 

TitleScene.cs

using System;
using Sce.PlayStation.Core;
using Sce.PlayStation.Core.Graphics;
using Sce.PlayStation.Core.Audio;
using Sce.PlayStation.HighLevel.GameEngine2D;
using Sce.PlayStation.HighLevel.GameEngine2D.Base;
using Sce.PlayStation.Core.Input;
 
namespace Pong
{
    public class TitleScene : Scene
    {
        private TextureInfo _ti;
        private Texture2D _texture;
        
        private Bgm _titleSong;
        private BgmPlayer _songPlayer;
        
        public TitleScene ()
        {
            this.Camera.SetViewFromViewport();
            _texture = new Texture2D("Application/images/title.png",false);
            _ti = new TextureInfo(_texture);
            SpriteUV titleScreen = new SpriteUV(_ti);
            titleScreen.Scale = _ti.TextureSizef;
            titleScreen.Pivot = new Vector2(0.5f,0.5f);
            titleScreen.Position = new Vector2(Director.Instance.GL.Context.GetViewport().Width/2,
                                              Director.Instance.GL.Context.GetViewport().Height/2);
            this.AddChild(titleScreen);
            
            Vector4 origColor = titleScreen.Color;
            titleScreen.Color = new Vector4(0,0,0,0);
            var tintAction = new TintTo(origColor,10.0f);
            ActionManager.Instance.AddAction(tintAction,titleScreen);
            tintAction.Run();
            
            _titleSong = new Bgm("/Application/audio/titlesong.mp3");
            
            if(_songPlayer != null)
            _songPlayer.Dispose();
            _songPlayer = _titleSong.CreatePlayer();
            
            Scheduler.Instance.ScheduleUpdateForTarget(this,0,false);

            // Clear any queued clicks so we dont immediately exit if coming in from the menu
            Touch.GetData(0).Clear();
        }
        
        public override void OnEnter ()
        {
            _songPlayer.Loop = true;
            _songPlayer.Play();
        }
        public override void OnExit ()
        {
            base.OnExit ();
            _songPlayer.Stop();
            _songPlayer.Dispose();
            _songPlayer = null;
        }
        
        public override void Update (float dt)
        {
            base.Update (dt);
            var touches = Touch.GetData(0).ToArray();
            if((touches.Length >0 && touches[0].Status == TouchStatus.Down) || Input2.GamePad0.Cross.Press)
            {
                Director.Instance.ReplaceScene(new MenuScene());
            }
        }
    
        ~TitleScene()
        {
            _texture.Dispose();
            _ti.Dispose ();
        }
    }
}
 

MenuScene.cs

using System;
using Sce.PlayStation.Core;
using Sce.PlayStation.Core.Graphics;
using Sce.PlayStation.Core.Input;

using Sce.PlayStation.HighLevel.GameEngine2D;
using Sce.PlayStation.HighLevel.GameEngine2D.Base;

using Sce.PlayStation.HighLevel.UI;

namespace Pong
{
    public class MenuScene : Sce.PlayStation.HighLevel.GameEngine2D.Scene
    {
        private Sce.PlayStation.HighLevel.UI.Scene _uiScene;
        
        public MenuScene ()
        {
            this.Camera.SetViewFromViewport();
            Sce.PlayStation.HighLevel.UI.Panel dialog = new Panel();
            dialog.Width = Director.Instance.GL.Context.GetViewport().Width;
            dialog.Height = Director.Instance.GL.Context.GetViewport().Height;
            
            ImageBox ib = new ImageBox();
            ib.Width = dialog.Width;
            ib.Image = new ImageAsset("/Application/images/title.png",false);
            ib.Height = dialog.Height;
            ib.SetPosition(0.0f,0.0f);
            
            Button buttonUI1 = new Button();
            buttonUI1.Name = "buttonPlay";
            buttonUI1.Text = "Play Game";
            buttonUI1.Width = 300;
            buttonUI1.Height = 50;
            buttonUI1.Alpha = 0.8f;
            buttonUI1.SetPosition(dialog.Width/2 - 150,200.0f);
            buttonUI1.TouchEventReceived += (sender, e) => {
                Director.Instance.ReplaceScene(new GameScene());
            };
            
            Button buttonUI2 = new Button();
            buttonUI2.Name = "buttonMenu";
            buttonUI2.Text = "Main Menu";
            buttonUI2.Width = 300;
            buttonUI2.Height = 50;
            buttonUI2.Alpha = 0.8f;
            buttonUI2.SetPosition(dialog.Width/2 - 150,250.0f);
            buttonUI2.TouchEventReceived += (sender, e) => {
            Director.Instance.ReplaceScene(new TitleScene());
            };        
                
            dialog.AddChildLast(ib);
            dialog.AddChildLast(buttonUI1);
            dialog.AddChildLast(buttonUI2);
            _uiScene = new Sce.PlayStation.HighLevel.UI.Scene();
            _uiScene.RootWidget.AddChildLast(dialog);
            UISystem.SetScene(_uiScene);
            Scheduler.Instance.ScheduleUpdateForTarget(this,0,false);
        }
        public override void Update (float dt)
        {
            base.Update (dt);
            UISystem.Update(Touch.GetData(0));
            
        }
        
        public override void Draw ()
        {
            base.Draw();
            UISystem.Render ();
        }
        
        ~MenuScene()
        {
            
        }
    }
}

GameScene.cs

using System;
using Sce.PlayStation.Core;
using Sce.PlayStation.HighLevel.GameEngine2D;
using Sce.PlayStation.HighLevel.GameEngine2D.Base;
using Sce.PlayStation.HighLevel.Physics2D;
using Sce.PlayStation.Core.Audio;

namespace Pong
{
    public class GameScene : Scene
    {
    private Paddle _player,_ai;
    public static Ball ball;
    private PongPhysics _physics;
    private Scoreboard _scoreboard;
    private SoundPlayer _pongBlipSoundPlayer;
    private Sound _pongSound;
        
        // Change the following value to true if you want bounding boxes to be rendered
        private static Boolean DEBUG_BOUNDINGBOXS = false;
        
        public GameScene ()
        {
            this.Camera.SetViewFromViewport();
            _physics = new PongPhysics();

            
            ball = new Ball(_physics.SceneBodies[(int)PongPhysics.BODIES.Ball]);
            _player = new Paddle(Paddle.PaddleType.PLAYER, 
                                 _physics.SceneBodies[(int)PongPhysics.BODIES.Player]);
            _ai = new Paddle(Paddle.PaddleType.AI, 
                             _physics.SceneBodies[(int)PongPhysics.BODIES.Ai]);
            _scoreboard = new Scoreboard();
            
            this.AddChild(_scoreboard);
            this.AddChild(ball);
            this.AddChild(_player);
            this.AddChild(_ai);
            
            
            // This is debug routine that will draw the physics bounding box around the players paddle
            if(DEBUG_BOUNDINGBOXS)
            {
                this.AdHocDraw += () => {
                    var bottomLeftPlayer = _physics.SceneBodies[(int)PongPhysics.BODIES.Player].AabbMin;
                    var topRightPlayer = _physics.SceneBodies[(int)PongPhysics.BODIES.Player].AabbMax;
                    Director.Instance.DrawHelpers.DrawBounds2Fill(
                        new Bounds2(bottomLeftPlayer*PongPhysics.PtoM,topRightPlayer*PongPhysics.PtoM));

                    var bottomLeftAi = _physics.SceneBodies[(int)PongPhysics.BODIES.Ai].AabbMin;
                    var topRightAi = _physics.SceneBodies[(int)PongPhysics.BODIES.Ai].AabbMax;
                    Director.Instance.DrawHelpers.DrawBounds2Fill(
                        new Bounds2(bottomLeftAi*PongPhysics.PtoM,topRightAi*PongPhysics.PtoM));

                    var bottomLeftBall = _physics.SceneBodies[(int)PongPhysics.BODIES.Ball].AabbMin;
                    var topRightBall = _physics.SceneBodies[(int)PongPhysics.BODIES.Ball].AabbMax;
                    Director.Instance.DrawHelpers.DrawBounds2Fill(
                        new Bounds2(bottomLeftBall*PongPhysics.PtoM,topRightBall*PongPhysics.PtoM));
                };
            }
            
            //Now load the sound fx and create a player
            _pongSound = new Sound("/Application/audio/pongblip.wav");
            _pongBlipSoundPlayer = _pongSound.CreatePlayer();
            
            Scheduler.Instance.ScheduleUpdateForTarget(this,0,false);
        }
        
        private void ResetBall()
        {
            //Move ball to screen center and release in a random directory
            _physics.SceneBodies[(int)PongPhysics.BODIES.Ball].Position = 
                new Vector2(Director.Instance.GL.Context.GetViewport().Width/2,
                            Director.Instance.GL.Context.GetViewport().Height/2) / PongPhysics.PtoM;
            
            System.Random rand = new System.Random();
            float angle = (float)rand.Next(0,360);
        
            if((angle%90) <=15) angle +=15.0f;
        
            _physics.SceneBodies[(int)PongPhysics.BODIES.Ball].Velocity = 
                new Vector2(0.0f,5.0f).Rotate(PhysicsUtility.GetRadian(angle));
        }
        
        public override void Update (float dt)
        {
            base.Update (dt);
            
            if(Input2.GamePad0.Select.Press)
                Director.Instance.ReplaceScene(new MenuScene());
            
            //We don't need these, but sadly, the Simulate call does.
            Vector2 dummy1 = new Vector2();
            Vector2 dummy2 = new Vector2();
            
            //Update the physics simulation
            _physics.Simulate(-1,ref dummy1,ref dummy2);
            
            //Now check if the ball it either paddle, and if so, play the sound
            if(_physics.QueryContact((uint)PongPhysics.BODIES.Ball,(uint)PongPhysics.BODIES.Player) ||
                _physics.QueryContact((uint)PongPhysics.BODIES.Ball,(uint)PongPhysics.BODIES.Ai))
            {
                if(_pongBlipSoundPlayer.Status == SoundStatus.Stopped)
                    _pongBlipSoundPlayer.Play();
            }
            
            //Check if the ball went off the top or bottom of the screen and update score accordingly
            Results result = Results.StillPlaying;
            bool scored = false;
            
            if(ball.Position.Y > Director.Instance.GL.Context.GetViewport().Height + ball.Scale.Y/2)
            {
                result = _scoreboard.AddScore(true);
                scored = true;
            }
            if(ball.Position.Y < 0 - ball.Scale.Y/2)
            {
                result =_scoreboard.AddScore(false);
                scored = true;
            }
            
            // Did someone win?  If so, show the GameOver scene
            if(result == Results.AiWin) 
                Director.Instance.ReplaceScene(new GameOverScene(false));
            if(result == Results.PlayerWin) 
                Director.Instance.ReplaceScene(new GameOverScene(true));
            
            //If someone did score, but game isn't over, reset the ball position to the middle of the screen
            if(scored == true)
            {
                ResetBall ();
            }
            
            //Finally a sanity check to make sure the ball didn't leave the field.
            var ballPB = _physics.SceneBodies[(int)PongPhysics.BODIES.Ball];
            
            if(ballPB.Position.X < -(ball.Scale.X/2f)/PongPhysics.PtoM ||
               ballPB.Position.X > (Director.Instance.GL.Context.GetViewport().Width)/PongPhysics.PtoM)
            {
                ResetBall();
            }
        }
        
        ~GameScene(){
            _pongBlipSoundPlayer.Dispose();
        }
    }
}

Ball.cs

using System;
using Sce.PlayStation.Core;
using Sce.PlayStation.Core.Graphics;
using Sce.PlayStation.HighLevel.GameEngine2D;
using Sce.PlayStation.HighLevel.GameEngine2D.Base;
using Sce.PlayStation.HighLevel.Physics2D;

namespace Pong
{
    public class Ball : SpriteUV
    {
        private PhysicsBody _physicsBody;
        // Change this value to make the game faster or slower
        public const float BALL_VELOCITY = 5.0f;
        
        public Ball (PhysicsBody physicsBody)
        {
            _physicsBody = physicsBody;
            
            this.TextureInfo = new TextureInfo(new Texture2D("Application/images/ball.png",false));
            this.Scale = this.TextureInfo.TextureSizef;
            this.Pivot = new Sce.PlayStation.Core.Vector2(0.5f,0.5f);
            this.Position = new Sce.PlayStation.Core.Vector2(
                Director.Instance.GL.Context.GetViewport().Width/2 -Scale.X/2,
                Director.Instance.GL.Context.GetViewport().Height/2 -Scale.Y/2);
            
            
            //Right angles are exceedingly boring, so make sure we dont start on one
            //So if our Random angle is between 90 +- 25 degrees or 270 +- 25 degrees
            //we add 25 degree to value, ie, making 90 into 115 instead
            System.Random rand = new System.Random();
            float angle = (float)rand.Next(0,360);
        
            if((angle%90) <=25) angle +=25.0f;
            this._physicsBody.Velocity = new Vector2(0.0f,BALL_VELOCITY).Rotate(PhysicsUtility.GetRadian(angle));;
            
            Scheduler.Instance.ScheduleUpdateForTarget(this,0,false);
        }
        
        public override void Update (float dt)
        {

            this.Position = _physicsBody.Position * PongPhysics.PtoM;

            
            // We want to prevent situations where the balls is bouncing side to side
            // so if there isnt a certain amount of movement on the Y axis, set it to + or - 0.2 randomly
            // Note, this can result in the ball bouncing "back", as in it comes from the top of the screen
            // But riccochets back up at the user.  Frankly, this keeps things interesting imho
            var normalizedVel = _physicsBody.Velocity.Normalize();
            if(System.Math.Abs (normalizedVel.Y) < 0.2f) 
            {
                System.Random rand = new System.Random();
                if(rand.Next (0,1) == 0)
                    normalizedVel.Y+= 0.2f;
                
                else
                    normalizedVel.Y-= 0.2f;
            }
            
            // Pong is a mess with physics, so just fix the ball velocity
            // Otherwise the ball could get faster and faster ( or slower ) on each collision
            _physicsBody.Velocity = normalizedVel * BALL_VELOCITY;

        }
        
        ~Ball()
        {
            this.TextureInfo.Texture.Dispose();
            this.TextureInfo.Dispose();
        }
    }
}

Paddle.cs

using System;
using Sce.PlayStation.Core;
using Sce.PlayStation.Core.Graphics;
using Sce.PlayStation.HighLevel.GameEngine2D;
using Sce.PlayStation.HighLevel.GameEngine2D.Base;
using Sce.PlayStation.HighLevel.Physics2D;

namespace Pong
{
    public class Paddle : SpriteUV
    {
        public enum PaddleType { PLAYER, AI };
        
        private PaddleType _type;
        private PhysicsBody _physicsBody;
        private float _fixedY;
        
        public Paddle (PaddleType type, PhysicsBody physicsBody)
        {
            _physicsBody = physicsBody;
            _type = type;

            this.TextureInfo = new TextureInfo(new Texture2D("Application/images/Paddle.png",false));
            this.Scale = this.TextureInfo.TextureSizef;
            this.Pivot = new Sce.PlayStation.Core.Vector2(0.5f,0.5f);
            
            if(_type== PaddleType.AI)
            {
                this.Position = new Sce.PlayStation.Core.Vector2(
                    Director.Instance.GL.Context.GetViewport().Width/2 - this.Scale.X/2,
                    10 + this.Scale.Y/2);                    
            }
            else
            {
                this.Position = new Sce.PlayStation.Core.Vector2(
                    Director.Instance.GL.Context.GetViewport().Width/2 - this.Scale.X/2,
                    Director.Instance.GL.Context.GetViewport().Height - this.Scale.Y/2 - 10);
            }
            
            // Cache the starting Y position, so we can reset and prevent any vertical movement from the Physics Engien
            _fixedY = _physicsBody.Position.Y;
            
            // Start with a minor amount of movement
            _physicsBody.Force = new Vector2(-10.0f,0);
            
            Scheduler.Instance.ScheduleUpdateForTarget(this,0,false);
        }
        
        // This method will fix the physics bounding box to the sprites current position
        // Not currently used, was used for debug, left in for interest sake only
        private void ClampBoundingBox()
        {
            var bbBL = new Vector2(Position.X- Scale.X/2, Position.Y- Scale.Y/2) / PongPhysics.PtoM;
            var bbTR = new Vector2(Position.X+ Scale.X/2, Position.Y+ Scale.Y/2) / PongPhysics.PtoM;
            _physicsBody.AabbMin = bbBL;
            _physicsBody.AabbMax = bbTR;
            
        }
        public override void Update (float dt)
        {
            // Reset rotation to prevent "spinning" on collision
            _physicsBody.Rotation = 0.0f;
            
            
            if(_type == PaddleType.PLAYER)
            {
                if(Input2.GamePad0.Left.Down)
                {
                    _physicsBody.Force = new Vector2(-30.0f,0.0f);
                }
                if(Input2.GamePad0.Right.Down)
                {
                    _physicsBody.Force = new Vector2(30.0f,0.0f);
                }
            }
            else if(_type == PaddleType.AI)
            {
                if(System.Math.Abs (GameScene.ball.Position.X - this.Position.X) <= this.Scale.Y/2)
                    _physicsBody.Force = new Vector2(0.0f,0.0f);
                else if(GameScene.ball.Position.X < this.Position.X)
                    _physicsBody.Force = new Vector2(-20.0f,0.0f);
                else if(GameScene.ball.Position.X > this.Position.X)
                    _physicsBody.Force = new Vector2(20.0f,0.0f);
            }
            
            //Prevent vertical movement on collision.  Could also implement by making paddle Kinematic
            //However, lose ability to use Force in that case and have to use AngularVelocity instead
            //which results in more logic in keeping the AI less "twitchy", a common Pong problem
            if(_physicsBody.Position.Y != _fixedY)
                _physicsBody.Position = new Vector2(_physicsBody.Position.X,_fixedY);
            
            this.Position = _physicsBody.Position * PongPhysics.PtoM;
        }
        
        ~Paddle()
        {
            this.TextureInfo.Texture.Dispose ();
            this.TextureInfo.Dispose();
        }
    }
}

Scoreboard.cs

using System;

using Sce.PlayStation.Core.Imaging;
using Sce.PlayStation.Core.Graphics;
using Sce.PlayStation.Core;
using Sce.PlayStation.HighLevel.GameEngine2D;
using Sce.PlayStation.HighLevel.GameEngine2D.Base;

namespace Pong
{
    public enum Results { PlayerWin, AiWin, StillPlaying };
    
    public class Scoreboard : SpriteUV
    {
        public int playerScore = 0;
        public int aiScore = 0;
        
        public Scoreboard ()
        {
            this.TextureInfo = new TextureInfo();
            UpdateImage();
            
            this.Scale = this.TextureInfo.TextureSizef;
            this.Pivot = new Vector2(0.5f,0.5f);
            this.Position = new Vector2(Director.Instance.GL.Context.GetViewport().Width/2,
                                        Director.Instance.GL.Context.GetViewport().Height/2);
            
        }
        
        private void UpdateImage()
        {
            Image image = new Image(ImageMode.Rgba,new ImageSize(110,100),new ImageColor(0,0,0,0));
            Font font = new Font(FontAlias.System,50,FontStyle.Regular);
            image.DrawText(playerScore + " - " + aiScore,new ImageColor(255,255,255,255),font,new ImagePosition(0,0));
            image.Decode();

            var texture  = new Texture2D(110,100,false,PixelFormat.Rgba);
            if(this.TextureInfo.Texture != null)
                this.TextureInfo.Texture.Dispose();
            this.TextureInfo.Texture = texture;
            texture.SetPixels(0,image.ToBuffer());
            font.Dispose();
            image.Dispose();
        }
        public void Clear()
        {
            playerScore = aiScore = 0;
            UpdateImage();
        }
        
        public Results AddScore(bool player)
        {
            if(player)
                playerScore++;
            else
                aiScore++;
            if(playerScore > 3) return Results.PlayerWin;
            if(aiScore > 3) return Results.AiWin;
            
            UpdateImage();

            return Results.StillPlaying;
        }
    }
}

GameOver.cs

using System;
using Sce.PlayStation.Core;
using Sce.PlayStation.Core.Graphics;
using Sce.PlayStation.Core.Audio;
using Sce.PlayStation.HighLevel.GameEngine2D;
using Sce.PlayStation.HighLevel.GameEngine2D.Base;
using Sce.PlayStation.Core.Input;

namespace Pong
{
    public class GameOverScene : Scene
    {
        private TextureInfo _ti;
        private Texture2D _texture;
        
        public GameOverScene (bool win)
        {
            this.Camera.SetViewFromViewport();
            if(win)
                _texture = new Texture2D("Application/images/winner.png",false);
            else
                _texture = new Texture2D("Application/images/loser.png",false);
            _ti = new TextureInfo(_texture);
            SpriteUV titleScreen = new SpriteUV(_ti);
            titleScreen.Scale = _ti.TextureSizef;
            titleScreen.Pivot = new Vector2(0.5f,0.5f);
            titleScreen.Position = new Vector2(Director.Instance.GL.Context.GetViewport().Width/2,
                                               Director.Instance.GL.Context.GetViewport().Height/2);
            this.AddChild(titleScreen);
            
            Scheduler.Instance.ScheduleUpdateForTarget(this,0,false);
            
            Touch.GetData(0).Clear();
        }
        
        public override void Update (float dt)
        {
            base.Update (dt);
            int touchCount = Touch.GetData(0).ToArray().Length;
            if(touchCount > 0 || Input2.GamePad0.Cross.Press)
            {
                Director.Instance.ReplaceScene( new TitleScene());
            }
        }
        
        ~GameOverScene()
        {
            _texture.Dispose();
            _ti.Dispose ();
        }
    }
}

Programming , , ,

Month List

Popular Comments