First commit

This commit is contained in:
Sergio Vera Castellano 2017-12-31 17:56:58 +01:00
parent 3959af0d2f
commit eb6f43d1dc
3 changed files with 113 additions and 0 deletions

View File

@ -0,0 +1,11 @@
# 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 I'll focus on 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/).

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)
}