AS3 Boolean seemingly not working - actionscript-3

Ok, so this is obviously going to be something that I stupidly overlooked in my code, but I am having problems with a boolean check in as3. In the below if statement I set a boolean, I can confirm that the boolean is set in this if switch as I have run a trace to check that:
if(switchA && switchB){
if(Side == "LEFT"){
localAttachCoords.x = (-Parent.collision.SideLength - entity.collision.SideLength)/2
localAttachCoords.y = Parent.collision.SideLength/2 - (((TargNode-1)*8) + entity.collision.SideLength/2)
}
if(Side == "RIGHT"){
localAttachCoords.x = (Parent.collision.SideLength + entity.collision.SideLength)/2
localAttachCoords.y = -(Parent.collision.SideLength/2 - (((TargNode-1)*8) + entity.collision.SideLength/2))
}
if(Side == "UP"){
localAttachCoords.y = (Parent.collision.SideLength + entity.collision.SideLength)/2
localAttachCoords.x = -(Parent.collision.SideLength/2 - (((TargNode-1)*8) + entity.collision.SideLength/2))
}
if(Side == "DOWN"){
localAttachCoords.y = (-Parent.collision.SideLength - entity.collision.SideLength)/2
localAttachCoords.x = Parent.collision.SideLength/2 - (((TargNode-1)*8) + entity.collision.SideLength/2)
}
entity.attached = true
entity.Parent = Parent
}
This would all be well and good, but for the fact that in a function from another class, executed every frame, claims that the boolean was set to false, I confirmed this with another trace function.
This is the function, taken from the class whose instance is referred to as entity in the above switch:
public function update(){
if (physics) physics.update()
if (node && physics){
trace(attached)
if(attached){
physics.nodeUpdate()
}
}
}
This function claims in the trace that attached == false despite it being set true earlier with no other reference to the attached variable. Any help would be appreciated!

Pathing
There are some un-addressed variables in your issue, foremost being the pathing you're taking to check your variable. This is relevant because of namespaces/scope affect what each piece of code has access to.
If your functions and variables shared the same space (i.e., global/document/timeline), then any reference the the same named variable will always return the same value, unless (as LoremIpsum noted) it's being shadowed by a local variable by the same name.
Obviously, this is not the case since you're using public function which is a class-only declaration. If the boolean you're looking for is on the timeline, and the class wants to read that variable, you need to have a valid path to it. Instantiated classes that are DisplayObjects and have been added to the DisplayList have both parent and stage properties which you can use to access the timeline global namespace (thereby providing access to your boolean).
However, if the class is not a DisplayObject (e.g., it does not extend a Sprite, Shape, or MovieClip), then access to the timeline has to be provided manually, either by setting a property on the class, or passing an argument to a method on the class.
Further complicating the matter is if the Boolean exists in another class object (either instantiated or static), you'd then need a way to get between them. A case of A sees B, C sees B, but neither A or C see eachother.
Values
A boolean is always going to be false, even if the assigned value was null, so if your class is trying to reference a variable that it can't see, that value will always be false. For example...
var foo:Boolean = this["fiddlesticks"];
trace("foo = " + foo); // traces: "foo = false"
There is no property this.fiddlesticks, so while the resolved value is null, foo becomes false. Consider using hasOwnProperty(), which indicates whether an object has a specified property defined, and is a method available to all objects.
Switch
You don't have to manually create your own switch using if then else if, AS3 has its own switch statement.
switch (Side) {
case "LEFT":
// Do stuff for left
break;
case "RIGHT":
// Do stuff for right
break;
case "UP":
// Throw your hands up
break;
case "DOWN":
// Get down and boogie!
break;
}
I hope that all helps. I'd like to say exactly what's going on with the access to your Boolean, but there simply isn't enough information to say.
Cheers!

Related

How to use a signal as function parameter in CAPL

I am trying to write a function in CAPL that takes a signal and calculates the physical value with the signal value, the signal factor and the signal offset.
This is how a simple gateway normally works:
message CAN1.myMessage1 myMessage1 = {DIR = RX};//message from the database
message CAN2.myMessage2 myMessage2 = {DIR = TX};//another message from the database
on message CAN1.*
{
if(this.id == myMessage1.id)
{
myMessage1 = this;
myMessage2.mySignalB = myMessage1.mySignalA * myMessage1.mySignalA.factor + myMessage1.mySignalA.offset;
}
}
And this is what I am trying to do:
...
on message CAN1.*
{
if(this.id ==myMessage1.id)
{
myMessage1 = this;
myMessage2.mySignalB = PhysicalValue(myMessage1.mySignalA);
}
}
double PhysicalValue(signal * s)
{
return s*s.factor+s.offset;
}
There are two problems with this code:
Firstly when I pass the signal as the parameter the compiler says that the types don't match. The second problem is that inside the function the attributes (factor and offset) are no longer recognized.
These problems might have something to do with the weird object-oriented-but-not-really nature of CAPL. The value of the signals can be accessed directly but it also has attributes?
int rawValue = myMessage1.mySignalA;
If you are familiar with C you might say that the problem is that I am specifying a pointer in the function but that I am not passing a pointer into it. But in CAPL there are no pointers and the * simply means anything.
Without the * I would have needed to use a specific signal which would have defeated the purpose of the function.
EDIT:
I have found the attribute .phys by now which does exactly what my demo function would have done.
double physValue = myMessage1.mySignalA.phys;
This has already made my code much shorter but there are other operations that I need to perform for multiple signals so being able to use signals as a function parameter would still be useful.
What you can do is this:
double PhysicalValue(signal * s)
{
// access signal by prepending a $
return $s.phys;
}
Call like this
on message CAN1.*
{
if(this.id ==myMessage1.id)
{
myMessage1 = this;
myMessage2.mySignalB = PhysicalValue(CAN1::myMessage1::mySignalA);
}
}
I.e. when you call your function, you have to provide the qualified name of the signal (with colons rather than dots). To my knowledge it is not possible to use myMessage1.mySignalA, since signals itself are not a CAPL datatype.
Apart from this, you might re-think whether you really should be using on message, but rather switch to on signal. Handling the signal values no matter with which message they are sent is done by CANoe's signal server.
Note that CANoe already has a function which does exactly what you're trying to do (multiplying by factor and adding offset). It's called getSignal:
on message CAN1.*
{
if(this.id == myMessage1.id)
{
myMessage2.mySignalB = getSignal(myMessage1::mySignalA);
}
}
Offsets and factors are defined in e.g. the DBC files.

Arma 3 - addAction with dynamic variables to specific Object

Playing around with custom composition spawning in Arma 3. I am currently using "LARs Composition Spawn Script" (https://forums.bistudio.com/forums/topic/191902-eden-composition-spawning/) to spawn a custom compostion. Spawning compositions around the map works like a charm.
In the composition there is one object (AI) whith varname "quest_giver". To this specific Object I want to add an Action. My current code is:
// SPAWN RANDOM COMPOSITION ON RANDOM POSITION
_spawned_composition = [ _random_composition, _pos, [0,0,0], random 360 ] call LARS_fnc_spawnComp;
// GET OBJECTS FROM THE SPAWNED COMP BACK (ARRAY)
_objects = [_spawned_composition] call LARs_fnc_getCompObjects;
// TRYING TO ITERATE THROUGH OBJECTS TO FIND "quest_giver"
// AND ADD ACTION TO IT.
{
_type = typeName _x;
if (_type == "GROUP") then {
_units = units _x;
{
_var = missionNamespace getVariable ["name", _x];
_name = typeOf _var;
if (_name == "quest_giver") then {
player globalChat format["%1",_name];
//_speak = _x addAction ["Speak", {hint format ["Hello, it works !"]}];
};
} forEach _units;
};
} forEach _objects;
Error at If(_name == "quest_giver") where _name is an OBJECT but "quest_giver" of course a STRING. So I get Error Generic error in expression.
However, _var = missionNamespace getVariable ["name",_x]; returns "quest_giver". But it as an OBJECT, since typeOf _var returns "OBJECT" not STRING.
I just can't figure out the most simpliest thing here I guess. Any idea, if this would even work in theory ?
What I am trying to achieve
Create various custom compositions, where on Object in it is always the "quest_giver". Works so far.
Choose random comp and spawn it on random position in the world. Works so far.
Add action to the quest giver so player can speak to him. Text Pop up with simple text, content would be a random quest ala bring me 5 x Water Bottles.
I know my way around before and after the add action part but can't figure out how to add action to this specific object. ...
unless I'm mistaken, you seem to be confused about how to get the unit's name?
it might be you want to get a name var from the unit's namespace (if the thing you're using does put it there):
_name = _x getVariable ["name" /*var name*/, "" /*default value*/];
if (_name == "quest_giver") then {
//...
or more likely (if it's about the name set via editor) with the name function:
if ((name _x) == "quest_giver") then {

Using objects instead of arrays

I've spent nearly 1 week to learn working with objects instead of arrays. I had thought it was easy to call them and created some objects and set their properties. However I can't access them now, I tried this:
function onBoxClick(event:MouseEvent):void {
var str:String = event.currentTarget.name;
trace(str);
str = str.substring(str.indexOf("_") + 1);
trace(getChildByName("copy_" + str)); // trying to trace an object by name
}
My question is if there's a practical way of dealing with objects, otherwise what's the purpose of using them.
Edit: Here's my function that I use to create movieclips and other things:
function addBoxes(isUpdate:Boolean):void {
var copyOne:Object = getReadOnlyValues();
copyOne.name = "copy_" + num;
// Set default mc1 settings
var settings1:Object = copyOne.mc1Settings;
for(var num2:String in settings1) {
copyOne.mc1[num2] = settings1[num2];
}
// Set default mc1text settings
var settings2:Object = copyOne.mc1TextSettings;
for(var num3:String in settings2) {
copyOne.mc1Text[num3] = settings2[num3];
}
copyOne.mc1.x = nextXpos;
copyOne.mc1.name = "captionBox_" + num;
addChild(copyOne.mc1);
copyOne.mc1.addEventListener(MouseEvent.CLICK, onCaptionClick);
copyOne.mc1Text.name = "captionBoxText_" + num;
copyOne.mc1.addChild(copyOne.mc1Text);
// ---------------------------------------------------------------
// Set default mc2 settings
var settings4:Object = copyOne.mc2Settings;
for(var num4:String in settings4) {
copyOne.mc2[num4] = settings4[num4];
}
// Set default mc2text settings
var settings5:Object = copyOne.mc2TextSettings;
for(var num5:String in settings5) {
copyOne.mc2Text[num5] = settings5[num5];
}
copyOne.mc2.x = nextXpos;
copyOne.mc2.y = copyOne.mc1.height;
copyOne.mc2.name = "box2_" + num;
addChild(copyOne.mc2);
copyOne.mc2Text.name = "box2BoxText_" + num;
copyOne.mc2.addChild(copyOne.mc2Text);
copyOne.mc2.addEventListener(MouseEvent.CLICK, onBoxClick);
if (num / subunits is int) {
trace (num);
// createMc("normalBox", true);
}
nextXpos = nextXpos + copyOne.mc2.width;
// traceObj(copyOne);
// traceObj(getReadOnlyValues());
}
I called this function in a loop so I created many movieclips. Now I can't access objects' properties and their childen (e.g textfield).
Objects I have on stage: Movieclips and textfields
Where they come from: The function above
What I'm trying to do with them: Tracing movieclips and textfields (that are holded by objects) to change their children (textfield) text
What happens instead of what I expect: Trace code outputs undefined instead of giving me object type trace(getChildByName("copy_" + str)); // trying to trace an object by name
Is there a practical way of accessing an object whose name is "copy_1" and its property whose name is "box2_1" (movieclip)?
One problem I see is the "copyOne" object has been created within the scope of "addBoxes", so it will no longer exist outside of this function.
Another is you're trying to access an Object via getChildByName, which only addresses displayObjects of the displayObjectContainer you are calling from.
If you want to loosely keep track of variables with things like Objects or MovieClips (which are both dynamic-style objects that let you add properties to them as you wish), just use MovieClips to house your values. The movieClips, being on the stage, will be retained in memory until removed from the displayList (stage).
Also, check out the Dictionary, a sort of key/value based way of storing collections of objects.
Better yet, if you use strongly-typed custom objects (creating your own classes to extend MCs, and adding your own public or private methods and values), there are benefits such as using Vectors (fancy, fast arrays that are compatible with any Object type you choose).
I don't really know if I understood your question or not, but as #ozmachine said in his answer, you can not use getChildByName, instead I think that you can take a look on this, may be it can help :
var container:DisplayObjectContainer = this;
function getReadOnlyValues():Object {
return {
mc1: new box(),
mc1: {
name: 'mc1_',
alpha: 1,
x: 0,
y: 0,
width: 30,
height: 25
},
mc1Text: new TextField(),
mc1Text: {
text: 'test',
x: 0,
y: 0,
selectable: false,
multiline: false,
wordWrap: false
}
}
};
// create 5 objects
for(var i=0; i<5; i++){
container['copy_'+i] = getReadOnlyValues();
var obj:Object = getObjectByName('copy_'+i);
obj.mc1.alpha = 1;
obj.mc1.x = 0;
obj.mc1.y = 50 * i;
obj.mc1.width = 100;
obj.mc1.addChild(obj.mc1Text);
obj.mc1Text.text = 'test_' + i;
addChild(obj.mc1);
}
// get object by name
function getObjectByName(name:String):Object {
return container[name];
}
// change the text of the 4th button
stage.addEventListener(MouseEvent.CLICK, function(e:MouseEvent):void {
var obj:Object = getObjectByName('copy_3');
obj.mc1Text.text = 'new text';
})
Array and Object are both data structures.
Data means some form of information.
Data structure means some form of information being stored in a certain way.
Array and Object are two different ways to store information.
Arrays identify data with integer numbers.
An integer number to identify a single element of an array is called an index
Arrays are ideal to represent a list of similar things that belong to each other.
var names:Array = ["John", "Paul", "George", "Ringo"];
This often means that the elements of an array are of the same type, like in the example above.
But they don't have to:
var numbers:Array = [42, "twenty-five", "XIIV"];
For the above examples it's easy to answer the questions "What are the names of the four beatles?", "What different representations of numbers did you stumble upon during your trip through the historic town?". Other questions are harder or impossible to answer. "What Roman numerals did you stumble upon in the historic town?"
Objects identify data with names.
A name to identify a single element of an object is called a property
Objects are ideal to represent a list of dissimilar things that belong to each other.
var paula:Object = {age:37, name:"Paula", hairColor:0x123456};
This often means that the elements of an object are of different type, like in the example above.
But they don't have to:
var car:Object = {manufacturer:"Porsche", color:"red", sound:"wroooooom", soundOfDriver:"weeeeeeeeeeee"};
Considering this, let's take a look at your code and see how it applies.
The big picture is that you have a function addBoxes that you call multiple times. As one function should have one purpose, this function will do something similar every time it is executed. Uh-Oh: "similar". Whatever the result of this function is, it should go into an array. Each call to that function would be an element of the array. You can see this clearly on your use of "num" to identify whatever is happening in your current run of the function.
What data is present in your function?
copyOne
mc1
mc1Text
mc2
mc2Text
copyOne is a troublemaker here and what causes your confusion. It's trying to do everything at once and therefore you are not able to think clearly about when to use a Array and when Object. One would call it a god object. And that's not a good object to have around.
Your choice for variable names is very bad.
You choose super generic names like "mcX" only to later add a name property to it that describes what it truly is.
But even that doesn't hold true for whatever "Box2" is supposed to be.
Choose names so that it'S easy to understand what something in your code is.
It looks like you created all or parts of this structure jsut for this question and therefore lacked meaningful names.
I highly recommend that you do not learn by such made up projects. But from the real world.
I will therefore impose the following goal:
mc1 and mc1Text represent a caption
mc2 and mc2Text represent a content
With all this, I ask again:
What data is present in your function?
captionBox
captionText
contentBox
contentText
Both caption and content consist of a box and a text.
These are different things, so caption and content are each an object with properties "box" and "text"
One could think that due to this similarity, they both should go into an array.
But I beg to differ. A caption and a text are not the same thing. You deal with captions and texts differently. Walking on the streets you might catch a big caption in the news quickly, but not a lengthy text. That's why each of them should be a property of the object that's created in the function.
Here's somewhat of a conclusion:
var allBoxes:Array = []; // array to store the similar results of every function call
function createBoxes():void
{
var boxes:Object = {};
//the box consists of caption & content, both bying of the same type, but are containing different data
boxes.caption = {box:{}, text:{}}; //caption
boxes.content = {box:{}, text:{}}; //content
allBoxes.push(boxes);
}
This is it. That's how and why I would model your data with objects and arrays.
But it doesn't end here. My conclusion lacks a lot of the code you posted.
While the above is mostly language independent, the missing code is specific to Actionscript and not just on how to model data. It's as follows...
As3 is object oriented.
This is good, because the above conclusion has a lot of objects in it.
To define how some object is/does/moves/farts/etc, one creates classes.
The following changes take place (for reasons out of the scope of this answer):
createBoxes (formerly known as addBoxes) calls the constructor of
a class "CaptionAndContent" that extends Sprite.
There's no more need to explicitely create an object "boxes" as the constructor does exactly that.
The caption and content will not have a property "box", because
they can be the box themselves. This is exactly how it's done in the
code of the question. The default settings are set in the constructors of their classes.
Here's reduced snippet of code that hopefully illustrates how the classes could look like.
Each class should be in its own file, with the necessary imports, package block and the additional functionality that you did not specify in your question.
public class CaptionAndContent extends Sprite
{
private var caption:Caption;
private var content:Content;
public function CaptionAndContent(captionText:String = "", contentText:String = "")
{
caption = new Caption(captionText);
addChild(caption);
content = new Content(contentText);
content.y = caption.height;
addChild(content);
}
}
public class ClickableBoxWithText extends Sprite
{
protected var textField:TextField;
public function ClickableBoxWithText(text:String = "")
{
textField = new TextField();
textField.text = text;
addChild(textField);
addEventListener(MouseEvent.CLICK, onClick);
}
protected function onClick(mouseEvent:MouseEvent):void
{
//override this in a sublclass
}
}
public class Caption extends ClickableBoxWithText
{
public function Caption(text:String = "")
{
super(text);
// apply all the default settings of caption here.
}
}
public class Content extends ClickableBoxWithText
{
public function Content(text:String = "")
{
super(text);
// apply all the default settings of content here.
}
}
Using them would look something like this:
var allBoxes:Array = []; // array to store the similar results of every function call
function createBoxes():void
{
var captionAndContent:CaptionAndContent = new CaptionAndContent("This is the caption...", "...for this content");
captionAndContent.x = nextXpos;
addChild(captionAndContent);
allBoxes.push(captionAndContent);
}
Last but not least, the identification problem in the click handler.
Your question already contains the answer:
event.currentTarget
That's the reference to the object that was clicked on.
In my code it would be
mouseEvent.currentTarget
This identifies the object already. It's pointless to look up one of its properties (its name for example) in order to search all the objects for that name, just to identify the same object that you already had to identify (without a name) in order to get the name.
You aren't identifying the objects by name anyway. What differs between the names and what supposedly makes them unique is a number at their end. As pointed out in this answer, this is what's called an index and the thing you are trying to identify with it should go into an array. In my example codes, this is allBoxes.

Call a function if String number is inferior to 0?

I've got this code in my Toolbar.as :
var money = 9999;
argent.text = String(money);
trace(money);
How do I do to say
if (money < 0){
callFunction();
}
?
Thank you very much for your answers
EDIT
I've tried everything.
Here's what I did :
var money:int = 9999;
argent.text = money.toString();
trace(money);
stageRef.addEventListener("checkingMoney", checkMoney, false, 0, true);
I've add the EventListner in order to check the money (as nothing was triggering the condition if money<0 before).
And then :
public function checkMoney(event):void{
var money;
trace("checking");
if (parseInt(money) < 0){
trace("dangerous");
}
}
So the function is well triggered (the trace "checking" is on), but even the number is under 0 (-4600), the trace "dangerous" do NOT appear..
I don't understand.
You need to read up on how datatyping works. It works similarly in all OOP-based languages, so an AS3-specific article really isn't necessary. Avoid anything regarding PHP datatypes, though.
For what you have posted, though, you have done a few things incorrectly.
First off, every object (whether it be a variable, function, or class), should always have the datatype declared. You can get away with not doing it, but your app will run slightly faster if you do and there is less chance of compiler warnings.
So
var money = 9999;
should be
var money:int = 9999; // could also use Number (AS3's float) or uint
You should avoid hard-casts such as String(money), as well. This can be slow and can cause errors. For casting a Number to a String, you should always use Number.toString(), as that is its intended purpose and I believe it is optimized whereas other cast types are not.
if (money < 0) is actually correct. It may have been throwing IDE warnings because you didn't set the type of money. If you need to compare a numeric String value, you need to cast it back to a number using Number(var). Note that casting a String to Number is one of the few times you want to use a hard cast DataType(object) instead of a soft cast (object as DataType).
I don't get the problem.
1st of all money variable is missing a type.
If money is int here than:
var money:int = 9999;
argent.text = money.toString();
trace(money);
if (money < 0){
callFunction();
}
and that should work.
If for some reason money is String in here than:
var money:String = "9999";
argent.text = money;
trace(money);
if (Number(money) < 0){
callFunction();
}
I don't usually do this, but I'm posting a second answer because your edit is drastically different than what you originally posted. For future reference, please post the entire code that is relevant. You seemed to have missed some context originally and forced us to solve the wrong problem (don't get me wrong, it still needed to be fixed but it was not the issue at hand)
So what you are seeing is a scope issue. Basically, an object declared in an object (be it a Class, Function, loop, or conditional) is only available within that object and within child objects. Additionally, all objects declared in the top-level scope of a class must have an access modifier (public, private, internal, protected, etc).
So let's assume this class structure:
public class ClassName {
public function ClassName();
public function checkMoney();
}
An object declared in the constructor (ClassName()) is not available in checkMoney(). So you need to do one of two things:
Declare the object in top-level scope:
public class ClassName {
private var money:int;
public function ClassName(){
money = 9999;
checkMoney()
}
public function checkMoney() {
// you now have access to money
}
}
or pass the object into the function:
public class ClassName {
public function ClassName(){
var money:int = 9999;
checkMoney(money);
}
public function checkMoney(value:Number) {
// check "value" here. Note that Numbers and Strings are NOT passed be reference, so changing the value will NOT change the original variable
}
}

AS3 Call a variable from a compound string

I don't know how to explain this good, I'll do my best :p
I have this code:
public function clickeado(MouseEvent):void{
if(getChildByName("placa") == null){
addChild(info);
}
trace(MouseEvent.target.name)
switch(MouseEvent.target.name){
case "_783":
info.circuito_tf.text = _783_circuito;
info.localidad_tf.text = _783_localidad;
info.responsable_tf.text = _783_responsable;
break;
I want that the text of "info.circuito_tf.text" to be the value of the variable called "_783_circuito". It's ok. Now I have 17 more cases, so I decided to do something like this:
switch(MouseEvent.target.name){
case "_783":
info.circuito_tf.text = MouseEvent.target.name + "_circuito";
info.localidad_tf.text = MouseEvent.target.name + "_localidad";
info.responsable_tf.text = MouseEvent.target.name + "_responsable";
break;
I wish I explained well, thanks!
ps: the value of info.circuito_tf.text in the second case it's "783circuito" instead of the value of the variable
You can address a variable through a string via this syntax:
info.circuito_tf.text = this[MouseEvent.target.name + "_circuito"];
Watch out for undefined values, though.
Yes, with this syntax you don't need the switch statement at all, just make sure your movie clips all have valid names and correct variables exist and are assigned values.