dep -> govendor

This commit is contained in:
2018-03-18 05:53:01 +00:00
parent 93fb27403b
commit 88acc05085
1033 changed files with 754817 additions and 113 deletions

View File

@@ -0,0 +1,16 @@
# bouncing
Bouncing particles using the [imdraw](https://godoc.org/github.com/faiface/pixel/imdraw) package.
Made by [Peter Hellberg](https://github.com/peterhellberg/) as part of his [pixel-experiments](https://github.com/peterhellberg/pixel-experiments)
## Screenshots
![bouncing animation](https://user-images.githubusercontent.com/565124/32401910-7cd87fb2-c119-11e7-8121-7fb46e5e11a8.gif)
![bouncing screenshot](screenshot.png)
## Links
- https://github.com/peterhellberg/pixel-experiments/tree/master/bouncing
- https://gist.github.com/peterhellberg/674f32a15a7d2d249e634ce781f333e8

View File

@@ -0,0 +1,303 @@
package main
import (
"image/color"
"math"
"math/rand"
"time"
"github.com/faiface/pixel"
"github.com/faiface/pixel/imdraw"
"github.com/faiface/pixel/pixelgl"
)
var (
w, h, s, scale = float64(640), float64(360), float64(2.3), float64(32)
p, bg = newPalette(Colors), color.RGBA{32, p.color().G, 32, 255}
balls = []*ball{
newRandomBall(scale),
newRandomBall(scale),
}
)
func run() {
win, err := pixelgl.NewWindow(pixelgl.WindowConfig{
Bounds: pixel.R(0, 0, w, h),
VSync: true,
Undecorated: true,
})
if err != nil {
panic(err)
}
imd := imdraw.New(nil)
imd.EndShape = imdraw.RoundEndShape
imd.Precision = 3
go func() {
start := time.Now()
for range time.Tick(16 * time.Millisecond) {
bg = color.RGBA{32 + (p.color().R/128)*4, 32 + (p.color().G/128)*4, 32 + (p.color().B/128)*4, 255}
s = pixel.V(math.Sin(time.Since(start).Seconds())*0.8, 0).Len()*2 - 1
scale = 64 + 15*s
imd.Intensity = 1.2 * s
}
}()
for !win.Closed() {
win.SetClosed(win.JustPressed(pixelgl.KeyEscape) || win.JustPressed(pixelgl.KeyQ))
if win.JustPressed(pixelgl.KeySpace) {
for _, ball := range balls {
ball.color = ball.palette.next()
}
}
if win.JustPressed(pixelgl.KeyEnter) {
for _, ball := range balls {
ball.pos = center()
ball.vel = randomVelocity()
}
}
imd.Clear()
for _, ball := range balls {
imd.Color = ball.color
imd.Push(ball.pos)
}
imd.Polygon(scale)
for _, ball := range balls {
imd.Color = color.RGBA{ball.color.R, ball.color.G, ball.color.B, 128 - uint8(128*s)}
imd.Push(ball.pos)
}
imd.Polygon(scale * s)
for _, ball := range balls {
aliveParticles := []*particle{}
for _, particle := range ball.particles {
if particle.life > 0 {
aliveParticles = append(aliveParticles, particle)
}
}
for _, particle := range aliveParticles {
imd.Color = particle.color
imd.Push(particle.pos)
imd.Circle(16*particle.life, 0)
}
}
win.Clear(bg)
imd.Draw(win)
win.Update()
}
}
func main() {
rand.Seed(4)
go func() {
for range time.Tick(32 * time.Millisecond) {
for _, ball := range balls {
go ball.update()
for _, particle := range ball.particles {
go particle.update()
}
}
}
}()
pixelgl.Run(run)
}
func newParticleAt(pos, vel pixel.Vec) *particle {
c := p.color()
c.A = 5
return &particle{pos, vel, c, rand.Float64() * 1.5}
}
func newRandomBall(radius float64) *ball {
return &ball{
center(), randomVelocity(),
math.Pi * (radius * radius),
radius, p.random(), p, []*particle{},
}
}
func center() pixel.Vec {
return pixel.V(w/2, h/2)
}
func randomVelocity() pixel.Vec {
return pixel.V((rand.Float64()*2)-1, (rand.Float64()*2)-1).Scaled(scale / 4)
}
type particle struct {
pos pixel.Vec
vel pixel.Vec
color color.RGBA
life float64
}
func (p *particle) update() {
p.pos = p.pos.Add(p.vel)
p.life -= 0.03
switch {
case p.pos.Y < 0 || p.pos.Y >= h:
p.vel.Y *= -1.0
case p.pos.X < 0 || p.pos.X >= w:
p.vel.X *= -1.0
}
}
type ball struct {
pos pixel.Vec
vel pixel.Vec
mass float64
radius float64
color color.RGBA
palette *Palette
particles []*particle
}
func (b *ball) update() {
b.pos = b.pos.Add(b.vel)
var bounced bool
switch {
case b.pos.Y <= b.radius || b.pos.Y >= h-b.radius:
b.vel.Y *= -1.0
bounced = true
if b.pos.Y < b.radius {
b.pos.Y = b.radius
} else {
b.pos.Y = h - b.radius
}
case b.pos.X <= b.radius || b.pos.X >= w-b.radius:
b.vel.X *= -1.0
bounced = true
if b.pos.X < b.radius {
b.pos.X = b.radius
} else {
b.pos.X = w - b.radius
}
}
for _, a := range balls {
if a != b {
d := a.pos.Sub(b.pos)
if d.Len() > a.radius+b.radius {
continue
}
pen := d.Unit().Scaled(a.radius + b.radius - d.Len())
a.pos = a.pos.Add(pen.Scaled(b.mass / (a.mass + b.mass)))
b.pos = b.pos.Sub(pen.Scaled(a.mass / (a.mass + b.mass)))
u := d.Unit()
v := 2 * (a.vel.Dot(u) - b.vel.Dot(u)) / (a.mass + b.mass)
a.vel = a.vel.Sub(u.Scaled(v * b.mass))
b.vel = b.vel.Add(u.Scaled(v * a.mass))
bounced = true
}
}
if bounced {
b.color = p.next()
b.particles = append(b.particles,
newParticleAt(b.pos, b.vel.Rotated(1).Scaled(rand.Float64())),
newParticleAt(b.pos, b.vel.Rotated(2).Scaled(rand.Float64())),
newParticleAt(b.pos, b.vel.Rotated(3).Scaled(rand.Float64())),
newParticleAt(b.pos, b.vel.Rotated(4).Scaled(rand.Float64())),
newParticleAt(b.pos, b.vel.Rotated(5).Scaled(rand.Float64())),
newParticleAt(b.pos, b.vel.Rotated(6).Scaled(rand.Float64())),
newParticleAt(b.pos, b.vel.Rotated(7).Scaled(rand.Float64())),
newParticleAt(b.pos, b.vel.Rotated(8).Scaled(rand.Float64())),
newParticleAt(b.pos, b.vel.Rotated(9).Scaled(rand.Float64())),
newParticleAt(b.pos, b.vel.Rotated(10).Scaled(rand.Float64()+1)),
newParticleAt(b.pos, b.vel.Rotated(20).Scaled(rand.Float64()+1)),
newParticleAt(b.pos, b.vel.Rotated(30).Scaled(rand.Float64()+1)),
newParticleAt(b.pos, b.vel.Rotated(40).Scaled(rand.Float64()+1)),
newParticleAt(b.pos, b.vel.Rotated(50).Scaled(rand.Float64()+1)),
newParticleAt(b.pos, b.vel.Rotated(60).Scaled(rand.Float64()+1)),
newParticleAt(b.pos, b.vel.Rotated(70).Scaled(rand.Float64()+1)),
newParticleAt(b.pos, b.vel.Rotated(80).Scaled(rand.Float64()+1)),
newParticleAt(b.pos, b.vel.Rotated(90).Scaled(rand.Float64()+1)),
)
}
}
func newPalette(cc []color.Color) *Palette {
colors := []color.RGBA{}
for _, v := range cc {
if c, ok := v.(color.RGBA); ok {
colors = append(colors, c)
}
}
return &Palette{colors, len(colors), 0}
}
type Palette struct {
colors []color.RGBA
size int
index int
}
func (p *Palette) clone() *Palette {
return &Palette{p.colors, p.size, p.index}
}
func (p *Palette) next() color.RGBA {
if p.index++; p.index >= p.size {
p.index = 0
}
return p.colors[p.index]
}
func (p *Palette) color() color.RGBA {
return p.colors[p.index]
}
func (p *Palette) random() color.RGBA {
p.index = rand.Intn(p.size)
return p.colors[p.index]
}
var Colors = []color.Color{
color.RGBA{190, 38, 51, 255},
color.RGBA{224, 111, 139, 255},
color.RGBA{73, 60, 43, 255},
color.RGBA{164, 100, 34, 255},
color.RGBA{235, 137, 49, 255},
color.RGBA{247, 226, 107, 255},
color.RGBA{47, 72, 78, 255},
color.RGBA{68, 137, 26, 255},
color.RGBA{163, 206, 39, 255},
color.RGBA{0, 87, 132, 255},
color.RGBA{49, 162, 242, 255},
color.RGBA{178, 220, 239, 255},
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.9 KiB

View File

@@ -0,0 +1,20 @@
# Conway's Game of Lfe
Created by [Nathan Leniz](https://github.com/terakilobyte).
Inspired by and heavily uses [the doc](https://golang.org/doc/play/life.go)
> The Game of Life, also known simply as Life, is a cellular automaton devised by the British mathematician John Horton Conway in 1970. The "game" is a zero-player game, meaning that its evolution is determined by its initial state, requiring no further input. One interacts with the Game of Life by creating an initial configuration and observing how it evolves, or, for advanced "players", by creating patterns with particular properties. The Game has been reprogrammed multiple times in various coding languages.
For more information, please see the [wikipedia](https://en.wikipedia.org/wiki/Conway%27s_Game_of_Life) article.
## Use
go run main.go -h
-frameRate duration
The framerate in milliseconds (default 33ms)
-size int
The size of each cell (default 5)
-windowSize float
The pixel size of one side of the grid (default 800)
![life](life.png)

Binary file not shown.

After

Width:  |  Height:  |  Size: 86 KiB

View File

@@ -0,0 +1,74 @@
package life
import (
"github.com/faiface/pixel"
"github.com/faiface/pixel/imdraw"
"golang.org/x/image/colornames"
)
// Shamelessly taken/inspired by https://golang.org/doc/play/life.go
// Grid is the structure in which the cellular automota live
type Grid struct {
h int
cellSize int
Cells [][]bool
}
// NewGrid constructs a new Grid
func NewGrid(h, size int) *Grid {
cells := make([][]bool, h)
for i := 0; i < h; i++ {
cells[i] = make([]bool, h)
}
return &Grid{h: h, cellSize: size, Cells: cells}
}
// Alive returns whether the specified position is alive
func (g *Grid) Alive(x, y int) bool {
x += g.h
x %= g.h
y += g.h
y %= g.h
return g.Cells[y][x]
}
// Set sets the state of a specific location
func (g *Grid) Set(x, y int, state bool) {
g.Cells[y][x] = state
}
// Draw draws the grid
func (g *Grid) Draw(imd *imdraw.IMDraw) {
for i := 0; i < g.h; i++ {
for j := 0; j < g.h; j++ {
if g.Alive(i, j) {
imd.Color = colornames.Black
} else {
imd.Color = colornames.White
}
imd.Push(
pixel.V(float64(i*g.cellSize), float64(j*g.cellSize)),
pixel.V(float64(i*g.cellSize+g.cellSize), float64(j*g.cellSize+g.cellSize)),
)
imd.Rectangle(0)
}
}
}
// Next returns the next state
func (g *Grid) Next(x, y int) bool {
// Count the adjacent cells that are alive.
alive := 0
for i := -1; i <= 1; i++ {
for j := -1; j <= 1; j++ {
if (j != 0 || i != 0) && g.Alive(x+i, y+j) {
alive++
}
}
}
// Return next state according to the game rules:
// exactly 3 neighbors: on,
// exactly 2 neighbors: maintain current state,
// otherwise: off.
return alive == 3 || alive == 2 && g.Alive(x, y)
}

View File

@@ -0,0 +1,35 @@
// Package life manages the "game" state
// Shamelessly taken from https://golang.org/doc/play/life.go
package life
import "math/rand"
// Life stores the state of a round of Conway's Game of Life.
type Life struct {
A, b *Grid
h int
}
// NewLife returns a new Life game state with a random initial state.
func NewLife(h, size int) *Life {
a := NewGrid(h, size)
for i := 0; i < (h * h / 2); i++ {
a.Set(rand.Intn(h), rand.Intn(h), true)
}
return &Life{
A: a, b: NewGrid(h, size),
h: h,
}
}
// Step advances the game by one instant, recomputing and updating all cells.
func (l *Life) Step() {
// Update the state of the next field (b) from the current field (a).
for y := 0; y < l.h; y++ {
for x := 0; x < l.h; x++ {
l.b.Set(x, y, l.A.Next(x, y))
}
}
// Swap fields a and b.
l.A, l.b = l.b, l.A
}

View File

@@ -0,0 +1,64 @@
package main
import (
"flag"
"math/rand"
"time"
"golang.org/x/image/colornames"
"github.com/faiface/pixel"
"github.com/faiface/pixel/examples/community/game_of_life/life"
"github.com/faiface/pixel/imdraw"
"github.com/faiface/pixel/pixelgl"
)
var (
size *int
windowSize *float64
frameRate *time.Duration
)
func init() {
rand.Seed(time.Now().UnixNano())
size = flag.Int("size", 5, "The size of each cell")
windowSize = flag.Float64("windowSize", 800, "The pixel size of one side of the grid")
frameRate = flag.Duration("frameRate", 33*time.Millisecond, "The framerate in milliseconds")
flag.Parse()
}
func main() {
pixelgl.Run(run)
}
func run() {
cfg := pixelgl.WindowConfig{
Title: "Pixel Rocks!",
Bounds: pixel.R(0, 0, *windowSize, *windowSize),
VSync: true,
}
win, err := pixelgl.NewWindow(cfg)
if err != nil {
panic(err)
}
win.Clear(colornames.White)
// since the game board is square, rows and cols will be the same
rows := int(*windowSize) / *size
gridDraw := imdraw.New(nil)
game := life.NewLife(rows, *size)
tick := time.Tick(*frameRate)
for !win.Closed() {
// game loop
select {
case <-tick:
gridDraw.Clear()
game.A.Draw(gridDraw)
gridDraw.Draw(win)
game.Step()
}
win.Update()
}
}

View File

@@ -0,0 +1,13 @@
# Isometric view basics
Created by [Sergio Vera](https://github.com/svera).
Isometric view is a display method used to create an illusion of 3D for an otherwise 2D game - sometimes referred to as pseudo 3D or 2.5D.
Implementing an isometric view can be done in many ways, but for the sake of simplicity we'll implement a tile-based approach, which is the most efficient and widely used method.
In the tile-based approach, each visual element is broken down into smaller pieces, called tiles, of a standard size. These tiles will be arranged to form the game world according to pre-determined level data - usually a 2D array.
For a detailed explanation about the maths behind this, read [http://clintbellanger.net/articles/isometric_math/](http://clintbellanger.net/articles/isometric_math/).
![Result](result.png)

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

View File

@@ -0,0 +1,102 @@
package main
import (
"image"
"os"
"github.com/faiface/pixel"
"github.com/faiface/pixel/pixelgl"
_ "image/png"
)
const (
windowWidth = 800
windowHeight = 800
// sprite tiles are squared, 64x64 size
tileSize = 64
f = 0 // floor identifier
w = 1 // wall identifier
)
var levelData = [][]uint{
{f, f, f, f, f, f}, // This row will be rendered in the lower left part of the screen (closer to the viewer)
{w, f, f, f, f, w},
{w, f, f, f, f, w},
{w, f, f, f, f, w},
{w, f, f, f, f, w},
{w, w, w, w, w, w}, // And this in the upper right
}
var win *pixelgl.Window
var offset = pixel.V(400, 325)
var floorTile, wallTile *pixel.Sprite
func loadPicture(path string) (pixel.Picture, error) {
file, err := os.Open(path)
if err != nil {
return nil, err
}
defer file.Close()
img, _, err := image.Decode(file)
if err != nil {
return nil, err
}
return pixel.PictureDataFromImage(img), nil
}
func run() {
var err error
cfg := pixelgl.WindowConfig{
Title: "Isometric demo",
Bounds: pixel.R(0, 0, windowWidth, windowHeight),
VSync: true,
}
win, err = pixelgl.NewWindow(cfg)
if err != nil {
panic(err)
}
pic, err := loadPicture("castle.png")
if err != nil {
panic(err)
}
wallTile = pixel.NewSprite(pic, pixel.R(0, 448, tileSize, 512))
floorTile = pixel.NewSprite(pic, pixel.R(0, 128, tileSize, 192))
depthSort()
for !win.Closed() {
win.Update()
}
}
// Draw level data tiles to window, from farthest to closest.
// In order to achieve the depth effect, we need to render tiles up to down, being lower
// closer to the viewer (see painter's algorithm). To do that, we need to process levelData in reverse order,
// so its first row is rendered last, as OpenGL considers its origin to be in the lower left corner of the display.
func depthSort() {
for x := len(levelData) - 1; x >= 0; x-- {
for y := len(levelData[x]) - 1; y >= 0; y-- {
isoCoords := cartesianToIso(pixel.V(float64(x), float64(y)))
mat := pixel.IM.Moved(offset.Add(isoCoords))
// Not really needed, just put to show bigger blocks
mat = mat.ScaledXY(win.Bounds().Center(), pixel.V(2, 2))
tileType := levelData[x][y]
if tileType == f {
floorTile.Draw(win, mat)
} else {
wallTile.Draw(win, mat)
}
}
}
}
func cartesianToIso(pt pixel.Vec) pixel.Vec {
return pixel.V((pt.X-pt.Y)*(tileSize/2), (pt.X+pt.Y)*(tileSize/4))
}
func main() {
pixelgl.Run(run)
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 126 KiB

View File

@@ -0,0 +1,19 @@
# Maze generator in Go
Created by [Stephen Chavez](https://github.com/redragonx)
This uses the game engine: Pixel. Install it here: https://github.com/faiface/pixel
I made this to improve my understanding of Go and some game concepts with some basic maze generating algorithms.
Controls: Press 'R' to restart the maze.
Optional command-line arguments: `go run ./maze-generator.go`
- `-w` sets the maze's width in pixels.
- `-h` sets the maze's height in pixels.
- `-c` sets the maze cell's size in pixels.
Code based on the Recursive backtracker algorithm.
- https://en.wikipedia.org/wiki/Maze_generation_algorithm#Recursive_backtracker
![Screenshot](screenshot.png)

View File

@@ -0,0 +1,317 @@
package main
// Code based on the Recursive backtracker algorithm.
// https://en.wikipedia.org/wiki/Maze_generation_algorithm#Recursive_backtracker
// See https://youtu.be/HyK_Q5rrcr4 as an example
// YouTube example ported to Go for the Pixel library.
// Created by Stephen Chavez
import (
"crypto/rand"
"errors"
"flag"
"fmt"
"math/big"
"time"
"github.com/faiface/pixel"
"github.com/faiface/pixel/examples/community/maze/stack"
"github.com/faiface/pixel/imdraw"
"github.com/faiface/pixel/pixelgl"
"github.com/pkg/profile"
"golang.org/x/image/colornames"
)
var visitedColor = pixel.RGB(0.5, 0, 1).Mul(pixel.Alpha(0.35))
var hightlightColor = pixel.RGB(0.3, 0, 0).Mul(pixel.Alpha(0.45))
var debug = false
type cell struct {
walls [4]bool // Wall order: top, right, bottom, left
row int
col int
visited bool
}
func (c *cell) Draw(imd *imdraw.IMDraw, wallSize int) {
drawCol := c.col * wallSize // x
drawRow := c.row * wallSize // y
imd.Color = colornames.White
if c.walls[0] {
// top line
imd.Push(pixel.V(float64(drawCol), float64(drawRow)), pixel.V(float64(drawCol+wallSize), float64(drawRow)))
imd.Line(3)
}
if c.walls[1] {
// right Line
imd.Push(pixel.V(float64(drawCol+wallSize), float64(drawRow)), pixel.V(float64(drawCol+wallSize), float64(drawRow+wallSize)))
imd.Line(3)
}
if c.walls[2] {
// bottom line
imd.Push(pixel.V(float64(drawCol+wallSize), float64(drawRow+wallSize)), pixel.V(float64(drawCol), float64(drawRow+wallSize)))
imd.Line(3)
}
if c.walls[3] {
// left line
imd.Push(pixel.V(float64(drawCol), float64(drawRow+wallSize)), pixel.V(float64(drawCol), float64(drawRow)))
imd.Line(3)
}
imd.EndShape = imdraw.SharpEndShape
if c.visited {
imd.Color = visitedColor
imd.Push(pixel.V(float64(drawCol), (float64(drawRow))), pixel.V(float64(drawCol+wallSize), float64(drawRow+wallSize)))
imd.Rectangle(0)
}
}
func (c *cell) GetNeighbors(grid []*cell, cols int, rows int) ([]*cell, error) {
neighbors := []*cell{}
j := c.row
i := c.col
top, _ := getCellAt(i, j-1, cols, rows, grid)
right, _ := getCellAt(i+1, j, cols, rows, grid)
bottom, _ := getCellAt(i, j+1, cols, rows, grid)
left, _ := getCellAt(i-1, j, cols, rows, grid)
if top != nil && !top.visited {
neighbors = append(neighbors, top)
}
if right != nil && !right.visited {
neighbors = append(neighbors, right)
}
if bottom != nil && !bottom.visited {
neighbors = append(neighbors, bottom)
}
if left != nil && !left.visited {
neighbors = append(neighbors, left)
}
if len(neighbors) == 0 {
return nil, errors.New("We checked all cells...")
}
return neighbors, nil
}
func (c *cell) GetRandomNeighbor(grid []*cell, cols int, rows int) (*cell, error) {
neighbors, err := c.GetNeighbors(grid, cols, rows)
if neighbors == nil {
return nil, err
}
nBig, err := rand.Int(rand.Reader, big.NewInt(int64(len(neighbors))))
if err != nil {
panic(err)
}
randomIndex := nBig.Int64()
return neighbors[randomIndex], nil
}
func (c *cell) hightlight(imd *imdraw.IMDraw, wallSize int) {
x := c.col * wallSize
y := c.row * wallSize
imd.Color = hightlightColor
imd.Push(pixel.V(float64(x), float64(y)), pixel.V(float64(x+wallSize), float64(y+wallSize)))
imd.Rectangle(0)
}
func newCell(col int, row int) *cell {
newCell := new(cell)
newCell.row = row
newCell.col = col
for i := range newCell.walls {
newCell.walls[i] = true
}
return newCell
}
// Creates the inital maze slice for use.
func initGrid(cols, rows int) []*cell {
grid := []*cell{}
for j := 0; j < rows; j++ {
for i := 0; i < cols; i++ {
newCell := newCell(i, j)
grid = append(grid, newCell)
}
}
return grid
}
func setupMaze(cols, rows int) ([]*cell, *stack.Stack, *cell) {
// Make an empty grid
grid := initGrid(cols, rows)
backTrackStack := stack.NewStack(len(grid))
currentCell := grid[0]
return grid, backTrackStack, currentCell
}
func cellIndex(i, j, cols, rows int) int {
if i < 0 || j < 0 || i > cols-1 || j > rows-1 {
return -1
}
return i + j*cols
}
func getCellAt(i int, j int, cols int, rows int, grid []*cell) (*cell, error) {
possibleIndex := cellIndex(i, j, cols, rows)
if possibleIndex == -1 {
return nil, fmt.Errorf("cellIndex: CellIndex is a negative number %d", possibleIndex)
}
return grid[possibleIndex], nil
}
func removeWalls(a *cell, b *cell) {
x := a.col - b.col
if x == 1 {
a.walls[3] = false
b.walls[1] = false
} else if x == -1 {
a.walls[1] = false
b.walls[3] = false
}
y := a.row - b.row
if y == 1 {
a.walls[0] = false
b.walls[2] = false
} else if y == -1 {
a.walls[2] = false
b.walls[0] = false
}
}
func run() {
// unsiged integers, because easier parsing error checks.
// We must convert these to intergers, as done below...
uScreenWidth, uScreenHeight, uWallSize := parseArgs()
var (
// In pixels
// Defualt is 800x800x40 = 20x20 wallgrid
screenWidth = int(uScreenWidth)
screenHeight = int(uScreenHeight)
wallSize = int(uWallSize)
frames = 0
second = time.Tick(time.Second)
grid = []*cell{}
cols = screenWidth / wallSize
rows = screenHeight / wallSize
currentCell = new(cell)
backTrackStack = stack.NewStack(1)
)
// Set game FPS manually
fps := time.Tick(time.Second / 60)
cfg := pixelgl.WindowConfig{
Title: "Pixel Rocks! - Maze example",
Bounds: pixel.R(0, 0, float64(screenHeight), float64(screenWidth)),
}
win, err := pixelgl.NewWindow(cfg)
if err != nil {
panic(err)
}
grid, backTrackStack, currentCell = setupMaze(cols, rows)
gridIMDraw := imdraw.New(nil)
for !win.Closed() {
if win.JustReleased(pixelgl.KeyR) {
fmt.Println("R pressed")
grid, backTrackStack, currentCell = setupMaze(cols, rows)
}
win.Clear(colornames.Gray)
gridIMDraw.Clear()
for i := range grid {
grid[i].Draw(gridIMDraw, wallSize)
}
// step 1
// Make the initial cell the current cell and mark it as visited
currentCell.visited = true
currentCell.hightlight(gridIMDraw, wallSize)
// step 2.1
// If the current cell has any neighbours which have not been visited
// Choose a random unvisited cell
nextCell, _ := currentCell.GetRandomNeighbor(grid, cols, rows)
if nextCell != nil && !nextCell.visited {
// step 2.2
// Push the current cell to the stack
backTrackStack.Push(currentCell)
// step 2.3
// Remove the wall between the current cell and the chosen cell
removeWalls(currentCell, nextCell)
// step 2.4
// Make the chosen cell the current cell and mark it as visited
nextCell.visited = true
currentCell = nextCell
} else if backTrackStack.Len() > 0 {
currentCell = backTrackStack.Pop().(*cell)
}
gridIMDraw.Draw(win)
win.Update()
<-fps
updateFPSDisplay(win, &cfg, &frames, grid, second)
}
}
// Parses the maze arguments, all of them are optional.
// Uses uint as implicit error checking :)
func parseArgs() (uint, uint, uint) {
var mazeWidthPtr = flag.Uint("w", 800, "w sets the maze's width in pixels.")
var mazeHeightPtr = flag.Uint("h", 800, "h sets the maze's height in pixels.")
var wallSizePtr = flag.Uint("c", 40, "c sets the maze cell's size in pixels.")
flag.Parse()
// If these aren't default values AND if they're not the same values.
// We should warn the user that the maze will look funny.
if *mazeWidthPtr != 800 || *mazeHeightPtr != 800 {
if *mazeWidthPtr != *mazeHeightPtr {
fmt.Printf("WARNING: maze width: %d and maze height: %d don't match. \n", *mazeWidthPtr, *mazeHeightPtr)
fmt.Println("Maze will look funny because the maze size is bond to the window size!")
}
}
return *mazeWidthPtr, *mazeHeightPtr, *wallSizePtr
}
func updateFPSDisplay(win *pixelgl.Window, cfg *pixelgl.WindowConfig, frames *int, grid []*cell, second <-chan time.Time) {
*frames++
select {
case <-second:
win.SetTitle(fmt.Sprintf("%s | FPS: %d with %d Cells", cfg.Title, *frames, len(grid)))
*frames = 0
default:
}
}
func main() {
if debug {
defer profile.Start().Stop()
}
pixelgl.Run(run)
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

View File

@@ -0,0 +1,86 @@
package stack
type Stack struct {
top *Element
size int
max int
}
type Element struct {
value interface{}
next *Element
}
func NewStack(max int) *Stack {
return &Stack{max: max}
}
// Return the stack's length
func (s *Stack) Len() int {
return s.size
}
// Return the stack's max
func (s *Stack) Max() int {
return s.max
}
// Push a new element onto the stack
func (s *Stack) Push(value interface{}) {
if s.size+1 > s.max {
if last := s.PopLast(); last == nil {
panic("Unexpected nil in stack")
}
}
s.top = &Element{value, s.top}
s.size++
}
// Remove the top element from the stack and return it's value
// If the stack is empty, return nil
func (s *Stack) Pop() (value interface{}) {
if s.size > 0 {
value, s.top = s.top.value, s.top.next
s.size--
return
}
return nil
}
func (s *Stack) PopLast() (value interface{}) {
if lastElem := s.popLast(s.top); lastElem != nil {
return lastElem.value
}
return nil
}
//Peek returns a top without removing it from list
func (s *Stack) Peek() (value interface{}, exists bool) {
exists = false
if s.size > 0 {
value = s.top.value
exists = true
}
return
}
func (s *Stack) popLast(elem *Element) *Element {
if elem == nil {
return nil
}
// not last because it has next and a grandchild
if elem.next != nil && elem.next.next != nil {
return s.popLast(elem.next)
}
// current elem is second from bottom, as next elem has no child
if elem.next != nil && elem.next.next == nil {
last := elem.next
// make current elem bottom of stack by removing its next element
elem.next = nil
s.size--
return last
}
return nil
}

View File

@@ -0,0 +1,9 @@
# Parallax scrolling demo
Created by [Sergio Vera](https://github.com/svera)
This example shows how to implement an infinite side scrolling background with a depth effect, using [parallax scrolling](https://en.wikipedia.org/wiki/Parallax_scrolling). Code is based in the [infinite scrolling background](https://github.com/faiface/pixel/tree/master/examples/community/scrolling-background) demo.
Credits to [Peter Hellberg](https://github.com/peterhellberg) for the improved background images.
![Parallax scrolling background](result.png)

Binary file not shown.

After

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

View File

@@ -0,0 +1,74 @@
package main
import (
"image"
"os"
"time"
_ "image/png"
"github.com/faiface/pixel"
"github.com/faiface/pixel/pixelgl"
)
func loadPicture(path string) (pixel.Picture, error) {
file, err := os.Open(path)
if err != nil {
return nil, err
}
defer file.Close()
img, _, err := image.Decode(file)
if err != nil {
return nil, err
}
return pixel.PictureDataFromImage(img), nil
}
const (
windowWidth = 600
windowHeight = 450
foregroundHeight = 149
// This is the scrolling speed (pixels per second)
// Negative values will make background to scroll to the left,
// positive to the right.
backgroundSpeed = -60
foregroundSpeed = -120
)
func run() {
cfg := pixelgl.WindowConfig{
Title: "Parallax scrolling demo",
Bounds: pixel.R(0, 0, windowWidth, windowHeight),
VSync: true,
}
win, err := pixelgl.NewWindow(cfg)
if err != nil {
panic(err)
}
// Pic must have double the width of the window, as it will scroll to the left or right
picBackground, err := loadPicture("background.png")
if err != nil {
panic(err)
}
picForeground, err := loadPicture("foreground.png")
if err != nil {
panic(err)
}
background := NewScrollingBackground(picBackground, windowWidth, windowHeight, backgroundSpeed)
foreground := NewScrollingBackground(picForeground, windowWidth, foregroundHeight, foregroundSpeed)
last := time.Now()
for !win.Closed() {
dt := time.Since(last).Seconds()
last = time.Now()
background.Update(win, dt)
foreground.Update(win, dt)
win.Update()
}
}
func main() {
pixelgl.Run(run)
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 91 KiB

View File

@@ -0,0 +1,64 @@
package main
import (
"math"
"github.com/faiface/pixel"
"github.com/faiface/pixel/pixelgl"
)
// ScrollingBackground stores all needed information to scroll a background
// to the left or right
type ScrollingBackground struct {
width float64
height float64
displacement float64
speed float64
backgrounds [2]*pixel.Sprite
positions [2]pixel.Vec
}
// NewScrollingBackground construct and returns a new instance of scrollingBackground,
// positioning the background images according to the speed value
func NewScrollingBackground(pic pixel.Picture, width, height, speed float64) *ScrollingBackground {
sb := &ScrollingBackground{
width: width,
height: height,
speed: speed,
backgrounds: [2]*pixel.Sprite{
pixel.NewSprite(pic, pixel.R(0, 0, width, height)),
pixel.NewSprite(pic, pixel.R(width, 0, width*2, height)),
},
}
sb.positionImages()
return sb
}
// If scrolling speed > 0, put second background image ouside the screen,
// at the left side, otherwise put it at the right side.
func (sb *ScrollingBackground) positionImages() {
if sb.speed > 0 {
sb.positions = [2]pixel.Vec{
pixel.V(sb.width/2, sb.height/2),
pixel.V((sb.width/2)-sb.width, sb.height/2),
}
} else {
sb.positions = [2]pixel.Vec{
pixel.V(sb.width/2, sb.height/2),
pixel.V(sb.width+(sb.width/2), sb.height/2),
}
}
}
// Update will move backgrounds certain pixels, depending of the amount of time passed
func (sb *ScrollingBackground) Update(win *pixelgl.Window, dt float64) {
if math.Abs(sb.displacement) >= sb.width {
sb.displacement = 0
sb.positions[0], sb.positions[1] = sb.positions[1], sb.positions[0]
}
d := pixel.V(sb.displacement, 0)
sb.backgrounds[0].Draw(win, pixel.IM.Moved(sb.positions[0].Add(d)))
sb.backgrounds[1].Draw(win, pixel.IM.Moved(sb.positions[1].Add(d)))
sb.displacement += sb.speed * dt
}

View File

@@ -0,0 +1,12 @@
# Procedural 1D terrain generator
Created by [Sergio Vera](https://github.com/svera).
This is a demo of a 1D terrain generator using [Perlin noise](https://en.wikipedia.org/wiki/Perlin_noise) algorithm.
Press *space* to generate a random terrain.
Uses [Go-Perlin](https://github.com/aquilax/go-perlin).
Texture by [hh316](https://hhh316.deviantart.com/art/Seamless-stone-cliff-face-mountain-texture-377076626).
![Randomly generated 1D terrain](result.png)

View File

@@ -0,0 +1,104 @@
package main
import (
"image"
"math/rand"
"os"
"time"
_ "image/jpeg"
perlin "github.com/aquilax/go-perlin"
"github.com/faiface/pixel"
"github.com/faiface/pixel/imdraw"
"github.com/faiface/pixel/pixelgl"
"golang.org/x/image/colornames"
)
const (
width = 800
height = 600
// Top of the mountain must be around the half of the screen height
verticalOffset = height / 2
// Perlin noise provides variations in values between -1 and 1,
// we multiply those so they're visible on screen
scale = 100
waveLength = 100
alpha = 2.
beta = 2.
n = 3
maximumSeedValue = 100
)
func init() {
rand.Seed(time.Now().UTC().UnixNano())
}
func main() {
pixelgl.Run(run)
}
func run() {
cfg := pixelgl.WindowConfig{
Title: "Procedural terrain 1D",
Bounds: pixel.R(0, 0, width, height),
VSync: true,
}
win, err := pixelgl.NewWindow(cfg)
if err != nil {
panic(err)
}
pic, err := loadPicture("stone.jpg")
if err != nil {
panic(err)
}
imd := imdraw.New(pic)
drawTerrain(win, imd)
for !win.Closed() {
if win.JustPressed(pixelgl.KeySpace) {
drawTerrain(win, imd)
}
win.Update()
}
}
func loadPicture(path string) (pixel.Picture, error) {
file, err := os.Open(path)
if err != nil {
return nil, err
}
defer file.Close()
img, _, err := image.Decode(file)
if err != nil {
return nil, err
}
return pixel.PictureDataFromImage(img), nil
}
func drawTerrain(win *pixelgl.Window, imd *imdraw.IMDraw) {
var seed = rand.Int63n(maximumSeedValue)
p := perlin.NewPerlin(alpha, beta, n, seed)
imd.Clear()
win.Clear(colornames.Skyblue)
for x := 0.; x < width; x++ {
y := p.Noise1D(x/waveLength)*scale + verticalOffset
renderTexturedLine(x, y, imd)
}
imd.Draw(win)
}
// Render a textured line in position x with a height y.
// Note that the textured line is just a 1 px width rectangle.
// We push the opposite vertices of that rectangle and specify the points of the
// texture we want to apply to them. Pixel will fill the rest of the rectangle interpolating the texture.
func renderTexturedLine(x, y float64, imd *imdraw.IMDraw) {
imd.Intensity = 1.
imd.Picture = pixel.V(x, 0)
imd.Push(pixel.V(x, 0))
imd.Picture = pixel.V(x+1, y)
imd.Push(pixel.V(x+1, y))
imd.Rectangle(0)
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 759 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 368 KiB

View File

@@ -0,0 +1,22 @@
# raycaster
A raycaster made by [Peter Hellberg](https://github.com/peterhellberg/) as part of his [pixel-experiments](https://github.com/peterhellberg/pixel-experiments).
Based on Lodes article on [raycasting](http://lodev.org/cgtutor/raycasting.html).
## Controls
WASD for strafing and arrow keys for rotation.
Place blocks using the number keys.
## Screenshots
![raycaster animation](https://user-images.githubusercontent.com/565124/31828029-798e6620-b5b9-11e7-96b7-fda540755745.gif)
![raycaster screenshot](screenshot.png)
## Links
- https://github.com/peterhellberg/pixel-experiments/tree/master/raycaster
- https://gist.github.com/peterhellberg/835eccabf95800555120cc8f0c9e16c2

File diff suppressed because one or more lines are too long

Binary file not shown.

After

Width:  |  Height:  |  Size: 47 KiB

View File

@@ -0,0 +1,7 @@
# Infinite scrolling background demo
Created by [Sergio Vera](https://github.com/svera)
This example shows how to implement an infinite side scrolling background.
Credits to [Peter Hellberg](https://github.com/peterhellberg) for the improved background image.

Binary file not shown.

After

Width:  |  Height:  |  Size: 56 KiB

View File

@@ -0,0 +1,83 @@
package main
import (
"image"
"os"
"time"
_ "image/png"
"github.com/faiface/pixel"
"github.com/faiface/pixel/pixelgl"
)
func loadPicture(path string) (pixel.Picture, error) {
file, err := os.Open(path)
if err != nil {
return nil, err
}
defer file.Close()
img, _, err := image.Decode(file)
if err != nil {
return nil, err
}
return pixel.PictureDataFromImage(img), nil
}
const (
windowWidth = 600
windowHeight = 450
// This is the scrolling speed
linesPerSecond = 60
)
func run() {
cfg := pixelgl.WindowConfig{
Title: "Scrolling background demo",
Bounds: pixel.R(0, 0, windowWidth, windowHeight),
VSync: true,
}
win, err := pixelgl.NewWindow(cfg)
if err != nil {
panic(err)
}
// Pic must have double the width of the window, as it will scroll to the left
pic, err := loadPicture("gamebackground.png")
if err != nil {
panic(err)
}
// Backgrounds are made taking the left and right halves of the image
background1 := pixel.NewSprite(pic, pixel.R(0, 0, windowWidth, windowHeight))
background2 := pixel.NewSprite(pic, pixel.R(windowWidth, 0, windowWidth*2, windowHeight))
// In the beginning, vector1 will put background1 filling the whole window, while vector2 will
// put background2 just at the right side of the window, out of view
vector1 := pixel.V(windowWidth/2, windowHeight/2)
vector2 := pixel.V(windowWidth+(windowWidth/2), windowHeight/2)
i := float64(0)
last := time.Now()
for !win.Closed() {
dt := time.Since(last).Seconds()
last = time.Now()
// When one of the backgrounds has completely scrolled, we swap displacement vectors,
// so the backgrounds will swap positions too regarding the previous iteration,
// thus making the background endless.
if i <= -windowWidth {
i = 0
vector1, vector2 = vector2, vector1
}
// This delta vector will move the backgrounds to the left
d := pixel.V(-i, 0)
background1.Draw(win, pixel.IM.Moved(vector1.Sub(d)))
background2.Draw(win, pixel.IM.Moved(vector2.Sub(d)))
i -= linesPerSecond * dt
win.Update()
}
}
func main() {
pixelgl.Run(run)
}

View File

@@ -0,0 +1,20 @@
# starfield
Classic starfield… with [supposedly accurate stellar colors](http://www.vendian.org/mncharity/dir3/starcolor/)
Made by [Peter Hellberg](https://github.com/peterhellberg/) as part of his [pixel-experiments](https://github.com/peterhellberg/pixel-experiments)
## Controls
Arrow up and down to change speed. Space bar to almost stop.
## Screenshots
![starfield animation](https://user-images.githubusercontent.com/565124/32411599-a5fcba72-c1df-11e7-8730-a570470a4eee.gif)
![starfield screenshot](screenshot.png)
## Links
- https://github.com/peterhellberg/pixel-experiments/tree/master/starfield
- https://gist.github.com/peterhellberg/4018e228cced61a0bb26991e49299c96

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.0 KiB

View File

@@ -0,0 +1,165 @@
package main
import (
"image/color"
"math/rand"
"time"
"github.com/faiface/pixel"
"github.com/faiface/pixel/imdraw"
"github.com/faiface/pixel/pixelgl"
)
const w, h = float64(1024), float64(512)
var speed = float64(200)
var stars [1024]*star
func init() {
rand.Seed(4)
for i := 0; i < len(stars); i++ {
stars[i] = newStar()
}
}
type star struct {
pixel.Vec
Z float64
P float64
C color.RGBA
}
func newStar() *star {
return &star{
pixel.V(random(-w, w), random(-h, h)),
random(0, w), 0, Colors[rand.Intn(len(Colors))],
}
}
func (s *star) update(d float64) {
s.P = s.Z
s.Z -= d * speed
if s.Z < 0 {
s.X = random(-w, w)
s.Y = random(-h, h)
s.Z = w
s.P = s.Z
}
}
func (s *star) draw(imd *imdraw.IMDraw) {
p := pixel.V(
scale(s.X/s.Z, 0, 1, 0, w),
scale(s.Y/s.Z, 0, 1, 0, h),
)
o := pixel.V(
scale(s.X/s.P, 0, 1, 0, w),
scale(s.Y/s.P, 0, 1, 0, h),
)
r := scale(s.Z, 0, w, 11, 0)
imd.Color = s.C
if p.Sub(o).Len() > 6 {
imd.Push(p, o)
imd.Line(r)
}
imd.Push(p)
imd.Circle(r, 0)
}
func run() {
win, err := pixelgl.NewWindow(pixelgl.WindowConfig{
Bounds: pixel.R(0, 0, w, h),
VSync: true,
Undecorated: true,
})
if err != nil {
panic(err)
}
imd := imdraw.New(nil)
imd.Precision = 7
imd.SetMatrix(pixel.IM.Moved(win.Bounds().Center()))
last := time.Now()
for !win.Closed() {
win.SetClosed(win.JustPressed(pixelgl.KeyEscape) || win.JustPressed(pixelgl.KeyQ))
if win.Pressed(pixelgl.KeyUp) {
speed += 10
}
if win.Pressed(pixelgl.KeyDown) {
if speed > 10 {
speed -= 10
}
}
if win.Pressed(pixelgl.KeySpace) {
speed = 100
}
d := time.Since(last).Seconds()
last = time.Now()
imd.Clear()
for _, s := range stars {
s.update(d)
s.draw(imd)
}
win.Clear(color.Black)
imd.Draw(win)
win.Update()
}
}
func main() {
pixelgl.Run(run)
}
func random(min, max float64) float64 {
return rand.Float64()*(max-min) + min
}
func scale(unscaledNum, min, max, minAllowed, maxAllowed float64) float64 {
return (maxAllowed-minAllowed)*(unscaledNum-min)/(max-min) + minAllowed
}
// Colors based on stellar types listed at
// http://www.vendian.org/mncharity/dir3/starcolor/
var Colors = []color.RGBA{
color.RGBA{157, 180, 255, 255},
color.RGBA{162, 185, 255, 255},
color.RGBA{167, 188, 255, 255},
color.RGBA{170, 191, 255, 255},
color.RGBA{175, 195, 255, 255},
color.RGBA{186, 204, 255, 255},
color.RGBA{192, 209, 255, 255},
color.RGBA{202, 216, 255, 255},
color.RGBA{228, 232, 255, 255},
color.RGBA{237, 238, 255, 255},
color.RGBA{251, 248, 255, 255},
color.RGBA{255, 249, 249, 255},
color.RGBA{255, 245, 236, 255},
color.RGBA{255, 244, 232, 255},
color.RGBA{255, 241, 223, 255},
color.RGBA{255, 235, 209, 255},
color.RGBA{255, 215, 174, 255},
color.RGBA{255, 198, 144, 255},
color.RGBA{255, 190, 127, 255},
color.RGBA{255, 187, 123, 255},
color.RGBA{255, 187, 123, 255},
}