I'm a beginner in Kinect Programming. Yet I read different tutorials and texts about it. Furthermore I was working on the code examples ("Controls Basis-WPF").
Unfortunately none of the sources teach me how to code grabbing and releasing in a way that I understand.
I would like to create dynamically KinectTileButtons. While the program is running the user should be able to place the buttons to the positions he prefers. The player uses his hand as the cursor.
For example:
There is a button b1 on the top left corner.
While the hand of the user is not on b1, the button doesn't change his position.
If the user's hand is on the button AND he makes the "GRAB"-gesture, the position of the button is like the position of his hand (variable position). When he RELEASES, the position of button is constant and will not change until the user is grabbing for the button the next time.
I'm very thankful for any advices, suggestions or code examples, because I really don't know how I should continue to work on this problem.
Thanks in advance
derpate
What you should be going for is to change the location of the buttons on the window. I would have some global bools to signify is they are grabbing and holding. Then I would put a conditional in the update to move the label to the position of the hand. Here's some pseudo-code:
bool grabbing = false;
bool selected = false;
var button;
var handElement;
Start()
{
button = window.Button;
handElement = window.handElement;
...
sensor.Start();
}
Update() //all frames ready
{
using (SkeletonFrame sf = e.OpenSkeletonFrame())
{
... //get skeleton and position
... //tell if grabbing
if (/*however you do the grab gesture*/)
grabbing = true;
if (selected && grabbing)
{
button.X = handElement.X;
button.Y = handElement.Y;
}
}
}
Button_OnClick()//or whatever it is called for the Kinect UI control
{
selected = true;
}
Sorry for the pseudo-code, I just haven't worked with the Kinect UI before, and I didn't want to have half pseudo-code with the elements I don't know, however I know that it has events like OnClick() for when it is held, and I don't know what you mean by "GRAB" gesture but I assume you know how to implement it if you know what it is. Good luck!
Know also this only works for one button. If you were doing this for many, I would suggest a class... something like:
class MoveableButton : KinectButton//again, don't know the exact name of this
{
private int X, Y;
private bool selected = false, grabbing = false;
public void Selected()
{
selected = true;
}
public void Grabbed()
{
grabbing = true;
}
public void LetGo()
{
grabbing = false;
selected = false;
}
public void Update(UIElement hand)
{
if (selected && grabbing)
{
this.X = hand.X;
this.Y = hand.Y;
}
}
}
This you would then call the appropriate methods during certain frames, I would have an array of them to loop through for Update.
Related
Anyone know how i can stop this from flicking basically I'm doing a raycast and if it hits the crafting table it it shows up a text saying press e to craft but it is flickering cause its in the void update function but if anyone knows a work around that would be nice thanks!
if(hit.collider.tag == "CraftingTable")
{
if(textIsOn)
{
noshowcraftingtext();
}
else
{
showcraftingtext();
}
}
void showcraftingtext()
{
textIsOn = true;
pressEToShowCraftingTableUI.SetActive(true);
}
void noshowcraftingtext()
{
textIsOn = false;
pressEToShowCraftingTableUI.SetActive(false);
}
The main problem of your code is that you are trying to change the state after state was changed.
That's why updated isn't the case in a big project, because all such things will lead to unpredictable or logically conflicted behavior, to avoid this you should use Data driven approach instead.
But to fix exactly your issue, you need to have a function, which isn't based on the state of the object, but returns what should happen right now.
There isn't much about what's going on inside your game, but I can guess that you are firing a raycast with mouse and then checking is it craftable or not.
public void Raycaster : MonoBehavior {
public void YourClickMethod()
{
if(hit.collider.tag == "CraftingTable")
{
hit.collider.GetComponent<UserInputReceiver>().SetClicked(this);
}
}
}
And on the object which is receiving your raycast you should add this:
public class UserInputReceiver : MonoBehavior {
private bool _isEnabled = false;
//set this inside inspector
public GameObject ObjectToEnable;
private Raycaster _currentSender = null
public void SetClicked(Raycaster sender){
_isEnabled = !_isEnabled;
_currentSender = sender;
}
public void Update(){
if(_currentSender != null && _isEnabled) {
_isEnabled = Vector3.Distance(transform.position, _currentSender.transform.position) < 1f; //set the threshold based on your unit system
}
//or another object, you can put it inside public field and enable him
//gameObject.SetActive(_isEnabled);
objectToEnable.SetActive(_isEnabled); //here you can pass a reference through inspector for your canvas
}
}
This is how you can outstand this issue with a short way.
This code will set the flag based on the received input and the distance. If you need to keep enabled text forever, than remove distance check than it will enable only with a second click, without distance dependency.
Forewords
Firstly, I know posting graphical resources for codes is not encouraged in this platform. I will also post the code but, in this particular case, I think posting a video about it is much more helpful than just posting some arbitrary code because the structuring of game projects really vary depending on their requirements. However, I still respect the platform's rules so if a mod asks me to format my question according to the community rules, I can do that or they also can simply delete my question. I respect that.
The Issue
It's actually a simple issue but it's driving me crazy because of its simplicity. I just want to fade in when I load a scene and then fade out whenever I click a button. As to how I do that, this is the video about it.
To sum up, I load another scene called "Fader" which contains a ColorRect with a black color and AnimationPlayer to change ColorRect's alpha value.
The code is below with extra comments on relevant parts:
using Godot;
using System;
public class TitleScreen : Control
{
private Button[] buttons;
private Control fader; // the scene that I inject
public override void _Ready() // when title screen gets ready
{
GD.Print("Preparing TitleScreen...");
InitButtons();
InitFader(); // initialize fader
FadeIn(); // do fade in animation
}
private void InitFader() // initializing fader
{
GD.Print("Initializing fader...");
var faderScene = (PackedScene)ResourceLoader.Load("res://components/Fader.tscn"); // load external fader scene
fader = (Control)faderScene.Instance(); // instantiate the scene
fader.SetSize(OS.WindowSize); // set the size of fader scene to the game window, just in case
var rect = (ColorRect)fader.GetNode("rect"); // get "rect" child from fader scene
rect.SetSize(OS.WindowSize); // set "rect" size to the game window as well, just in case
fader.Visible = false; // set the visibility to false
AddChild(fader); // add initialized fader scene as a child of title screen
}
private void InitButtons()
{
GD.Print("Initializing buttons...");
buttons = new Button[3]{
(Button)GetNode("menu_container/leftmenu_container/menu/start_button"),
(Button)GetNode("menu_container/leftmenu_container/menu/continue_button"),
(Button)GetNode("menu_container/leftmenu_container/menu/exit_button"),
};
GD.Print("Adding events to buttons...");
buttons[0].Connect("pressed", this, "_StartGame");
buttons[2].Connect("pressed", this, "_QuitGame");
}
private void FadeIn()
{
GD.Print("Fading in...");
fader.Visible = true; // set visibility of fader to true
var player = (AnimationPlayer)fader.GetNode("player"); // get animation player
player.Play("FadeIn"); // play FadeIn animation
fader.Visible = false; // set visibility of fader to false
}
private void FadeOut()
{
// similar to FadeIn
GD.Print("Fading out...");
fader.Visible = true;
var player = (AnimationPlayer)fader.GetNode("player");
player.Play("FadeOut");
fader.Visible = false;
}
public void _StartGame() // whenever I click start game button
{
FadeOut(); // fade out
GetTree().ChangeScene("res://stages/Demo01.tscn");
}
public void _QuitGame() // whenever I click quit game button
{
FadeOut(); // fade out
GetTree().Quit();
}
}
Seems like I can't see something. Why does it not fade in and out?
Environment
Manjaro 19.0.2
Mono JIT Compiler 6.4.0 (if it is relevant)
Godot 3.2
So, the issue was Play method on AnimationPlayer object kinda runs like async (dunno if this is the correct term for it).
Luckily, there is a feature called signals in Godot. There are animation_started and animation_finished signals on AnimationPlayer objects. Basically, I created a C# script for Fader scene, hooked the signals from player to fader as in:
animation_started to _FaderAnimationStart
animation_finished to _FaderAnimationEnd
At the end, my script looks like below:
using Godot;
using System;
public class Fader : Control
{
private ColorRect rect;
private AnimationPlayer player;
public override void _Ready()
{
GD.Print("Initializing Fader...");
rect = (ColorRect)GetNode("rect");
player = (AnimationPlayer)GetNode("player");
SetSize(OS.WindowSize);
rect.SetSize(OS.WindowSize);
Visible = false;
}
private void _FaderAnimationStart(String anim_name)
{
Visible = true;
}
private void _FaderAnimationEnd(String anim_name)
{
Visible = false;
}
}
I solved it thanks to njamster's answer and Hans Passant's comment.
However, this only solves half of the problem. Yes, the scene now fades in when it loads but it does not fade out. Given that it executes kinda-async (again, I'm not sure if this is the correct term), changing scene interrupts while running the animation. I will update the answer when I solve that problem as well.
Update
Well, I cannot seem to solve the fade out part because it requires to access parent node from initialized child scene. There are some methods I can think of.
First one is to somehow parameterize "Fader" scene. This can be done in many ways but at the end, when you initialize it from another scene, you need to cast it to Fader and I don't know if this is a valid way to do it. Another concern is standardizing this in the codebase. A similar method is discussed in here.
Second one is to write it as a plugin which has it benefits and drawbacks. C# is not really battle-tested in this particular area.
Third one is to use a state management system. Here is a redux implementation for Godot. And you need to somehow integrate it for signals, which seems like a hassle.
So, overall, I still do not know how to fade out.
I'm trying to divide the screen to 2 and use them as 2 different buttons (L,R) in Unity. But for the ones who are playing first time, I want to show the buttons' text and image to teach them what they do, and after that I want to disable buttons' image and text, they will be still interactable but invisible.
First time screen
How can I ?
Way easier and more reliable than what you did would simply be do add something like this to your Button:
using UnityEngine;
using UnityEngine.UI;
[RequireComponent(typeof(Button))]
[DisallowMultipleComponent]
public class HintsController : MonoBehaviour
{
private Image _image;
private Text _text;
private float _originalAlpha;
// optional to control if Hints should be enabled on starting the App
public bool enableAtStart;
private void Awake()
{
// GetComponentInChildren finds the component on this object or any
// child of this object recursively
// (true) : make sure you also find the components if this or the child objects
// are currently disabled
// On this way you don't even have to rely on that the Image is on the
// Button GameObject or below in the hierachy
_image = GetComponentInChildren<Image>(true);
_text = GetComponentInChildren<Text>(true);
if(_image)
{
_originalAlpha = _image.color.a;
}
// optional to controll if Hints should be enabled on starting the App
ShowHints(enableAtStart);
}
public void ShowHints(bool isVisible)
{
// Skip if no Image found
if (_image)
{
var color = _image.color;
color.a = isVisible ? _originalAlpha : 0;
_image.color = color;
}
// Skip if no Text found
if (_text)
{
_text.enabled = isVisible;
}
}
}
Then from any other script, you simply can do e.g.
// TODO somehow get the reference either to the button GameObject or the Button component
var button;
button.GetComponent<HintsController>().ShowHints(false);
To disable hints.
I used button.image.enabled = bool valuefor image component and button.transform.GetChild(0).gameObject.SetActive(bool value) for the text.
i would suggest just making an empty for each button in the scene view, name them left and right. drag you button images(sprites) onte the scene and size them to fill the camera with proper positioning. apply boxCollider2D to both of the parent game objects(the empties you created and named left and right.) then you will need some light scripting.
pseudo-wise i would say:
you will use:
void OnMouseDown(){
//button touched
}
to see if the button is pressed.
when your tutorial is over you will set the image and text invisible with the code you mentioned above or something similar. this script goes on each button.
I'm wanting to have two textures switch when ever I press the space bar in my project. But when I do, nothing is happening.
can anyone see what I'm doing wrong with my logic? I had this working with switching between 2 shaders, but not it is materials, it isn't working. I'm very confused by this.
void Switch()
{
Debug.Log(gameObject.renderer.material.name);
if(Input.GetButtonDown("Jump"))
{
diffuse = false;
//if(gameObject.renderer.material == diffuse_Material)
}
else
{
diffuse = true;
}
if(diffuse == true)
{
gameObject.renderer.material = mask_Material;
print("1");
Debug.Log(gameObject.renderer.material.name);
}
else
{
gameObject.renderer.material = diffuse_Material;
print("2");
Debug.Log(gameObject.renderer.material.name);
}
My codes changes the material once, but doesn't change back again when I press the space bar again.
update
I've taken my code out of the update method and placed it in its own one. I've since modified it to be a "simple" bool check. Now when I play the game my object starts with the material I first want on it, but when I hit space, it only changed the material for a fraction of a second.
How can I do it so that on the press of a single button, my bool toggles between true and false. I thought i had it, but I guess I don't. My debug log now looks like this:
DepthMask (instance)
1
DepthMask (instance)
2
Diffuse (instance)
Diffuce (instance)
DepthMask (instance)
DepthMask (instance)
1
I think the problem is the following:
When the user presses the jump key the boolean gets set to true, the material changes and its all good. BUT then the update method gets called again, and followed by that I'm assuming your Switch method also.
Input.GetButtonDown("Jump") will now evaluate to false, causing your boolean value diffuse to become true again, and the material changes back.
Is the material supposed to toggle everytime the users presses the Jump button? If so, change your code to (the else statement can be completely removed):
void Switch()
{
Debug.Log(gameObject.renderer.material.name);
if(Input.GetButtonDown("Jump"))
{
diffuse = !diffuse;
// material only needs to change if diffuse changed
if(diffuse)
{
gameObject.renderer.material = mask_Material;
print("1");
Debug.Log(gameObject.renderer.material.name);
}
else
{
gameObject.renderer.material = diffuse_Material;
print("2");
Debug.Log(gameObject.renderer.material.name);
}
}
}
EDIT: included the entire Switch method.
You could try to compare
renderer.sharedMaterial
instead of
renderer.material
to get the non-instanced version of the material. Something like this:
public Material a;
public Material b;
void Update ()
{
if (Input.GetButtonDown("Jump"))
{
if (renderer.sharedMaterial == a)
{
gameObject.renderer.material = b;
}
else
{
gameObject.renderer.material = a;
}
}
}
I have been trying to program a way of preventing my character from touching a wall so he couldn't go trough it but I can't find a proper way of doing like you can see in this video (that I recorded). Sorry about the (decent) mic quality : https://youtu.be/jhTSDgSXXa8. Also I said prevent the collision but rather it detects it and stops but you can go through.
The collision code is :
foreach (PictureBox pbMur in pbListeMurs)
{
if (pbCharacterCat.Bounds.IntersectsWith(pbMur.Bounds))
{
if (pbCharacterCat.Right > pbMur.Left)
{
bWalkRight = false;
bIdle = true;
}
}
}
Thank you ! :D
I'm not sure how you are using bIdle and walkRight, but these types of boolean flags are easy to get wrong and it turns your whole code into a complete mess as you typically try to plug holes and end up springing new ones in the process.
First of all, why do you even need them? Wouldn't this be enough?
var newPotentialCharacterBounds =
GetNewBounds(pbCharacterCat.Bounds, movementDirection);
var collidedWalls = pbListeMurs.Where(wall =>
wall.Bounds.IntersectsWith(newPotentialCharacterBounds));
if (!collidedWall.Any())
{
pbCharacterCat.Bounds = newPotentialCharacterBounds
}
//else do nothing
How does this work? Well, the premise is that your character can't start in an invalid position, and if it is never allowed to reach an invalid position then you never need to undo movements or reset positions.
I'd propose you create an enumeration that describes all possible directions:
enum Direction { Up, Down, Left, Right };
When the corresponding direction command is given, get the potential new position of the character (newPotentialCharacterBounds and GetNewBounds). If that position collides with anything, simply do nothing, if it doesn't, move!
UPDATE: Pseudocode follows:
//event handler for move right fires, and calls:
TryMove(pbCharacterCat, Direction.Right)
//event handler for move left fires and calls:
TryMove(pbCharacterCat, Direction.Left)
//etc.
private static Rectangle GetNewBounds(
Rectangle current, Direction direction)
{
switch (direction)
{
case Direction.Right:
{
var newBounds = current;
newBounds.Offset(horizontalDelta, 0);
return newBounds;
}
case Direction.Left:
{
var newBounds = current;
newBounds.Offset(-horizontalDelta, 0);
return newBounds;
}
//etc.
}
//uses System.Linq
private bool TryMove(Control ctrl, Direction direction)
{
var newBounds =
GetNewBounds(ctrl.Bounds, direction);
var collidedWalls = pbListeMurs.Where(wall =>
wall.Bounds.IntersectsWith(newBounds));
if (!collidedWall.Any())
{
ctrl.Bounds = newBounds;
return true;
}
//Can't move in that direction
Debug.Assert(collidedWall.Single); //sanity check
return false;
}
Becuase TryMove returns if the movement was successful or not, now you can leverage that information; different sound effects for instance, etc.