graphics for demo game
This commit is contained in:
BIN
assets/bg/bedroom.png
Normal file
BIN
assets/bg/bedroom.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.2 MiB |
BIN
assets/bg/kitchen.png
Normal file
BIN
assets/bg/kitchen.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.4 MiB |
BIN
assets/spr/player.png
Normal file
BIN
assets/spr/player.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 4.0 MiB |
@@ -12,7 +12,7 @@ func defineCat(g *p.Game) {
|
|||||||
Sprite: "spr/cat",
|
Sprite: "spr/cat",
|
||||||
Speed: 40,
|
Speed: 40,
|
||||||
SpeechColor: color.RGBA{200, 200, 255, 255},
|
SpeechColor: color.RGBA{200, 200, 255, 255},
|
||||||
W: 18,
|
W: 34,
|
||||||
H: 14,
|
H: 20,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ func definePlayer(g *p.Game) {
|
|||||||
Sprite: "spr/player",
|
Sprite: "spr/player",
|
||||||
Speed: 80,
|
Speed: 80,
|
||||||
SpeechColor: color.RGBA{255, 230, 160, 255},
|
SpeechColor: color.RGBA{255, 230, 160, 255},
|
||||||
W: 14,
|
W: 28,
|
||||||
H: 28,
|
H: 62,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ func defineBedroom(g *p.Game) {
|
|||||||
Background: "bg/bedroom",
|
Background: "bg/bedroom",
|
||||||
Music: "mus/wakeup",
|
Music: "mus/wakeup",
|
||||||
Actors: []p.SceneActor{
|
Actors: []p.SceneActor{
|
||||||
{CharacterName: "player", At: p.Point{X: 160, Y: 120}},
|
{CharacterName: "player", At: p.Point{X: 160, Y: 145}},
|
||||||
},
|
},
|
||||||
Hotspots: []p.Hotspot{
|
Hotspots: []p.Hotspot{
|
||||||
{
|
{
|
||||||
@@ -29,7 +29,7 @@ func defineBedroom(g *p.Game) {
|
|||||||
OnTake: p.If(p.Flag(FlagKeyTaken),
|
OnTake: p.If(p.Flag(FlagKeyTaken),
|
||||||
p.Say("player", "Már elvittem."),
|
p.Say("player", "Már elvittem."),
|
||||||
p.Seq(
|
p.Seq(
|
||||||
p.Walk("player", p.Point{X: 130, Y: 120}),
|
p.Walk("player", p.Point{X: 130, Y: 145}),
|
||||||
p.Give("key"),
|
p.Give("key"),
|
||||||
p.SetFlag(FlagKeyTaken),
|
p.SetFlag(FlagKeyTaken),
|
||||||
p.Say("player", "Pont jól jöhet."),
|
p.Say("player", "Pont jól jöhet."),
|
||||||
@@ -38,7 +38,7 @@ func defineBedroom(g *p.Game) {
|
|||||||
OnUse: p.If(p.Flag(FlagKeyTaken),
|
OnUse: p.If(p.Flag(FlagKeyTaken),
|
||||||
p.Say("player", "Már elvittem a kulcsot."),
|
p.Say("player", "Már elvittem a kulcsot."),
|
||||||
p.Seq(
|
p.Seq(
|
||||||
p.Walk("player", p.Point{X: 130, Y: 120}),
|
p.Walk("player", p.Point{X: 130, Y: 145}),
|
||||||
p.Give("key"),
|
p.Give("key"),
|
||||||
p.SetFlag(FlagKeyTaken),
|
p.SetFlag(FlagKeyTaken),
|
||||||
p.Say("player", "Megvan a kulcs."),
|
p.Say("player", "Megvan a kulcs."),
|
||||||
@@ -51,7 +51,7 @@ func defineBedroom(g *p.Game) {
|
|||||||
Label: "ajtó",
|
Label: "ajtó",
|
||||||
OnLook: p.Say("player", "Az ajtó a konyhába vezet."),
|
OnLook: p.Say("player", "Az ajtó a konyhába vezet."),
|
||||||
OnUse: p.Seq(
|
OnUse: p.Seq(
|
||||||
p.Walk("player", p.Point{X: 260, Y: 130}),
|
p.Walk("player", p.Point{X: 260, Y: 145}),
|
||||||
p.GoTo("kitchen"),
|
p.GoTo("kitchen"),
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -8,8 +8,8 @@ func defineKitchen(g *p.Game) {
|
|||||||
Background: "bg/kitchen",
|
Background: "bg/kitchen",
|
||||||
Music: "mus/calm",
|
Music: "mus/calm",
|
||||||
Actors: []p.SceneActor{
|
Actors: []p.SceneActor{
|
||||||
{CharacterName: "player", At: p.Point{X: 60, Y: 130}},
|
{CharacterName: "player", At: p.Point{X: 60, Y: 145}},
|
||||||
{CharacterName: "cat", At: p.Point{X: 210, Y: 132}},
|
{CharacterName: "cat", At: p.Point{X: 215, Y: 142}},
|
||||||
},
|
},
|
||||||
Hotspots: []p.Hotspot{
|
Hotspots: []p.Hotspot{
|
||||||
{
|
{
|
||||||
@@ -21,7 +21,7 @@ func defineKitchen(g *p.Game) {
|
|||||||
p.Say("player", "Már nyitva van."),
|
p.Say("player", "Már nyitva van."),
|
||||||
p.If(p.HasItem("key"),
|
p.If(p.HasItem("key"),
|
||||||
p.Seq(
|
p.Seq(
|
||||||
p.Walk("player", p.Point{X: 70, Y: 130}),
|
p.Walk("player", p.Point{X: 70, Y: 145}),
|
||||||
p.Say("player", "Klikk."),
|
p.Say("player", "Klikk."),
|
||||||
p.SetFlag(FlagCupboardOpen),
|
p.SetFlag(FlagCupboardOpen),
|
||||||
p.Give("beans"),
|
p.Give("beans"),
|
||||||
@@ -32,7 +32,7 @@ func defineKitchen(g *p.Game) {
|
|||||||
),
|
),
|
||||||
OnUseWith: map[string]p.Action{
|
OnUseWith: map[string]p.Action{
|
||||||
"key": p.Seq(
|
"key": p.Seq(
|
||||||
p.Walk("player", p.Point{X: 70, Y: 130}),
|
p.Walk("player", p.Point{X: 70, Y: 145}),
|
||||||
p.Say("player", "Klikk."),
|
p.Say("player", "Klikk."),
|
||||||
p.SetFlag(FlagCupboardOpen),
|
p.SetFlag(FlagCupboardOpen),
|
||||||
p.Give("beans"),
|
p.Give("beans"),
|
||||||
@@ -48,7 +48,7 @@ func defineKitchen(g *p.Game) {
|
|||||||
OnTake: p.If(p.Flag(FlagMugTaken),
|
OnTake: p.If(p.Flag(FlagMugTaken),
|
||||||
p.Say("player", "Tiszta már mind elfogyott."),
|
p.Say("player", "Tiszta már mind elfogyott."),
|
||||||
p.Seq(
|
p.Seq(
|
||||||
p.Walk("player", p.Point{X: 125, Y: 130}),
|
p.Walk("player", p.Point{X: 125, Y: 145}),
|
||||||
p.Give("mug"),
|
p.Give("mug"),
|
||||||
p.SetFlag(FlagMugTaken),
|
p.SetFlag(FlagMugTaken),
|
||||||
p.Say("player", "Egy bögre, kérem."),
|
p.Say("player", "Egy bögre, kérem."),
|
||||||
@@ -57,7 +57,7 @@ func defineKitchen(g *p.Game) {
|
|||||||
OnUse: p.If(p.Flag(FlagMugTaken),
|
OnUse: p.If(p.Flag(FlagMugTaken),
|
||||||
p.Say("player", "Már elvettem egyet."),
|
p.Say("player", "Már elvettem egyet."),
|
||||||
p.Seq(
|
p.Seq(
|
||||||
p.Walk("player", p.Point{X: 125, Y: 130}),
|
p.Walk("player", p.Point{X: 125, Y: 145}),
|
||||||
p.Give("mug"),
|
p.Give("mug"),
|
||||||
p.SetFlag(FlagMugTaken),
|
p.SetFlag(FlagMugTaken),
|
||||||
p.Say("player", "Egy bögre, kérem."),
|
p.Say("player", "Egy bögre, kérem."),
|
||||||
@@ -75,7 +75,7 @@ func defineKitchen(g *p.Game) {
|
|||||||
),
|
),
|
||||||
OnUseWith: map[string]p.Action{
|
OnUseWith: map[string]p.Action{
|
||||||
"beans": p.Seq(
|
"beans": p.Seq(
|
||||||
p.Walk("player", p.Point{X: 180, Y: 130}),
|
p.Walk("player", p.Point{X: 180, Y: 145}),
|
||||||
p.SetFlag(FlagCoffeeHasBeans),
|
p.SetFlag(FlagCoffeeHasBeans),
|
||||||
p.TakeAway("beans"),
|
p.TakeAway("beans"),
|
||||||
p.Say("player", "Bab a helyén."),
|
p.Say("player", "Bab a helyén."),
|
||||||
@@ -83,7 +83,7 @@ func defineKitchen(g *p.Game) {
|
|||||||
p.RunScript("victory")),
|
p.RunScript("victory")),
|
||||||
),
|
),
|
||||||
"mug": p.Seq(
|
"mug": p.Seq(
|
||||||
p.Walk("player", p.Point{X: 180, Y: 130}),
|
p.Walk("player", p.Point{X: 180, Y: 145}),
|
||||||
p.SetFlag(FlagCoffeeHasMug),
|
p.SetFlag(FlagCoffeeHasMug),
|
||||||
p.TakeAway("mug"),
|
p.TakeAway("mug"),
|
||||||
p.Say("player", "Bögre a helyén."),
|
p.Say("player", "Bögre a helyén."),
|
||||||
@@ -105,7 +105,7 @@ func defineKitchen(g *p.Game) {
|
|||||||
Label: "ajtó",
|
Label: "ajtó",
|
||||||
OnLook: p.Say("player", "Vissza a hálóba."),
|
OnLook: p.Say("player", "Vissza a hálóba."),
|
||||||
OnUse: p.Seq(
|
OnUse: p.Seq(
|
||||||
p.Walk("player", p.Point{X: 20, Y: 130}),
|
p.Walk("player", p.Point{X: 20, Y: 145}),
|
||||||
p.GoTo("bedroom"),
|
p.GoTo("bedroom"),
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ func defineIntroScript(g *p.Game) {
|
|||||||
p.Wait(0.4),
|
p.Wait(0.4),
|
||||||
p.Say("player", "Brr, hideg van."),
|
p.Say("player", "Brr, hideg van."),
|
||||||
p.Say("player", "Egy kávé kéne, mielőtt szétszakad a fejem."),
|
p.Say("player", "Egy kávé kéne, mielőtt szétszakad a fejem."),
|
||||||
p.Walk("player", p.Point{X: 160, Y: 130}),
|
p.Walk("player", p.Point{X: 200, Y: 145}),
|
||||||
),
|
),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,12 +18,14 @@ type AssetManager = Manager[Asset]
|
|||||||
// the actual *ebiten.Image bytes live, lazily decoded on first access.
|
// the actual *ebiten.Image bytes live, lazily decoded on first access.
|
||||||
type loadedAssets struct {
|
type loadedAssets struct {
|
||||||
images map[string]*ebiten.Image
|
images map[string]*ebiten.Image
|
||||||
|
placeholders map[string]bool
|
||||||
defaultW, defaultH int
|
defaultW, defaultH int
|
||||||
}
|
}
|
||||||
|
|
||||||
func newLoadedAssets(w, h int) *loadedAssets {
|
func newLoadedAssets(w, h int) *loadedAssets {
|
||||||
return &loadedAssets{
|
return &loadedAssets{
|
||||||
images: make(map[string]*ebiten.Image),
|
images: make(map[string]*ebiten.Image),
|
||||||
|
placeholders: make(map[string]bool),
|
||||||
defaultW: w,
|
defaultW: w,
|
||||||
defaultH: h,
|
defaultH: h,
|
||||||
}
|
}
|
||||||
@@ -37,16 +39,23 @@ func (la *loadedAssets) image(am *AssetManager, name string) *ebiten.Image {
|
|||||||
if !ok {
|
if !ok {
|
||||||
img := placeholderImage(name, la.defaultW, la.defaultH)
|
img := placeholderImage(name, la.defaultW, la.defaultH)
|
||||||
la.images[name] = img
|
la.images[name] = img
|
||||||
|
la.placeholders[name] = true
|
||||||
return img
|
return img
|
||||||
}
|
}
|
||||||
img := loadImageFile(a.Path)
|
img := loadImageFile(a.Path)
|
||||||
if img == nil {
|
if img == nil {
|
||||||
img = placeholderImage(name, la.defaultW, la.defaultH)
|
img = placeholderImage(name, la.defaultW, la.defaultH)
|
||||||
|
la.placeholders[name] = true
|
||||||
}
|
}
|
||||||
la.images[name] = img
|
la.images[name] = img
|
||||||
return img
|
return img
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (la *loadedAssets) isPlaceholder(name string) bool {
|
||||||
|
_, _ = la.images[name], la.placeholders[name] // ensure populated via image()
|
||||||
|
return la.placeholders[name]
|
||||||
|
}
|
||||||
|
|
||||||
func loadImageFile(path string) *ebiten.Image {
|
func loadImageFile(path string) *ebiten.Image {
|
||||||
f, err := os.Open(path)
|
f, err := os.Open(path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -268,12 +268,14 @@ func drawCharacter(dst *ebiten.Image, g *Game, c *runtimeChar) {
|
|||||||
w := c.def.W
|
w := c.def.W
|
||||||
h := c.def.H
|
h := c.def.H
|
||||||
if w == 0 {
|
if w == 0 {
|
||||||
w = 14
|
w = 24
|
||||||
}
|
}
|
||||||
if h == 0 {
|
if h == 0 {
|
||||||
h = 26
|
h = 56
|
||||||
}
|
}
|
||||||
if c.def.Sprite != "" {
|
// Try the real sprite first. Only fall through to the stylized
|
||||||
|
// placeholder when no actual art is on disk.
|
||||||
|
if c.def.Sprite != "" && !g.loaded.isPlaceholder(c.def.Sprite) {
|
||||||
img := g.loaded.image(g.AssetManager, c.def.Sprite)
|
img := g.loaded.image(g.AssetManager, c.def.Sprite)
|
||||||
sw, sh := img.Bounds().Dx(), img.Bounds().Dy()
|
sw, sh := img.Bounds().Dx(), img.Bounds().Dy()
|
||||||
if sw > 0 && sh > 0 {
|
if sw > 0 && sh > 0 {
|
||||||
@@ -284,9 +286,84 @@ func drawCharacter(dst *ebiten.Image, g *Game, c *runtimeChar) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
col := color.RGBA{200, 200, 200, 255}
|
// Touch the asset cache so isPlaceholder is populated for later frames.
|
||||||
|
if c.def.Sprite != "" {
|
||||||
|
_ = g.loaded.image(g.AssetManager, c.def.Sprite)
|
||||||
|
}
|
||||||
|
x := c.pos.X - w/2
|
||||||
|
y := c.pos.Y - h
|
||||||
|
bodyCol := color.RGBA{200, 200, 200, 255}
|
||||||
if rgba, ok := c.def.SpeechColor.(color.RGBA); ok {
|
if rgba, ok := c.def.SpeechColor.(color.RGBA); ok {
|
||||||
col = rgba
|
bodyCol = rgba
|
||||||
}
|
}
|
||||||
vector.DrawFilledRect(dst, float32(c.pos.X-w/2), float32(c.pos.Y-h), float32(w), float32(h), col, false)
|
if w > h {
|
||||||
|
drawQuadrupedPlaceholder(dst, x, y, w, h, bodyCol)
|
||||||
|
} else {
|
||||||
|
drawHumanoidPlaceholder(dst, x, y, w, h, bodyCol)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func drawHumanoidPlaceholder(dst *ebiten.Image, x, y, w, h float64, body color.RGBA) {
|
||||||
|
pants := color.RGBA{40, 50, 90, 255}
|
||||||
|
skin := color.RGBA{245, 200, 155, 255}
|
||||||
|
outline := color.RGBA{20, 20, 30, 255}
|
||||||
|
|
||||||
|
headR := h * 0.14
|
||||||
|
headCY := y + headR + 1
|
||||||
|
|
||||||
|
// pants / legs — two narrow strips
|
||||||
|
pantsTop := y + h*0.62
|
||||||
|
pantsH := h - (pantsTop - y) - 1
|
||||||
|
legW := w * 0.36
|
||||||
|
vector.DrawFilledRect(dst, float32(x+w*0.08), float32(pantsTop), float32(legW), float32(pantsH), pants, false)
|
||||||
|
vector.DrawFilledRect(dst, float32(x+w*0.56), float32(pantsTop), float32(legW), float32(pantsH), pants, false)
|
||||||
|
|
||||||
|
// torso — full-width rect, shirt color
|
||||||
|
torsoTop := headCY + headR
|
||||||
|
torsoH := pantsTop - torsoTop
|
||||||
|
vector.DrawFilledRect(dst, float32(x), float32(torsoTop), float32(w), float32(torsoH), body, false)
|
||||||
|
vector.StrokeRect(dst, float32(x), float32(torsoTop), float32(w), float32(torsoH), 1, outline, false)
|
||||||
|
|
||||||
|
// head — circle in skin tone
|
||||||
|
vector.DrawFilledCircle(dst, float32(x+w/2), float32(headCY), float32(headR), skin, true)
|
||||||
|
|
||||||
|
// feet — short dark blobs at the very bottom
|
||||||
|
footH := 2.0
|
||||||
|
vector.DrawFilledRect(dst, float32(x+w*0.05), float32(y+h-footH), float32(legW+2), float32(footH), outline, false)
|
||||||
|
vector.DrawFilledRect(dst, float32(x+w*0.55), float32(y+h-footH), float32(legW+2), float32(footH), outline, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
func drawQuadrupedPlaceholder(dst *ebiten.Image, x, y, w, h float64, body color.RGBA) {
|
||||||
|
outline := color.RGBA{20, 20, 30, 255}
|
||||||
|
dark := color.RGBA{
|
||||||
|
R: body.R / 2, G: body.G / 2, B: body.B / 2, A: 255,
|
||||||
|
}
|
||||||
|
|
||||||
|
// body
|
||||||
|
bodyY := y + h*0.30
|
||||||
|
bodyH := h * 0.65
|
||||||
|
vector.DrawFilledRect(dst, float32(x), float32(bodyY), float32(w*0.78), float32(bodyH), body, false)
|
||||||
|
|
||||||
|
// head — circle on the right
|
||||||
|
headR := h * 0.30
|
||||||
|
headCX := x + w - headR
|
||||||
|
headCY := y + h*0.50
|
||||||
|
vector.DrawFilledCircle(dst, float32(headCX), float32(headCY), float32(headR), body, true)
|
||||||
|
|
||||||
|
// ears — two triangles approximated as small rects
|
||||||
|
earW := w * 0.07
|
||||||
|
earH := h * 0.30
|
||||||
|
vector.DrawFilledRect(dst, float32(headCX-headR*0.7), float32(y), float32(earW), float32(earH), body, false)
|
||||||
|
vector.DrawFilledRect(dst, float32(headCX+headR*0.4), float32(y), float32(earW), float32(earH), body, false)
|
||||||
|
|
||||||
|
// eye — dark dot
|
||||||
|
vector.DrawFilledCircle(dst, float32(headCX+headR*0.25), float32(headCY-1), 1.2, outline, true)
|
||||||
|
|
||||||
|
// tail — small dark line stub on the left
|
||||||
|
vector.DrawFilledRect(dst, float32(x-w*0.04), float32(bodyY+1), float32(w*0.08), 2, dark, false)
|
||||||
|
|
||||||
|
// legs — two short bars at the bottom
|
||||||
|
legW := w * 0.07
|
||||||
|
vector.DrawFilledRect(dst, float32(x+w*0.10), float32(y+h-3), float32(legW), 3, dark, false)
|
||||||
|
vector.DrawFilledRect(dst, float32(x+w*0.55), float32(y+h-3), float32(legW), 3, dark, false)
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user