Openhab rules issue - xbmc

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.

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?

Pause/Resume Action/Animation on Sprite in Cocos2d

Using Cocos2d-x and C++, I'm trying to play and pause an animation for a sprite.
I'm using version 3.15.1 of Cocos2dx.
I have a class called PlayerSprite which is derrived from the cocos2d::Sprite class. Inside PlayerSprite initialization, I've setup my animation with the following code:
SpriteBatchNode* playerSpriteBatch = SpriteBatchNode::create("player.png");
SpriteFrameCache* spriteFrameCache = SpriteFrameCache::getInstance();
spriteFrameCache->addSpriteFramesWithFile("player.plist");
Vector<SpriteFrame*> animFrames(2);
char str[18] = { 0 };
for (int i = 1; i < 3; i++) {
sprintf(str, "player_idle_%d.png", i);
SpriteFrame* frame = spriteFrameCache->getSpriteFrameByName(str);
animFrames.pushBack(frame);
}
Animation* idleAnim = Animation::createWithSpriteFrames(animFrames, 0.8f);
self->idleAction = self->runAction(RepeatForever::create(Animate::create(idleAnim)));
self->idleAction->setTag(0);
When I run the code, it works fine and the animation loops correctly.
In my void update() method, I am trying to pause/play the action/animation based of weather the player is moving or idle.
I do this with the following code:
const bool isIdleActionRunning = this->getNumberOfRunningActionsByTag(0) > 0 ? true : false;
const bool isMoving = !vel.isZero();
if (!isMoving && !isIdleActionRunning) {
// Player is idle AND animation is not running
// Run animation
this->runAction(idleAction);
} else if (isMoving && isIdleActionRunning) {
// Player is moving but animation is running
// Pause animation
this->stopActionByTag(0);
}
When I run this code now, my character falls, and as soon as he hits the gound, I get an error at this->runAction(idleAction); saying:
Access violation reading location 0xDDDDDDE5
I believe this is caused due to this->stopActionByTag(0) deleting the action pointer. I've tried to clone the action to avoid this but have had no success.
I know this is a bit late and you might already have solved this but here goes...
Your problem is that you cannot use one instance of Action (idleAction) multiple times. So, once you have run it and removed it, it is released and cannot be used. So, you have 2 options now,
Either create a new idleAction Action every time before running the action.
Or, have an idleAction retained and don't run it ever. Instead, create a clone of this idleAction and run a new clone each time. i.e.
idleAction->retain();
const bool isIdleActionRunning = this->getNumberOfRunningActionsByTag(0) > 0 ? true : false;
const bool isMoving = !vel.isZero();
if (!isMoving && !isIdleActionRunning) {
// Player is idle AND animation is not running
// Run animation
Action idleActionClone = idleAction->clone();
this->runAction(idleActionClone);
} else if (isMoving && isIdleActionRunning) {
// Player is moving but animation is running
// Pause animation
this->stopActionByTag(0);
}
Solution: call retain() to keep your action.
It's a matter of memory management of cocos2d-x.
In create() function of your RepeatForever class (derived from Ref), the reference count is set to 1 and there is a line of code ret->autorelease() before returning the object, which means this object will be released automatically at the end of this frame.
You called runAction() function the same frame you created it, the action is retained by ActionManager, it's reference count set to 2, and then 1 at the end of the frame (autorelease).
After your stopping it, it's released by ActionManager, reference count set to 0 and it's deleted. After this you use your action, it will be an access violation method.
*Edit: don't forget to release the action manually when PlayerSprite is deleted, or it's a leak.
When you stop action it's being recycled from memory. In order to play action once more, you have to recreate it. So you may just make a creator function, which returns your animation. The downside is you're recreating animation each time and it'll also play from the beginning (technically you can rewind it).
But I've developed a simpler technique to pause/resume animations:
Let's say you have an action:
action = MoveBy::create(5.0f, Vec2(50, 100));
Now, you can embed this action into Speed action like this:
action = Speed::create(MoveBy::create(5.0f, Vec2(50, 100)), 1.0f);
1.0f - is speed, so it's normal action rate. Now to pause just call:
action->setSpeed(0.0f);
and to resume:
action->setSpeed(1.0f);
you can also use different speed if you need it for some reason or another ;)

How to check if sprites are hit in special order

I have 3 0f 8 sprites on screen that I would like the reader to hit in order:
touching the egges first, then the sugar and finally the lemon (if done correctly a gold cup appears)
EggsSprite
SugarSprite
LemonSprite
the functions I have work but i would like to know if there an easier way to maintain and extend to other sprites onscreen (I have 8 sprites and hope to produce different "recipies")
ccTouchesBegan I detect touches on the sprites
if(CGRectContainsPoint(EggsSprite.boundingBox, location))
{
EggsSprite_is_hit = YES;
NSLog(#"EggsSprite_is_hit = YES");
}
if(CGRectContainsPoint(SugarSprite.boundingBox, location))
{
SugarSprite_is_hit = YES;
NSLog(#"RunCheckSugar");
[self CheckSugar];
}
if(CGRectContainsPoint(LemonSprite.boundingBox, location))
{
NSLog(#"RunCheckLemon");
LemonSprite_is_hit = YES;
[self CheckLemon];
}
this runs
-(void)CheckLemon
{
NSLog(#"LemonSprite is hit");
if(MeringueUnlocked == YES)
{
NSLog(#"You made a merangue");
Award.opacity=255;
}
else if(MeringueUnlocked == NO)
{
NSLog(#"Incorrect order");
EggsSprite_is_hit = NO;
LemonSprite_is_hit = NO;
SugarSprite_is_hit = NO;
MeringueUnlocked = NO;
}
}
-(void)CheckSugar
{
if(SugarSprite_is_hit == YES && EggsSprite_is_hit== YES)
{
NSLog(#"SugarSprite is hit");
NSLog(#"And Egg Sprite is hit");
SugarSprite_is_hit = NO;
MeringueUnlocked = YES;
}
else if(SugarSprite_is_hit == YES && EggsSprite_is_hit== YES)
{
NSLog(#"SugarSprite not hit ressetting all");
EggsSprite_is_hit = NO;
LemonSprite_is_hit = NO;
SugarSprite_is_hit = NO;
MeringueUnlocked = NO;
}
}
It seems to work ok, but it would be horrible to extend, I cant seem to find any examples on touching sprites in order so any psudo code ideas will be welcome :) as its the approach that Im more stuck on since I'm new to coding.
with thanks :)
N
When your sprites are created, assign to their 'tag' properties order in which they should be hit:
EggsSprite.tag = 1;
SugarSprite.tag = 2;
LemonSprite.tag = 3;
Then make an instance variable to store index of last sprite hit:
int _lastSpriteHitIndex;
and for index of last sprite in your sequence:
int _finalSpriteIndex;
Set its value somewhere in init (or whatever method you use to create your layer):
_finalSpriteIndex = 3;
Then in your touch handler:
// find sprite which was touched
// compare its tag with tag of last touched sprite
if (_lastSpriteHitIndex == touchedSprite.tag - 1)
{
// if it is next sprite in our planned order of sprites,
// store its tag as _lastSpriteHitIndex
_lastSpriteHitIndex = touchedSprite.tag;
}
else
{
// if it's wrong sprite, reset sequence
_lastSpriteHitIndex = 0;
}
if (_lastSpriteHitIndex == _finalSpriteIndex)
{
// Congrats! You hit sprites in correct order!
}
Basically it's a finite-state machine in which hitting sprites in correct order advances machine to next state, and hitting wrong sprite resets machine to initial state. _lastSpriteHitIndex repesents current state, _finalSpriteIndex represents final state.
If you don't want to reset to initial state on wrong sprite hit, just remove else clause - without it machine will simply not advance when hitting wrong sprite.

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.

How to stop a character from going out of the screen?

i'm making this game where a ninja is supposed to go up and down. I wrote a method for a button to do so but the problem is that when the ninja is at the top of the screen (landscape)
it still goes up when i touch the up button so, i did this
-(void)upPressed:(id)sender
{
if(CGPointEqualToPoint(ninja.position, ccp(0,280)))
{
id standStill = [CCMoveBy actionWithDuration:0 position:ccp(0,0)];
[ninja runAction:standStill];
}else
{
id moveUp = [CCMoveBy actionWithDuration:.1 position:ccp(0,80)];
[ninja runAction:moveUp];
}
}
and the problem still exists. any help?
i.e when the ninja is at (0,280), i want the up button to do nothing
You are testing for equality. This if condition will only be true if the ninja is exactly at {0, 200}.
Try this instead:
if (ninja.position.y < 280)
{
// no need to run an action for this
ninja.position = CGPointZero;
// but you should stop any potentially running (move) action
[ninja stopAllActions];
}
else ...