I am making a game using Haxe+OpenFL. I had targeted js once ago, then I switched to neko and the following construction stopped working:
if(e.shiftKey)
do smth
Ofc I've not changed this block of code, nor context since changing the target. What has gone wrong?
P. S. Tracing shows, that holding alt, ctrl or shift keys do not change corresponding properties of MouseEvent object
Based on this link, it used to be a problem, but has been fixed two years ago. Strangely, my tests show it still doesn't work.
This class demonstrates that it will work correctly in js but not in neko.
class Main extends Sprite
{
public function new()
{
super();
var s:Sprite = new Sprite();
s.graphics.beginFill(0xff0000);
s.graphics.drawCircle(100, 100, 200);
s.graphics.endFill();
addChild(s);
//testing a simple click event
s.addEventListener(MouseEvent.CLICK, OnClick);
//testing wheel events, as I read somewhere it could a been a bug in earlier versions
s.addEventListener(MouseEvent.MOUSE_WHEEL, OnWheel);
//testing click events on the stage object, in case it acted differently
addEventListener(MouseEvent.CLICK, OnStageClick);
}
private function OnStageClick(e:MouseEvent):Void
{
trace(e.shiftKey);
}
private function OnWheel(e:MouseEvent):Void
{
trace(e.shiftKey);
}
private function OnClick(e:MouseEvent):Void
{
trace(e.shiftKey);
}
}
An alternative solution could be to use openfl.events.KeyboardEvent and note when the shift key is up or down as a boolean (note that shift's keycode is 16). This example works correctly in my tests.
class Main extends Sprite
{
var shiftIsPressed:Bool = false;
public function new()
{
super();
stage.addEventListener(KeyboardEvent.KEY_DOWN, OnDown);
stage.addEventListener(KeyboardEvent.KEY_UP, OnUp);
stage.addEventListener(MouseEvent.CLICK, OnClick);
}
private function OnUp(e:KeyboardEvent):Void
{
if (e.keyCode == 16)
{
shiftIsPressed = false;
}
}
private function OnDown(e:KeyboardEvent):Void
{
if (e.keyCode == 16)
{
shiftIsPressed = true;
}
}
private function OnClick(e:MouseEvent):Void
{
if (shiftIsPressed)
{
trace('Click!');
}
}
}
Update
Since I've always used the keyboard event trick I mentioned earlier, I missed the fact that it also does not work in C++. I suppose those two targets use some custom event system and someone forgot to register the modifier keys to the created event.
Update 2 (sept 22)
Someone fixed it
Related
Note that I have already checked out this question, but the answers to it do not seem to be correct.
If I wanted to have private methods in regular JavaScript (which the answers suggest is not possible), I'd do something like this:
function myThing() {
var thingConstructor = function(someParam) {
this.publicFn(foo) {
return privateFn(foo);
}
function privateFn(foo) {
return 'called private fn with ' + foo;
}
}
}
var theThing = new myThing('param');
var result = theThing.publicFn('Hi');//should be 'called private fn with Hi'
result = theThing.privateFn; //should error
I'm trying to figure out what the syntax is to encapsulate the private function in TypeScript. If it turns out you can't, that's fine, but given that the answers in that older question incorrectly state that you can't create private methods in ordinary JavaScript, I am unwilling to just take those answers as authoritative.
So, it turns out it's just as simple as marking the method private. The thing I was missing is to be able to use the method is you need to use the this keyword.
So
export class myThing {
constructor(){}
publicFn(foo) {
return this.privateFn(foo);
}
private privateFn(foo) {
return 'called private fn with ' + foo;
}
}
I would like to call a function that is located outside the Main class of my Haxe game.
I am able to add bubbles to the game using: addChild(new Bubble(player.x, player.y));
I would like to update the game without using an EventListener in each added object.
The follow code: Bubble.tick();
Yields this error when run from main:
Bubble has no field tick
Bubble Class:
package;
import flash.Lib;
import flash.display.Bitmap;
import flash.display.BitmapData;
import flash.display.Sprite;
import flash.display.MovieClip;
import openfl.Assets;
import flash.events.Event;
class Bubble extends Sprite
{
private var newBubble:Bitmap;
private static var gameBubble:Array<Sprite> = new Array<Sprite>();
public function new (xpos:Float,ypos:Float) {
super ();
this.x = xpos;
this.y = ypos;
newBubble = new Bitmap (Assets.getBitmapData ("img/sprite_bubble_16x16.png"));
newBubble.x = -12.5;
newBubble.y = -12.5;
addChild(newBubble);
gameBubble.push(this);
trace("Bubble");
}
private function tick2(e:Event) {
this.y -= 5;
checkPop();
}
public function tick() {
this.y -= 5;
checkPop();
}
private function checkPop() {
if(this.y < 0) {
this.parent.removeChild(this);
}
}
}
tick is a member method, not a static method.
Bubble.tick()
will look for static public function tick(), while
var b = new Bubble();
b.tick();
will look for public function tick().
Static functions are tied to the class, not a specific instance of the object. Member functions are tied to a specific instance of an object, and can use this to access that instance.
Hope that helps
EDIT (in response to your comment):
It's hard to tell exactly what you are trying to do, but it looks like you want each "Bubble" to slowly move towards the bottom of the screen, and to be removed when it does.
You have 2 options:
1) Every bubble instance creates it's own timer, and tick is a member function (public function tick) which does this.y -= 5 etc.
2) tick is a static function (static public function tick) which does a loop over every bubble (for (bubble in gameBubble) { bubble.y-=5; ...etc... })
The basic rule: anything static can't access this, because it doesn't know which bubble you are talking about, so you'll have to use your static array to go through each of them.
I am a Java Beginner and have a little question.
I have got 2 Classes:
the first one is a java formular, the important code is:
#Override
public void keyPressed(KeyEvent event) {
int key = event.getKeyCode();
if(key == 17) {
System.out.println("STRG");
if(roboter.running == true) {
roboter.running = false;
}
}
}
the second one is a class (called robot) which main part is the for loop:
public class Roboter {
public boolean running = false;
public void myFunction() {
for(...;...;...) {
for(...;...;...) {
if(!running)
break;
// DO SOMETHING IMPORTANT
}
}
}
Well, this doesn't work. I think it is because I can't change the value of running while my for loop. I have no idea how to slove this problem. Maybe there is an other solution? My aim is to stop the robots myFunction if an user press a key.I hope you can help me
I am sorry for my english, if you don't undestand me I will try to rewrite the question.
The class that handles the keyboard input should run in a separate Thread.
I've tried following the steps in Joost Van Schaik's article on tombstoning but was unable to get it to work for me. I'm no doubt doing something wrong. In my ViewModel:
private string _foobar ="init";
public string testStr
{
get
{
return _foobar;
}
set
{
_foobar = value;
}
}
And in my page:
<TextBox x:Name="tBoxTest" Text="{Binding testStr, Mode=TwoWay}" />
While the application is running, changing the value in tBoxTest sets _foobar just fine, but try to serialize it and it’s as if it has forgotten the instance??? Any help would be greatly appreciated.
I was able to get tombstoning to work, along with having an object be visible to all my ViewModels, by doing the following:
In a Model class, I added:
private static Model1 _instance;
public static Model1 Instance
{
get { return _instance; }
set { _instance = value; }
}
public static void CreateNew()
{
if (_instance == null)
{
_instance = new Model1();
_instance.FirstString = "init";
}
}
Then in ApplicationExtensions.cs I added:
public static void SaveToIsolatedStorage(this Application app, Model1 model)
{
var dataFileName = GetIsFile((model.GetType()));
using (var userAppStore =
IsolatedStorageFile.GetUserStoreForApplication())
{
if (userAppStore.FileExists(dataFileName))
{
userAppStore.DeleteFile(dataFileName);
}
using (var iss = userAppStore.CreateFile(dataFileName))
{
SilverlightSerializer.Serialize(model, iss);
}
}
}
And in App.xaml.cs I changed LoadModel() to:
private void LoadModel()
{
try
{
Model1.Instance = this.RetrieveFromIsolatedStorage<Model1>();
}
catch (Exception) { }
if (Model1.Instance == null) Model1.CreateNew();
}
That all made things like this work in my ViewModel files:
public string TestStr
{
get
{
return Model1.Instance.FirstString;
}
set
{
Model1.Instance.FirstString = value;
}
}
And by that, I mean that the Model1 object is getting serialized and tombstoning is working - at least I’m getting what I think I want. I’ve tested it a lot by navigating between apps, phone settings, turning the phone off and on, locking it and calling it while in the app from another phone. Performance when deserializing is great. And I can work with the vars.
That said, Mr. Van Schaik replied to a request for assistance with: "If you are subclassing from an MVVMLight ViewModelBase it does, and then you should call RaisePropertyChanged from your setter like this:
private string _foobar ="init";
public string TestStr
{
get
{
return _foobar;
}
set
{
RaisePropertyChanged("TestStr");
_foobar = value;
}
}
RaisePropertyChanged notifies any listenings views (i.e. the TextBox you bound to it) that a property is changed and that the should update their contents. This is a crucial mechanism."
So I will work with what I was originally trying but with the addition of RaisePropertyChanged to see what that does.
UPDATE
Although I implemented RaisedPropertyChanged (using the code snippet mvvminpc) in my MainViewModel.cs file, that still had no effect (as good as it may be for other things) on serializing anything created within the ViewModel. I'm probably still doing something wrong, but it may also be because view models inherit from a protected class (answer from Laurent Bugnion). I (very reluctantly) tried changing that class from protected to public and recompiling, but it didn't help in my case and I hate to fork a referenced library like that. Anyway, I'm just forging ahead for now with creating the Model1 instance in App.xaml.cs. Seems to work. While I was at it, I modified one of Van Schaik's methods to accept any type of object:
public static void SaveToIsolatedStorage<T>(this Application app, T obj)
where T : class
{
var dataFileName = GetIsFile(typeof(T));
using (var userAppStore =
IsolatedStorageFile.GetUserStoreForApplication())
{
if (userAppStore.FileExists(dataFileName))
{
userAppStore.DeleteFile(dataFileName);
}
using (var iss = userAppStore.CreateFile(dataFileName))
{
SilverlightSerializer.Serialize(obj, iss);
}
}
}
From the code you've posted there isn't an instant answer.
My advice to debug this is:
if you've copied the code exactly from that article then add something (a messagebox?) to the empty catch handler - `catch (Exception){ }
use the debugger to put breakpoints in the LoadModel and SaveToIsolatedStorage methods
use these breakpoints to step through the Load and Save code - is the code correctly loading and saving?
To be honest, with problems like this, doing a little investigation yourself is much better than asking questions on here (IMO!)
How does undo work? Does it copy all the managed objects every time any of the values change? Or does it only copy the actual changes together with an information which objects were affected? Is that heavy or lightweight?
The 'undo' mechanism for pretty much any language that supports Object-Oriented constructs uses the Memento Design Pattern to make it happen.
Here's a rough implementation to get you thinking. This handles your stack of undoable operations. (It doesn't handle redo, but that's easy to support by replacing the stack with a list and keeping track of the current item.)
public class Undoable {
public static void Do(Action do, Action undo) {
do();
sUndoStack.Push(new Undoable(do, undo));
}
public static void Undo() {
sUndoStack.Pop().mUndoCallback();
}
private Undoable(Action doCallback, undoCallback) {
mDoCallback = doCallback;
mUndoCallback = undoCallback;
}
private Action mDoCallback, mUndoCallback;
// note: using a global stack here is lame, but works for demo purposes
private static readonly Stack<Undoable> sUndoStack = new Stack<Undoable>();
}
To use this, let's say the user can change a value in some object like this:
public class Foo {
public string Bar {
get { return mBar; }
set {
if (mBar != value) {
mBar = value;
}
}
}
private string mBar;
}
To make that operation undoable, we just change the setter to:
set {
if (mBar != value) {
string oldValue = mBar;
Undoable.Do(() => mBar = value,
() => mBar = oldValue);
}
}
Now, if you call Undoable.Undo() from anywhere in the application, your instance of Foo will restore the previous value of Bar. If Foo also raises an event when Bar changes (not shown here), the UI will also properly refresh on undo too.