Good day,
The scenario is this, I have 3 sprites and I want to execute actions to them using sequence, inside the update().
Another thing if the sprite is still executing the action, it will not acquire new action but if it is done executing the action it will create a new action then execute it.
I used .isDone() for the checking.
Here is the pseudo code:
-Legend for readability:
SampleSprite - assuming that this is the array of sprites. isStillOnAction - boolean, true if currently executing action, false if not.
RANDOM NUMBER FROM 2-5 - is a random number from 2 to 5.
for(int ctr = 0; ctr < 3; ctr++){
if(!SpriteSample[ctr].isStillOnAction) // not currently executing action, so we can now assign an action
{
SampleSprite[ctr].isStillOnAction = true; // the isStillOnAction boolean is changed to true
if(SampleSprite[ctr].facingDirection == 1)
{
SampleSprite[ctr].moveAction = cocos2d::MoveBy::create( RANDOM NUMBER FROM 2-5, cocos2d::Vec2( 0, 100 ) );
SampleSprite[ctr].stoppingAction = cocos2d::MoveBy::create( RANDOM NUMBER FROM 2-5, cocos2d::Vec2( 10, 0 ) );
}
else if(SampleSprite[ctr].facingDirection == 2)
{
SampleSprite[ctr].moveAction = cocos2d::MoveBy::create( RANDOM NUMBER FROM 2-5, cocos2d::Vec2( 0, -100 ) );
SampleSprite[ctr].stoppingAction = cocos2d::MoveBy::create( RANDOM NUMBER FROM 2-5, cocos2d::Vec2( 10, 0 ) );
}
else if(SampleSprite[ctr].facingDirection == 3)
{
SampleSprite[ctr].moveAction = cocos2d::MoveBy::create( RANDOM NUMBER FROM 2-5, cocos2d::Vec2( -100, 0 ) );
SampleSprite[ctr].stoppingAction = cocos2d::MoveBy::create( RANDOM NUMBER FROM 2-5, cocos2d::Vec2( 0,10 ) );
}
else if(SampleSprite[ctr].facingDirection == 4)
{
SampleSprite[ctr].moveAction = cocos2d::MoveBy::create( RANDOM NUMBER FROM 2-5, cocos2d::Vec2( 100, 0 ) );
SampleSprite[ctr].stoppingAction = cocos2d::MoveBy::create( RANDOM NUMBER FROM 2-5, cocos2d::Vec2( 0, 10 ) );
}
SampleSprite[ctr].moveStopAction = cocos2d::Sequence::create(SampleSprite[ctr].moveAction, SampleSprite[ctr].stoppingAction, nullptr);
SampleSprite[ctr].characterSprite->runAction( SampleSprite[ctr].moveStopAction );
}
else // currently executing action
{
if(SampleSprite[ctr].moveStopAction->isDone()) // check if done executing action
{
SampleSprite[ctr].isStillOnAction = false;
}
}}
Result:
It runs the sequence action but after that it freezes then it crashes.
What is the possible problem that I overlooked?
Thank you in advance smile
Running actions inside a scheduled function will not crash the app. The problem is likely to be:
the action has be released when you use .isDone(). When a action is done, it will decrease its reference count and be released unless you have retained it ( not recommended).
MoveBy::create() returns an auto-release object, which means if you don't call runAction on it or retain it, it will be released at the end of this frame.
You can use tags to check whether an action is running:
static const int MY_MOVEBY_ACTION = 3333;
for(int ctr = 0; ctr < 3; ctr++){
if(!SpriteSample[ctr].characterSprite->getActionByTag(MY_MOVE_ACTION)) // not currently executing action, so we can now assign an action
{
SampleSprite[ctr].isStillOnAction = true; // the isStillOnAction boolean is changed to true
//......
SampleSprite[ctr].moveStopAction = cocos2d::Sequence::create(SampleSprite[ctr].moveAction, SampleSprite[ctr].stoppingAction, nullptr);
moveStopAction->setTag(MY_MOVE_ACTION);
SampleSprite[ctr].characterSprite->runAction( SampleSprite[ctr].moveStopAction );
}
else // currently executing action
{
if(SampleSprite[ctr].moveStopAction->isDone()) // check if done executing action
{
SampleSprite[ctr].isStillOnAction = false;
}
}}
Related
A =[0,0,0,0,0] if I select 1 element and increment it by 1, so the should that to become new array A=[0,0,1,0,0] and when I also select another element and increment it then the new array may become A=[0,1,1,0,0] and so on. the increment is done by button, the increment may not only be 1 times.
in short is to make a counter for each of the random selected element and update the array anytime
Your question is rather an JS question than an react-native.
Below is an sample:
let numbers = [0,0,0,0,0]
const max = numbers.length
function replaceArrayElement (values, index) {
return ([...values.slice(0, index), values[index]+1, ...values.slice(index+1)])
}
function getRandomInt() {
return Math.floor(Math.random() * max);
}
for(var i = 0; i<=10; i++){
numbers = replaceArrayElement(numbers, getRandomInt())
}
console.log('numbers: ',numbers)
Is there a script command that I can specify a particular slice in a LinePlotImageDisplay and do the Align Slice Horizontally by Calibration (or Uncalibrated (channels)) action?
The following scipt is a complete implantation based on example codes provided by BmyGuest. It will align all slices in a LinePlotImageDisplay horizontally either by calibration or by channel (i.e. un-calibrated).
class SliceAlignment : object {
number true, false; // boolean
image imgLPID;
imageDisplay LPID; // line plot image display
number CalculateImageToGroupTransformFactors( object self, image slice_src, image slice_ref, number &relOff, number &relScale ) {
number origin_ref, scale_ref, origin_src, scale_src;
string unit_ref, unit_src;
number calFMT = 0; // origin is expressed in calibrated unit
//
slice_src.ImageGetDimensionCalibration( 0, origin_src, scale_src, unit_src, calFMT );
slice_ref.ImageGetDimensionCalibration( 0, origin_ref, scale_ref, unit_ref, calFMT );
//
relScale = scale_src / scale_ref;
relOff = (origin_src - origin_ref) / scale_ref ;
// check if both images are calibrated in same unit
if( unit_src != unit_ref ) return false
return true;
};
void AlignNthSliceHorizontallyByChannel( object self, number slice_idx ) {
// get current reference slice index
number refSlice_idx = LPID.LinePlotImageDisplayGetSlice();
// get slice ID's (as objects)
object slice_ref = LPID.ImageDisplayGetSliceIDByIndex(refSlice_idx);
object slice_src = LPID.ImageDisplayGetSliceIDByIndex(slice_idx);
number int_offset = 0, int_scale = 1.0; // vertical (intensity) offset and scaling factors
number pos_offset = 0, pos_scale = 1.0; // horizontal (position) offset and scaling factors
LPID.LinePlotImageDisplaySetImageToGroupTransform( slice_src, slice_ref, int_offset, int_scale, pos_offset, pos_scale );
};
void AlignNthSliceHorizontallyByCalibration( object self, number slice_idx ) {
// get current reference slice index
number refSlice_idx = LPID.LinePlotImageDisplayGetSlice();
// get slice ID's (as objects)
object slice_ref = LPID.ImageDisplayGetSliceIDByIndex(refSlice_idx);
object slice_src = LPID.ImageDisplayGetSliceIDByIndex(slice_idx);
number int_offset = 0, int_scale = 1.0; // vertical (intensity) offset and scaling factors
number pos_offset, pos_scale; // horizontal (position) offset and scaling factors
number unit_check = self.CalculateImageToGroupTransformFactors( imgLPID{slice_idx}, imgLPID{refSlice_idx}, pos_offset, pos_scale );
if( unit_check == false ) {
string prompt = "slice #" + slice_idx + " [" + LPID.ImageDisplayGetSliceLabelById( LPID.ImageDisplayGetSliceIDByIndex(slice_idx) ) + "] is calibrated in different unit!";
if( !ContinueCancelDialog( prompt ) ) return
};
LPID.LinePlotImageDisplaySetImageToGroupTransform( slice_src, slice_ref, int_offset, int_scale, pos_offset, pos_scale );
return;
};
void AlignAllSlicesHorizontallyByChannel( object self ) {
number nSlices = LPID.LinePlotImageDisplayCountSlices();
for( number idx = 0; idx < nSlices; idx++ ) self.AlignNthSliceHorizontallyByChannel( idx );
return;
};
void AlignAllSlicesHorizontallyByCalibration( object self ) {
number nSlices = LPID.LinePlotImageDisplayCountSlices();
for( number idx = 0; idx < nSlices; idx++ ) self.AlignNthSliceHorizontallyByCalibration( idx );
return;
};
object init( object self, image img ) {
// check if the image display is correct type
imgLPID := img;
LPID = imgLPID.ImageGetImageDisplay(0);
if( LPID.ImageDisplayGetDisplayType() != 3 ) throw( "Please choose a valid line plot display" );
return self;
};
SliceAlignment( object self ) {
true = 1; false = 0;
result( "SliceAlignment [obj ID:" + self.ScriptObjectGetID().hex() + "] constructured\n" );
};
~SliceAlignment( object self ) {
result( "SliceAlignment [obj ID:" + self.ScriptObjectGetID().hex() + "] destructured\n\n" );
}; };
{; object objAlign = alloc(SliceAlignment);
objAlign.init( GetFrontImage() );
if( OptionDown() ) objAlign.AlignAllSlicesHorizontallyByChannel();
else objAlign.AlignAllSlicesHorizontallyByCalibration(); };
No, there is no single 'convenience' command to achieve this alignment. You will have to create the according function yourself from reading a slices calibration and setting its display-coordinate system. You might find the following (old) tutorial PDF on the FELMI homepage might be useful:
SlicesInLinePlotDisplay.pdf
The following example script might also be useful. It shows how one slice is aligned relative to another slice. (Just on the X-axis)
// All Slices in a LinePlot are grouped into a single 'group'
// Slices can be moved relative to each other by specifying their image-to-group transform,
// and the whole image (i.e. the group) can be moved with respect to the display using the group-to-display transform.
// To set the image-to-group transform of the slice specified by 'slice_id', with respect to the slice specified by 'ref_id'
// use the command:
// LinePlotImageDisplaySetImageToGroupTransform( LinePlotImageDisplay lpid, ScriptObject slice_id, ScriptObject ref_id, double off_val, double scale_val, double off_dim_0, double scale_dim_0 )
/*********************************************************/
// Create 2 LinePlots and add them into one display
// (Initially they are aligned by their calibrations)
number sc1 = 1
number of1 = -50
number sc2 = 2
number of2 = -20
image sl1 := realImage("S1",4,300)
image sl2 := realImage("S2",4,300)
sl1 = (iwidth-icol)/iwidth
sl2 = (iwidth-icol)/iwidth
sl1[0,50,1,60] = 1
sl1[0,250,1,260] = 1
sl2[0,10,1,15] = 1
sl2[0,110,1,115] = 1
// Adding Calibrations
sl1.ImageSetDimensionCalibration(0,of1,sc1,"CH",0)
sl2.ImageSetDimensionCalibration(0,of2,sc2,"CH",0)
sl1.DisplayAt(20,30)
sl2.DisplayAt(750,30)
OKDialog( "Put into one Display" )
imageDisplay disp = sl1.ImageGetImageDisplay(0)
disp.ImageDisplayAddImage( sl2, "S2") // When added like this, the slices are automatically aligned by their respective calibration!
disp.LinePlotImageDisplaySetDoAutoSurvey( 0, 0 )
object ref_id = disp.ImageDisplayGetSliceIDByIndex(0) // Slice 0
object slice_id = disp.ImageDisplayGetSliceIDByIndex(1) // Slice 1
OKDialog("Now align by channels (i.e. undo any relative sclice alignment)")
// Simply set the relative "shifts" and "scales" to 0 and 1.
disp.LinePlotImageDisplaySetImageToGroupTransform( slice_id, ref_id, 0, 1, 0, 1 )
OKDialog("Now align by chalibration ")
number relScale = sc2/sc1
number relOff = of2-of1
disp.LinePlotImageDisplaySetImageToGroupTransform( slice_id, ref_id, 0, 1, relOff, relScale )
I'm using Silk4J and I have a table which is reported as SapTable in the Locator Spy. From that table, I'm trying to get all the texts of the second column, but it hangs or terminates with an exception. In the following you find the code for my tries. Finally I reached the last row of the table, but it hangs there again.
In all examples I'm using a while loop instead of a for loop, because I want to insert more conditions later.
Try 1: Straight forward (I thought)
SapTable table; // initialized somewhere else
int maxrows = table.getRowCount();
int row = 0;
while (row < maxrows)
{
String text = table.getCell(row, COLUMN).getText();
logger.debug(text);
row++;
}
However, this code prints all visible columns, then hangs.
Try 2: adding a PageDn keypress via Silk
Since try 1 printed only the visible cells, I thought adding a keypress every page could help. That was my code:
SapTable table; // initialized somewhere else
int maxrows = table.getRowCount();
int row = 0;
int visibleRows = table.getVisibleRowCount();
table.setFocus();
while (row < maxrows)
{
String text = table.getCell(row, COLUMN).getText();
logger.debug(text);
row++;
if (row % visibleRows == 0)
window.sendVKey(VKey.PAGE_DOWN);
}
Unfortunately this results in an exception "The virtual key is not enabled".
Try 3: adding a PageDn keypress via AwtRobot
Since the built-in sendVKey method did not work, but pressing the PageDn manually works, I switched to an AwtRobot:
SapTable table; // initialized somewhere else
int maxrows = table.getRowCount();
int row = 0;
int visibleRows = table.getVisibleRowCount();
table.setFocus();
while (row < maxrows)
{
String text = table.getCell(row, COLUMN).getText();
logger.debug(text);
row++;
if (row % visibleRows == 0)
{
Robot robot = new Robot();
robot.keyPress(KeyEvent.VK_PAGE_DOWN);
robot.keyRelease(KeyEvent.VK_PAGE_DOWN);
}
}
Pressing the key now works and I can see the table scroll to the next entry. However, my test application still hangs.
Try 4: Resetting the row count
Using the Locator Spy again, I found out that the index of the row is reset to zero, so I mimiced that in my code:
SapTable table; // initialized somewhere else
int maxrows = table.getRowCount();
int row = 0;
int visibleRows = table.getVisibleRowCount();
table.setFocus();
while (row < maxrows)
{
String text = table.getCell(row, COLUMN).getText();
logger.debug(text);
row++;
if (row % visibleRows == 0)
{
Robot robot = new Robot();
robot.keyPress(KeyEvent.VK_PAGE_DOWN);
robot.keyRelease(KeyEvent.VK_PAGE_DOWN);
row = 0; // <--
}
}
In this case, it prints the first N (number of visible) items of the list, scrolls to position N+1, prints the name of the first (!) row and then hangs when accessing the item with index 1 (after the reset).
Try 5: Sleeping
With some sleeping, I can reach the end of the table:
SapTable table; // initialized somewhere else
int maxrows = table.getRowCount();
int row = 0;
int visibleRows = table.getVisibleRowCount();
table.setFocus();
while (row < maxrows)
{
String text = table.getCell(row, COLUMN).getText();
logger.debug(text);
row++;
if (row % visibleRows == 0)
{
Robot robot = new Robot();
robot.keyPress(KeyEvent.VK_PAGE_DOWN);
robot.keyRelease(KeyEvent.VK_PAGE_DOWN);
row = 0;
Thread.sleep(1000); // <--
}
}
In this case, I get all items in the table. But since I don't know when the table ends, it does another getCell() call, which results in a hang again.
The question
I'm really stuck. I've also looked for other methods like getting the real number of rows in the table (getRowCount() doesn't), but didn't find one yet.
How do I get the real number of rows of a SapTable in Silk4J?
It took some trying - the underlying SAP automation API is not really helpful in this case - but here is how you can make it work:
private List<String> fetchItems() {
SapTable table = desktop.find("sap.Table");
SapVerticalScrollBar scrollBar = table.find("/SapVerticalScrollBar");
// the scrollbar maximum value seems to be a more reliable
// way to get the number of items than getRowCount
int itemCount = scrollBar.getMaximum() + 1;
List<String> items = new ArrayList<String>();
int currentAbsoluteRow = 0;
// the first loop iterates through the table page by page
for (int firstRowInPage = 0;
firstRowInPage < itemCount;
firstRowInPage = scrollToNextPage(firstRowInPage)) {
// this loop goes through the items of the current page
for (int currentRowInPage = 0;
currentRowInPage < table.getVisibleRowCount();
currentRowInPage++) {
if(++currentAbsoluteRow > itemCount) {
// we've read all the available items
return items;
}
SapComponent cell = table.getCell(currentRowInPage, 1);
items.add(cell.getProperty("Text").toString());
}
}
return items;
}
private int scrollToNextPage(int firstRowInPage) {
SapTable table = desktop.find("sap.Table");
SapVerticalScrollBar scrollBar = table.find("/SapVerticalScrollBar");
firstRowInPage += scrollBar.getPageSize();
scrollBar.scrollTo(firstRowInPage);
return firstRowInPage;
}
Some pitfalls that I encountered:
getRowCount() returned a higher count than there was in actual items
getVisibleRowCount() returns the number of items that would fit on the current page, even if not all rows were filled with actual items
The returned cell objects are only valid as long as the cell is on the screen, so you'll need to pull the information you want before you scroll to the next page.
While doing some work for my lab in university
I am creating this function where there is a for loop inside another one.
It is not important to know what the method is used for. I just can't figure out why the program doesn't enter the second for loop. This is the code:
public void worseFit(int[] array){
int tempPosition = -1;
int tempWeight = 101 ;
for (int x = 0; x < (array.length - 1); x++){
if (allCrates.getSize() < 1){
Crate crate = new Crate();
crate.addWeight(array[0]);
allCrates.add(crate);
} else{
for( int i = 1; i < (allCrates.getSize() - 1); i++ ){
Crate element = allCrates.getElement(i);
int weight = element.getTotalWeight();
if (weight < tempWeight){
tempWeight = weight;
tempPosition = i;
Crate crate = new Crate();
if (weight + tempWeight <= 100){
crate.addWeight(weight + tempWeight);
allCrates.setElement(i, crate);
} else {
crate.addWeight(weight);
allCrates.setElement(allCrates.getSize(), crate);
} // if
} // if
} // for
} // if
} // for
} // worseFit
Once the program enters the else part of the code it goes straight
away back to the beginning of the first for loop.
Would anyone know how to solve this problem?
There seems to be some discrepancies with the expected values of allCrates.getSize().
If allCrates.getSize() returns 2, it will go to the second for loop, but not run it, as i < allCrates.getSize() - 1 will result in false
You might want to use <= instead of <
Initialize the variable i in your second loop to 0 instead of 1. Because if your getSize() returns 1 the it will not enter the if part and after entering the else part the for loop condition will evaluate to false and hence your for loop will not be executed.
For generating the bingo ticket generator I need the shuffling array .
When I press a button I should retrive the values from array (ex. array(1,2,3,4,5,6,7,8,9)). I
If I retrive first five random value may be 2 5 7 4 8. If press the button again then it should retrive other than previously retrived value (ex. 1 3 9 6 7)
I don't know if you are allowed to modify your input but why not try something like this :
// passing your array as argument
// passing the total number you want to extract as argument
function getRandNumbers( a:Array, requested_numbers:Number ):Array
{
// verify we don't request to much numbers
if ( requested_numbers > a.length )
{
trace( "Not enought available numbers in array" );
return null;
}
results_array = new Array(); // create our output array
while( results_array.length < requested_numbers )
{
rnd = Math.floor( Math.random() * a.length );
results_array.push( a[rnd] );
a.splice( rnd, 1 ); // remove the random result
}
}
now you're sure your array will contain only non used numbers each time you will call getRandNumbers.