Last active
December 10, 2016 08:52
-
-
Save renegr/119e95e58a7a6d3b31da1bdb1b043a2d to your computer and use it in GitHub Desktop.
snake with eve
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# Snake | |
*Implemented with eve 0.2.2 (on master: 44b086e91de8a1a70b11f12a1d0f6a08aeda6c15)* | |
Start by adding a game board wich is 30x30 big. We will place the player in the middle. | |
``` | |
search | |
x = range[from:1, to:30] | |
y = range[from:1, to:30] | |
commit | |
[#game state:"menu" frame: 0 width: 30 height: 30] | |
[#cell x y content: "nothing"] | |
[#player position: [x: 15, y: 15] | |
length: 4 | |
velocity: [x: 1, y: 0] | |
next-velocity: [x:1 y: 0]] | |
``` | |
## The menu | |
Before we start a fresh game, the user needs to click the start button. | |
```eve | |
search | |
[#game state = "menu"] | |
bind @browser | |
[#div children: | |
[#button action:"start-game" text: "Click here to start"]] | |
``` | |
Here we go: | |
```eve | |
search @event @browser @session | |
[#click #direct-target element: [#button action = "start-game"]] | |
game = [#game] | |
commit | |
game.state := "playing" | |
``` | |
## The Board | |
We will draw the board only when we are in play state: | |
```eve | |
search | |
game = [#game state = "playing"] | |
cell = [#cell x y] | |
bind @browser | |
[#div style:[position: "relative"] children: | |
[#div cell text: "."]] | |
``` | |
Each cell will be placed at their respective position, which is calculated based on their x & y coordinate: | |
``` | |
search @browser @session | |
div = [#div cell] | |
bind @browser | |
div.style := [display:"inline-block" width: "10px" height:"10px" left:"{{cell.x * 10}}px" top:"{{cell.y * 10}}px" position: "absolute" overflow:"hidden"] | |
``` | |
### Coloring the cells | |
Each cell with content=nothing will be black: | |
``` | |
search @browser @session | |
[#div cell style] | |
cell.content = "nothing" | |
bind @browser | |
style <- [background-color: "black"] | |
``` | |
The players cell will be green: | |
``` | |
search @browser @session | |
[#div cell style] | |
cell.content = "player" | |
bind @browser | |
style <- [background-color: "green"] | |
``` | |
## The Player | |
We are going to change the cells content from "nothing" to "player", if the cell at current position has the content set to "nothing". | |
``` | |
search @browser @session | |
[#player position] | |
[#time frames] | |
cell = [#cell x = position.x | |
y = position.y | |
content = "nothing"] | |
commit | |
cell.content := "player" | |
cell.frame := frames | |
``` | |
When the players snake grew to big, we need to transform the players tail to the game board, by changing the content from "player" to "nothing". Every part of the snake that has an higher index then the player's length, will change the content to "nothing" again. | |
Eve's nature is unordered. **So how to do we know which of the cells are the "oldest**"? | |
Each player's cell has a "frame" attribute. This attribute is an evergrowing value, since the game started. Everytime we convert a "nothing" cell to a "player" cell, we store the frame-count along with the cell. For example: The first cell will be created at "frame" 30, the next at frame 40, and so on. Sorting by the frame attribute (descending) we can select all cells that have a greater index then the players snake. Done. Now we found those cells that no longer belong to the players snake. | |
```eve | |
search @browser @session | |
player = [#player] | |
cell = [#cell content = "player" frame] | |
length = count[given: cell] | |
is(length > player.length) | |
index = sort[value: frame direction: "down"] | |
index > player.length | |
commit | |
cell.content := "nothing" | |
``` | |
### Updating players position | |
We want to update the position every 3rd frame. | |
Not exactly sure why we need to catch frame != frames, but this has been taken from the flappy bird example. The game will not run without this constraint. | |
```eve | |
search @session | |
[#player position velocity next-velocity] | |
[#time frames] | |
game = [#game frame != frames] | |
// Update velocity if needed | |
vx = if velocity.x != next-velocity.x then next-velocity.x | |
else velocity.x | |
vy = if velocity.y != next-velocity.y then next-velocity.y | |
else velocity.y | |
value = mod[value: frames by:3] | |
value = 0 | |
commit @session | |
game <- [frame: frames] | |
velocity <- [x: vx, y: vy] | |
position <- [x: position.x + vx | |
y: position.y + vy] | |
``` | |
### Player goes offscreen | |
When the player goes offscreen, he will start on the opposite side again. | |
```eve | |
search | |
[#game width height] | |
[#player position] | |
(nx, ny) = if position.x > width then (0, position.y) | |
else if position.x < 0 then (width, position.y) | |
else if position.y > height then (position.x, 0) | |
else if position.y < 0 then (position.x, height) | |
commit | |
position <- [x: nx y: ny] | |
``` | |
### Keyboard (up,right,down,left) changes direction | |
We do not change velocity directly, instead we are going to modify next-velocity. | |
We are updating the position of the player in the frames-tick. Thus THIS is the actual place, where we want to update the actual velocity. Next-velocity will cue the update | |
```eve | |
search @event @session | |
ev = [#keyup key] | |
[#player velocity next-velocity] | |
(nx, ny) = if key = 38 then (0,-1) // up | |
else if key = 40 then (0,1) // down | |
else if key = 37 then (-1,0) //left | |
else if key = 39 then (1,0) //right | |
// Constrain opposite directions | |
rx = if nx = velocity.x * -1 then velocity.x | |
else nx | |
ry = if ny = velocity.y * -1 then velocity.y | |
else ny | |
commit | |
next-velocity.x := rx | |
next-velocity.y := ry | |
``` | |
## Todos | |
- Random fruits should be placed on screen, that the player can eat upon collision. Depending on the type of the fruit, the players snake should grow. | |
- Colliding with self or any other obstacle than fruit, should end the game | |
- Wishlist: multiplayer. | |
- |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment