Compare commits
1 Commits
rework-ani
...
collidersy
| Author | SHA1 | Date | |
|---|---|---|---|
| 267e15cc27 |
3
.gitignore
vendored
@@ -1,2 +1 @@
|
|||||||
openquell*
|
openquell
|
||||||
tmp
|
|
||||||
|
|||||||
24
Makefile
@@ -1,12 +1,3 @@
|
|||||||
version = $(shell egrep "version string = " config/static.go | cut -d'"' -f 2)
|
|
||||||
BRANCH = $(shell git branch --show-current)
|
|
||||||
COMMIT = $(shell git rev-parse --short=8 HEAD)
|
|
||||||
BUILD = $(shell date +%Y.%m.%d.%H%M%S)
|
|
||||||
#VERSION := $(if $(filter $(BRANCH), development),$(version)-$(BRANCH)-$(COMMIT)-$(BUILD),$(version))
|
|
||||||
VERSION := $(version)-$(BRANCH)-$(COMMIT)-$(BUILD)
|
|
||||||
SHORTVERSION := $(version)-$(BRANCH)-$(COMMIT)
|
|
||||||
LDFLAGS := -ldflags "-X 'openquell/config.VERSION=$(VERSION)'"
|
|
||||||
|
|
||||||
all: clean build
|
all: clean build
|
||||||
@echo ok
|
@echo ok
|
||||||
|
|
||||||
@@ -14,19 +5,8 @@ clean:
|
|||||||
rm -f openquell
|
rm -f openquell
|
||||||
|
|
||||||
build:
|
build:
|
||||||
go build -ldflags "-X 'openquell/config.VERSION=$(VERSION)'"
|
go build
|
||||||
|
|
||||||
buildwasm:
|
|
||||||
env GOOS=js GOARCH=wasm go build -o openquell.wasm $(LDFLAGS) .
|
|
||||||
|
|
||||||
buildwindows:
|
|
||||||
GOOS=windows GOARCH=amd64 go build $(LDFLAGS) -o openquell.exe
|
|
||||||
|
|
||||||
zipwasm:
|
|
||||||
zip -r openquell-$(SHORTVERSION).zip index.html openquell.wasm wasm_exec.js
|
|
||||||
|
|
||||||
wasm: buildwasm zipwasm
|
|
||||||
@ls -l openquell-$(SHORTVERSION).zip
|
|
||||||
|
|
||||||
test:
|
test:
|
||||||
@echo $(VERSION)
|
@echo 1
|
||||||
|
|||||||
84
TODO.md
@@ -1,70 +1,32 @@
|
|||||||
## Levels:
|
## Levels:
|
||||||
|
|
||||||
|
- ignore comments in lvl files
|
||||||
|
|
||||||
|
- check when sphere bounces from one end to the other endlessly w/o
|
||||||
|
any solids in between. this is a game lock and equals game over
|
||||||
|
|
||||||
|
- Start the game end timer and add a score FIXME: put the actual max
|
||||||
|
reachable score into the level definition along with the minimum
|
||||||
|
steps required to reach it, also add a step counter
|
||||||
|
|
||||||
|
- Grid Observer:
|
||||||
|
https://github.com/mlange-42/arche/issues/374
|
||||||
|
|
||||||
|
- Add some final message when the player reaches the last level, start
|
||||||
|
from scratch or a message to buy me some beer, whatever
|
||||||
|
|
||||||
|
- Check player-player collisions!
|
||||||
|
|
||||||
|
- Add player mergers, possibly as an option, so maybe we could have
|
||||||
|
different primary and secondary players: one pair can merge, the
|
||||||
|
other not. Like S + s and M + m or something.
|
||||||
|
|
||||||
- Add shaders for animation (player destruction etc)
|
- Add shaders for animation (player destruction etc)
|
||||||
|
|
||||||
- Start New game starts with last played level, better add a Resume
|
- Add player HUD + Stats (as hud_system!)
|
||||||
Game menu item for this and use Start New always for level 1.
|
|
||||||
|
|
||||||
- for finding caller:
|
|
||||||
pc := make([]uintptr, 10)
|
|
||||||
n := runtime.Callers(0, pc)
|
|
||||||
pc = pc[:n]
|
|
||||||
fs := runtime.CallersFrames(pc)
|
|
||||||
source, _ := fs.Next()
|
|
||||||
source, _ = fs.Next()
|
|
||||||
source, _ = fs.Next()
|
|
||||||
|
|
||||||
slog.Debug("get observer", "minmoves", observer.LevelScore,
|
## Collider Rework
|
||||||
"file", source.File, "line", source.Line)
|
|
||||||
|
|
||||||
- Turn menu button in hud_system (events in level_scene!) into ebitenui button
|
|
||||||
|
|
||||||
- Obstacle don't stop at collectibles
|
|
||||||
|
|
||||||
- Player can collect collectible hidden under obstacle (should be
|
|
||||||
fixed when above is fixed)
|
|
||||||
|
|
||||||
- Add player idle animation
|
|
||||||
|
|
||||||
- Add player collision animation
|
|
||||||
|
|
||||||
- Create pixel art ui elements (button, list things) and ui borders/backgrounds
|
|
||||||
|
|
||||||
- Modify font and font color matching the palette
|
|
||||||
|
|
||||||
- Replace HUD with pixel art variant
|
|
||||||
|
|
||||||
- On game start respond to any key (ebitengine-input has an anykey func)
|
|
||||||
|
|
||||||
- Switch to use https://github.com/quasilyte/ebitengine-input
|
|
||||||
|
|
||||||
- Add drag support: point and hold on the player, move cursor in some
|
|
||||||
direction and let the player start moving on release. Respond to
|
|
||||||
mouse and touch pad. See ~/tmp/ebiten/examples/drag/.
|
|
||||||
|
|
||||||
- Add options scene (mouse, player speed, sound options etc)
|
|
||||||
|
|
||||||
- Add save to disk feature including settings and player
|
|
||||||
accomplishements (FIXME: find the lib, asked in Discord)
|
|
||||||
|
|
||||||
- Add coded animated background like in https://github.com/tinne26/bindless/tree/main/src/misc/background
|
|
||||||
|
|
||||||
- Rework sprites (again!) to match stellar background: maybe more
|
|
||||||
technical tiles and items? Like some robotic setup?
|
|
||||||
|
|
||||||
- Fix collision snapin: sometimes, when an entity moves to the right
|
|
||||||
or south (NOT left or north!) it snaps in visibly, so a short wobble
|
|
||||||
can be seen.
|
|
||||||
|
|
||||||
- Rework animation system: since it is impossible to assign multiple
|
|
||||||
animation types to an entity via LDTK, hard code it in Tiles. Keep
|
|
||||||
implementation though. CAUTION: last time I changed this, the
|
|
||||||
collectible detonation didn't work anymore!
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Collider Rework [abandoned: see branch collider-system, fails]
|
|
||||||
|
|
||||||
- do not use the map anymore for collision detection
|
- do not use the map anymore for collision detection
|
||||||
- central collision_system
|
- central collision_system
|
||||||
|
|||||||
17
assets/levels/00-deadly-obstacles.lvl
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
Description: test obstacles
|
||||||
|
Background: background-lila
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#######
|
||||||
|
#o #
|
||||||
|
# t #
|
||||||
|
#> S <#
|
||||||
|
# #
|
||||||
|
# ^ #
|
||||||
|
#######
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
17
assets/levels/01-friendly-obstacles.lvl
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
Description: test obstacles
|
||||||
|
Background: background-lila
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#############
|
||||||
|
# t #
|
||||||
|
#> S # #
|
||||||
|
# ># ^#
|
||||||
|
#< #W#####
|
||||||
|
# o v# o#
|
||||||
|
#############
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
17
assets/levels/02-start.lvl
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
Description: find the fruit
|
||||||
|
Background: background-lila
|
||||||
|
|
||||||
|
|
||||||
|
# ############
|
||||||
|
# #
|
||||||
|
############ #
|
||||||
|
# o S #
|
||||||
|
# ######## ###
|
||||||
|
+ #
|
||||||
|
############ #
|
||||||
|
# o # #
|
||||||
|
# # ######## #
|
||||||
|
# # o
|
||||||
|
# ############
|
||||||
|
|
||||||
|
|
||||||
17
assets/levels/03-own.lvl
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
Description: win
|
||||||
|
Background: background-lila
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
########
|
||||||
|
#v o #
|
||||||
|
# S<# #
|
||||||
|
# #### #
|
||||||
|
|
||||||
|
|
||||||
|
# #### #
|
||||||
|
# #
|
||||||
|
#> ^#
|
||||||
|
########
|
||||||
|
|
||||||
17
assets/levels/04-mayhem.lvl
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
Description: use multiple players
|
||||||
|
Background: background-lila
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
########W#
|
||||||
|
# v #
|
||||||
|
# #
|
||||||
|
#S s#
|
||||||
|
############
|
||||||
|
# o #
|
||||||
|
######## #
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
17
assets/levels/05-space.lvl
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
Description: space
|
||||||
|
Background: background-lila
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#
|
||||||
|
|
||||||
|
|
||||||
|
S
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
30
assets/levels/gen.sh
Executable file
@@ -0,0 +1,30 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
width=$(grep "width " ../../main.go | awk '{print $4}')
|
||||||
|
height=$(grep "height " ../../main.go | awk '{print $4}')
|
||||||
|
|
||||||
|
read -p " Enter level name: " name
|
||||||
|
read -p " Enter background: " background
|
||||||
|
read -p "Enter description: " des
|
||||||
|
|
||||||
|
if test -z "$name"; then
|
||||||
|
name="newlevel"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if test -z "$bbackground"; then
|
||||||
|
background="background-lila"
|
||||||
|
fi
|
||||||
|
|
||||||
|
w=$(($width/32))
|
||||||
|
h=$(($height/32))
|
||||||
|
|
||||||
|
(
|
||||||
|
echo "Description: $des"
|
||||||
|
echo "Background: $background"
|
||||||
|
|
||||||
|
for x in $(seq 1 $h); do
|
||||||
|
for y in $(seq 1 $w); do
|
||||||
|
echo -n " "
|
||||||
|
done
|
||||||
|
echo
|
||||||
|
done
|
||||||
|
)
|
||||||
@@ -1,79 +1,63 @@
|
|||||||
package assets
|
package assets
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bufio"
|
||||||
_ "image/png"
|
_ "image/png"
|
||||||
|
"io/fs"
|
||||||
"log"
|
"log"
|
||||||
|
"log/slog"
|
||||||
"openquell/config"
|
"openquell/config"
|
||||||
"openquell/util"
|
"openquell/util"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"sort"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/hajimehoshi/ebiten/v2"
|
"github.com/hajimehoshi/ebiten/v2"
|
||||||
"github.com/solarlune/ldtkgo"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var Project = LoadLDTK("levels")
|
var Levels = LoadLevels("levels")
|
||||||
var Tiles = InitTiles()
|
var Tiles = InitTiles()
|
||||||
|
|
||||||
type TileAnimation struct {
|
|
||||||
OnCollision bool // wether to animate a collision
|
|
||||||
OnDestruction bool // wether to animate destruction
|
|
||||||
OnIdle bool // wether to animate during idling
|
|
||||||
|
|
||||||
CollisionSheet AnimationSet // an entry in assets.Animations[name]
|
|
||||||
DestructionSheet AnimationSet
|
|
||||||
IdleSheet AnimationSet
|
|
||||||
}
|
|
||||||
|
|
||||||
// Tile: contains image, identifier (as used in level data) and
|
// Tile: contains image, identifier (as used in level data) and
|
||||||
// additional properties
|
// additional properties
|
||||||
type Tile struct {
|
type Tile struct {
|
||||||
Id, Ref string
|
Id byte
|
||||||
Sprite *ebiten.Image
|
Sprite *ebiten.Image
|
||||||
ToggleSprite *ebiten.Image
|
Class string
|
||||||
Solid bool // wall brick
|
Solid bool // wall brick
|
||||||
Player bool // player sphere
|
Player bool // player sphere
|
||||||
IsPrimary bool // primary player sphere
|
IsPrimary bool // primary player sphere
|
||||||
Renderable bool // visible, has sprite
|
Renderable bool // visible, has sprite
|
||||||
Velocity bool // movable
|
Velocity bool // movable
|
||||||
Collectible bool // collectible, vanishes once collected
|
Collectible bool // collectible, vanishes once collected
|
||||||
Transient bool // turns into brick wall when traversed
|
Transient bool // turns into brick wall when traversed
|
||||||
Destroyable bool // turns into empty floor when bumped into twice
|
Destroyable bool // turns into empty floor when bumped into twice
|
||||||
Tiles []*ebiten.Image // has N sprites
|
Particle int // -1=unused, 0-3 = show image of slice
|
||||||
TileNames []string // same thing, only the names
|
Tiles []*ebiten.Image // has N sprites
|
||||||
Obstacle bool // is an obstacle/enemy
|
TileNames []string // same thing, only the names
|
||||||
Direction int // obstacle business end shows into this direction
|
Obstacle bool // is an obstacle/enemy
|
||||||
Shader *ebiten.Shader
|
Direction int // obstacle business end shows into this direction
|
||||||
Alpha *ebiten.Image
|
|
||||||
Bond bool // denotes an entity which can have a relation to another
|
|
||||||
Door bool // a door, can be manipulated by a switch
|
|
||||||
Switch bool // opens|closes a door
|
|
||||||
Animation TileAnimation
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (tile *Tile) Clone() *Tile {
|
func (tile *Tile) Clone() *Tile {
|
||||||
newtile := &Tile{
|
newtile := &Tile{
|
||||||
Id: tile.Id,
|
Id: tile.Id,
|
||||||
Ref: tile.Ref,
|
Sprite: tile.Sprite,
|
||||||
Sprite: tile.Sprite,
|
Class: tile.Class,
|
||||||
ToggleSprite: tile.ToggleSprite,
|
Solid: tile.Solid,
|
||||||
Solid: tile.Solid,
|
Player: tile.Player,
|
||||||
Player: tile.Player,
|
IsPrimary: tile.IsPrimary,
|
||||||
IsPrimary: tile.IsPrimary,
|
Renderable: tile.Renderable,
|
||||||
Renderable: tile.Renderable,
|
Velocity: tile.Velocity,
|
||||||
Velocity: tile.Velocity,
|
Collectible: tile.Collectible,
|
||||||
Collectible: tile.Collectible,
|
Transient: tile.Transient,
|
||||||
Transient: tile.Transient,
|
Destroyable: tile.Destroyable,
|
||||||
Destroyable: tile.Destroyable,
|
Particle: tile.Particle,
|
||||||
Tiles: tile.Tiles,
|
Tiles: tile.Tiles,
|
||||||
TileNames: tile.TileNames,
|
TileNames: tile.TileNames,
|
||||||
Obstacle: tile.Obstacle,
|
Obstacle: tile.Obstacle,
|
||||||
Direction: tile.Direction,
|
Direction: tile.Direction,
|
||||||
Alpha: tile.Alpha,
|
|
||||||
Shader: tile.Shader,
|
|
||||||
Bond: tile.Bond,
|
|
||||||
Door: tile.Door,
|
|
||||||
Switch: tile.Switch,
|
|
||||||
Animation: tile.Animation,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return newtile
|
return newtile
|
||||||
@@ -84,52 +68,55 @@ const (
|
|||||||
Secondary bool = false
|
Secondary bool = false
|
||||||
)
|
)
|
||||||
|
|
||||||
func GetSprites(class []string) []*ebiten.Image {
|
|
||||||
sprites := []*ebiten.Image{}
|
|
||||||
|
|
||||||
for _, sprite := range class {
|
|
||||||
sprites = append(sprites, Assets[sprite])
|
|
||||||
}
|
|
||||||
|
|
||||||
return sprites
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewTilePlayer(isprimary bool) *Tile {
|
func NewTilePlayer(isprimary bool) *Tile {
|
||||||
tile := &Tile{
|
tile := &Tile{
|
||||||
|
Id: 'S',
|
||||||
|
Class: "sphere",
|
||||||
Renderable: true,
|
Renderable: true,
|
||||||
Player: true,
|
Player: true,
|
||||||
Velocity: true,
|
Velocity: true,
|
||||||
IsPrimary: isprimary,
|
IsPrimary: isprimary,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
switch isprimary {
|
||||||
|
case Primary:
|
||||||
|
tile.Sprite = Assets["sphere-blue"]
|
||||||
|
case Secondary:
|
||||||
|
tile.Sprite = Assets["sphere-blue-secondary"]
|
||||||
|
tile.Id = 's'
|
||||||
|
}
|
||||||
|
|
||||||
// primary sprite is always the first one
|
// primary sprite is always the first one
|
||||||
tile.Tiles = []*ebiten.Image{Assets["sphere"], Assets["sphere-small"]}
|
tile.Tiles = []*ebiten.Image{Assets["sphere-blue"], Assets["sphere-blue-secondary"]}
|
||||||
return tile
|
return tile
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewTileBlock() *Tile {
|
func NewTileBlock(class string) *Tile {
|
||||||
return &Tile{
|
return &Tile{
|
||||||
|
Id: '#',
|
||||||
|
Sprite: Assets[class],
|
||||||
|
Class: class,
|
||||||
Solid: true,
|
Solid: true,
|
||||||
Renderable: true,
|
Renderable: true,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewTileCollectible() *Tile {
|
func NewTileCollectible(class string) *Tile {
|
||||||
return &Tile{
|
return &Tile{
|
||||||
|
Id: 'o',
|
||||||
|
Sprite: Assets[class],
|
||||||
|
Class: class,
|
||||||
Solid: false,
|
Solid: false,
|
||||||
Renderable: true,
|
Renderable: true,
|
||||||
Collectible: true,
|
Collectible: true,
|
||||||
Animation: TileAnimation{
|
|
||||||
OnDestruction: true,
|
|
||||||
DestructionSheet: Animations["collectible-detonating"],
|
|
||||||
OnIdle: true,
|
|
||||||
IdleSheet: Animations["collectible-idle"],
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewTileObstacle(direction int) *Tile {
|
func NewTileObstacle(class string, direction int) *Tile {
|
||||||
return &Tile{
|
return &Tile{
|
||||||
|
Id: '+',
|
||||||
|
Sprite: Assets[class],
|
||||||
|
Class: class,
|
||||||
Solid: false,
|
Solid: false,
|
||||||
Renderable: true,
|
Renderable: true,
|
||||||
Obstacle: true,
|
Obstacle: true,
|
||||||
@@ -138,122 +125,184 @@ func NewTileObstacle(direction int) *Tile {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewTileTranswall() *Tile {
|
func NewTileParticle(class []string) *Tile {
|
||||||
|
sprites := []*ebiten.Image{}
|
||||||
|
|
||||||
|
for _, sprite := range class {
|
||||||
|
sprites = append(sprites, Assets[sprite])
|
||||||
|
}
|
||||||
|
|
||||||
return &Tile{
|
return &Tile{
|
||||||
|
Id: '*',
|
||||||
|
Class: "particle",
|
||||||
|
Solid: false,
|
||||||
|
Renderable: false,
|
||||||
|
Particle: 0,
|
||||||
|
Tiles: sprites,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewTileTranswall(class []string) *Tile {
|
||||||
|
sprites := []*ebiten.Image{}
|
||||||
|
names := []string{}
|
||||||
|
|
||||||
|
for _, sprite := range class {
|
||||||
|
sprites = append(sprites, Assets[sprite])
|
||||||
|
names = append(names, sprite)
|
||||||
|
}
|
||||||
|
|
||||||
|
return &Tile{
|
||||||
|
Id: 't',
|
||||||
|
Class: "transwall",
|
||||||
Solid: false,
|
Solid: false,
|
||||||
Renderable: true,
|
Renderable: true,
|
||||||
Transient: true,
|
Transient: true,
|
||||||
|
Tiles: sprites,
|
||||||
|
Sprite: sprites[0], // initially use the first
|
||||||
|
TileNames: names,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewTileHiddenDoor(alpha string) *Tile {
|
func NewTileHiddenDoor(class []string) *Tile {
|
||||||
|
sprites := []*ebiten.Image{}
|
||||||
|
names := []string{}
|
||||||
|
|
||||||
|
for _, sprite := range class {
|
||||||
|
sprites = append(sprites, Assets[sprite])
|
||||||
|
names = append(names, sprite)
|
||||||
|
}
|
||||||
|
|
||||||
return &Tile{
|
return &Tile{
|
||||||
|
Id: 'W',
|
||||||
|
Class: "hiddendoor",
|
||||||
Solid: false,
|
Solid: false,
|
||||||
Renderable: true,
|
Renderable: true,
|
||||||
Destroyable: true,
|
Destroyable: true,
|
||||||
Alpha: Assets[alpha],
|
Tiles: sprites,
|
||||||
Shader: Shaders["destruct"],
|
Sprite: sprites[0], // initially use the first
|
||||||
}
|
TileNames: names,
|
||||||
}
|
|
||||||
|
|
||||||
func NewTileSwitch() *Tile {
|
|
||||||
return &Tile{
|
|
||||||
Solid: false,
|
|
||||||
Renderable: true,
|
|
||||||
Bond: true,
|
|
||||||
Switch: true,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewTileDoor() *Tile {
|
|
||||||
return &Tile{
|
|
||||||
Solid: false,
|
|
||||||
Renderable: true,
|
|
||||||
Bond: true,
|
|
||||||
Door: true,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// used to map level data bytes to actual tiles
|
// used to map level data bytes to actual tiles
|
||||||
type TileRegistry map[string]*Tile
|
type TileRegistry map[byte]*Tile
|
||||||
|
|
||||||
|
// holds a raw level spec:
|
||||||
|
//
|
||||||
|
// Name: the name of the level file w/o the .lvl extension
|
||||||
|
// Background: an image name used as game background for this level
|
||||||
|
// Description: text to display on top
|
||||||
|
// Data: a level spec consisting of chars of the above mapping and spaces, e.g.:
|
||||||
|
// ####
|
||||||
|
// # #
|
||||||
|
// ####
|
||||||
|
//
|
||||||
|
// Each level data must be 20 chars wide (= 640 px width) and 15 chars
|
||||||
|
// high (=480 px height).
|
||||||
|
type RawLevel struct {
|
||||||
|
Name string
|
||||||
|
Description string
|
||||||
|
Background *ebiten.Image
|
||||||
|
Data []byte
|
||||||
|
}
|
||||||
|
|
||||||
func InitTiles() TileRegistry {
|
func InitTiles() TileRegistry {
|
||||||
return TileRegistry{
|
return TileRegistry{
|
||||||
"floor": {Renderable: false},
|
' ': {Id: ' ', Class: "floor", Renderable: false},
|
||||||
"default": NewTileBlock(),
|
//'#': NewTileBlock("block-grey32"),
|
||||||
"solidorange": NewTileBlock(),
|
'#': NewTileBlock("block-greycolored"),
|
||||||
"PlayerPrimary": NewTilePlayer(Primary),
|
'B': NewTileBlock("block-orange-32"),
|
||||||
"PlayerSecondary": NewTilePlayer(Secondary),
|
'S': NewTilePlayer(Primary),
|
||||||
"Collectible": NewTileCollectible(),
|
's': NewTilePlayer(Secondary),
|
||||||
"ObstacleStar": NewTileObstacle(config.All),
|
'o': NewTileCollectible("collectible-orange"),
|
||||||
"ObstacleNorth": NewTileObstacle(config.North),
|
'+': NewTileObstacle("obstacle-star", config.All),
|
||||||
"ObstacleSouth": NewTileObstacle(config.South),
|
'^': NewTileObstacle("obstacle-north", config.North),
|
||||||
"ObstacleWest": NewTileObstacle(config.West),
|
'v': NewTileObstacle("obstacle-south", config.South),
|
||||||
"ObstacleEast": NewTileObstacle(config.East),
|
'<': NewTileObstacle("obstacle-west", config.West),
|
||||||
"Transient": NewTileTranswall(),
|
'>': NewTileObstacle("obstacle-east", config.East),
|
||||||
"HiddenDoor": NewTileHiddenDoor("damage"),
|
'*': NewTileParticle([]string{
|
||||||
"HiddenDoor2": NewTileHiddenDoor("damage"),
|
//"particle-ring-1",
|
||||||
"HiddenDoor3": NewTileHiddenDoor("damage"),
|
"particle-ring-2",
|
||||||
"HiddenDoor4": NewTileHiddenDoor("damage"),
|
"particle-ring-3",
|
||||||
"HiddenDoor5": NewTileHiddenDoor("damage"),
|
"particle-ring-4",
|
||||||
"HiddenDoor6": NewTileHiddenDoor("damage"),
|
"particle-ring-5",
|
||||||
"HiddenDoor7": NewTileHiddenDoor("damage"),
|
"particle-ring-6",
|
||||||
"HiddenDoor8": NewTileHiddenDoor("damage"),
|
}),
|
||||||
"HiddenDoor9": NewTileHiddenDoor("damage"),
|
't': NewTileTranswall([]string{"transwall", "block-orange-32"}),
|
||||||
"HiddenDoor10": NewTileHiddenDoor("damage"),
|
'W': NewTileHiddenDoor([]string{"block-greycolored", "block-greycolored-damaged"}),
|
||||||
"HiddenDoor11": NewTileHiddenDoor("damage"),
|
|
||||||
"HiddenDoor12": NewTileHiddenDoor("damage"),
|
|
||||||
"HiddenDoor13": NewTileHiddenDoor("damage"),
|
|
||||||
"Switch": NewTileSwitch(),
|
|
||||||
"Door": NewTileDoor(),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// load LDTK project at compile time into ram
|
// load levels at compile time into ram, creates a slice of raw levels
|
||||||
func LoadLDTK(dir string) *ldtkgo.Project {
|
func LoadLevels(dir string) []RawLevel {
|
||||||
fd, err := assetfs.Open("levels/openquell.ldtk")
|
levels := []RawLevel{}
|
||||||
|
|
||||||
|
// we use embed.FS to iterate over all files in ./levels/
|
||||||
|
entries, err := assetfs.ReadDir(dir)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalf("failed to open LDTK file levels/openquell.ldtk: %s", err)
|
log.Fatalf("failed to read level dir %s: %s", dir, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
sort.Slice(entries, func(i, j int) bool {
|
||||||
|
return entries[i].Name() < entries[j].Name()
|
||||||
|
})
|
||||||
|
|
||||||
|
for _, levelfile := range entries {
|
||||||
|
if levelfile.Type().IsRegular() && strings.Contains(levelfile.Name(), ".lvl") {
|
||||||
|
path := filepath.Join("assets", dir)
|
||||||
|
level := ParseRawLevel(path, levelfile)
|
||||||
|
|
||||||
|
levels = append(levels, level)
|
||||||
|
|
||||||
|
slog.Debug("loaded level", "path", path, "file", levelfile)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return levels
|
||||||
|
}
|
||||||
|
|
||||||
|
func ParseRawLevel(dir string, levelfile fs.DirEntry) RawLevel {
|
||||||
|
fd, err := os.Open(filepath.Join(dir, levelfile.Name()))
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("failed to read level file %s: %s", levelfile.Name(), err)
|
||||||
}
|
}
|
||||||
defer fd.Close()
|
defer fd.Close()
|
||||||
|
|
||||||
fileinfo, err := fd.Stat()
|
name := strings.TrimSuffix(levelfile.Name(), ".lvl")
|
||||||
if err != nil {
|
des := ""
|
||||||
log.Fatalf("failed to stat() LDTK file levels/openquell.ldtk: %s", err)
|
background := &ebiten.Image{}
|
||||||
}
|
data := []byte{}
|
||||||
|
|
||||||
filesize := fileinfo.Size()
|
scanner := bufio.NewScanner(fd)
|
||||||
buffer := make([]byte, filesize)
|
for scanner.Scan() {
|
||||||
|
// ignore any whitespace
|
||||||
|
line := scanner.Text()
|
||||||
|
|
||||||
_, err = fd.Read(buffer)
|
// ignore empty lines
|
||||||
if err != nil {
|
if len(line) == 0 {
|
||||||
log.Fatalf("failed to read bytes from LDTK file levels/openquell.ldtk: %s", err)
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
project, err := ldtkgo.Read(buffer)
|
switch {
|
||||||
if err != nil {
|
case strings.Contains(line, "Background:"):
|
||||||
panic(err)
|
haveit := strings.Split(line, ": ")
|
||||||
}
|
if util.Exists(Assets, haveit[1]) {
|
||||||
|
background = Assets[haveit[1]]
|
||||||
// do some sanity checks
|
|
||||||
properties := []string{"minmoves", "level", "description"}
|
|
||||||
need := len(properties)
|
|
||||||
|
|
||||||
for idx, level := range project.Levels {
|
|
||||||
have := 0
|
|
||||||
|
|
||||||
for _, property := range level.Properties {
|
|
||||||
if util.Contains(properties, property.Identifier) {
|
|
||||||
have++
|
|
||||||
}
|
}
|
||||||
}
|
case strings.Contains(line, "Description:"):
|
||||||
|
haveit := strings.Split(line, ": ")
|
||||||
if have != need {
|
des = haveit[1]
|
||||||
log.Fatalf("level definition for level %d (%s) invalid: %d missing properties\n required: %s",
|
default:
|
||||||
idx, level.Identifier, need-have, strings.Join(properties, ", "),
|
// all other non-empty and non-equalsign lines are
|
||||||
)
|
// level definition matrix data, merge thes into data
|
||||||
|
data = append(data, line+"\n"...)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return project
|
return RawLevel{
|
||||||
|
Name: name,
|
||||||
|
Data: data,
|
||||||
|
Background: background,
|
||||||
|
Description: des,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,49 +0,0 @@
|
|||||||
package assets
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"log"
|
|
||||||
"log/slog"
|
|
||||||
"path"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/hajimehoshi/ebiten/v2"
|
|
||||||
)
|
|
||||||
|
|
||||||
type ShaderRegistry map[string]*ebiten.Shader
|
|
||||||
|
|
||||||
var Shaders = LoadShaders("shaders")
|
|
||||||
|
|
||||||
func LoadShaders(dir string) ShaderRegistry {
|
|
||||||
shaders := ShaderRegistry{}
|
|
||||||
|
|
||||||
entries, err := assetfs.ReadDir(dir)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatalf("failed to read shaders dir %s: %s", dir, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, file := range entries {
|
|
||||||
path := path.Join(dir, file.Name())
|
|
||||||
fd, err := assetfs.Open(path)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatalf("failed to open shader file %s: %s", file.Name(), err)
|
|
||||||
}
|
|
||||||
defer fd.Close()
|
|
||||||
|
|
||||||
name := strings.TrimSuffix(file.Name(), ".kg")
|
|
||||||
|
|
||||||
buf := new(bytes.Buffer)
|
|
||||||
buf.ReadFrom(fd)
|
|
||||||
|
|
||||||
shader, err := ebiten.NewShader([]byte(buf.Bytes()))
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
shaders[name] = shader
|
|
||||||
|
|
||||||
slog.Debug("loaded shader asset", "path", path)
|
|
||||||
}
|
|
||||||
|
|
||||||
return shaders
|
|
||||||
}
|
|
||||||
@@ -1,17 +1,14 @@
|
|||||||
package assets
|
package assets
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
|
||||||
"embed"
|
"embed"
|
||||||
"encoding/json"
|
|
||||||
"image"
|
"image"
|
||||||
_ "image/png"
|
_ "image/png"
|
||||||
"io/fs"
|
|
||||||
"log"
|
"log"
|
||||||
"log/slog"
|
"log/slog"
|
||||||
"path"
|
"os"
|
||||||
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/hajimehoshi/ebiten/v2"
|
"github.com/hajimehoshi/ebiten/v2"
|
||||||
)
|
)
|
||||||
@@ -19,64 +16,13 @@ import (
|
|||||||
// Maps image name to image data
|
// Maps image name to image data
|
||||||
type AssetRegistry map[string]*ebiten.Image
|
type AssetRegistry map[string]*ebiten.Image
|
||||||
|
|
||||||
// A helper to pass the registry easier around
|
//go:embed levels/*.lvl sprites/*.png fonts/*.ttf
|
||||||
type assetData struct {
|
|
||||||
Registry AssetRegistry
|
|
||||||
}
|
|
||||||
|
|
||||||
// to parse asesprite animation json
|
|
||||||
type AnimationGeo struct {
|
|
||||||
X int `json:"x"`
|
|
||||||
Y int `json:"y"`
|
|
||||||
Width int `json:"w"`
|
|
||||||
Height int `json:"h"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type AnimationFrame struct {
|
|
||||||
Position AnimationGeo `json:"frame"`
|
|
||||||
Duration int `json:"duration"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type AnimationMeta struct {
|
|
||||||
Name string `json:"image"`
|
|
||||||
Geo AnimationGeo `json:"size"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// Needed to thaw sprite set written by asesprite
|
|
||||||
type AnimationJSON struct {
|
|
||||||
Meta AnimationMeta `json:"Meta"`
|
|
||||||
Frames []AnimationFrame `json:"frames"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// used to store Animation data
|
|
||||||
type AnimationSprite struct {
|
|
||||||
Sprite *ebiten.Image
|
|
||||||
Duration time.Duration
|
|
||||||
}
|
|
||||||
|
|
||||||
type AnimationSet struct {
|
|
||||||
Width, Height int
|
|
||||||
Sprites []AnimationSprite
|
|
||||||
File string
|
|
||||||
}
|
|
||||||
|
|
||||||
// names in the registry match the sprite set png file name, the JSON
|
|
||||||
// file names are irrelevant as they point to the matching file using
|
|
||||||
// the "image" field.
|
|
||||||
type AnimationRegistry map[string]AnimationSet
|
|
||||||
|
|
||||||
//go:embed sprites/*.png fonts/*.ttf levels/*.ldtk shaders/*.kg sprites/*.json
|
|
||||||
var assetfs embed.FS
|
var assetfs embed.FS
|
||||||
|
|
||||||
// Called at build time, creates the global asset and animation registries
|
var Assets = LoadImages("sprites")
|
||||||
var Assets, Animations = LoadImages()
|
|
||||||
|
|
||||||
// load pngs and json files
|
func LoadImages(dir string) AssetRegistry {
|
||||||
func LoadImages() (AssetRegistry, AnimationRegistry) {
|
images := AssetRegistry{}
|
||||||
dir := "sprites"
|
|
||||||
imagedata := &assetData{}
|
|
||||||
imagedata.Registry = AssetRegistry{}
|
|
||||||
rawanimations := []AnimationJSON{}
|
|
||||||
|
|
||||||
// we use embed.FS to iterate over all files in ./assets/
|
// we use embed.FS to iterate over all files in ./assets/
|
||||||
entries, err := assetfs.ReadDir(dir)
|
entries, err := assetfs.ReadDir(dir)
|
||||||
@@ -85,93 +31,24 @@ func LoadImages() (AssetRegistry, AnimationRegistry) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for _, imagefile := range entries {
|
for _, imagefile := range entries {
|
||||||
path := path.Join(dir, imagefile.Name())
|
path := filepath.Join("assets", dir, imagefile.Name())
|
||||||
|
fd, err := os.Open(path)
|
||||||
fd, err := assetfs.Open(path)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalf("failed to open file %s: %s", imagefile.Name(), err)
|
log.Fatalf("failed to open image file %s: %s", imagefile.Name(), err)
|
||||||
}
|
}
|
||||||
defer fd.Close()
|
defer fd.Close()
|
||||||
|
|
||||||
switch {
|
name := strings.TrimSuffix(imagefile.Name(), ".png")
|
||||||
case strings.HasSuffix(path, ".png"):
|
|
||||||
name, image := ReadImage(imagefile, fd)
|
|
||||||
imagedata.Registry[name] = image
|
|
||||||
|
|
||||||
case strings.HasSuffix(path, ".json"):
|
img, _, err := image.Decode(fd)
|
||||||
animationjson := ReadJson(imagefile, fd)
|
if err != nil {
|
||||||
rawanimations = append(rawanimations, animationjson)
|
log.Fatalf("failed to decode image %s: %s", imagefile.Name(), err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
images[name] = ebiten.NewImageFromImage(img)
|
||||||
|
|
||||||
slog.Debug("loaded asset", "path", path)
|
slog.Debug("loaded asset", "path", path)
|
||||||
}
|
}
|
||||||
|
|
||||||
// preprocess animation sprites
|
return images
|
||||||
animations := ProcessAnimations(rawanimations, imagedata)
|
|
||||||
|
|
||||||
return imagedata.Registry, animations
|
|
||||||
}
|
|
||||||
|
|
||||||
func ReadImage(imagefile fs.DirEntry, fd fs.File) (string, *ebiten.Image) {
|
|
||||||
name := strings.TrimSuffix(imagefile.Name(), ".png")
|
|
||||||
|
|
||||||
img, _, err := image.Decode(fd)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatalf("failed to decode image %s: %s", imagefile.Name(), err)
|
|
||||||
}
|
|
||||||
|
|
||||||
image := ebiten.NewImageFromImage(img)
|
|
||||||
|
|
||||||
return name, image
|
|
||||||
}
|
|
||||||
|
|
||||||
func ReadJson(imagefile fs.DirEntry, fd fs.File) AnimationJSON {
|
|
||||||
buf := new(bytes.Buffer)
|
|
||||||
buf.ReadFrom(fd)
|
|
||||||
|
|
||||||
animationjson := AnimationJSON{}
|
|
||||||
|
|
||||||
err := json.Unmarshal(buf.Bytes(), &animationjson)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatalf("failed to parse JSON: %s", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return animationjson
|
|
||||||
}
|
|
||||||
|
|
||||||
// turn a raw JSON from Asesprite into something we can use better
|
|
||||||
// internally we also load all the sprites of an animation by using
|
|
||||||
// image.SubImage() on the spriteset matching the animation name.
|
|
||||||
// so, if the animation JSON is called "player-idle.json", then we
|
|
||||||
// expect to receive the spriteset in a file "player-idle.png", which
|
|
||||||
// has of course already been loaded at this stage. These spritesets
|
|
||||||
// must contain a row of sprites. We get the measurements from the JSON.
|
|
||||||
func ProcessAnimations(rawanimations []AnimationJSON, imagedata *assetData) AnimationRegistry {
|
|
||||||
animations := AnimationRegistry{}
|
|
||||||
|
|
||||||
for _, animation := range rawanimations {
|
|
||||||
animationset := AnimationSet{}
|
|
||||||
|
|
||||||
animationset.File = strings.TrimSuffix(animation.Meta.Name, ".png")
|
|
||||||
|
|
||||||
for _, frame := range animation.Frames {
|
|
||||||
sprite := imagedata.Registry[animationset.File].SubImage(
|
|
||||||
image.Rect(
|
|
||||||
frame.Position.X,
|
|
||||||
frame.Position.Y,
|
|
||||||
frame.Position.X+frame.Position.Width,
|
|
||||||
frame.Position.Y+frame.Position.Height,
|
|
||||||
)).(*ebiten.Image)
|
|
||||||
|
|
||||||
animationset.Sprites = append(animationset.Sprites,
|
|
||||||
AnimationSprite{Sprite: sprite, Duration: time.Duration(frame.Duration)})
|
|
||||||
}
|
|
||||||
|
|
||||||
animationset.Width = animationset.Sprites[0].Sprite.Bounds().Dx()
|
|
||||||
animationset.Height = animationset.Sprites[0].Sprite.Bounds().Dy()
|
|
||||||
|
|
||||||
animations[animationset.File] = animationset
|
|
||||||
}
|
|
||||||
|
|
||||||
return animations
|
|
||||||
}
|
}
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 50 KiB |
|
Before Width: | Height: | Size: 50 KiB |
@@ -1,164 +0,0 @@
|
|||||||
{ "frames": [
|
|
||||||
{
|
|
||||||
"filename": "collectible-detonating 0.ase",
|
|
||||||
"frame": { "x": 0, "y": 0, "w": 64, "h": 64 },
|
|
||||||
"rotated": false,
|
|
||||||
"trimmed": false,
|
|
||||||
"spriteSourceSize": { "x": 0, "y": 0, "w": 64, "h": 64 },
|
|
||||||
"sourceSize": { "w": 64, "h": 64 },
|
|
||||||
"duration": 100
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"filename": "collectible-detonating 1.ase",
|
|
||||||
"frame": { "x": 64, "y": 0, "w": 64, "h": 64 },
|
|
||||||
"rotated": false,
|
|
||||||
"trimmed": false,
|
|
||||||
"spriteSourceSize": { "x": 0, "y": 0, "w": 64, "h": 64 },
|
|
||||||
"sourceSize": { "w": 64, "h": 64 },
|
|
||||||
"duration": 100
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"filename": "collectible-detonating 2.ase",
|
|
||||||
"frame": { "x": 128, "y": 0, "w": 64, "h": 64 },
|
|
||||||
"rotated": false,
|
|
||||||
"trimmed": false,
|
|
||||||
"spriteSourceSize": { "x": 0, "y": 0, "w": 64, "h": 64 },
|
|
||||||
"sourceSize": { "w": 64, "h": 64 },
|
|
||||||
"duration": 100
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"filename": "collectible-detonating 3.ase",
|
|
||||||
"frame": { "x": 192, "y": 0, "w": 64, "h": 64 },
|
|
||||||
"rotated": false,
|
|
||||||
"trimmed": false,
|
|
||||||
"spriteSourceSize": { "x": 0, "y": 0, "w": 64, "h": 64 },
|
|
||||||
"sourceSize": { "w": 64, "h": 64 },
|
|
||||||
"duration": 100
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"filename": "collectible-detonating 4.ase",
|
|
||||||
"frame": { "x": 256, "y": 0, "w": 64, "h": 64 },
|
|
||||||
"rotated": false,
|
|
||||||
"trimmed": false,
|
|
||||||
"spriteSourceSize": { "x": 0, "y": 0, "w": 64, "h": 64 },
|
|
||||||
"sourceSize": { "w": 64, "h": 64 },
|
|
||||||
"duration": 100
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"filename": "collectible-detonating 5.ase",
|
|
||||||
"frame": { "x": 320, "y": 0, "w": 64, "h": 64 },
|
|
||||||
"rotated": false,
|
|
||||||
"trimmed": false,
|
|
||||||
"spriteSourceSize": { "x": 0, "y": 0, "w": 64, "h": 64 },
|
|
||||||
"sourceSize": { "w": 64, "h": 64 },
|
|
||||||
"duration": 100
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"filename": "collectible-detonating 6.ase",
|
|
||||||
"frame": { "x": 384, "y": 0, "w": 64, "h": 64 },
|
|
||||||
"rotated": false,
|
|
||||||
"trimmed": false,
|
|
||||||
"spriteSourceSize": { "x": 0, "y": 0, "w": 64, "h": 64 },
|
|
||||||
"sourceSize": { "w": 64, "h": 64 },
|
|
||||||
"duration": 100
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"filename": "collectible-detonating 7.ase",
|
|
||||||
"frame": { "x": 448, "y": 0, "w": 64, "h": 64 },
|
|
||||||
"rotated": false,
|
|
||||||
"trimmed": false,
|
|
||||||
"spriteSourceSize": { "x": 0, "y": 0, "w": 64, "h": 64 },
|
|
||||||
"sourceSize": { "w": 64, "h": 64 },
|
|
||||||
"duration": 100
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"filename": "collectible-detonating 8.ase",
|
|
||||||
"frame": { "x": 512, "y": 0, "w": 64, "h": 64 },
|
|
||||||
"rotated": false,
|
|
||||||
"trimmed": false,
|
|
||||||
"spriteSourceSize": { "x": 0, "y": 0, "w": 64, "h": 64 },
|
|
||||||
"sourceSize": { "w": 64, "h": 64 },
|
|
||||||
"duration": 100
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"filename": "collectible-detonating 9.ase",
|
|
||||||
"frame": { "x": 576, "y": 0, "w": 64, "h": 64 },
|
|
||||||
"rotated": false,
|
|
||||||
"trimmed": false,
|
|
||||||
"spriteSourceSize": { "x": 0, "y": 0, "w": 64, "h": 64 },
|
|
||||||
"sourceSize": { "w": 64, "h": 64 },
|
|
||||||
"duration": 100
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"filename": "collectible-detonating 10.ase",
|
|
||||||
"frame": { "x": 640, "y": 0, "w": 64, "h": 64 },
|
|
||||||
"rotated": false,
|
|
||||||
"trimmed": false,
|
|
||||||
"spriteSourceSize": { "x": 0, "y": 0, "w": 64, "h": 64 },
|
|
||||||
"sourceSize": { "w": 64, "h": 64 },
|
|
||||||
"duration": 100
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"filename": "collectible-detonating 11.ase",
|
|
||||||
"frame": { "x": 704, "y": 0, "w": 64, "h": 64 },
|
|
||||||
"rotated": false,
|
|
||||||
"trimmed": false,
|
|
||||||
"spriteSourceSize": { "x": 0, "y": 0, "w": 64, "h": 64 },
|
|
||||||
"sourceSize": { "w": 64, "h": 64 },
|
|
||||||
"duration": 100
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"filename": "collectible-detonating 12.ase",
|
|
||||||
"frame": { "x": 768, "y": 0, "w": 64, "h": 64 },
|
|
||||||
"rotated": false,
|
|
||||||
"trimmed": false,
|
|
||||||
"spriteSourceSize": { "x": 0, "y": 0, "w": 64, "h": 64 },
|
|
||||||
"sourceSize": { "w": 64, "h": 64 },
|
|
||||||
"duration": 100
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"filename": "collectible-detonating 13.ase",
|
|
||||||
"frame": { "x": 832, "y": 0, "w": 64, "h": 64 },
|
|
||||||
"rotated": false,
|
|
||||||
"trimmed": false,
|
|
||||||
"spriteSourceSize": { "x": 0, "y": 0, "w": 64, "h": 64 },
|
|
||||||
"sourceSize": { "w": 64, "h": 64 },
|
|
||||||
"duration": 100
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"filename": "collectible-detonating 14.ase",
|
|
||||||
"frame": { "x": 896, "y": 0, "w": 64, "h": 64 },
|
|
||||||
"rotated": false,
|
|
||||||
"trimmed": false,
|
|
||||||
"spriteSourceSize": { "x": 0, "y": 0, "w": 64, "h": 64 },
|
|
||||||
"sourceSize": { "w": 64, "h": 64 },
|
|
||||||
"duration": 100
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"meta": {
|
|
||||||
"app": "http://www.aseprite.org/",
|
|
||||||
"version": "1.x-dev",
|
|
||||||
"image": "collectible-detonating.png",
|
|
||||||
"format": "RGBA8888",
|
|
||||||
"size": { "w": 960, "h": 64 },
|
|
||||||
"scale": "1",
|
|
||||||
"frameTags": [
|
|
||||||
],
|
|
||||||
"layers": [
|
|
||||||
{ "name": "Yellow Sphere", "opacity": 255, "blendMode": "normal" },
|
|
||||||
{ "name": "Layer 8", "opacity": 255, "blendMode": "normal" },
|
|
||||||
{ "name": "Layer 7", "opacity": 255, "blendMode": "normal" },
|
|
||||||
{ "name": "Layer 6", "opacity": 255, "blendMode": "normal" },
|
|
||||||
{ "name": "Layer 5", "opacity": 255, "blendMode": "normal" },
|
|
||||||
{ "name": "Layer 4", "opacity": 255, "blendMode": "normal" },
|
|
||||||
{ "name": "Layer 3", "opacity": 255, "blendMode": "normal" },
|
|
||||||
{ "name": "Layer 2", "opacity": 255, "blendMode": "normal" },
|
|
||||||
{ "name": "Layer 1", "opacity": 255, "blendMode": "normal" },
|
|
||||||
{ "name": "Blitz Outer", "opacity": 70, "blendMode": "normal" },
|
|
||||||
{ "name": "Blitz Middle", "opacity": 84, "blendMode": "normal" },
|
|
||||||
{ "name": "Blitz Inner", "opacity": 97, "blendMode": "normal" }
|
|
||||||
],
|
|
||||||
"slices": [
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
Before Width: | Height: | Size: 6.6 KiB |
|
Before Width: | Height: | Size: 647 B |
|
Before Width: | Height: | Size: 689 B |
|
Before Width: | Height: | Size: 472 B |
|
Before Width: | Height: | Size: 325 B |
|
Before Width: | Height: | Size: 179 B |
|
Before Width: | Height: | Size: 179 B |
|
Before Width: | Height: | Size: 109 B |
|
Before Width: | Height: | Size: 716 B |
|
Before Width: | Height: | Size: 783 B |
|
Before Width: | Height: | Size: 802 B |
|
Before Width: | Height: | Size: 1.1 KiB |
|
Before Width: | Height: | Size: 909 B |
|
Before Width: | Height: | Size: 924 B |
|
Before Width: | Height: | Size: 937 B |
|
Before Width: | Height: | Size: 876 B |
|
Before Width: | Height: | Size: 577 B |
|
Before Width: | Height: | Size: 5.4 KiB |
|
Before Width: | Height: | Size: 1.1 KiB |
|
Before Width: | Height: | Size: 271 B |
|
Before Width: | Height: | Size: 43 KiB |
|
Before Width: | Height: | Size: 1.7 KiB |
@@ -1,2 +0,0 @@
|
|||||||
#!/bin/sh
|
|
||||||
montage -tile 4x0 -geometry +0+0 block* collectible-orange.png obstacle-* sphere-blue* transwall.png map.png && okular map.png
|
|
||||||
|
Before Width: | Height: | Size: 14 KiB |
|
Before Width: | Height: | Size: 4.3 KiB |
|
Before Width: | Height: | Size: 5.3 KiB |
|
Before Width: | Height: | Size: 5.3 KiB |
|
Before Width: | Height: | Size: 5.3 KiB |
|
Before Width: | Height: | Size: 5.3 KiB |
|
Before Width: | Height: | Size: 5.3 KiB |
|
Before Width: | Height: | Size: 132 KiB |
|
Before Width: | Height: | Size: 503 B |
|
Before Width: | Height: | Size: 543 B |
|
Before Width: | Height: | Size: 141 KiB |
|
Before Width: | Height: | Size: 1.2 KiB |
@@ -1,36 +0,0 @@
|
|||||||
// Copyright 2020 The Ebiten Authors
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
// you may not use this file except in compliance with the License.
|
|
||||||
// You may obtain a copy of the License at
|
|
||||||
//
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
// See the License for the specific language governing permissions and
|
|
||||||
// limitations under the License.
|
|
||||||
|
|
||||||
//go:build ignore
|
|
||||||
|
|
||||||
//kage:unit pixels
|
|
||||||
|
|
||||||
package main
|
|
||||||
|
|
||||||
var Damaged int
|
|
||||||
|
|
||||||
const HP float = 0
|
|
||||||
|
|
||||||
func Fragment(_ vec4, texCoord vec2, _ vec4) vec4 {
|
|
||||||
wallpx := imageSrc0At(texCoord) // A pixel from the wall tile
|
|
||||||
mask := imageSrc1At(texCoord) // A pixel from the damage mask image
|
|
||||||
|
|
||||||
if Damaged == 1 && (wallpx.a != 0.0 && mask.a != 0.0) {
|
|
||||||
alpha := clamp(HP+(1.0-mask.a), 0.0, 1.0)
|
|
||||||
// Create a darker pixel if it's inside a damage mask.
|
|
||||||
return vec4(wallpx.r*alpha, wallpx.g*alpha, wallpx.b*alpha, wallpx.a)
|
|
||||||
}
|
|
||||||
|
|
||||||
return wallpx // Otherwise, leave a pixel color as is
|
|
||||||
}
|
|
||||||
@@ -1,49 +0,0 @@
|
|||||||
JASC-PAL
|
|
||||||
0100
|
|
||||||
46
|
|
||||||
23 32 56
|
|
||||||
37 58 94
|
|
||||||
60 94 139
|
|
||||||
79 143 186
|
|
||||||
115 190 211
|
|
||||||
164 221 219
|
|
||||||
25 51 45
|
|
||||||
37 86 46
|
|
||||||
70 130 50
|
|
||||||
117 167 67
|
|
||||||
168 202 88
|
|
||||||
208 218 145
|
|
||||||
77 43 50
|
|
||||||
122 72 65
|
|
||||||
173 119 87
|
|
||||||
192 148 115
|
|
||||||
215 181 148
|
|
||||||
231 213 179
|
|
||||||
52 28 39
|
|
||||||
96 44 44
|
|
||||||
136 75 43
|
|
||||||
190 119 43
|
|
||||||
222 158 65
|
|
||||||
232 193 112
|
|
||||||
36 21 39
|
|
||||||
65 29 49
|
|
||||||
117 36 56
|
|
||||||
165 48 48
|
|
||||||
207 87 60
|
|
||||||
218 134 62
|
|
||||||
30 29 57
|
|
||||||
64 39 81
|
|
||||||
122 54 123
|
|
||||||
162 62 140
|
|
||||||
198 81 151
|
|
||||||
223 132 165
|
|
||||||
9 10 20
|
|
||||||
16 20 31
|
|
||||||
21 29 40
|
|
||||||
32 46 55
|
|
||||||
57 74 80
|
|
||||||
87 114 119
|
|
||||||
129 151 150
|
|
||||||
168 181 178
|
|
||||||
199 207 204
|
|
||||||
235 237 233
|
|
||||||
|
Before Width: | Height: | Size: 145 KiB After Width: | Height: | Size: 145 KiB |
BIN
assets/sprites/background-orange.png
Normal file
|
After Width: | Height: | Size: 152 KiB |
|
Before Width: | Height: | Size: 3.1 KiB |
|
Before Width: | Height: | Size: 3.1 KiB After Width: | Height: | Size: 50 KiB |
BIN
assets/sprites/background-transparent.png
Normal file
|
After Width: | Height: | Size: 1.7 KiB |
|
Before Width: | Height: | Size: 1.8 KiB |
|
Before Width: | Height: | Size: 1.8 KiB |
|
Before Width: | Height: | Size: 1.8 KiB |
|
Before Width: | Height: | Size: 1.8 KiB |
@@ -1,181 +0,0 @@
|
|||||||
{ "frames": [
|
|
||||||
{
|
|
||||||
"filename": "backgroundstars 0.ase",
|
|
||||||
"frame": { "x": 0, "y": 0, "w": 640, "h": 384 },
|
|
||||||
"rotated": false,
|
|
||||||
"trimmed": false,
|
|
||||||
"spriteSourceSize": { "x": 0, "y": 0, "w": 640, "h": 384 },
|
|
||||||
"sourceSize": { "w": 640, "h": 384 },
|
|
||||||
"duration": 2000
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"filename": "backgroundstars 1.ase",
|
|
||||||
"frame": { "x": 640, "y": 0, "w": 640, "h": 384 },
|
|
||||||
"rotated": false,
|
|
||||||
"trimmed": false,
|
|
||||||
"spriteSourceSize": { "x": 0, "y": 0, "w": 640, "h": 384 },
|
|
||||||
"sourceSize": { "w": 640, "h": 384 },
|
|
||||||
"duration": 100
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"filename": "backgroundstars 2.ase",
|
|
||||||
"frame": { "x": 1280, "y": 0, "w": 640, "h": 384 },
|
|
||||||
"rotated": false,
|
|
||||||
"trimmed": false,
|
|
||||||
"spriteSourceSize": { "x": 0, "y": 0, "w": 640, "h": 384 },
|
|
||||||
"sourceSize": { "w": 640, "h": 384 },
|
|
||||||
"duration": 100
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"filename": "backgroundstars 3.ase",
|
|
||||||
"frame": { "x": 1920, "y": 0, "w": 640, "h": 384 },
|
|
||||||
"rotated": false,
|
|
||||||
"trimmed": false,
|
|
||||||
"spriteSourceSize": { "x": 0, "y": 0, "w": 640, "h": 384 },
|
|
||||||
"sourceSize": { "w": 640, "h": 384 },
|
|
||||||
"duration": 100
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"filename": "backgroundstars 4.ase",
|
|
||||||
"frame": { "x": 2560, "y": 0, "w": 640, "h": 384 },
|
|
||||||
"rotated": false,
|
|
||||||
"trimmed": false,
|
|
||||||
"spriteSourceSize": { "x": 0, "y": 0, "w": 640, "h": 384 },
|
|
||||||
"sourceSize": { "w": 640, "h": 384 },
|
|
||||||
"duration": 2000
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"filename": "backgroundstars 5.ase",
|
|
||||||
"frame": { "x": 3200, "y": 0, "w": 640, "h": 384 },
|
|
||||||
"rotated": false,
|
|
||||||
"trimmed": false,
|
|
||||||
"spriteSourceSize": { "x": 0, "y": 0, "w": 640, "h": 384 },
|
|
||||||
"sourceSize": { "w": 640, "h": 384 },
|
|
||||||
"duration": 100
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"filename": "backgroundstars 6.ase",
|
|
||||||
"frame": { "x": 3840, "y": 0, "w": 640, "h": 384 },
|
|
||||||
"rotated": false,
|
|
||||||
"trimmed": false,
|
|
||||||
"spriteSourceSize": { "x": 0, "y": 0, "w": 640, "h": 384 },
|
|
||||||
"sourceSize": { "w": 640, "h": 384 },
|
|
||||||
"duration": 100
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"filename": "backgroundstars 7.ase",
|
|
||||||
"frame": { "x": 4480, "y": 0, "w": 640, "h": 384 },
|
|
||||||
"rotated": false,
|
|
||||||
"trimmed": false,
|
|
||||||
"spriteSourceSize": { "x": 0, "y": 0, "w": 640, "h": 384 },
|
|
||||||
"sourceSize": { "w": 640, "h": 384 },
|
|
||||||
"duration": 100
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"filename": "backgroundstars 8.ase",
|
|
||||||
"frame": { "x": 5120, "y": 0, "w": 640, "h": 384 },
|
|
||||||
"rotated": false,
|
|
||||||
"trimmed": false,
|
|
||||||
"spriteSourceSize": { "x": 0, "y": 0, "w": 640, "h": 384 },
|
|
||||||
"sourceSize": { "w": 640, "h": 384 },
|
|
||||||
"duration": 2000
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"filename": "backgroundstars 9.ase",
|
|
||||||
"frame": { "x": 5760, "y": 0, "w": 640, "h": 384 },
|
|
||||||
"rotated": false,
|
|
||||||
"trimmed": false,
|
|
||||||
"spriteSourceSize": { "x": 0, "y": 0, "w": 640, "h": 384 },
|
|
||||||
"sourceSize": { "w": 640, "h": 384 },
|
|
||||||
"duration": 100
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"filename": "backgroundstars 10.ase",
|
|
||||||
"frame": { "x": 6400, "y": 0, "w": 640, "h": 384 },
|
|
||||||
"rotated": false,
|
|
||||||
"trimmed": false,
|
|
||||||
"spriteSourceSize": { "x": 0, "y": 0, "w": 640, "h": 384 },
|
|
||||||
"sourceSize": { "w": 640, "h": 384 },
|
|
||||||
"duration": 100
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"filename": "backgroundstars 11.ase",
|
|
||||||
"frame": { "x": 7040, "y": 0, "w": 640, "h": 384 },
|
|
||||||
"rotated": false,
|
|
||||||
"trimmed": false,
|
|
||||||
"spriteSourceSize": { "x": 0, "y": 0, "w": 640, "h": 384 },
|
|
||||||
"sourceSize": { "w": 640, "h": 384 },
|
|
||||||
"duration": 100
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"filename": "backgroundstars 12.ase",
|
|
||||||
"frame": { "x": 7680, "y": 0, "w": 640, "h": 384 },
|
|
||||||
"rotated": false,
|
|
||||||
"trimmed": false,
|
|
||||||
"spriteSourceSize": { "x": 0, "y": 0, "w": 640, "h": 384 },
|
|
||||||
"sourceSize": { "w": 640, "h": 384 },
|
|
||||||
"duration": 2000
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"filename": "backgroundstars 13.ase",
|
|
||||||
"frame": { "x": 8320, "y": 0, "w": 640, "h": 384 },
|
|
||||||
"rotated": false,
|
|
||||||
"trimmed": false,
|
|
||||||
"spriteSourceSize": { "x": 0, "y": 0, "w": 640, "h": 384 },
|
|
||||||
"sourceSize": { "w": 640, "h": 384 },
|
|
||||||
"duration": 100
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"filename": "backgroundstars 14.ase",
|
|
||||||
"frame": { "x": 8960, "y": 0, "w": 640, "h": 384 },
|
|
||||||
"rotated": false,
|
|
||||||
"trimmed": false,
|
|
||||||
"spriteSourceSize": { "x": 0, "y": 0, "w": 640, "h": 384 },
|
|
||||||
"sourceSize": { "w": 640, "h": 384 },
|
|
||||||
"duration": 100
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"filename": "backgroundstars 15.ase",
|
|
||||||
"frame": { "x": 9600, "y": 0, "w": 640, "h": 384 },
|
|
||||||
"rotated": false,
|
|
||||||
"trimmed": false,
|
|
||||||
"spriteSourceSize": { "x": 0, "y": 0, "w": 640, "h": 384 },
|
|
||||||
"sourceSize": { "w": 640, "h": 384 },
|
|
||||||
"duration": 100
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"filename": "backgroundstars 16.ase",
|
|
||||||
"frame": { "x": 10240, "y": 0, "w": 640, "h": 384 },
|
|
||||||
"rotated": false,
|
|
||||||
"trimmed": false,
|
|
||||||
"spriteSourceSize": { "x": 0, "y": 0, "w": 640, "h": 384 },
|
|
||||||
"sourceSize": { "w": 640, "h": 384 },
|
|
||||||
"duration": 100
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"filename": "backgroundstars 17.ase",
|
|
||||||
"frame": { "x": 10880, "y": 0, "w": 640, "h": 384 },
|
|
||||||
"rotated": false,
|
|
||||||
"trimmed": false,
|
|
||||||
"spriteSourceSize": { "x": 0, "y": 0, "w": 640, "h": 384 },
|
|
||||||
"sourceSize": { "w": 640, "h": 384 },
|
|
||||||
"duration": 2000
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"meta": {
|
|
||||||
"app": "http://www.aseprite.org/",
|
|
||||||
"version": "1.x-dev",
|
|
||||||
"image": "backgroundstars-animated.png",
|
|
||||||
"format": "RGBA8888",
|
|
||||||
"size": { "w": 11520, "h": 384 },
|
|
||||||
"scale": "1",
|
|
||||||
"frameTags": [
|
|
||||||
],
|
|
||||||
"layers": [
|
|
||||||
{ "name": "background", "opacity": 255, "blendMode": "normal" },
|
|
||||||
{ "name": "stars", "opacity": 124, "blendMode": "normal" }
|
|
||||||
],
|
|
||||||
"slices": [
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
Before Width: | Height: | Size: 52 KiB |
|
Before Width: | Height: | Size: 5.5 KiB |
BIN
assets/sprites/block-grey.png
Normal file
|
After Width: | Height: | Size: 584 B |
|
Before Width: | Height: | Size: 4.4 KiB After Width: | Height: | Size: 4.4 KiB |
|
Before Width: | Height: | Size: 1.8 KiB After Width: | Height: | Size: 1.8 KiB |
|
Before Width: | Height: | Size: 5.7 KiB After Width: | Height: | Size: 5.7 KiB |
|
Before Width: | Height: | Size: 1.8 KiB After Width: | Height: | Size: 1.8 KiB |
@@ -1,156 +0,0 @@
|
|||||||
{ "frames": [
|
|
||||||
{
|
|
||||||
"filename": "collectible #Detonation 0.ase",
|
|
||||||
"frame": { "x": 0, "y": 0, "w": 64, "h": 64 },
|
|
||||||
"rotated": false,
|
|
||||||
"trimmed": false,
|
|
||||||
"spriteSourceSize": { "x": 0, "y": 0, "w": 64, "h": 64 },
|
|
||||||
"sourceSize": { "w": 64, "h": 64 },
|
|
||||||
"duration": 20
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"filename": "collectible #Detonation 1.ase",
|
|
||||||
"frame": { "x": 64, "y": 0, "w": 64, "h": 64 },
|
|
||||||
"rotated": false,
|
|
||||||
"trimmed": false,
|
|
||||||
"spriteSourceSize": { "x": 0, "y": 0, "w": 64, "h": 64 },
|
|
||||||
"sourceSize": { "w": 64, "h": 64 },
|
|
||||||
"duration": 20
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"filename": "collectible #Detonation 2.ase",
|
|
||||||
"frame": { "x": 128, "y": 0, "w": 64, "h": 64 },
|
|
||||||
"rotated": false,
|
|
||||||
"trimmed": false,
|
|
||||||
"spriteSourceSize": { "x": 0, "y": 0, "w": 64, "h": 64 },
|
|
||||||
"sourceSize": { "w": 64, "h": 64 },
|
|
||||||
"duration": 20
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"filename": "collectible #Detonation 3.ase",
|
|
||||||
"frame": { "x": 192, "y": 0, "w": 64, "h": 64 },
|
|
||||||
"rotated": false,
|
|
||||||
"trimmed": false,
|
|
||||||
"spriteSourceSize": { "x": 0, "y": 0, "w": 64, "h": 64 },
|
|
||||||
"sourceSize": { "w": 64, "h": 64 },
|
|
||||||
"duration": 20
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"filename": "collectible #Detonation 4.ase",
|
|
||||||
"frame": { "x": 256, "y": 0, "w": 64, "h": 64 },
|
|
||||||
"rotated": false,
|
|
||||||
"trimmed": false,
|
|
||||||
"spriteSourceSize": { "x": 0, "y": 0, "w": 64, "h": 64 },
|
|
||||||
"sourceSize": { "w": 64, "h": 64 },
|
|
||||||
"duration": 100
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"filename": "collectible #Detonation 5.ase",
|
|
||||||
"frame": { "x": 320, "y": 0, "w": 64, "h": 64 },
|
|
||||||
"rotated": false,
|
|
||||||
"trimmed": false,
|
|
||||||
"spriteSourceSize": { "x": 0, "y": 0, "w": 64, "h": 64 },
|
|
||||||
"sourceSize": { "w": 64, "h": 64 },
|
|
||||||
"duration": 100
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"filename": "collectible #Detonation 6.ase",
|
|
||||||
"frame": { "x": 384, "y": 0, "w": 64, "h": 64 },
|
|
||||||
"rotated": false,
|
|
||||||
"trimmed": false,
|
|
||||||
"spriteSourceSize": { "x": 0, "y": 0, "w": 64, "h": 64 },
|
|
||||||
"sourceSize": { "w": 64, "h": 64 },
|
|
||||||
"duration": 100
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"filename": "collectible #Detonation 7.ase",
|
|
||||||
"frame": { "x": 448, "y": 0, "w": 64, "h": 64 },
|
|
||||||
"rotated": false,
|
|
||||||
"trimmed": false,
|
|
||||||
"spriteSourceSize": { "x": 0, "y": 0, "w": 64, "h": 64 },
|
|
||||||
"sourceSize": { "w": 64, "h": 64 },
|
|
||||||
"duration": 100
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"filename": "collectible #Detonation 8.ase",
|
|
||||||
"frame": { "x": 512, "y": 0, "w": 64, "h": 64 },
|
|
||||||
"rotated": false,
|
|
||||||
"trimmed": false,
|
|
||||||
"spriteSourceSize": { "x": 0, "y": 0, "w": 64, "h": 64 },
|
|
||||||
"sourceSize": { "w": 64, "h": 64 },
|
|
||||||
"duration": 100
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"filename": "collectible #Detonation 9.ase",
|
|
||||||
"frame": { "x": 576, "y": 0, "w": 64, "h": 64 },
|
|
||||||
"rotated": false,
|
|
||||||
"trimmed": false,
|
|
||||||
"spriteSourceSize": { "x": 0, "y": 0, "w": 64, "h": 64 },
|
|
||||||
"sourceSize": { "w": 64, "h": 64 },
|
|
||||||
"duration": 100
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"filename": "collectible #Detonation 10.ase",
|
|
||||||
"frame": { "x": 640, "y": 0, "w": 64, "h": 64 },
|
|
||||||
"rotated": false,
|
|
||||||
"trimmed": false,
|
|
||||||
"spriteSourceSize": { "x": 0, "y": 0, "w": 64, "h": 64 },
|
|
||||||
"sourceSize": { "w": 64, "h": 64 },
|
|
||||||
"duration": 100
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"filename": "collectible #Detonation 11.ase",
|
|
||||||
"frame": { "x": 704, "y": 0, "w": 64, "h": 64 },
|
|
||||||
"rotated": false,
|
|
||||||
"trimmed": false,
|
|
||||||
"spriteSourceSize": { "x": 0, "y": 0, "w": 64, "h": 64 },
|
|
||||||
"sourceSize": { "w": 64, "h": 64 },
|
|
||||||
"duration": 100
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"filename": "collectible #Detonation 12.ase",
|
|
||||||
"frame": { "x": 768, "y": 0, "w": 64, "h": 64 },
|
|
||||||
"rotated": false,
|
|
||||||
"trimmed": false,
|
|
||||||
"spriteSourceSize": { "x": 0, "y": 0, "w": 64, "h": 64 },
|
|
||||||
"sourceSize": { "w": 64, "h": 64 },
|
|
||||||
"duration": 100
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"filename": "collectible #Detonation 13.ase",
|
|
||||||
"frame": { "x": 832, "y": 0, "w": 64, "h": 64 },
|
|
||||||
"rotated": false,
|
|
||||||
"trimmed": false,
|
|
||||||
"spriteSourceSize": { "x": 0, "y": 0, "w": 64, "h": 64 },
|
|
||||||
"sourceSize": { "w": 64, "h": 64 },
|
|
||||||
"duration": 100
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"meta": {
|
|
||||||
"app": "http://www.aseprite.org/",
|
|
||||||
"version": "1.x-dev",
|
|
||||||
"image": "collectible-detonating.png",
|
|
||||||
"format": "I8",
|
|
||||||
"size": { "w": 896, "h": 64 },
|
|
||||||
"scale": "1",
|
|
||||||
"frameTags": [
|
|
||||||
{ "name": "Detonation", "from": 1, "to": 14, "direction": "forward" }
|
|
||||||
],
|
|
||||||
"layers": [
|
|
||||||
{ "name": "Yellow Sphere", "opacity": 255, "blendMode": "normal" },
|
|
||||||
{ "name": "Layer 8", "opacity": 255, "blendMode": "normal" },
|
|
||||||
{ "name": "Layer 7", "opacity": 255, "blendMode": "normal" },
|
|
||||||
{ "name": "Layer 6", "opacity": 255, "blendMode": "normal" },
|
|
||||||
{ "name": "Layer 5", "opacity": 255, "blendMode": "normal" },
|
|
||||||
{ "name": "Layer 4", "opacity": 255, "blendMode": "normal" },
|
|
||||||
{ "name": "Layer 3", "opacity": 255, "blendMode": "normal" },
|
|
||||||
{ "name": "Layer 2", "opacity": 255, "blendMode": "normal" },
|
|
||||||
{ "name": "Layer 1", "opacity": 255, "blendMode": "normal" },
|
|
||||||
{ "name": "Blitz Outer", "opacity": 70, "blendMode": "normal" },
|
|
||||||
{ "name": "Blitz Middle", "opacity": 84, "blendMode": "normal" },
|
|
||||||
{ "name": "Blitz Inner", "opacity": 97, "blendMode": "normal" }
|
|
||||||
],
|
|
||||||
"slices": [
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
Before Width: | Height: | Size: 2.1 KiB |
@@ -1,54 +0,0 @@
|
|||||||
{ "frames": [
|
|
||||||
{
|
|
||||||
"filename": "collectible-idle 0.ase",
|
|
||||||
"frame": { "x": 0, "y": 0, "w": 32, "h": 32 },
|
|
||||||
"rotated": false,
|
|
||||||
"trimmed": false,
|
|
||||||
"spriteSourceSize": { "x": 0, "y": 0, "w": 32, "h": 32 },
|
|
||||||
"sourceSize": { "w": 32, "h": 32 },
|
|
||||||
"duration": 200
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"filename": "collectible-idle 1.ase",
|
|
||||||
"frame": { "x": 32, "y": 0, "w": 32, "h": 32 },
|
|
||||||
"rotated": false,
|
|
||||||
"trimmed": false,
|
|
||||||
"spriteSourceSize": { "x": 0, "y": 0, "w": 32, "h": 32 },
|
|
||||||
"sourceSize": { "w": 32, "h": 32 },
|
|
||||||
"duration": 200
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"filename": "collectible-idle 2.ase",
|
|
||||||
"frame": { "x": 64, "y": 0, "w": 32, "h": 32 },
|
|
||||||
"rotated": false,
|
|
||||||
"trimmed": false,
|
|
||||||
"spriteSourceSize": { "x": 0, "y": 0, "w": 32, "h": 32 },
|
|
||||||
"sourceSize": { "w": 32, "h": 32 },
|
|
||||||
"duration": 200
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"filename": "collectible-idle 3.ase",
|
|
||||||
"frame": { "x": 96, "y": 0, "w": 32, "h": 32 },
|
|
||||||
"rotated": false,
|
|
||||||
"trimmed": false,
|
|
||||||
"spriteSourceSize": { "x": 0, "y": 0, "w": 32, "h": 32 },
|
|
||||||
"sourceSize": { "w": 32, "h": 32 },
|
|
||||||
"duration": 200
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"meta": {
|
|
||||||
"app": "http://www.aseprite.org/",
|
|
||||||
"version": "1.x-dev",
|
|
||||||
"image": "collectible-idle.png",
|
|
||||||
"format": "RGBA8888",
|
|
||||||
"size": { "w": 128, "h": 32 },
|
|
||||||
"scale": "1",
|
|
||||||
"frameTags": [
|
|
||||||
],
|
|
||||||
"layers": [
|
|
||||||
{ "name": "Layer 1", "opacity": 255, "blendMode": "normal" }
|
|
||||||
],
|
|
||||||
"slices": [
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
Before Width: | Height: | Size: 931 B |
|
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 1.3 KiB |
|
Before Width: | Height: | Size: 448 B |
|
Before Width: | Height: | Size: 615 B |
|
Before Width: | Height: | Size: 357 B |
|
Before Width: | Height: | Size: 7.0 KiB |
|
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 1.9 KiB |
|
Before Width: | Height: | Size: 712 B |
|
Before Width: | Height: | Size: 967 B After Width: | Height: | Size: 5.3 KiB |
|
Before Width: | Height: | Size: 935 B After Width: | Height: | Size: 5.3 KiB |
|
Before Width: | Height: | Size: 950 B After Width: | Height: | Size: 5.3 KiB |
|
Before Width: | Height: | Size: 1023 B After Width: | Height: | Size: 5.3 KiB |
|
Before Width: | Height: | Size: 963 B After Width: | Height: | Size: 5.3 KiB |
BIN
assets/sprites/particle-dust-0.png
Normal file
|
After Width: | Height: | Size: 5.8 KiB |
BIN
assets/sprites/particle-dust-1.png
Normal file
|
After Width: | Height: | Size: 6.2 KiB |
BIN
assets/sprites/particle-dust-2.png
Normal file
|
After Width: | Height: | Size: 6.4 KiB |