How to get node of which keyframe was added? - godot

I have a custom Animation node like this:
Custom_AnimationPlayer:
tool
extends AnimationPlayer
func add_animation(name : String, animation: Animation):
var ani = Custom_Animation.new()
.add_animation(name, ani)
Custom_Animation:
tool
extends Animation
class_name Custom_Animation
var local_node=self.get_local_scene()
func track_insert_key(track_idx : int, time : float, key, transition : float = 1) -> void:
var key_idx=track_find_key(track_idx,time,true)
.track_insert_key(track_idx, time, key, transition)
var track_path=track_get_path(track_idx)
var key_node=local_node.get_node(track_path)
# use key_node
I'm trying to get the node of which the key was added (key_node) but this only works if the AnimationPlayer's Root Node is the top most node
so is there any reliable way to get the node of which the keyframe was added?

Related

mapbox.getCenter in wrong format for my variable?

I have a page with a mapbox map, and I want the map to remember a saved position when reloading the page. Apparently the string format from getCenter is not the correct lng/lat format that I can use to center map. How do I get it in the right format?
I use map.getZoom and map.getCenter to save some variables into local.storage
First I set the variables, and a starting position if no value is set:
var mzoom = localStorage.getItem("mzoomKey");
if(mzoom == null){
var mzoom = 13;
}
var posi = localStorage.getItem("posiKey");
if(posi == null){
var posi = [9.84861, 55.86128];
}
and then these variables is used for zoom and center of the mapbox map:
center: posi, // starting position [lng, lat]
zoom: mzoom, // starting zoom
and then I set the local.storage variables when the user clicks a button:
var mzoom = map.getZoom();
localStorage.setItem("mzoomKey", mzoom);
var posi = map.getCenter();
localStorage.setItem("posiKey", posi);
console.log(posi);
The zoom Part works - but the center part dosent.
the Console log writes:
ko {lng: 9.84861, lat: 55.86128}
lng_lat.js:151 Uncaught Error: `LngLatLike` argument must be specified as a LngLat instance, an object {lng: <lng>, lat: <lat>}, an object {lon: <lng>, lat: <lat>}, or an array of [<lng>, <lat>]
at ko.convert (lng_lat.js:151:15)
at Map.jumpTo (camera.js:1005:32)
at new Map (map.js:575:18)
at map_V2.html:61:13
How do I get the center position in the right format?

GDScript modularization

Is it possible to modularize in GDScript?
What I have in mind is that I have a player class with variable input, of type IInput, like this:
Player.gd:
extends KinematicBody
var input = load("res://Scripts/Inputs/PlayerInput.gd").new()
func _physics_process(delta):
if input.is_down("left_trigger"): speed = sprintSpeed
else: speed = runSpeed
Where "res://Scripts/Inputs/PlayerInput.gd" would look like this
extends "res://Scripts/Inputs/IInput.gd"
class_name PlayerInput
var controlTranslatinos = {"left_stick_up" : "move_up",
"left_stick_down" : "move_down",
"left_stick_left" : "move_left",
"left_stick_right" : "move_right",
"right_stick_up" : "rotate_up",
"right_stick_down" : "rotate_down",
"right_stick_left" : "rotate_left",
"right_stick_right" : "rotate_right",
"x" : "attack",
"left_trigger" : "defend",
"a" : "jump",
"right_trigger" : "sprint"}
func pressure(controlName):
var translatedControl = controlTranslatinos[controlName]
var preasure = Input.get_action_strength(translatedControl)
return preasure
func is_down(controlName):
return Input.is_action_pressed(controlTranslatinos[controlName])
and where "res://Scripts/Inputs/IInput.gd" would look like this:
extends Node
class_name IInput
const controls = [ "move_up", "move_down", "move_left", "move_right",
"rotate_up", "rotate_down", "rotate_left", "rotate_right",
"attack", "defend", "jump", "sprint" ]
func pressure(controlName):
return 0
func is_down(controlName):
return false
Goal is to change actor's input to AIInput class and back to PlayerInput on demand. This would also be good for other stuff.
Is it possible to implement this in some other way?
Error at `PlayerInput.gd`
There's an error at first line of PlayerInput, saying:
`Script not fully loaded (cyclic preload?): "res://Scripts/Inputs/IInput.gd"
I get what cyclic preload would mean, but I don't get how cyclic loading is happening at this instance. Can you explain how/why this is happening? How can I overcome it?
If this error wouldn't show up I think the modularization would work (the way I imagine it works).

UISlider with buffering progress - AVPlayer

I'm using AVPlayer to stream audio from a server and what I want to do now is to show a custom UISlider who shows the progress of the buffering.
Anyone come up with this? Please give me solution.
Now player load whole duration in once and show in UISlider.
you need to use preferredforwardbufferduration
This property defines the preferred forward buffer duration in seconds. If set to 0, the player will choose an appropriate level of buffering for most use cases. Setting this property to a low value will increase the chance that playback will stall and re-buffer, while setting it to a high value will increase demand on system resources.
also check here for detailed example of how to use : Is it possible to pause and resume buffering of AVPlayer?
inside your player you need to observe time range using below function
override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?)
like this:
let timeRanges = change![NSKeyValueChangeKey.newKey] as? NSArray
if timeRanges != nil && timeRanges!.count != 0 {
DispatchQueue.main.async {
let cmTimeRange = (timeRanges![0] as AnyObject).timeRangeValue as CMTimeRange
self.playerView.timeSlider.bufferValue = Float(CMTimeGetSeconds(cmTimeRange.start) + CMTimeGetSeconds(cmTimeRange.duration))
}
}
I have a custom slider with a variable I defined as bufferValue you can override func draw(_ rect: CGRect)inside your slider and apply changes while buffer is progressing.
I get draw to call anytime bufferValue changes by calling self.setNeedsDisplay()inside didSet
#IBInspectable var bufferValue : Float = 0 {
didSet {
if(bufferValue < 0 ) {
bufferValue = 0
} else if (bufferValue > maximumValue) {
bufferValue = maximumValue
}
self.setNeedsDisplay()
}
}

Haxe for loop only uses last item

After some hours doing some testing I figured out that my map contains the correct values, but the loop that I am using only seems to be using the last added value in this map. Am I missing something obvious here?
The function that adds items to the map: (controls is the map variable)
public static function CreateThumbstick(mActorType:ActorType, mLocation:Int, mDirectionLock:Int)
{
var controllerName = "Thumbstick"+mLocation;
if(!controls.exists(controllerName)){
createRecycledActor(mActorType, 0, 0, Script.FRONT);
var lastActor = getLastCreatedActor();
var myPosition = GetPosition(controllerName, lastActor);
lastActor.setX(myPosition.x);
lastActor.setY(myPosition.y);
var myPos = new Vector2(lastActor.getXCenter(), lastActor.getYCenter());
var controlUnit = new ControlUnit(lastActor, myPos, -1);
controls.set(controllerName, controlUnit);
trace("added key: " + controllerName +" with value: "+ lastActor);
} else {
trace("!!WARNING!! Control unit already exists in this position. Command ignored!");
}
}
Upon creating 3 thumbsticks, the log states the following:
added key: Thumbstick1 with value: [Actor 1,Thumbstick]
added key: Thumbstick2 with value: [Actor 2,Thumbstick]
added key: Thumbstick3 with value: [Actor 3,Thumbstick]
When the screen is touched, it should loop through each item in my map, but it is using the last added item 3 times to check the distance with, rather then all 3 items once. Here is the Listener that is being called when the screen is touched:
addMultiTouchStartListener(function(event:TouchEvent, list:Array<Dynamic>):Void
{
for (unit in controls){
trace(lastDebugLine + "checking distance to " + unit.GetActor());
if(GetDistance(unit.GetCenter(), touch.GetPosition()) < 64){
break;
}
}
});
// used "touch.GetPosition()" instead of actuall code for easy reading. This is not causing any problems!
Upon touching the screen, the log states the following:
checking distance to [Actor 3,Thumbstick]
checking distance to [Actor 3,Thumbstick]
checking distance to [Actor 3,Thumbstick]
I am quite new to the Haxe language, so my guess is that I am missing something obvious, even after I have followed the Haxe API very closely. This is the example used from the Haxe API page:
var map4 = ["M"=>"Monday", "T"=>"Tuesday"];
for (value in map4) {
trace(value); // Monday \n Tuesday
}
All explanations are welcome!
Added ControlUnit class:
import com.stencyl.models.Actor;
class ControlUnit
{
static var actor;
static var center;
static var touchID;
public function new(mActor:Actor, mPosition:Vector2, mTouchID:Int)
{
actor = mActor;
center = mPosition;
touchID = mTouchID;
}
public function GetActor():Actor{
return(actor);
}
public function GetCenter():Vector2{
return(center);
}
public function GetTouchID():Int{
return(touchID);
}
}
You just used static for vars in class definitions - they aren't instance aware/based.
Check 'properties', getters, setters etc. in https://haxe.org/manual/class-field-property.html
Are you sure that getLastCreatedActor() is returning a separate instance each time? If it's returning the same instance each time you will likely see what you're getting.
Isn't that because all of your keys map to the same value? Try mapping them to different values and test it.

Create an audio source and assign a clip in Unity

Folks I'm having trouble creating an audio source and assigning it a clip in Unity.
I'm streaming a file and the debugger tells me it's found the file and it's ready to play using the following code.
#script RequireComponent(AudioSource)
var www : WWW;
var audioSource: AudioSource = gameObject.AddComponent<AudioSource>();
var myAudioClip: AudioClip;
function Start ()
{
www = new WWW ("file://" + Application.dataPath.Substring (0, Application.dataPath.LastIndexOf ("/")) + "/Assets/intro.wav");
myAudioClip = www.audioClip;
Debug.Log(myAudioClip.isReadyToPlay);
}
However the debugger gives me errors in my audioSource declaration.
Unexpected Token: )
expecting ), found ';'
'; expected, insert a semicolon at the end.
This error points at the line
var audioSource: AudioSource = gameObject.AddComponent();
Ultimately my aim is to then assign the clip to the audioSource and let rip!
You already have declared that a component of AudioSource is needed;
#script RequireComponent(AudioSource)
So no need to add it as a component. I don't normally use UnityScript but here's the code you want;
#script RequireComponent(AudioSource)
var www : WWW;
var audioSource : AudioSource;
var myAudioClip : AudioClip;
function Start () {
audioSource = GetComponent(AudioSource);
StartCoroutine( LoadAudio( "file://" + Application.dataPath.Substring (0, Application.dataPath.LastIndexOf ("/")) + "/Assets/intro.wav" ) );
}
function LoadAudio( path : String ) {
www = new WWW ( path );
yield www;
myAudioClip = www.audioClip;
Debug.Log(myAudioClip.isReadyToPlay);
}
To use the WWW class you can use coroutines to wait until it's done loading the asset you require. Or you can keep checking whether www.isDone is true.
Documentation; http://docs.unity3d.com/ScriptReference/Coroutine.html

Resources