I´m making an Android game (just to learn some stuff). You collect objects and you get points for that. When player reaches for example 200 points, the objects start coming faster, the background changes etc...It is like a next level. But when you reach those 200 points, I would like to show an image or text on the screen (something like "2 level") for like 2 seconds but I don´t know how.
I tried to work with the timer but I failed.
I´ve got an "if" statement
if (score >= 200) {
frameLayout.setBackgroundResource(R.drawable.lvl2); // background change
// Make objects go faster
collect_obj1 = Math.round(screenWidth / 57F);
collect_obj2 = Math.round(screenWidth / 33F);
critical_obj = Math.round(screenWidth / 42F); // If you hit this one = Game Over
characterLvl1.setImageResource(R.drawable.characterLvl2); // character change
}
Try this:
long start_time = System.currentTimeMillis();
long current_time = System.currentTimeMillis();
long time_limit = 2000; // In milliseconds: this is the time you want to show the
// object(2 sec)
while(current_time - start_time) != 2000) {
ShowObject(); //Here is where you show the object.
current_time = System.currentTimeMillis();
}
HideObject(); //Hide the object after the while loop
It should work. And of course implement it however you want, because this is not the cleanest code ever. Or if you want something more efficient with handlers, etc. see this:
Link to another similar question on StackOverflow
Edit: Made it a bit better.
Related
I ran into a problem, where doing everything on a single thread may lead to some lags. The problem is, when I start to create loads of new objects (like 300 per second), my physics rate drops.
I sort all rendering objects each frame, so I would know which one to draw in which order, this might be the reason why it can handle only so little, but even if that was removed, there still would be like max operations per update, otherwise physics will lag.
Any ideas on how to achieve the correct zOrder, or remove possible physics lags?
Or detach physics from rendering ... ?
My game loop:
while (isRunning) {
currentFrameTime = System.nanoTime();
passedTime = currentFrameTime - lastFrameTime;
lastFrameTime = currentFrameTime;
physicsPassedTime += passedTime;
updatePassedTime += passedTime;
if (physicsPassedTime >= (double) 1_000_000_000 / physicsRate) {
physicsPassedTime = 0;
PhysicsUpdate();
}
if (updatePassedTime >= (double) 1_000_000_000 / refreshRate) {
updatePassedTime = 0;
Update();
Render();
LateUpdate();
}
}
Looks like the best solution (as suggested in comments) will be to run a second loop on a second thread with just physics update, and everything else on the other thread.
That way frame drops should not intervene with the physic updates.
Edit: Implemented this, and works like charm. I'll mark the answer when I'll be able to.
I'm working on a game and I want my enemies to spawn with a delay between 1-5 seconds. My code for that part looks like this:
#Override
public void run() {
try {
while (true) {
Random r = new Random();
int cooldownTime = r.nextInt((5000 - 1000) + 1) + 1000;
long lastSpawn = 0;
long time = System.currentTimeMillis();
if (time > lastSpawn + cooldownTime) {
System.out.println(cooldownTime);
addEnemies();
lastSpawn = time;
}
If I understand nextInt correctly this should spawn enemies 1000-5000 ms apart every time, but my results are really weird and I can't quite figure out why. This is an example of what it would look like if I print cooldownTime.
2523
1190
1095
1061
1168
1119
1052
1159
1071
1076
1000
1394
1249
1070
And so on... It seems that the first enemy is truly spawned randomly and the others are always in the low 1000's. This happens every time. Does anyone know why it's like that? I'm quite lost.
Calling Random r = new Random(); repeatedly is extremely pathological and ruins the statistical properties of the generator. (The results you get are most likely a strong function of your system clock time.)
Do that step once and your results will be far better. (There are also more efficient ways to implement a delay than this - consider sleep - Java compilers are not yet optimising out burn loops.)
Note also that your observations are further complicated by the fact that you are not printing every number drawn.
Not sure if this your exact issue, but you had some problems with the logic of System.currentTimeMillis() and were just looking at the total current time and not the difference between the time.
Additionally you only want to look for a new random value once the if actually executes so you do not generate a Random number each loop iteration, but rather each time an enemy spawns you generate a new one for the next enemy.
Here is the modified code that takes all of this into account:
Random r = new Random();
long time = System.currentTimeMillis();
int cooldownTime = r.nextInt((5000 - 1000) + 1) + 1000;
while (true) {
long timeDifference = System.currentTimeMillis() - time;
if (timeDifference > cooldownTime) {
//addEnemies();
System.out.println(timeDifference); //Prints the time taken for enemy to spawn
cooldownTime = r.nextInt((5000 - 1000) + 1) + 1000;
time = System.currentTimeMillis(); //set the initial time again
}
}
This will generate a random number between 1000 and 5000 and execute the if block each time after the delay, resetting the values in the if to do it forever.
However, there are most likely better ways to add a delay to your logic like some comments pointed out(sleep), but this is the corrected logic for your method.
Well, first of all, several of your variables are being created INSIDE the loop. You need to move the creation of the Random object, as well as the lastSpawn and cooldown variables outside the loop. This is because the lastSpawn variable is being overwritten each time the loop executes with 0, meaning you're always checking if the current time is greater than 0. You need to store it outside the loop so that it will retain the last value you assigned to it. For the same reason, cooldown needs to be outside the loop because you're generating a new cooldown every loop, and System.currentTimeMillis() is ALWAYS going to be larger than it because System.currentTimeMillis() gets you the system time offset from January 1, 1970. Finally, as System.currentTimeMillis() is represented by a long, you'll want any time-related variables to be long as well, otherwise you could end up overflowing your variable if the current time in milliseconds is too high for an integer to store.
Here is a better way to achieve what you're looking to do:
import java.util.Random;
public class RandomCooldown {
public static void main(String [] args) {
Random rand = new Random();
long start = System.currentTimeMillis();
long lastSpawn = start;
long cooldown = getCooldown(rand);
while(true) {
long time = System.currentTimeMillis();
long elapsed = (time - lastSpawn);
if(elapsed >= cooldown) {
System.out.println("Adding enemies!");
cooldown = getCooldown(rand); // only generate a new cooldown once the old cooldown has been surpassed
lastSpawn = time;
}
}
}
public static long getCooldown(Random rand) {
return (long)((rand.nextInt(4000) + 1) + 1000);
}
}
Hope this helps!
Here is a suggestion that works as I think you like. I has not one but two loops. The outer loop generates new enemies and the inner loop makes updates (not sure how much of that this enemy generating thread needs to update but included it just in case).
public void run() {
Random r = new Random();
// setup
while (true) {
int wait = r.nextInt((5000 - 1000) + 1) + 1000;
long time = System.currentTimeMillis();
System.out.println("Adding enemies at " + time
+ ", next add roughly in " + wait + " ms.");
while (wait + time > System.currentTimeMillis()) {
try {
Thread.sleep(30);
} catch (InterruptedException e) {
e.printStackTrace();
}
// update
}
}
}
The Random object is reused and the call Thread.sleep(30) makes the thread hand over control for 30 ms, a time during which the CPU can do more useful things than busy wait. (30 is BTW not a magic number that must be used but just a number I chose. You need to experiment and find what number works best in your game.)
The print out shows what happens.
Adding enemies at 1565096018610, next add roughly in 2890 ms.
Adding enemies at 1565096021530, next add roughly in 2301 ms.
Adding enemies at 1565096023863, next add roughly in 4944 ms.
Adding enemies at 1565096028813, next add roughly in 3042 ms.
Adding enemies at 1565096031879, next add roughly in 2661 ms.
... and so on. The actual numbers will not be the same of course when you run this code but similar.
Hope this helps and good luck with your game!
It looks fine to me. You should probably use the same Random() instance for each iteration. And remember: humans have no ability to perceive randomness. Alternatively, you could try seeding the Random-Generator (using the Random(long seed) constructor), just in case there's some weird stuff happening with your seed.
I'm new to java and I'm trying to constantly add "zombie" entity to my game after a delay, and then shortening the delay as time goes on.
In my PlayState class I've got the code to spawn the entities in a position when my update(); method is run (which houses getInput(); and such. Not shown for clarity.)
public void update(long elapsed) {
this.entities.add(new Zombie(-535));
}
How would i make a delay that shortens? I'm guessing I would make the delay and then use a multiplier which i have getting smaller every 10 seconds or so, but how would I do this?
Now, I don't know much about the finer workings of your class, but this might give you a general idea of what I mean:
int counter = 50;
for(int i = 100; i >= 0; i--)
{
if(i == counter)
{
counter = counter / 2;
this.entities.add(new Zombie(-535));
}
}
Suppose i is the the total run-time of the game, and counter represents a percent of the game when you want to add a zombie.
If you want to add a zombie after 50% of the run-time (here, 100 seconds), then as the time reduces, you check if the time has come to add a zombie (Here, 50 seconds).
What I've done here is reduce the delay to half, and continue checking if the time has come to add a zombie.
Maybe you could call sleep on your thread of execution:
int sleepInMs = 5000
Thread.sleep(sleepInMs);
sleepInMs+=1000; //Then of course handle the case when sleepInMs == 0
Really need more information about your implementation.
For a simple delay, use "delay ms;"
Edit ms for the number of milliseconds you want. 1000 milliseconds is one second
This is just a hypothetical question, but could be a way to get around an issue I have been having.
Imagine you want to be able to time a calculation function based not on the answer, but on the time it takes to calculating. So instead of finding out what a + b is, you wish to continue perform some calculation while time < x seconds.
Look at this pseudo code:
public static void performCalculationsForTime(int seconds)
{
// Get start time
int millisStart = System.currentTimeMillis();
// Perform calculation to find the 1000th digit of PI
// Check if the given amount of seconds have passed since millisStart
// If number of seconds have not passed, redo the 1000th PI digit calculation
// At this point the time has passed, return the function.
}
Now I know that I am horrible, despicable person for using precious CPU cycles to simple get time to pass, but what I am wondering is:
A) Is this possible and would JVM start complaining about non-responsiveness?
B) If it is possible, what calculations would be best to try to perform?
Update - Answer:
Based on the answers and comments, the answer seems to be that "Yes, this is possible. But only if it is not done in Android main UI thread, because the user's GUI will be become unresponsive and will throw an ANR after 5 seconds."
A) Is this possible and would JVM start complaining about non-responsiveness?
It is possible, and if you run it in the background, neither JVM nor Dalvik will complain.
B) If it is possible, what calculations would be best to try to perform?
If the objective is to just run any calculation for x seconds, just keep adding 1 to a sum until the required time has reached. Off the top of my head, something like:
public static void performCalculationsForTime(int seconds)
{
// Get start time
int secondsStart = System.currentTimeMillis()/1000;
int requiredEndTime = millisStart + seconds;
float sum = 0;
while(secondsStart != requiredEndTime) {
sum = sum + 0.1;
secondsStart = System.currentTimeMillis()/1000;
}
}
You can and JVM won't complain if your code is not part of some complex system that actually tracks thread execution time.
long startTime = System.currentTimeMillis();
while(System.currentTimeMillis() - startTime < 100000) {
// do something
}
Or even a for loop that checks time only every 1000 cycles.
for (int i = 0; ;i++) {
if (i % 1000 == 0 && System.currentTimeMillis() - startTime < 100000)
break;
// do something
}
As for your second question, the answer is probably calculating some value that can always be improved upon, like your PI digits example.
The Problem I have ArrayList of "pellets". I'm pushing around 25 of them and they all bounce. However, for some reason they seem to go faster while render() is slower / takes more time (wut?) Please help me make it so that the 25 sprites smoothly glide about at a constant speed. It also jerks when only 5 sprites are onScreen.
Tried this stuff:
Reading around SO. They recommended getDeltaTime
Gdx.graphics.getDeltaTime() multiplying by pelletSpeed (no Change)
In the current code the pellets hop, jerk, and inconsistently sputter about almost unpredictably. I am assuming that it's going constant speed underneath the hood but honestly it's hard to tell
For Loop in Render:
String currentDir = pelletList.get(i).getDir();
String currentColor = pelletList.get(i).getColor6();
pelletSpeedElapsedTime = TimeUtils.nanoTime();
if(currentDir.equals("Up")) {
pelletList.get(i).y -= pelletSpeed * TimeUtils.timeSinceNanos(pelletSpeedElapsedTime);
if(pelletList.get(i).y < 0 ) {
pelletList.get(i).setDir("Down");
}
} else if (currentDir.equals("Down")) {
pelletList.get(i).y += pelletSpeed * TimeUtils.timeSinceNanos(pelletSpeedElapsedTime);
if(pelletList.get(i).y > screenHeight) {
pelletList.get(i).setDir("Up");
}
} else if (currentDir.equals("Left")) {
pelletList.get(i).x -= pelletSpeed * TimeUtils.timeSinceNanos(pelletSpeedElapsedTime);
if(pelletList.get(i).x < 0) {
pelletList.get(i).setDir("Right");
}
} else if (currentDir.equals("Right")) {
pelletList.get(i).x += pelletSpeed * TimeUtils.timeSinceNanos(pelletSpeedElapsedTime);
if(pelletList.get(i).x > screenWidth) {
pelletList.get(i).setDir("Left");
}
}
Thanks
The pelletSpeedElapsedTime = TimeUtils.nanoTime(); looks suspicious to me - you're getting this time, and then calculating elapsed time for bullets immediately afterward. Almost no time will have elapsed by then, and you won't be accounting at all for whatever time passes before the next call to whatever method this is.
I think (guessing at what the rest of your code is like) that you want to move that pelletSpeedElapsedTime assignment to the end of this method. The idea here is that you want to capture the time where you finished this update, so that the next time you update you know how much time has passed between updates (e.g. time spent rendering, sleeping, whatever.)
Doing this would mean that you'd have to handle the case where pelletSpeedElapsedTime hasn't been initialized, as well (maybe initialize it in the constructor? again, not sure of the broader context.) Also, I don't think all those TimeUtils.timeSinceNanos calls or necessary - I would call that once at the start of this section of code and use the value (to make sure the moving entities all get a consistent time delta, and to avoid the redundant call/calculation.)