Commit Graph

243 Commits

Author SHA1 Message Date
ba6892aa95 WASM Texture Caching
* Refactor texture caching in render.Engine:
  * New interface method: NewTexture(filename string, image.Image)
  * WASM immediately encodes the image to PNG and generates a JavaScript
    `Image()` object to load it with a data URI and keep it in memory.
  * SDL2 saves the bitmap to disk as it did before.
  * WASM: deprecate the sessionStorage for holding image data. Session
    storage methods panic if called. The image data is directly kept in
    Go memory as a js.Value holding an Image().
* Shared Memory workaround: the level.Chunk.ToBitmap() function is where
  chunk textures get cached, but it had no access to the render.Engine
  used in the game. The `pkg/shmem` package holds global pointers to
  common structures like the CurrentRenderEngine as a work-around.
  * Also shmem.Flash() so Doodle can make its d.Flash() function
    globally available, any sub-package can now flash text to the screen
    regardless of source code location.
  * JavaScript API for Doodads now has a global Flash() function
    available.
* WASM: Handle window resize so Doodle can recompute its dimensions
  instead of scaling/shrinking the view.
2019-06-27 12:03:52 -07:00
48fc40ade4 Texture Caching for WASM Canvas Engine
* Add RGBA color blending support in WASM build.
* Initial texture caching API for Canvas renderer engine. The WASM build
  writes the chunk caches as a "data:image/png" base64 URL on the
  browser's sessionStorage, for access to copy into the Canvas.
* Separated the ClickEvent from the MouseEvent (motion) in the WASM
  event queue system, to allow clicking and dragging.
* Added the EscapeKey handler, which will abruptly terminate the WASM
  application, same as it kills the window in the desktop build.
* Optimization fix: I discovered that if the user clicks and holds over
  a single pixel when drawing a level, repeated Set() operations were
  firing meaning multiple cache invalidations. Not noticeable on PC but
  on WebAssembly it crippled the browser. Now if the cursor isn't moving
  it doesn't do anything.
2019-06-26 22:44:08 -07:00
c5c85330de WASM Event Queue
* Refactor the event system in the WASM render engine to serialize the
  async JavaScript events into a channel, so that queued events are read
  off serially in the main loop similar to SDL. This fixes keyboard
  input issues, altho if you type really fast some input keys get lost.
2019-06-26 20:33:24 -07:00
af67b20d9b Initial WebAssembly Build Target
* Initial WebAssembly build target for Doodle in the wasm/ folder.
* Add a new render.Engine implementation, lib/render/canvas that uses
  the HTML 5 Canvas API instead of SDL2 for the WebAssembly target.
  * Ported the basic DrawLine(), DrawBox() etc. functions from SDL2 to
    Canvas context2d API.
  * Fonts are handled with CSS embedded fonts named after the font
    filename and defined in wasm/index.html
* `make wasm` builds the WASM program, and `make wasm-serve` runs a dev
  Go server that hosts the WASM file for development. The server also
  watches the dev tree for *.go files and rebuilds the WASM binary
  automatically on change.
* This build "basically" runs the game. UI and fonts all work and mouse
  movements and clicks are detected. No wallpaper support yet or texture
  caching (which will crash the game as soon as you click and draw a
  pixel in your map!)
2019-06-26 18:40:40 -07:00
8d855582ed Clean up documentation 2019-06-25 18:58:48 -07:00
9efe16582c Add Play/Edit Buttons to Toggle Between Modes
* Instead of needing to press the "P" and "E" keys to toggle from edit
  mode to play mode (and back again), respectively, the UI now draws a
  "Play (P)" or "Edit (E)" button on the bottom right corner of the
  level canvas. Clicking it will toggle the mode.
2019-06-25 18:36:53 -07:00
4c2e8eca49 Add blank white wallpaper 2019-06-25 18:10:57 -07:00
c7fee43f54 New Wallpapers: Legal Pad and Blueprint 2019-06-25 17:48:17 -07:00
3d3561b8e6 Blueprint Theme Palette
* Fix the EditorUI not showing the correct palette baked into the level
  and only showing the default. This was tricky because the palette UI
  can only be configured at setup time but not updated later.
* Add a new default palette for the Blueprint theme. Blueprint has a
  dark background, so the palette colors should be bright. This palette
  is chosen when you start a map with the blueprint wallpaper.
* Add a background Canvas to the MenuScene. In the "New Level" screen,
  the background canvas will update to show the wallpaper settings
  you've chosen as a preview of the level theme you're about to create.
2019-06-25 17:43:23 -07:00
7281fcbf91 Add "Load Drawing" Menu UI
* To the MenuScene add the "Load Drawing" window UI.
* Displays the user's Levels and Doodads using rows of buttons, 4
  buttons per row. Clicking the button loads the EditorScene with that
  filename.
* Free Version does not display the Doodads label or button on this
  menu screen.
2019-06-25 15:23:01 -07:00
4dd1bebc5f Add MenuScene with New Level UI
* Debug mode: no longer enables the DebugOverlay (F3) by default, but
  does now insert the current FPS counter into the window title bar.
* ui.Frame: set a default "mostly transparent" BG color so the frame
  background doesn't render as white.
* Add the MenuScene which will house the game's main menus.
* The "New Level" menu is first to be added.
  * UI lets you pick Page Type and Wallpaper using radio buttons.
  * Page Type: Unbounded, Bounded (default), No Negative Space, Bordered
  * Fix bugs in uix.Canvas to fully support all these page types.
2019-06-25 15:01:37 -07:00
1150d6d3e9 Add Branding Module for Centralized Game Info
* Moves the game's Title, Summary and Version into pkg/branding where it
  is centrally controlled.
2019-06-23 17:52:48 -07:00
99eab19c5b Pub/Sub Messages Between Linked Actors (JavaScript)
* Implement the pub/sub message passing system that lets the JavaScript
  VM of one actor (say, a Button) send messages to other linked actors
  in the level (say, an Electric Door)
* Buttons now emit a "power(true)" message while pressed and
  "power(false)" when released. Sticky Buttons do not release and so do
  not send the power(false) message.
* Electric Doors listen for the "power" event and open or close
  themselves based on the boolean value received.
* If a Sticky Button receives power and is currently pressed down, it
  will pop back up (reset to "off" position) and notify its linked
  actors that they have lost power too. So if a Sticky Button held an
  Electric Door open, and another Button powers the Sticky Button, it
  would pop back up and also close the Electric Door.
2019-06-23 17:34:11 -07:00
87416f9740 Link Tool UX
* On the Doodads tab is the Link button to enter the Link Tool.
* Click Link, then click the 1st doodad on the level, then click the 2nd
  doodad to complete the link.
* The actors struct in the Level holds the link IDs for each actor.
2019-06-23 16:15:09 -07:00
b06c52a705 UI: Add MainWindow Widget and start an example app
* MainWindow is ideal for apps that just want a UI and
  don't manage their own SDL windows.
* The example app will grow into a series of demos that
  test the UI toolkit to help fix bugs and grow features.
2019-06-08 17:03:59 -07:00
567b3158f1 Minor Tweaks 2019-06-08 17:02:28 -07:00
de79bde776 Add silly cheat codes to make Play Mode editable 2019-05-28 22:34:54 -07:00
1523deeb9c Return False: Solid Collision Between Actors
* Implement the handler code for `return false` when actors are
  colliding with each other and wish to act like solid walls.
* The locked doors will `return false` when they're closed and the
  colliding actor does not have the matching key.
* Add arbitrary key/value storage to Actors. The colored keys will set
  an actor value "key:%TITLE%" on the one who touched the key before
  destroying itself. The colored doors check that key when touched to
  decide whether to open.
* The trapdoor now only opens if you're touching it from the top (your
  overlap box Y value is 0), but if you touch it from below and the door
  is closed, it acts like a solid object.
2019-05-28 21:43:30 -07:00
a2e1bd1ccb Improve OnCollide Doodad Script Handling
* Events.OnCollide now receives a CollideEvent object, which makes
  available the .Actor who collided and the .Overlap rect which is
  zero-relative to the target actor. Doodad scripts can use the .Overlap
  to see WHERE in their own box the other actor has intruded.
  * Update the LockedDoor and ElectricDoor doodads to detect when the
    player has entered their inner rect (since their doors are narrower
    than their doodad size)
  * Update the Button doodads to only press in when the player actually
    touches them (because their sizes are shorter than their doodad
    height)
  * Update the Trapdoor to only trigger its animation when the board
    along its top has been touched, not when the empty space below was
    touched from the bottom.
* Events.OnLeave now implemented and fires when an actor who was
  previously intersecting your doodad has left.
* The engine detects when an event JS callback returns false.
  Eventually, the OnCollide can return false to signify the collision is
  not accepted and the actor should be bumped away as if they hit solid
  geometry.
2019-05-06 22:58:09 -07:00
61af068b80 Load Balance Collision and Actor Loop Across CPU Cores
* Add sync.WaitGroup to some parts of the level collision detection
  function and Canvas.Loop() to speed up the frame rate by load
  balancing some work in parallel across multiple cores.
* Improves FPS from 30 to 55+ even for busy scenes with lots of mobile
  enemies walking around.
* Before the level collision optimization, framerate would sometimes dip
  to 30 FPS simply to move the player character on a completely blank
  map!
2019-05-06 17:06:40 -07:00
d28745f89e Mobile Enemy Doodad Test
* Add a Red Azulian as a test for mobile enemies.
  * Its A.I. has it walk back and forth, changing directions when it
    comes up against an obstacle for a few moments.
  * It plays walking animations and can trigger collision events with
    other Doodads, such as the Electric Door and Trapdoor.
* Move Gravity responsibility to the doodad scripts themselves.
  * Call `Self.SetGravity(true)` to opt the Doodad in to gravity.
  * The canvas.Loop() adds gravity to any doodad that has it enabled.
2019-05-06 16:30:45 -07:00
a73dec9f31 Doodad Animations Managed In-Engine
* Add animation support for Doodad actors (Play Mode) into the core
  engine, so that the Doodad script can register named animations and
  play them without managing all the details themselves.
  * Doodad API functions on Self: AddAnimation, PlayAnimation,
    StopAnimation, IsAnimating
* CLI: the `doodad convert` command will name each layer after the
  filename used as the input image.
* CLI: fix the `doodad convert` command creating duplicate Palette
  colors when converting a series of input images into a Doodad.
2019-05-06 15:30:43 -07:00
ac490473b3 Load Doodads from System Path as well as User Path 2019-05-06 13:35:08 -07:00
f76ba6fbb7 WIP: MsgPack stubs, Level Filesystem Module
* Add some encoding/decoding functions for binary msgpack format for
  levels and doodads. Currently it writes msgpack files that can be
  decoded and printed by Python (mp2json.py) but it can't re-read from
  the binary format. For now, levels will continue to write in JSON
  format.
* Add filesystem abstraction functions to the balance/ package to search
  multiple paths to find Levels and Doodads, to make way for
  system-level doodads.
2019-05-06 12:41:46 -07:00
d042457365 Use Azulian doodad as player character instead of empty dummy 2019-05-01 18:30:30 -07:00
af35703df0 Add Azulian doodad sprites and build script 2019-05-01 18:27:20 -07:00
693664db6c Shareware Build Flags
* Build the app with -tags="shareware" to compile the free/shareware
  build of the game.
* `make build-free` compiles both binaries to the bin/ folder in
  shareware mode.
* The constant balance.FreeVersion is true in the shareware build and
  all functionality related to the Doodad Editor UI mode is disabled
  in this build mode.
2019-04-19 17:23:37 -07:00
52a2545692 Remove ScreenshotKey Event, Add F* Key Handlers
* The F3 key now toggles the Debug Overlay, which is now OFF by default.
* The F4 key now toggles the Debug Collision Boxes feature.
2019-04-19 16:21:04 -07:00
2a162a86dd UI: Fix packing bug in the GUITest 2019-04-19 15:08:00 -07:00
fb8f4b1029 Remove pkg/log from lib/render package
This breaks the last ties from the lib/ folder of publicly open
sourceable code from the internals of Doodle in pkg/
2019-04-18 22:14:02 -07:00
35d96b714d Add JavaScript panic catcher to doodads
* Add example mischievous doodad script that alters the logger date
  format and animates its canvas's mask color.
2019-04-18 22:02:59 -07:00
258b2eb285 Script Timers, Multiple Doodad Frames
* CLI: fix the `doodad convert` command to share the same Palette when
  converting each frame (layer) of a doodad so subsequent layers find
  the correct color swatches for serialization.
* Scripting: add timers and intervals to Doodad scripts to allow them to
  animate themselves or add delayed callbacks. The timers have the same
  API as a web browser: setTimeout(), setInterval(), clearTimeout(),
  clearInterval().
* Add support for uix.Actor to change its currently rendered layer in
  the level. For example a Button Doodad can set its image to Layer 1
  (pressed) when touched by the player, and Trapdoors can cycle through
  their layers to animate opening and closing.
  * Usage from a Doodad script: Self.ShowLayer(1)
* Default Doodads: added scripts for all Buttons, Doors, Keys and the
  Trapdoor to run their various animations when touched (in the case of
  Keys, destroy themselves when touched, because there is no player
  inventory yet)
2019-04-18 18:15:05 -07:00
81cb3bd617 1st Round of Doodad Sprites + Improve Doodad Tool
* Improve the `doodad convert` command to convert a series of input
  images into multiple Frames of a Doodad:
  `doodad convert frame1.png frame2.png frameN.png output.doodad`
* Add the initial round of dev-asset sprites for the default Doodads:
  * Button, Button-TypeB and Sticky Button
  * Red, Blue, Green and Yellow Locked Doors and Keys
  * Electric Door
  * Trapdoor Down
* Add dev-assets/palette.json that defines our default doodad color
  palette. Eventually the JSON will be used by the `doodad` tool to give
  the layers meaningful names.
2019-04-17 00:02:41 -07:00
c70add17e4 Fix the Save As and Open menu buttons in Edit Mode
The "Save As" and "Open" buttons still used an old implementation that
assumed you were talking about files only in the "./maps" folder instead
of loading them from the user's levels and doodads folders.

Now all of the menu buttons in Edit Mode intelligently open files the
same as the `edit <filename>` command from the dev console. You can omit
the file extension and it will attempt to load a Level before a Doodad
to find the first named file, or provide the full extension to be
specific.
2019-04-15 23:22:38 -07:00
1e80304061 Initial Doodad JavaScript System
* Add the JavaScript system for Doodads to run their scripts in levels,
  and wire initial OnCollide() handler support.
* CLI: Add a `doodad install-script` command to the doodad tool.
  * Usage: `doodad install-script <index.js> <filename.doodad>`
* Add dev-assets folder for storing source files for the official
  default doodads, sprites, levels, etc. and for now add a JavaScript
  for the first test doodad.
2019-04-15 23:07:40 -07:00
b33d93599a Unit Tests for Collision Detection 2019-04-15 20:19:52 -07:00
f8a83cbad9 Detect Collision Between Actors
* Move all collision code into the pkg/collision package.
  * pkg/doodads/collision.go -> pkg/collision/collide_level.go
  * pkg/doodads/collide_actors.go for new Actor collide support
* Add initial collision detection code between actors in Play Mode.
2019-04-15 19:17:25 -07:00
241186209c Play Mode: Fix Level Collision w/ Scrolling
Fixes:
* Move the call to CollidesWithGrid() inside the Canvas instead of
  outside in the PlayScene.movePlayer() so it can apply to all Actors
  in motion.
* PlayScene.movePlayer() in turn just sets the player's Velocity so the
  Canvas.Loop() can move the actor itself.
* When keeping the player inside the level boundaries: previously it was
  assuming the player Position was relative to the window, and was
  checking the WorldIndexAt and getting wrong results.
* Canvas scrolling (loopFollowActor): check that the actor is getting
  close to the screen edge using the Viewport into the world, NOT the
  screen-relative coordinates of the Canvas bounding boxes.
2019-04-14 15:25:03 -07:00
5c08577214 Port over code from old collision dev PR 2019-04-09 19:17:56 -07:00
8fc4f39da0 Improvements to the Debug Overlay Feature
* Scenes can insert custom key/value labels to the debug overlay and
  track string variables in real time
* Added ability to unthrottle FPS in main loop
2019-04-09 18:28:08 -07:00
bd3dd41cea Clean up extra log modules 2019-04-09 17:47:03 -07:00
2b42a072a0 Code Layout Refactor
* All private Doodle source code into the pkg/ folder.
* Potentially public code into the lib/ folder.
* Centralize the logger into a subpackage.
2019-04-09 17:35:44 -07:00
d0ff137b04 Windows Executable Cross-Compile with MinGW
* Added Windows build instructions to Building.md and added a
  "make mingw" command to cross-compile the Windows binary into
  the bin/ folder.
* Fix a bug in the Wallpaper texture loader where it would error out
  when caching textures to disk the first time.
2019-04-06 19:30:25 -07:00
569e67bf9e Fedora Dockerfile for building 2019-04-05 13:16:33 -07:00
92847fc3b7 Docker Build Scripts for Debian and Ubuntu 2019-02-28 18:32:44 -08:00
bca848d534 Wallpapers and Bounded Levels
Implement the Wallpaper system into the levels and the concept of
Bounded and Unbounded levels.

The first wallpaper image is notepad.png which looks like standard ruled
notebook paper. On bounded levels, the top/left edges of the page look
as you would expect and the blue lines tile indefinitely in the positive
directions. On unbounded levels, you only get the repeating blue lines
but not the edge pieces.

A wallpaper is just a rectangular image file. The image is divided into
four equal quadrants to be the Corner, Top, Left and Repeat textures for
the wallpaper. The Repeat texture is ALWAYS used and fills all the empty
space behind the drawing. (Doodads draw with blank canvases as before
because only levels have wallpapers!)

Levels have four options of a "Page Type":
- Unbounded       (default, infinite space)
- NoNegativeSpace (has a top left edge but can grow infinitely)
- Bounded         (has a top left edge and bounded size)
- Bordered        (bounded with bordered texture; NOT IMPLEMENTED!)

The scrollable viewport of a Canvas will respect the wallpaper and page
type settings of a Level loaded into it. That is, if the level has a top
left edge (not Unbounded) you can NOT scroll to see negative coordinates
below (0,0) -- and if the level has a max dimension set, you can't
scroll to see pixels outside those dimensions.

The Canvas property NoLimitScroll=true will override the scroll locking
and let you see outside the bounds, for debugging.

- Default map settings for New Level are now:
  - Page Type: NoNegativeSpace
  - Wallpaper: notepad.png (default)
  - MaxWidth: 2550  (8.5" * 300 ppi)
  - MaxHeight: 3300 ( 11" * 300 ppi)
2018-10-27 22:35:06 -07:00
b4a366baa9 Introduce Drawing Tools Concept, Pencil and Actor
The uix.Canvas widget now maintains a selected Tool which configures how
the mouse interacts with the (editable) Canvas widget.

The default Tool is the PencilTool and implements the old behavior: it
draws pixels when clicked and dragged based on your currently selected
Color Swatch. This tool automatically becomes active when you toggle the
Palette tab in the editor mode.

A new Tool is the ActorTool which becomes active when you select the
Doodads tab. In the ActorTool you can't draw pixels on the level, but
when you mouse over a Doodad instance (Actor) in your level, you may
pick it up and drag it someplace else.

Left-click an Actor to pick it up and drag it somewhere else.
Right-click to delete it completely.

You can also delete an Actor by dragging it OFF of the Canvas, like back
onto the palette drawer or onto the menu bar.
2018-10-20 17:08:20 -07:00
0044b72943 Drag Doodads Onto Levels in Edit Mode
Add the ability to drag and drop Doodads onto the level. The Doodad
buttons on the palette now trigger a Drag/Drop behavior when clicked,
and a "blueprint colored" version of the Doodad follows your cursor,
centered on it.

Actors are assigned a random UUID ID when they are placed into a level.

The Canvas gained a MaskColor property that forces all pixels in the
drawing to render as the same color. This is a visual-only effect, and
is used when dragging Doodads in so they render as "blueprints" instead
of their actual colors until they are dropped.

Fix the chunk bitmap cache system so it saves in the $XDG_CACHE_FOLDER
instead of /tmp and has better names. They go into
`~/.config/doodle/chunks/` and have UUID file names -- but they
disappear quickly! As soon as they are cached into SDL2 they are removed
from disk.

Other changes:

- UI: Add Hovering() method that returns the widgets that are beneath
      a point (your cursor) and those that are not, for easy querying
      for event propagation.
- UI: Add ability to return an ErrStopPropagation to tell the master
      Scene (outside the UI) not to continue sending events to other
      parts of the code, so that you don't draw pixels during a drag
      event.
2018-10-20 16:03:59 -07:00
20771fbe13 Draw Actors Embedded in Levels in Edit Mode
Add the JSON format for embedding Actors (Doodad instances) inside of a
Level. I made a test map that manually inserted a couple of actors.

Actors are given to the Canvas responsible for the Level via the
function `InstallActors()`. So it means you'll call LoadLevel and then
InstallActors to hook everything up.

The Canvas creates sub-Canvas widgets from each Actor.

After drawing the main level geometry from the Canvas.Chunker, it calls
the drawActors() function which does the same but for Actors.

Levels keep a global map of all Actors that exist. For any Actors that
are visible within the Viewport, their sub-Canvas widgets are presented
appropriately on top of the parent Canvas. In case their sub-Canvas
overlaps the parent's boundaries, their sub-Canvas is resized and moved
appropriately.

- Allow the MainWindow to be resized at run time, and the UI
  recalculates its sizing and position.
- Made the in-game Shell properties editable via environment variables.
  The kirsle.env file sets a blue and pink color scheme.
- Begin the ground work for Levels and Doodads to embed files inside
  their data via the level.FileSystem type.
- UI: Labels can now contain line break characters. It will
  appropriately render multiple lines of render.Text and take into
  account the proper BoxSize to contain them all.
- Add environment variable DOODLE_DEBUG_ALL=true that will turn on ALL
  debug overlay and visualization options.
- Add debug overlay to "tag" each Canvas widget with some of its
  details, like its Name and World Position. Can be enabled with the
  environment variable DEBUG_CANVAS_LABEL=true
- Improved the FPS debug overlay to show in labeled columns and multiple
  colors, with easy ability to add new data points to it.
2018-10-19 13:32:25 -07:00
1c5a0842e4 Tune Some Constants via Environment Variables
Some of the constants in the `balance` package can be set at startup
time via environment variables. With this, you can customize the color
and style of the developer shell, turn on debugging visuals to outline
Canvas widgets, and more.

The parser is at `balance/debug.go` and human readable descriptions
are in the `balance/README.md`
2018-10-19 09:55:41 -07:00