Situation: The tank has a Shot() method and a code that checks if the bullet hits the obstacle after being fired. The bullet flies up the X-coordinate. The do...while loop checks how far the bullet can travel without obstacles. After that, the animation of the bullet flight itself takes place through TranslateTransition. And the last loop goes through all the game obstacles and checks for contact through intersects and, if successful, removes the obstacle.
do {
y = (int) (bulletObj.getImageBullet().getTranslateX() + register) / PlayField.BRICK_SIZE;
x = (int) bulletObj.getImageBullet().getTranslateY() / PlayField.BRICK_SIZE;
line = LevelData.LevelOne[x][y];
register += 1;
} while (line.equals("0"));
System.out.println(System.currentTimeMillis()); // 1643642047472 ms.
bulletTranslate = new TranslateTransition();
bulletTranslate.setFromX(bulletObj.getImageBullet().getTranslateX());
bulletTranslate.setToX(bulletObj.getImageBullet().getTranslateX() + register - 18);
bulletTranslate.setNode(bulletObj.getImageBullet());
bulletTranslate.setDuration(Duration.millis(register)); // Let register = 300 мs.
bulletTranslate.play();
System.out.println(System.currentTimeMillis()); // 1643642047474 ms.
bulletObj.getImageBullet().setTranslateX(bulletObj.getImageBullet().getTranslateX() + register - 18);
for (GameObject platform: PlayField.platforms) {
if (platform.getImage().getBoundsInParent().intersects(bulletObj.getImageBullet().getBoundsInParent()))
{
System.out.println(System.currentTimeMillis()); // 1643642047474 ms.
tankRoot.getChildren().remove(platform.getImage());
PlayField.platforms.remove(platform);
LevelData.LevelOne[x][y] = "0";
break;
}
}
Everything works as expected, but there is only one problem.
The problem is that the obstacle objects are removed faster than the animation bullets pass.
And it is necessary that after contact they are deleted simultaneously.
How to solve the problem?
Before the shot
After the shot, the object disappeared during the flight of the bullet
P.S Sorry, I used google translate.
As #jewelsea suggested, you need to supply a minimal reproducible example to get some proper help.
Having said that, based on the code you provided, below is my initial analysis. Note that this is a rough analysis by reading the code.. so everything is just an assumption ;)
The first part of the code (do-while) is to determine the distance the bullet needs to travel (determining the value of register)
The second part is to initiate animation of bullet to translate from its current position (using the register value).
The third part is to set the final translate value to the bullet and the final part is to check if the bounds are intersected and delete the node.
I think the thrid part (below line of code) is not needed and could be the cause for your issue. You are updating the value to the end value and immediately checking if it is intersected.. which will be true and will delete instantly.
bulletObj.getImageBullet().setTranslateX(bulletObj.getImageBullet().getTranslateX() + register - 18);
Try moving your 'for' loop code to onFinished of translation. Something like..
bulletTranslate = new TranslateTransition();
bulletTranslate.setFromX(bulletObj.getImageBullet().getTranslateX());
bulletTranslate.setToX(bulletObj.getImageBullet().getTranslateX() + register - 18);
bulletTranslate.setNode(bulletObj.getImageBullet());
bulletTranslate.setDuration(Duration.millis(register)); // Let register = 300 мs.
bulletTranslate.setOnFinished(e->{
for (GameObject platform: PlayField.platforms) {
if (platform.getImage().getBoundsInParent().intersects(bulletObj.getImageBullet().getBoundsInParent()))
{
tankRoot.getChildren().remove(platform.getImage());
PlayField.platforms.remove(platform);
LevelData.LevelOne[x][y] = "0";
break;
}
}
});
bulletTranslate.play();
Related
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.
im new to android studio and i want this function to loop and create an infinite ball falling loop which will be scored until the two integers do not match but when i try to run it, it will only loop once and if i change streak = 2 in the else statement the app crashes
public void mainGameLoop(){
do {
//sets Balls integer
setColourint();
ball.setVisibility(View.VISIBLE);
//ball fall
float bottomOfScreen = getResources().getDisplayMetrics()
.heightPixels - (ball.getHeight() * 4);
//fall animation
ball.animate()
.translationY(bottomOfScreen)
.setInterpolator(new AccelerateInterpolator())
.setInterpolator(new BounceInterpolator())
.setDuration(9000);
//once animation is complete compares balls variable with current variable
if (colourint == ranint){
//if they are same then +1 score
score = score+1;
scr.setText(Integer.parseInt(String.valueOf(score)));
} else {
//else game is over
streak = 2;
}
//repeat until game is over
} while (streak == 1);
}
once the balls reached the bottom of the relative layout i want the function to check if the setcoulour int and the ran int are the same and then if the are score = score + 1, ball goes back to the top, the setColourInt function is called and the ball falls again(and so on and so on) but if not loop ends and it's game over...i apologise for my blatant incompetence but I can't imagine you guys don't remember when you too, were this naive when it came to coding. many thanks Tom
You have to give the UI a chance to draw what you're doing. The way you have it coded, whichever method (onStart, onCreate, etc) that calls your mainGameLoop will never return because it's stuck in an infinite loop. This is an error.
One way to do this is to create a View and implement your game draw logic in the onDraw method. The UI thread will call your onDraw method when it is time to draw. Here's an article that talks about this approach: http://cjds.github.io/2014/04/28/Creating-a-simple-android-game/
I'm creating a game with a score system similar to the one in Flappy Bird.
if you didn't get it
When the player successfully passes the right and left
obstacle I want my score variable to increase by 1. I don't know the logic behind it though.
Right now I have (this is inside a for loop checking every obstacle in an update method):
'over' making sure the score only increases by 1.
if (bird.getPosition().y > obstacle.getPosLeft().y) {
if (!over) {
over = true;
score++;
}
and when the obstacle gets off the screen (yes, y is 0 at the bottom, not the top):
if (obstacle.getPosLeft().y + Obstacle.OBSTACLE_HEIGHT < 0){
obstacle.reposition(obstacle.getPosLeft().y + (OBSTACLE_SPACING + Obstacle.OBSTACLE_HEIGHT)* OBSTACLE_COUNT);
over = false;
}
The problem is that you can pass 2 obstacle pairs before the first one gets re-positioned which means that you only get the 2nd point after reposition() is called for obstacle 1.
How would you fix this problem?
Just make a "obstacle.over" boolean so that each has its own state.
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.
I am trying to find the most reliable way to identify if the user is driving, walking, biking or is stationary. I am going to use this in an Android application. I would prefer to avoid GPS as much as possible.
Please let me know what algorithms worked for you, their advantages and disadvatages. Thanks!
Google has an API for this in Google Play Services. Check out https://developer.android.com/reference/com/google/android/gms/location/ActivityRecognitionApi.html
I wouldn't suggest coding it on your own, its not easy (I had a version about a year before Google did, it was buggy and battery draining).
You probably will never get a completely accurate result, but a reasonable estimate could be determined using
- GPS to identify speed
- Is the charger plugged in
- is the phone off, or on screensaver
- is the movement detector going off a lot - likely walking but may be driving on dirt road
I was playing with a simplistic version of this as follows (sorry code is in Python)
def inspect_phone(self):
self.phone_gps_lat = 137.0000 # get from phone
self.phone_gps_lng = 100.0000 # get from phone
self.phone_moving = False # get from phone
self.phone_move_dist_2_mn = 4
self.phone_on_charge = True
self.screen_saver = False
#-------------------------------
phone_status = ''
if self.phone_on_charge == True:
phone_status += 'Phone is charging'
if self.phone_moving == True:
phone_status += ', driving in Car'
else:
phone_status += ', sitting still'
else:
if self.screen_saver == False:
phone_status += 'Phone is being used'
else:
phone_status += 'Phone is off'
if self.phone_moving == True:
if self.phone_move_dist_2_mn < 5:
phone_status += ', going for Walk'
elif self.phone_move_dist_2_mn > 500:
phone_status += ', flying on Plane'
else:
phone_status += ', riding on ' + transport['Public']
return phone_status
I have made a small logic to get the best polylines for each activity and optimize the draw, since we need certain quantity of latitudes and longitudes in order to draw the best track that the user has made.
Lets say when the user press to start a new activity it will prompt 3 options, run, walk or biking.
This method takes what the user has selected and updates the locationRequest for each one.
public void setTrackActivity(long interval, long fastInterval) {
//Update the locationRequest intervals for each different Activity
mLocationRequest.setInterval(interval);
mLocationRequest.setFastestInterval(fastInterval);
mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
}
For walking I set the locationRequest intervals within 6 seconds
delay for each request.
For runing I set the locationRequest intervals within 2 seconds delay
for each request.
For runing I set the locationRequest intervals within 1 second delay
for each request.
Then, to save up more polylines when drawing the map, I take the same concept. If an user is walking it will trace a polyline each 30 polylines that have been made
public void drawTrack(GoogleMap googleMap) {
googleMap.clear(); //Clearing markers and polylines
PolylineOptions polyline_options = new PolylineOptions().addAll(mLinkedList)
.color(ContextCompat.getColor(mContext, R.color.colorAccent)).width(Constants.POLYLINE_WIDTH).geodesic(true);
// Adding the polyline to the map
Polyline polyline = googleMap.addPolyline(polyline_options);
// set the zindex so that the poly line stays on top of my tile overlays
polyline.setZIndex(1000);
// we add each polyline to an array of polylines
mPolylinesArray.add(polyline);
// We add the latest latlang points we got
mLatLngArray.add(mLinkedList.getLast());
//If we have made 30 polylines we store 1 line starting from that first point to the last, so we can save 28 polylines and draw one instead of having so many points for lets say 10 meters, this value must change depending on the activity, if biking, runing or walking
if (mLatLngArray.size() % 30 == 0) {
// First we delete all polylines saved at the array
for (Polyline pline : mPolylinesArray) {
pline.remove();
}
// We create a new polyline based on the first and last latlang from the 30 we took
Polyline routeSoFar = googleMap.addPolyline(new PolylineOptions().color(Color.GREEN).width(Constants.POLYLINE_WIDTH).geodesic(true));
// Draw the polyline
routeSoFar.setPoints(mLatLngArray);
// set the zindex so that the poly line stays on top of my tile overlays
routeSoFar.setZIndex(1000);
// Clear polyline array
mPolylinesArray.clear();
// Add polyline to array
mPolylinesArray.add(routeSoFar);
}
}
Where mLinkedList is an LinkedList<LatLng> so we can have the first and last element (if you want to draw a custom marker when activity starts and when activity finish )
mPolylinesArray is an array of Polylines ArrayList<Polyline>