Skip to content

Commit

Permalink
Better docs
Browse files Browse the repository at this point in the history
  • Loading branch information
aviks committed Aug 19, 2020
1 parent 7884b85 commit 33094c6
Show file tree
Hide file tree
Showing 7 changed files with 112 additions and 18 deletions.
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,6 @@
/dev/
/docs/build/
/docs/site/
docs/Manifest.toml
docs/gzexamples
docs/src/examples
22 changes: 19 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,27 @@ A zero overhead game development framework for beginners.
## Overview
The aim of this package is to remove accidental complexity from the game development process. We therefore always choose simplicity and consistency over features. The users of this package will include young programmers learning their first language, maybe moving on from Scratch. While we aim to support reasonably sophisticated 2D games, our first priority will remain learners, and their teachers.

## Example
The best way to learn how to use this package is by looking at code. There are some simple examples in the [example subdirectory](https://github.com/aviks/GameZero.jl/tree/master/example/BasicGame). More comprehensive examples are listed in the [GZExamples](https://github.com/SquidSinker/GZExamples) repository.
## Running Games

Games created using GameZero are `.jl` files that live in any directory.
To play the games, start the Julia REPL and:

```
pkg> add GameZero
pkg> add Colors
julia> using GameZero
julia> rungame("C:\\path\\to\\game\\Spaceship\\Spaceship.jl")
```

## Creating Games
[Read the documentation](https://juliahub.com/docs/GameZero/tTDGf/) to get started. The best way to learn how to use this package is by looking at existing games created with it. There are some simple examples in the [example subdirectory](https://github.com/aviks/GameZero.jl/tree/master/example/BasicGame). More comprehensive examples are listed in the [GZExamples](https://github.com/SquidSinker/GZExamples) repository. The documentation will also display the example sources.

## Status
This is an early release. Please try to make interesting games with this, and report any issues or missing features.
This is an early release. Please try to make new games, and [report](https://github.com/aviks/GameZero.jl/issues) any bugs, usability issues or missing features. We particularly welcome more games in the [GZExamples](https://github.com/SquidSinker/GZExamples) repository.

## Acknowledgement
The design of this library is inspired by the python package [PyGameZero](https://pygame-zero.readthedocs.io) by [Daniel Pope](https://github.com/lordmauve). Much of the design however has been changed to make things more Julian, and the implementation is independent.
2 changes: 2 additions & 0 deletions docs/Project.toml
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
[deps]
Documenter = "e30172f5-a6a5-5a46-863b-614d45cd2de4"
GameZero = "9da27670-f782-11e9-1da1-f53579315bfe"
LibGit2 = "76f85450-5226-5b5a-8eaa-529ad045b433"
Literate = "98b081ad-f1c9-55d3-8b20-4c87d4299306"
33 changes: 30 additions & 3 deletions docs/make.jl
Original file line number Diff line number Diff line change
@@ -1,16 +1,43 @@
using Documenter, GameZero
using Literate
using LibGit2

out_path = "src/examples"
rm("gzexamples"; force=true, recursive=true)
rm(out_path; force=true, recursive=true )

LibGit2.clone("https://github.com/SquidSinker/GZExamples", "gzexamples")

config = Dict{Any, Any}("documenter"=>false, "execute"=>false, "credit"=>false)
Literate.markdown("../example/BasicGame/basic.jl", out_path; config=config)
Literate.markdown("../example/BasicGame/basic2.jl", out_path; config=config)
config["repo_root_url"] = "https://github.com/SquidSinker/GZExamples"
config["repo_root_path"] = "gzexamples"
Literate.markdown("gzexamples/Breakout/Breakout.jl", out_path; config=config)
Literate.markdown("gzexamples/Spaceship/Spaceship.jl", out_path; config=config)
Literate.markdown("gzexamples/Pandemic Sim/pandemicsim.jl", out_path; config=config)
Literate.markdown("gzexamples/Galaxian/Galaxian.jl", out_path; config=config)
Literate.markdown("gzexamples/Flappy bird/flappybird.jl", out_path; config=config)

makedocs(;
modules=[GameZero],
format=Documenter.HTML(),
pages=[
"Home" => "index.md",
"Examples" => Any[
"Basic Game 1" => "examples/basic.md",
"Basic Game 2" => "examples/basic2.md",
"BreakOut" => "examples/Breakout.md",
"Spaceship" => "examples/Spaceship.md",
"Pandemic Sim" => "examples/pandemicsim.md",
"Galaxian" => "examples/Galaxian.md",
"Flappy Bird" => "examples/flappybird.md",

],
"API" => "api.md"
],
repo="https://github.com/aviks/GameZero.jl/blob/{commit}{path}#L{line}",
sitename="GameZero.jl",
authors="Avik Sengupta",
assets=String[],
authors="Avik Sengupta"
)

deploydocs(;
Expand Down
35 changes: 29 additions & 6 deletions docs/src/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ The best way to learn how to use this package is by looking at code. There are s

## Assets
![](assets/directory_structure.png)

Each game, and its assets, are stored in a separate directory. Within this directory, there is a .jl file, which stores the game code. As well as this, there are three subfolders for sounds, images, and music. The games are executed using the rungame function provided by the Game Zero package, meaning that games do not have to be Julia packages or modules, making it much simpler. An empty file also counts as a valid game.

## Initialising a screen
Expand All @@ -17,7 +18,7 @@ HEIGHT
WIDTH
BACKGROUND
```
All of these are optional, and if not specified, will default to 400*400, and a white background
All of these are optional, and if not specified, will default to 400x400, and a white background. `HEIGHT` and `WIDTH` should be integers, and `BACKGROUND` should be set to a `Colorant` object from [Colors](https://juliahub.com/ui/Packages/Colors/NKjaT)

## Actors
Game objects on-screen are represented as `Actors` which have several associated attributes. Using `Actors`, you can change position, change the image and check for collisions. However, not all moving parts need to be Actors as those without a specific image can be defined as a `Circle` or a `Rect`, which have the same associated attributes (apart from image). `Actors` are usually the primary game objects that you move around.
Expand All @@ -26,19 +27,41 @@ Game objects on-screen are represented as `Actors` which have several associated
GameZero.jl also includes basic geometric shapes. `Rects`, `Circles` and `Lines` can be used to do everything an `Actor` can, having the same attributes (apart from image).

## Moving objects
All objects have many attributes to define position. The corners — `topleft`, `topright`, `bottomleft`, and `bottomright` — are tuples (x and y coordinates). The sides — `top`, `bottom`, `left` and `right` — read either the x or y coordinate (top and bottom are x, left and right are y). These position attributes can be used either to read position or to set position. In addition, objects also have an x and y attribute which are anchored to the top left of the objects.
All objects have many attributes to define position. The corners — `topleft`, `topright`, `bottomleft`, and `bottomright` — are tuples (x and y coordinates). The sides — `top`, `bottom`, `left` and `right` — read either the x or y coordinate (top and bottom are x, left and right are y). These position attributes can be used either to read position or to set position. In addition, objects also have an `x` and `y` attribute which are anchored to the top left of the objects. Finally, the `position` attribute is a synomym for `topleft`

## Draw and Update methods
These functions are run by the game engine automatically every frame, meaning developers do not have to define their own event loop. The `update` function is used to change game state and attributes of the Actors and the `draw` function renders on-screen objects.
You write a game by defining your own `draw` and `update` methods. These functions are run by the game engine automatically every frame, meaning developers do not have to define their own event loop. The `update` function is used to change game state and attributes of the Actors and the `draw` function renders on-screen objects.

The `draw` method can be defined to take zero or one argument. If present, the single argument is the `Game` object. In other words, define one of

`function draw() .... end`
`function draw(g::Game) .... end`

The `update` method can be defined to take zero, one or two arguments. The first argument is the `Game` object, and the second argument is the the time step from the previous frame.

`function update() .... end`
`function update(g::Game) .... end`
`function update(g::Game, dt) .... end`

## Keyboard inputs
To take an instantaneous input, use the `on_key_down`. For a constant input, such as for movement, use an if statement in the update function to check the value of the keyboard attribute of the game object (`g.keyboard`).
To take an instantaneous input, define the `on_key_down()` in your game. This function can take upto three postional arguments: The `Game` object, the `key` and the `keymod`. You can define the function with zero, one, two or three arguments, depending on which values you need. However, since the
arguments are positional, the order matters.

In other words, you can define one of:

`function on_key_down() .... end`
`function on_key_down(g) .... end`
`function on_key_down(g, key) .... end`
`function on_key_down(g, key, keymod) .... end`


For a constant input, such as for movement, you can check for keypress within the `update` function, via the `keyboard` attribute of the game object (`g.keyboard`).

## Mouse input
Mouse movement can be tracked using the `on_mouse_move` function. For mouse clicks, use the `on_mouse_down` function.
Mouse movement can be tracked defining the `on_mouse_move` function in your game. The inputs to the function should be the `Game` object, and the mouse position as a tuple of numbers. For mouse clicks, use the `on_mouse_down` function, which takes as input the `Game` object, position, and the button.

## Playing sounds
To play sound effects, you can use the `play_sound` function. To play music on a loop, use the `play_music` function.
To play sound effects, you can call the `play_sound` function. To play music on a loop, call the `play_music` function. Both these functions can take `.wav`, `.mp3` and `.ogg` files.

## Timers
To set a timer in a normal program, `sleep` would be used. However, in this instance, this would cause the whole game to pause for that amount of time. Therefore, to avoid having to use a complicated `@async` loop, you can use the function `schedule_once`, which takes a function and a time in seconds, and sets the function to run after that amount of time.
Expand Down
19 changes: 16 additions & 3 deletions example/BasicGame/basic.jl
Original file line number Diff line number Diff line change
@@ -1,22 +1,32 @@

# Height of the game window
HEIGHT = 400
# Width of the game window
WIDTH = 400
# Background color of the game window
BACKGROUND = colorant"purple"
count = 1

# Globals to store the velocity of the actor
dx = 2
dy = 2

# Create an `Actor` object with an image
a=Actor("alien.png")

# Start playing background music
play_music("radetzky_ogg")

# The draw function is called by the framework. All we do here is draw the Actor
function draw(g::Game)
draw(a)
end

# The update function is called every frame. Within the function, we
# * change the position of the actor by the velocity
# * if the actor hits the edges, we invert the velocity, and play a sound
# * if the up/down/left/right keys are pressed, we change the velocity to move the actor in the direction of the keypress
function update(g::Game)
global count, dx, dy
count = count+1
global dx, dy
a.position.x += dx
a.position.y += dy
if a.x > 400-a.w || a.x < 2
Expand All @@ -40,12 +50,15 @@ function update(g::Game)

end

# If the "space" key is pressed, change the displayed image to the "hurt" variant.
# Also schedule an event to change it back to normal after one second.
function on_key_down(g, k)
if k == Keys.SPACE
alien_hurt()
schedule_once(alien_normal, 1)
end
end

# We define functions to change the image for the actor. These functions are called from the keydown and scheduled events.
alien_hurt() = a.image = "alien_hurt.png"
alien_normal() = a.image = "alien.png"
16 changes: 13 additions & 3 deletions example/BasicGame/basic2.jl
Original file line number Diff line number Diff line change
@@ -1,10 +1,17 @@

# Height of the screen
HEIGHT = 200
# Width of the screen
WIDTH = 400
# Global variables to store a range of colors.
# The Colors package is always imported into a game
colors = range(colorant"black", colorant"white")
current_color, color_state = iterate(colors)

function draw(g::Game)
# The draw function is called once per frame to render objects to the screen.
# In our game, we only define the `draw` function, it's called by the engine.
# Within the function, we draw the individual elements, in this case line, rectangles and circles
function draw()
fill(current_color)
draw(Line(50, 100, 350, 100), colorant"white")
draw(Rect(50, 100, 20, 50), colorant"red", fill=true)
Expand All @@ -17,7 +24,11 @@ function draw(g::Game)

end

function update(g::Game)
# The update function is called once per frame by the game engine, and should be used
# to change the game state. In this case, we iterate through the color range, and store
# the current color in a global variable. The global value is then used in the `draw`
# function to render the screen background
function update()
global current_color
global color_state
i = iterate(colors, color_state)
Expand All @@ -27,5 +38,4 @@ function update(g::Game)
reverse!(colors)
current_color, color_state = iterate(colors)
end

end

0 comments on commit 33094c6

Please sign in to comment.