Skip to content

Instantly share code, notes, and snippets.

@renegr
Last active December 10, 2016 08:52
Show Gist options
  • Save renegr/119e95e58a7a6d3b31da1bdb1b043a2d to your computer and use it in GitHub Desktop.
Save renegr/119e95e58a7a6d3b31da1bdb1b043a2d to your computer and use it in GitHub Desktop.
snake with eve
# 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