Fire Event every (x) passes in Java? - java

Ok, i am creating a bukkit plugin which uses this event:
public void onCreatureSpawn(CreatureSpawnEvent e) {
// Do stuff
}
Inside of the event i need and if statement to fire every (x) amount of time the Creature event has been fired.
For instance if 10 creatures spawned, out of those 10, i would need the if statement to fire 2 times.
Out of the two creatures, 2 of them will get a special characteristic. My issue is, how can i make it so where this statement only fires (x) out of the many times it has been fired?
I have also tried something along the lines of the example below, but ran into some issues:
int outOf = Plugin.getConfig().getInt("armourSpawn");
int count = 1;
if(count%outOf==0) {
// This will fire (x) out of (x) times
}
count++;
Basically, the user will chose (x) out of 10 Monsters will have some certain characteristic in the config.
Out of ALL the creatures (that are monsters) that spawn i want a ration of (x) to 10 that have the characteristic.

To better illustrate the Random choice solution:
import java.util.Random;
Random rand = new Random();
int percentage = 25; //Set this to whatever percentage you want.
public void onCreatureSpawn(CreatureSpawnEvent e) {
//This will generate a number between 0 and 99 (inclusive)
int generatedNumber = rand.nextInt(100);
//If the generated number is smaller than the percentage you chose, you have "success".
if(generatedNumber < percentage){
addCharacteristic(creature, characteristic);
}else{
//Do whatever you need to normally.
}
}

Related

JAVA / Processing - Instantiating multiple of same objects - Only displays one out of 5

I have a problem regarding drawing multiple of the same objects. They end on top of each other, and their "Object values" even get added together e.g. if a zombie has "2" movement value and there is added 2 into the current level. Then when zombies are moved, they move "4" each. This does not happen if two different objects are moved e.g. Zombie and Dragon. I have created the following code based on my project - for a simpler overview. However, the behavior is the same.
It should be mentioned the objects of the same type have the same "HashCode". I have also made comments and println to help figure out the problem. Each of the 5 objects have different position (When set). However, they are rendered on top of each other and merged (Movement).
EnemyDatabase enemyDatabase;
ArrayList<Enemy> enemiesInlevel = new ArrayList<Enemy>();
void setup()
{
size(600, 600);
enemyDatabase = new EnemyDatabase();
enemyDatabase.enemies.add(new Enemy("Zombie", 3));
//If dragon is added - Then it can draw both - But only once
//enemyDatabase.enemies.add(new Enemy("Dragon", 10));
//Add 10 zombies to the level
for(int i=0; i< 5;i++)
{
//5 Zombies are created and succesfully added to the database
enemiesInlevel.add(enemyDatabase.enemies.get((int)random(0, enemyDatabase.enemies.size())));;
}
for(int i=0; i<enemiesInlevel.size();i++)
{
//Sets the position of all 5 - Gives random position
Enemy enemy = enemiesInlevel.get(i);
enemy.SetPosition();
}
}
void draw()
{
background(255, 200, 0);
//Draw 5 enemies - Of index 0 (Zombie)
for(int i=0; i<enemiesInlevel.size();i++)
{
Enemy tempEnemy = enemiesInlevel.get(i);
tempEnemy.draw();
//It runs 5 times - print returns 5 total objects in enemiesInlevel
}
}
class EnemyDatabase
{
ArrayList<Enemy> enemies = new ArrayList<Enemy>();
}
class Enemy
{
String enemyName;
int enemyHealth;
PVector enemyPosition;
public Enemy(String name, int hp)
{
enemyName = name;
enemyHealth = hp;
}
public void SetPosition()
{
enemyPosition = new PVector(random(0, width), random(0, height));
//Each of the objects has a random position
println(enemyPosition);
}
public void draw()
{
rect(enemyPosition.x, enemyPosition.y, 25, 25);
}
}
UPDATE
Here is an image of the problem
As the image shows from the output in the image line: The enemies have different positions when added to the array (5 different enemies) However, as the image shows, it still only displays one - And this happens because all of the sudden the positions is the same. I even tried to give a "Random position" in the "DrawImage" all of the enemies still end up having the same position
Hope you guys can figure it out. I certainly have a hard time - I usually don't work in processing Thank you
DrSatan's comment is correct. You're only ever adding a single Enemy to your EnemiesDatabase. So when you select 5 random enemies, you're really just selecting the same enemy 5 times.
It might look like they have different positions in your print statements, but that's because you're printing out the position every time you set it. You're setting it five times, but only the last position really counts for anything.
In other words, you're taking a single instance of Enemy, moving it around the screen 5 times, and printing out the position each time. But then when you draw it, only the last position you moved it to is what you see.
You need to refactor your code so you add more enemies to your EnemyDatabase, but please note that you're going to have similar problems no matter how many enemies are in your EnemyDatabsae, because you don't have any logic that makes sure you don't select the same instance twice. Even if you had 100 enemies in your database, nothing is stopping your random function from selecting the same enemy 5 times.
If I were you, I'd rethink my design. I don't really see the reason to have a separate EnemyDatabase class at all. Maybe just create a function that adds X random enemies to the level, where X is a parameter? That's up to you, but your fundamental problem here is that you only have a single instance of Enemy.

How to ensure execution of if statement despite other ongoing tasks - finch robot

I've been tasked with creating a program which will lead a finch robot to move around somewhat randomly for the allotted amount of time, while counting the number of objects that it detects during the movement and returning this amount to then be displayed.
I can get the robot to move randomly, and I can get it to count objects that it detects - but not at the same time.
main:
int millsec = 5000;
int obstacleOccur = finchRandom(millsec);
System.out.println(obstacleOccur);
method:
static public int finchRandom(int x)
{
Finch myf = new Finch();
Random rand = new Random();
int obs = 0;
long time = System.currentTimeMillis()+x;
while(time - System.currentTimeMillis() > 0)
{
if (myf.isObstacle())
{
obs++; //this counts the obstacles
System.out.println("Obstacle");
} //below activates the wheels to move randomly,
//the function is setWheelVelocities(leftWheel,rightWheel,duration)
myf.setWheelVelocities(rand.nextInt(150)-75,rand.nextInt(150)-75,rand.nextInt(x/2));
}
return obs; //returns the count of obstacles
}
I believe it is because the if statement and incrementation for counting obstacles can't be ran while the finch robot is moving around. Are there any ways around this?
Thanks in advance.
The answer is multithreaded programming, your job is to figure out how to use THread or Runnable or a lambda expression to do so. Because any given thread can only do one thing at a time, and you need to be doing at least two things at a time.

LeJOS NXT Programming Sonic Sensor

I am trying to make a NXT Robot that has attached the Ultrasonic Sensor. It has to drive until the distance is 15, and then the engines have to stop. After it stops it has to turn, but it doesn't work.
import lejos.nxt.*;
public class test {
public static void main(String [] args) throws InterruptedException {
UltrasonicSensor ultra = new UltrasonicSensor(SensorPort.S1);
for (int i = 0; i < 5; i++) {
try {
Motor.B.rotate(-1500 , true);
Motor.C.rotate(-1500 , true);
} catch (Exception E){}
while ( ultra.getDistance() < 15 ) {
Motor.B.backward();
Motor.C.backward();
}
LCD.clear();
LCD.drawString("Distance : "+ultra.getDistance(), 0, 0);
}
Button.waitForAnyPress();
}
}
My old code, which also didn't work:
import lejos.nxt.*;
public class test {
public static void main(String [] args) throws InterruptedException {
UltrasonicSensor ultra = new UltrasonicSensor(SensorPort.S1);
try {
Motor.B.rotate(-720);
Motor.C.rotate(-720);
} catch (Exception E){}
for (int i = 0; i < 5; i++)
{
LCD.drawString("Distance : "+ultra.getDistance(), 0, i);
Thread.sleep(2000);
int maxDistance = ultra.getDistance();
if (maxDistance < 15){
Motor.B.stop();
Motor.C.stop();
}
}
Button.waitForAnyPress();
}
}
Assumptions
Okay, from the looks of things, your code is probably not doing what you want. (In the future, when writing a question on Stack Overflow, please clarify in detail what the expected behavior is, as well as what erroneous behavior you're seeing. Those are usually the first two questions we would ask of you, anyway.)
First of all, you're going to want to ensure that your NXT kit has been set up properly, with your two motors on B and C, and your sensor on S1. If this is so, continue reading.
Code Interpretation
The motor commands:
try {
Motor.B.rotate(-1500, true);
Motor.C.rotate(-1500, true);
} catch (Exception E) {}
look like they're valid motor commands... but wait! You're using a two-wheeled robot, with the motors connected to two wheels that point in opposite directions? But you're using the same distance and direction for your motor's limit angle! If your wheels oppose each other, then this will do nothing but make the robot spin in a circle.
NOTE: Since your motors are configured properly, as written in your comments, ignore this part.
If you change the direction of one of the motors by changing the positive to a negative, then you'll have them both working in unison to move your robot forward (or backwards, if you change the wrong one!)
Also, keep in mind that passing true as the second argument in
Motor.B.rotate(-1500, true);
Motor.C.rotate(-1500, true);
makes this function in a very specific fashion, according to the Javadoc (emphasis mine):
If immediateReturn is true, method returns immediately and the motor stops by itself.
If any motor method is called before the limit is reached, the rotation is canceled.
The first sentence means that this does what we want it to: It tells our motor to find the right limit angle by itself, but don't make our program wait for it. However, the second sentence means that if any other motor commands are called, it will stop moving to the given limit angle. Yeah, that's right. Those next few lines make us stop moving the motors and do what they say instead.
Now, this code is problematic for two reasons:
while (ultra.getDistance() < 30) {
Motor.B.backward();
Motor.C.backward();
}
First, these commands will IMMEDIATELY stop our previous two motor commands from executing, which basically means the motors will jump straight to going "backwards" and looping until the distance sensor reads greater than or equal to 30. This is actually what we want, but we need a bit more...
Second, after your sensor reads the distance greater than 30, your motors are never told to stop! So even when your program is showing you the distance, and waiting for your button to be pressed, it'll still be moving!
A Solution
Okay, there's a few things that need to change:
Your initial motor command is being blocked out by the later commands that tell it to move to the correct position.
Your motors don't stop when they're supposed to.
Below is your code, edited to address each of these issues. I've included notes where I've made changes to show you what I've changed.
import lejos.nxt.*;
public class test {
public static void main(String [] args) throws InterruptedException {
UltrasonicSensor ultra = new UltrasonicSensor(SensorPort.S1);
for (int i = 0; i < 5; i++) {
// No initial motor movement (because it did nothing anyway)
// We change this to approach from either direction.
while (ultra.getDistance() != 30) {
// Check whether it's behind or ahead of it.
// Assuming that B- and C- increase distance, and B+ and C+ decrease it (depends on robot configuration).
// This is called a feedback loop, by the way.
if (ultra.getDistance() < 30) { // Move forward (distance+)
Motor.B.backward();
Motor.C.backward();
} else { // Move backward (distance-)
Motor.B.forward();
Motor.C.forward();
}
}
// We only get here when the distance is right, so stop the motors.
Motor.B.stop();
Motor.C.stop();
LCD.clear();
LCD.drawString("Distance : "+ultra.getDistance(), 0, 0);
}
Button.waitForAnyPress();
}
}
Now, this code isn't perfect; it may have a tendency to oscillate between forward and backward on slippery surfaces (which may turn it slightly to the left or right due to differences in applied torque), or if the sensor misses the correct position and the robot overshoots it.
This code also doesn't wait until the robot stabilizes at the given position, just until the sensor first reports the correct one. Again, this may result in sliding around a bit if the wheels don't have decent traction, the motors are set to smooth acceleration, or if the motors run at too high of a speed.
To correct these flaws, you'd need a more advanced type of feedback loop which accounts for acceleration and slip, and you'd need to wait until the robot stabilizes at the correct position for a short period of time before stopping the motors.
However, this should get you moving in the right direction, so to speak.
EDIT Corrected drive motor directionality, as specified in the comments.

Incremental values how to show one value at a time

I am making a simple sequence from randomly generated numbers. Each number will show an image linked to it.
for example,
the value 1 will show a picture of a cat.
value 2 a dog
and value 3 a mouse.
Each image has it's own dedicated imageview, the layout looks like this by default, i.e image views that store black until it's number is called:
Each time the sequence increments. so on the second run two images will show, on the third 3 will show and so on.
The problem I am having is that all the images show at once. So for sequence one just the one image flashes (which is what I want). but on the second run both images show at once together instead of showing the first image then the second.
So to clarify let's say on the four runs the stored array is 1,2,3,3 I would want
image 1 to show, and disappear.then
image 2 show and disappear. then
image 3 show and disappear
and then image 3 to show and disappear.
But what I actually get is on the fourth run 1,2&3 will show at once and disappear at the same time together. How can I break this up to achieve what I want. I have tried many methods and the same result happens. I can't get my head around this problem.
Here is my code:
ArrayList<Integer> stored_vals = new ArrayList<Integer>();
public void Gen() {
int i=0 ;
Random rand = new Random();
int rndInt = rand.nextInt(3)+ 1 ;
list.add(rndInt);
int totalElements = list.size();
Log.d("LOOK", Integer.toString(rndInt));
Log.i("VALUE LIST ", list.toString()+" <<<<LIST HERE");
while(i < totalElements) {
retval =list.get(i);
Log.d("RETVAL", Integer.toString(retval));
String imgName = "flash" + retval;
int id = getResources().getIdentifier(imgName, "drawable", getPackageName());
if (retval==1){
Cat.setImageResource(id);
Reset_View();
}
else if (retval==2){
Dog.setImageResource(id);
Reset_View();
}
else if (retval==3){
Mouse.setImageResource(id);
Reset_View();
}
i++;
}
}
To try and delay the images showing at one at a time and to reset to it's default after showing for a few seconds I call Reset_View(); which is the following code:
CountDownTimer Reset_View = new CountDownTimer(1000 , 0010){
public void onTick(long millisUntilFinished) {
}
public void onFinish() {
Centre.setImageResource(R.drawable.i1);
upperRight.setImageResource(R.drawable.i2);
lowerRight.setImageResource(R.drawable.i3);
lowerLeft.setImageResource(R.drawable.i4);
upperLeft.setImageResource(R.drawable.i5);
}
};
So how can I achieve what I want. I have been stuck on this idea for weeks.
This is a high level idea of what you could do.
Put all the showing and hiding in the countdowntimer. So basically you would need to handle the 'onTick' and hide or show the images when needed. Something like 'time > 0 and < 1000' hide all but the first image. 1000 to 2000, show only second image. 2000 to 3000, show only third image. On finish, hide all.
When you instantiate the timer after the for loop, if retval is 1 - then 1000 would be how long to run, retval = 2, then 2000, retval = 3, then 3000.
There is probably a better way to do it but this is the first thing that comes to my mind.
One problem might be that Reset_View(); is not a method. The line even states public CLASS Reset_View(); extends CountDownTimer. ( I don't know ho that can be a valid class name but whatever) Therefore, calling Reset_View(); will not actually do anything.
You need to change the name of the class to something else, I suggest ResetTimer. Then to reset the Views you must create an instance of ResetTimer and use its start() method like this:
new ResetTimer(1000, 1000).start();
Note: the first number in the constructor is the total time (in milliseconds) until the timers onFinish() is called. The second one it the time between the onTick()s. Since you don't use this method, the number you put in there doesn't matter.

Linked JSliders With Maximum Combined Value

What's the best way to 'link' JSliders to put a cap on the combined value?
Imagine a fighting game where the user can specify character traits like speed, agility, endurance and accuracy. The user is given 100 points to allocate however he chooses, but the total value of all the sliders must not exceed 100. That is, the sliders should not allow such increases.
If the user has allocated 30 points each to speed, agility and endurance, then the slider for accuracy should allow a maximum of 10 points (because 30 + 30 + 30 + 10 = 100). Notwithstanding, the range of the each slider should remain unchanged (in this case, 0 to 100).
I hope this makes sense. Thanks for the help.
"nichts einfacher als das" - dachte ... (insert name :-)
Basically, all such enhanced functionality must be implemented in the model: for JSlider, that's a BoundedRangeModel. Implement/extend and enforce its value to respect the "combined" max. Something like
public static class LimitedBoundedRangeModel extends DefaultBoundedRangeModel {
BoundedRangeModel limit;
public LimitedBoundedRangeModel(BoundedRangeModel limit) {
this.limit = limit;
}
/**
* #inherited <p>
*/
#Override
public void setRangeProperties(int newValue, int newExtent, int newMin,
int newMax, boolean adjusting) {
if (limit != null) {
int combined = newValue + limit.getValue();
if (combined > newMax) {
newValue = newMax - limit.getValue();
}
}
super.setRangeProperties(newValue, newExtent, newMin, newMax, adjusting);
}
}
// use
LimitedBoundedRangeModel firstModel = new LimitedBoundedRangeModel(null);
LimitedBoundedRangeModel secondModel = new LimitedBoundedRangeModel(firstModel);
firstModel.limit= secondModel;
JSlider first = new JSlider(firstModel);
JSlider second = new JSlider(secondModel);
While simple (two dependents only) and crude (direct bidirectional coupling) and as such not really usable out in the wild, it should at least work ... but doesn't - one of those surprises which hit me from time to time ;-) The visual problem is the thumb-position:
the combined max is respected when clicking to the right of the thumb: the thumb never moves over the threshhold
when dragging, the thumb can be moved everywhere which might be expected, as the ui isn't aware of the model tweak - it knows only the "local" max
on drag-end, the thumb remains at that invalid position.. which smells like a bug as now the thumb is out-off synch with the model
The reason for this misbehaviour is that the changeListener in Handler: it doesn't recalculate its thumb position when dragging (which is okay). The subtle bug is, that the internal dragging flag is only reset after the model's adjusting property is reset, so missing the very last notification about the final value ...
Hack around is to invoke the firing of an additional changeEvent, if the adjusting flag changes from true to false
boolean invoke =
(adjusting != getValueIsAdjusting()) && !adjusting;
super.setRangeProperties(newValue, newExtent, newMin, newMax, adjusting);
if (invoke) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
fireStateChanged();
}
});
}
Create 4 sliders and some variables: the maximum total value (say, 100) and the current total (0).
When the value of any of the sliders modifies, do:
// I hope my logic isn't failing me at this point
if (slider.getValue() > (maxTotal - currentTotal))
slider.setValue(maxTotal - currentTotal);
currentTotal = slider1.getValue() + slider2.getValue()
+ slider3.getValue() + slider4.getValue();

Categories

Resources