iPad's mobile safari crashing on canvas-based game (easeljs, soundjs, preloadjs) - ipad

I've done quite a bit of searching, so please forgive me if this has been asked before (I couldn't seem to find the right phrasing, if this is the case).
I have converted a quiz game from Flash to html5 using the createjs suite of libraries, and it is functioning suitably well on android devices and iPhones (tested on an iPhone 4s and 5c). However, it appears to be crashing on an iPad whenever I try and load it.
As I am packaging the game in cocoonjs for mobile deployment, I first thought the issue lied somewhere in the conversion process, but the same issue is encountered when I visit the URL on an iPad, leading me to believe the issue must be somewhere in my code.
The code itself uses a loadManifest to preload the image assets for the game and the opening audio file. There are approximately 170 assets loaded in this queue. The files are loaded using an onLoad method from the body tag and call loadFiles(), which looks like this (truncated for the multitude of image assets loaded in the manifest):
var queue = new createjs.LoadQueue(true);
var manifest = [
{id:"gameintro", src:"audio/intro.mp3"},
{src:"images/Path.png"},
...
{src:"images/owl.png"}
];
queue.loadManifest(manifest);
queue.setMaxConnections(5);
queue.addEventListener("complete", loadComplete);
function loadAll() {
document.getElementById('canvas').style.backgroundImage="url('images/splash.png')";
canvas = document.getElementById('canvas');
canvas.height = H;
canvas.width = W;
stage = new createjs.Stage("canvas");
var loadingText = new createjs.Text("Loading...", "bold 30px Arial", "#9d3202");
loadingText.x = 350;
loadingText.y = 585;
loadingText.textBaseline = "alphabetic";
stage.addChild(loadingText);
stage.update();
while (manifest.length > 0) {
loadAnother();
}
//console.log('done');
}
function loadAnother() {
// Get the next manifest item, and load it
var item = manifest.shift();
queue.loadFile(item);
// If we have no more items, disable the UI.
if (manifest.length == 0) {
//do nothing
}
}
function loadComplete()
{
stage.removeAllChildren();
var clickToPlay = new createjs.Bitmap("images/clicktoplay.png");
clickToPlay.x = 350;
clickToPlay.y = 565;
clickToPlay.textBaseline = "alphabetic";
stage.addChild(clickToPlay);
stage.update();
canvas.addEventListener("click", function(event) {
event.target.removeEventListener(event.type, arguments.callee);
createjs.Sound.registerSound({id:"gameintro", src:"audio/intro.mp3"});
createjs.Sound.addEventListener("fileload", function(event){
event.target.removeEventListener(event.type, arguments.callee);
init();
});
});
}
loadAll();
};
The init function that runs after this loads the remaining audio files (of which there are many ~ 160 mp3's) and starts the opening animation. The code for that section is as follows:
function init(){
createjs.Sound.registerSound({id:"meintroduction", src:"audio/Mentor/ME1.mp3"});
...
createjs.Sound.registerSound({id:"jennyfalse3", src:"audio/Pirate_Jenny/PJE10.mp3"});
document.getElementById('canvas').style.background="#B5D7ED";
canvas = document.getElementById('canvas');
canvas.height = H;
canvas.width = W;
stage = new createjs.Stage("canvas");
//add path
path = new createjs.Bitmap("images/Path.png");
path.x = 0;
path.y = 0;
stage.addChild(path);
//add sun
sun = new createjs.Bitmap("images/sun.png");
sun.x = 800;
sun.y = 600;
stage.addChild(sun);
//add pinkcloud
pinkcloud = new createjs.Bitmap("images/pinkcloud.png");
pinkcloud.x = -4;
pinkcloud.y = 150;
stage.addChild(pinkcloud);
//add bluecloud
bluecloud = new createjs.Bitmap("images/bluecloud.png");
bluecloud.x = -4;
bluecloud.y = 250;
stage.addChild(bluecloud);
//add farisland
farisland = new createjs.Bitmap("images/farisland.png");
farisland.x = 600;
farisland.y = 180;
stage.addChild(farisland);
//add backwave
backwave = new createjs.Bitmap("images/backwave.png");
backwave.x = -4;
backwave.y = 420;
stage.addChild(backwave);
//shark
shark = new createjs.Bitmap("images/shark.png");
shark.x = 900;
shark.y = 600;
stage.addChild(shark);
//fish3
fish3 = new createjs.Bitmap("images/fish3.png");
fish3.x = 800;
fish3.y = 600;
stage.addChild(fish3);
//add middlewave
middlewave = new createjs.Bitmap("images/middlewave.png");
middlewave.x = -800;
middlewave.y = 450;
stage.addChild(middlewave);
//add ship
pirateship = new createjs.Bitmap("images/pirateship.png");
pirateship.x = -500;
pirateship.y = 400;//445x384
pirateship.regX = 445/2;
pirateship.regY = 384/2;
stage.addChild(pirateship);
//fish1
fish1 = new createjs.Bitmap("images/fish1.png");
fish1.x = 800;
fish1.y = 600;
stage.addChild(fish1);
//fish1
fish2 = new createjs.Bitmap("images/fish2.png");
fish2.x = 900;
fish2.y = 700;
stage.addChild(fish2);
//add frontwave
frontwave = new createjs.Bitmap("images/frontwave.png");
frontwave.x = -4;
frontwave.y = 500;
stage.addChild(frontwave);
//bird
bird1 = new createjs.Bitmap("images/bird.png");
bird1.x = 0;
bird1.y = 0;
bird1.scaleX = -1;
stage.addChild(bird1);
bird2 = new createjs.Bitmap("images/bird.png");
bird2.x = 800;
bird2.y = 0;
stage.addChild(bird2);
//add island
island = new createjs.Bitmap("images/island.png");
island.x = 800;
island.y = 200;
stage.addChild(island);
//add setsail
setsail = new createjs.Bitmap("images/Setsail.png");
setsail.x = -358;
setsail.y = 80;
createjs.Tween.get(setsail).to({alpha: 0,},0);
stage.addChild(setsail);
setsail1 = new createjs.Bitmap("images/Setsail.png");
setsail1.x = 350;
setsail1.y = 80;
//add butwatchout
butwatchout = new createjs.Bitmap("images/Butwatchout.png");
butwatchout.x = -358;
butwatchout.y = 300;
createjs.Tween.get(butwatchout).to({alpha: 0,},0);
//stage.addChild(butwatchout);
butwatchout1 = new createjs.Bitmap("images/Butwatchout.png");
butwatchout1.x = 200;
butwatchout1.y = 300;
setTimeout(function(){createjs.Sound.play("gameintro");},1500);
fn = createjs.Ticker.on("tick", tick);
createjs.Ticker.setFPS(80);
createjs.Ticker.addEventListener("tick", stage );
}
The ticker then uses some basic rotations and tweens to move things about, and also employs some alpha filters to manage the transparency of certain assets (like the front wave on the ship). After all this is finished, the user then progresses into the actual game, which uses some very basic createjs.Bitmaps to add the elements to the stage, along with Sound.play and some SpriteSheets for the rudimentary animations like blinking and mouth-movements for the quizzers. However, the whole thing doesn't make it past the opening sequence on an iPad.
If anyone could take a look (amateurgamingleague.com/pirates/english) and give me a bit of insight as to where I'm messing up, out would be greatly appreciated!!
Thank you!

I have had the same crashes on Ipad (2). It even did delete all session cookies and my users where logged out...
The problem is the amount of sounds you're preloading (or how big they are, not sure). Change your code to not preload so many audio anymore, and load them on demand (when user clicks on something) if possible. I also needed to start the game with a click/touch/user event before any sound could be played.

I got the same issue.
Try to use slash before the directory like
var manifest = [
{id:"gameintro", src:"/audio/intro.mp3"},
{src:"/images/Path.png"},
...
{src:"/images/owl.png"}
];

Related

How to get rid of image tearing d3d11?

If I open my app in full screen, I get severe tears. In other games, even with vcync turned off, this is almost invisible. How can I achieve the same effect without vsync? cube example
DXGI_SWAP_CHAIN_DESC1 scd = {};
if (mIsGame)
{
scd.Width = RECT_WIDTH(mRect_Game);
scd.Height = RECT_HEIGHT(mRect_Game);
}
else
{
scd.Width = RECT_WIDTH(mRect_Editor);
scd.Height = RECT_HEIGHT(mRect_Editor);
}
scd.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
scd.SampleDesc.Count = 1;
scd.SampleDesc.Quality = 0;
scd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
scd.BufferCount = 1;
if (mIsGame)
scd.Flags = DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH;
FOG_TRACE(dxgiFactory2->CreateSwapChainForHwnd(mDevice, mHwnd, &scd, 0, 0, &mSwapChain1));
FOG_TRACE(mSwapChain1->QueryInterface(IID_PPV_ARGS(&mSwapChain)));
dxgiFactory2->Release();
if (mIsGame)
{
FOG_TRACE(mSwapChain1->SetFullscreenState(true, 0));
mFullScreen = true;
}

Windows 10 Universal App custom map

I want to create an app for airplane navigation. Since for pilots the Bing maps are useless I need to create my own map a texture of an aeronautical map.
I couldn't find any clue how to start on this. Is there an SDK for Bing maps where I can create my own texture/overlay?
Do I need to start from rock bottom and create a picture and change its position so the relevant part is in the visible area of the device?
I need the following features:
Show current position on the map.
Add some custom POIs via coordinates
After quite some research I figured it out myself.
Here is most of the code needed if you have the same scenario
Uri format:
"https://webserver/tiles/{zoomlevel}/{x}/{y}.png";
private void InitMap()
{
_gps = new Geolocator();
pointBuffer = cologne;
image = RandomAccessStreamReference.CreateFromUri(new Uri("ms-appx:///Assets/images/airplane.png"));
MyMap.Style = MapStyle.None;
//Setup Icao Layer
_icaoTileSource = new MapTileSource();
var _tileLayer = new HttpMapTileDataSource();
_tileLayer.UriFormatString = IcaoUri;
_icaoTileSource.DataSource = _tileLayer;
MyMap.TileSources.Add(_icaoTileSource);
//Setup VFR Layer
_vfrTileSource = new MapTileSource();
var _vfrtileLayer = new HttpMapTileDataSource();
_vfrtileLayer.UriFormatString = VfrUri;
_vfrTileSource.DataSource = _vfrtileLayer;
//Setup Low Level Layer
_lowlvlTileSource = new MapTileSource();
var _lowlvltileLayer = new HttpMapTileDataSource();
_lowlvltileLayer.UriFormatString = LowLvlUri;
_lowlvlTileSource.DataSource = _lowlvltileLayer;
airplane = new MapIcon()
{
Title = "My Position",
Image = image,
Visible = true,
Location = cologne,
NormalizedAnchorPoint = new Point(0.5, 0.5)
};
_tileLayer.AllowCaching = true;
MyMap.MapElements.Add(airplane);
systemSetCenter = true;
MyMap.Center = cologne;
MyMap.ZoomLevel = 10;
_vm.ZoomLevel = MyMap.ZoomLevel;
MyMap.ZoomLevelChanged += (s, e) =>
{
if(s.ZoomLevel > maxZoomLevel)
{
s.ZoomLevel = maxZoomLevel;
}
_vm.ZoomLevel = s.ZoomLevel;
};
}

How to set microphone buffer size in Web Audio API to avoid the 1/3 second delay (which is much faster in Java)?

This code works in Firefox in Windows 7. It plays transformed microphone on speakers. Its transformed by javascript code as numbers ranging -1 to 1 for audio amplitudes many times per second. It has a 1/3 second delay, but the same hardware runs much faster in java with my https://sourceforge.net/projects/jsoundcard software which adjusts buffer use by timing statistics. They both get faster when OS process thread priority is raised, but java is still much faster. Theres no reason Firefox or Web Audio API should have that much more delay, even though its become the norm that things dont work well in browsers, but with HTML5 (which is an open standard in progress) thats changing. Is there somewhere in Web Audio API to adjust the microphone buffer size?
var volume = .7;
var maxMicrophoneAmplitude = 1;
var soundFunc = function(ins, outs){
var microphoneAmplitude = ins[0];
var estimatedFramesPerSecond = 44100;
var decaySeconds = .1;
var decay = 1/(estimatedFramesPerSecond*decaySeconds);
maxMicrophoneAmplitude = Math.max(maxMicrophoneAmplitude, microphoneAmplitude)*(1-decay);
microphoneAmplitude/maxMicrophoneAmplitude * volume
outs[0] = microphoneAmplitude/maxMicrophoneAmplitude * volume;
};
soundFunc.inSize = 1;
soundFunc.outSize = 1;
var inputNodes = {};
window.onload = function(){
var context = new AudioContext();
if(!navigator.getUserMedia && navigator['mozGetUserMedia']){
navigator.getUserMedia = navigator['mozGetUserMedia'];
}
if(!navigator.getUserMedia && navigator['webkitGetUserMedia']){
navigator.getUserMedia = navigator['webkitGetUserMedia'];
}
if(!navigator.getUserMedia && navigator['msGetUserMedia']){
navigator.getUserMedia = navigator['msGetUserMedia'];
}
var framesPerBuffer = 1024;
var scriptNode = context.createScriptProcessor(framesPerBuffer, 1, 1);
scriptNode.onaudioprocess = function(audioProcessingEvent){
var inputBuffer = audioProcessingEvent.inputBuffer;
var outputBuffer = audioProcessingEvent.outputBuffer;
var chansIn = [];
var chansOut = [];
for(var c=0; c<inputBuffer.numberOfChannels; c++){
chansIn[c] = inputBuffer.getChannelData(c);
}
for(var c=0; c<outputBuffer.numberOfChannels; c++){
chansOut[c] = outputBuffer.getChannelData(c);
}
var ins = new Float32Array(inputBuffer.numberOfChannels);
var outs = new Float32Array(outputBuffer.numberOfChannels);
for(var f=0; f<framesPerBuffer; f++){
for(var c=0; c<inputBuffer.numberOfChannels; c++){
ins[c] = chansIn[c][f];
}
soundFunc(ins, outs);
for(var c=0; c<outputBuffer.numberOfChannels; c++){
chansOut[c][f] = outs[c];
}
}
}
if(navigator.getUserMedia){
navigator.getUserMedia(
{'audio':true},
function(stream){
var input = context.createMediaStreamSource(stream);
//http://stackoverflow.com/questions/22860468/html5-microphone-capture-stops-after-5-seconds-in-firefox says to save a reference to avoid sound ending after 5 seconds
inputNodes.mic = input;
input.connect(scriptNode);
scriptNode.connect(context.destination);
input.start();
},
function(e){ alert('Error capturing audio. e='+e); }
);
}else alert('getUserMedia not supported in this browser.');
};
I do believe (#cwilso can probably correct me on this if I'm wrong) that the API uses a model where samples are pulled from the nodes, rather than the nodes pushing the samples to the nodes following it. That means that the buffer size that you set in your script processor is the source of the delay, not the input buffer size of the microphone stream. Try setting that buffer size lower.
var framesPerBuffer = 256;
var scriptNode = context.createScriptProcessor(framesPerBuffer, 1, 1);

How to fill series data in candle chart in xamarin (TeeChart and MonoTouch)

I am using a tee chart library in xamarin (Android). i am facing a problem to daynamic binding data in "Candle Chart"
The Sample Code Like this!
protected override void OnCreate(Bundle bundle)
{
base.OnCreate(bundle);
RequestWindowFeature(WindowFeatures.NoTitle);
SetContentView(Resource.Layout.CandleChart);
//InitializeComponent();
chart = new Steema.TeeChart.TChart(this.ApplicationContext);
chart.Zoom.Style = Steema.TeeChart.ZoomStyles.InChart;
Steema.TeeChart.Themes.BlackIsBackTheme myTheme = new Steema.TeeChart.Themes.BlackIsBackTheme(chart.Chart);
myTheme.Apply();
Type tmp = (Type)Steema.TeeChart.Utils.SeriesTypesOf[12];
Steema.TeeChart.Styles.Series series;
series = chart.Series.Add(tmp);
series.FillSampleValues(); /* Here i want to fill series with my data listed bellow */
chart.Aspect.View3D = Needs3D(chart[0]);
chart.Panel.Transparent = true;
SetContentView(chart);
}
now i want add series data manually
like :
currentItem.Data.Close
currentItem.Data.Open
currentItem.Data.High
currentItem.Data.Low
currentItem.Time
etc.. so, plz help me to achieve this ..
thanks, in advance
==================================================================================
My Code Like as Bellow
private void LoadChart(GraphOutput resGraph)
{
DataSet_Obj.Tables.Add("CandleTable");
DataSet_Obj.Tables["CandleTable"].Columns.Add(new DataColumn("Date", System.Type.GetType("System.DateTime")));
DataSet_Obj.Tables["CandleTable"].Columns.Add(new DataColumn("Open", System.Type.GetType("System.Double")));
DataSet_Obj.Tables["CandleTable"].Columns.Add(new DataColumn("Close", System.Type.GetType("System.Double")));
DataSet_Obj.Tables["CandleTable"].Columns.Add(new DataColumn("High", System.Type.GetType("System.Double")));
DataSet_Obj.Tables["CandleTable"].Columns.Add(new DataColumn("Low", System.Type.GetType("System.Double")));
for (int i = 0; i < resGraph.graphSymbol[0].CandleSticks.Length; i++)
{
DataRow_Obj = DataSet_Obj.Tables["CandleTable"].NewRow();
DataRow_Obj["Date"] = resGraph.graphSymbol[0].CandleSticks[i].CandleTime; //DateTime
DataRow_Obj["Low"] = resGraph.graphSymbol[0].CandleSticks[i].CandleData.Low; //Float
DataRow_Obj["Close"] = resGraph.graphSymbol[0].CandleSticks[i].CandleData.Close; //Float
DataRow_Obj["Open"] = resGraph.graphSymbol[0].CandleSticks[i].CandleData.Open; //Float
DataRow_Obj["High"] = resGraph.graphSymbol[0].CandleSticks[i].CandleData.High; //Float
DataSet_Obj.Tables["CandleTable"].Rows.Add(DataRow_Obj);
DataRow_Obj = null;
}
Tag_Serie_Candle = new Steema.TeeChart.Styles.Candle ();
chart.Series.Add(Tag_Serie_Candle);
chart.Aspect.View3D = Needs3D(chart[0]);
chart.Panel.Transparent = true;
try
{
Tag_Serie_Candle.DataSource = DataSet_Obj.Tables["CandleTable"]; /* here I got Error Like: "Cannot bind to non-supported datasource: CandleTable" */
Tag_Serie_Candle.OpenValues.DataMember = DataSet_Obj.Tables["CandleTable"].Columns["Open"].ToString();
Tag_Serie_Candle.CloseValues.DataMember = DataSet_Obj.Tables["CandleTable"].Columns["Close"].ToString();
Tag_Serie_Candle.DateValues.DataMember = DataSet_Obj.Tables["CandleTable"].Columns["Date"].ToString();
Tag_Serie_Candle.DateValues.DateTime = true;
Tag_Serie_Candle.HighValues.DataMember = DataSet_Obj.Tables["CandleTable"].Columns["High"].ToString();
Tag_Serie_Candle.LowValues.DataMember = DataSet_Obj.Tables["CandleTable"].Columns["Low"].ToString();
Tag_Serie_Candle.LabelMember = "Candle Chart";
Tag_Serie_Candle.CheckDataSource();
chartpie.AddView(chart, new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MatchParent, ViewGroup.LayoutParams.MatchParent));
}
catch (Exception exe)
{
exe.Message.ToString();
}
}
You should do something as in the examples here:
http://www.teechart.net/support/viewtopic.php?f=4&t=2978&p=10547#p10547
http://www.teechart.net/support/viewtopic.php?f=4&t=3291&p=11691#p11691
http://www.teechart.net/support/viewtopic.php?f=4&t=2741&p=11681#p11681
I have found that, at the present moment, this is not working. I added the defect (ID566) list to be fixed as soon as possible (now fixed, see update at the bottom of the reply). If you register at Steema Software's Bugzilla system, you will be able to be in the CC List and be notified about status updates. In the meantime you can manually read values from the DataSet using this code:
Tag_Serie_Candle.DateValues.DateTime = true;
for (int i = 0; i < DataSet_Obj.Tables["CandleTable"].Rows.Count; i++)
{
DataRow row = DataSet_Obj.Tables["CandleTable"].Rows[i];
DateTime dt = Convert.ToDateTime(row["Date"]);
Double open = Convert.ToDouble(row["Open"]);
Double high = Convert.ToDouble(row["High"]);
Double low = Convert.ToDouble(row["Low"]);
Double close = Convert.ToDouble(row["Close"]);
Tag_Serie_Candle.Add(dt, open, high, low, close);
}
UPDATE: As of 11th February 2014, the defect has been fixed. Anyone interested in testing the solution please let me know.

In Actionscript, is there a way to create a copy or cached version of a Loader?

I'm loading an SWF animation and want to display it in multiple places concurrently, but the only way I could figure out how to do that is to load it every time I display it, as seen here:
private function playSounds():void {
for (var i:Number = 0; i < 14; i++)
{
for (var a:Number = 0; a < 16; a++)
{
if (boxes[i][a].x == linePos && boxes[i][a].selected == true && played[i][a] == false)
{
played[i][a] = true;
MovieClip();
var swf:URLRequest = new URLRequest("../assets/glow2.swf")
var glow:Loader = new Loader()
glow.load(swf)
glow.x = boxes[i][a].x - 25*0.7;
glow.y = boxes[i][a].y - 27*0.7;
glow.scaleX = 0.7;
glow.scaleY = 0.7;
this.addChild(glow);
glows.push(glow)
glowTime.push(0)
var sc:SoundChannel = new SoundChannel();
sc = (sounds[i] as Sound).play();
}
}
}
}
This is very very slow when it's being displayed more than, say, 5 times at once so I'm wondering if there's a way to only have to load it once and use it in multiple places.
You have the content property of the Loader.
Thus, load once, use the content many times.
edit: you may want to add a listener to know when the loading completes, before you use the loaded content:
addEventListener(Event.COMPLETE, completeHandler);
edit2:
var mc1:MovieClip = new MovieClip();
var mc2:MovieClip = new MovieClip();
var my_Loader:Loader = new Loader();
mc1.addChild(my_Loader);
mc2.addChild(my_Loader);
(haven't tried though).
One quick workaround is to create a second loader and pass the loaded bytes to that via the loadBytes() method:
var l:Loader = new Loader();
l.contentLoaderInfo.addEventListener(Event.COMPLETE,ready);
l.load(new URLRequest("../assets/glow2.swf"));
function ready(event:Event):void{
var mc:MovieClip = event.currentTarget.content as MovieClip;
var clone:Loader = new Loader();
clone.loadBytes(event.currentTarget.bytes);
addChild(mc);
addChild(clone);
clone.x = 100;
}
This will work in most cases. In some cases you should be able to get away with something as simple as:
var clone:MovieClip = MovieClip(new mc.constructor());
And there is also a 3rd option: 'blitting' your moviclip, which means you'll store one or more (depending how many MoveClip frames you need to cache) of BitmapData objects in memory which will draw() from the source MovieClip you want to draw (in multiple locations at the same time).
The loadBytes approach achieves what the question suggests: creates a copy of the Loader, so it re-uses the bytes loaded, but initializes new content, so uses memory for that.
If this is not what you need, caching the MovieClip using BitmapData is your best bet.

Resources