How can I address a script I don't know the type of? - unity3d

My game uses a variety of different game modes, and I'd like to spawn a different GameController script at the beginning of the scene depending on the game mode selected. Then other items (e.g., Enemies), would reference the main GameController, whether that be GameController_Mode1, GameController_Mode2, etc. But how can I have other objects referencing this if I don't know the type?
Unity iOS requires strict unityscript typing, so I can't use duck typing to get around this.

You can do this the same way you'd do it in C#, polymorphism. Derive all of your controllers from a single base Controller class. Then your GameController var can be set to any instantiation of a derived controller (see Start() in the example below).
Here is a quick example using a simple controller:
#pragma strict
var controller : MyController;
class MyController {
var data : int;
public function MyController(){
this.data = 42;
}
public function Print(){
Debug.Log("Controller: " + this.data);
}
}
class MyController1 extends MyController {
public function MyController1(){
this.data = 43;
}
public function Print(){
Debug.Log("Controller1: " + this.data);
}
}
class MyController2 extends MyController {
public function MyController2(){
this.data = 44;
}
public function Print(){
Debug.Log("Controller2: " + this.data);
}
}
function Start () {
controller = new MyController();
controller.Print(); // prints Controller: 42
controller = new MyController1();
controller.Print(); // prints Controller1: 43
controller = new MyController2();
controller.Print(); // prints Controller2: 44
}
I'm making any assumption that your gamecontrollers share function names and that the only difference is the code in each function.
[Update]
Regarding Heisenbug's comment below: You can use GetComponent to get the base class controller if your controller is a component.
Baseclass(BaseController.js):
class BaseController extends MonoBehaviour{
public function Print(){
Debug.Log("BaseController");
}
}
Extended class(Controller1.js):
class Controller1 extends BaseController {
public function Print(){
Debug.Log("Controller1: " + this.data);
}
}
Test:
var controller : BaseController;
controller = gameObject.GetComponent("BaseController"); //.GetComponent(BaseController) also works
controller.Print(); // will print "Controller1" if actual attached component is a Controller1 type

While it looks like there are some good answers already but it is worth mentioning Unity's SendMessage system. It is a really simple approach if all you need to do is call functions on the other object SendMessage.
http://docs.unity3d.com/Documentation/ScriptReference/GameObject.SendMessage.html
In short you can use the following syntax:
TargetGameObject.SendMessage("targetFunction", argument, SendMessageOptions.DontRequireReceiver);
You can also use SendMessage to call javascript functions from C# scripts or vice versa.

Related

libGDX Classes relationship

I am trying Libgdx Game Class to make a game.And I am following a book.There is an example. Example has 4 classes and 1 DesktopLauncher. DesktopLauncher use StarfishCollector3() class to main function. Despite I dont call create method and render method which are in GameBeta abstract class to StarfishCollector3, the project is working.Can you explain what I dont know.
class StarfishCollector3 : GameBeta() {
var turtle:Turtle=null
var starfish:ActorBeta=null
var ocean:ActorBeta=null
var winMessage:ActorBeta=null
var win:Boolean = true
override fun initialize() {
ocean= ActorBeta()
ocean.setTexture(Texture( Gdx.files.internal("water.jpg") ))
mainStage.addActor(ocean)
starfish = ActorBeta();
starfish.setTexture(Texture(Gdx.files.internal("starfish.png")) );
starfish.setPosition( 380F,380F );
mainStage.addActor( starfish );
turtle = Turtle()
turtle.setTexture( Texture(Gdx.files.internal("turtle-1.png")) )
turtle.setPosition( 20F,20F )
mainStage.addActor( turtle )
winMessage = ActorBeta();
winMessage.setTexture( Texture(Gdx.files.internal("you-win.png")) );
winMessage.setPosition( 180F,180F );
winMessage.setVisible( false );
mainStage.addActor( winMessage );
win = false }
override fun update(dt: Float) {
if (turtle.overlaps(starfish as ActorBeta)){
starfish.remove()
winMessage.setVisible(true)} }
}
abstract class GameBeta: Game() {
protected var mainStage: Stage=null
abstract fun initialize()
override fun create() {`
mainStage = Stage()
initialize() }
abstract fun update(dt:Float)
.
override fun render() {
var dt= Gdx.graphics.getDeltaTime()
mainStage.act()
update(dt)
Gdx.gl.glClearColor(0F,0F,0F,1F)
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT)
mainStage.draw()
}
}
The heirarchy of StarfishCollector3 is that it extends GameBeta, which extends Game, which implements ApplicationListener.
In DesktopLauncher you instantiate a StarfishCollector3 and pass it as an implicit ApplicationListener to an Application constructor by calling something like new LwjglApplication(starfishCollectior, config);. When you instantiate that LwjglApplication (or Lwjgl3Application or AndroidApplication, etc. depending on backend), the constructor of that Application class sets up the game engine. It creates all the classes for managing OpenGL and drawing the game in a repeating loop, pausing and resuming, etc.
So the Application class is using your StarfishCollector3 as an ApplicationListener and calling its relevant lifecycle methods at the appropriate times.

Flutter, Dart. Create anonymous class

Maybe it's really dumb question. But I cannot believe there is no resources, where it's described. Even from the official documentation. What I'm trying to do, it's create Anonymous class for the next function.
How to create Anonymous class in Dart with custom function something like next in Kotlin?
Handler(Looper.getMainLooper()).post(Runnable() {
#override
open fun run() {
//...
}
private fun local() {
//....
}
})
Dart does not support creating an anonymous class.
What you're trying to do is not possible.
On the other hand, you can create anonymous functions. So you could use that to mimic an anonymous class.
The idea is to add a constructor of your abstract class, that defer its implementation to callbacks.
abstract class Event {
void run();
}
class _AnonymousEvent implements Event {
_AnonymousEvent({void run()}): _run = run;
final void Function() _run;
#override
void run() => _run();
}
Event createAnonymousEvent() {
return _AnonymousEvent(
run: () => print('run'),
);
}
It's not strictly the same as an anonymous class and is closer to the decorator pattern. But it should cover most use-cases.
This is an alternative way, but not fully equivalent:
Problem, e.g.:
I would like to implement OnChildClickListener inline in my code without class. For this method:
void setOnChildClickListener(OnChildClickListener listener) {
...
}
Instead of this:
abstract class OnChildClickListener {
bool onChildClick(int groupPosition, int childPosition);
}
use this:
typedef OnChildClickListener = Function(int groupPosition, int childPosition);
And in code you can implement it in this way:
listView.setOnChildClickListener((int groupPosition, int childPosition) {
// your code here
});
In other words do not use abstract class, but use typedef.

String Constructor not working in unity c#

Salutations, this'll be brief.
So, I tried to change the name of one the hero struct in my game, but it doesn't update, neither in the inspector nor in the de facto code.
I can call the constructor just fine, and if I print the heroname before and after (in the constructor), it tells me the new name. However, It does not change.
Here is the (simplified) code:
//This already has a name in the inspector that I want to override
public List<TroopStat> PlayerHeroStats = new List<TroopStat>();
void Start () {
PlayerHeroStats[0].ChangeTroopType();
}
[System.Serializable]
public struct TroopStat {
public string nameOfTroop;
public void ChangeTroopType() {
nameOfTroop = "Blabla";
}
}
Any ideas?
Structs are value types. You need to assign a new struct or use class instead.
This should work:
void Start () {
TroopStat stat = PlayerHeroStats[0];
stat.ChangeTroopType();
PlayerHeroStats[0] = stat;
}
Or make the TroopStat a class.
You can read more about it here.

How to use addChild() w/o extension from another class?

Is it possible to use addChild() without 'extends' from another Class ?
It's strange, that i need to extension from another classes to use it ... but maybe its my lack of knowledge in as3 ...
Main:
public class Main extends Sprite
{
private var sprite:Sprite = new Sprite();
public function Main()
{
if (stage) init();
else addEventListener(Event.ADDED_TO_STAGE, init);
}
private function init(e:Event = null):void
{
removeEventListener(Event.ADDED_TO_STAGE, init);
// entry point
var myVar:MyClass = new Myclass();
addChild(myVar);
}
}
MyClass:
public class MyClass
{
private var sprite:Sprite = new Sprite();
public function MyClass()
{
sprite.graphics.lineStyle(1, 0x990000, 1);
sprite.graphics.drawRoundRect(5, 5, 500, 150, 10, 10);
addChild(sprite);
}
}
addChild is method that add's DisplayObject to DisplayObjectContainer, so yes, you must extend your custom classes if you want to see it on screen
futher reading: http://help.adobe.com/en_US/as3/dev/WS5b3ccc516d4fbf351e63e3d118a9b90204-7e3e.html
http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/flash/display/DisplayObjectContainer.html
I looks like you're trying to do this:
public class MyClass
{
private var sprite:Sprite;
public function MyClass(container:MovieClip)
// ^^^^^^^^^ Take a reference to a container to add children to.
{
sprite = new Sprite()
sprite.graphics.lineStyle(1, 0x990000, 1);
sprite.graphics.drawRoundRect(5, 5, 500, 150, 10, 10);
container.addChild(sprite);
// ^^^^^^ Add internal sprite to the referenced container.
}
}
Where you provide a container to add children to.
Meaning your Main class will simply pass a reference to itself to your MyClass instance.
private function init(e:Event = null):void
{
removeEventListener(Event.ADDED_TO_STAGE, init);
var myVar:MyClass = new MyClass(this);
// ^^^^ Simply pass the main class as the container.
}
Another option is to simply expose sprite from MyClass and then use:
addChild(myVar.sprite);
In your Main class.
The simple answer to your question is: no, a custom class cannot addChild without extending a subclass of DisplayObjectContainer. The method addChild() and its related methods are defined in DisplayObjectContainer and only subclasses of it can use them.
You often see the method addChild() used without a calling object (ex: theobject.addChild()) but that's only because the keyword "this" is implied. In reality addChild() is always called by a DisplayObjectContainer instance.

is it possible to put Class in a variable and access the class's static variables and functions in actionscript3?

Say I had the following class
public class Scene{
public static var title="new scene";
public function Scene(){}
public static function start() { trace("scene started"); }
}
How can you access the Scene class's static variables and functions like this?
var i:Class = Scene;
trace(i.title);
i.start();
I'm trying to figure out how variables assigned with Class work in actionscript.
Any tips would be welcome. Thanks.
Static methods are called from the class:
trace(Scene.title);
Scene.start();
Singleton patterns enable constructor, local reference, and potentially abstraction through interface classes.
Example of Scene as a singleton:
package
{
public class Scene
{
private static var instance:Scene = new Scene();
public static function getInstance():Scene
{
return instance;
}
public var title:String = "new scene";
public function Scene()
{
if (instance)
throw new Error("Scene is a singleton and can only be accessed through Scene.getInstance()");
}
public function start():void
{
trace("scene started.");
}
}
}
Your example implementation would now be:
var i:Scene = Scene.getInstance();
trace(i.title);
i.start();
This is how you can access the dynamic class (Scene) & it's properties / methods :
var myDynamicClasses:Array = [Scene]; // Required
var i:Class = Class(getDefinitionByName("Scene"));
trace(i.title);
i.start.call();
This could throw an error, if the first line is not included. Because, when the compiler notices the class Scene (not the one from adobe's package) is not being used it ignores it. Thus it would be not available for dynamic initialization.
We could force the compiler to include these classes by putting these class names in variables or declare an array as above as a quick hack.
If you have many dynamic classes, you could add a reference to them in this array & each class will be included by the compiler for dynamic initialization.
var i:Class = Scene;
trace(i.title);
Should throw an error because the compiler can no longer assume that i is a scene when it gets to line 2. If you were to coerce the Class object, it should work.
var i:Class = Scene;
trace((Scene(Class).title);