Non-persistence of class variables in StateMachine in CodenameOne - codenameone

I am writing an App which declares some class variables in StateMachine as for example:
Label Logo=null; Image helpIcon=null;
and these are initialised in initVars()
Logo = new Label(resFile.getImage("ic_action_play.png"));
helpIcon = resFile.getImage("ic_action_help.png");
beforeMain() calls createMenu() to setup a menu dynamically.
private void createMenu(int menuNumber, Form targetForm) {
Toolbar tb = targetForm.getToolbar();
if (menuNumber == MAIN_MENU && !menuInitialised) {
tb.addComponent(BorderLayout.WEST, Logo);
menuInitialised = true;
}
tb.addCommandToRightBar("", helpIcon, (e)->getDialog(1));
etc...
This works fine.
One of the menu items shows a Dialog, "Setup" and if I set a breakpoint in beforeSetup(Form f)
all the class variables have been reset to null. The instance of StateMachine hasn't changed
and the Ctor is not called. The only way I could retain the initialisations was to make the (class) variables that are
initialised in initVars() static. Is that right or am I not doing this correctly?

initVars happens before class init code e.g.:
private int myValue = 1;
protected void initVars() {
myValue = 2;
// will print 2
System.out.println(myValue);
}
public Statemachine() {
// will print 1
System.out.println(myValue);
}
The output of this will be:
2
1
As initVars happens before the constructor and initializing a value in the class scope is the equivalent of setting it in the constructor. The solution is not to initialize the variable and only set it in the initVars().
This is one of the old GUI builder oddities which is why we are moving towards the new GUI builder.

Related

How do I use my own function in a timer class?

The code is taken from here:
https://learn.microsoft.com/en-us/dotnet/api/system.windows.forms.timer?view=windowsdesktop-6.0
private:
static System::Windows::Forms::Timer^ myTimer = gcnew System::Windows::Forms::Timer;
static int alarmCounter = 1;
static bool exitFlag = false;
// This is the method to run when the timer is raised.
static void TimerEventProcessor( Object^ /*myObject*/, EventArgs^ /*myEventArgs*/ )
{
myTimer->Stop();
// Displays a message box asking whether to continue running the timer.
if ( MessageBox::Show( "Continue running?", String::Format( "Count is: {0}", alarmCounter ), MessageBoxButtons::YesNo ) == DialogResult::Yes )
{
// Restarts the timer and increments the counter.
alarmCounter += 1;
myTimer->Enabled = true;
}
else
{
// Stops the timer.
exitFlag = true;
}
}
For example, after the line myTimer->Stop(); I want to use my own method. How do I identify it? E0020 ID "draw 1" is not defined.
System:: Void Practform::MyForm::draw1() {
. . .
}
Please tell me, because I'm a little stalled, since I've never worked with this.
I have a feeling that what you are bumping up against is attempting to invoke an instance method from a static method. To do so, you would need to have an instance of the class which has the method, e.g:
ref struct Foo {
void InstanceMethod() {}
static void StaticMethod() {
auto instance = gcnew Foo();
instance->InstanceMethod();
}
}
called like so:
Foo::StaticMethod();
However, taking the example code, it could be easier (and more appropriate) to change the static methods to instance methods, like so:
using namespace System;
using namespace System::Windows::Forms;
ref struct MyForm : Form {
Timer ^myTimer = gcnew Timer();
MyForm(void) {
myTimer->Tick += gcnew EventHandler(this, &MyForm::TimerEventProcessor);
myTimer->Interval = 5000;
myTimer->Start();
}
void TimerEventProcessor(Object ^, EventArgs ^) {
myTimer->Stop();
draw1();
}
void draw1() {
MessageBox::Show("Done", "Timer is done", MessageBoxButtons::OK);
}
};
called like so:
auto form = gcnew MyForm();
form->Show();
Notes:
I'm assuming that you've added the code from the example into your own class, called MyForm
I've used struct throughout instead of class to make everything public - you should use the appropriate access modifiers to your use case
The most notable change is the use of the EventHandler constructor which takes an instance of the handler as its first argument, and the method to execute as its second.
The advantages of using instance methods and properties are that:
you will have access to this in the draw1() method (given the name of the method, is likely to want to draw using the form instance), and
the Timer instance will be garbage collected as appropriate,

Accessing a variable in another scene

Is it possible to change a variable in another scene in unity. I have a script right now that has the user pick 5 heroes and those 5 heroes get saved to a array, but in order for the game to run how i want it, that array will be in another scene and I'm not sure how to go about saving the five heroes data to an array in another scene. I can do it all in one scene but 2 scenes would be more efficient. Here's my code:
using UnityEngine;
using System.Collections;
public class HeroChooser : MonoBehaviour {
public static GameObject Archer;
GameObject Berserker;
GameObject Rouge;
GameObject Warrior;
GameObject Mage;
GameObject MainCamera;
public int counter = 0;
public bool archerOn = false;
public bool berserkerOn = false;
public bool rougeOn = false;
public bool mageOn = false;
public bool warriorOn = false;
// Use this for initialization
void Start () {
}
// Update is called once per frame
void Update () {
}
void OnGUI(){
if(archerOn == false){
if (GUI.Button (new Rect(50,0,50,50), "Archer")){
Archer = GameObject.Find("Archer");
MainCamera = GameObject.Find("Main Camera");
HeroArraySaver heroArraySaver = MainCamera.GetComponent<HeroArraySaver>();
heroArraySaver.array[counter] = Archer;
archerOn = true;
counter++;
}
}
Its saying that: Static member HeroArraySaver.array cannot be accessed with an instance reference, qualify it with a type name instead im not sure how to go about fixing it.
A simple way would be to create an empty GameObject and attach a script/MonoBehaviour to that which holds your data. To make it persist you would have to call DontDestroyOnLoad() on that GameObject. This will ensure your GameObject will hang around when moving to a different scene.
So something like:
GameObject myPersistentDataObject = new GameObject("myPersistentDataObject");
MyDataClass data_class = myPersistentDataObject.AddComponent<MyDataClass>();
//set your data to whatever you need to maintain
And in your Awake of your MyDataClass you'd do something like
void Awake()
{
DontDestroyOnLoad(transform.gameObject);
}
Then in your other scene you can simply find your GameObject again and retrieve its data from the attached component.
Assuming you have integer IDs for the heroes, simply store them in a static variable:
public class GlobalData {
public static int[] heroIds;
}
Static variables can be accessed from any scene and will persist as long as your game runs. The same technique works for strings or enums.

How to share an Array between all Classes in an application?

I want to share an Array which all classes can "get" and "change" data inside that array. Something like a Global array or Multi Access array. How this is possible with ActionScript 3.0 ?
There are a couple of ways to solve this. One is to use a global variable (as suggested in unkiwii's answer) but that's not a very common approach in ActionScript. More common approaches are:
Class variable (static variable)
Create a class called DataModel or similar, and define an array variable on that class as static:
public class DataModel {
public static var myArray : Array = [];
}
You can then access this from any part in your application using DataModel.myArray. This is rarely a great solution because (like global variables) there is no way for one part of your application to know when the content of the array is modified by another part of the application. This means that even if your data entry GUI adds an object to the array, your data list GUI will not know to show the new data, unless you implement some other way of telling it to redraw.
Singleton wrapping array
Another way is to create a class called ArraySingleton, which wraps the actual array and provides access methods to it, and an instance of which can be accessed using the very common singleton pattern of keeping the single instance in a static variable.
public class ArraySingleton {
private var _array : Array;
private static var _instance : ArraySingleton;
public static function get INSTANCE() : ArraySingleton {
if (!_instance)
_instance = new ArraySingleton();
return _instance;
}
public function ArraySingleton() {
_array = [];
}
public function get length() : uint {
return _array.length;
}
public function push(object : *) : void {
_array.push(object);
}
public function itemAt(idx : uint) : * {
return _array[idx];
}
}
This class wraps an array, and a single instance can be accessed through ArraySingleton.INSTANCE. This means that you can do:
var arr : ArraySingleton = ArraySingleton.INSTANCE;
arr.push('a');
arr.push('b');
trace(arr.length); // traces '2'
trace(arr.itemAt(0)); // trace 'a'
The great benefit of this is that you can dispatch events when items are added or when the array is modified in any other way, so that all parts of your application can be notified of such changes. You will likely want to expand on the example above by implementing more array-like interfaces, like pop(), shift(), unshift() et c.
Dependency injection
A common pattern in large-scale application development is called dependency injection, and basically means that by marking your class in some way (AS3 meta-data is often used) you can signal that the framework should "inject" a reference into that class. That way, the class doesn't need to care about where the reference is coming from, but the framework will make sure that it's there.
A very popular DI framework for AS3 is Robotlegs.
NOTE: I discourage the use of Global Variables!
But here is your answer
You can go to your default package and create a file with the same name of your global variable and set the global variable public:
//File: GlobalArray.as
package {
public var GlobalArray:Array = [];
}
And that's it! You have a global variable. You can acces from your code (from anywhere) like this:
function DoSomething() {
GlobalArray.push(new Object());
GlobalArray.pop();
for each (var object:* in GlobalArray) {
//...
}
}
As this question was linked recently I would add something also. I was proposed to use singleton ages ago and resigned on using it as soon as I realized how namespaces and references work and that having everything based on global variables is bad idea.
Aternative
Note this is just a showcase and I do not advice you to use such approach all over the place.
As for alternative to singleton you could have:
public class Global {
public static const myArray:Alternative = new Alternative();
}
and use it almost like singleton:
var ga:Alternative = Global.myArray;
ga.e.addEventListener(GDataEvent.NEW_DATA, onNewData);
ga.e.addEventListener(GDataEvent.DATA_CHANGE, onDataChange);
ga.push(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, "ten");
trace(ga[5]); // 5
And your Alternative.as would look similar to singleton one:
package adnss.projects.tchqs
{
import flash.utils.Proxy;
import flash.utils.flash_proxy;
public class Alternative extends Proxy
{
private var _data:Array = [];
private var _events:AltEventDisp = new AltEventDisp();
private var _dispatching:Boolean = false;
public var blockCircularChange:Boolean = true;
public function Alternative() {}
override flash_proxy function getProperty(id:*):* {var i:int = id;
return _data[i += (i < 0) ? _data.length : 0];
//return _data[id]; //version without anal item access - var i:int could be removed.
}
override flash_proxy function setProperty(id:*, value:*):void { var i:int = id;
if (_dispatching) { throw new Error("You cannot set data while DATA_CHANGE event is dipatching"); return; }
i += (i < 0) ? _data.length : 0;
if (i > 9 ) { throw new Error ("You can override only first 10 items without using push."); return;}
_data[i] = value;
if (blockCircularChange) _dispatching = true;
_events.dispatchEvent(new GDataEvent(GDataEvent.DATA_CHANGE, i));
_dispatching = false;
}
public function push(...rest) {
var c:uint = -_data.length + _data.push.apply(null, rest);
_events.dispatchEvent(new GDataEvent(GDataEvent.NEW_DATA, _data.length - c, c));
}
public function get length():uint { return _data.length; }
public function get e():AltEventDisp { return _events; }
public function toString():String { return String(_data); }
}
}
import flash.events.EventDispatcher;
/**
* Dispatched after data at existing index is replaced.
* #eventType adnss.projects.tchqs.GDataEvent
*/
[Event(name = "dataChange", type = "adnss.projects.tchqs.GDataEvent")]
/**
* Dispatched after new data is pushed intwo array.
* #eventType adnss.projects.tchqs.GDataEvent
*/
[Event(name = "newData", type = "adnss.projects.tchqs.GDataEvent")]
class AltEventDisp extends EventDispatcher { }
The only difference form Singleton is that you can actually have multiple instances of this class so you can reuse it like this:
public class Global {
public static const myArray:Alternative = new Alternative();
public static const myArray2:Alternative = new Alternative();
}
to have two separated global arrays or even us it as instance variable at the same time.
Note
Wrapping array like this an using methods like myArray.get(x) or myArray[x] is obviously slower than accessing raw array (see all additional steps we are taking at setProperty).
public static const staticArray:Array = [1,2,3];
On the other hand you don't have any control over this. And the content of the array can be changed form anywhere.
Caution about events
I would have to add that if you want to involve events in accessing data that way you should be careful. As with every sharp blade it's easy to get cut.
For example consider what happens when you do this this:
private function onDataChange(e:GDataEvent):void {
trace("dataChanged at:", e.id, "to", Global.myArray[e.id]);
Global.myArray[e.id]++;
trace("new onDataChange is called before function exits");
}
The function is called after data in array was changed and inside that function you changing the data again. Basically it's similar to doing something like this:
function f(x:Number) {
f(++x);
}
You can see what happens in such case if you toggle myArray.blockCircularChange. Sometimes you would intentionally want to have such recursion but it is likely that you will do it "by accident". Unfortunately flash will suddenly stop such events dispatching without even telling you why and this could be confusing.
Download full example here
Why using global variables is bad in most scenarios?
I guess there is many info about that all over the internet but to be complete I will add simple example.
Consider you have in your app some view where you display some text, or graphics, or most likely game content. Say you have chess game. Mayby you have separated logic and graphics in two classes but you want both to operate on the same pawns. So you create your Global.pawns variable and use that in both Grahpics and Logic class.
Everything is randy-dandy and works flawlessly. Now You come with the great idea - add option for user to play two matches at once or even more. All you have to do is to create another instance of your match... right?
Well you are doomed at this point because, every single instance of your class will use the same Global.pawns array. You not only have this variable global but also you have limited yourself to use only single instance of each class that use this variable :/
So before you use any global variables, just think twice if the thing you want to store in it is really global and universal across your entire app.

Problem Loading Textures via DrawableGameComponent Implementation

I get a ContentLoadException "File not found", when the debugger hits my LoadContent method in my DrawableGameComponent. I created a test string that outputs the Content Root Directory and it is as follows : \GameName\bin\x86\Debug\Content minus my personal folders preceding it of course.
Here is the code in the Game child class :
GraphicsDeviceManager graphics;
global_vars variables;
public Game1()
{
graphics = new GraphicsDeviceManager(this);
Content.RootDirectory = "Content"; //Folder for the Content Manager to place pipelined files as they are loaded
}
/// <summary>
/// Allows the game to perform any initialization it needs to before starting to run.
/// This is where it can query for any required services and load any non-graphic
/// related content. Calling base.Initialize will enumerate through any components
/// and initialize them as well.
/// </summary>
protected override void Initialize()
{
variables = new global_vars(graphics);
Character c = new Character(null, null, variables, this);
this.Components.Add(c);
base.Initialize();
}
And the DrawableGameComponent implementation :
public Character(Ability[] starting_abilities, Player owner, global_vars vars, Game game) : base(game)
{
this.variables = vars;
this.abilities = starting_abilities;
this.character_owner = owner;
this.experience = 0;
this.position = new Rectangle(variables.CHARACTER_START_POSITION_X, variables.CHARACTER_START_POSITION_Y, variables.CHARACTER_WIDTH + variables.CHARACTER_START_POSITION_X, variables.CHARACTER_HEIGHT + variables.CHARACTER_START_POSITION_Y);
}
public override void Initialize()
{
base.UpdateOrder = variables.CHARACTER_UPDATE_PRIORITY;
base.DrawOrder = variables.CHARACTER_UPDATE_PRIORITY;
base.Enabled = true; //Enables Game to call Update on this component
base.Visible = true; //Enables Game to call Draw on this component
this.move_speed = 3;
this.position.X = variables.CHARACTER_START_POSITION_X;
this.position.Y = variables.CHARACTER_START_POSITION_Y;
this.move_state = variables.CHARACTER_DEFAULT_MOVESTATE;
this.charsprite = new SpriteBatch(variables.manager.GraphicsDevice);
base.Initialize(); //Super class calls LoadContent
}
protected override void LoadContent()
{
String test = Game.Content.RootDirectory;
character_default = Game.Content.Load<Texture2D>("Character_Grey_Eyes_Center");
character_right = Game.Content.Load<Texture2D>("Character_Grey_Eyes_Right");
character_left = Game.Content.Load<Texture2D>("Character_Grey_Eyes_Left");
character_down = Game.Content.Load<Texture2D>("Character_Grey_Eyes_Down");
character_up = Game.Content.Load<Texture2D>("Character_Grey_Eyes_Up");
base.LoadContent();
}
I've checked and double checked the Folders, Filenames, etc and they all look normal. I'm absolutely stumped.
Solved it. My Character was being added to the Component list in the Games Initialize() before it's super class call to base.Initialize(). This made my game begin calling the Character's Load and Init functions. Since the Game's Init was not called, the super class Microsoft.Xna.Framework.Game Content variable was either a null pointer or not set up properly.
The solution was to add the Character to the Component list in the game's LoadContent()

Where should I put initialization code so it would be executed in before VS initializes my control in design mode

I have a method Translate extension which searches for a translation. Normally translations are loaded in Window constructor (I tried in App.Setup too). No if i run the application all the translations are displayed correctly, but when opening a user control all translations are gone.
So the question is where do I put my initialization code so it would be executed before VS initializes design window
it should be default constructor
Either the class constructor (or code called from it) or some static member initialized by a static constructor.
Option 1:
public partial class MyUserControl : UserControl
{
int thisWillWork = 1;
int thisWillAlsoWork;
public MyUserControl()
{
thisWillAlsoWork = 1;
InitializeComponents();
}
Option 2:
public class SomeOtherClass
{
public static int YouCanUseThis = 1;
public static int AndThisAlso;
static SomeOtherClass()
{
AndThisAlso = 1;
}
}

Resources