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) {
|
||||
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?
|
||||
if strings.HasSuffix(filename, 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.GameVersion = branding.Version
|
||||
|
||||
// Maintenance functions, clean up cruft before save.
|
||||
m.PruneLinks()
|
||||
|
||||
bin, err := m.ToJSON()
|
||||
if err != nil {
|
||||
return err
|
||||
|
|
|
@ -6,7 +6,6 @@ import (
|
|||
"git.kirsle.net/apps/doodle/lib/ui"
|
||||
"git.kirsle.net/apps/doodle/pkg/balance"
|
||||
"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/log"
|
||||
"git.kirsle.net/apps/doodle/pkg/scripting"
|
||||
|
@ -89,19 +88,15 @@ func (s *MainScene) SetupDemoLevel(d *Doodle) error {
|
|||
H: int32(d.height),
|
||||
})
|
||||
|
||||
// Title screen level to load.
|
||||
lvlName, _ := filesystem.FindFile("example1.level")
|
||||
lvl, err := level.LoadJSON(lvlName)
|
||||
if err != nil {
|
||||
log.Error("Error loading title-screen.level: %s", err)
|
||||
}
|
||||
s.scripting = scripting.NewSupervisor()
|
||||
s.canvas.SetScriptSupervisor(s.scripting)
|
||||
|
||||
// Title screen level to load.
|
||||
if lvl, err := level.LoadFile("example1.level"); err == nil {
|
||||
s.canvas.LoadLevel(d.Engine, lvl)
|
||||
s.canvas.InstallActors(lvl.Actors)
|
||||
|
||||
// Load all actor scripts.
|
||||
s.scripting = scripting.NewSupervisor()
|
||||
s.canvas.SetScriptSupervisor(s.scripting)
|
||||
if err := s.scripting.InstallScripts(lvl); err != nil {
|
||||
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 {
|
||||
log.Error("Error running actor main() functions: %s", err)
|
||||
}
|
||||
} else {
|
||||
log.Error("Error loading title-screen.level: %s", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -36,6 +36,7 @@ type PlayScene struct {
|
|||
// The alert box shows up when the level goal is reached and includes
|
||||
// buttons what to do next.
|
||||
alertBox *ui.Window
|
||||
alertBoxLabel *ui.Label
|
||||
alertReplayButton *ui.Button // Replay level
|
||||
alertEditButton *ui.Button // Edit 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) {
|
||||
if col.InFire {
|
||||
a.Canvas.MaskColor = render.Black
|
||||
s.DieByFire()
|
||||
} else if col.InWater {
|
||||
a.Canvas.MaskColor = render.DarkBlue
|
||||
} else {
|
||||
|
@ -201,11 +203,11 @@ func (s *PlayScene) SetupAlertbox() {
|
|||
* Frame for selecting User Levels
|
||||
******************/
|
||||
|
||||
label1 := ui.NewLabel(ui.Label{
|
||||
s.alertBoxLabel = ui.NewLabel(ui.Label{
|
||||
Text: "Congratulations on clearing the level!",
|
||||
Font: balance.LabelFont,
|
||||
})
|
||||
frame.Pack(label1, ui.Pack{
|
||||
frame.Pack(s.alertBoxLabel, ui.Pack{
|
||||
Anchor: ui.N,
|
||||
FillX: true,
|
||||
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.
|
||||
func (s *PlayScene) Loop(d *Doodle, ev *events.State) error {
|
||||
// Update debug overlay values.
|
||||
|
|
|
@ -188,6 +188,24 @@ func (w *Canvas) drawStrokes(e render.Engine, strokes []*drawtool.Stroke) {
|
|||
)
|
||||
|
||||
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() {
|
||||
if !point.Inside(VP) {
|
||||
continue
|
||||
|
|
Loading…
Reference in New Issue
Block a user