diff --git a/client/assets/dino_blue.png b/client/assets/dino_blue.png new file mode 100644 index 0000000..8fb8734 Binary files /dev/null and b/client/assets/dino_blue.png differ diff --git a/client/assets/dino_green.png b/client/assets/dino_green.png new file mode 100644 index 0000000..1ee6744 Binary files /dev/null and b/client/assets/dino_green.png differ diff --git a/client/assets/dino_red.png b/client/assets/dino_red.png new file mode 100644 index 0000000..9089923 Binary files /dev/null and b/client/assets/dino_red.png differ diff --git a/client/assets/dino_yellow.png b/client/assets/dino_yellow.png new file mode 100644 index 0000000..c99f59e Binary files /dev/null and b/client/assets/dino_yellow.png differ diff --git a/client/assets/imagebank.go b/client/assets/imagebank.go new file mode 100644 index 0000000..7708340 --- /dev/null +++ b/client/assets/imagebank.go @@ -0,0 +1,51 @@ +package assets + +import ( + "bytes" + _ "embed" + "image" + "log" + + "github.com/hajimehoshi/ebiten/v2" +) + +type ImgAssetName string + +const ( + Green ImgAssetName = "Green" + Blue ImgAssetName = "Blue" + Yellow ImgAssetName = "Yellow" + Red ImgAssetName = "Red" +) + +var ( + ImageBank map[ImgAssetName]*ebiten.Image + + //go:embed dino_blue.png + blue_img []byte + //go:embed dino_green.png + green_img []byte + //go:embed dino_red.png + red_img []byte + //go:embed dino_yellow.png + yellow_img []byte +) + +func init() { + ImageBank = make(map[ImgAssetName]*ebiten.Image) + + ImageBank[Blue] = LoadImageFatal(blue_img) + ImageBank[Green] = LoadImageFatal(green_img) + ImageBank[Red] = LoadImageFatal(red_img) + ImageBank[Yellow] = LoadImageFatal(yellow_img) +} + +func LoadImageFatal(b []byte) *ebiten.Image { + + img, _, err := image.Decode(bytes.NewReader(b)) + if err != nil { + log.Fatal(err) + } + return ebiten.NewImageFromImage(img) + +} diff --git a/client/elements/dino.go b/client/elements/dino.go new file mode 100644 index 0000000..5197580 --- /dev/null +++ b/client/elements/dino.go @@ -0,0 +1,106 @@ +package elements + +import ( + "client/assets" + "client/gamedata" + "image" + + "github.com/hajimehoshi/ebiten/v2" +) + +const ( + dinoWidth = 24 + dinoHeight = 24 +) + +type DinoInfo struct { + DinoAction gamedata.DinoAction + NumCycles int + XOffset int +} + +var ( + dinoCycleCount = []DinoInfo{ + {gamedata.DinoActionIdle, 4, 0}, + {gamedata.DinoActionWalk, 6, 4}, + {gamedata.DinoActionSlap, 3, 10}, + } +) + +type Dino struct { + Sprite *ebiten.Image + dinotype gamedata.DinoType + dinoaction gamedata.DinoAction + cycle int + asset *ebiten.Image + left bool + slapping bool +} + +func NewDino(dtype gamedata.DinoType) *Dino { + dino := &Dino{ + Sprite: ebiten.NewImage(dinoWidth*2, dinoHeight*2), + cycle: 0, + dinotype: dtype, + dinoaction: gamedata.DinoActionIdle, + } + + switch dtype { + case gamedata.DinoTypeBlue: + dino.asset = assets.ImageBank[assets.Blue] + case gamedata.DinoTypeGreen: + dino.asset = assets.ImageBank[assets.Green] + case gamedata.DinoTypeRed: + dino.asset = assets.ImageBank[assets.Red] + case gamedata.DinoTypeYellow: + dino.asset = assets.ImageBank[assets.Yellow] + } + + return dino +} + +func (d *Dino) Update() { + d.cycle++ +} + +func (d *Dino) Draw() { + d.Sprite.Clear() + + idx := d.cycle / 8 % dinoCycleCount[d.dinoaction].NumCycles + x0 := dinoWidth * (idx + dinoCycleCount[d.dinoaction].XOffset) + y0 := 0 + x1 := x0 + dinoWidth + y1 := dinoHeight + + op := &ebiten.DrawImageOptions{} + if d.left { + op.GeoM.Scale(-1, 1) + op.GeoM.Translate(dinoWidth, 0) + } + op.GeoM.Translate(-dinoWidth/2, -dinoHeight/2) + op.GeoM.Scale(2, 2) + op.GeoM.Translate(dinoWidth, dinoHeight) + d.Sprite.DrawImage(d.asset.SubImage(image.Rect(x0, y0, x1, y1)).(*ebiten.Image), op) + + if d.slapping && idx >= dinoCycleCount[d.dinoaction].NumCycles-1 { + d.slapping = false + } + +} + +func (d *Dino) SetAction(action gamedata.DinoAction) { + if d.slapping { + //wait until we're done slapping + } else { + d.dinoaction = action + if action == gamedata.DinoActionSlap { + d.cycle = 0 + d.slapping = true + } + } + +} + +func (d *Dino) SetLeft(left bool) { + d.left = left +} diff --git a/client/game/game.go b/client/game/game.go index ef80b7e..1669af0 100644 --- a/client/game/game.go +++ b/client/game/game.go @@ -64,6 +64,8 @@ type Game struct { //similar fields that we see in the client list, but for us eliminated bool hit bool + + dino *elements.Dino } func NewGame() *Game { @@ -74,6 +76,7 @@ func NewGame() *Game { elimblocky: elements.NewBlock(), cycle: 0, name: namelist[rand.Intn(len(namelist))], + dino: elements.NewDino(gamedata.DinoTypeGreen), } g.blocky.SetColor(color.RGBA{R: 0xff, G: 0x00, B: 0x00, A: 0xff}) @@ -93,6 +96,7 @@ func NewGame() *Game { func (g *Game) Update() error { g.blocky.Update() + g.dino.Update() //g.hitblocky.Update() g.HandleInput() @@ -158,6 +162,12 @@ func (g *Game) Draw(screen *ebiten.Image) { text.Draw(screen, client.Name, f2, top) } + g.dino.Draw() + dop := &ebiten.DrawImageOptions{} + dop.GeoM.Translate(-float64(g.dino.Sprite.Bounds().Dx())/2, -float64(g.dino.Sprite.Bounds().Dy())/2) + dop.GeoM.Translate(g.blocky.GetPosition().X, g.blocky.GetPosition().Y) + screen.DrawImage(g.dino.Sprite, dop) + } func (g *Game) Layout(outsideWidth, outsideHeight int) (screenwidth, screenheight int) { @@ -260,6 +270,7 @@ func (g *Game) HandleInput() { dx := 0 dy := 0 + if ebiten.IsKeyPressed(ebiten.KeyW) { dy = -movementLimit } @@ -268,9 +279,17 @@ func (g *Game) HandleInput() { } if ebiten.IsKeyPressed(ebiten.KeyA) { dx = -movementLimit + g.dino.SetLeft(true) } if ebiten.IsKeyPressed(ebiten.KeyD) { dx = +movementLimit + g.dino.SetLeft(false) + } + + if math.Abs(float64(dx)) > 0 || math.Abs(float64(dy)) > 0 { + g.dino.SetAction(gamedata.DinoActionWalk) + } else { + g.dino.SetAction(gamedata.DinoActionIdle) } cpos := g.blocky.GetPosition() @@ -280,6 +299,7 @@ func (g *Game) HandleInput() { if inpututil.IsKeyJustPressed(ebiten.KeySpace) { g.SendSlap() + g.dino.SetAction(gamedata.DinoActionSlap) } } diff --git a/client/gamedata/gamedata.go b/client/gamedata/gamedata.go index 8b92fbd..11c4a33 100644 --- a/client/gamedata/gamedata.go +++ b/client/gamedata/gamedata.go @@ -2,6 +2,25 @@ package gamedata import "math" +type DinoType int + +const ( + DinoTypeGreen DinoType = iota + DinoTypeBlue + DinoTypeRed + DinoTypeYellow + DinoTypeMax +) + +type DinoAction int + +const ( + DinoActionIdle DinoAction = iota + DinoActionWalk + DinoActionSlap + DinoActionMax +) + type Coordinates struct { X float64 `json:"X"` Y float64 `json:"Y"`