WriteableBitmapEx Resize function in WInRT - windows-runtime

I try to write function that will be resize images. I use WriteableBitmapEx for WinRT/Win8 function Resize();
public class PictureExtension
{
private MemoryRandomAccessStream _memoryRandomAccessStream;
private readonly Stream _dataStream;
private readonly double _height;
private readonly double _width;
public PictureExtension(Stream dataStream, double height, double width)
{
_dataStream = dataStream;
_memoryRandomAccessStream = (_dataStream.ToRandomAccessStream());
_height = height;
_width = width;
}
public byte[] ToArray(double maxSide)
{
if (_height <= maxSide && _width <= maxSide)
{
return _dataStream.ToArray();
}
else
{
var target = new WriteableBitmap((int) _width, (int) _height);
var aspectRatio = (double)_width / _height;
double newHeight;
double newWidth;
if (_width > _height)
{
newWidth = maxSide;
newHeight = newWidth / aspectRatio;
}
else
{
newHeight = maxSide;
newWidth = maxSide * aspectRatio;
}
int count = (int)_dataStream.Length;
using (var bmpStream = target.PixelBuffer.AsStream())
{
bmpStream.Seek(0, SeekOrigin.Begin);
bmpStream.Write(_dataStream.ToArray(), 0, _dataStream.ToArray().Length);
}
var resized = target.Resize((int)newWidth, (int)newHeight, WriteableBitmapExtensions.Interpolation.Bilinear);
return resized.ToByteArray();
}
}
}
}
This function return array of byte but it is not image any more.. I tested with PNG and JPG formats.. What's wrong?

I've been examining this problem before, try the code in this thread:
How to resize Image in C# WinRT/winmd?

The best help would be if you follow your post at the CodePlex site ;) http://writeablebitmapex.codeplex.com/discussions/399624
No need for cross posting.

Not sure if that would help you, but there is a LoadAsync() overload I wrote load a bitmap at the given decode resolution which might help you depending on your scenario.
http://winrtxamltoolkit.codeplex.com/SourceControl/changeset/view/0657c67a93d5#WinRTXamlToolkit%2fImaging%2fWriteableBitmapLoadExtensions.cs

Related

AS3 Issues with Rotation

I have a fairly basic app where you navigate menus and then access videos and demos.
My issue is that when you access a video, it forces you to rotate the screen first.
By using stage.scaleMode = Stage.ScaleMode.NO_SCALE I was able to make it work perfectly on my iPhone 7, but I can't find a way to scale up for iPhone 8 or 10.
I've been trying to use other StageScaleModes, and they work perfectly for the menus but when the screen is rotated, the scale becomes insanely wonky.
It either stays within the original aspect ratio or becomes much to big for the screen.
I've tried using stage.stageWidth and stage.stageHeight to correct this but they never return the correct size.
Any help in either fixing the issue in rotation or making NO_SCALE work would be greatly appreciated.
EDIT:
public function playVideo(path2: String): Function {
path = path2;
var listener: * ;
listener = function (e: MouseEvent = null): void {
stage.addChild(pleaseRotateScreen);
stage.autoOrients = true;
stage.addEventListener(StageOrientationEvent.ORIENTATION_CHANGING, orientationChangeListener_Videos);
}
return listener;
}
function orientationChangeListener_Videos(e: StageOrientationEvent) {
if (e.afterOrientation == StageOrientation.ROTATED_RIGHT || e.afterOrientation == StageOrientation.ROTATED_LEFT) {
stage.removeEventListener(StageOrientationEvent.ORIENTATION_CHANGING, orientationChangeListener_Videos);
stage.autoOrients = false;
stage.removeChild(pleaseRotateScreen);
startVideo();
}
}
EDIT2
public function startVideo(): void { //bring up the video UI.
stage.displayState = StageDisplayState.FULL_SCREEN;
headerTextField = new TextField();
headerTextField.autoSize = TextFieldAutoSize.LEFT;
var theFont = new BrownReg();
var rectClip: Sprite = new Sprite();
headerTextField.autoSize = "left";
//headerTextField.text = pageClip2.uiText;
headerTextField.text = "Stage Width: " + stage.width + " Stage.Height: " + stage.stageHeight;
headerTextField.selectable = false;
backPlate = new MovieClip;
backPlate.graphics.beginFill(0x000000);
backPlate.graphics.drawRect(0, 0, stage.stageWidth, stage.stageHeight);
backPlate.graphics.endFill();
overlay = new blackOverlay;
video_UI.addChild(overlay);
overlay.addEventListener(MouseEvent.CLICK, bringUpVideoUI);
mcScroll.addChild(backPlate);
TweenLite.to(menu_clip, .4, { alpha: 0, ease: Expo.easeOut });
TweenLite.to(screen_clip, .4, { alpha: 0, ease: Expo.easeOut });
TweenLite.to(pageClip, .4, { alpha: 0, ease: Expo.easeOut });
TweenLite.to(mcScroll, .4, { alpha: 0, ease: Expo.easeOut });
TweenLite.to(topbar_clip, .4, { alpha: 0, ease: Expo.easeOut });
video_UI.addChild(gradientVid);
gradientVid.y = 750 - 100;
X_UI = new videoX;
X_UI.x = (1254+24); X_UI.y = (678+24);
video_UI.addChild(X_UI);
X_UI.addEventListener(MouseEvent.CLICK, closeVideo);
pauseUI = new MovieClip;
pauseUI.addChild(pauseClip);
pauseUI.x = (140+24); pauseUI.y = (672+30);
video_UI.addChild(pauseUI);
pauseUI.addEventListener(MouseEvent.CLICK, pauseVid);
jumpBackUI = new mcFastForward;
jumpBackUI.rotation = 180;
jumpBackUI.x = (32+30); jumpBackUI.y = (672+30);
video_UI.addChild(jumpBackUI);
jumpBackUI.addEventListener(MouseEvent.CLICK, seekBack);
jumpForwardUI = new mcFastForward;
jumpForwardUI.x = (248+30); jumpForwardUI.y = (672+30);
video_UI.addChild(jumpForwardUI);
jumpForwardUI.addEventListener(MouseEvent.CLICK, seekForward);
var f: TextFormat = new TextFormat();
headerTextField.x = 32; headerTextField.y = 60;
f.size = 48;
f.font = theFont.fontName;
f.color = 0xffffff;
headerTextField.embedFonts = true;
headerTextField.setTextFormat(f);
video_UI.addChild(headerTextField);
video_UI.alpha = 0;
videoRect.width = stage.stageWidth;
videoRect.height = stage.stageHeight;
//videoRect.scaleX = videoRect.scaleY;
initVideo();
bringUpVideoUI();
}
Before Rotate
After Rotate
Edit 3:
public function initVideo(): void {
var obj: MovieClip = new MovieClip();
var nc: NetConnection = new NetConnection();
nc.connect(null);
netstream = new NetStream(nc);
netstream.client = obj;
obj.onMetaData = onMetaData;
stageVideo = stage.stageVideos[0];
stageVideo.addEventListener(StageVideoEvent.RENDER_STATE, onRender);
stageVideo.attachNetStream(netstream);
netstream.play(path);
netstream.seek(0);
netstream.removeEventListener(NetStatusEvent.NET_STATUS, netStatusHandler);
netstream.addEventListener(NetStatusEvent.NET_STATUS, netStatusHandler);
netstream.addEventListener(AsyncErrorEvent.ASYNC_ERROR, doAsyncError);
netstream.addEventListener(NetStatusEvent.NET_STATUS, doNetStatus);
netstream.addEventListener(IOErrorEvent.IO_ERROR, doIOError);
if (netstream != null) {
netstream.removeEventListener(AsyncErrorEvent.ASYNC_ERROR, doAsyncError);
netstream.removeEventListener(NetStatusEvent.NET_STATUS, doNetStatus);
netstream.removeEventListener(IOErrorEvent.IO_ERROR, doIOError);
}
}
//Video Functions
public function shrinkVideo() { }
public function enlargeVideo() { }
protected function doSecurityError(evt: SecurityErrorEvent): void { trace("AbstractStream.securityError:" + evt.text); }
protected function doIOError(evt: IOErrorEvent): void { trace("AbstractScreem.ioError:" + evt.text); }
protected function doAsyncError(evt: AsyncErrorEvent) { trace("AsyncError:" + evt.text); }
protected function doNetStatus(evt: NetStatusEvent): void { }
private function onMetaData(e: Object): void { duration = e.duration; }
private function onRender(e: StageVideoEvent): void {
if(videoDemo == true){
addEventListener(Event.ENTER_FRAME, onEnterFrame);
cl.addEventListener(MouseEvent.CLICK, _handleClick); //add the clickforward to the the rectangle.
}
stageVideo.viewPort = videoRect;
}
private function netStatusHandler(e: NetStatusEvent): void { //get the end of a video
if (e.info.code == "NetStream.Play.Stop") {
if (demo == true) {
netstream.play(path); //loop the video if its in a demo
} else if (videoDemo == true) {
returnFromDemo();
}else{
exitVid();
}
}
}
When developing a multiscreen game or app, developers need to read device's screen size to correctly rescale and reorganise screen elements.
These sizing issues can be very frustrating, especially as behavior is not the same across OSes and devices.
My personal preference is to always have my apps run in
fullscreenMode = true / aspectRatio = portrait / autoOrients = false, only.
If there is a need to redraw/resize stuff based on a change in orientation, then a handler should be able to 'fake' it, rather than actually modifying the stage.

Libgdx Screenshot method not working

A couple of weeks ago I implemented this method https://github.com/libgdx/libgdx/wiki/Take-a-Screenshot
And it worked great with libgdx 1.3.1 . Now though I upgraded to 1.6.0 and it have stopped working.
When the method is executed it freezes. I have it implemented on a button, and it gets stuck in "downclick" and nothing more happens.
private void saveScreenshot() {
try{
FileHandle fh;
do{
fh = new FileHandle(files.getLocalStoragePath() + "screenshot" + ".png");
}while(fh.exists());
Pixmap pixmap = getScreenshot(0, 0, Gdx.graphics.getWidth(), Gdx.graphics.getHeight() - 130, true);
PixmapIO.writePNG(fh, pixmap);
pixmap.dispose();
System.out.println("Path:" + fh.toString());
}catch(Exception e) {
}
}
private Pixmap getScreenshot(int x, int y, int w, int h, boolean yDown){
final Pixmap pixmap = ScreenUtils.getFrameBufferPixmap(x, y, w, h);
w = pixmap.getWidth();
h = pixmap.getHeight();
if(yDown) {
ByteBuffer pixels = pixmap.getPixels();
int numBytes = w * h * 4;
byte[] lines = new byte[numBytes];
int numBytesPerLine = w * 4;
for (int i = 0; i < h; i++) {
pixels.position((h - i - 1) * numBytesPerLine);
pixels.get(lines, i * numBytesPerLine, numBytesPerLine);
}
pixels.clear();
pixels.put(lines);
}
return pixmap;
}
btnArrow.addListener(new ChangeListener() {
//photoshop "save" and "back" on arrow/back image to clarify.
#Override
public void changed(ChangeEvent event, Actor actor) {
saveScreenshot();
sharePhoto();
}
});
I share the image to facebook aswell. And this method is in AndroidLauncher of course and is passed through an interface. And here I fetch the screenshot:
public void sharePhoto() {
Matrix matrix = new Matrix();
String filePath = (files.getLocalStoragePath() + "screenshot" + ".png");
BitmapFactory.Options options = new BitmapFactory.Options();
options.inPreferredConfig = Bitmap.Config.ARGB_8888;
Bitmap bitmap = BitmapFactory.decodeFile(filePath, options);
Bitmap rotateBit = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);
//Starts sharing process
SharePhoto photo = new SharePhoto.Builder()
.setBitmap(rotateBit)
.build();
SharePhotoContent content = new SharePhotoContent.Builder()
.addPhoto(photo)
.build();
share.show(content);
}
So what I believe may be the issue is libgdx have done changes on Pixmap class or Bitmap class of some sort. Since sharing a link through facebook on that button works fine.
I also printed the path as you can see in saveScreenshot() and it returns this
selinux_android_setcategory: no category for userid: 0, path: /data/data/com.sparc.tormt.android/lib
Is it stuck because this is an infinite loop if the file already exists:
do {
fh = new FileHandle(files.getLocalStoragePath() + "screenshot" + ".png");
} while(fh.exists());

Windows Store apps do not support WPF's <InkCanvas>

I am working on an application which can take input thru touch screen using mouse or stylus.. Found that <InkCanvas> works really great for me, but Windows Store app project does not recognize/support <InkCanvas> tag.
Does any came across similar kind of requirement and scenario.
Any suggestion.
Of course, one of them is but it is not as flexible as <InkCanvas>
Use this control in xaml like: <ctrl:InkCanvas x:Name="inkCanvas" />
Don't forget to reference 'ctrl' like: xmlns:ctrl="using:MyAppNamespace"
using System;
using System.Collections.Generic;
using Windows.Devices.Input;
using Windows.Foundation;
using Windows.UI;
using Windows.UI.Input;
using Windows.UI.Input.Inking;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Input;
using Windows.UI.Xaml.Media;
using Windows.UI.Xaml.Shapes;
using System.Linq;
using System.Threading.Tasks;
using Windows.Storage;
using Windows.Storage.Streams;
using Windows.UI.Xaml.Media.Imaging;
using System.Runtime.InteropServices.WindowsRuntime;
namespace MyAppNamespace
{
public class InkCanvas : Canvas
{
InkManager m_InkManager = new Windows.UI.Input.Inking.InkManager();
private uint m_PenId;
private uint _touchID;
private Point _previousContactPt;
private Point currentContactPt;
private double x1;
private double y1;
private double x2;
private double y2;
private Color m_CurrentDrawingColor = Colors.Black;
private double m_CurrentDrawingSize = 4;
public List<InkStroke> Strokes { get { return m_InkManager.GetStrokes().ToList(); } }
public InkCanvas()
{
m_InkManager.Mode = Windows.UI.Input.Inking.InkManipulationMode.Inking;
SetDefaults(m_CurrentDrawingSize, m_CurrentDrawingColor);
this.PointerPressed += new PointerEventHandler(OnCanvasPointerPressed);
this.PointerMoved += new PointerEventHandler(OnCanvasPointerMoved);
this.PointerReleased += new PointerEventHandler(OnCanvasPointerReleased);
this.PointerExited += new PointerEventHandler(OnCanvasPointerReleased);
}
public void Clear()
{
this.Children.Clear();
var strokes = m_InkManager.GetStrokes();
for (int i = 0; i < strokes.Count; i++)
strokes[i].Selected = true;
m_InkManager.DeleteSelected();
}
public async Task<byte[]> GetBytes()
{
var bytes = new byte[0];
if (Strokes.Count > 0)
{
var tempFile = await ApplicationData.Current.LocalFolder.CreateFileAsync(Guid.NewGuid().ToString() + ".jpg");
var writeStream = await tempFile.OpenAsync(FileAccessMode.ReadWrite);
await m_InkManager.SaveAsync(writeStream);
await writeStream.FlushAsync();
var reader = new DataReader(writeStream.GetInputStreamAt(0));
bytes = new byte[writeStream.Size];
await reader.LoadAsync((uint)writeStream.Size);
reader.ReadBytes(bytes);
reader.DetachStream();
await tempFile.DeleteAsync();
}
return bytes;
}
public async Task<BitmapImage> GetBitmapImage()
{
var bitmapImage = new BitmapImage();
var bytes = await GetBytes();
if (bytes.Length > 0)
{
using (var stream = new InMemoryRandomAccessStream())
{
// For AsBuffer manually add [ using System.Runtime.InteropServices.WindowsRuntime ];
await stream.WriteAsync(bytes.AsBuffer());
stream.Seek(0);
bitmapImage.SetSource(stream);
}
}
return bitmapImage;
}
#region Pointer Event Handlers
public void OnCanvasPointerReleased(object sender, PointerRoutedEventArgs e)
{
if (e.Pointer.PointerId == m_PenId)
{
Windows.UI.Input.PointerPoint pt = e.GetCurrentPoint(this);
// Pass the pointer information to the InkManager.
m_InkManager.ProcessPointerUp(pt);
}
else if (e.Pointer.PointerId == _touchID)
{
// Process touch input
}
_touchID = 0;
m_PenId = 0;
e.Handled = true;
}
private void OnCanvasPointerMoved(object sender, PointerRoutedEventArgs e)
{
if (e.Pointer.PointerId == m_PenId)
{
PointerPoint pt = e.GetCurrentPoint(this);
// Render a red line on the canvas as the pointer moves.
// Distance() is an application-defined function that tests
// whether the pointer has moved far enough to justify
// drawing a new line.
currentContactPt = pt.Position;
x1 = _previousContactPt.X;
y1 = _previousContactPt.Y;
x2 = currentContactPt.X;
y2 = currentContactPt.Y;
var color = m_CurrentDrawingColor;
var size = m_CurrentDrawingSize;
if (Distance(x1, y1, x2, y2) > 2.0)
{
Line line = new Line()
{
X1 = x1,
Y1 = y1,
X2 = x2,
Y2 = y2,
StrokeThickness = size,
Stroke = new SolidColorBrush(color)
};
_previousContactPt = currentContactPt;
// Draw the line on the canvas by adding the Line object as
// a child of the Canvas object.
this.Children.Add(line);
}
// Pass the pointer information to the InkManager.
m_InkManager.ProcessPointerUpdate(pt);
}
else if (e.Pointer.PointerId == _touchID)
{
// Process touch input
}
}
private double Distance(double x1, double y1, double x2, double y2)
{
double d = 0;
d = Math.Sqrt(Math.Pow((x2 - x1), 2) + Math.Pow((y2 - y1), 2));
return d;
}
public void OnCanvasPointerPressed(object sender, PointerRoutedEventArgs e)
{
// Get information about the pointer location.
PointerPoint pt = e.GetCurrentPoint(this);
_previousContactPt = pt.Position;
// Accept input only from a pen or mouse with the left button pressed.
PointerDeviceType pointerDevType = e.Pointer.PointerDeviceType;
if (pointerDevType == PointerDeviceType.Pen ||
pointerDevType == PointerDeviceType.Mouse &&
pt.Properties.IsLeftButtonPressed)
{
// Pass the pointer information to the InkManager.
m_InkManager.ProcessPointerDown(pt);
m_PenId = pt.PointerId;
e.Handled = true;
}
else if (pointerDevType == PointerDeviceType.Touch)
{
// Process touch input
}
}
#endregion
#region Mode Functions
// Change the color and width in the default (used for new strokes) to the values
// currently set in the current context.
private void SetDefaults(double strokeSize, Color color)
{
var newDrawingAttributes = new InkDrawingAttributes();
newDrawingAttributes.Size = new Size(strokeSize, strokeSize);
newDrawingAttributes.Color = color;
newDrawingAttributes.FitToCurve = true;
m_InkManager.SetDefaultDrawingAttributes(newDrawingAttributes);
this.Background = new SolidColorBrush(Colors.White);
}
#endregion
}
}
You use the InkManager class in WinRT instead of WPF's InkCanvas. I think you might need to use your own Canvas control with some Shapes (Polyline?) and handle the Pointer~ events yourself, but I haven't done it myself so I can't say for sure.

Flex mobile Button skinning in ActionScript - multiline labelDisplay

I am working on a Flex mobile application, and have been optimizing its performance on mobile. I have read that skins must be written in ActionScript so I have tried to create my AS ButtonSkin.
public class mButtonSkin extends ButtonSkin
{
private static var colorMatrix:Matrix = new Matrix();
protected var radiusX:Number = 12;
protected var mAngle:Number = 30;
protected var labelWidth:Number;
protected var labelHeight:Number;
protected var paddingLeft:Number = 12;
protected var paddingRight:Number = 12;
protected var paddingTop:Number = 2;
protected var paddingBottom:Number = 2;
public function mButtonSkin() {
super();
}
override protected function drawBackground(unscaledWidth:Number,unscaledHeight:Number) : void {
colorMatrix.createGradientBox(width,height,mAngle);
if (currentState == "up") {
graphics.beginGradientFill(GradientType.LINEAR,
[hostComponent.getStyle("fill3"),hostComponent.getStyle("fill1")], [1,1], [0,255], colorMatrix);
} else {
graphics.beginFill(hostComponent.getStyle("fill4"));
}
graphics.lineStyle(0.5,hostComponent.getStyle("borderColor"),0.5);
graphics.drawRoundRect(0,0,hostComponent.width,hostComponent.height,12);
graphics.endFill();
}
override protected function layoutContents(unscaledWidth:Number, unscaledHeight:Number) : void {
labelDisplay.wordWrap = true;
labelDisplay.multiline = true;
labelDisplay.commitStyles();
labelWidth = width - paddingLeft - paddingRight;
labelHeight = height - paddingTop - paddingBottom;
var x:Number = width / 2 - labelWidth / 2;
var y:Number = height / 2 - getElementPreferredHeight(labelDisplay) / 2;
setElementSize(labelDisplay,labelWidth,labelHeight);
setElementPosition(labelDisplay,x,y);
}
override protected function labelDisplay_valueCommitHandler(event:FlexEvent) : void {
labelDisplayShadow.text = "";
}
}
Applying this skin in my buttons:
Button labelDisplay has wrong alignment (verticalAlignment must be middle).
After clicking the button:
My button's labelDisplay is now vertically-aligned to middle.
Did i miss something? What have I done wrong?
on the layoutContents function, before positioning the labelDisplay element, i checked first whether it's numLines property is greater than 1. here's my updated function:
override protected function layoutContents(unscaledWidth:Number, unscaledHeight:Number) : void {
labelDisplay.wordWrap = true;
labelDisplay.multiline = true;
labelWidth = width - paddingLeft - paddingRight;
labelHeight = height - paddingTop - paddingBottom;
var x:Number = width * .5 - labelWidth * .5;
var y:Number = height * .5 - getElementPreferredHeight(labelDisplay) * .5;
setElementSize(labelDisplay,labelWidth,labelHeight);
if (labelDisplay.numLines == 1)
setElementPosition(labelDisplay,x,y);
else
setElementPosition(labelDisplay, x, labelDisplay.getLayoutBoundsY());
}
this solution may not be useful to other devs out there but it solved my problem.

Why is my canvas never drawing?

I started playing around with Dart yesterday and thought I would try to make a simple game engine. I'm also new to the canvas element , so I'm sure I'm making a silly mistake somewhere.
Here is my main game loop.
class FunTime {
FunTime(){
gameTime = new Date.now();
gameState = new List<IDrawableGameComponent>();
StartMenu startMenu = new StartMenu();
gameState.add(startMenu);
CanvasElement _canvas = document.query('#canvas');
context = _canvas.getContext('2d');
}
List<IDrawableGameComponent> gameState;
Date gameTime;
CanvasRenderingContext2D context;
}
void main() {
var exit = false;
FunTime game = new FunTime();
Date previousDraw = new Date.now();
while (!exit){
game.gameTime = new Date.now();
//update
game.gameState.last().update(game.gameTime);
int elapsed = game.gameTime.difference(previousDraw).inMilliseconds;
//draw (60 fps)
if(previousDraw == null || elapsed > 16){
//print("Draw Called{$elapsed}");
previousDraw = game.gameTime;
game.gameState.last().draw(game.gameTime, game.context);
}
}
}
Here is the code for the StartMenu code:
class StartMenu implements IDrawableGameComponent{
num positionX = 0;
StartMenu(){
}
void load(){
}
void update(Date gameTime){
//if(positionX < 200)
// positionX++;
}
void draw(Date gameTime, CanvasRenderingContext2D ctx){
ctx.clearRect(0, 0, 800, 600);
ctx.fillStyle = 'black';
ctx.fillRect(0,0,800,600);
ctx.fillStyle = 'white';
ctx.fillRect(positionX, 50, 400, 200);
}
}
For some reason the rectangles are never drawn unless I step through the code. Its almost like the brwoser doesn't have enough time to draw it before the next clear is called. I've tried increasing the draw interval but it doesn't change anything.
Here is how I solved the problem:
class FunTime {
FunTime(){
gameTime = new Date.now();
gameState = new List<IDrawableGameComponent>();
StartMenu startMenu = new StartMenu();
gameState.add(startMenu);
canvas = document.query('#canvas');
context = canvas.getContext('2d');
_previousDraw = 0;
animate(0);
}
animate(int time){
int elapsed = time - _previousDraw;
if( _previousDraw == 0 || elapsed > 16){
this.gameState.last().draw(time, this.context);
_previousDraw = time;
}
this.gameState.last().update(time);
window.webkitRequestAnimationFrame(animate, this.canvas);
}
int _previousDraw;
List<IDrawableGameComponent> gameState;
Date gameTime;
CanvasRenderingContext2D context;
CanvasElement canvas;
}
void main() {
FunTime game = new FunTime();
}
The while loop in the main() method never returns to let the browser thread draw. This is why it only works when you step through it.
This alternative works: using window.setInterval, to call a function every 16ms, but it may not be the correct way for a game loop.
void main() {
var exit = false;
FunTime game = new FunTime();
Date previousDraw = new Date.now();
window.setInterval( () { //note the callback
game.gameTime = new Date.now();
//update
game.gameState.last().update(game.gameTime);
int elapsed = game.gameTime.difference(previousDraw).inMilliseconds;
//draw (60 fps)
if(previousDraw == null || elapsed > 16){
previousDraw = game.gameTime;
game.gameState.last().draw(game.gameTime, game.context);
}
}, 16); //16 ms
}