Casting a scene to the type of the attached script or instancing with passing a parameter in Godot - scene

onready var _boardView_scene = load("res://UrBoardView.tscn") gets the scene reference.
Then I try to instance the scene like this _urBoardViewInstance = _boardView_scene.instance(). The UrBoardView scene has a script of type BoardView like this to its topmost node(meaning the scene is of type BoardView)-
extends Node
class_name BoardView
The _urBoardViewInstance get instanced as a Node here. Casting it to BoardView is not working(giving null) here - var boardViewCast = _urBoardViewInstance as BoardView
I need to call a custom init method from BoardView script before sending it to add_child(_urBoardViewInstance).
Basically, I want to instance the scene not as a node but as the type of script that it has attached.(or just call like this
_urBoardViewInstance = _boardView_scene.instance().new(board)
which apparently is not possible in Godot right now.)
And that casting is not working.
This is the how I am casting -
var boardViewCast: BoardView
_urBoardViewInstance = _boardView_scene.instance()
boardViewCast = _urBoardViewInstance as BoardView
boardViewCast.init(gameplay.Board)
the boardViewCast is null after this. It basically does not cast at all.

so in the script I was trying to set a variable by getting node from the scene. onready var board: UrBoard = $UrBoard like this. Deleting the variable fixed the issue(actually not setting the var from getNode. Kept the variable).Dont know why that would cause the issue. Cause the scene was ok being instance as a node. and it ok was being added to child. The script did not have any errors. it was running fine in its own scene.

Related

Invalid set index 'texture' (on base: 'null instance')

Invalid set index 'texture' (on base: 'null instance') with value of type 'StreamTexture'.
extends Panel
var ItemClass = preload("res://Item.tscn")
var item = "res://Blue Jeans.png"
func _ready():
if randi() % 2 == 0:
item = ItemClass.instance()
add_child(item)
extends TextureRect
func _ready():
if randi() % 2 == 0:
$TextureRect.texture = load("res://Blue Jeans.png")
else:
$TextureRect.texture = load("res://Brown Boots.png")
I followed the exact tutorial on YT https://www.youtube.com/watch?v=FHYb63ppHmk
but it seems to debug differently.
This line:
$TextureRect.texture = load("res://Blue Jeans.png")`
Loads a png as a StreamTexture using load, and tries to set it to the texture property of whatever $TextureRect is.
But the error says that there is no texture property on a null instance. Thus, the problem is that $TextureRect is a null instance.
So what does the expression $TextureRect do? It is equivalent to get_node("TextureRect"). In other words it is trying to get a child node called "TextureRect". And it is getting null…
Does the node on which the script is attached have a child node called "TextureRect"? You didn't share how the scene tree looks like, but I suspect it does not.
The script you shared says extends TextureRect, thus the script would be attached to a TextureRect. However, that is not what they do in the tutorial. In the tutorial the script is attached to a Node2D that has the TextureRect as child. You can see that at 4:10 on the tutorial video.
If you want to set the texture of the node on which the script is attached, set texture directly:
texture = load("res://Blue Jeans.png")`
Or if you rather be explicit, use self:
self.texture = load("res://Blue Jeans.png")`
On the other hand, if you are trying to follow the tutorial, then put the script on a node that has the TextureRect as a child (called "TextureRect"), and there $TextureRect would work.

SceneKit: cannot add SCNReferenceNode programmatically though works in Xcode Scene Editor

Adding a SCNReferenceNode works when done from the Xcode Scene Editor. When done programmatically with the code below, however, nothing appears in the scene.
filePath contains a valid path as proven by the print statement as well as stepping through the code.
Help?
if let filePath = NSBundle.mainBundle().pathForResource("RefTest", ofType: "scn", inDirectory: "TestScene.scnassets") {
let referenceURL = NSURL(fileURLWithPath: filePath)
if #available(iOS 9.0, *) {
let referenceNode = SCNReferenceNode(URL: referenceURL)
scene!.rootNode.addChildNode(referenceNode!)
print(referenceNode)
}
}
The class docs claim that the loading policy instructs the SCNReferenceNode to load immediately by default:
When the reference node loads its content (either automatically,
according to the loadingPolicy property, or when you call the load
method), SceneKit loads the referenced scene file. All children of the
scene file’s root node become children of the reference node.
However, this doesn't seem to happen by default. You must invoke the load function like so:
let referenceNode = SCNReferenceNode(URL: referenceURL
referenceNode.load()
Alternatively, perhaps you could play with the loadingPolicy property as well, but invoking the load function definitely works.

Why are the init methods inherited from a class not 'suggested?

I have just started to shift from Obj-C to Swift in Xcode.
I think I understand how the init() methods work now, but for some strange reason, convenience methods do not appear on the list of suggestions which I get when pressing esc.
For example, let's say I've created a class:
class GameScene: SKScene {...}
When I am trying to write the line:
let scene = SKScene(size: ...)
It is suggested when I type let scene = SKScene(s, but when I try to write the line:
let scene = GameScene(size: ...)
It isn't suggested when I type let scene = GameScene(s. Why is this? I don't experience this problem in Obj-C.

How the elements of scene.children in threeJS can be accessed?

I added some objects to ThreeJS scene (using scene.add(object)). I know the name of object and just want to fetch index of it from scene.children.
I tried to use scene.children.indexOf("objectName") but it returns -1 index. Can anybody suggest what can I do?
Thanks
var object = scene.getObjectByName( "objectName" );
or to recursively search the scene graph
var object = scene.getObjectByName( "objectName", true );
Alternatively, you can search by ID.
var id = scene.getObjectById( 4, true );
three.js r.60
I believe that something that can actually can answer your question is the following code that I use to clean the scene:
while (scene.children.length > 0) {
scene.remove(scene.children[scene.children.length - 1]);
}
this way I don't need to access an element by its name or id. The object are simply fetched from the array with an index, so it's like scene.children[i].
You got an alert text as undefined because you're getting back an object not a value/text. You would need to alert something like scene.getObjectByName( "objectName" ).name or scene.getObjectByName( "objectName" ).id i believe.
The relevant docs: getObjectById, getObjectByName. An important note from getObjectByName:
Note that for most objects the name is an empty string by default. You will have to set it manually to make use of this method.
This could be why you were getting undefined. Also, if you are getting undefined, trying to access .name or .id is going to throw an error. If you were getting an object back you would see something like "[object Object]" in the alert.
Another important note I learned the hard way is that the value you need to pass to getObjectById is object.id, and not object.uuid. Also, object.id is essentially just the index of the object in the children array.
Putting it all together:
// var object = new THREE.Mesh(...) or similar
object.name = 'objectName';
scene.add(object);
var retrievedObject = scene.getObjectById(object.id);
// or
var retrievedObject = scene.getObjectByName('objectName');
alert(retrievedObject.name);

ActionScript 2 loadClip depth

When I use:
loader = new MovieClipLoader();
_root.createEmptyMovieClip("level1",getNextHighestDepth());
_root.level1.createEmptyMovieClip("image",getNextHighestDepth());
loader.loadClip("http://someimage.jpg",_root.level1.image);
...it works and the image shows up.
But when I use:
loader = new MovieClipLoader();
_root.createEmptyMovieClip("level1",getNextHighestDepth());
_root.level1.createEmptyMovieClip("level2",getNextHighestDepth());
_root.level1.level2.createEmptyMovieClip("image",getNextHighestDepth());
loader.loadClip("http://someimage.jpg",_root.level1.level2.image);
...the image doesn't show up. Can anyone tell me why? How can I make this work?
the depth you are supplying is going to be '1'. is that what you are expecting?
each movie clip has it's own set of depths, so the nextHighestDepth() of the newly create 'image' mc, will be 1. it should not prevent loading the image though.
As gthmb says, you should call getNextHighestDepth() on the same MovieClip as you do the createEmptyMovieClip() on. So your code example should be more like:
loader = new MovieClipLoader();
_root.createEmptyMovieClip("level1",_root.getNextHighestDepth());
_root.level1.createEmptyMovieClip("level2",_root.level1.getNextHighestDepth());
_root.level1.level2.createEmptyMovieClip("image",_root.level1.level2.getNextHighestDepth());
loader.loadClip("http://someimage.jpg",_root.level1.level2.image);
Also, I would recommend storing references to the created MovieClips, so you won't have to use the full path in each occurrence in the code, something in the lines of this:
loader = new MovieClipLoader();
var level1:MovieClip = _root.createEmptyMovieClip("level1",_root.getNextHighestDepth());
var level2:MovieClip = level1.createEmptyMovieClip("level2",level1.getNextHighestDepth());
var image:MovieClip = level2.createEmptyMovieClip("image",level2.getNextHighestDepth());
loader.loadClip("http://someimage.jpg",image);

Resources