Looking for some ideas on how to implement this, don't necessarily need the exact code.
Let's say I have a game where the player's hit points are displayed in a label, say 100HP. When he takes damage, say 30 damage, I want that label to count down from 99, 98 , 97 ... 70. It should take 2 seconds to perform the countdown whether you take 30 damage or 3000 damage.
I'm wondering what's the most efficient way to get this loop to count down "smoothly" over 2 seconds no matter what the damage taken is.
I'd probably extend a CCLabelSomething to do that, embedding the desired behaviour. Suggest a fixed width font, otherwise nothing smooth will happen (visually). Figure out what is 'smooth for you', ie how many updates in the 2 second period. in the assumed 'setScore' public method, start a scheduled update cycle with appropriate delay. In the schedule callback, change the text of the label.
say 20 updates, ie 10 per seconds. Schedule with .1f delay between intervals. Upon setScore, compute the 'delta' per update (currentScore - newScore)/20. Decrement currentScore down to newScore by this delta. In the schedule callBack, stop your scheduled update if the displayed score is equal to the newScore.
Related
I am looking to add a variable to count from 1 to 217 every hour in AnyLogic, in order to use as a choice condition to set a parameters row reference.
I am assuming I either need to use an event or a state chart however I am really struggling with the exact and cannot find anything online.
If you have any tips please let me know, any help would be appreciated
Thank you,
Tash
A state machine isn't necessary in this case as this can be achieve using a calculation or a timed event. AnyLogic has time() function which returns time since model start as a double in model time units of measurements.
For example: if model time units is seconds and it has been running for 2hr 2min 10sec then time(SECOND) will return 7330.0 (it is always a double value). 1/217th of an hour corresponds to about 3600/217 = 16.58 seconds. Also, java has a handy function Math.floor() which rounds down a double value, so Math.floor(8.37) = 8.0.
Assembling it all together:
// how many full hours have elapsed from the start of the model
double fullHrsFromStart = Math.floor(time(HOUR));
// how many seconds have elapsed in the current model hour
double secondsInCurrentHour = time(SECOND) - fullHrsFromStart * 3600.0;
// how many full 16.58 (1/217th of an hour) intervals have elapsed
int fullIntervals = (int)(secondsInCurrentHour / 16.58);
This can be packaged into a function and called any time and it is pretty fast.
Alternatively: an Event can be created which increments some count by 1 every 16.58 seconds and ten resets it back to 0 when the count reaches 217.
As far as I know, love.update and love.draw is called every frame. You can turn vsync off (unlimited calls to love.update) or leave it on (fixed to refresh rate). Since different computers have different refresh rates, you need to be able to support different ups's, otherwise the game will run at different speeds for different computers.
There are 2 solutions I can think of:
Cap UPS.
Run at an arbitrary UPS.
There were a few issues with 2, so I think a constant UPS might be better. My computer's refresh rate is 57Hz so I used that in the code.
function love.update(dt)
t = t + dt
while t >= 1/57 do
t = t - 1/57
--stuff
end
end
The game runs fine if I turn vsync on, but if it's off, then it's slightly jittery and I think it would probably be like that regardless of vsync on other PC's. Is there a way to cap the UPS better or should I just use solution 2?
you need to use the dt in update function,
let's say you have a sprite moving 1 pixel every frame
function love.update(dt)
sprite.x = sprite.x + 1
end
for you with a refresh rate of 57 fps the sprite will move of 57 pixel per second, but others would see it move at say 60 pixel per second
function love.update(dt)
sprite.x = sprite.x + 60*dt
end
now at 57 fps, you call 57 time update in one second and your sprite would move exactly 60 pixel (60*(1/57)*57), and others running at 60fps would also see it moving of 60 pixels (60*(1/60)*60)
using dt you are doing computation time relative, not frame relative discarding the problem altogether
It seems like you know how to set vsync, but here's the code I'm using in love.load() to set it:
love.window.setMode(1, 1, {vsync = false, fullscreen = true})
At the start of my update loop I have the following code:
self.t1 = love.timer.getTime()
This grabs the time at the beginning of the loop and is paired with the following code at the end end of the loop:
self.delta = love.timer.getTime() - self.t1
if self.delta < self.fps then
-- sleep to maintain 60fps
love.timer.sleep(self.fps - self.delta)
end
-- calculate frame rate
self.delta = love.timer.getTime() - self.t1
self.frameRate = 1 / self.delta
If your computer is able to run the update at faster than 60FPS then the game will sleep at the end of the update loop to enforce a constant frame rate. Unfortunately this only caps the frame rate (solution 1 in your post). That being said, this method runs with no jitters (I have tested on multiple Windows machines).
I believe I got this method from this link.
Be careful with vsync since some computer screens can run at different frame-rate (like 60fps, 120fps...). And even with computer screens that run at the same frame-rate, enabling vsync in love2d is a setting that can be overridden by the graphic card settings. So you should always consider using the delta-time (dt). Refer to #nepta answer to know how the delta-time should be used.
Actually have a LineStringField on my model, and need actualize this field every 15 seconds, i have a total of 300 points, this represent a problem in the asynchronous performance?.
I'm working on a 2D video game framework, and I've never written a game loop before. Most frameworks I've ever looked in to seem to implement both a draw and update methods.
For my project I implemented a loop that calls these 2 methods. I noticed with other frameworks, these methods don't always get called alternating. Some frameworks will have update run way more than draw does. Also, most of these types of frameworks will run at 60FPS. I figure I'll need some sort of sleep in here.
My question is, what is the best method for implementing this type of loop? Do I call draw then update, or vice versa? In my case, I'm writing a wrapper around SDL2, so maybe that library requires something to be setup in a certain way?
Here's some "pseudo" code I'm thinking of for the implementation.
loop do
clear_screen
draw
update
sleep(16.milliseconds)
break if window_is_closed
end
Though my project is being written in Crystal-Lang, I'm more looking for a general concept that could be applied to any language.
It depends what you want to achieve. Some games prefer the game logic to run more frequently than the frame rate (I believe Source games do this), for some games you may want the game logic to run less frequently (the only example of this I can think of is the servers of some multiplayer games, quite famously Overwatch).
It's important to consider as well that this is a question of resolution, not speed. A game with logic rate 120 and frame rate 60 is not necessarily running at x2 speed, any time critical operations within the game logic should be done relative to the clock*, not the tic rate, or your game will literally go into slow motion if the frames take too long to render.
I would recommend writing a loop like this:
loop do
time_until_update = (update_interval + time_of_last_update) - current_time
time_until_draw = (draw_interval + time_of_last_draw) - current_time
work_done = false
# Update the game if it's been enough time
if time_until_update <= 0
update
time_of_last_update = current_time
work_done = true
end
# Draw the screen if it's been enough time
if time_until_draw <= 0
clear_screen
draw
time_of_last_draw = current_time
work_done = true
end
# Nothing to do, sleep for the smallest period
if work_done == false
smaller = time_until_update
if time_until_draw < smaller
smaller = time_until_draw
end
sleep_for(smaller)
end
# Leave, maybe
break if window_is_closed
end
You don't want to wait for 16ms every frame otherwise you might end up over-waiting if the frame takes a non-trivial amount of time to complete. The work_done variable is so that we know whether or not the intervals we calculated at the start of the loop are still valid, we may have done 5ms of work, which would throw our sleeping completely off so in that scenario we go back around and calculate fresh values.
* You may want to abstractify the clock, using the clock directly can have some weird effects, for example if you save the game and you save the last time you used a magical power as a clock time, it will instantly come off cooldown when you load the save, as that is now minutes, hours or even days in the past. Similar issues exist with the process being suspended by the operating system.
This is more of an open discussion topic than anything else. Currently I'm storing 50 Float32 values in my NSMutableArray *voltageArray before I refresh my CPTPlot *plot. Every time I obtain 50 values, I remove the previous 50 from the voltageArray and repeat the process....always displaying the 50 values in "real time" on my plot.
However, the data I'm receiving (which is voltage coming from a Cypress BLE module equipped with a pressure transducer) is so quick that any variation (0.4 V to 4.0 V; no pressure to lots of pressure) cannot be seen on my graph. It just shows up as a straight line, varying up and down without showing increased or decreased slopes.
To show overall change, I wanted to take those 50 values, store them in the first index of another NSMutableArray *stampArray and use the index of stampArray to display information. Meanwhile, the numberOfRecordsForPlot: method would look like this:
- (NSUInteger)numberOfRecordsForPlot:(CPTPlot *)plotnumberOfRecords {
return (DATA_PER_STAMP * _stampCount);
}
This would initially be 50, then after 50 pieces of data are captured from the BLE module, _stampCount would increase by one, and the number of records for plot would increase by 50 (till about 2500-10000 range, then I'd refresh the whole the thing and restart the process.)
Is this the right approach? How would I be able to make the first 50 points stay on the graph, while building the next 50, etc.? Imagine an y = x^2 graph, and what the graph looks like when applying integration (the whole breaking the area under the curve into rectangles).
Look at the "Real Time Plot" demo in the Plot Gallery example app included with Core Plot. It starts off with an empty plot, adding a new point each cycle until reaching the maximum number of points. After that, one old point is removed for each new one added so the total number stays constant. The demo uses a timer to pass random data to the plot, but your app can of course collect data from anywhere. Be sure to always interact with the graph from the main thread.
I doubt you'll be able to display 10,000 data points on one plot (does your display have enough pixels to resolve that many points?). If not, you'll get much better drawing performance if you filter and/or smooth the data to remove some of the points before sending them to the plot.