This code plots an XYChart and using combination of right mouse button click and drag perform free hand draw, while with left mouse button click and drag perform Zoom In on selected area.
My problem is about zoom on freehand draw it always get translated. For example try to draw somewhere around a corner.
How can I solve this?
public class Zoom extends Application {
Path path;//Add path for freehand
BorderPane pane;
Rectangle rect;
SimpleDoubleProperty rectinitX = new SimpleDoubleProperty();
SimpleDoubleProperty rectinitY = new SimpleDoubleProperty();
SimpleDoubleProperty rectX = new SimpleDoubleProperty();
SimpleDoubleProperty rectY = new SimpleDoubleProperty();
double initXLowerBound = 0, initXUpperBound = 0, initYLowerBound = 0, initYUpperBound = 0;
#Override
public void start(Stage stage) {
stage.setTitle("Lines plot");
final NumberAxis xAxis = new NumberAxis(1, 12, 1);
final NumberAxis yAxis = new NumberAxis(0.53000, 0.53910, 0.0005);
yAxis.setTickLabelFormatter(new NumberAxis.DefaultFormatter(yAxis) {
#Override
public String toString(Number object) {
return String.format("%7.5f", object);
}
});
final LineChart<Number, Number> lineChart = new LineChart<Number, Number>(xAxis, yAxis);
lineChart.setCreateSymbols(false);
lineChart.setAlternativeRowFillVisible(false);
lineChart.setAnimated(true);
XYChart.Series series1 = new XYChart.Series();
series1.getData().add(new XYChart.Data(1, 0.53185));
series1.getData().add(new XYChart.Data(2, 0.532235));
series1.getData().add(new XYChart.Data(3, 0.53234));
series1.getData().add(new XYChart.Data(4, 0.538765));
series1.getData().add(new XYChart.Data(5, 0.53442));
series1.getData().add(new XYChart.Data(6, 0.534658));
series1.getData().add(new XYChart.Data(7, 0.53023));
series1.getData().add(new XYChart.Data(8, 0.53001));
series1.getData().add(new XYChart.Data(9, 0.53589));
series1.getData().add(new XYChart.Data(10, 0.53476));
series1.getData().add(new XYChart.Data(11, 0.530123));
series1.getData().add(new XYChart.Data(12, 0.53035));
pane = new BorderPane();
pane.setCenter(lineChart);
Scene scene = new Scene(pane, 800, 600);
lineChart.getData().addAll(series1);
initXLowerBound = ((NumberAxis) lineChart.getXAxis()).getLowerBound();
initXUpperBound = ((NumberAxis) lineChart.getXAxis()).getUpperBound();
initYLowerBound = ((NumberAxis) lineChart.getYAxis()).getLowerBound();
initYUpperBound = ((NumberAxis) lineChart.getYAxis()).getUpperBound();
stage.setScene(scene);
path = new Path();
path.setStrokeWidth(1);
path.setStroke(Color.BLACK);
scene.setOnMouseClicked(mouseHandler);
scene.setOnMouseDragged(mouseHandler);
scene.setOnMouseEntered(mouseHandler);
scene.setOnMouseExited(mouseHandler);
scene.setOnMouseMoved(mouseHandler);
scene.setOnMousePressed(mouseHandler);
scene.setOnMouseReleased(mouseHandler);
pane.getChildren().add(path);
rect = new Rectangle();
rect.setFill(Color.web("blue", 0.1));
rect.setStroke(Color.BLUE);
rect.setStrokeDashOffset(50);
rect.widthProperty().bind(rectX.subtract(rectinitX));
rect.heightProperty().bind(rectY.subtract(rectinitY));
pane.getChildren().add(rect);
stage.show();
}
EventHandler<MouseEvent> mouseHandler = new EventHandler<MouseEvent>() {
#Override
public void handle(MouseEvent mouseEvent) {
if (mouseEvent.getButton() == MouseButton.PRIMARY)
{
if (mouseEvent.getEventType() == MouseEvent.MOUSE_PRESSED) {
rect.setX(mouseEvent.getX());
rect.setY(mouseEvent.getY());
rectinitX.set(mouseEvent.getX());
rectinitY.set(mouseEvent.getY());
} else if (mouseEvent.getEventType() == MouseEvent.MOUSE_DRAGGED) {
rectX.set(mouseEvent.getX());
rectY.set(mouseEvent.getY());
} else if (mouseEvent.getEventType() == MouseEvent.MOUSE_RELEASED) {
if ((rectinitX.get() >= rectX.get())&&(rectinitY.get() >= rectY.get()))
{
LineChart<Number, Number> lineChart = (LineChart<Number, Number>) pane.getCenter();
((NumberAxis) lineChart.getXAxis()).setLowerBound(initXLowerBound);
((NumberAxis) lineChart.getXAxis()).setUpperBound(initXUpperBound);
((NumberAxis) lineChart.getYAxis()).setLowerBound(initYLowerBound);
((NumberAxis) lineChart.getYAxis()).setUpperBound(initYUpperBound);
ZoomFreeHand(path, 1.0, 1.0, 0, 0);
}
else
{
//Zoom In
double Tgap = 0;
double newLowerBound, newUpperBound, axisShift;
double xScaleFactor, yScaleFactor;
double xaxisShift, yaxisShift;
LineChart<Number, Number> lineChart = (LineChart<Number, Number>) pane.getCenter();
// Zoom in Y-axis by changing bound range.
NumberAxis yAxis = (NumberAxis) lineChart.getYAxis();
Tgap = yAxis.getHeight()/(yAxis.getUpperBound() - yAxis.getLowerBound());
axisShift = getSceneShiftY(yAxis);
yaxisShift = axisShift;
newUpperBound = yAxis.getUpperBound() - ((rectinitY.get() - axisShift) / Tgap);
newLowerBound = yAxis.getUpperBound() - (( rectY.get() - axisShift) / Tgap);
if (newUpperBound > yAxis.getUpperBound())
newUpperBound = yAxis.getUpperBound();
yScaleFactor = (yAxis.getUpperBound() - yAxis.getLowerBound())/(newUpperBound - newLowerBound);
yAxis.setLowerBound(newLowerBound);
yAxis.setUpperBound(newUpperBound);
NumberAxis xAxis = (NumberAxis) lineChart.getXAxis();
Tgap = xAxis.getWidth()/(xAxis.getUpperBound() - xAxis.getLowerBound());
axisShift = getSceneShiftX(xAxis);
xaxisShift = axisShift;
newLowerBound = ((rectinitX.get() - axisShift) / Tgap) + xAxis.getLowerBound();
newUpperBound = ((rectX.get() - axisShift) / Tgap) + xAxis.getLowerBound();
if (newUpperBound > xAxis.getUpperBound())
newUpperBound = xAxis.getUpperBound();
xScaleFactor = (xAxis.getUpperBound() - xAxis.getLowerBound())/(newUpperBound - newLowerBound);
xAxis.setLowerBound( newLowerBound );
xAxis.setUpperBound( newUpperBound );
ZoomFreeHand(path, xScaleFactor, yScaleFactor, xaxisShift, yaxisShift);
}
// Hide the rectangle
rectX.set(0);
rectY.set(0);
}
}
else if (mouseEvent.getButton() == MouseButton.SECONDARY) //free hand graphics
{
if(mouseEvent.getEventType() == MouseEvent.MOUSE_PRESSED){
path.getElements().clear();
path.getElements().add(new MoveTo(mouseEvent.getX(), mouseEvent.getY()));
}
else if(mouseEvent.getEventType()==MouseEvent.MOUSE_DRAGGED){
path.getElements().add(new LineTo(mouseEvent.getX(), mouseEvent.getY()));
}
}
}
};
private static double getSceneShiftX(Node node) {
double shift = 0;
do {
shift += node.getLayoutX();
node = node.getParent();
} while (node != null);
return shift;
}
private static double getSceneShiftY(Node node) {
double shift = 0;
do {
shift += node.getLayoutY();
node = node.getParent();
} while (node != null);
return shift;
}
private static void ZoomFreeHand(Path path, double xScaleFactor, double yScaleFactor, double xaxisShift, double yaxisShift) {
double layX, layY;
layX = path.getLayoutX();
layY = path.getLayoutY();
path.setScaleX(xScaleFactor);
path.setScaleY(yScaleFactor);
path.setTranslateX(xaxisShift);
path.setTranslateY(yaxisShift);
}
public static void main(String[] args) {
launch(args);
}
}
I think it worth using something like this:
ObservableList<PathElement> mypathElements = path.getElements();
for (int i = 0; i < mypathElements.size(); i++) {
final PathElement element = mypathElements.get(i);
if (element instanceof MoveTo) {
final MoveTo move = (MoveTo)element;
//change move coordinates
} else if (element instanceof LineTo) {
final LineTo line = (LineTo)element;
//change line coordinates
}
}
Same issue as in Javafx 2 chart resize with freehand draw and same answer:
It seems you coordinates are based on wrong anchors. You need to find a node which contains graph itself and work only with this node's coordinates, not axis or scene.
I would even advise to add all mouse events to that node instead of scene to avoid excessive coordinates translation.
Another advise would be use ScenicView tool to investigate your application and see which nodes has what coordinates and verify your math.
I'd recommend replace those:
private static double getSceneShiftX(Node node) {
double shift = 0;
do {
shift += node.getLayoutX();
node = node.getParent();
} while (node != null);
return shift;
}
private static double getSceneShiftY(Node node) {
double shift = 0;
do {
shift += node.getLayoutY();
node = node.getParent();
} while (node != null);
return shift;
}
with Node.localToScene, Node.sceneToLocal conversion methods that took points or Bounds as arguments.
Related
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.
I'm working on a 3D game for the Technology Student Association.
I am an amateur programmer, so this is probably why I'm having these problems. It started at first by adding a 3rd level, and Flash not recognizing the packages that the private functions are in. Please advise, here's the code:
package {
import flash.display.*;
import flash.events.*;
import flash.geom.*;
public class Dungeon3D extends MovieClip {
public var viewSprite:Sprite; // everything
public var worldSprite:Sprite; // walls, ceiling, floor, coins
// references to objects
public var map:Map; // mc to use for wall and coin positions
public var map2:Map2; // mc to use for wall and coin positions
public var squares:Array; // blocks on map
public var worldObjects:Array; // walls and coins
private var charPos:Point; // player location
// keyboard input
private var leftArrow, rightArrow, upArrow, downArrow: Boolean;
// car direction and speed
private var dir:Number = 90;
private var speed:Number = 0;
//mrb: variables
private var gameMode:String = "start";
public var playerObjects:Array;
private var gameScore:int;
private var playerLives:int;
// start game
public function startGame() {
gameMode = "play";
playerObjects = new Array();
gameScore = 0;
playerLives = 3;
}
public function startDungeon3D() {
viewSprite = new Sprite();
viewSprite.x = 275;
viewSprite.y = 250;
viewSprite.z = -500;
addChild(viewSprite);
// add an inner sprite to hold everything, lay it down
worldSprite = new Sprite();
viewSprite.addChild(worldSprite);
worldSprite.rotationX = -90;
// cover above with ceiling tiles
for(var i:int=-5;i<5;i++) {
for(var j:int=-6;j<1;j++) {
var ceiling:Ceiling = new Ceiling();
ceiling.x = i*200;
ceiling.y = j*200;
ceiling.z = -200; // above
worldSprite.addChild(ceiling);
}
}
// cover below with floor tiles
for(i=-5;i<5;i++) {
for(j=-6;j<1;j++) {
var floor:Floor = new Floor();
floor.x = i*200;
floor.y = j*200;
floor.z = 0; // below
worldSprite.addChild(floor);
}
}
// get the game map
map = new Map();
// look for squares in map, and put four walls in each spot
// also move coins up and rotate them
worldObjects = new Array();
squares = new Array();
for(i=0;i<map.numChildren;i++) {
var object = map.getChildAt(i);
//var mc = this.gamelevel.getChildAt(i);
if (object is Square) {
// add four walls, one for each edge of square
addWall(object.x+object.width/2, object.y, object.width, 0);
addWall(object.x, object.y+object.height/2, object.height, 90);
addWall(object.x+object.width, object.y+object.height/2, object.height, 90);
addWall(object.x+object.width/2, object.y+object.height, object.width, 0);
// remember squares for collision detection
squares.push(object);
} else if (object is Coin) {
object.z = -50; // move up
object.rotationX = -90; // turn to face player
worldSprite.addChild(object);
worldObjects.push(object); // add to array fo zSort
} else if (object is Key) {
object.z = -50; // move up
object.rotationX = -90; // turn to face player
worldSprite.addChild(object);
worldObjects.push(object); // add to array fo zSort
} else if (object is Chest) {
object.z = -50; // move up
object.rotationX = -90; // turn to face player
worldSprite.addChild(object);
worldObjects.push(object); // add to array fo zSort
} else if (object is Door) {
object.z = 77; // move up
object.rotationX = 90; // turn to face player
worldSprite.addChild(object);
worldObjects.push(object); // add to array fo zSort
}
}
// keep track of virtual position of character
charPos = new Point(0,0);
// arrange all walls and coins for distance
zSort();
// respond to key events
stage.addEventListener(KeyboardEvent.KEY_DOWN,keyPressedDown);
stage.addEventListener(KeyboardEvent.KEY_UP,keyPressedUp);
// advance game
addEventListener(Event.ENTER_FRAME, moveGame);
}
public function startDungeon3D2() {
// create the world and center it
viewSprite = new Sprite();
viewSprite.x = 275;
viewSprite.y = 250;
viewSprite.z = -500;
addChild(viewSprite);
// add an inner sprite to hold everything, lay it down
worldSprite = new Sprite();
viewSprite.addChild(worldSprite);
worldSprite.rotationX = -90;
// cover above with ceiling tiles
for(var i:int=-5;i<5;i++) {
for(var j:int=-6;j<1;j++) {
var ceiling:Ceiling = new Ceiling();
ceiling.x = i*200;
ceiling.y = j*200;
ceiling.z = -200; // above
worldSprite.addChild(ceiling);
}
}
// cover below with floor tiles
for(i=-5;i<5;i++) {
for(j=-6;j<1;j++) {
var floor:Floor = new Floor();
floor.x = i*200;
floor.y = j*200;
floor.z = 0; // below
worldSprite.addChild(floor);
}
}
// get the game map
map2 = new Map2();
// look for squares in map, and put four walls in each spot
// also move coins up and rotate them
worldObjects = new Array();
squares = new Array();
for(i=0;i<map2.numChildren;i++) {
var object = map2.getChildAt(i);
//var mc = this.gamelevel.getChildAt(i);
if (object is Square) {
// add four walls, one for each edge of square
addWall(object.x+object.width/2, object.y, object.width, 0);
addWall(object.x, object.y+object.height/2, object.height, 90);
addWall(object.x+object.width, object.y+object.height/2, object.height, 90);
addWall(object.x+object.width/2, object.y+object.height, object.width, 0);
// remember squares for collision detection
squares.push(object);
} else if (object is Coin) {
object.z = -50; // move up
object.rotationX = -90; // turn to face player
worldSprite.addChild(object);
worldObjects.push(object); // add to array fo zSort
} else if (object is Key) {
object.z = -50; // move up
object.rotationX = -90; // turn to face player
worldSprite.addChild(object);
worldObjects.push(object); // add to array fo zSort
} else if (object is Chest) {
object.z = -50; // move up
object.rotationX = -90; // turn to face player
worldSprite.addChild(object);
worldObjects.push(object); // add to array fo zSort
} else if (object is Door) {
object.z = -50; // move up
object.rotationX = -90; // turn to face player
worldSprite.addChild(object);
worldObjects.push(object); // add to array fo zSort
}
}
public function startDungeon3D3() {
// create the world and center it
viewSprite = new Sprite();
viewSprite.x = 275;
viewSprite.y = 250;
viewSprite.z = -500;
addChild(viewSprite);
// add an inner sprite to hold everything, lay it down
worldSprite = new Sprite();
viewSprite.addChild(worldSprite);
worldSprite.rotationX = -90;
// cover above with ceiling tiles
for(var i:int=-5;i<5;i++) {
for(var j:int=-6;j<1;j++) {
var ceiling:Ceiling = new Ceiling();
ceiling.x = i*200;
ceiling.y = j*200;
ceiling.z = -200; // above
worldSprite.addChild(ceiling);
}
}
// cover below with floor tiles
for(i=-5;i<5;i++) {
for(j=-6;j<1;j++) {
var floor:Floor = new Floor();
floor.x = i*200;
floor.y = j*200;
floor.z = 0; // below
worldSprite.addChild(floor);
}
}
// get the game map
map3 = new Map3();
// cover below with floor tiles
for(i=-5;i<5;i++) {
for(j=-6;j<1;j++) {
var floor:Floor = new Floor();
floor.x = i*200;
floor.y = j*200;
floor.z = 0; // below
worldSprite.addChild(floor);
}
}
// look for squares in map, and put four walls in each spot
// also move coins up and rotate them
worldObjects = new Array();
squares = new Array();
for(i=0;i<map3.numChildren;i++) {
var object = map3.getChildAt(i);
//var mc = this.gamelevel.getChildAt(i);
if (object is Square) {
// add four walls, one for each edge of square
addWall(object.x+object.width/2, object.y, object.width, 0);
addWall(object.x, object.y+object.height/2, object.height, 90);
addWall(object.x+object.width, object.y+object.height/2, object.height, 90);
addWall(object.x+object.width/2, object.y+object.height, object.width, 0);
// remember squares for collision detection
squares.push(object);
} else if (object is Coin) {
object.z = -50; // move up
object.rotationX = -90; // turn to face player
worldSprite.addChild(object);
worldObjects.push(object); // add to array fo zSort
} else if (object is Key) {
object.z = -50; // move up
object.rotationX = -90; // turn to face player
worldSprite.addChild(object);
worldObjects.push(object); // add to array fo zSort
} else if (object is Chest) {
object.z = -50; // move up
object.rotationX = -90; // turn to face player
worldSprite.addChild(object);
worldObjects.push(object); // add to array fo zSort
} else if (object is Door) {
object.z = -50; // move up
object.rotationX = -90; // turn to face player
worldSprite.addChild(object);
worldObjects.push(object); // add to array fo zSort
}
}
// keep track of virtual position of character
charPos = new Point(0,0);
// arrange all walls and coins for distance
zSort();
// respond to key events
stage.addEventListener(KeyboardEvent.KEY_DOWN,keyPressedDown);
stage.addEventListener(KeyboardEvent.KEY_UP,keyPressedUp);
// advance game
addEventListener(Event.ENTER_FRAME, moveGame);
}
// add a vertical wall
public function addWall(x, y, len, rotation) {
var wall:Wall = new Wall();
wall.x = x;
wall.y = y;
wall.z = -wall.height/2;
wall.width = len;
wall.rotationX = 90;
wall.rotationZ = rotation;
worldSprite.addChild(wall);
worldObjects.push(wall);
}
// set arrow variables to true
public function keyPressedDown(event:KeyboardEvent) {
if (event.keyCode == 37) {
leftArrow = true;
} else if (event.keyCode == 39) {
rightArrow = true;
} else if (event.keyCode == 38) {
upArrow = true;
} else if (event.keyCode == 40) {
downArrow = true;
}
}
// set arrow variables to false
public function keyPressedUp(event:KeyboardEvent) {
if (event.keyCode == 37) {
leftArrow = false;
} else if (event.keyCode == 39) {
rightArrow = false;
} else if (event.keyCode == 38) {
upArrow = false;
} else if (event.keyCode == 40) {
downArrow = false;
}
}
private function turnPlayer(d) {
// change direction
dir += d;
// rotate world to change view
viewSprite.rotationY = dir-90;
}
// main game function
public function moveGame(e) {
// see if turning left or right
var turn:Number = 0;
if (leftArrow) {
turn = 10;
} else if (rightArrow) {
turn = -10;
}
// turn
if (turn != 0) {
turnPlayer(turn);
}
// if up arrow pressed, then accelerate, otherwise decelerate
speed = 0;
if (upArrow) {
speed = 10;
} else if (downArrow) {
speed = -10;
}
// move
if (speed != 0) {
movePlayer(speed);
}
// re-sort objects
if ((speed != 0) || (turn != 0)) {
zSort();
}
// see if any coins hit
checkCoins();
checkKey();
checkChest();
checkDoor();
}
public function movePlayer(d) {
// calculate current player area
// make a rectangle to approximate space used by player
var charSize:Number = 50; // approximate player size
var charRect:Rectangle = new Rectangle(charPos.x-charSize/2, charPos.y-charSize/2, charSize, charSize);
// get new rectangle for future position of player
var newCharRect:Rectangle = charRect.clone();
var charAngle:Number = (-dir/360)*(2.0*Math.PI);
var dx:Number = d*Math.cos(charAngle);
var dy:Number = d*Math.sin(charAngle);
newCharRect.x += dx;
newCharRect.y += dy;
// calculate new location
var newX:Number = charPos.x + dx;
var newY:Number = charPos.y + dy;
// loop through squares and check collisions
for(var i:int=0;i<squares.length;i++) {
// get block rectangle, see if there is a collision
var blockRect:Rectangle = squares[i].getRect(map);
if (blockRect.intersects(newCharRect)) {
// horizontal push-back
if (charPos.x <= blockRect.left) {
newX += blockRect.left - newCharRect.right;
} else if (charPos.x >= blockRect.right) {
newX += blockRect.right - newCharRect.left;
}
// vertical push-back
if (charPos.y >= blockRect.bottom) {
newY += blockRect.bottom - newCharRect.top;
} else if (charPos.y <= blockRect.top) {
newY += blockRect.top - newCharRect.bottom;
}
}
}
// move character position
charPos.y = newY;
charPos.x = newX;
// move terrain to show proper view
worldSprite.x = -newX;
worldSprite.z = newY;
}
// spin coins and see if any have been hit
private function checkCoins() {
// look at all objects
for(var i:int=worldObjects.length-1;i>=0;i--) {
// only look at coins
if (worldObjects[i] is Coin) {
// spin it!
worldObjects[i].rotationZ += 10;
// check distance from character
var dist:Number = Math.sqrt(Math.pow(charPos.x-worldObjects[i].x,2)+Math.pow(charPos.y-worldObjects[i].y,2));
// if close enough, remove coin
if (dist < 50) {
worldSprite.removeChild(worldObjects[i]);
worldObjects.splice(i,1);
}
}
}
}
// spin coins and see if any have been hit
private function checkKey() {
// look at all objects
for(var i:int=worldObjects.length-1;i>=0;i--) {
// only look at coins
if (worldObjects[i] is Key) {
// spin it!
worldObjects[i].rotationZ += 10;
// check distance from character
var dist:Number = Math.sqrt(Math.pow(charPos.x-worldObjects[i].x,2)+Math.pow(charPos.y-worldObjects[i].y,2));
// if close enough, remove coin
if (dist < 50) {
getObject(i); // mrb: call to getobject
worldSprite.removeChild(worldObjects[i]);
worldObjects.splice(i,1);
}
}
}
}
// spin coins and see if any have been hit
private function checkChest() {
// look at all objects
for(var i:int=worldObjects.length-1;i>=0;i--) {
// only look at coins
if (worldObjects[i] is Chest) {
// spin it!
worldObjects[i].rotationZ += 10;
// check distance from character
var dist:Number = Math.sqrt(Math.pow(charPos.x-worldObjects[i].x,2)+Math.pow(charPos.y-worldObjects[i].y,2));
// if close enough and have the key end the level; don't remove if no key
if (dist < 50) {
getObject(i); // mrb: call to getobject
//worldSprite.removeChild(worldObjects[i]);
//worldObjects.splice(i,1);
}
}
}
}
// spin coins and see if any have been hit
private function checkDoor() {
// look at all objects
for(var i:int=worldObjects.length-1;i>=0;i--) {
// only look at coins
if (worldObjects[i] is Door) {
// spin it!
worldObjects[i].rotationZ += 10;
// check distance from character
var dist:Number = Math.sqrt(Math.pow(charPos.x-worldObjects[i].x,2)+Math.pow(charPos.y-worldObjects[i].y,2));
// if close enough and have the key end the level; don't remove if no key
if (dist < 50) {
getObject(i); // mrb: call to getobject
//worldSprite.removeChild(worldObjects[i]);
//worldObjects.splice(i,1);
}
}
}
}
// player collides with objects
public function getObject(objectNum:int) {
// award points for treasure
if (worldObjects[objectNum] is Treasure) {
//var pb:PointBurst = new PointBurst(map,100,worldObjects[objectNum].x,worldObjects[objectNum].y);
//gamelevel.removeChild(otherObjects[objectNum]);
//otherObjects.splice(objectNum,1);
//addScore(100);
// got the key, add to inventory
} else if (worldObjects[objectNum] is Key) {
//pb = new PointBurst(gamelevel,"Got Key!" ,otherObjects[objectNum].x,otherObjects[objectNum].y);
playerObjects.push("Key");
trace(playerObjects.indexOf("Key"));
//gamelevel.removeChild(otherObjects[objectNum]);
//otherObjects.splice(objectNum,1);
// hit the door, end level if hero has the key
} else if (worldObjects[objectNum] is Door) {
if (playerObjects.indexOf("Key") == -1) return; // i don't have the key
if (worldObjects[objectNum].currentFrame == 1) { // i got the key
worldObjects[objectNum].gotoAndPlay("open");
levelComplete();
}
// got the chest, game won, if hero has the key
} else if (worldObjects[objectNum] is Chest) {
if (playerObjects.indexOf("Key") == -1) return;
trace(worldObjects[objectNum].currentFrame);
if (worldObjects[objectNum].currentFrame == 1) {
worldObjects[objectNum].gotoAndStop("open");
gameComplete();
}
}
}
// level over, bring up dialog
public function levelComplete() {
gameMode = "done";
var dialog:Dialog = new Dialog();
dialog.x = 175;
dialog.y = 100;
addChild(dialog);
dialog.message.text = "Level Complete!";
}
// game over, bring up dialog
public function gameComplete() {
gameMode = "gameover";
var dialog:Dialog = new Dialog();
dialog.x = 175;
dialog.y = 100;
addChild(dialog);
dialog.message.text = "You Got the Treasure!";
}
// dialog button clicked
public function clickDialogButton(event:MouseEvent) {
removeChild(MovieClip(event.currentTarget.parent));
// new life, restart, or go to next level
if (gameMode == "dead") {
// reset hero
//showLives();
//hero.mc.x = hero.startx;
//hero.mc.y = hero.starty;
gameMode = "play";
} else if (gameMode == "gameover") {
cleanUp();
gotoAndStop("start");
} else if (gameMode == "done") {
cleanUp();
nextFrame();
}
// give stage back the keyboard focus
stage.focus = stage;
}
// clean up game
public function cleanUp() {
//removeChild(gamelevel);
//this.removeEventListener(Event.ENTER_FRAME,gameLoop);
//stage.removeEventListener(KeyboardEvent.KEY_DOWN,keyDownFunction);
//stage.removeEventListener(KeyboardEvent.KEY_UP,keyUpFunction);
stage.removeEventListener(KeyboardEvent.KEY_DOWN,keyPressedDown);
stage.removeEventListener(KeyboardEvent.KEY_UP,keyPressedUp);
this.removeEventListener(Event.ENTER_FRAME, moveGame);
removeChild(viewSprite);
}
// sort all objects so the closest ones are highest in the display list
private function zSort() {
var objectDist:Array = new Array();
for(var i:int=0;i<worldObjects.length;i++) {
var z:Number = worldObjects[i].transform.getRelativeMatrix3D(root).position.z;
objectDist.push({z:z,n:i});
}
objectDist.sortOn( "z", Array.NUMERIC | Array.DESCENDING );
for(i=0;i<objectDist.length;i++) {
worldSprite.addChild(worldObjects[objectDist[i].n]);
}
}
}
}
}
These are the errors im getting now, even though the code IS there. The file name IS Dungeon3D.as
C:\Users\school\Desktop\Dungeon3DV3\Dungeon3D.as, Line 217 1114: The public attribute can only be used inside a package.
C:\Users\school\Desktop\Dungeon3DV3\Dungeon3D.as, Line 324 1114: The public attribute can only be used inside a package.
C:\Users\school\Desktop\Dungeon3DV3\Dungeon3D.as, Line 337 1114: The public attribute can only be used inside a package.
C:\Users\school\Desktop\Dungeon3DV3\Dungeon3D.as, Line 350 1114: The public attribute can only be used inside a package.
C:\Users\school\Desktop\Dungeon3DV3\Dungeon3D.as, Line 362 1013: The private attribute may be used only on class property definitions.
C:\Users\school\Desktop\Dungeon3DV3\Dungeon3D.as, Line 372 1114: The public attribute can only be used inside a package.
C:\Users\school\Desktop\Dungeon3DV3\Dungeon3D.as, Line 412 1114: The public attribute can only be used inside a package.
C:\Users\school\Desktop\Dungeon3DV3\Dungeon3D.as, Line 465 1013: The private attribute may be used only on class property definitions.
C:\Users\school\Desktop\Dungeon3DV3\Dungeon3D.as, Line 484 1013: The private attribute may be used only on class property definitions.
C:\Users\school\Desktop\Dungeon3DV3\Dungeon3D.as, Line 504 1013: The private attribute may be used only on class property definitions.
C:\Users\school\Desktop\Dungeon3DV3\Dungeon3D.as, Line 524 1013: The private attribute may be used only on class property definitions.
C:\Users\school\Desktop\Dungeon3DV3\Dungeon3D.as, Line 545 1114: The public attribute can only be used inside a package.
C:\Users\school\Desktop\Dungeon3DV3\Dungeon3D.as, Line 581 1114: The public attribute can only be used inside a package.
C:\Users\school\Desktop\Dungeon3DV3\Dungeon3D.as, Line 591 1114: The public attribute can only be used inside a package.
C:\Users\school\Desktop\Dungeon3DV3\Dungeon3D.as, Line 601 1114: The public attribute can only be used inside a package.
C:\Users\school\Desktop\Dungeon3DV3\Dungeon3D.as, Line 624 1114: The public attribute can only be used inside a package.
C:\Users\school\Desktop\Dungeon3DV3\Dungeon3D.as, Line 637 1013: The private attribute may be used only on class property definitions.
Whenever i change where something is in the code itself, i still get the same errors. Flash screw up? Or is the code being drawn from a different folder?
You missed } after startDungeon3D2() method. Add it in line number 214.
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.
I saw this code but it only works if the destination is specified by search!
I need to navigate to a specific position using latitude and longitude .
GeocodeQuery Mygeocodequery = null;
Mygeocodequery = new GeocodeQuery();
Mygeocodequery.SearchTerm = "Seattle, WA";
Mygeocodequery.GeoCoordinate = new GeoCoordinate(MyGeoPosition.Coordinate.Latitude,MyGeoPosition.Coordinate.Longitude);
Mygeocodequery.QueryCompleted += Mygeocodequery_QueryCompleted;
Mygeocodequery.QueryAsync();
void Mygeocodequery_QueryCompleted(object sender, QueryCompletedEventArgs<IList<MapLocation>> e)
{
if (e.Error == null)
{
MyQuery = new RouteQuery();
MyCoordinates.Add(e.Result[0].GeoCoordinate);
MyQuery.Waypoints = MyCoordinates;
MyQuery.QueryCompleted += MyQuery_QueryCompleted;
MyQuery.QueryAsync();
Mygeocodequery.Dispose();
}
}
void MyQuery_QueryCompleted(object sender, QueryCompletedEventArgs<Route> e)
{
if (e.Error == null)
{
Route MyRoute = e.Result;
MapRoute MyMapRoute = new MapRoute(MyRoute);
MyMap.AddRoute(MyMapRoute);
MyQuery.Dispose();
}
}
Here's a sample code (assuming you already have your source and target coordinates).
public partial class Foo : PhoneApplicationPage
{
List<GeoCoordinate> MyCoordinates = new List<GeoCoordinate>();
public Foo()
{
InitializeComponent();
}
private void SetMapCoordinates()
{
MyCoordinates.Add(new GeoCoordinate(Target.Latitude, Target.Longitude));
MyCoordinates.Add(new GeoCoordinate(Source.Latitude, Source.Longitude));
DrawMyRoute();
}
void MyRoute()
{
MyQuery = new RouteQuery();
MyQuery.TravelMode = TravelMode.Walking;
MyQuery.Waypoints = MyCoordinates;
MyQuery.QueryCompleted += MyQuery_QueryCompleted;
MyQuery.QueryAsync();
}
void MyQuery_QueryCompleted(object sender, QueryCompletedEventArgs<Route> e)
{
if (e.Error == null)
{
Route MyRoute = e.Result;
MapRoute MyMapRoute = new MapRoute(MyRoute);
MyMapRoute.Color = (Colors.Blue);
MyLocMap.AddRoute(MyMapRoute);
#region Draw source location ellipse
Ellipse myCircle = new Ellipse();
myCircle.Fill = new SolidColorBrush(Colors.Blue);
myCircle.Height = 20;
myCircle.Width = 20;
myCircle.Opacity = 50;
MapOverlay myLocationOverlay = new MapOverlay();
myLocationOverlay.Content = myCircle;
myLocationOverlay.PositionOrigin = new Point(0.5, 0.5);
myLocationOverlay.GeoCoordinate = CoordinateConverter.ConvertGeocoordinate(SourceLocation);
MylocationLayer = new MapLayer();
MylocationLayer.Add(myLocationOverlay);
MyLocMap.Layers.Add(MylocationLayer);
#endregion
#region Draw target location ellipse
Ellipse CarCircle = new Ellipse();
CarCircle.Fill = new SolidColorBrush(Colors.Red);
CarCircle.Height = 20;
CarCircle.Width = 20;
CarCircle.Opacity = 50;
MapOverlay CarLocationOverlay = new MapOverlay();
CarLocationOverlay.Content = CarCircle;
CarLocationOverlay.PositionOrigin = new Point(0.5, 0.5);
CarLocationOverlay.GeoCoordinate = CoordinateConverter.ConvertGeocoordinate(TargetLocation);
CarlocationLayer = new MapLayer();
CarlocationLayer.Add(CarLocationOverlay);
MyLocMap.Layers.Add(CarlocationLayer);
#endregion
MyQuery.Dispose();
}
}
protected override void OnNavigatedTo(NavigationEventArgs e)
{
SetMapCoordinates();
}
}
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
}