Add Switches, Fire/Water Collision and Play Menu
* New doodads: Switches. * They come in four varieties: wall switch (background element, with "ON/OFF" text) and three side-profile switches for the floor, left or right walls. * On collision with the player, they flip their state from "OFF" to "ON" or vice versa. If the player walks away and then collides again, the switch flips again. * Can be used to open/close Electric Doors when turned on/off. Their default state is "off" * If a switch receives a power signal from another linked switch, it sets its own state to match. So, two "on/off" switches that are connected to a door AND to each other will both flip on/off when one of them flips. * Update the Level Collision logic to support Decoration, Fire and Water pixel collisions. * Previously, ALL pixels in the level were acting as though solid. * Non-solid pixels don't count for collision detection, but their attributes (fire and water) are collected and returned. * Updated the MenuScene to support loading a map file in Play Mode instead of Edit Mode. Updated the title screen menu to add a button for playing levels instead of editing them. * Wrote some documentation.
10
Ideas.md
|
@ -76,10 +76,10 @@ The major milestones of the game are roughly:
|
||||||
* Colors are not tied to behaviors. Each "Swatch" on the palette has its own
|
* Colors are not tied to behaviors. Each "Swatch" on the palette has its own
|
||||||
color and a set of boolean flags for `solid`, `fire` and `water` behaviors.
|
color and a set of boolean flags for `solid`, `fire` and `water` behaviors.
|
||||||
* [ ] User interface to edit (add/remove) swatches from the palette.
|
* [ ] User interface to edit (add/remove) swatches from the palette.
|
||||||
* [ ] A Toolbox window with radio buttons to select between various drawing tools.
|
* [x] A Toolbox window with radio buttons to select between various drawing tools.
|
||||||
* [x] Pencil (the default) draws single pixels on the level.
|
* [x] Pencil (the default) draws single pixels on the level.
|
||||||
* [ ] Rectangle would draw a rectangular outline.
|
* [x] Rectangle would draw a rectangular outline.
|
||||||
* [ ] Line would draw a line from point to point.
|
* [x] Line would draw a line from point to point.
|
||||||
* [ ] A way to adjust brush properties:
|
* [ ] A way to adjust brush properties:
|
||||||
* [ ] Brush size, shape (round or square).
|
* [ ] Brush size, shape (round or square).
|
||||||
* [ ] Tools to toggle "layers" of visibility into your level:
|
* [ ] Tools to toggle "layers" of visibility into your level:
|
||||||
|
@ -98,11 +98,11 @@ The major milestones of the game are roughly:
|
||||||
|
|
||||||
For creating Doodads in particular:
|
For creating Doodads in particular:
|
||||||
|
|
||||||
* [ ] Make a way to enter Edit Mode in either "Level Mode" or "Doodad Mode",
|
* [x] Make a way to enter Edit Mode in either "Level Mode" or "Doodad Mode",
|
||||||
i.e. by a "New Level" or "New Doodad" button.
|
i.e. by a "New Level" or "New Doodad" button.
|
||||||
* [ ] Create a "frame manager" window to see and page between the frames of the
|
* [ ] Create a "frame manager" window to see and page between the frames of the
|
||||||
drawing.
|
drawing.
|
||||||
* [ ] Ability to work on canvases with constrained size (including smaller than
|
* [x] Ability to work on canvases with constrained size (including smaller than
|
||||||
your window). This will use a Canvas widget in the UI toolkit as an abstraction
|
your window). This will use a Canvas widget in the UI toolkit as an abstraction
|
||||||
layer. Small canvases will be useful for drawing doodads of a fixed size.
|
layer. Small canvases will be useful for drawing doodads of a fixed size.
|
||||||
|
|
||||||
|
|
15
TODO.md
|
@ -47,8 +47,8 @@
|
||||||
- [x] Buttons
|
- [x] Buttons
|
||||||
- [x] Press Button
|
- [x] Press Button
|
||||||
- [x] Sticky Button
|
- [x] Sticky Button
|
||||||
- [ ] Switches
|
- [x] Switches (4 varieties)
|
||||||
- [ ] Doors
|
- [x] Doors
|
||||||
- [x] Locked Doors and Keys
|
- [x] Locked Doors and Keys
|
||||||
- [x] Electric Doors
|
- [x] Electric Doors
|
||||||
- [x] Trapdoors (all 4 directions)
|
- [x] Trapdoors (all 4 directions)
|
||||||
|
@ -66,6 +66,7 @@ In addition to those listed above:
|
||||||
as a level goal and ends the level.
|
as a level goal and ends the level.
|
||||||
- Doodads "Warp Door A" through "Warp Door D"
|
- Doodads "Warp Door A" through "Warp Door D"
|
||||||
- The campaign.json would link levels together.
|
- The campaign.json would link levels together.
|
||||||
|
- [ ] Conveyor Belt
|
||||||
|
|
||||||
## New Ideas
|
## New Ideas
|
||||||
|
|
||||||
|
@ -75,3 +76,13 @@ In addition to those listed above:
|
||||||
keys only get picked up by player characters and not "any doodad that
|
keys only get picked up by player characters and not "any doodad that
|
||||||
touches them"
|
touches them"
|
||||||
- [ ] ``
|
- [ ] ``
|
||||||
|
|
||||||
|
## Path to Multiplayer
|
||||||
|
|
||||||
|
* Add a Player abstraction between events and player characters.
|
||||||
|
* Keyboard keys would update PlayerOne's state with actions (move left, right, jump, etc)
|
||||||
|
* Possible to have multiple local players (i.e. bound to different keyboard keys, bound to joypads, etc.)
|
||||||
|
* A NetworkPlayer provides a Player's inputs from over a network.
|
||||||
|
* Client/server negotiation, protocol
|
||||||
|
* Client can request chunks from server for local rendering.
|
||||||
|
* Players send inputs over network sockets.
|
||||||
|
|
|
@ -24,6 +24,23 @@ buttons() {
|
||||||
cd ..
|
cd ..
|
||||||
}
|
}
|
||||||
|
|
||||||
|
switches() {
|
||||||
|
cd switches/
|
||||||
|
|
||||||
|
doodad convert -t "Switch" switch-off.png switch-on.png switch.doodad
|
||||||
|
doodad convert -t "Floor Switch" down-off.png down-on.png switch-down.doodad
|
||||||
|
doodad convert -t "Left Switch" left-off.png left-on.png switch-left.doodad
|
||||||
|
doodad convert -t "Right Switch" right-off.png right-on.png switch-right.doodad
|
||||||
|
|
||||||
|
doodad install-script switch.js switch.doodad
|
||||||
|
doodad install-script switch.js switch-down.doodad
|
||||||
|
doodad install-script switch.js switch-left.doodad
|
||||||
|
doodad install-script switch.js switch-right.doodad
|
||||||
|
|
||||||
|
cp *.doodad ../../../assets/doodads/
|
||||||
|
cd ..
|
||||||
|
}
|
||||||
|
|
||||||
doors() {
|
doors() {
|
||||||
cd doors/
|
cd doors/
|
||||||
|
|
||||||
|
@ -104,6 +121,7 @@ objects() {
|
||||||
}
|
}
|
||||||
|
|
||||||
buttons
|
buttons
|
||||||
|
switches
|
||||||
doors
|
doors
|
||||||
trapdoors
|
trapdoors
|
||||||
azulians
|
azulians
|
||||||
|
|
|
@ -23,8 +23,8 @@ function main() {
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
animating = true;
|
animating = true;
|
||||||
Self.PlayAnimation("close", function() {
|
|
||||||
opened = false;
|
opened = false;
|
||||||
|
Self.PlayAnimation("close", function() {
|
||||||
animating = false;
|
animating = false;
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
BIN
dev-assets/doodads/switches/down-off.png
Normal file
After Width: | Height: | Size: 678 B |
BIN
dev-assets/doodads/switches/down-on.png
Normal file
After Width: | Height: | Size: 674 B |
BIN
dev-assets/doodads/switches/left-off.png
Normal file
After Width: | Height: | Size: 702 B |
BIN
dev-assets/doodads/switches/left-on.png
Normal file
After Width: | Height: | Size: 696 B |
BIN
dev-assets/doodads/switches/right-off.png
Normal file
After Width: | Height: | Size: 695 B |
BIN
dev-assets/doodads/switches/right-on.png
Normal file
After Width: | Height: | Size: 702 B |
BIN
dev-assets/doodads/switches/switch-off.png
Normal file
After Width: | Height: | Size: 687 B |
BIN
dev-assets/doodads/switches/switch-on.png
Normal file
After Width: | Height: | Size: 699 B |
38
dev-assets/doodads/switches/switch.js
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
function main() {
|
||||||
|
console.log("%s initialized!", Self.Doodad.Title);
|
||||||
|
|
||||||
|
// Switch has two frames:
|
||||||
|
// 0: Off
|
||||||
|
// 1: On
|
||||||
|
|
||||||
|
var state = false;
|
||||||
|
var collide = false;
|
||||||
|
|
||||||
|
Message.Subscribe("power", function(powered) {
|
||||||
|
state = powered;
|
||||||
|
showState(state);
|
||||||
|
});
|
||||||
|
|
||||||
|
Events.OnCollide(function(e) {
|
||||||
|
if (collide === false) {
|
||||||
|
state = !state;
|
||||||
|
Message.Publish("power", state);
|
||||||
|
showState(state);
|
||||||
|
|
||||||
|
collide = true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
Events.OnLeave(function(e) {
|
||||||
|
collide = false;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// showState shows the on/off frame based on the boolean powered state.
|
||||||
|
function showState(state) {
|
||||||
|
if (state) {
|
||||||
|
Self.ShowLayer(1);
|
||||||
|
} else {
|
||||||
|
Self.ShowLayer(0);
|
||||||
|
}
|
||||||
|
}
|
22
docs/Doodad Ideas.md
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
# Doodad Ideas and Implementation Notes
|
||||||
|
|
||||||
|
## Crumbly Floor
|
||||||
|
|
||||||
|
A rectangular floor piece with lines indicating cracks. Most similar to:
|
||||||
|
the break-away floors in Tomb Raider.
|
||||||
|
|
||||||
|
Animation frames/states:
|
||||||
|
|
||||||
|
* Default: a rectangle with jagged lines through it indicating cracks.
|
||||||
|
* Rumble: draw little rumble mark lines and maybe shake the segments around.
|
||||||
|
* Break: the floor breaks apart and pieces fall/shrink into nothing over a few
|
||||||
|
frames of animation.
|
||||||
|
|
||||||
|
Behavior:
|
||||||
|
|
||||||
|
* If touched, act as a solid object.
|
||||||
|
* If touched along its top edge, start the Rumble animation. If touched from
|
||||||
|
the bottom, don't do anything, just act solid.
|
||||||
|
* After a moment of rumbling, stop acting solid and play the break animation.
|
||||||
|
A player standing on top of the floor falls through it now.
|
||||||
|
* When the broken floor scrolls out of view it resets.
|
|
@ -2,6 +2,43 @@
|
||||||
|
|
||||||
## Cheats
|
## Cheats
|
||||||
|
|
||||||
| Cheat Code | Effect |
|
* `unleash the beast` - disable frame rate throttling.
|
||||||
|-------------------|--------------------------------|
|
* `don't edit and drive` - enable editing while playing a level.
|
||||||
| unleash the beast | Disable frame rate throttling. |
|
* `scroll scroll scroll your boat` - enable scrolling the level with arrow keys
|
||||||
|
while playing a level.
|
||||||
|
|
||||||
|
## Bool Props
|
||||||
|
|
||||||
|
Some boolean switches can be toggled in the command shell.
|
||||||
|
|
||||||
|
Usage: `boolProp <name> <value>`
|
||||||
|
|
||||||
|
The value is truthy if its first character is the letter T or the number 1.
|
||||||
|
All other values are false. Examples: True, true, T, t, 1.
|
||||||
|
|
||||||
|
* `Debug` or `D`: toggle debug mode within the app.
|
||||||
|
* `DebugOverlay` or `DO`: toggle the debug text overlay.
|
||||||
|
* `DebugCollision` or `DC`: toggle collision hitbox lines.
|
||||||
|
|
||||||
|
## Interesting Tricks
|
||||||
|
|
||||||
|
### Editable Map While Playing
|
||||||
|
|
||||||
|
In Play Mode run the command:
|
||||||
|
|
||||||
|
| Command | Effect |
|
||||||
|
|--------------------------------------------|----------------------------------------------------------------|
|
||||||
|
| `$ d.Scene.Drawing().Editable = true` | Can click and drag new pixels onto the level while playing it. |
|
||||||
|
| `$ d.Scene.Drawing().Scrollable = true` | Arrow keys scroll the map, like in editor mode. |
|
||||||
|
| `$ d.Scene.Drawing().NoLimitScroll = true` | Allow map to scroll beyond bounded limits. |
|
||||||
|
|
||||||
|
The equivalent Canvas in the Edit Mode is at `d.Scene.UI.Canvas`
|
||||||
|
|
||||||
|
### Edit Out-of-Bounds in Editor Mode
|
||||||
|
|
||||||
|
In Edit Mode run the command:
|
||||||
|
|
||||||
|
`$ d.Scene.UI.Canvas.NoLimitScroll = true`
|
||||||
|
|
||||||
|
and you can scroll the map freely outside of the normal scroll boundaries. For
|
||||||
|
example, to see/edit pixels outside the top-left edges of bounded levels.
|
||||||
|
|
|
@ -211,6 +211,11 @@ func (c Color) DecodeMsgpack(dec *msgpack.Decoder) error {
|
||||||
// return nil
|
// return nil
|
||||||
// }
|
// }
|
||||||
|
|
||||||
|
// IsZero returns if the color is all zeroes (invisible).
|
||||||
|
func (c Color) IsZero() bool {
|
||||||
|
return c.Red+c.Green+c.Blue+c.Alpha == 0
|
||||||
|
}
|
||||||
|
|
||||||
// Add a relative color value to the color.
|
// Add a relative color value to the color.
|
||||||
func (c Color) Add(r, g, b, a int) Color {
|
func (c Color) Add(r, g, b, a int) Color {
|
||||||
var (
|
var (
|
||||||
|
@ -237,6 +242,16 @@ func (c Color) Add(r, g, b, a int) Color {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// AddColor adds another Color to your Color.
|
||||||
|
func (c Color) AddColor(other Color) Color {
|
||||||
|
return c.Add(
|
||||||
|
int(other.Red),
|
||||||
|
int(other.Green),
|
||||||
|
int(other.Blue),
|
||||||
|
int(other.Alpha),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
// Lighten a color value.
|
// Lighten a color value.
|
||||||
func (c Color) Lighten(v int) Color {
|
func (c Color) Lighten(v int) Color {
|
||||||
return c.Add(v, v, v, 0)
|
return c.Add(v, v, v, 0)
|
||||||
|
|
|
@ -23,6 +23,10 @@ type Collide struct {
|
||||||
BottomPoint render.Point
|
BottomPoint render.Point
|
||||||
BottomPixel *level.Swatch
|
BottomPixel *level.Swatch
|
||||||
MoveTo render.Point
|
MoveTo render.Point
|
||||||
|
|
||||||
|
// Swatch attributes affecting the collision at this time.
|
||||||
|
InFire bool
|
||||||
|
InWater bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reset a Collide struct flipping all the bools off, but keeping MoveTo.
|
// Reset a Collide struct flipping all the bools off, but keeping MoveTo.
|
||||||
|
@ -196,7 +200,8 @@ func CollidesWithGrid(d doodads.Actor, grid *level.Chunker, target render.Point)
|
||||||
|
|
||||||
// IsColliding returns whether any sort of collision has occurred.
|
// IsColliding returns whether any sort of collision has occurred.
|
||||||
func (c *Collide) IsColliding() bool {
|
func (c *Collide) IsColliding() bool {
|
||||||
return c.Top || c.Bottom || c.Left || c.Right
|
return c.Top || c.Bottom || c.Left || c.Right ||
|
||||||
|
c.InFire || c.InWater
|
||||||
}
|
}
|
||||||
|
|
||||||
// ScanBoundingBox scans all of the pixels in a bounding box on the grid and
|
// ScanBoundingBox scans all of the pixels in a bounding box on the grid and
|
||||||
|
@ -235,21 +240,39 @@ func (c *Collide) ScanBoundingBox(box render.Rect, grid *level.Chunker) bool {
|
||||||
// bounding boxes of the doodad.
|
// bounding boxes of the doodad.
|
||||||
func (c *Collide) ScanGridLine(p1, p2 render.Point, grid *level.Chunker, side Side) {
|
func (c *Collide) ScanGridLine(p1, p2 render.Point, grid *level.Chunker, side Side) {
|
||||||
for point := range render.IterLine2(p1, p2) {
|
for point := range render.IterLine2(p1, p2) {
|
||||||
if _, err := grid.Get(point); err == nil {
|
if swatch, err := grid.Get(point); err == nil {
|
||||||
// A hit!
|
// We're intersecting a pixel! If it's a solid one we'll return it
|
||||||
|
// in our result. If non-solid, we'll collect attributes from it
|
||||||
|
// and return them in the final result for gameplay behavior.
|
||||||
|
if swatch.Fire {
|
||||||
|
c.InFire = true
|
||||||
|
}
|
||||||
|
if swatch.Water {
|
||||||
|
c.InWater = true
|
||||||
|
}
|
||||||
|
|
||||||
|
// Non-solid swatches don't collide so don't pay them attention.
|
||||||
|
if !swatch.Solid {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
switch side {
|
switch side {
|
||||||
case Top:
|
case Top:
|
||||||
c.Top = true
|
c.Top = true
|
||||||
c.TopPoint = point
|
c.TopPoint = point
|
||||||
|
c.TopPixel = swatch
|
||||||
case Bottom:
|
case Bottom:
|
||||||
c.Bottom = true
|
c.Bottom = true
|
||||||
c.BottomPoint = point
|
c.BottomPoint = point
|
||||||
|
c.BottomPixel = swatch
|
||||||
case Left:
|
case Left:
|
||||||
c.Left = true
|
c.Left = true
|
||||||
c.LeftPoint = point
|
c.LeftPoint = point
|
||||||
|
c.LeftPixel = swatch
|
||||||
case Right:
|
case Right:
|
||||||
c.Right = true
|
c.Right = true
|
||||||
c.RightPoint = point
|
c.RightPoint = point
|
||||||
|
c.RightPixel = swatch
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -161,8 +161,13 @@ func (c *Chunk) ToBitmap(filename string, mask render.Color) (render.Texturer, e
|
||||||
for px := range c.Iter() {
|
for px := range c.Iter() {
|
||||||
var color = px.Swatch.Color
|
var color = px.Swatch.Color
|
||||||
if mask != render.Invisible {
|
if mask != render.Invisible {
|
||||||
|
// A semi-transparent mask will overlay on top of the actual color.
|
||||||
|
if mask.Alpha < 255 {
|
||||||
|
color = color.AddColor(mask)
|
||||||
|
} else {
|
||||||
color = mask
|
color = mask
|
||||||
}
|
}
|
||||||
|
}
|
||||||
img.Set(
|
img.Set(
|
||||||
int(px.X-pointOffset.X),
|
int(px.X-pointOffset.X),
|
||||||
int(px.Y-pointOffset.Y),
|
int(px.Y-pointOffset.Y),
|
||||||
|
|
|
@ -40,34 +40,40 @@ func (s *MainScene) Setup(d *Doodle) error {
|
||||||
frame := ui.NewFrame("frame")
|
frame := ui.NewFrame("frame")
|
||||||
s.frame = frame
|
s.frame = frame
|
||||||
|
|
||||||
button1 := ui.NewButton("Button1", ui.NewLabel(ui.Label{
|
var buttons = []struct {
|
||||||
Text: "New Map",
|
Name string
|
||||||
|
Func func()
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
Name: "Play a Level",
|
||||||
|
Func: d.GotoPlayMenu,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "Create a New Level",
|
||||||
|
Func: d.GotoNewMenu,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "Edit a Level",
|
||||||
|
Func: d.GotoLoadMenu,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, button := range buttons {
|
||||||
|
button := button
|
||||||
|
btn := ui.NewButton(button.Name, ui.NewLabel(ui.Label{
|
||||||
|
Text: button.Name,
|
||||||
Font: balance.StatusFont,
|
Font: balance.StatusFont,
|
||||||
}))
|
}))
|
||||||
button1.Handle(ui.Click, func(p render.Point) {
|
btn.Handle(ui.Click, func(p render.Point) {
|
||||||
d.GotoNewMenu()
|
button.Func()
|
||||||
})
|
})
|
||||||
|
s.Supervisor.Add(btn)
|
||||||
button2 := ui.NewButton("Button2", ui.NewLabel(ui.Label{
|
frame.Pack(btn, ui.Pack{
|
||||||
Text: "Load Map",
|
|
||||||
Font: balance.StatusFont,
|
|
||||||
}))
|
|
||||||
button2.Handle(ui.Click, func(p render.Point) {
|
|
||||||
d.GotoLoadMenu()
|
|
||||||
})
|
|
||||||
|
|
||||||
frame.Pack(button1, ui.Pack{
|
|
||||||
Anchor: ui.N,
|
Anchor: ui.N,
|
||||||
Fill: true,
|
PadY: 8,
|
||||||
|
// Fill: true,
|
||||||
|
FillX: true,
|
||||||
})
|
})
|
||||||
frame.Pack(button2, ui.Pack{
|
}
|
||||||
Anchor: ui.N,
|
|
||||||
PadY: 12,
|
|
||||||
Fill: true,
|
|
||||||
})
|
|
||||||
|
|
||||||
s.Supervisor.Add(button1)
|
|
||||||
s.Supervisor.Add(button2)
|
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,6 +36,9 @@ type MenuScene struct {
|
||||||
// Values for the New menu
|
// Values for the New menu
|
||||||
newPageType string
|
newPageType string
|
||||||
newWallpaper string
|
newWallpaper string
|
||||||
|
|
||||||
|
// Values for the Load/Play menu.
|
||||||
|
loadForPlay bool // false = load for edit
|
||||||
}
|
}
|
||||||
|
|
||||||
// Name of the scene.
|
// Name of the scene.
|
||||||
|
@ -54,13 +57,24 @@ func (d *Doodle) GotoNewMenu() {
|
||||||
|
|
||||||
// GotoLoadMenu loads the MenuScene and shows the "Load" window.
|
// GotoLoadMenu loads the MenuScene and shows the "Load" window.
|
||||||
func (d *Doodle) GotoLoadMenu() {
|
func (d *Doodle) GotoLoadMenu() {
|
||||||
log.Info("Loading the MenuScene to the Load window")
|
log.Info("Loading the MenuScene to the Load window for Edit Mode")
|
||||||
scene := &MenuScene{
|
scene := &MenuScene{
|
||||||
StartupMenu: "load",
|
StartupMenu: "load",
|
||||||
}
|
}
|
||||||
d.Goto(scene)
|
d.Goto(scene)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GotoPlayMenu loads the MenuScene and shows the "Load" window for playing a
|
||||||
|
// level, not editing it.
|
||||||
|
func (d *Doodle) GotoPlayMenu() {
|
||||||
|
log.Info("Loading the MenuScene to the Load window for Play Mode")
|
||||||
|
scene := &MenuScene{
|
||||||
|
StartupMenu: "load",
|
||||||
|
loadForPlay: true,
|
||||||
|
}
|
||||||
|
d.Goto(scene)
|
||||||
|
}
|
||||||
|
|
||||||
// Setup the scene.
|
// Setup the scene.
|
||||||
func (s *MenuScene) Setup(d *Doodle) error {
|
func (s *MenuScene) Setup(d *Doodle) error {
|
||||||
s.Supervisor = ui.NewSupervisor()
|
s.Supervisor = ui.NewSupervisor()
|
||||||
|
@ -358,7 +372,11 @@ func (s *MenuScene) setupLoadWindow(d *Doodle) error {
|
||||||
Font: balance.MenuFont,
|
Font: balance.MenuFont,
|
||||||
}))
|
}))
|
||||||
btn.Handle(ui.Click, func(p render.Point) {
|
btn.Handle(ui.Click, func(p render.Point) {
|
||||||
|
if s.loadForPlay {
|
||||||
|
d.PlayLevel(lvl)
|
||||||
|
} else {
|
||||||
d.EditFile(lvl)
|
d.EditFile(lvl)
|
||||||
|
}
|
||||||
})
|
})
|
||||||
s.Supervisor.Add(btn)
|
s.Supervisor.Add(btn)
|
||||||
lvlRow.Pack(btn, ui.Pack{
|
lvlRow.Pack(btn, ui.Pack{
|
||||||
|
@ -383,7 +401,9 @@ func (s *MenuScene) setupLoadWindow(d *Doodle) error {
|
||||||
* Frame for selecting User Doodads
|
* Frame for selecting User Doodads
|
||||||
******************/
|
******************/
|
||||||
|
|
||||||
if !balance.FreeVersion {
|
// Doodads not shown if we're loading a map to play, nor are they
|
||||||
|
// available to the free version.
|
||||||
|
if !s.loadForPlay && !balance.FreeVersion {
|
||||||
label2 := ui.NewLabel(ui.Label{
|
label2 := ui.NewLabel(ui.Label{
|
||||||
Text: "Doodads",
|
Text: "Doodads",
|
||||||
Font: balance.LabelFont,
|
Font: balance.LabelFont,
|
||||||
|
|
|
@ -7,6 +7,7 @@ import (
|
||||||
"git.kirsle.net/apps/doodle/lib/render"
|
"git.kirsle.net/apps/doodle/lib/render"
|
||||||
"git.kirsle.net/apps/doodle/lib/ui"
|
"git.kirsle.net/apps/doodle/lib/ui"
|
||||||
"git.kirsle.net/apps/doodle/pkg/balance"
|
"git.kirsle.net/apps/doodle/pkg/balance"
|
||||||
|
"git.kirsle.net/apps/doodle/pkg/collision"
|
||||||
"git.kirsle.net/apps/doodle/pkg/doodads"
|
"git.kirsle.net/apps/doodle/pkg/doodads"
|
||||||
"git.kirsle.net/apps/doodle/pkg/level"
|
"git.kirsle.net/apps/doodle/pkg/level"
|
||||||
"git.kirsle.net/apps/doodle/pkg/log"
|
"git.kirsle.net/apps/doodle/pkg/log"
|
||||||
|
@ -115,6 +116,17 @@ func (s *PlayScene) Setup(d *Doodle) error {
|
||||||
s.drawing.Resize(render.NewRect(int32(d.width), int32(d.height)))
|
s.drawing.Resize(render.NewRect(int32(d.width), int32(d.height)))
|
||||||
s.drawing.Compute(d.Engine)
|
s.drawing.Compute(d.Engine)
|
||||||
|
|
||||||
|
// Handler when an actor touches water or fire.
|
||||||
|
s.drawing.OnLevelCollision = func(a *uix.Actor, col *collision.Collide) {
|
||||||
|
if col.InFire {
|
||||||
|
a.Canvas.MaskColor = render.Black
|
||||||
|
} else if col.InWater {
|
||||||
|
a.Canvas.MaskColor = render.DarkBlue
|
||||||
|
} else {
|
||||||
|
a.Canvas.MaskColor = render.Invisible
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Given a filename or map data to play?
|
// Given a filename or map data to play?
|
||||||
if s.Level != nil {
|
if s.Level != nil {
|
||||||
log.Debug("PlayScene.Setup: received level from scene caller")
|
log.Debug("PlayScene.Setup: received level from scene caller")
|
||||||
|
|
|
@ -77,6 +77,9 @@ func (w *Canvas) loopActorCollision() error {
|
||||||
info, ok := collision.CollidesWithGrid(a, w.chunks, delta)
|
info, ok := collision.CollidesWithGrid(a, w.chunks, delta)
|
||||||
if ok {
|
if ok {
|
||||||
// Collision happened with world.
|
// Collision happened with world.
|
||||||
|
if w.OnLevelCollision != nil {
|
||||||
|
w.OnLevelCollision(a, info)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
delta = info.MoveTo // Move us back where the collision check put us
|
delta = info.MoveTo // Move us back where the collision check put us
|
||||||
|
|
||||||
|
|
|
@ -11,6 +11,7 @@ import (
|
||||||
"git.kirsle.net/apps/doodle/lib/ui"
|
"git.kirsle.net/apps/doodle/lib/ui"
|
||||||
"git.kirsle.net/apps/doodle/pkg/balance"
|
"git.kirsle.net/apps/doodle/pkg/balance"
|
||||||
"git.kirsle.net/apps/doodle/pkg/bindata"
|
"git.kirsle.net/apps/doodle/pkg/bindata"
|
||||||
|
"git.kirsle.net/apps/doodle/pkg/collision"
|
||||||
"git.kirsle.net/apps/doodle/pkg/doodads"
|
"git.kirsle.net/apps/doodle/pkg/doodads"
|
||||||
"git.kirsle.net/apps/doodle/pkg/drawtool"
|
"git.kirsle.net/apps/doodle/pkg/drawtool"
|
||||||
"git.kirsle.net/apps/doodle/pkg/level"
|
"git.kirsle.net/apps/doodle/pkg/level"
|
||||||
|
@ -75,6 +76,9 @@ type Canvas struct {
|
||||||
OnLinkActors func(a, b *Actor)
|
OnLinkActors func(a, b *Actor)
|
||||||
linkFirst *Actor
|
linkFirst *Actor
|
||||||
|
|
||||||
|
// Collision handlers for level geometry.
|
||||||
|
OnLevelCollision func(*Actor, *collision.Collide)
|
||||||
|
|
||||||
/********
|
/********
|
||||||
* Editable canvas private variables.
|
* Editable canvas private variables.
|
||||||
********/
|
********/
|
||||||
|
|
|
@ -114,6 +114,9 @@ func (w *Canvas) PresentWallpaper(e render.Engine, p render.Point) error {
|
||||||
limit.Y = S.H
|
limit.Y = S.H
|
||||||
}
|
}
|
||||||
|
|
||||||
|
limit.X += size.W
|
||||||
|
limit.Y += size.H
|
||||||
|
|
||||||
// Tile the repeat texture.
|
// Tile the repeat texture.
|
||||||
for x := origin.X - size.W; x < limit.X; x += size.W {
|
for x := origin.X - size.W; x < limit.X; x += size.W {
|
||||||
for y := origin.Y - size.H; y < limit.Y; y += size.H {
|
for y := origin.Y - size.H; y < limit.Y; y += size.H {
|
||||||
|
|