I need to create repeatable sequence of actions (CCMoveBy, CCMoveTo), but they need to use random params (position, duration). I wrote 2 methods:
-(void) randomizeVec
and
-(void) calcTiltDuration
In fact, those params depends on external variable (factor). I can't do something like that:
id randomize = [CCCallFuncN actionWithTarget:self selector:#selector(randomizeVec)];
id calcTilt = [CCCallFuncN actionWithTarget:self selector:#selector(calcTiltDuration)];
CCMoveBy* tilt = [CCMoveBy actionWithDuration:mTIltDuration position:randomVec];
CCMoveTo* restore = [CCMoveTo actionWithDuration:mTIltDuration position:initialTowerNodePos];
CCDelayTime* wait = [CCDelayTime actionWithDuration:0.1];
CCSequence* seq = [CCSequence actions:wait,calcTilt,randomize, tilt, restore, nil];
[aNode runAction:[CCRepeatForever actionWithAction:seq]];
because values are copied once and randomizeVec and calcTiltDuration don't affect actions, so I wrote a method:
-(void) moveRandomVector:(CCNode*) node
{
int dx = rand_between(-1, 2) * mShakeFactor *2 ;
int dy = rand_between(-1, 2) * mShakeFactor *2;
CCMoveBy* action = [CCMoveBy actionWithDuration:0.1/mShakeFactor position:CGPointMake(dx, dy)];
CCMoveTo* action2 = [CCMoveTo actionWithDuration:0.1/mShakeFactor position:initialTowerNodePos];
CCEaseInOut* easyTilt = [CCEaseInOut actionWithAction:action rate:0.1];
CCEaseInOut* easyRestore = [CCEaseInOut actionWithAction:action2 rate:0.1];
CCSequence* seq = [CCSequence actions:easyTilt,easyRestore , nil];
[node runAction:seq];
}
which is called via CCCallFuncN:
id action = [CCCallFuncN actionWithTarget:self selector:#selector(moveRandomVector:)];
CCSequence* sq = [CCSequence actionOne:action two:[CCDelayTime actionWithDuration:0.1]];
[towerNode runAction:[CCRepeatForever actionWithAction:sq]];
The factors change (mShakeFactor) in external methods.
Is it proper approach? I'm not Cocos2d expert and I worry about situation when action that runs sequence with CCCallFuncN in it stops but, CCMove* actions and others in moveRandomVector don't. Maybe you know different approach that I could implement?
Finally I moved the code responsible for starting actions to update method. Each time update is called I check if I can run sequence of actions (Boolean variable). If I can I run it and then set the variable to NO, but after last action in sequence I call method, which checks if I can run sequence again. It is comfortable, because it allows me to change variables that affect actions (CCMoveBy, CCMoveTo) and it resembles CCRepeatForever.
Related
I have a setting of ROS indigo, Gazebo under Ubuntu 14.04. Under ROS, moveit node is running. A robot arm IRB120 is simulated and standing in Gazebo. I have a node that uses moveit (move_group node) to plan a path (trajectory) for for the destination that Bob wants. The planned trajectory will be sent to Gazebo to be shown later.
There is two approaches that Bob can use to describe the destination:
Angles of each joints of the arm: using an array of six numbers (for six joints of the arm), the form of each joint and shin is defined. This approach works fine. It uses the JointConstraint class:
double goal_poses [] = {0.52, 0.50, 0.73, -0.02, 0.31, 6.83};
for(int i = 0 ; i < 6; i++) // iterate over joints of the arm.
{
moveit_msgs::JointConstraint jc;
jc.weight = 1.0;
jc.tolerance_above = 0.0001;
jc.tolerance_below = 0.0001;
jc.position = goal_poses[i];
jc.joint_name = names[i];
goal_constraint.joint_constraints.push_back(jc);
}
Define the location and direction of the end effector only. I can not use this approach. I have used the PositionConstraint class.
Problem in short: I can describe a destination using JointConstraint class, But I don't know how to describe it in PositionConstraint class. How to describe a goal, by just pointing out where the end effector should be?
How i describe the goal in PositionConstraint format: (I point out where the end effector should be and what it's orientation should be.)
moveit_msgs::PositionConstraint pc;
pc.weight = 1.0;
geometry_msgs::Pose p;
p.position.x = 0.3; // not sure if feasible position
p.position.y = 0.3; // not sure if feasible position
p.position.z = 0.3; // not sure if feasible position
pc.link_name="tool0";
p.orientation.x = 0;
p.orientation.y = 0;
p.orientation.z = 0;
p.orientation.w = 1;
pc.constraint_region.mesh_poses.push_back(p);
goal_constraint.position_constraints.push_back(pc);
But When the request is sent, server responds with:
[ERROR] [1527689581.951677797, 295.242000000]: Unable to construct goal representation
Note:
In both cases, I add the goal_constraint to the trajectory_request:
trajectory_request.goal.request.goal_constraints.push_back(goal_constraint);
// add other details to trajectory_request here...
trajectory_request is to be sent to the move_group. (by publishing the trajectory_request on the /move_group/goal topic)
A slightly different solution solved the problem of describing goal with end-effector orientation and location:
Instead of publishing the goal on a topic for another node to parse and read, we can use the moveit library function computeCartesianPath. (In this example the code to publish the trajectory is commented and partially missing)
void planTo(std::vector<double> coordinate, std::vector<double> orientation){
geometry_msgs::Pose p;
p.orientation.w = 1.0;
p.position.x = coordinate[0];
p.position.y = coordinate[1];
p.position.z = coordinate[2];
tf::Quaternion q = tf::createQuaternionFromRPY(
orientation[0],orientation[1],orientation[2]);
p.orientation.x = q.getX();
p.orientation.y = q.getY();
p.orientation.z = q.getZ();
p.orientation.w = q.getW();
std::vector<geometry_msgs::Pose> goals;
goals.push_back(p);
moveit::planning_interface::MoveGroup mg("manipulator");
mg.setStartStateToCurrentState();
// load the path in the `trajectory` variable:
moveit_msgs::RobotTrajectory trajectory;
mg.computeCartesianPath(goals, 0.01, 0.0, trajectory);
// publish to gazebo:
// trajectory.joint_trajectory.header.stamp = ros::Time::now();
// publisher.publish(trajectory.joint_trajectory);
}
I solved this a few months ago and unfortunately i do not remember the exact source/tutorial.
How can one get the count of invocations on a mocked object?
At a particular point in a test I'd like to get the current count of invocations for a certain method, then continue the test and finally validate that the method was invoked one more time.
This would be something like:
[given([mockA interestingMethod]) willReturnInt:5];
<do some work that may call 'interestingMethod' one or two times>
NSInteger count = currentCountOfInvocations([mockA interestingMethod]); //or something similar
<do some more work that [hopefully] calls interesting method one more time>
[verifyCount(mockA, times(count + 1)) interestingMethod];
You can mock anything with a block. So let's use a block to increment our own counter.
__block NSUInteger interestingMethodCount = 0;
[given([mockA interestingMethod]) willDo:^id(NSInvocation *invocation) {
interestingMethodCount += 1;
return #5;
}];
<do some work that may call 'interestingMethod' one or two times>
NSUInteger countAtCheckpoint = interestingMethodCount;
<do some more work that [hopefully] calls 'interestingMethod' one more time>
assertThat(#(interestingMethodCount), is(equalTo(#(countAtCheckpoint + 1))));
I've seen the answer about invoking a block that is stored in an array, but I can't get it to work with parameters.
I store the array an a part of an object, then when it's in a method, I want to invoke it, however, I need parameters.
Also, is there any limit to the parameters.
Lastly, I'd rather not use the extra storage to the variable, so invoking directly while in the array would be better.
__block int x = 123; // x lives in block storage
void (^printXAndY)(int) = ^(int y) {
x = x + y;
NSLog(#"X and Y: %d %d\n", x, y);
};
self.blocks = #[printXAndY];
printXAndY(10); // this works
void(^block)(void) = self.blocks[0];
block(); // this works
block(10); // this doesn't work
[self.blocks[0] invoke ];
The problem is this line:
void(^block)(void) = self.blocks[0];
You are declaring 'block' to take no parameters and return nothing. If you want the block to take a parameter, you need to declare it like this:
void(^block)(int) = self.blocks[0];
Note that block(); will no longer work. And when you declared the block incorrectly, that line was undefined behavior.
I have a function which does some array manipulation on an NSMutableArray. Somehow after a couple of loops of the while function the values inside 2 local variables are total garbage. They are not being assigned or manipulated anywhere. Here's how:
Here's the function:
-(void) normalize_path:(NSMutableArray *)path tool:(Tool)tool
{
NSUInteger last_accepted_point_index = 0;
NSUInteger current_point_index = 1;
while(current_point_index < [path count]){
VPoint * p1, * p2;
[[path objectAtIndex:last_accepted_point_index] getValue:&p1];
[[path objectAtIndex:current_point_index] getValue:&p2];
//float distance = [self distance_between:p1 and:p2];
// if(distance < MIN_POINT_DISTANCE){
// [path removeObjectAtIndex:current_point_index];
// }else{
// float opacity = tool.max_opacity - distance * tool.opacity_sensitivity;
// opacity = opacity <= tool.min_opacity ? tool.min_opacity : opacity;
// p2->opacity = opacity;
// float thickness = tool.max_thickness - distance * tool.thickness_sensitivity;
// thickness = thickness <= tool.min_thickness ? tool.min_thickness : thickness;
// p2->thickness = thickness;
// last_accepted_point_index = current_point_index;
// //current_point_index++;
// }
}
}
And it's called only in one place like so:
//...
[self normalize_path:opath tool:pen];
//...
Every run creates different values. I am confounded! What is going on here?
I think that this may be a memory issue which you can fix by removing the & from in front of p1 and p2 in the getValue: call. It's difficult to be totally sure as you haven't said what VPoint is, but normally this code would look like this:
VPoint p1, p2;
[[path objectAtIndex:last_accepted_point_index] getValue:&p1];
[[path objectAtIndex:current_point_index] getValue:&p2];
This would then set p1 and p2 to the actual values. Your distance between function would then not take references but the actual values of p1 and p2 (if you want to pass references as you are doing now, you'd put & in front of p1 and p2 in the distance callBetween method call.
I am currently making a Flappy Bird-copy. Relax, its just for me and the learningpart, im not going to publish it, so dont hate.
The bird is locked at:
self.size.width/3
The pipes are generated like this:
- (void)generatePipes {
for (NSInteger i = 0; i < 3; i++) {
pipeNode = [SKNode node];
[pipeNode setName:#"pipe"];
[pipeNode setPosition:CGPointMake(self.size.width + 100.0 + (200.0 * i), 0.0)];
[self addChild:pipeNode];
**BLABLABLA. Some code**
[pipeTop setPosition:CGPointMake(0.0, arc4random_uniform(250) + 460.0)];
[pipeBottom setPosition:CGPointMake(0.0, pipeTop.position.y - (550.0 + arc4random_uniform(10)))];
[pipeTop setPhysicsBody:[SKPhysicsBody bodyWithRectangleOfSize:pipeTop.size]];
[pipeBottom setPhysicsBody:[SKPhysicsBody bodyWithRectangleOfSize:pipeBottom.size]];
[pipeTop.physicsBody setDynamic:NO];
[pipeBottom.physicsBody setDynamic:NO];
pipeTop.physicsBody.categoryBitMask = blockBitMask;
pipeBottom.physicsBody.categoryBitMask = blockBitMask;
pipeNode.physicsBody.categoryBitMask = blockBitMask;
[pipeNode addChild:pipeTop];
//[pipeTop attachDebugRectWithSize:pipeTop.size];
//[pipeBottom attachDebugRectWithSize:pipeBottom.size];
[pipeNode addChild:pipeBottom];
}
}
THis is the only thing i have made somewhat work, and yes, i am new to game-development. FirstDistance is the distance before the first pipe arrive:
firstDistance += -moveAmount.x;
if(touchBegan > 0 && firstDistance > (self.size.width -(self.size.width/3)- 60)){
distanceSinceLastPipe += -moveAmount.x;
if (distanceSinceLastPipe >= 140.0) {
distanceSinceLastPipe = 0.0;
score += 1;
[_scoreLabel setText:[NSNumberFormatter localizedStringFromNumber:#(score)
numberStyle:NSNumberFormatterDecimalStyle]];
[self runAction:[SKAction playSoundFileNamed:#"pipe.mp3" waitForCompletion:NO]];
}
}
How do i tell the update-method that the pipes are passing the bird most efficent? Count pixels between pipes and reset it? Or is it any way to detect when they pass?
If you know the horizontal position of the bird you could use some "simple" math to calculate how long it will take the pipe to reach the position that means it has passed the bird. Some pseudoCode:
CGFloat totalDistanceForPipeToMove = pipe.position.x - endPosition.x; // endPosition == the final destination for the pipe.
CGFloat relativeSpeed = totalDistanceForPipeToMove / duration; // duration being the SKAction's duration
CGFloat distanceToBird = pipe.position.x - birdPosition.x;
CGFloat timeThePipeReachesTheBird = distanceToBird / relativeSpeed;
Then you can create an SKActionSequence, firing it at the same time as the pipe begins to move:
SKAction *wait = [SKAction waitForDuration: timeThePipeReachesTheBird];
SKAction *addToScore = [SKAction performSelector:#selector(addToScore) onTarget:self]; // performing the addToScore method
SKAction *sequence = [SKAction sequence:#[wait, addToScore]];
Another way to achieve what you are looking for is by having an invincible sprite trailing the birdSprite. Whenever this "scoreSprite" collides with a pipe you know the pipe has passed the bird...