How to detect whether a player drops below a certain Y level - bukkit

I'm trying to write bukkit plugin and one of the features I would like to add is when a player drops to Y level 8 or lower it runs a command on that player. My current case is I'd like to teleport them to other coordinates if they drop to Y level 8 or lower.
Is there a lite way of doing this without have a command run on every "move" event getting each players location then getting their y position then checking if it's less than 9? cause that seems like it would be a lot of work on the server if there are many people moving around.

There is a simpler way to do this without using runnables. Simply use a PlayerMoveEvent.
#EventHandler
public void onMove(PlayerMoveEvent event) {
if (event.getPlayer().getLocation().getY() <= 8) {
event.getPlayer().teleport(event.getPlayer().getLocation().add(0, 100, 0));
}
}

You could always use the SyncRepeatingTask. Then loop through all online players and check if their Y coordinate value is less than 9:
plugin.getServer().getScheduler().scheduleSyncRepeatingTask(plugin, new Runnable() {
public void run() {
for (Player player: Bukkit.getOnlinePlayers()) { // Loops through all online players
if (player.getLocation().getY() < 9) {
// The player's Y is below 9. Do whatever you want here. For example:
player.teleport(player.getLocation().add(0, 100, 0)); // Teleports the player 100 blocks above where they are
}
}
}
}, 50L, 50L); // Run every 2.5 seconds (50 ticks)
Just make sure to put the above code in your onEnable(), or a method that's called when your plugin is enabled.
If you want to change the repeat time dynamically based on the online players, you could use:
public void runTeleportTask() {
long time = Math.round(Bukkit.getServer().getOnlinePlayers().length / 10) + 10;
/*
Tweak the delay however you like, above we get the online players, and divide it by 10 then
add ten. We're adding 10 because you don't want to end up with a task that runs every
tick in this case... The fastest it would be needed would be every 10 ticks.
So if there were 100 players online, it would get 100/10 = 10, 10+10 = 20 = 1 second,
and if there were 250 players online, it would get 250/10 = 25, 25 + 10 = 35 = 1.75 seconds
*/
plugin.getServer().getScheduler().scheduleSyncDelayedTask(plugin, new Runnable() {
public void run() {
for (Player player : Bukkit.getOnlinePlayers()) {
if (player.getLocation().getY() < 9) {
player.teleport(player.getLocation().add(0, 100, 0));
}
}
runTeleportTask();
}
}, time);
}
Then all you have to do is invoke runTeleportTask() in your onEnable() method.

Related

SwiftUI adding delay to view from inside function call

I am trying to code a blackjack deal button where the cards are dealt like so on hitting the button:
Deal face-up card to a player, delay 1 second
Deal face down card to a dealer, delay 1 second
Deal face-up card to a player, delay 1 second
Deal face-up card to a dealer, delay 1 second
My struggle is getting the delays in between each dealt card to make it seem more realistic as opposed to all 4 cards just appearing upon hitting the button. I currently have a deal function defined as so that is called when the deal button is hit:
for dealRound in 1...2{
var dealCard = deck.last
deck.removeLast()
Timer.scheduledTimer(withTimeInterval: 1, repeats: false){ (_) in
player1.hand.append(dealCard!)
}
//player1.hand.append(dealCard!)
switch dealCard!.rank {
case 1:
player1.cardScore += 1
player1.hasAce = true
case 11,12,13:
player1.cardScore += 10
default:
player1.cardScore += dealCard!.rank
}
dealCard = deck.last
deck.removeLast()
Timer.scheduledTimer(withTimeInterval: 1, repeats: false){ (_) in
dealer.hand.append(dealCard!)
}
//If dealRound == 2, dealing upcard to dealer so include that in score
//Otherwise the down card is not included in the score until after the downcard is revealed
if dealRound == 2{
switch dealCard!.rank {
case 1:
dealer.cardScore += 1
dealer.hasAce = true
case 11,12,13:
dealer.cardScore += 10
default:
dealer.cardScore += dealCard!.rank
}
}
}
isDealt = true
}
However, when I hit the deal button, there is a delay and then all 4 cards appear at once. The images for the cards are defined as:
Image(dealer.hand[1].suit.rawValue + String(dealer.hand[1].rank) ).resizable().frame(width:120, height:160).offset(x: 40, y: -40)
I use dealer.hand[0] and player.hand[0] and [1] to show the other cards. The player and dealer are State variables of a Player class. I have tried using DispatchQueue.main.asyncAfter and sleep(1) but have run into similar problems. The only thing I can think to do would be to create 4 separate state Boolean variables and have them set to true after a delay (in a separate function from the deal) so the cards will appear. However, this seems like a poor way of doing it and I feel as though there may be a way similar to what I am trying but can't figure out.
In short: how would I go about adding a delay to an image appearing where the image is dependent on a #State class's array being appended to in a function call?

Updating image UI with unity

I was trying to make a program that updated the amount of hearts the player has every turn (full, half and empty hearts). When I was doing this I instantiated a gameobject of that prefab as a variable and then assigned it to my UI panel in unity. However (I'm not sure but I think that) the variables used in the update just before are still being referenced after being destroyed in the next loop giving me the error:
MissingReferenceException: The object of type 'GameObject' has been destroyed but you are still trying to access it.
Here is the update loop:
void Update()
{
if (HP <= 0)
{
anim.SetBool("Death", true);
Destroy(GameObject.Find("Hearts"));
Destroy(GameObject.Find("Inventory"));
text.alignment = TextAnchor.LowerCenter;
text.text = "\n YOU DIED";
text.fontSize = 150;
text.color = new Color(255, 0, 0);
} else {
foreach (Transform child in GameObject.Find("Hearts").transform)
{
Destroy(child.gameObject);
}
for (var i = 0; i<(int)HP; i++)
{
GameObject Heart = Instantiate(heart, new Vector3(0, 0, 0), Quaternion.identity) as GameObject;
Heart.transform.SetParent(GameObject.Find("Hearts").transform);
}
if (HP - (float)((int)HP) == 0.5F) {
GameObject HalfHeart = Instantiate(halfheart, new Vector3(0, 0, 0), Quaternion.identity) as GameObject;
HalfHeart.transform.SetParent(GameObject.Find("Hearts").transform);
}
for (var i =0; i<Mathf.Floor(MaxHP-HP); i++)
{
GameObject EmptyHeart = Instantiate(emptyheart, new Vector3(0, 0, 0), Quaternion.identity) as GameObject;
EmptyHeart.transform.SetParent(GameObject.Find("Hearts").transform);
}
}
Is there a way to instantiate a prefab without making a variable?, or a way to make the variable reference temporary so it only lasts one update?
Thank you for your help in advance!
The problem is that once HP goes below zero, every subsequent update will enter the first if-statement and try to delete the "Hearts" and "Inventory" objects over and over. You can solve this by adding a bool called isDead and change the statement to if (HP <= 0 && !isDead) and then set isDead = true inside the block. This will prevent it from entering it twice.
Frankly though, your way of solving things is entirely backwards. As others have pointed out, deleting and instantiating objects every frame is very inefficient, and Transform.Find is also slow. You don't really need to destroy anything at all - you can rather just have a list of hearts and enable/disable an appropriate amount whenever the HP changes. You can have a single half-heart at the end of the list and enable/disable it when appropriate - if you are using a HorizontalLayoutGroup, it will still align correctly. You might want to make it so that you can only change the HP using a property or function (something like ModifyHealth(float amount)), and put the logic for updating the hearts display in there.

How do I create a 2 task for same function using Qt?

I'm playing around with Qt. I am using one ultrasonic sensor, If I start the toy it works fine.
Currently, What am I doing? For example, I have programmed a toy, I will start the toy then it will start walking continuously, If someone is in front of the ultrasonic sensor, then it will sense that and will stop walking. (This is working fine). This is what I have created.
Toystart Thread:
bool Toystart::Limit()
{
if(Dist <= 55)
{
return true;
}
return false;
}
main Thread:
int sensor = 0;
if (toystart->Limit() )
{
if(sensor == 0)
{
toystart->Stop_talking();
delay (5000);
sensor = 1;
break;
}
}
What do I want exactly?
The above-mentioned code working fine, I want to create a more function. For example some person in front of doll that stops talking 5 seconds then it will check again the still Obst there it will stop talking. It needs to check again after 5 seconds if still Obst there It will go to new function there it will say please leave me then after 5 seconds if Obst not there it will walk.
But it is a blocking call. Your function is stuck for 5 seconds, and depending on how delay() is implemented it might make your whole app unresponsive to any other calls and events.
Pseudocode:
if (obstacle is near) {
if (last_operation == "wait") {
last_operation = "Action";
takeAction();
} else {
last_operation = "wait";
wait();
}
} else { // no obstacle
last_operation = "go";
go();
}
Is that what you're looking after?

How to schedule or call a method at random time interval in cocos2d iphone

I want to call a method at Irregular time interval means it should be random time plus i want it in some define range too.
Like : it should call at any second between 3 to 8 .
I tried this one :
[NSTimer scheduledTimerWithInterval: 1.0 target:self selector:#selector(myMethod:) userInfo:nil repeats: YES];
void mymethod()
{
if(arc4random() % 10 == 1)
{
// calling my method here;
}
}
This way , i am not getting randomization which i want.
Any one can please help me on this !!!
Here you can make a scheduler which will get called at random interval.
-(void)randomTimeScheduler{
int time = arc4random()%5;
int nextTimeOfCall = 3+time;
NSLog("it will be called after:%d",nextTimeOfCall);
[self performSelector:#selector(randomTimeScheduler) withObject:self afterDelay:nextTimeOfCall];
}
You have to call it from your class and then it will work as a scheduler. And it has finite interval time 3-8.

Invoke a method only once from a class

I have a shape class in which there is a method (hitTest(int,int)) that continuously checks if the mouse is inside its bounds or not. In another method, I keep on checking if the mouse has stayed there for more than 1 sec.
If it has, trigger a function (by notification/event) that runs animation
It it has not, then don't trigger the animation
If it has already triggered the animation and the animation is running but the mouse leaves the area during this, trigger an interrupt function (by notification/event)
//OnLoad _initHover = false;
void update() //called continously in the application per frame
{
if(hitTest(getMouseX(), getMouseY())){
if(!_initHover){
_initHover = true;
_hoverStartTime = getCurrentTime(); //start hover time
cout<<"Start hist test\n";
}
//If it has hovered over the video for 1.0 sec
if((ofGetElapsedTimef() - _hoverStartTime) > 1.0){
cout<<"Hitting continously for 1 sec\n";
notificationCenter->postNotification(new AnimationStartNotification);
}
}
else{
_initHover = false;
notificationCenter->postNotification(new AnimationInterruptNotification);
}
}
The above code runs fine but there's a logical issue I am facing while trying to use. There are multiple instances of the above Shape class and each class consequently has their update() method as well. The mouse cursor has which has animationStarthandler and animationStophandlers is a single class in the whole application.
Issue 1: So, even when one of the shape just notifies the animationStarthandler to fire, the other shape classes on which hit test is false set the animation to interrupt and the animation does not run.
Issue 2: When the hit test succeeds and the cursor has been in the area for more than 1 sec, the hit test will keep on sending the notification to start the animation (anim's duration 1.5 sec approx.) How do I restrict the hit test to fire the animation only once and keep on firing the same animation again and again?
If in the main method of my application, I directly try to fire the animation by calling the method playAnimation in the pointer class, I get the required result. But I want to give this hover timing and animation functionality to the ShapeClass itself. Any suggestions?
I think that you should consider adding a new boolean, which holds the information of the triggering of the animation (called in the code sample _animationTriggered). This prevents shapes that have not triggered the animation to stop it and the animation that triggered it to make it several times.
if(hitTest(getMouseX(), getMouseY()))
{
if(!_initHover)
{
_initHover = true;
_hoverStartTime = getCurrentTime();
cout<<"Start hist test\n";
}
if((ofGetElapsedTimef() - _hoverStartTime) > 1.0)
{
if (!_animationTriggered)
{
cout<<"Hitting continously for 1 sec\n";
notificationCenter->postNotification(new AnimationStartNotification);
_animationTriggered = true;
}
}
}
else
{
if ( _animationTriggered )
{
_initHover = false;
notificationCenter->postNotification(new AnimationInterruptNotification);
_animationTriggered = false;
}
}
Don't forget to initialie this new boolean in the same place as _initHover