PICO-8 Wiki
(Added see also)
Tags: Visual edit apiedit
No edit summary
Tag: Visual edit
 
(10 intermediate revisions by 6 users not shown)
Line 1: Line 1:
  +
The game loop is the mechanism that drives a game's logic and rendering processes. Because each cycle of the loop updates the display, it is important for the loop to run at regular intervals to keep the animation smooth and the game feeling responsive to user input.
== Game Loop ==
 
A Game Loop refers to the steps taken in order while a game is running.
 
   
  +
PICO-8 has a built-in game loop that runs 30 times per second. You use this in your code by defining three functions: [[Init|_init()]], <code>[[Update|_update()]]</code>, and <code>[[Draw|_draw()]]</code>.
Pico-8 divides this into three major steps, [[Init]], [[Update]], and [[Draw]]. The Update-Draw loop runs 30 times per second.
 
   
  +
Both <code>_update()</code> and <code>_draw()</code> must be defined for PICO-8's game loop to execute. <code>_init()</code> is optional.
=== Init ===
 
Init is arguably not a part of the game loop, because it happens before the loop begins, however, it's still important as part of the overall architecture. Init can be called later to reinitialize a cartridge, as a handy reset button.
 
   
  +
Since version 0.1.4 only <code>_update()</code> or <code>_draw()</code> needs to exist to enable the game loop.
=== Update ===
 
Update is where you will store your game logic. Input and audio are handled here, as well as the calculations to bring the game to the next step. Update runs every frame, and is never skipped (unlike _draw(), which can be skipped).
 
   
  +
You can define <code>_update60()</code> instead of <code>_update()</code> to have your code run at 60 times per second.
=== Draw ===
 
Draw is where the graphics are handled. Here you can make calls to other functions to help manage game state, or you can handle all drawing directly inside of the _draw() function. _draw() can be skipped during a frame, however, should the calculations and draw time combined take longer than a 1/30th second window.
 
   
  +
<syntaxhighlight lang="lua">
=== See Also: ===
 
  +
-- initialize the position to be the center of the screen
* [[Init]]
 
  +
function _init()
* [[Update]]
 
  +
xpos = 64
* [[Draw]]
 
  +
ypos = 64
  +
end
  +
  +
-- update the position based on the player pressing buttons
  +
function _update()
  +
if (btn(0) and xpos > 0) xpos -= 1
  +
if (btn(1) and xpos < 127) xpos += 1
  +
if (btn(2) and ypos > 0) ypos -= 1
  +
if (btn(3) and ypos < 127) ypos += 1
  +
end
  +
  +
-- clear the screen, then draw a circle at the current position
  +
function _draw()
  +
cls()
  +
circfill(xpos, ypos, 10, 8)
  +
end
  +
</syntaxhighlight>
  +
 
== Init ==
  +
  +
The <code>[[Init|_init()]]</code> function is called once when the cartridge is initialized. It is not part of the main game loop. However, it is a good practice when using the game loop to put all statements that initialize the cartridge in this function, instead of using statements at the top level of your code.
  +
  +
PICO-8 calls <code>_init()</code> automatically before starting the game loop if the game loop is being used.
  +
 
== Update ==
  +
  +
The <code>[[Update|_update()]]</code> function is where the game performs all of its logic for the next frame. This is where you read user input, update the game world simulation, and start (asynchronous) music and sound events.
  +
  +
The <code>_update60()</code> function serves the same purpose but changes your cart to run 60 times per second instead of 30.
  +
 
== Draw ==
  +
  +
The <code>[[Draw|_draw()]]</code> function is where the game does all of the work to draw the current state of the game to the screen.
  +
  +
PICO-8 attempts to call both <code>_update()</code> and <code>_draw()</code> 30 times per second. If the code takes longer than 1/30th of a second to execute, PICO-8 will skip the occasional call to <code>_draw()</code> so that the game world simulation has a chance to "catch up" to real time. The player is less likely to notice a missing <code>_draw()</code> call than slowness in the game simulation.
  +
  +
== Writing your own game loop ==
  +
  +
If for some reason you want different behavior for your game loop than is provided by <code>[[Update|_update()]]</code> and <code>[[Draw|_draw()]]</code>, you can implement a custom loop in your own code.
  +
  +
At the end of each frame, the PICO-8 game loop copies the graphics buffer to the screen, then waits until the next tick of the frame timer. To do this in your code, call the <code>[[Flip|flip()]]</code> function.
  +
  +
You can use the <code>[[Stat|stat()]]</code> function to measure the amount of time between ticks of the frame timer is spent executing your code. If <code>stat(1)</code> returns a value greater than 1, that means you passed a frame deadline without calling <code>flip()</code>, and you might need to do less work during the next frame (such as skipping draw calls) to catch up. This is how the built-in game loop determines whether to skip a call to <code>_draw()</code>.
  +
 
== See Also: ==
  +
* <code>[[Init|_init()]]</code>
  +
* <code>[[Update|_update()]]</code>
  +
* <code>[[Draw|_draw()]]</code>
   
 
======<nowiki/>======
 
======<nowiki/>======

Latest revision as of 10:04, 5 March 2022

The game loop is the mechanism that drives a game's logic and rendering processes. Because each cycle of the loop updates the display, it is important for the loop to run at regular intervals to keep the animation smooth and the game feeling responsive to user input.

PICO-8 has a built-in game loop that runs 30 times per second. You use this in your code by defining three functions: _init(), _update(), and _draw().

Both _update() and _draw() must be defined for PICO-8's game loop to execute. _init() is optional.

Since version 0.1.4 only _update() or _draw() needs to exist to enable the game loop.

You can define _update60() instead of _update() to have your code run at 60 times per second.

-- initialize the position to be the center of the screen
function _init()
  xpos = 64
  ypos = 64
end

-- update the position based on the player pressing buttons
function _update()
  if (btn(0) and xpos > 0) xpos -= 1
  if (btn(1) and xpos < 127) xpos += 1
  if (btn(2) and ypos > 0) ypos -= 1
  if (btn(3) and ypos < 127) ypos += 1
end

-- clear the screen, then draw a circle at the current position
function _draw()
  cls()
  circfill(xpos, ypos, 10, 8)
end

Init[]

The _init() function is called once when the cartridge is initialized. It is not part of the main game loop. However, it is a good practice when using the game loop to put all statements that initialize the cartridge in this function, instead of using statements at the top level of your code.

PICO-8 calls _init() automatically before starting the game loop if the game loop is being used.

Update[]

The _update() function is where the game performs all of its logic for the next frame. This is where you read user input, update the game world simulation, and start (asynchronous) music and sound events.

The _update60() function serves the same purpose but changes your cart to run 60 times per second instead of 30.

Draw[]

The _draw() function is where the game does all of the work to draw the current state of the game to the screen.

PICO-8 attempts to call both _update() and _draw() 30 times per second. If the code takes longer than 1/30th of a second to execute, PICO-8 will skip the occasional call to _draw() so that the game world simulation has a chance to "catch up" to real time. The player is less likely to notice a missing _draw() call than slowness in the game simulation.

Writing your own game loop[]

If for some reason you want different behavior for your game loop than is provided by _update() and _draw(), you can implement a custom loop in your own code.

At the end of each frame, the PICO-8 game loop copies the graphics buffer to the screen, then waits until the next tick of the frame timer. To do this in your code, call the flip() function.

You can use the stat() function to measure the amount of time between ticks of the frame timer is spent executing your code. If stat(1) returns a value greater than 1, that means you passed a frame deadline without calling flip(), and you might need to do less work during the next frame (such as skipping draw calls) to catch up. This is how the built-in game loop determines whether to skip a call to _draw().

See Also:[]

[]