First commit
This commit is contained in:
parent
3959af0d2f
commit
eb6f43d1dc
|
@ -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 |
|
@ -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)
|
||||
}
|
Loading…
Reference in New Issue