Accessing custom instance variable from other instance object - game-maker

I basically have this:
Obj1 Create event:
health_total = 50;
health_current = health_total;
health_text = instance_create(x,y-10,obj_health); // Object to show health of an instance object
health_text.origin = self; // Assign an 'origin' variable so I can access it later?
obj_health Draw event:
show_debug_message(origin.x); // <-- This works just great!
show_debug_message(origin.health_current); // <-- This throws error :(
I assume that the variable might be local but then, how do I make it public? GML is a bit new to me, though, I'm not new to programming. This makes my mind hurt.

Use id, not self:
health_text.origin = id;

Related

Meteor - Reactive Objects/Classes

TLDR
I like to really focus on keeping business logic away from the view model / controller. I find this sometimes rather hard in Meteor. Maybe I'm missing the point but I am after one of two things really:
1) A really good document explaining at a really low level how reactive values are being used.
2) A package that somehow manages an object so that if any of the setters are altered, they notify all of the get functions that would change as a result.
Unfortunately I've not seen either.
My Example
I have a fair bit ob business logic sitting behind a dialog used to document a consultation. I might have an event that sets a change of state.
I'd like to do something like this in the event:
const cc = new ConsultationEditor();
cc.setChiefComplaint(event.target.value);
console.log(cc.data());
ConsultationDict.set("consEdit", cc.data() );
When the user has updated this value, I'd then like to show a number of fields, based on the change. For this I have a helper with the following:
fields: function(){
console.log("trying to get fields");
const obj = ConsultationDict.get('consEdit');
cc = new ConsultationEditor(obj);
return cc.getFields();
}
But unfortunately this does not work for me.
What is your ConsultationDict?
The way you describe it, you want it to be a ReactiveDict as in the official ReactiveDict package.
https://atmospherejs.com/meteor/reactive-dict
Check this tutorial for examples:
https://themeteorchef.com/snippets/reactive-dict-reactive-vars-and-session-variables/
If you really need more fine tuning in your reactivity, you can also set a dependency tracker tracker = new Tracker.Dependency, and then refer to it wherever you change a variable with tracker.changed() and where the data needs to be notified with tracker.depend() like this:
var favoriteFood = "apples";
var favoriteFoodDep = new Tracker.Dependency;
var getFavoriteFood = function () {
favoriteFoodDep.depend();
return favoriteFood;
};
var setFavoriteFood = function (newValue) {
favoriteFood = newValue;
favoriteFoodDep.changed();
};
getFavoriteFood();
See the full Tracker doc here:
https://github.com/meteor/meteor/wiki/Tracker-Manual
I also found this gist to be useful to build reactive objects:
https://gist.github.com/richsilv/7d66269aab3552449a4c
and for a ViewModel type of behavior, check out
https://viewmodel.meteor.com/
I hope this helps.

ILGenerator. Whats wrong with this Code

I am trying to build a dynamic Property Accessor. Want something which is like really fast as close to calling the actually Property. Dont want to go the Reflection route as its very slow. So i opted to using DynamicAssembly and inject IL using ILGenerator. Below is the ILGenerator related code which seems to work
Label nulllabel = getIL.DefineLabel();
Label returnlabel = getIL.DefineLabel();
//_type = targetGetMethod.ReturnType;
if (methods.Count > 0)
{
getIL.DeclareLocal(typeof(object));
getIL.DeclareLocal(typeof(bool));
getIL.Emit(OpCodes.Ldarg_1); //Load the first argument
//(target object)
//Cast to the source type
getIL.Emit(OpCodes.Castclass, this.mTargetType);
//Get the property value
foreach (var methodInfo in methods)
{
getIL.EmitCall(OpCodes.Call, methodInfo, null);
if (methodInfo.ReturnType.IsValueType)
{
getIL.Emit(OpCodes.Box, methodInfo.ReturnType);
//Box if necessary
}
}
getIL.Emit(OpCodes.Stloc_0); //Store it
getIL.Emit(OpCodes.Br_S,returnlabel);
getIL.MarkLabel(nulllabel);
getIL.Emit(OpCodes.Ldnull);
getIL.Emit(OpCodes.Stloc_0);
getIL.MarkLabel(returnlabel);
getIL.Emit(OpCodes.Ldloc_0);
}
else
{
getIL.ThrowException(typeof(MissingMethodException));
}
getIL.Emit(OpCodes.Ret);
So above get the first argument which is the object that contains the property. the methods collection contains the nested property if any. for each property i use EmitCall which puts the the value on the stack and then i try to box it. This works like a charm.
The only issue is if you have a property like Order.Instrument.Symbol.Name and assume that Instrument object is null. Then the code will throw an null object exception.
So this what i did, i introduced a null check
foreach (var methodInfo in methods)
{
getIL.EmitCall(OpCodes.Call, methodInfo, null);
getIL.Emit(OpCodes.Stloc_0);
getIL.Emit(OpCodes.Ldloc_0);
getIL.Emit(OpCodes.Ldnull);
getIL.Emit(OpCodes.Ceq);
getIL.Emit(OpCodes.Stloc_1);
getIL.Emit(OpCodes.Ldloc_1);
getIL.Emit(OpCodes.Brtrue_S, nulllabel);
getIL.Emit(OpCodes.Ldloc_0);
if (methodInfo.ReturnType.IsValueType)
{
getIL.Emit(OpCodes.Box, methodInfo.ReturnType);
//Box if necessary
}
}
Now this code breaks saying That the object/memory is corrupted etc. So what exactly is wrong with this code. Am i missing something here.
Thanks in Advance.
Previously, if you had consecutive properties P returning string and then Q returning int, you would get something like this:
...
call P // returns string
call Q // requires a string on the stack, returns an int
box
...
Now you have something like this:
...
call P // returns string
store // stores to object
... // load, compare to null, etc.
load // loads an *object*
call Q // requires a *string* on the stack
store // stores to object *without boxing*
...
So I see two clear problems:
You are calling methods in such a way that the target is only known to be an object, not a specific type which has that method.
You are not boxing value types before storing them to a local of type object.
These can be solved by reworking your logic slightly. There are also a few other minor details you could clean up:
Rather than ceq followed by brtrue, just use beq.
There's no point in doing Stloc_1 followed by Ldloc_1 rather than just using the value on the stack since that local isn't used anywhere else.
Incorporating these changes, here's what I'd do:
Type finalType = null;
foreach (var methodInfo in methods)
{
finalType = methodInfo.ReturnType;
getIL.EmitCall(OpCodes.Call, methodInfo, null);
if (!finalType.IsValueType)
{
getIL.Emit(OpCodes.Dup);
getIL.Emit(OpCodes.Ldnull);
getIL.Emit(OpCodes.Beq_S, nulllabel);
}
}
if (finalType.IsValueType)
{
getIL.Emit(OpCodes.Box, methodInfo.ReturnType);
//Box if necessary
}
getIL.Emit(OpCodes.Br_S, returnLabel);
getIL.MarkLabel(nulllabel);
getIL.Emit(OpCodes.Pop);
getIL.Emit(OpCodes.Ldnull);
getIL.MarkLabel(returnlabel);
Note that we can get rid of both locals since we now just duplicate the top value on the stack before comparing against null.

Factory Method implementation in actionscript

Hey folks, i ve got this issue implementing the Factory method.
Following is the snippet of the the main chart class which calls ChartFactory's method to attain the proper object. I Type Cast chartobject so as to be able to call the Show method;i m apprehensive about that as well.
container = new VBox();
container.percentWidth = 100;
container.percentHeight = 100;
super.media.addChild(container);
chartObject = new ChartBase();
chartObject = ChartFactory.CreateChartObject(chartType);
IChart(chartObject).Show(o);
container.addChild(chartObject);
legend = new Legend();
legend.dataProvider = IChart(chartObject);
container.addChild(legend);
Following is the snippet of ChartFactory's method:
public static function CreateChartObject(subType:String):ChartBase
{
switch(subType)
{
case ChartFactory.AREA_CHART:
return new AreaCharts();
break;
case ChartFactory.COLUMN_CHART:
return new ColumnCharts();
break;
case ChartFactory.PIE_CHART:
return new PieCharts();
break;
default:
throw new ArgumentError(subType + ": Chart type is not recognized.");
}
}
And following is Show method of one of the several Charts type classes: AreaCharts, PieCharts etc. All of which implements IChart Interface.
public function Show(o:ObjectProxy):void
{
var grids:GridLines;
var stroke:SolidColorStroke;
var horizontalAxis:CategoryAxis;
var verticalAxis:LinearAxis;
var horizontalAxisRenderer:AxisRenderer;
var verticalAxisRenderer:AxisRenderer;
grids = new GridLines();
if(WidgetStylesheet.instance.LineChart_ShowGrid)
grids.setStyle("gridDirection", "both");
else
grids.setStyle("gridDirection", "");
stroke = new SolidColorStroke(WidgetStylesheet.instance.LineChart_GridLineColor, WidgetStylesheet.instance.LineChart_GridLineThickness);
grids.setStyle("horizontalStroke", stroke);
grids.setStyle("verticalStroke", stroke);
horizontalAxis = new CategoryAxis();
horizontalAxis.categoryField = o.LargeUrl.Chart.xField;
horizontalAxis.title = o.LargeUrl.Chart.xAxisTitle.toString();
verticalAxis = new LinearAxis();
verticalAxis.title = o.LargeUrl.Chart.yAxisTitle.toString();
horizontalAxisRenderer = new AxisRenderer();
horizontalAxisRenderer.axis = horizontalAxis;
horizontalAxisRenderer.setStyle("tickLength", 0);
horizontalAxisRenderer.setStyle("showLine", false);
horizontalAxisRenderer.setStyle("showLabels", true);
horizontalAxisRenderer.setStyle("fontSize", WidgetStylesheet.instance.ComputeChartAxisFontSize(o.HeadlineFontSize));
verticalAxisRenderer = new AxisRenderer();
verticalAxisRenderer.axis = verticalAxis;
verticalAxisRenderer.setStyle("tickLength", 0);
verticalAxisRenderer.setStyle("showLine", false);
verticalAxisRenderer.setStyle("fontSize", WidgetStylesheet.instance.ComputeChartAxisFontSize(o.HeadlineFontSize));
this.series = this.m_createSeries(o);
this.horizontalAxis = horizontalAxis;
this.horizontalAxisRenderers = [horizontalAxisRenderer];
this.verticalAxis = verticalAxis;
this.verticalAxisRenderers = [verticalAxisRenderer];
this.backgroundElements = [grids];
}
I'm afraid that there is more than one issue with this code. Unfortunately it is not obvious why your chart doesn't show up so you may apply some of advices below and use debugger to analyse the issue.
There is no point in creating ChartBase instance if you are going to change value of chartObject reference in the next line
chartObject = new ChartBase();
chartObject = ChartFactory.CreateChartObject(chartType);
If the API of your charts is IChart your factory should return IChart instead of casting.
public static function CreateChartObject(subType:String):IChart
Make sure that you are returning instances of the correct class from the factory. i.e. that you are returning your subclass of standard PieChart. Generally it's not the best idea to extend the class keeping the same name and just changing the package.
Once again, if you are not sure if the program enters some function use the Flash Builder debugger to check this. I can't imagine development without debugger.
Some thoughts:
you call the Show method, pass it some object but nowhere in that method is any child added to a displayObject. What exactly is Show supposed to do?
a lot of member variables in your classes start with UpperCase. The compiler can easily confuse those with class names, in case your classes are named the same. Bad practice to start variable and function names with capitals.
If your casting an instance to another class or interface fails, you will get a runtime error. Those are easy to debug using the Flash Builder debugger.
Hey ppl..
i found out wat wnt wrng..as olwys it wa "I".
I ve a habit of mkin mock ups secluded from the main project n dn integrate it. So in mock up i hd used an xml whch hd a format slightly diff dn d one being used in the main project.
N i hd a conditional chk to return from the prog if certain value doesnt match, n due to faulty xml i did'nt.
So this more a lexical error than a logical one.
Sorry n Thanx evryone for responding.

child of child movie clip are null in imported object from flex to flash right after being created

I have an Movie Clip in Flash that have subobject of button type which has subobject of input text and movie clips. Right after creation core Moveclip all subobject are set to null, when I expect them to be valid objects.
// hierarchy:
// core:MC_Core_design
// button_1:B_Mybutton
// text_name // dynamic text with instance name
// mc_icon // movie clip with instance name
var core:MC_Core_design = new MC_Core_design();
addChild(core);
core.button_1.text_name.text = "hello world"; // error: text_name is null
core.button_1.mc_icon.visible = false; // error: mc_icon is null
MC_Core_design was created in Flash and exported to Actionscript. I've done this for button_1 class aswell. The code was written using Flex.
When I comment out both lines that result in error I get correct view of the core Movie clip with all subobject.
How can I set subobject properties right after object creation?
You need to listen for the Event.INIT from the class when it is created. (If you are not embedding a symbol using the Embed metatag then Flash takes a few milliseconds to initialize the loaded movieclip). This does not seem to be a problem if the Flash IDE swf/swc does not contain any actionscript)
The issue is sometimes it can be really quick, so it fires the INIT event before you get a chance to attach the event listener to the object. so you can't just attach it after you instantiate the object.
A work around is to embed the swf as a byte array, then use the loader class to load the embedded bytes (This lets you set the event listener before calling load).
e.g.
[Embed(source="assets.swf", mimeType="application/octet-stream")]
private var assetBytes:Class;
private var clip:MovieClip;
private var loader:Loader;
public function LoadBytesExample()
{
loader = new Loader();
loader.contentLoaderInfo.addEventListener(Event.INIT, onAssetLoaded);
loader.loadBytes(new assetBytes());
}
private function onAssetLoaded(e:Event):void
{
var loader:Loader = (e.currentTarget as LoaderInfo).loader;
(e.currentTarget as LoaderInfo).removeEventListener(Event.INIT, onAssetLoaded);
clip = loader.content as MovieClip;
this.addChild(clip);
clip.someTextField.text = "HELLO WORLD";
}
Sorry for the formatting, just wrote that off the top of my head
And the syntax for embedding the symbol (You won't need to load this via a loader as the actionscript in the external swf/swc is stripped).
[Embed(source="assets.swf", symbol="somesymbol")]
private var assetSymbol:Class;
private var clip:MovieClip;
public function LoadSymbolExample()
{
clip = new assetSymbol();
clip.sometext.text = "Hello World";
}
If I see it right, button_1:B_Mybutton is not yet initialized.
I mean something like : button_1:B_Mybutton = new B_Mybutton();
About the other two variables text_name & mc_icon as you describe if they have been initialized already (as you term them as instance names), Iguess they should not give you any problem.
Also I asssume that you are setting access modifiers to all as public.
If you still have problem... pls share how all the required variables are defined. Just the relevant part would be enough.

structureMap mocks stub help

I have an BLL that does validation on user input then inserts a parent(PorEO) and then inserts children(PorBoxEO). So there are two calls to the same InsertJCDC. One like this=>InsertJCDC(fakePor) and another like this=>InsertJCDC(fakeBox).
When I stub out the parent I want to return fakePor. But when I run the code it returns null instead. Here is the unit test.
[Test]
public void PorBLL_InsertByPorInsertCV_DoingGoodCase()
{
// Startup object mapper
_Bootstrapper.Bootstrap();
// create the mock for generic Crud
IGenericCrud mockGenericCrud = MockRepository.GenerateMock<IGenericCrud>();
PorInsertCV fakePor = new PorInsertCV();
PorBoxInsertCV fakeBox = new PorBoxInsertCV();
// build fake return
PorEO fakePorNewRow = new PorEO();
fakePorNewRow.PorId = 22;
// stub parent and child insert routines.
mockGenericCrud.Stub(c => c.InsertJCDC<PorEO, PorInsertCV>(fakePor)).Return(fakePorNewRow);
mockGenericCrud.Stub(c => c.InsertJCDC<PorBoxEO, PorBoxInsertCV>(fakeBox)).Return(null);
ObjectFactory.Inject(typeof(IGenericCrud), mockGenericCrud);
IPorBLL localWithMock = ObjectFactory.GetInstance<IPorBLL>();
// build user args to csll bll with and use for insert
PorInsertCV userArgs = new PorInsertCV();
userArgs.AccessionNbr = "364-80-0007";
userArgs.NbrBoxes = 11;
userArgs.RegId = 20;
userArgs.TransmitedDt = Convert.ToDateTime("1/30/1980");
// call the bll using the stub
localWithMock.InsertByPorInsertCV(userArgs);
}
Any help is greatly appreciated
I can't really follow your code that well, but I'll give it a shot.
From my skills of deduction, this line here is the one giving you issues:
mockGenericCrud.Stub(c => c.InsertJCDC<PorEO, PorInsertCV>(fakePor)).Return(fakePorNewRow);
Because you're expecting fakePorNewRow to be returned when you call localWithMock.InsertByPorInsertCV(userArgs); - yeah?
If that's your case, what your problem is, is that it will only return fakePorNewRow when it is given fakePor ... not userArgs as you have given it.
Tell me if I'm completely off track.
HTHs,
Charles
Ps. You might want to add the tag of which mocking framework you are using to the question.

Resources