Make Fire Deadly
* Touching "fire" pixels in a level will pop up the End Level alert box saying you've died by fire and can restart the level. * Update level.WriteFile() to prune broken links between actors before save. So when a linked actor is deleted, the leftover link data is cleaned up. * Slight optimization in Canvas.drawStrokes: if either end of the stroke is not within view of the screen, don't show the stroke.
This commit is contained in:
parent
cb02feff1d
commit
6476a67faf
|
@ -85,6 +85,11 @@ Returns the file path and an error if not found anywhere.
|
||||||
func FindFile(filename string) (string, error) {
|
func FindFile(filename string) (string, error) {
|
||||||
var filetype string
|
var filetype string
|
||||||
|
|
||||||
|
// If the filename has path separators, return it as-is.
|
||||||
|
if strings.ContainsRune(filename, filepath.Separator) {
|
||||||
|
return filename, nil
|
||||||
|
}
|
||||||
|
|
||||||
// Any hint on what type of file we're looking for?
|
// Any hint on what type of file we're looking for?
|
||||||
if strings.HasSuffix(filename, enum.LevelExt) {
|
if strings.HasSuffix(filename, enum.LevelExt) {
|
||||||
filetype = enum.LevelExt
|
filetype = enum.LevelExt
|
||||||
|
|
35
pkg/level/fmt_maintenance.go
Normal file
35
pkg/level/fmt_maintenance.go
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
package level
|
||||||
|
|
||||||
|
import "git.kirsle.net/apps/doodle/pkg/log"
|
||||||
|
|
||||||
|
// Maintenance functions for the file format on disk.
|
||||||
|
|
||||||
|
// PruneLinks cleans up any Actor Links that can not be resolved in the
|
||||||
|
// level data. For example, if actors were linked in Edit Mode and one
|
||||||
|
// actor is deleted leaving a broken link.
|
||||||
|
//
|
||||||
|
// Returns the number of broken links pruned.
|
||||||
|
//
|
||||||
|
// This is called automatically in WriteFile.
|
||||||
|
func (m *Level) PruneLinks() int {
|
||||||
|
var count int
|
||||||
|
for id, actor := range m.Actors {
|
||||||
|
var newLinks []string
|
||||||
|
|
||||||
|
for _, linkID := range actor.Links {
|
||||||
|
if _, ok := m.Actors[linkID]; !ok {
|
||||||
|
log.Warn("Level.PruneLinks: actor %s (%s) was linked to unresolved actor %s",
|
||||||
|
id,
|
||||||
|
actor.Filename,
|
||||||
|
linkID,
|
||||||
|
)
|
||||||
|
count++
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
newLinks = append(newLinks, linkID)
|
||||||
|
}
|
||||||
|
|
||||||
|
actor.Links = newLinks
|
||||||
|
}
|
||||||
|
return count
|
||||||
|
}
|
|
@ -104,6 +104,9 @@ func (m *Level) WriteFile(filename string) error {
|
||||||
m.Version = 1
|
m.Version = 1
|
||||||
m.GameVersion = branding.Version
|
m.GameVersion = branding.Version
|
||||||
|
|
||||||
|
// Maintenance functions, clean up cruft before save.
|
||||||
|
m.PruneLinks()
|
||||||
|
|
||||||
bin, err := m.ToJSON()
|
bin, err := m.ToJSON()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
|
|
@ -6,7 +6,6 @@ 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/branding"
|
"git.kirsle.net/apps/doodle/pkg/branding"
|
||||||
"git.kirsle.net/apps/doodle/pkg/filesystem"
|
|
||||||
"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"
|
||||||
"git.kirsle.net/apps/doodle/pkg/scripting"
|
"git.kirsle.net/apps/doodle/pkg/scripting"
|
||||||
|
@ -89,19 +88,15 @@ func (s *MainScene) SetupDemoLevel(d *Doodle) error {
|
||||||
H: int32(d.height),
|
H: int32(d.height),
|
||||||
})
|
})
|
||||||
|
|
||||||
// Title screen level to load.
|
s.scripting = scripting.NewSupervisor()
|
||||||
lvlName, _ := filesystem.FindFile("example1.level")
|
s.canvas.SetScriptSupervisor(s.scripting)
|
||||||
lvl, err := level.LoadJSON(lvlName)
|
|
||||||
if err != nil {
|
|
||||||
log.Error("Error loading title-screen.level: %s", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
// Title screen level to load.
|
||||||
|
if lvl, err := level.LoadFile("example1.level"); err == nil {
|
||||||
s.canvas.LoadLevel(d.Engine, lvl)
|
s.canvas.LoadLevel(d.Engine, lvl)
|
||||||
s.canvas.InstallActors(lvl.Actors)
|
s.canvas.InstallActors(lvl.Actors)
|
||||||
|
|
||||||
// Load all actor scripts.
|
// Load all actor scripts.
|
||||||
s.scripting = scripting.NewSupervisor()
|
|
||||||
s.canvas.SetScriptSupervisor(s.scripting)
|
|
||||||
if err := s.scripting.InstallScripts(lvl); err != nil {
|
if err := s.scripting.InstallScripts(lvl); err != nil {
|
||||||
log.Error("Error with title screen level scripts: %s", err)
|
log.Error("Error with title screen level scripts: %s", err)
|
||||||
}
|
}
|
||||||
|
@ -110,6 +105,9 @@ func (s *MainScene) SetupDemoLevel(d *Doodle) error {
|
||||||
if err := s.canvas.InstallScripts(); err != nil {
|
if err := s.canvas.InstallScripts(); err != nil {
|
||||||
log.Error("Error running actor main() functions: %s", err)
|
log.Error("Error running actor main() functions: %s", err)
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
log.Error("Error loading title-screen.level: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,6 +36,7 @@ type PlayScene struct {
|
||||||
// The alert box shows up when the level goal is reached and includes
|
// The alert box shows up when the level goal is reached and includes
|
||||||
// buttons what to do next.
|
// buttons what to do next.
|
||||||
alertBox *ui.Window
|
alertBox *ui.Window
|
||||||
|
alertBoxLabel *ui.Label
|
||||||
alertReplayButton *ui.Button // Replay level
|
alertReplayButton *ui.Button // Replay level
|
||||||
alertEditButton *ui.Button // Edit Level
|
alertEditButton *ui.Button // Edit Level
|
||||||
alertNextButton *ui.Button // Next Level
|
alertNextButton *ui.Button // Next Level
|
||||||
|
@ -120,6 +121,7 @@ func (s *PlayScene) Setup(d *Doodle) error {
|
||||||
s.drawing.OnLevelCollision = func(a *uix.Actor, col *collision.Collide) {
|
s.drawing.OnLevelCollision = func(a *uix.Actor, col *collision.Collide) {
|
||||||
if col.InFire {
|
if col.InFire {
|
||||||
a.Canvas.MaskColor = render.Black
|
a.Canvas.MaskColor = render.Black
|
||||||
|
s.DieByFire()
|
||||||
} else if col.InWater {
|
} else if col.InWater {
|
||||||
a.Canvas.MaskColor = render.DarkBlue
|
a.Canvas.MaskColor = render.DarkBlue
|
||||||
} else {
|
} else {
|
||||||
|
@ -201,11 +203,11 @@ func (s *PlayScene) SetupAlertbox() {
|
||||||
* Frame for selecting User Levels
|
* Frame for selecting User Levels
|
||||||
******************/
|
******************/
|
||||||
|
|
||||||
label1 := ui.NewLabel(ui.Label{
|
s.alertBoxLabel = ui.NewLabel(ui.Label{
|
||||||
Text: "Congratulations on clearing the level!",
|
Text: "Congratulations on clearing the level!",
|
||||||
Font: balance.LabelFont,
|
Font: balance.LabelFont,
|
||||||
})
|
})
|
||||||
frame.Pack(label1, ui.Pack{
|
frame.Pack(s.alertBoxLabel, ui.Pack{
|
||||||
Anchor: ui.N,
|
Anchor: ui.N,
|
||||||
FillX: true,
|
FillX: true,
|
||||||
PadY: 16,
|
PadY: 16,
|
||||||
|
@ -277,6 +279,24 @@ func (s *PlayScene) RestartLevel() {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// DieByFire ends the level by fire.
|
||||||
|
func (s *PlayScene) DieByFire() {
|
||||||
|
log.Info("Watch out for fire!")
|
||||||
|
s.alertBox.Title = "You've died!"
|
||||||
|
s.alertBoxLabel.Text = "Watch out for fire!"
|
||||||
|
|
||||||
|
s.alertReplayButton.Show()
|
||||||
|
if s.CanEdit {
|
||||||
|
s.alertEditButton.Show()
|
||||||
|
}
|
||||||
|
s.alertExitButton.Show()
|
||||||
|
|
||||||
|
s.alertBox.Show()
|
||||||
|
|
||||||
|
// Stop the simulation.
|
||||||
|
s.running = false
|
||||||
|
}
|
||||||
|
|
||||||
// Loop the editor scene.
|
// Loop the editor scene.
|
||||||
func (s *PlayScene) Loop(d *Doodle, ev *events.State) error {
|
func (s *PlayScene) Loop(d *Doodle, ev *events.State) error {
|
||||||
// Update debug overlay values.
|
// Update debug overlay values.
|
||||||
|
|
|
@ -188,6 +188,24 @@ func (w *Canvas) drawStrokes(e render.Engine, strokes []*drawtool.Stroke) {
|
||||||
)
|
)
|
||||||
|
|
||||||
for _, stroke := range strokes {
|
for _, stroke := range strokes {
|
||||||
|
// If none of this stroke is in our viewport, don't waste time
|
||||||
|
// looping through it.
|
||||||
|
if stroke.Shape == drawtool.Freehand {
|
||||||
|
if len(stroke.Points) >= 2 {
|
||||||
|
if !stroke.Points[0].Inside(VP) && !stroke.Points[len(stroke.Points)-1].Inside(VP) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// TODO: a very long line that starts and ends outside the viewport
|
||||||
|
// but passes thru it would disappear when both ends are out of
|
||||||
|
// view.
|
||||||
|
if !stroke.PointA.Inside(VP) && !stroke.PointB.Inside(VP) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Iter the points and draw what's visible.
|
||||||
for point := range stroke.IterPoints() {
|
for point := range stroke.IterPoints() {
|
||||||
if !point.Inside(VP) {
|
if !point.Inside(VP) {
|
||||||
continue
|
continue
|
||||||
|
|
Loading…
Reference in New Issue
Block a user