2018-07-04 17:27:22 -05:00
|
|
|
package tiles
|
|
|
|
|
|
|
|
//noinspection ALL
|
|
|
|
import (
|
|
|
|
"bytes"
|
|
|
|
"errors"
|
|
|
|
"image"
|
|
|
|
"os"
|
|
|
|
|
2018-07-05 15:25:34 -05:00
|
|
|
"github.com/faiface/pixel/examples/community/ASharedJourney/assets_manager"
|
2018-07-04 17:27:22 -05:00
|
|
|
tiled "github.com/lafriks/go-tiled"
|
|
|
|
|
|
|
|
_ "image/png"
|
|
|
|
|
|
|
|
"log"
|
|
|
|
|
|
|
|
"fmt"
|
|
|
|
|
|
|
|
"github.com/faiface/pixel"
|
|
|
|
"github.com/faiface/pixel/pixelgl"
|
2018-07-05 15:25:34 -05:00
|
|
|
"github.com/faiface/pixel/examples/community/ASharedJourney/menu"
|
|
|
|
"github.com/faiface/pixel/examples/community/ASharedJourney/music"
|
|
|
|
"github.com/faiface/pixel/examples/community/ASharedJourney/shared"
|
2018-07-04 17:27:22 -05:00
|
|
|
)
|
|
|
|
|
|
|
|
// Level names
|
|
|
|
const (
|
|
|
|
bonhommeMap = "bonhomme"
|
|
|
|
orgyIsIsland = "orgyIsland"
|
|
|
|
veryEasyLevel = "veryEasy"
|
|
|
|
mazeLevel = "maze"
|
|
|
|
theLongCorridorLevel = "theLongCorridor"
|
|
|
|
amazeingLevel = "amazeing"
|
|
|
|
forestLevel = "forest"
|
|
|
|
myLittlePonyLevel = "myLittlePony"
|
|
|
|
theLittlePigLevel = "theLittlePig"
|
|
|
|
theStruggleLevel = "theStruggle"
|
|
|
|
inTheHoleTileID = 61
|
|
|
|
)
|
|
|
|
|
|
|
|
// CurrentLevel played
|
|
|
|
var CurrentLevel = -1
|
|
|
|
|
|
|
|
// Levels list
|
|
|
|
var Levels = [...]string{
|
|
|
|
veryEasyLevel,
|
|
|
|
amazeingLevel,
|
|
|
|
mazeLevel,
|
|
|
|
forestLevel,
|
|
|
|
theLongCorridorLevel,
|
|
|
|
theLittlePigLevel,
|
|
|
|
bonhommeMap,
|
|
|
|
theStruggleLevel,
|
|
|
|
myLittlePonyLevel,
|
|
|
|
}
|
|
|
|
|
|
|
|
// Uncomment this for testing :)
|
|
|
|
// var Levels = [...]string{biggerLevel}
|
|
|
|
|
|
|
|
const tilesPath = "map.png" // path to your tileset
|
|
|
|
|
|
|
|
// TileSize tile in pixels of squares
|
|
|
|
var TileSize int
|
|
|
|
var mapWidth int
|
|
|
|
var mapHeight int
|
|
|
|
|
|
|
|
// World struct with global tiles and obj positions
|
|
|
|
type World struct {
|
|
|
|
BackgroundTiles []SpriteWithPosition
|
|
|
|
Players []SpriteWithPosition
|
|
|
|
Movables []SpriteWithPosition
|
|
|
|
Obstacles []SpriteWithPosition
|
|
|
|
Water []SpriteWithPosition
|
|
|
|
Holes []SpriteWithPosition
|
|
|
|
WinStars []SpriteWithPosition
|
|
|
|
}
|
|
|
|
|
|
|
|
//SpriteWithPosition holds the sprite and its position into the window
|
|
|
|
type SpriteWithPosition struct {
|
|
|
|
Sprite *pixel.Sprite
|
|
|
|
Position pixel.Vec
|
|
|
|
InTheWater bool
|
|
|
|
InTheHole bool
|
|
|
|
HasWon bool
|
|
|
|
WinningPosition pixel.Vec
|
|
|
|
}
|
|
|
|
|
|
|
|
// loadMap load the map
|
|
|
|
func loadMap() (pixel.Picture, error) {
|
|
|
|
|
|
|
|
//noinspection GoUnresolvedReference
|
|
|
|
byteImage, err := assetsManager.Asset("assets/" + tilesPath)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
img, _, err := image.Decode(bytes.NewReader(byteImage))
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
return pixel.PictureDataFromImage(img), nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func getTilesFrames(spritesheet pixel.Picture) []pixel.Rect {
|
|
|
|
var tilesFrames []pixel.Rect
|
|
|
|
for y := spritesheet.Bounds().Max.Y - float64(TileSize); y > spritesheet.Bounds().Min.Y-float64(TileSize); y -= float64(TileSize) {
|
|
|
|
for x := spritesheet.Bounds().Min.X; x < spritesheet.Bounds().Max.X; x += float64(TileSize) {
|
|
|
|
tilesFrames = append(tilesFrames, pixel.R(x, y, x+float64(TileSize), y+float64(TileSize)))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return tilesFrames
|
|
|
|
}
|
|
|
|
|
|
|
|
func getOrigin(win *pixelgl.Window) pixel.Vec {
|
|
|
|
centerPosition := win.Bounds().Center()
|
|
|
|
originXPosition := centerPosition.X - float64(mapWidth)/2*float64(TileSize)
|
|
|
|
originYPosition := centerPosition.Y + float64(mapHeight)/2*float64(TileSize) - float64(TileSize)
|
|
|
|
|
|
|
|
return pixel.V(originXPosition, originYPosition)
|
|
|
|
}
|
|
|
|
|
|
|
|
func getSpritePosition(spriteIndex int, origin pixel.Vec) pixel.Vec {
|
|
|
|
spriteXPosition := origin.X + float64((spriteIndex%mapWidth)*TileSize) + float64(TileSize)/2
|
|
|
|
spriteYPosition := origin.Y + float64(TileSize)/2 - float64((spriteIndex/mapWidth)*TileSize)
|
|
|
|
|
|
|
|
return pixel.V(spriteXPosition, spriteYPosition)
|
|
|
|
}
|
|
|
|
|
|
|
|
// extractAndPlaceSprites filters out empty tiles and positions them properly on the screen
|
|
|
|
func extractAndPlaceSprites(
|
|
|
|
layerTiles []*tiled.LayerTile,
|
|
|
|
spritesheet pixel.Picture,
|
|
|
|
tilesFrames []pixel.Rect,
|
|
|
|
originPosition pixel.Vec,
|
|
|
|
) (positionedSprites []SpriteWithPosition) {
|
|
|
|
for index, layerTile := range layerTiles {
|
|
|
|
if !layerTile.IsNil() {
|
|
|
|
sprite := pixel.NewSprite(spritesheet, tilesFrames[layerTile.ID])
|
|
|
|
spritePosition := getSpritePosition(index, originPosition)
|
|
|
|
positionedSprites = append(positionedSprites, SpriteWithPosition{
|
|
|
|
Sprite: sprite,
|
|
|
|
Position: spritePosition,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return positionedSprites
|
|
|
|
}
|
|
|
|
|
|
|
|
func findLayerIndex(layerName string, layers []*tiled.Layer) (layerIndex int, err error) {
|
|
|
|
for index, layer := range layers {
|
|
|
|
if layer.Name == layerName {
|
|
|
|
return index, nil
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return -1, errors.New("Expected to find layer with name " + layerName)
|
|
|
|
}
|
|
|
|
|
|
|
|
// SetNextLevel called before NextLevel if you want to select it
|
|
|
|
func SetNexLevel(nextMapLevel int) {
|
|
|
|
if nextMapLevel == 0 {
|
|
|
|
CurrentLevel = len(Levels)
|
|
|
|
} else {
|
|
|
|
CurrentLevel = nextMapLevel - 1
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// NextLevel goes to next level
|
|
|
|
func NextLevel() World {
|
|
|
|
CurrentLevel = (CurrentLevel + 1) % len(Levels)
|
|
|
|
var newWorlg = GenerateMap(Levels[CurrentLevel])
|
|
|
|
if CurrentLevel != 0 {
|
|
|
|
//if !(len(Levels) == CurrentLevel){
|
|
|
|
if !(len(Levels)-1 == CurrentLevel) {
|
|
|
|
//last level was finished
|
|
|
|
menu.Menu(menu.WinLevelMenuImage, "Level solved, continue ...", pixel.V(150, 200), true, music.SOUND_EFFECT_WIN_GAME)
|
|
|
|
|
|
|
|
} else {
|
|
|
|
//game was finished
|
|
|
|
music.Music.PlayEffect(music.SOUND_EFFECT_WIN_FINAL_GAME)
|
|
|
|
menu.Menu(menu.FinishedGameImage, "You WIN", pixel.V(300, 140), true, music.SOUND_EFFECT_WIN_GAME)
|
|
|
|
//reload main menu
|
|
|
|
menu.Menu(menu.MainMenuImage, "Press ENTER to PLAY ...", pixel.V(180, 150), true, music.SOUND_EFFECT_START_GAME)
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return newWorlg
|
|
|
|
}
|
|
|
|
|
|
|
|
// RestartLevel reinitializes the current level
|
|
|
|
func RestartLevel() World {
|
|
|
|
return GenerateMap(Levels[CurrentLevel])
|
|
|
|
}
|
|
|
|
|
|
|
|
// GenerateMap generates the map from a .tmx file
|
|
|
|
func GenerateMap(levelFileName string) World {
|
|
|
|
//added support for relative file addressing
|
|
|
|
byteTiledMap, _ := assetsManager.Asset("assets/" + levelFileName + ".tmx")
|
|
|
|
gameMap, err := tiled.LoadFromReader("", bytes.NewReader(byteTiledMap))
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
log.Fatal(err)
|
|
|
|
fmt.Println("Error parsing map")
|
|
|
|
os.Exit(2)
|
|
|
|
}
|
|
|
|
mapWidth = gameMap.Width
|
|
|
|
mapHeight = gameMap.Height
|
|
|
|
TileSize = gameMap.TileHeight
|
|
|
|
|
|
|
|
spritesheet, err := loadMap()
|
|
|
|
if err != nil {
|
|
|
|
panic(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
tilesFrames := getTilesFrames(spritesheet)
|
|
|
|
|
|
|
|
originPosition := getOrigin(shared.Win)
|
|
|
|
|
|
|
|
var background []SpriteWithPosition
|
|
|
|
var players []SpriteWithPosition
|
|
|
|
var obstacles []SpriteWithPosition
|
|
|
|
var movables []SpriteWithPosition
|
|
|
|
var water []SpriteWithPosition
|
|
|
|
var winStars []SpriteWithPosition
|
|
|
|
var holes []SpriteWithPosition
|
|
|
|
|
|
|
|
backgoundIndex, err := findLayerIndex("background", gameMap.Layers)
|
|
|
|
if err == nil {
|
|
|
|
background = extractAndPlaceSprites(gameMap.Layers[backgoundIndex].Tiles, spritesheet, tilesFrames, originPosition)
|
|
|
|
}
|
|
|
|
playersLayerIndex, err := findLayerIndex("animals", gameMap.Layers)
|
|
|
|
if err == nil {
|
|
|
|
players = extractAndPlaceSprites(gameMap.Layers[playersLayerIndex].Tiles, spritesheet, tilesFrames, originPosition)
|
|
|
|
}
|
|
|
|
obstaclesLayerIndex, err := findLayerIndex("obstacles", gameMap.Layers)
|
|
|
|
if err == nil {
|
|
|
|
obstacles = extractAndPlaceSprites(gameMap.Layers[obstaclesLayerIndex].Tiles, spritesheet, tilesFrames, originPosition)
|
|
|
|
}
|
|
|
|
movablesLayerIndex, err := findLayerIndex("movables", gameMap.Layers)
|
|
|
|
if err == nil {
|
|
|
|
movables = extractAndPlaceSprites(gameMap.Layers[movablesLayerIndex].Tiles, spritesheet, tilesFrames, originPosition)
|
|
|
|
}
|
|
|
|
waterLayerIndex, err := findLayerIndex("water", gameMap.Layers)
|
|
|
|
if err == nil {
|
|
|
|
water = extractAndPlaceSprites(gameMap.Layers[waterLayerIndex].Tiles, spritesheet, tilesFrames, originPosition)
|
|
|
|
}
|
|
|
|
winStarsLayerIndex, err := findLayerIndex("win", gameMap.Layers)
|
|
|
|
if err == nil {
|
|
|
|
winStars = extractAndPlaceSprites(gameMap.Layers[winStarsLayerIndex].Tiles, spritesheet, tilesFrames, originPosition)
|
|
|
|
}
|
|
|
|
holesLayerIndex, err := findLayerIndex("holes", gameMap.Layers)
|
|
|
|
if err == nil {
|
|
|
|
holes = extractAndPlaceSprites(gameMap.Layers[holesLayerIndex].Tiles, spritesheet, tilesFrames, originPosition)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Playable checks
|
|
|
|
if len(players) == 0 {
|
|
|
|
panic(errors.New("no animal tile was placed"))
|
|
|
|
}
|
|
|
|
|
|
|
|
if len(winStars) == 0 {
|
|
|
|
panic(errors.New("no win star tile was placed"))
|
|
|
|
}
|
|
|
|
|
|
|
|
// Zz special tile
|
|
|
|
sprite := pixel.NewSprite(spritesheet, tilesFrames[inTheHoleTileID])
|
|
|
|
spritePosition := pixel.V(-100, -100)
|
|
|
|
holes = append(holes, SpriteWithPosition{
|
|
|
|
Sprite: sprite,
|
|
|
|
Position: spritePosition,
|
|
|
|
})
|
|
|
|
|
|
|
|
world := World{
|
|
|
|
BackgroundTiles: background,
|
|
|
|
Players: players,
|
|
|
|
Movables: movables,
|
|
|
|
Obstacles: obstacles,
|
|
|
|
Water: water,
|
|
|
|
Holes: holes,
|
|
|
|
WinStars: winStars,
|
|
|
|
}
|
|
|
|
return world
|
|
|
|
}
|
|
|
|
|
|
|
|
//DrawMap draws into window the given sprites
|
|
|
|
func DrawMap(positionedSprites []SpriteWithPosition) {
|
|
|
|
for _, positionedSprite := range positionedSprites {
|
|
|
|
positionedSprite.Sprite.Draw(shared.Win, pixel.IM.Moved(positionedSprite.Position))
|
|
|
|
}
|
|
|
|
}
|