AS3: creating a class with multiple and optional parameters? - class

I'm creating a slideshow where each slide can have:
- a video or a still
- 1 audio track or many (up to 3)
- 1 button or many (up to 3)
I was thinking that each slide can be it's own object, and then I would pass the video, audio, buttons, etc., into it as parameters:
package
{
import flash.media.Video;
public class Section
{
public function Section (video:Video, still:myPhotoClass, audiotrack:Sound, button:myButtonClass) {
// can have video OR a still
// can have 1 audio track or several
// can have 1 button or more
}
}
I'm not sure how to go about approaching this since there can be multiples of certain items (audio, buttons) and also two items are sort-of-optional in the sense that there can be ONE or the OTHER (video/still).
For example, is this something that I should just avoid passing as parameters altogether, using a different approach (getters/setters, maybe)?

Try "...(rest) parameter"
private var _optionalParam:Array;
public function exOptionalParam(arg1:Number, ...optionalParam) {
_optionalParam = optionalParam;
trace(_optionalParam ); // [all the additional arguments]
}

Let's see how this goes:
You can add all of your parameters and set them to null so they aren't needed, eg: video:Video = null, still:myPhotoClass = null, audiotrack1:Sound = null, audiotrack2:Sound, audiotrack3:null, button1... etc (Simple test worked)
Or just pass an array for the ones with multiple items, or a vector of the right type.

Related

#Unity3D - Attach an object to another using a face of the last object as a target and deleting the last one detected

Let's say that I have three simple box-like objects and I want to make different compositions by adding to the first object, already present in the scene, another one and then the other in whatever order i want by pressing a specific key on the keyboard (let's say W key for the Object 2 and S key for the Object 3).
For example:
After that I would like to delete the last present object every time I want by pressing Q key.
For example, I press W,W,S,W,S (Obj2, Obj2, Obj3, Obj2, Obj3).
After, I press Q three times (obtaining the composition Obj2, Obj2 because i destroyed the last three with Q).
And after that I press W one time (obtaining Obj2, Obj2, Obj2).
The modular part is made by a script put in an Empty GameObject(which is inside the Objects 1, 2 and 3.
public class Placement : MonoBehaviour
{
public GameObject shape1, shape2, shape3;
public Counter count;
void Start()
{
count = FindObjectOfType<Counter>();
}
void Update()
{
if (Input.GetKeyDown(KeyCode.W))
{
count.Array[count.i] = Instantiate(shape3, transform.position, transform.rotation);
this.enabled = false;
}
if (Input.GetKeyDown(KeyCode.S))
{
count.Array[count.i] = Instantiate(shape2, transform.position, transform.rotation);
this.enabled = false;
}
if (Input.GetKeyDown(KeyCode.Alpha6))
{
Destroy(count.Array[count.i]);
count.i = count.i - 1;
}
}
Then I used a counter and a GameObject array to "save" each clone put in the scene in another generic script always present in the scene.
public class Counter : MonoBehaviour
{
public int i = 0;
public GameObject[] Array = new GameObject[50];
public void Update()
{
if (Input.GetKeyDown(KeyCode.W))
{
i = i + 1;
}
if (Input.GetKeyDown(KeyCode.S))
{
i = i + 1;
}
}
}
The problems are:
The first script is "reloaded" each time because it's inside every instantiated object I put in the scene, so I have to use an external single script where I save every counter and/or GameObject reference I need;
If I remove this.enabled = false; from every Instantiate process the script partially works but it creates too many clones of the same object(because it's using every Empty GameObject in the scene as reference to where to put the clones and not just the last one present);
By creating too many clones(even if I press W/S one single time), if I try to destroy the last one, it will destroy many others and if I try to put others after the destroying process, it will clone the object in every position available and not the last one.
I'm starting to lose my mind in a dumb process.... :')
Use one empty game object as ObjectSpawnManager to manage your object spawn/despawn behaviour, put the first script to this object, so that you don't need put the same script on multiple instances.
Remove the Update part of Counter script, add public UpdateCounter method, and call it from ObjectSpawnManager script when the corresponding key down.
Since you have stated a few problems and no specific questions, I am going to propose to you an approach that should work and implement what you ask for. If you want clarification on a specific question, feel free to ask.
As you have stated yourself, it makes more sense to have a single script manage the whole process of placing objects. Attach this script, let's call it SpawnManagerScript to an empty GameObject e.g. SpawnManager in the scene.
I would also suggest you to use a List instead of an array if you are not sure how many objects will be there at some point in time. If you do want to limit the number of objects to 50 (looking at your code), an array is totally fine.
Assuming you were able to figure out the correct positioning of the objects upon spawning already, I won't go into detail regarding that.
If I understood you correctly, what's left to do now is the following:
Spawning GameObject:
Differentiate the user input (e.g. S & W) in your SpawnManagerScript. For each type of object you could have a public field in your SpawnManagerScript class which references e.g. a Prefab or template GameObject in the scene. You can use the template object for cloning on user input. Add this clone to the List or array of objects and position it correctly.
Deleting GameObject:
Again, detect your desired input key for deletion in the script. Grab the last element in the List or the last added element in the array from the respective container. Destroy it or set it to inactive. Remove the entry from the container.

Add or remove item in datagrid does not trigger WhenAnyPropertyChanged

I am using dynamic data with reactiveui,
` _propList.Connect()
.WhenAnyPropertyChanged()
.Subscribe(t =>
{
}`
the code will be trigger if I just edit any item in the grid. However, when I try to add or remove an item, it is not triggered.
In my view model I have something like this
private SourceList<Decision> _myList { get; set; } = new SourceList<Decision>();
private readonly IObservableCollection<Decision> _targetCollection = new ObservableCollectionExtended<Decision>();
public IObservableCollection<Decision> TargetCollection => _targetCollection;
in my view, I simply
this.OneWayBind(VM, vm => vm.TargetCollection, v => v.DataGrid1.DataSource);
If I remove or Add item in the grid, and press Save
_myList.Count() didn't change, but
_TargetCollection.Count() will increase or decrease by number of items I delete
In my ViewModel
OKCmd = ReactiveCommand.Create(() =>
{
//// _myList.Connect()
////.Subscribe(t =>
//// {
//// ;
//// }
//// );
t.Items.count() and it is the initial load items, but I couldn't seem to know what items have been added or removed. Am I missing something.
Of course, I can keep track of what items are added or removed in the UI, but I am hoping I don't have to do that.
Thanks.
To help me answer your question, I need to better understand what you are trying to achieve but first I will explain what the default behaviour of DD is.
If you want add / remove events you need _propList.Connect().Subscribe(changes => ...). These are the collection changes and you will receive all collection change events including the initial load, but no inline changes.
By default, no property changes are wire in. This is because to monitor property changes is expensive and is opt in only. Also WhenAnyPropertyChanged() never tiggers for the initial load. This is because the item is already loaded and no properties have changed between Connect being called and the property changed observable being subscribed to.
Following on from 2, you will never receive a property changed when an item is removed from the underlying source. This is because when an item it removed, any inline subscriptions are disposed of. Otherwise there would be memory leaks.
Another option for monitoring inline changes is to make use of 'MergeMany' which allows you to craft any observable on a specific item, and in your case you can create an observable to return the initial value as well as as subsequent changes.
It is possible using standard rx to listen to collection changes and inline changes in a single observable, which you would have to compose yourself. For example
var myCollectionChanges = _propList.Connect();
var myPropertyChanges = _propList.Connect().WhenAnyPropertyChanged();
var allMyChanges = myCollectionChanges.Select(_ => Unit.Default)
.Merge(myPropertyChanges.Select(_ => Unit.Default));
In the this example, I have used Select(_ => Unit.Default) to enable the merge operator as it requires the same signature. However what signature is returned is up to you, the key point being that the signatures must match.

Specman: Is there a way to access different variables by some index?

in my verification environment I have 3 different registers with the same fields: load_0, load_1 and load_2.
Now I have the same function duplicated 3 times for every register and differs only in one line:
duplicated_func_0() {
value = timer_regs.load_0; //This is the only different line (in duplicated_func_1 - load_1 is substituted
...
};
Is there a better way to access variable name (that differs only by its index) than duplicate the same function 3 times?
Something like this:
not_duplicated_func(index : uint) {
value = timer_regs.load_%x; //Is there a way to put the input index in the variable name instead of %x?
};
I will appreciate any help you can provide.
Inside timer_regs I wouldn't define 3 variables, load_0, load_1 and load_2, but a list of the respective type:
extend TIMER_REGS vr_ad_reg_file {
loads[3] : list of TIMER_LOAD vr_ad_reg;
};
This way you can access each register by index.
If you can't change the layout you already have, just constrain each list item to be equal to your existing instances:
extend TIMER_REGS vr_ad_reg_file {
loads[3] : list of TIMER_LOAD vr_ad_reg;
keep loads[0] == load_0;
keep loads[1] == load_1;
keep loads[2] == load_2;
};

Display all enums from an EMF model in a CheckBoxTable ?

I am trying to display a CheckBoxTable in an Eclipse page which enables the user to select any one of a number of items - the items that are available come from an EMF model and are enums.
I've got the content provider and the label provider set up correctly (I think) but I can't figure what to use to set the input in order to display the full list of enums.
So say my model has an enum called MyEnum which has values of ONE, TWO and THREE - I want to be able to display all three of those enums to the user as check boxes.
I need to call setInput(...) on the viewer but what do I pass into it to get those enums?
Although I've never done it for a CheckboxTableViewer, I have set an EEnum as the source of values for other StructuredViewer classes like ComboViewer. What I did was create a custom IStructuredContentProvider that is a subclass of ArrayList and takes the EEnum as a constructor argument (call this class EEnumContentProvider). In the constructor, I iterate over the EEnum's getELiterals() and call add() on each of their getInstance() values. Like this:
public EEnumContentProvider(EEnum source) {
List<EEnumLiteral> literals = source.getELiterals();
for (EEnumLiteral aLiteral : literals) {
add(aLiteral.getInstance());
}
}
You can easily implement IStructuredContentProvider.getElements(Object) by using returning the result of toArray() and you don't care about IContentProvider.setInput() because the contents aren't based on the input, they're static.
Then you can set an instance of EEnumContentProvider as the content provider for the viewer.
Simply you need to get the literals and add them to the control as follows:
/* Populate the Combo Box with the Literals */
EEnum cFEnum = Package.Literals.LITERAL_ENUMERATION;
/*
* Add an EMPTY item value so that the user can disable the specific
* feature
*/
this.cmbNames.add( EMPTY_STRING );
/*
* Add the Enumeration Literals to the
* appropriate SWT Combo widget.
*/
for (int i=0; i<cFEnum.getELiterals().size(); i++){
this.cmbNames.add( cFEnum.getEEnumLiteral( i ).toString() );
}
cFEnum = null;
String[] sortedTypes = this.cmbNames.getItems();
Arrays.sort( sortedTypes );
this.cmbNames.setItems( sortedTypes );

MVC Areas and routing

I'd like to have an area called "Products", where I can use routes such as
http://localhost/products/foo
http://localhost/products/bar
I would like to have the views and other assets organized into a folder structure like
/areas/products/views/foo/index.aspx
/areas/products/views/bar/index.aspx
I'd like to keep images, etc specifically related to each product (foo, bar) in their respective /area/products/views/(foo|bar)/ folder.
I also do not want to have to add a controller action for each product.
If I declare a route like
context.MapRoute(
"products-show-product"
, "Products/{id}"
, new { controller = "Products", action = "Index", id=UrlParameter.Optional }
);
and request the url
http://localhost/products/foo
then ProductsController.Index() is called, as I would expect. However, since the view "foo" is not in the views/products or views/shared folder, it isn't being found.
How can I do this so that I can keep each product's pages in a separate folder?
I don't have a concrete answer to your question since I am not sure about my understanding of it. However I have a general feeling for the direction for the solution.
When one starts to change locations of views, the corresponding methods that find those views also need to change. A simple approach would be to override the FindView and FindPartialView methods.
A simple demo. I created an Area called Blog, a Blog controller with an Index method. In my case I user the controller action as the SubFolder but I am sure that this can be extended to your case for each product folder. I assume that the product will be a request argument. Area http://www.freeimagehosting.net/uploads/85b5306402.gif
The basic idea is to interrogate the controllercontext for the controller, area, action and id and modify the what the default viewengine looks for. The default locations for area views looks like "~/Areas/{2}/Views/{1}/{0}.aspx", so we can basically inject values for the view name and in this case ActionName/Index. The view location will end up being ~/Area/Blog/Views/Blog/Index/Index.aspx.
This is just a rough outline, of the code that can be used. The string comparisons can definitely be updated to more robust methods. As it stands this method will work for the entire app as expected, except for the case when a request is made to the Blog area for the Index action.
public override ViewEngineResult FindView(ControllerContext controllerContext, string viewName, string masterName, bool useCache)
{
if (controllerContext.RouteData.DataTokens ["Area"] == "Blog" )
{
if (String.Compare(controllerContext.RouteData.Values ["Action"].ToString(),"Index",true) == 0)
{
var viewLocation = String.Format("{0}/{1}", controllerContext.RouteData.Values["Action"].ToString(), viewName);
return base.FindView(controllerContext, viewLocation , masterName, useCache);
}
}
return base.FindView(controllerContext, viewName, masterName, useCache);
}