SwiftUI adding delay to view from inside function call - swiftui

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?

Related

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?

Openhab rules issue

I was wondering if anyone can help to figure out why my openhab rule does not identify the change in state of my xbmc player when playing a movie.
The openhab server correctly identifies the change in state
But my rules do not trigger:
rules:
val Functions$Function1 dimLiving = [ int dimlevel |
//var boolean scene = (Scene_Living.state == 11);
// Only dim lights when a certain scene is selected
//if(scene) {
// sendCommand(Lamp_Living_Small, dimlevel)
//s sendCommand(Lamp_Living_Floor, dimlevel)
sendCommand(Lounge_Light_Dimm, dimlevel)
// }
]
rule "Lights on when paused"
when
Item htpc_state changed from Play to Pause
then
brightnessBeforePause = Lounge_Light_Dimm.state as DecimalType
if ( brightnessBeforePause < 50){
logInfo("Light", "Play to pause 2")
dimLiving.apply(50)
}
end
rule "Lights off when pause end"
when
Item htpc_state changed from Pause to Play
then
if (Lounge_Light_Dimm.state == 50){
logInfo("Light", "Pause to play 1")
dimLiving.apply(brightnessBeforePause)
}
end
I want to diim the Philips hue lights when the movie starts to play.
Everything is configured ok in the openhab.cfg
Did you define brightnessBeforePause? First line (after the imports, be sure to include those) should be
var Number brightnessBeforePause
And what is Lounge_Light_Dimm set to? If it's Undefined or Uninitialized both rules won't work. Try setting the lamp to a certain dim level before testing these rules.

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

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.

How to detect touch except the falling bodies from top in cocos2d-x ios game using c++

In my game there are certain zombies coming from top of the screen.I have stored all zombies sprites in an CCArray.Then using foreach loop I am making them falling down.
I just want to perform combo.It means that whenever I kill a zombie on tap, the combo_counter increases.
On killing two consecutive zombies the combo_counter goes to 2 but if I tap at any other location on the screen the combo_counter should go to 0.
So my problem is how to detect whether I have not tapped a zombie and tapped anyother place on the screen.I am attaching my code also of cctouchbegan method
zombies is a CCArray where all zombie sprites are stored
void Level1::ccTouchesBegan(cocos2d::CCSet *pTouch, cocos2d::CCEvent *pEvent)
{
CCTouch* touch = (CCTouch*)(pTouch->anyObject());
CCPoint location = touch->getLocationInView();
location = CCDirector::sharedDirector()->convertToGL(location);
CCObject* touchedzombie;
CCARRAY_FOREACH(zombies, touchedzombie)
{
if(!((CCSprite*) touchedzombie)->isVisible())
continue;
//
if(((CCSprite*)touchedzombie)==zombies->objectAtIndex(0))
{
// if((CCSprite*(touchedzombie)==zombies-))
if(touchedzombie!=NULL&&((CCSprite*)touchedzombie)->boundingBox().containsPoint(location))
{
this->setScoreonGame();
combo_counter++;
CCString *comboString=CCString::createWithFormat("comboX %d",combo_counter);
zombies_left--;
CCLOG("left = %d",zombies_left);
CCSize tt=((CCSprite*)touchedzombie)->getContentSize();
CCPoint pos_of_sprite=((CCSprite*)touchedzombie)->getPosition();
int rand_die1=Level1::random1();
CCString *str = CCString::createWithFormat("z2%d.png", rand_die1);
changedSprite = CCSprite::create(str->getCString());
CCLOG("Inside index 0");
((CCSprite*)touchedzombie)->setVisible(false);
changedSprite->setPositionX(pos_of_sprite.x);
changedSprite->setPositionY(pos_of_sprite.y);
changedSprite->setScaleX(Utils::getScaleX());
changedSprite->setScaleY(Utils::getScaleY());
this->addChild(changedSprite);
combo=CCLabelTTF::create(comboString->getCString(), "HoboStd", 50);
combo->setColor(ccRED);
combo->setPosition((ccp(changedSprite->getContentSize().width*0.50,changedSprite->getContentSize().height*1.05)));
changedSprite->addChild(combo,40);
this->runAction(CCSequence::create(delayAction,
callSelectorAction,
NULL));
this->removeChild( ((CCSprite*)touchedzombie),true);
this->Level1::reloadZombies();
// touchedzombie=NULL;
}
}
if(((CCSprite*)touchedzombie)==zombies->objectAtIndex(3))
{
// if((CCSprite*(touchedzombie)==zombies-))
if(touchedzombie!=NULL&&((CCSprite*)touchedzombie)->boundingBox().containsPoint(location))
{
// iftouched++;
this->setScoreonGame();
combo_counter++;
CCString *comboString=CCString::createWithFormat("comboX %d",combo_counter);
zombies_left--;
CCLOG("left = %d",zombies_left);
CCSize tt=((CCSprite*)touchedzombie)->getContentSize();
CCPoint pos_of_sprite=((CCSprite*)touchedzombie)->getPosition();
int rand_die1=Level1::random1();
CCString *str = CCString::createWithFormat("z2%d.png", rand_die1);
changedSprite3 = CCSprite::create(str->getCString());
// CCLOG("%s",str->getCString());
// CCLOG("Sprite Toucheddd");
CCLOG("Inside index 4");
// CCLog("width= %f height =%f",tt.width,tt.height);
// CCLog("x location =%f y location =%f",location.x,location.y);
// CCLog("Positon of Sprite X=%f Y=%f",pos_of_sprite.x,pos_of_sprite.y);
((CCSprite*)touchedzombie)->setVisible(false);
changedSprite3->setPositionX(pos_of_sprite.x);
changedSprite3->setPositionY(pos_of_sprite.y);
changedSprite3->setScaleX(Utils::getScaleX());
changedSprite3->setScaleY(Utils::getScaleY());
this->addChild(changedSprite3);
combo=CCLabelTTF::create(comboString->getCString(), "HoboStd", 50);
combo->setColor(ccRED);
combo->setPosition((ccp(changedSprite3->getContentSize().width*0.50,changedSprite3->getContentSize().height*1.05)));
changedSprite3->addChild(combo,40);
this->runAction(CCSequence::create(delayAction,
callSelectorAction3,
NULL));
this->removeChild( ((CCSprite*)touchedzombie),true);
this->Level1::reloadZombies();
touchedzombie=NULL;
}
//..upto 9 indexes...
}
}
First of all, it is not neccesary to do this checks : if(((CCSprite*)touchedzombie)==zombies->objectAtIndex(0))
How CCARRAY_FOREACH works, is it takes each object from the provided CCArray and assigns it to your touchedZombie variable - this means that if there are 10 elements in the array, this code will be run 10 times (exactly!). This means that with the first run, you will fall into the first if check (the one with objectAtIndex(0), with the second it will fall into the if check with objectAtIndex(1). Removing this if's not will not only speed up your function, but also tidy it up.
This would save you a lot of space, plus if you wanted to change something you would only have to do it in one place, which is safer.
Ok, to the problem at hand :
I see two solutions to this :
Leaving your code : you should move the combo code from the if blocks, and replace it with a flag. This flag should be set to false at the beginning of ccToucheBegan, and if you you detect a touch on a zombie, set it to true. Then after the CCARRAY_FOREACH block, this flag will tell you if there was a tap on a zombie or not. Change your combo accordingly.
Changing your code : You could also make the zombies CCMenuItemImages - this way they would have a different callback function than the rest of the screen. So whenever the ccTouchBegan method would be fired, you will know that it wasn't a zombie that was touched.
I hope everything is clear, if not - let me know.

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