Compare commits

...

64 Commits

Author SHA1 Message Date
0ee848bad4 +nix 2024-05-19 20:40:31 +02:00
933b9c403f build better oil6 based palette with more shades and not more hues 2024-04-16 19:30:12 +02:00
abc93d4d57 switched to ebitengine-input 2024-04-16 19:10:32 +02:00
b7383f065f add moving animation support, fix debug printing 2024-04-16 17:46:53 +02:00
f2f134fddb added robot draf 2024-04-16 17:31:17 +02:00
4f714b698d add ackrc 2024-04-15 13:45:46 +02:00
8c14f36463 more new tiles 2024-04-15 13:36:40 +02:00
d22042cc72 enhanced 2024-04-12 19:01:17 +02:00
dd25d217dc updated 2024-04-12 15:09:15 +02:00
a84b8b58e1 fixed snap in bug, started with space themed sprites 2024-04-12 15:08:40 +02:00
f23bdaf121 switched to go coded animation system, LDTK is not used for this anymore 2024-04-08 18:51:25 +02:00
2793710819 +more stuff to do 2024-04-08 14:52:55 +02:00
940d305c00 updated todo 2024-04-08 14:51:16 +02:00
2edaccbfda added duration from asesprite json, background animation, prepared
idle animation
2024-04-07 19:10:27 +02:00
0b0252022e started animation background 2024-04-07 14:24:28 +02:00
50dd76a268 trying star background 2024-04-07 13:46:29 +02:00
53bdb7e8ae switched to use the level gbimage instead of the background property 2024-04-07 13:07:03 +02:00
261f23a5a9 switched to apollo palette and self made sprites 2024-04-07 12:05:37 +02:00
77de9621c9 +todo 2024-04-06 19:07:50 +02:00
d80a0b99ad re-created all sprites using apollo palette 2024-04-06 19:06:34 +02:00
c76037486d +todos 2024-04-04 18:45:29 +02:00
cb3ccb323c better and easier to understand asset loading 2024-04-04 18:24:44 +02:00
95469ab3c7 changed aspect ration to 640x384 for better scaling on mobile 2024-04-04 17:53:22 +02:00
f844058bf9 completed animation setup and code based solely on LDTK settings 2024-04-03 19:39:08 +02:00
001b67f97a renamed particle* to animation*, added asesprite animation loading 2024-04-02 20:05:23 +02:00
20fa2639c6 Changes:
- fixed collectible detonation animation timing
- replaced those animatin sprites
- also replaced the collectible sprite with one created with asesprite
- more todo stuff added
2024-04-01 19:43:37 +02:00
faf0fd99c2 Changes:
- use toggle tile for all toggling entities (transient, switch, door)
- get rod of hard coded sprites (exception: particle class, to be
  fixed later)
- changed switch sprite (rect instead of elipse)
2024-03-31 20:16:15 +02:00
f6f2172f11 new door 2024-03-29 20:17:51 +01:00
c6f9557483 fix to make player stop on closed door 2024-03-29 18:54:47 +01:00
c7c3859a70 move player_player on top of pair_system 2024-03-29 11:54:37 +01:00
82c67551aa changes:
- exchanged switch+door sprites
- added asesprite cheat sheet
- implemented door toggle on switch toggle
2024-03-29 11:51:05 +01:00
dcf31e46ed fixes+changes:
- fixed windows build, using path, instead of path/filepath
- added switch + door, implemented relation (pair_system missing yet)
- fixed ldtk map loading, now using correct entitymap.png tileset
2024-03-28 19:41:20 +01:00
f6d5385d35 started with switch/door pair 2024-03-28 13:53:03 +01:00
dc2574643c fixed 2024-03-27 18:39:04 +01:00
4c2ecc6f1f Changes:
- separated entities spriteset from primarymap, which only contains
  tiles
- fixed star obstacle
2024-03-27 18:37:41 +01:00
5b7c88a1a9 fixed hiddendoor tiles, now uses destruct shader no spriteset 2024-03-24 19:36:00 +01:00
f8c09fda76 first try to use new tiles 2024-03-22 19:02:52 +01:00
693293b8c8 added 2024-03-22 17:57:44 +01:00
51d3776abf fixed player loop detection, added more levels 2024-03-21 19:04:47 +01:00
19c9a5d502 better wasm build 2024-03-21 13:32:14 +01:00
d055c9e913 Merge pull request 'separate-collision-checker' (#1) from separate-collision-checker into master
Reviewed-on: #1
2024-03-21 13:31:03 +01:00
52c4cb4e66 bump 2024-03-21 13:28:44 +01:00
e93c08f81f fixes:
- using 1 func for grid collision checking with func arguments in
  player and obstacle systems.
- moving obstacles now kill player if business ends points toward him
  on contact
- added retry in popup menu
2024-03-21 13:25:06 +01:00
1d16fcb73f fixes:
- fixed bumpedge test for obstacles
- fixed obstacle crash when going to the south or east
- added wasm builder
2024-03-21 09:38:47 +01:00
ae0e3a0676 added mouse menu to player hud (events in level_scene), fix level 4 2024-03-18 19:34:57 +01:00
daa5e41551 center description 2024-03-17 16:30:11 +01:00
35057ec8a6 added back button 2024-03-17 16:29:56 +01:00
449a75aa7d added more levels 2024-03-17 16:29:41 +01:00
db228094eb fixed level select widget size 2024-03-16 23:11:22 +01:00
927233aafb +ui bug 2024-03-16 18:50:24 +01:00
b9ac1c7995 added one more level, rm comments 2024-03-16 18:49:28 +01:00
2084150456 fixed last level oos bug, added more levels and entities 2024-03-15 20:08:23 +01:00
1d9164d140 finaly got ldtkgo to work! 2024-03-11 18:31:01 +01:00
af19ccb833 shifted from proprietary ascii rawlevel to LDTK (using ldtkgo@master) 2024-03-10 13:05:31 +01:00
a2ed7782b2 added game font rendering using etxt to player hud, fixed current level 2024-03-01 18:10:09 +01:00
ae8058e052 added final menu after last level 2024-03-01 14:08:35 +01:00
6f85a90b58 fixed slow grid drawing, which also fixed transient tile quirk 2024-03-01 10:55:14 +01:00
1c0f3d19d0 added MinMoves to lvl files, added score system in game observer 2024-02-28 19:58:05 +01:00
ebaeb51f68 started implementing score system 2024-02-28 13:15:45 +01:00
707281212a added player loop detection, loose level if last player loops 2024-02-27 18:20:00 +01:00
5d2475d525 two players fuse now if they collide 2024-02-27 17:28:18 +01:00
ac88a74bd7 turn player into primary if only one left 2024-02-27 16:52:20 +01:00
18be0ebe38 added hud system, turned all observers into one central observer 2024-02-27 14:45:23 +01:00
451b66a53d obstacle collision fixes, player alive checks, player remove
workaround, see TODO
2024-02-26 19:07:35 +01:00
299 changed files with 10525 additions and 1252 deletions

505
.ackrc Normal file
View File

@ -0,0 +1,505 @@
--ignore-ack-defaults
# This is the default ackrc for ack version v3.7.0.
# There are four different ways to match
#
# is: Match the filename exactly
#
# ext: Match the extension of the filename exactly
#
# match: Match the filename against a Perl regular expression
#
# firstlinematch: Match the first 250 characters of the first line
# of text against a Perl regular expression. This is only for
# the --type-add option.
### Directories to ignore
# Bazaar
# https://bazaar.canonical.com/
--ignore-directory=is:.bzr
# Codeville
# http://freshmeat.sourceforge.net/projects/codeville
--ignore-directory=is:.cdv
# Interface Builder (Xcode)
# https://en.wikipedia.org/wiki/Interface_Builder
--ignore-directory=is:~.dep
--ignore-directory=is:~.dot
--ignore-directory=is:~.nib
--ignore-directory=is:~.plst
# Git
# https://git-scm.com/
--ignore-directory=is:.git
# When submodules are used, .git is a file.
--ignore-file=is:.git
# Mercurial
# https://www.mercurial-scm.org/
--ignore-directory=is:.hg
# Quilt
# https://directory.fsf.org/wiki/Quilt
--ignore-directory=is:.pc
# Subversion
# https://subversion.apache.org/
--ignore-directory=is:.svn
# Monotone
# https://www.monotone.ca/
--ignore-directory=is:_MTN
# CVS
# https://savannah.nongnu.org/projects/cvs
--ignore-directory=is:CVS
# RCS
# https://www.gnu.org/software/rcs/
--ignore-directory=is:RCS
# SCCS
# https://en.wikipedia.org/wiki/Source_Code_Control_System
--ignore-directory=is:SCCS
# darcs
# http://darcs.net/
--ignore-directory=is:_darcs
# Vault/Fortress
--ignore-directory=is:_sgbak
# autoconf
# https://www.gnu.org/software/autoconf/
--ignore-directory=is:autom4te.cache
# Perl module building
--ignore-directory=is:blib
--ignore-directory=is:_build
# Perl Devel::Cover module's output directory
# https://metacpan.org/release/Devel-Cover
--ignore-directory=is:cover_db
# Node modules created by npm
--ignore-directory=is:node_modules
# CMake cache
# https://www.cmake.org/
--ignore-directory=is:CMakeFiles
# Eclipse workspace folder
# https://eclipse.org/
--ignore-directory=is:.metadata
# Cabal (Haskell) sandboxes
# https://www.haskell.org/cabal/users-guide/installing-packages.html
--ignore-directory=is:.cabal-sandbox
# Python caches
# https://docs.python.org/3/tutorial/modules.html
--ignore-directory=is:__pycache__
--ignore-directory=is:.pytest_cache
# macOS Finder remnants
--ignore-directory=is:__MACOSX
--ignore-file=is:.DS_Store
### Files to ignore
# Backup files
--ignore-file=ext:bak
--ignore-file=match:/~$/
# Emacs swap files
--ignore-file=match:/^#.+#$/
# vi/vim swap files https://www.vim.org/
--ignore-file=match:/[._].*[.]swp$/
# core dumps
--ignore-file=match:/core[.]\d+$/
# minified JavaScript
--ignore-file=match:/[.-]min[.]js$/
--ignore-file=match:/[.]js[.]min$/
# minified CSS
--ignore-file=match:/[.]min[.]css$/
--ignore-file=match:/[.]css[.]min$/
# JS and CSS source maps
--ignore-file=match:/[.]js[.]map$/
--ignore-file=match:/[.]css[.]map$/
# PDFs, because they pass Perl's -T detection
--ignore-file=ext:pdf
# Common graphics, just as an optimization
--ignore-file=ext:gif,jpg,jpeg,png
# Common archives, as an optimization
--ignore-file=ext:gz,tar,tgz,zip
# Python compiled modules
--ignore-file=ext:pyc,pyd,pyo
# Python's pickle serialization format
# https://docs.python.org/2/library/pickle.html#example
# https://docs.python.org/3.7/library/pickle.html#examples
--ignore-file=ext:pkl,pickle
# C extensions
--ignore-file=ext:so
# Compiled gettext files
--ignore-file=ext:mo
# Visual Studio user and workspace settings
# https://code.visualstudio.com/docs/getstarted/settings
--ignore-dir=is:.vscode
### Filetypes defined
# Makefiles
# https://www.gnu.org/s/make/
--type-add=make:ext:mk
--type-add=make:ext:mak
--type-add=make:is:makefile
--type-add=make:is:Makefile
--type-add=make:is:Makefile.Debug
--type-add=make:is:Makefile.Release
--type-add=make:is:GNUmakefile
# Rakefiles
# https://rake.rubyforge.org/
--type-add=rake:is:Rakefile
# CMake
# https://cmake.org/
--type-add=cmake:is:CMakeLists.txt
--type-add=cmake:ext:cmake
# Bazel build tool
# https://docs.bazel.build/versions/master/skylark/bzl-style.html
--type-add=bazel:ext:bzl
# https://docs.bazel.build/versions/master/guide.html#bazelrc-the-bazel-configuration-file
--type-add=bazel:ext:bazelrc
# https://docs.bazel.build/versions/master/build-ref.html#BUILD_files
--type-add=bazel:is:BUILD
# https://docs.bazel.build/versions/master/build-ref.html#workspace
--type-add=bazel:is:WORKSPACE
# Actionscript
--type-add=actionscript:ext:as,mxml
# Ada
# https://www.adaic.org/
--type-add=ada:ext:ada,adb,ads
# ASP
# https://docs.microsoft.com/en-us/previous-versions/office/developer/server-technologies/aa286483(v=msdn.10)
--type-add=asp:ext:asp
# ASP.Net
# https://dotnet.microsoft.com/apps/aspnet
--type-add=aspx:ext:master,ascx,asmx,aspx,svc
# Assembly
--type-add=asm:ext:asm,s
# DOS/Windows batch
--type-add=batch:ext:bat,cmd
# ColdFusion
# https://en.wikipedia.org/wiki/ColdFusion
--type-add=cfmx:ext:cfc,cfm,cfml
# Clojure
# https://clojure.org/
--type-add=clojure:ext:clj,cljs,edn,cljc
# C
# .xs are Perl C files
--type-add=cc:ext:c,h,xs
# C header files
--type-add=hh:ext:h
# CoffeeScript
# https://coffeescript.org/
--type-add=coffeescript:ext:coffee
# C++
--type-add=cpp:ext:cpp,cc,cxx,m,hpp,hh,h,hxx
# C++ header files
--type-add=hpp:ext:hpp,hh,h,hxx
# C#
--type-add=csharp:ext:cs
# Crystal-lang
# https://crystal-lang.org/
--type-add=crystal:ext:cr,ecr
# CSS
# https://www.w3.org/Style/CSS/
--type-add=css:ext:css
# Dart
# https://dart.dev/
--type-add=dart:ext:dart
# Delphi
# https://en.wikipedia.org/wiki/Embarcadero_Delphi
--type-add=delphi:ext:pas,int,dfm,nfm,dof,dpk,dproj,groupproj,bdsgroup,bdsproj
# Elixir
# https://elixir-lang.org/
--type-add=elixir:ext:ex,exs
# Elm
# https://elm-lang.org
--type-add=elm:ext:elm
# Emacs Lisp
# https://www.gnu.org/software/emacs
--type-add=elisp:ext:el
# Erlang
# https://www.erlang.org/
--type-add=erlang:ext:erl,hrl
# Fortran
# https://en.wikipedia.org/wiki/Fortran
--type-add=fortran:ext:f,f77,f90,f95,f03,for,ftn,fpp
# Go
# https://golang.org/
--type-add=go:ext:go
# Groovy
# https://www.groovy-lang.org/
--type-add=groovy:ext:groovy,gtmpl,gpp,grunit,gradle
# GSP
# https://gsp.grails.org/
--type-add=gsp:ext:gsp
# Haskell
# https://www.haskell.org/
--type-add=haskell:ext:hs,lhs
# HTML
--type-add=html:ext:htm,html,xhtml
# Jade
# http://jade-lang.com/
--type-add=jade:ext:jade
# Java
# https://www.oracle.com/technetwork/java/index.html
--type-add=java:ext:java,properties
# JavaScript
--type-add=js:ext:js
# JSP
# https://www.oracle.com/technetwork/java/javaee/jsp/index.html
--type-add=jsp:ext:jsp,jspx,jspf,jhtm,jhtml
# JSON
# https://json.org/
--type-add=json:ext:json
# Kotlin
# https://kotlinlang.org/
--type-add=kotlin:ext:kt,kts
# Less
# http://www.lesscss.org/
--type-add=less:ext:less
# Common Lisp
# https://common-lisp.net/
--type-add=lisp:ext:lisp,lsp
# Lua
# https://www.lua.org/
--type-add=lua:ext:lua
--type-add=lua:firstlinematch:/^#!.*\blua(jit)?/
# Markdown
# https://en.wikipedia.org/wiki/Markdown
--type-add=markdown:ext:md,markdown
# We understand that there are many ad hoc extensions for markdown
# that people use. .md and .markdown are the two that ack recognizes.
# You are free to add your own in your ackrc file.
# Matlab
# https://en.wikipedia.org/wiki/MATLAB
--type-add=matlab:ext:m
# Objective-C
--type-add=objc:ext:m,h
# Objective-C++
--type-add=objcpp:ext:mm,h
# OCaml
# https://ocaml.org/
--type-add=ocaml:ext:ml,mli,mll,mly
# Perl
# https://perl.org/
--type-add=perl:ext:pl,pm,pod,t,psgi
--type-add=perl:firstlinematch:/^#!.*\bperl/
# Perl tests
--type-add=perltest:ext:t
# Perl's Plain Old Documentation format, POD
--type-add=pod:ext:pod
# PHP
# https://www.php.net/
--type-add=php:ext:php,phpt,php3,php4,php5,phtml
--type-add=php:firstlinematch:/^#!.*\bphp/
# Plone
# https://plone.org/
--type-add=plone:ext:pt,cpt,metadata,cpy,py
# PowerShell
# https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_scripts
# https://learn.microsoft.com/en-us/powershell/scripting/developer/module/understanding-a-windows-powershell-module
--type-add=powershell:ext:ps1,psm1
# PureScript
# https://www.purescript.org
--type-add=purescript:ext:purs
# Python
# https://www.python.org/
--type-add=python:ext:py
--type-add=python:firstlinematch:/^#!.*\bpython/
# R
# https://www.r-project.org/
# https://r4ds.had.co.nz/r-markdown.html
--type-add=rr:ext:R,Rmd
# reStructured Text
# https://docutils.sourceforge.io/rst.html
--type-add=rst:ext:rst
# Ruby
# https://www.ruby-lang.org/
--type-add=ruby:ext:rb,rhtml,rjs,rxml,erb,rake,spec
--type-add=ruby:is:Rakefile
--type-add=ruby:firstlinematch:/^#!.*\bruby/
# Rust
# https://www.rust-lang.org/
--type-add=rust:ext:rs
# Sass
# https://sass-lang.com
--type-add=sass:ext:sass,scss
# Scala
# https://www.scala-lang.org/
--type-add=scala:ext:scala,sbt
# Scheme
# https://groups.csail.mit.edu/mac/projects/scheme/
--type-add=scheme:ext:scm,ss
# Shell
--type-add=shell:ext:sh,bash,csh,tcsh,ksh,zsh,fish
--type-add=shell:firstlinematch:/^#!.*\b(?:ba|t?c|k|z|fi)?sh\b/
# Smalltalk
# http://www.smalltalk.org/
--type-add=smalltalk:ext:st
# Smarty
# https://www.smarty.net/
--type-add=smarty:ext:tpl
# SQL
# https://www.iso.org/standard/45498.html
--type-add=sql:ext:sql,ctl
# Stylus
# http://stylus-lang.com/
--type-add=stylus:ext:styl
# SVG
# https://en.wikipedia.org/wiki/Scalable_Vector_Graphics
--type-add=svg:ext:svg
# Swift
# https://developer.apple.com/swift/
--type-add=swift:ext:swift
--type-add=swift:firstlinematch:/^#!.*\bswift/
# Tcl
# https://www.tcl.tk/
--type-add=tcl:ext:tcl,itcl,itk
# TeX & LaTeX
# https://www.latex-project.org/
--type-add=tex:ext:tex,cls,sty
# Template Toolkit (Perl)
# http//template-toolkit.org/
--type-add=ttml:ext:tt,tt2,ttml
# TOML
# https://toml.io/
--type-add=toml:ext:toml
# TypeScript
# https://www.typescriptlang.org/
--type-add=ts:ext:ts,tsx
# Visual Basic
--type-add=vb:ext:bas,cls,frm,ctl,vb,resx
# Verilog
--type-add=verilog:ext:v,vh,sv
# VHDL
# http://www.eda.org/twiki/bin/view.cgi/P1076/WebHome
--type-add=vhdl:ext:vhd,vhdl
# Vim
# https://www.vim.org/
--type-add=vim:ext:vim
# XML
# https://www.w3.org/TR/REC-xml/
--type-add=xml:ext:xml,dtd,xsd,xsl,xslt,ent,wsdl
--type-add=xml:firstlinematch:/<[?]xml/
# YAML
# https://yaml.org/
--type-add=yaml:ext:yaml,yml
# TOM
--ignore-directory=is:src
--ignore-directory=is:tmp
--ignore-directory=is:fonts
--ignore-file=ext:ldtk
--ignore-file=ext:png
--ignore-file=ext:ase
--ignore-file=ext:json
--ignore-file=ext:svg

3
.gitignore vendored
View File

@ -1 +1,2 @@
openquell
openquell*
tmp

View File

@ -1,3 +1,12 @@
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
@echo ok
@ -5,8 +14,22 @@ clean:
rm -f openquell
build:
go build
go build -ldflags "-X 'openquell/config.VERSION=$(VERSION)'"
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:
@echo 1
@echo $(VERSION)
nixshell:
nix-shell -p xorg.libX11 xorg.libXrandr libGL xorg.libXcursor xorg.libXinerama xorg.libXi xorg.libXxf86vm xorg_sys_opengl

62
TODO.md
View File

@ -1,32 +1,46 @@
## Levels:
- ignore comments in lvl files
- Start New game starts with last played level, better add a Resume
Game menu item for this and use Start New always for level 1.
- 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
- Turn menu button in hud_system (events in level_scene!) into ebitenui button
- 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
- Obstacle don't stop at collectibles
- Grid Observer:
https://github.com/mlange-42/arche/issues/374
- Player can collect collectible hidden under obstacle (should be
fixed when above is fixed)
- Add player idle animation
- Add some final message when the player reaches the last level, start
from scratch or a message to buy me some beer, whatever
- Add player collision animation
- Check player-player collisions!
- Create pixel art ui elements (button, list things) and ui borders/backgrounds
Replace HUD with pixel art variant
- 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.
- Modify font and font color matching the palette
- Add shaders for animation (player destruction etc)
- On game start respond to any key (ebitengine-input has an anykey func)
- Add player HUD + Stats (as hud_system!)
- 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)
## Collider Rework
- Add save to disk feature including settings and player
accomplishements (FIXME: find the lib, asked in Discord)
- Rework sprites (again!) to match stellar background: maybe more
technical tiles and items? Like some robotic setup?
## Collider Rework [abandoned: see branch collider-system, fails]
- do not use the map anymore for collision detection
- central collision_system
@ -44,3 +58,17 @@
Collider.IntersectResolve => func(newpos) {player.pos = newpos; player.vel = stop}
- in the end it must be possible to add new entities without the need
to write a collision check for them, but have collision detection anyway!
## Just in case stuff
- 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,
"file", source.File, "line", source.Line)

View File

@ -1,17 +0,0 @@
Description: test obstacles
Background: background-lila
#######
#o #
# t #
#> S <#
# #
# ^ #
#######

View File

@ -1,17 +0,0 @@
Description: test obstacles
Background: background-lila
#############
# t #
#> S # #
# ># ^#
#< #W#####
# o v# o#
#############

View File

@ -1,17 +0,0 @@
Description: find the fruit
Background: background-lila
# ############
# #
############ #
# o S #
# ######## ###
+ #
############ #
# o # #
# # ######## #
# # o
# ############

View File

@ -1,17 +0,0 @@
Description: win
Background: background-lila
########
#v o #
# S<# #
# #### #
# #### #
# #
#> ^#
########

View File

@ -1,17 +0,0 @@
Description: use multiple players
Background: background-lila
########W#
# v #
# #
#S s#
############
# o #
######## #

View File

@ -1,17 +0,0 @@
Description: space
Background: background-lila
#
S
#

View File

@ -1,30 +0,0 @@
#!/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
)

6425
assets/levels/openquell.ldtk Normal file

File diff suppressed because it is too large Load Diff

View File

@ -1,63 +1,80 @@
package assets
import (
"bufio"
_ "image/png"
"io/fs"
"log"
"log/slog"
"openquell/config"
"openquell/util"
"os"
"path/filepath"
"sort"
"strings"
"github.com/hajimehoshi/ebiten/v2"
"github.com/solarlune/ldtkgo"
)
var Levels = LoadLevels("levels")
var Project = LoadLDTK("levels")
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
OnMoving bool // wether to animate during moving
CollisionSheet AnimationSet // an entry in assets.Animations[name]
DestructionSheet AnimationSet
IdleSheet AnimationSet
}
// Tile: contains image, identifier (as used in level data) and
// additional properties
type Tile struct {
Id byte
Sprite *ebiten.Image
Class string
Solid bool // wall brick
Player bool // player sphere
IsPrimary bool // primary player sphere
Renderable bool // visible, has sprite
Velocity bool // movable
Collectible bool // collectible, vanishes once collected
Transient bool // turns into brick wall when traversed
Destroyable bool // turns into empty floor when bumped into twice
Particle int // -1=unused, 0-3 = show image of slice
Tiles []*ebiten.Image // has N sprites
TileNames []string // same thing, only the names
Obstacle bool // is an obstacle/enemy
Direction int // obstacle business end shows into this direction
Id, Ref string
Sprite *ebiten.Image
ToggleSprite *ebiten.Image
Solid bool // wall brick
Player bool // player sphere
IsPrimary bool // primary player sphere
Renderable bool // visible, has sprite
Velocity bool // movable
Collectible bool // collectible, vanishes once collected
Transient bool // turns into brick wall when traversed
Destroyable bool // turns into empty floor when bumped into twice
Tiles []*ebiten.Image // has N sprites
TileNames []string // same thing, only the names
Obstacle bool // is an obstacle/enemy
Direction int // obstacle business end shows into this direction
Shader *ebiten.Shader
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 {
newtile := &Tile{
Id: tile.Id,
Sprite: tile.Sprite,
Class: tile.Class,
Solid: tile.Solid,
Player: tile.Player,
IsPrimary: tile.IsPrimary,
Renderable: tile.Renderable,
Velocity: tile.Velocity,
Collectible: tile.Collectible,
Transient: tile.Transient,
Destroyable: tile.Destroyable,
Particle: tile.Particle,
Tiles: tile.Tiles,
TileNames: tile.TileNames,
Obstacle: tile.Obstacle,
Direction: tile.Direction,
Id: tile.Id,
Ref: tile.Ref,
Sprite: tile.Sprite,
ToggleSprite: tile.ToggleSprite,
Solid: tile.Solid,
Player: tile.Player,
IsPrimary: tile.IsPrimary,
Renderable: tile.Renderable,
Velocity: tile.Velocity,
Collectible: tile.Collectible,
Transient: tile.Transient,
Destroyable: tile.Destroyable,
Tiles: tile.Tiles,
TileNames: tile.TileNames,
Obstacle: tile.Obstacle,
Direction: tile.Direction,
Alpha: tile.Alpha,
Shader: tile.Shader,
Bond: tile.Bond,
Door: tile.Door,
Switch: tile.Switch,
Animation: tile.Animation,
}
return newtile
@ -68,55 +85,52 @@ const (
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 {
tile := &Tile{
Id: 'S',
Class: "sphere",
Renderable: true,
Player: true,
Velocity: true,
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
tile.Tiles = []*ebiten.Image{Assets["sphere-blue"], Assets["sphere-blue-secondary"]}
tile.Tiles = []*ebiten.Image{Assets["sphere"], Assets["sphere-small"]}
return tile
}
func NewTileBlock(class string) *Tile {
func NewTileBlock() *Tile {
return &Tile{
Id: '#',
Sprite: Assets[class],
Class: class,
Solid: true,
Renderable: true,
}
}
func NewTileCollectible(class string) *Tile {
func NewTileCollectible() *Tile {
return &Tile{
Id: 'o',
Sprite: Assets[class],
Class: class,
Solid: false,
Renderable: true,
Collectible: true,
Animation: TileAnimation{
OnDestruction: true,
DestructionSheet: Animations["collectible-detonating"],
OnIdle: true,
IdleSheet: Animations["collectible-idle"],
},
}
}
func NewTileObstacle(class string, direction int) *Tile {
func NewTileObstacle(direction int) *Tile {
return &Tile{
Id: '+',
Sprite: Assets[class],
Class: class,
Solid: false,
Renderable: true,
Obstacle: true,
@ -125,184 +139,122 @@ func NewTileObstacle(class string, direction int) *Tile {
}
}
func NewTileParticle(class []string) *Tile {
sprites := []*ebiten.Image{}
for _, sprite := range class {
sprites = append(sprites, Assets[sprite])
}
func NewTileTranswall() *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,
Renderable: true,
Transient: true,
Tiles: sprites,
Sprite: sprites[0], // initially use the first
TileNames: names,
}
}
func NewTileHiddenDoor(class []string) *Tile {
sprites := []*ebiten.Image{}
names := []string{}
for _, sprite := range class {
sprites = append(sprites, Assets[sprite])
names = append(names, sprite)
}
func NewTileHiddenDoor(alpha string) *Tile {
return &Tile{
Id: 'W',
Class: "hiddendoor",
Solid: false,
Renderable: true,
Destroyable: true,
Tiles: sprites,
Sprite: sprites[0], // initially use the first
TileNames: names,
Alpha: Assets[alpha],
Shader: Shaders["destruct"],
}
}
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
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
}
type TileRegistry map[string]*Tile
func InitTiles() TileRegistry {
return TileRegistry{
' ': {Id: ' ', Class: "floor", Renderable: false},
//'#': NewTileBlock("block-grey32"),
'#': NewTileBlock("block-greycolored"),
'B': NewTileBlock("block-orange-32"),
'S': NewTilePlayer(Primary),
's': NewTilePlayer(Secondary),
'o': NewTileCollectible("collectible-orange"),
'+': NewTileObstacle("obstacle-star", config.All),
'^': NewTileObstacle("obstacle-north", config.North),
'v': NewTileObstacle("obstacle-south", config.South),
'<': NewTileObstacle("obstacle-west", config.West),
'>': NewTileObstacle("obstacle-east", config.East),
'*': NewTileParticle([]string{
//"particle-ring-1",
"particle-ring-2",
"particle-ring-3",
"particle-ring-4",
"particle-ring-5",
"particle-ring-6",
}),
't': NewTileTranswall([]string{"transwall", "block-orange-32"}),
'W': NewTileHiddenDoor([]string{"block-greycolored", "block-greycolored-damaged"}),
"floor": {Renderable: false},
"default": NewTileBlock(),
"solidorange": NewTileBlock(),
"PlayerPrimary": NewTilePlayer(Primary),
"PlayerSecondary": NewTilePlayer(Secondary),
"Collectible": NewTileCollectible(),
"ObstacleStar": NewTileObstacle(config.All),
"ObstacleNorth": NewTileObstacle(config.North),
"ObstacleSouth": NewTileObstacle(config.South),
"ObstacleWest": NewTileObstacle(config.West),
"ObstacleEast": NewTileObstacle(config.East),
"Transient": NewTileTranswall(),
"HiddenDoor": NewTileHiddenDoor("damage"),
"HiddenDoor2": NewTileHiddenDoor("damage"),
"HiddenDoor3": NewTileHiddenDoor("damage"),
"HiddenDoor4": NewTileHiddenDoor("damage"),
"HiddenDoor5": NewTileHiddenDoor("damage"),
"HiddenDoor6": NewTileHiddenDoor("damage"),
"HiddenDoor7": NewTileHiddenDoor("damage"),
"HiddenDoor8": NewTileHiddenDoor("damage"),
"HiddenDoor9": NewTileHiddenDoor("damage"),
"HiddenDoor10": NewTileHiddenDoor("damage"),
"HiddenDoor11": NewTileHiddenDoor("damage"),
"HiddenDoor12": NewTileHiddenDoor("damage"),
"HiddenDoor13": NewTileHiddenDoor("damage"),
"Switch": NewTileSwitch(),
"Door": NewTileDoor(),
}
}
// load levels at compile time into ram, creates a slice of raw levels
func LoadLevels(dir string) []RawLevel {
levels := []RawLevel{}
// we use embed.FS to iterate over all files in ./levels/
entries, err := assetfs.ReadDir(dir)
// load LDTK project at compile time into ram
func LoadLDTK(dir string) *ldtkgo.Project {
fd, err := assetfs.Open("levels/openquell.ldtk")
if err != nil {
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)
log.Fatalf("failed to open LDTK file levels/openquell.ldtk: %s", err)
}
defer fd.Close()
name := strings.TrimSuffix(levelfile.Name(), ".lvl")
des := ""
background := &ebiten.Image{}
data := []byte{}
fileinfo, err := fd.Stat()
if err != nil {
log.Fatalf("failed to stat() LDTK file levels/openquell.ldtk: %s", err)
}
scanner := bufio.NewScanner(fd)
for scanner.Scan() {
// ignore any whitespace
line := scanner.Text()
filesize := fileinfo.Size()
buffer := make([]byte, filesize)
// ignore empty lines
if len(line) == 0 {
continue
}
_, err = fd.Read(buffer)
if err != nil {
log.Fatalf("failed to read bytes from LDTK file levels/openquell.ldtk: %s", err)
}
switch {
case strings.Contains(line, "Background:"):
haveit := strings.Split(line, ": ")
if util.Exists(Assets, haveit[1]) {
background = Assets[haveit[1]]
project, err := ldtkgo.Read(buffer)
if err != nil {
panic(err)
}
// 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, ": ")
des = haveit[1]
default:
// all other non-empty and non-equalsign lines are
// level definition matrix data, merge thes into data
data = append(data, line+"\n"...)
}
if have != need {
log.Fatalf("level definition for level %d (%s) invalid: %d missing properties\n required: %s",
idx, level.Identifier, need-have, strings.Join(properties, ", "),
)
}
}
return RawLevel{
Name: name,
Data: data,
Background: background,
Description: des,
}
return project
}

49
assets/loader-shaders.go Normal file
View File

@ -0,0 +1,49 @@
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
}

View File

@ -1,14 +1,17 @@
package assets
import (
"bytes"
"embed"
"encoding/json"
"image"
_ "image/png"
"io/fs"
"log"
"log/slog"
"os"
"path/filepath"
"path"
"strings"
"time"
"github.com/hajimehoshi/ebiten/v2"
)
@ -16,13 +19,64 @@ import (
// Maps image name to image data
type AssetRegistry map[string]*ebiten.Image
//go:embed levels/*.lvl sprites/*.png fonts/*.ttf
// A helper to pass the registry easier around
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 Assets = LoadImages("sprites")
// Called at build time, creates the global asset and animation registries
var Assets, Animations = LoadImages()
func LoadImages(dir string) AssetRegistry {
images := AssetRegistry{}
// load pngs and json files
func LoadImages() (AssetRegistry, AnimationRegistry) {
dir := "sprites"
imagedata := &assetData{}
imagedata.Registry = AssetRegistry{}
rawanimations := []AnimationJSON{}
// we use embed.FS to iterate over all files in ./assets/
entries, err := assetfs.ReadDir(dir)
@ -31,24 +85,93 @@ func LoadImages(dir string) AssetRegistry {
}
for _, imagefile := range entries {
path := filepath.Join("assets", dir, imagefile.Name())
fd, err := os.Open(path)
path := path.Join(dir, imagefile.Name())
fd, err := assetfs.Open(path)
if err != nil {
log.Fatalf("failed to open image file %s: %s", imagefile.Name(), err)
log.Fatalf("failed to open file %s: %s", imagefile.Name(), err)
}
defer fd.Close()
name := strings.TrimSuffix(imagefile.Name(), ".png")
switch {
case strings.HasSuffix(path, ".png"):
name, image := ReadImage(imagefile, fd)
imagedata.Registry[name] = image
img, _, err := image.Decode(fd)
if err != nil {
log.Fatalf("failed to decode image %s: %s", imagefile.Name(), err)
case strings.HasSuffix(path, ".json"):
animationjson := ReadJson(imagefile, fd)
rawanimations = append(rawanimations, animationjson)
}
images[name] = ebiten.NewImageFromImage(img)
slog.Debug("loaded asset", "path", path)
}
return images
// preprocess animation sprites
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
}

View File

Before

Width:  |  Height:  |  Size: 145 KiB

After

Width:  |  Height:  |  Size: 145 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 50 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 50 KiB

View File

Before

Width:  |  Height:  |  Size: 4.4 KiB

After

Width:  |  Height:  |  Size: 4.4 KiB

View File

Before

Width:  |  Height:  |  Size: 1.8 KiB

After

Width:  |  Height:  |  Size: 1.8 KiB

View File

Before

Width:  |  Height:  |  Size: 5.7 KiB

After

Width:  |  Height:  |  Size: 5.7 KiB

View File

Before

Width:  |  Height:  |  Size: 1.8 KiB

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

View File

@ -0,0 +1,164 @@
{ "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": [
]
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 647 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 689 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 472 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 325 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 179 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 179 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 109 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 716 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 783 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 802 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 909 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 924 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 937 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 876 B

View File

Before

Width:  |  Height:  |  Size: 1.3 KiB

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 577 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.4 KiB

BIN
assets/oldsprites/door.ase Normal file

Binary file not shown.

BIN
assets/oldsprites/door1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

BIN
assets/oldsprites/door2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 271 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 43 KiB

BIN
assets/oldsprites/hud.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

View File

@ -0,0 +1,2 @@
#!/bin/sh
montage -tile 4x0 -geometry +0+0 block* collectible-orange.png obstacle-* sphere-blue* transwall.png map.png && okular map.png

BIN
assets/oldsprites/map.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

BIN
assets/oldsprites/menu.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 132 KiB

View File

Before

Width:  |  Height:  |  Size: 2.0 KiB

After

Width:  |  Height:  |  Size: 2.0 KiB

View File

Before

Width:  |  Height:  |  Size: 9.3 KiB

After

Width:  |  Height:  |  Size: 9.3 KiB

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 503 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 543 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 141 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

View File

@ -0,0 +1,36 @@
// 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
}

View File

@ -0,0 +1,45 @@
JASC-PAL
0100
42
0 0 0
0 0 0
14 14 14
29 29 29
51 51 51
80 80 80
99 99 99
122 122 122
167 167 167
192 192 192
228 228 228
251 245 239
242 211 171
255 227 160
255 216 117
255 202 60
255 168 36
255 141 0
73 77 126
63 69 136
54 61 145
44 52 155
35 44 164
26 36 173
39 39 68
31 31 76
27 27 80
22 22 85
17 17 90
14 14 93
139 109 156
142 98 167
145 86 179
150 68 197
154 52 213
158 36 229
198 159 165
204 153 161
212 145 155
221 136 149
230 127 143
241 116 135

Binary file not shown.

Binary file not shown.

BIN
assets/space/obstacle.ase Normal file

Binary file not shown.

BIN
assets/space/oilshades.ase Normal file

Binary file not shown.

View File

@ -0,0 +1,33 @@
JASC-PAL
0100
30
242 211 171
236 199 134
230 193 96
224 176 50
205 142 32
198 159 165
186 140 144
180 129 129
172 115 115
147 87 98
139 109 156
118 93 138
97 80 118
82 68 100
62 51 75
73 77 126
61 61 106
51 48 83
37 33 56
27 21 37
39 39 68
39 39 68
39 39 68
39 39 68
39 39 68
251 245 239
223 207 198
194 178 174
171 157 155
146 134 130

BIN
assets/space/player.ase Normal file

Binary file not shown.

BIN
assets/space/robot.ase Normal file

Binary file not shown.

42
assets/space/space.pal Normal file
View File

@ -0,0 +1,42 @@
JASC-PAL
0100
39
32 0 59
63 0 83
108 0 108
146 0 124
187 0 151
236 0 178
255 19 186
255 64 190
255 113 213
255 147 231
255 186 253
245 220 255
255 255 255
0 0 0
12 12 12
26 26 26
39 39 39
54 54 54
71 71 71
86 86 86
99 99 99
118 118 118
133 133 133
153 153 153
177 177 177
205 205 205
42 2 0
52 9 0
71 24 0
94 46 0
131 71 0
165 96 0
201 106 0
243 119 0
255 165 41
255 186 82
255 239 169
255 250 211
255 255 247

BIN
assets/space/sprites.ase Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

49
assets/sprites/apollo.pal Normal file
View File

@ -0,0 +1,49 @@
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

Binary file not shown.

Before

Width:  |  Height:  |  Size: 152 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 50 KiB

After

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

View File

@ -0,0 +1,181 @@
{ "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": [
]
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 52 KiB

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 584 B

View File

@ -0,0 +1,156 @@
{ "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": [
]
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

View File

@ -0,0 +1,54 @@
{ "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": [
]
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 931 B

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 448 B

Some files were not shown because too many files have changed in this diff Show More