Add taunts

This commit is contained in:
Trevor Slocum 2023-01-26 22:30:53 -08:00
parent 383cfdc182
commit 0cd961dd83
9 changed files with 819 additions and 239 deletions

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.1 KiB

After

Width:  |  Height:  |  Size: 15 KiB

586
component/framedata.go Normal file
View File

@ -0,0 +1,586 @@
package component
import (
"image"
"code.rocketnine.space/tslocum/boxbrawl/asset"
)
// AllPlayerFrames defines all frame data for the game. Frames are defined in reverse order.
var AllPlayerFrames = [][][]FrameData{
{ // ActionIdle
{
stdHit(asset.FrameAt(asset.ImgPlayer, 0, 0)),
},
{
stdHit(asset.FrameAt(asset.ImgPlayer, 1, 0)),
},
{
stdHit(asset.FrameAt(asset.ImgPlayer, 2, 0)),
},
{
stdHit(asset.FrameAt(asset.ImgPlayer, 3, 0)),
},
{
stdHit(asset.FrameAt(asset.ImgPlayer, 4, 0)),
},
{
stdHit(asset.FrameAt(asset.ImgPlayer, 5, 0)),
},
{
stdHit(asset.FrameAt(asset.ImgPlayer, 6, 0)),
},
{
stdHit(asset.FrameAt(asset.ImgPlayer, 7, 0)),
},
{
stdHit(asset.FrameAt(asset.ImgPlayer, 8, 0)),
},
{
stdHit(asset.FrameAt(asset.ImgPlayer, 9, 0)),
},
{
stdHit(asset.FrameAt(asset.ImgPlayer, 10, 0)),
},
{
stdHit(asset.FrameAt(asset.ImgPlayer, 11, 0)),
},
{
stdHit(asset.FrameAt(asset.ImgPlayer, 12, 0)),
},
{
stdHit(asset.FrameAt(asset.ImgPlayer, 13, 0)),
},
{
stdHit(asset.FrameAt(asset.ImgPlayer, 14, 0)),
},
{
stdHit(asset.FrameAt(asset.ImgPlayer, 15, 0)),
},
{
stdHit(asset.FrameAt(asset.ImgPlayer, 16, 0)),
},
{
stdHit(asset.FrameAt(asset.ImgPlayer, 17, 0)),
},
{
stdHit(asset.FrameAt(asset.ImgPlayer, 18, 0)),
},
{
stdHit(asset.FrameAt(asset.ImgPlayer, 19, 0)),
},
{
stdHit(asset.FrameAt(asset.ImgPlayer, 20, 0)),
},
{
stdHit(asset.FrameAt(asset.ImgPlayer, 21, 0)),
},
{
stdHit(asset.FrameAt(asset.ImgPlayer, 22, 0)),
},
{
stdHit(asset.FrameAt(asset.ImgPlayer, 23, 0)),
},
{
stdHit(asset.FrameAt(asset.ImgPlayer, 24, 0)),
},
{
stdHit(asset.FrameAt(asset.ImgPlayer, 25, 0)),
},
{
stdHit(asset.FrameAt(asset.ImgPlayer, 26, 0)),
},
{
stdHit(asset.FrameAt(asset.ImgPlayer, 27, 0)),
},
}, { // ActionStunned
{
FrameData{
T: HitboxNone,
R: image.Rect(0, 0, 0, 0),
S: asset.FrameAt(asset.ImgPlayer, 0, 2),
},
},
}, { // ActionBlock
{
// TODO
},
}, { // ActionPunch
{
{
T: HitboxNormal,
R: image.Rect(0, 0, PlayerSize, PlayerSize),
S: asset.FrameAt(asset.ImgPlayer, 12, 1),
},
{
T: HitboxHurt,
R: image.Rect(-5, -5, PlayerSize+10, PlayerSize+10),
},
},
{
stdHit(asset.FrameAt(asset.ImgPlayer, 11, 1)),
},
{
stdHit(asset.FrameAt(asset.ImgPlayer, 10, 1)),
},
{
stdHit(asset.FrameAt(asset.ImgPlayer, 9, 1)),
},
{
stdHit(asset.FrameAt(asset.ImgPlayer, 8, 1)),
},
{
stdHit(asset.FrameAt(asset.ImgPlayer, 7, 1)),
},
{
stdHit(asset.FrameAt(asset.ImgPlayer, 6, 1)),
},
{
stdHit(asset.FrameAt(asset.ImgPlayer, 5, 1)),
},
{
stdHit(asset.FrameAt(asset.ImgPlayer, 4, 1)),
},
{
stdHit(asset.FrameAt(asset.ImgPlayer, 3, 1)),
},
{
stdHit(asset.FrameAt(asset.ImgPlayer, 2, 1)),
},
{
stdHit(asset.FrameAt(asset.ImgPlayer, 1, 1)),
},
{
stdHit(asset.FrameAt(asset.ImgPlayer, 0, 1)),
},
}, { // ActionTaunt1
{
stdHit(asset.FrameAt(asset.ImgPlayer, 28, 4)),
FrameData{
G: 15,
},
}, {
stdHit(asset.FrameAt(asset.ImgPlayer, 27, 4)),
}, {
stdHit(asset.FrameAt(asset.ImgPlayer, 26, 4)),
}, {
stdHit(asset.FrameAt(asset.ImgPlayer, 25, 4)),
}, {
stdHit(asset.FrameAt(asset.ImgPlayer, 24, 4)),
}, {
stdHit(asset.FrameAt(asset.ImgPlayer, 23, 4)),
}, {
stdHit(asset.FrameAt(asset.ImgPlayer, 22, 4)),
}, {
stdHit(asset.FrameAt(asset.ImgPlayer, 21, 4)),
}, {
stdHit(asset.FrameAt(asset.ImgPlayer, 20, 4)),
}, {
stdHit(asset.FrameAt(asset.ImgPlayer, 19, 4)),
}, {
stdHit(asset.FrameAt(asset.ImgPlayer, 18, 4)),
}, {
stdHit(asset.FrameAt(asset.ImgPlayer, 17, 4)),
}, {
stdHit(asset.FrameAt(asset.ImgPlayer, 16, 4)),
}, {
stdHit(asset.FrameAt(asset.ImgPlayer, 15, 4)),
}, {
stdHit(asset.FrameAt(asset.ImgPlayer, 14, 4)),
}, {
stdHit(asset.FrameAt(asset.ImgPlayer, 13, 4)),
}, {
stdHit(asset.FrameAt(asset.ImgPlayer, 12, 4)),
}, {
stdHit(asset.FrameAt(asset.ImgPlayer, 11, 4)),
}, {
stdHit(asset.FrameAt(asset.ImgPlayer, 10, 4)),
}, {
stdHit(asset.FrameAt(asset.ImgPlayer, 9, 4)),
}, {
stdHit(asset.FrameAt(asset.ImgPlayer, 8, 4)),
}, {
stdHit(asset.FrameAt(asset.ImgPlayer, 7, 4)),
}, {
stdHit(asset.FrameAt(asset.ImgPlayer, 6, 4)),
}, {
stdHit(asset.FrameAt(asset.ImgPlayer, 5, 4)),
}, {
stdHit(asset.FrameAt(asset.ImgPlayer, 4, 4)),
}, {
stdHit(asset.FrameAt(asset.ImgPlayer, 3, 4)),
}, {
stdHit(asset.FrameAt(asset.ImgPlayer, 2, 4)),
}, {
stdHit(asset.FrameAt(asset.ImgPlayer, 1, 4)),
}, {
stdHit(asset.FrameAt(asset.ImgPlayer, 0, 4)),
}, {
stdHit(asset.FrameAt(asset.ImgPlayer, 14, 3)),
}, {
stdHit(asset.FrameAt(asset.ImgPlayer, 13, 3)),
}, {
stdHit(asset.FrameAt(asset.ImgPlayer, 12, 3)),
}, {
stdHit(asset.FrameAt(asset.ImgPlayer, 11, 3)),
}, {
stdHit(asset.FrameAt(asset.ImgPlayer, 10, 3)),
}, {
stdHit(asset.FrameAt(asset.ImgPlayer, 9, 3)),
}, {
stdHit(asset.FrameAt(asset.ImgPlayer, 8, 3)),
}, {
stdHit(asset.FrameAt(asset.ImgPlayer, 7, 3)),
}, {
stdHit(asset.FrameAt(asset.ImgPlayer, 6, 3)),
}, {
stdHit(asset.FrameAt(asset.ImgPlayer, 5, 3)),
}, {
stdHit(asset.FrameAt(asset.ImgPlayer, 4, 3)),
}, {
stdHit(asset.FrameAt(asset.ImgPlayer, 3, 3)),
}, {
stdHit(asset.FrameAt(asset.ImgPlayer, 2, 3)),
}, {
stdHit(asset.FrameAt(asset.ImgPlayer, 1, 3)),
}, {
stdHit(asset.FrameAt(asset.ImgPlayer, 0, 3)),
},
}, { // ActionTaunt2
{
stdHit(asset.FrameAt(asset.ImgPlayer, 14, 6)),
FrameData{
G: 41,
},
stdHit(asset.FrameAt(asset.ImgPlayer, 13, 6)),
}, {
stdHit(asset.FrameAt(asset.ImgPlayer, 12, 6)),
}, {
stdHit(asset.FrameAt(asset.ImgPlayer, 11, 6)),
}, {
stdHit(asset.FrameAt(asset.ImgPlayer, 10, 6)),
}, {
stdHit(asset.FrameAt(asset.ImgPlayer, 9, 6)),
}, {
stdHit(asset.FrameAt(asset.ImgPlayer, 8, 6)),
}, {
stdHit(asset.FrameAt(asset.ImgPlayer, 7, 6)),
}, {
stdHit(asset.FrameAt(asset.ImgPlayer, 6, 6)),
}, {
stdHit(asset.FrameAt(asset.ImgPlayer, 5, 6)),
}, {
stdHit(asset.FrameAt(asset.ImgPlayer, 4, 6)),
}, {
stdHit(asset.FrameAt(asset.ImgPlayer, 3, 6)),
}, {
stdHit(asset.FrameAt(asset.ImgPlayer, 2, 6)),
}, {
stdHit(asset.FrameAt(asset.ImgPlayer, 1, 6)),
}, {
stdHit(asset.FrameAt(asset.ImgPlayer, 0, 6)),
}, {
stdHit(asset.FrameAt(asset.ImgPlayer, 40, 5)),
}, {
stdHit(asset.FrameAt(asset.ImgPlayer, 39, 5)),
}, {
stdHit(asset.FrameAt(asset.ImgPlayer, 38, 5)),
}, {
stdHit(asset.FrameAt(asset.ImgPlayer, 37, 5)),
}, {
stdHit(asset.FrameAt(asset.ImgPlayer, 36, 5)),
}, {
stdHit(asset.FrameAt(asset.ImgPlayer, 35, 5)),
}, {
stdHit(asset.FrameAt(asset.ImgPlayer, 34, 5)),
}, {
stdHit(asset.FrameAt(asset.ImgPlayer, 33, 5)),
}, {
stdHit(asset.FrameAt(asset.ImgPlayer, 32, 5)),
}, {
stdHit(asset.FrameAt(asset.ImgPlayer, 31, 5)),
}, {
stdHit(asset.FrameAt(asset.ImgPlayer, 30, 5)),
}, {
stdHit(asset.FrameAt(asset.ImgPlayer, 29, 5)),
}, {
stdHit(asset.FrameAt(asset.ImgPlayer, 28, 5)),
}, {
stdHit(asset.FrameAt(asset.ImgPlayer, 27, 5)),
}, {
stdHit(asset.FrameAt(asset.ImgPlayer, 26, 5)),
}, {
stdHit(asset.FrameAt(asset.ImgPlayer, 25, 5)),
}, {
stdHit(asset.FrameAt(asset.ImgPlayer, 24, 5)),
}, {
stdHit(asset.FrameAt(asset.ImgPlayer, 23, 5)),
}, {
stdHit(asset.FrameAt(asset.ImgPlayer, 22, 5)),
}, {
stdHit(asset.FrameAt(asset.ImgPlayer, 21, 5)),
}, {
stdHit(asset.FrameAt(asset.ImgPlayer, 20, 5)),
}, {
stdHit(asset.FrameAt(asset.ImgPlayer, 19, 5)),
}, {
stdHit(asset.FrameAt(asset.ImgPlayer, 18, 5)),
}, {
stdHit(asset.FrameAt(asset.ImgPlayer, 17, 5)),
}, {
stdHit(asset.FrameAt(asset.ImgPlayer, 16, 5)),
}, {
stdHit(asset.FrameAt(asset.ImgPlayer, 15, 5)),
}, {
stdHit(asset.FrameAt(asset.ImgPlayer, 14, 5)),
}, {
stdHit(asset.FrameAt(asset.ImgPlayer, 13, 5)),
}, {
stdHit(asset.FrameAt(asset.ImgPlayer, 12, 5)),
}, {
stdHit(asset.FrameAt(asset.ImgPlayer, 11, 5)),
}, {
stdHit(asset.FrameAt(asset.ImgPlayer, 10, 5)),
}, {
stdHit(asset.FrameAt(asset.ImgPlayer, 9, 5)),
}, {
stdHit(asset.FrameAt(asset.ImgPlayer, 8, 5)),
}, {
stdHit(asset.FrameAt(asset.ImgPlayer, 7, 5)),
}, {
stdHit(asset.FrameAt(asset.ImgPlayer, 6, 5)),
}, {
stdHit(asset.FrameAt(asset.ImgPlayer, 5, 5)),
}, {
stdHit(asset.FrameAt(asset.ImgPlayer, 4, 5)),
}, {
stdHit(asset.FrameAt(asset.ImgPlayer, 3, 5)),
}, {
stdHit(asset.FrameAt(asset.ImgPlayer, 2, 5)),
}, {
stdHit(asset.FrameAt(asset.ImgPlayer, 1, 5)),
}, {
stdHit(asset.FrameAt(asset.ImgPlayer, 0, 5)),
},
}, { // ActionTaunt3
{
stdHit(asset.FrameAt(asset.ImgPlayer, 22, 8)),
FrameData{
G: 19,
},
}, {
stdHit(asset.FrameAt(asset.ImgPlayer, 21, 8)),
}, {
stdHit(asset.FrameAt(asset.ImgPlayer, 20, 8)),
}, {
stdHit(asset.FrameAt(asset.ImgPlayer, 19, 8)),
}, {
stdHit(asset.FrameAt(asset.ImgPlayer, 18, 8)),
}, {
stdHit(asset.FrameAt(asset.ImgPlayer, 17, 8)),
}, {
stdHit(asset.FrameAt(asset.ImgPlayer, 16, 8)),
}, {
stdHit(asset.FrameAt(asset.ImgPlayer, 15, 8)),
}, {
stdHit(asset.FrameAt(asset.ImgPlayer, 14, 8)),
}, {
stdHit(asset.FrameAt(asset.ImgPlayer, 13, 8)),
}, {
stdHit(asset.FrameAt(asset.ImgPlayer, 12, 8)),
}, {
stdHit(asset.FrameAt(asset.ImgPlayer, 11, 8)),
}, {
stdHit(asset.FrameAt(asset.ImgPlayer, 10, 8)),
}, {
stdHit(asset.FrameAt(asset.ImgPlayer, 9, 8)),
}, {
stdHit(asset.FrameAt(asset.ImgPlayer, 8, 8)),
}, {
stdHit(asset.FrameAt(asset.ImgPlayer, 7, 8)),
}, {
stdHit(asset.FrameAt(asset.ImgPlayer, 6, 8)),
}, {
stdHit(asset.FrameAt(asset.ImgPlayer, 5, 8)),
}, {
stdHit(asset.FrameAt(asset.ImgPlayer, 4, 8)),
}, {
stdHit(asset.FrameAt(asset.ImgPlayer, 3, 8)),
}, {
stdHit(asset.FrameAt(asset.ImgPlayer, 2, 8)),
}, {
stdHit(asset.FrameAt(asset.ImgPlayer, 1, 8)),
}, {
stdHit(asset.FrameAt(asset.ImgPlayer, 0, 8)),
}, {
stdHit(asset.FrameAt(asset.ImgPlayer, 18, 7)),
}, {
stdHit(asset.FrameAt(asset.ImgPlayer, 17, 7)),
}, {
stdHit(asset.FrameAt(asset.ImgPlayer, 16, 7)),
}, {
stdHit(asset.FrameAt(asset.ImgPlayer, 15, 7)),
}, {
stdHit(asset.FrameAt(asset.ImgPlayer, 14, 7)),
}, {
stdHit(asset.FrameAt(asset.ImgPlayer, 13, 7)),
}, {
stdHit(asset.FrameAt(asset.ImgPlayer, 12, 7)),
}, {
stdHit(asset.FrameAt(asset.ImgPlayer, 11, 7)),
}, {
stdHit(asset.FrameAt(asset.ImgPlayer, 10, 7)),
}, {
stdHit(asset.FrameAt(asset.ImgPlayer, 9, 7)),
}, {
stdHit(asset.FrameAt(asset.ImgPlayer, 8, 7)),
}, {
stdHit(asset.FrameAt(asset.ImgPlayer, 7, 7)),
}, {
stdHit(asset.FrameAt(asset.ImgPlayer, 6, 7)),
}, {
stdHit(asset.FrameAt(asset.ImgPlayer, 5, 7)),
}, {
stdHit(asset.FrameAt(asset.ImgPlayer, 4, 7)),
}, {
stdHit(asset.FrameAt(asset.ImgPlayer, 3, 7)),
}, {
stdHit(asset.FrameAt(asset.ImgPlayer, 2, 7)),
}, {
stdHit(asset.FrameAt(asset.ImgPlayer, 1, 7)),
}, {
stdHit(asset.FrameAt(asset.ImgPlayer, 0, 7)),
},
}, { // ActionTaunt4
{
stdHit(asset.FrameAt(asset.ImgPlayer, 27, 10)),
FrameData{
G: 35,
},
}, {
stdHit(asset.FrameAt(asset.ImgPlayer, 26, 10)),
}, {
stdHit(asset.FrameAt(asset.ImgPlayer, 25, 10)),
}, {
stdHit(asset.FrameAt(asset.ImgPlayer, 24, 10)),
}, {
stdHit(asset.FrameAt(asset.ImgPlayer, 23, 10)),
}, {
stdHit(asset.FrameAt(asset.ImgPlayer, 22, 10)),
}, {
stdHit(asset.FrameAt(asset.ImgPlayer, 21, 10)),
}, {
stdHit(asset.FrameAt(asset.ImgPlayer, 20, 10)),
}, {
stdHit(asset.FrameAt(asset.ImgPlayer, 19, 10)),
}, {
stdHit(asset.FrameAt(asset.ImgPlayer, 18, 10)),
}, {
stdHit(asset.FrameAt(asset.ImgPlayer, 17, 10)),
}, {
stdHit(asset.FrameAt(asset.ImgPlayer, 16, 10)),
}, {
stdHit(asset.FrameAt(asset.ImgPlayer, 15, 10)),
}, {
stdHit(asset.FrameAt(asset.ImgPlayer, 14, 10)),
}, {
stdHit(asset.FrameAt(asset.ImgPlayer, 13, 10)),
}, {
stdHit(asset.FrameAt(asset.ImgPlayer, 12, 10)),
}, {
stdHit(asset.FrameAt(asset.ImgPlayer, 11, 10)),
}, {
stdHit(asset.FrameAt(asset.ImgPlayer, 10, 10)),
}, {
stdHit(asset.FrameAt(asset.ImgPlayer, 9, 10)),
}, {
stdHit(asset.FrameAt(asset.ImgPlayer, 8, 10)),
}, {
stdHit(asset.FrameAt(asset.ImgPlayer, 7, 10)),
}, {
stdHit(asset.FrameAt(asset.ImgPlayer, 6, 10)),
}, {
stdHit(asset.FrameAt(asset.ImgPlayer, 5, 10)),
}, {
stdHit(asset.FrameAt(asset.ImgPlayer, 4, 10)),
}, {
stdHit(asset.FrameAt(asset.ImgPlayer, 3, 10)),
}, {
stdHit(asset.FrameAt(asset.ImgPlayer, 2, 10)),
}, {
stdHit(asset.FrameAt(asset.ImgPlayer, 1, 10)),
}, {
stdHit(asset.FrameAt(asset.ImgPlayer, 0, 10)),
}, {
stdHit(asset.FrameAt(asset.ImgPlayer, 34, 9)),
}, {
stdHit(asset.FrameAt(asset.ImgPlayer, 33, 9)),
}, {
stdHit(asset.FrameAt(asset.ImgPlayer, 32, 9)),
}, {
stdHit(asset.FrameAt(asset.ImgPlayer, 31, 9)),
}, {
stdHit(asset.FrameAt(asset.ImgPlayer, 30, 9)),
}, {
stdHit(asset.FrameAt(asset.ImgPlayer, 29, 9)),
}, {
stdHit(asset.FrameAt(asset.ImgPlayer, 28, 9)),
}, {
stdHit(asset.FrameAt(asset.ImgPlayer, 27, 9)),
}, {
stdHit(asset.FrameAt(asset.ImgPlayer, 26, 9)),
}, {
stdHit(asset.FrameAt(asset.ImgPlayer, 25, 9)),
}, {
stdHit(asset.FrameAt(asset.ImgPlayer, 24, 9)),
}, {
stdHit(asset.FrameAt(asset.ImgPlayer, 23, 9)),
}, {
stdHit(asset.FrameAt(asset.ImgPlayer, 22, 9)),
}, {
stdHit(asset.FrameAt(asset.ImgPlayer, 21, 9)),
}, {
stdHit(asset.FrameAt(asset.ImgPlayer, 20, 9)),
}, {
stdHit(asset.FrameAt(asset.ImgPlayer, 19, 9)),
}, {
stdHit(asset.FrameAt(asset.ImgPlayer, 18, 9)),
}, {
stdHit(asset.FrameAt(asset.ImgPlayer, 17, 9)),
}, {
stdHit(asset.FrameAt(asset.ImgPlayer, 16, 9)),
}, {
stdHit(asset.FrameAt(asset.ImgPlayer, 15, 9)),
}, {
stdHit(asset.FrameAt(asset.ImgPlayer, 14, 9)),
}, {
stdHit(asset.FrameAt(asset.ImgPlayer, 13, 9)),
}, {
stdHit(asset.FrameAt(asset.ImgPlayer, 12, 9)),
}, {
stdHit(asset.FrameAt(asset.ImgPlayer, 11, 9)),
}, {
stdHit(asset.FrameAt(asset.ImgPlayer, 10, 9)),
}, {
stdHit(asset.FrameAt(asset.ImgPlayer, 9, 9)),
}, {
stdHit(asset.FrameAt(asset.ImgPlayer, 8, 9)),
}, {
stdHit(asset.FrameAt(asset.ImgPlayer, 7, 9)),
}, {
stdHit(asset.FrameAt(asset.ImgPlayer, 6, 9)),
}, {
stdHit(asset.FrameAt(asset.ImgPlayer, 5, 9)),
}, {
stdHit(asset.FrameAt(asset.ImgPlayer, 4, 9)),
}, {
stdHit(asset.FrameAt(asset.ImgPlayer, 3, 9)),
}, {
stdHit(asset.FrameAt(asset.ImgPlayer, 2, 9)),
}, {
stdHit(asset.FrameAt(asset.ImgPlayer, 1, 9)),
}, {
stdHit(asset.FrameAt(asset.ImgPlayer, 0, 9)),
},
},
}

View File

@ -17,6 +17,10 @@ const (
ActionStunned
ActionBlock
ActionPunch
ActionTaunt1
ActionTaunt2
ActionTaunt3
ActionTaunt4
)
type HitboxType int
@ -28,9 +32,10 @@ const (
)
type FrameData struct {
T HitboxType
R image.Rectangle
S *ebiten.Image
T HitboxType // Type
R image.Rectangle // Rect
S *ebiten.Image // Sprite
G int // Go to frame (for looping actions)
}
const PlayerSize = 16
@ -55,154 +60,13 @@ func stdHit(sprite *ebiten.Image) FrameData {
}
}
// AllPlayerFrames defines all frame data for the game. Frames are defined in reverse order.
var AllPlayerFrames = [][][]FrameData{
{ // ActionIdle
{
stdHit(asset.FrameAt(asset.ImgPlayer, 0, 0)),
},
{
stdHit(asset.FrameAt(asset.ImgPlayer, 1, 0)),
},
{
stdHit(asset.FrameAt(asset.ImgPlayer, 2, 0)),
},
{
stdHit(asset.FrameAt(asset.ImgPlayer, 3, 0)),
},
{
stdHit(asset.FrameAt(asset.ImgPlayer, 4, 0)),
},
{
stdHit(asset.FrameAt(asset.ImgPlayer, 5, 0)),
},
{
stdHit(asset.FrameAt(asset.ImgPlayer, 6, 0)),
},
{
stdHit(asset.FrameAt(asset.ImgPlayer, 7, 0)),
},
{
stdHit(asset.FrameAt(asset.ImgPlayer, 8, 0)),
},
{
stdHit(asset.FrameAt(asset.ImgPlayer, 9, 0)),
},
{
stdHit(asset.FrameAt(asset.ImgPlayer, 10, 0)),
},
{
stdHit(asset.FrameAt(asset.ImgPlayer, 11, 0)),
},
{
stdHit(asset.FrameAt(asset.ImgPlayer, 12, 0)),
},
{
stdHit(asset.FrameAt(asset.ImgPlayer, 13, 0)),
},
{
stdHit(asset.FrameAt(asset.ImgPlayer, 14, 0)),
},
{
stdHit(asset.FrameAt(asset.ImgPlayer, 15, 0)),
},
{
stdHit(asset.FrameAt(asset.ImgPlayer, 16, 0)),
},
{
stdHit(asset.FrameAt(asset.ImgPlayer, 17, 0)),
},
{
stdHit(asset.FrameAt(asset.ImgPlayer, 18, 0)),
},
{
stdHit(asset.FrameAt(asset.ImgPlayer, 19, 0)),
},
{
stdHit(asset.FrameAt(asset.ImgPlayer, 20, 0)),
},
{
stdHit(asset.FrameAt(asset.ImgPlayer, 21, 0)),
},
{
stdHit(asset.FrameAt(asset.ImgPlayer, 22, 0)),
},
{
stdHit(asset.FrameAt(asset.ImgPlayer, 23, 0)),
},
{
stdHit(asset.FrameAt(asset.ImgPlayer, 24, 0)),
},
{
stdHit(asset.FrameAt(asset.ImgPlayer, 25, 0)),
},
{
stdHit(asset.FrameAt(asset.ImgPlayer, 26, 0)),
},
{
stdHit(asset.FrameAt(asset.ImgPlayer, 27, 0)),
},
}, { // ActionStunned
{
FrameData{
T: HitboxNone,
R: image.Rect(0, 0, 0, 0),
S: asset.FrameAt(asset.ImgPlayer, 0, 2),
},
},
}, { // ActionBlock
{
// TODO
},
}, { // ActionPunch
{
{
T: HitboxNormal,
R: image.Rect(0, 0, PlayerSize, PlayerSize),
S: asset.FrameAt(asset.ImgPlayer, 12, 1),
},
{
T: HitboxHurt,
R: image.Rect(-5, -5, PlayerSize+10, PlayerSize+10),
},
},
{
stdHit(asset.FrameAt(asset.ImgPlayer, 11, 1)),
},
{
stdHit(asset.FrameAt(asset.ImgPlayer, 10, 1)),
},
{
stdHit(asset.FrameAt(asset.ImgPlayer, 9, 1)),
},
{
stdHit(asset.FrameAt(asset.ImgPlayer, 8, 1)),
},
{
stdHit(asset.FrameAt(asset.ImgPlayer, 7, 1)),
},
{
stdHit(asset.FrameAt(asset.ImgPlayer, 6, 1)),
},
{
stdHit(asset.FrameAt(asset.ImgPlayer, 5, 1)),
},
{
stdHit(asset.FrameAt(asset.ImgPlayer, 4, 1)),
},
{
stdHit(asset.FrameAt(asset.ImgPlayer, 3, 1)),
},
{
stdHit(asset.FrameAt(asset.ImgPlayer, 2, 1)),
},
{
stdHit(asset.FrameAt(asset.ImgPlayer, 1, 1)),
},
{
stdHit(asset.FrameAt(asset.ImgPlayer, 0, 1)),
},
},
// stdHitRange returns FrameData using a standard hitbox and the provided sprite range.
func stdHitRange(sprite *ebiten.Image, spriteX int, spriteY int, size int) []FrameData {
data := make([]FrameData, size)
for i := 0; i < size; i++ {
data[i] = stdHit(asset.FrameAt(asset.ImgPlayer, spriteX+i, spriteY))
}
return data
}
func FrameDataForActionTick(a PlayerAction, tick int) []FrameData {
@ -236,6 +100,10 @@ type Player struct {
Action PlayerAction
ActionTicksLeft int
NoPunch bool
PlayAgain bool
}
func (p *Player) String() string {

View File

@ -2,7 +2,6 @@ package game
import (
"crypto/sha1"
"image"
"image/color"
"log"
"math"
@ -27,31 +26,16 @@ const (
type Game struct {
Players []component.Player
Winner int
}
var addedGame bool
func NewGame() (*Game, error) {
player1 := component.Player{
PlayerNum: 1,
Color: color.RGBA{255, 0, 0, 255},
Action: component.ActionIdle,
ActionTicksLeft: len(component.AllPlayerFrames[component.ActionIdle]),
X: -playerSpawnGap / 2,
Y: 0,
}
player2 := component.Player{
PlayerNum: 2,
Color: color.RGBA{0, 0, 255, 255},
Action: component.ActionIdle,
ActionTicksLeft: len(component.AllPlayerFrames[component.ActionIdle]),
X: playerSpawnGap / 2,
Y: 0,
}
g := &Game{
Players: []component.Player{player1, player2},
Players: make([]component.Player, 2),
}
g.reset()
if !addedGame {
entity.NewOnceEntity()
@ -75,6 +59,28 @@ func (g *Game) clone() (result *Game) {
return
}
func (g *Game) reset() {
g.Players[0] = component.Player{
PlayerNum: 1,
Color: color.RGBA{255, 0, 0, 255},
Action: component.ActionIdle,
ActionTicksLeft: len(component.AllPlayerFrames[component.ActionIdle]),
X: -playerSpawnGap - component.PlayerWidth,
Y: 0,
}
g.Players[1] = component.Player{
PlayerNum: 2,
Color: color.RGBA{0, 0, 255, 255},
Action: component.ActionIdle,
ActionTicksLeft: len(component.AllPlayerFrames[component.ActionIdle]),
X: playerSpawnGap,
Y: 0,
}
g.Winner = 0
}
func (g *Game) Layout(_, _ int) (screenWidth, screenHeight int) {
// Maintain constant internal resolution.
if world.InternalScreenWidth != world.ScreenWidth || world.InternalScreenHeight != world.ScreenHeight {
@ -173,7 +179,6 @@ func (g *Game) InitNetworking(localPort int, numPlayers int, players []ggpo.Play
log.Fatalf("failed to add player: %s", err)
}
if players[i].PlayerType == ggpo.PlayerTypeLocal {
world.CurrentPlayer = int(handle)
err = peer.SetFrameDelay(handle, frameDelay)
if err != nil {
log.Fatalf("failed to set frame delay: %s", err)
@ -198,15 +203,19 @@ func (g *Game) ReadInputs() InputBits {
in.setButton(ButtonRight)
}
if inpututil.IsKeyJustPressed(ebiten.KeyH) {
if ebiten.IsKeyPressed(ebiten.KeyH) {
in.setButton(ButtonPunch)
}
return in
}
if ebiten.IsKeyPressed(ebiten.KeyL) {
in.setButton(ButtonTaunt)
}
var physicsRects = []image.Rectangle{
image.Rect(-world.GroundWidth/2, 0, world.GroundWidth/2, -world.GroundHeight),
if ebiten.IsKeyPressed(ebiten.KeyEnter) {
in.setButton(ButtonStart)
}
return in
}
func (g *Game) applyPhysics() {
@ -221,63 +230,74 @@ func (g *Game) applyPhysics() {
playerRect := world.FloatRect(g.Players[i].X, g.Players[i].Y, g.Players[i].X+float64(component.PlayerSize), g.Players[i].Y+float64(component.PlayerSize))
oppRect := world.FloatRect(g.Players[opp].X, g.Players[opp].Y, g.Players[opp].X+float64(component.PlayerSize), g.Players[opp].Y+float64(component.PlayerSize))
isGrounded := func() (r image.Rectangle, ok bool) {
for _, physRect := range physicsRects {
if component.RectTouches(playerRect, physRect) {
return physRect, true
}
// Apply ground collision.
var (
collideXY = -1
collideX = -1
collideY = -1
collideG = -1
)
for j, physRect := range world.PhysicsRects {
if physRect.Overlaps(playerRect) {
collideXY = j
collideX = j
collideY = j
}
if physRect.Overlaps(component.TranslateRect(playerRect, int(p.VX), int(p.VY))) {
collideXY = j
}
if physRect.Overlaps(component.TranslateRect(playerRect, int(p.VX), 0)) {
collideX = j
}
if physRect.Overlaps(component.TranslateRect(playerRect, 0, int(p.VY))) {
collideY = j
}
if physRect.Overlaps(component.TranslateRect(playerRect, 0, -1)) {
collideG = j
}
return image.Rectangle{}, false
}
// Apply velocity.
p.X, p.Y = p.X+p.VX, p.Y+p.VY
// Apply ground collision.
groundRect, grounded := isGrounded()
if grounded {
// Min is left, Max is right
collideX := p.X+component.PlayerWidth >= float64(groundRect.Min.X) && p.X <= float64(groundRect.Max.X)
// Min is bottom, Max is top
collideY := p.Y-component.PlayerHeight >= float64(groundRect.Min.Y) && p.Y <= float64(groundRect.Max.Y)
log.Println(world.CurrentPlayer, collideX, collideY)
if collideY {
/*if collideX {
if p.X+component.PlayerWidth >= float64(groundRect.Min.X) {
p.X = float64(groundRect.Min.X) - component.PlayerWidth
} else {
p.X = float64(groundRect.Max.X)
}
}*/
if collideY {
topDist := p.Y - float64(groundRect.Max.Y)
bottomDist := p.Y - component.PlayerHeight - float64(groundRect.Min.Y)
if math.Abs(topDist) < math.Abs(bottomDist) { // Closer to top.
p.Y = float64(groundRect.Max.Y)
} else { // Closer to bottom.
p.Y = float64(groundRect.Min.Y) + component.PlayerHeight
}
p.VY = 0
}
}
} else if p.VY > -world.Gravity { // Apply gravity.
if collideG == -1 && p.VY > -world.Gravity {
p.VY -= math.Max(math.Abs(p.VY/2.5), 0.1)
if p.VY < -world.Gravity {
p.VY = -world.Gravity
}
}
if p.VY != 0 {
log.Println("VY", world.CurrentPlayer, p.VY)
if collideXY == -1 {
p.X, p.Y = p.X+p.VX, p.Y+p.VY
} else if collideX == -1 {
p.X = p.X + p.VX
p.VY = 0
} else if collideY == -1 {
p.Y = p.Y + p.VY
p.VX = 0
} else {
p.VX, p.VY = 0, 0
}
/*if grounded {
log.Println("grounded")
p.VY = 0 // TODO
}*/
if collideX != -1 && collideY != -1 {
collideRect := world.PhysicsRects[collideX]
leftDist := p.X + component.PlayerWidth - float64(collideRect.Min.X)
rightDist := p.X - float64(collideRect.Max.X)
if leftDist < rightDist { // Closer to left.
p.X = float64(collideRect.Min.X) - component.PlayerWidth
} else { // Closer to right.
p.X = float64(collideRect.Max.X)
}
bottomDist := p.Y - component.PlayerHeight - float64(collideRect.Min.Y)
topDist := p.Y - float64(collideRect.Max.Y)
if bottomDist < topDist { // Closer to bottom.
p.Y = float64(collideRect.Min.Y) - component.PlayerHeight
} else { // Closer to top.
p.Y = float64(collideRect.Max.Y)
}
}
// Apply player collision.
if playerRect.Overlaps(oppRect) {
@ -287,6 +307,10 @@ func (g *Game) applyPhysics() {
p.X = o.X + component.PlayerSize
}
}
if g.Winner == 0 && p.Y < -world.GroundHeight {
g.Winner = o.PlayerNum
}
}
}
@ -316,9 +340,15 @@ func (g *Game) UpdateByInputs(inputs []InputBits) {
g.Players[i].VX = g.Players[i].VX * 0.8
g.Players[i].VY = g.Players[i].VY * 0.8
if player.Action != component.ActionStunned {
if g.Players[i].Action == component.ActionIdle {
if input.isButtonOn(ButtonUp) && !component.TranslateRect(playerRect, 0, -1).Overlaps(oppRect) {
grounded := g.Players[i].Y > -world.FloatValueThreshold && g.Players[i].Y < world.FloatValueThreshold
var grounded bool
for _, physRect := range world.PhysicsRects {
if g.Players[i].Y < float64(physRect.Max.Y)+world.FloatValueThreshold && g.Players[i].Y > float64(physRect.Max.Y)-world.FloatValueThreshold {
grounded = true
break
}
}
if grounded {
g.Players[i].VY = world.JumpVelocity
}
@ -334,12 +364,32 @@ func (g *Game) UpdateByInputs(inputs []InputBits) {
g.Players[i].VX = 1
}
if g.Players[i].Action == component.ActionIdle {
if input.isButtonOn(ButtonPunch) {
if input.isButtonOn(ButtonPunch) {
if !g.Players[i].NoPunch {
g.Players[i].Action = component.ActionPunch
g.Players[i].ActionTicksLeft = len(component.AllPlayerFrames[component.ActionPunch]) // TODO
g.Players[i].NoPunch = true
continue
}
} else if g.Players[i].NoPunch {
g.Players[i].NoPunch = false
}
if input.isButtonOn(ButtonTaunt) {
switch {
case input.isButtonOn(ButtonRight):
g.Players[i].Action = component.ActionTaunt2
case input.isButtonOn(ButtonDown):
g.Players[i].Action = component.ActionTaunt3
case input.isButtonOn(ButtonLeft):
g.Players[i].Action = component.ActionTaunt4
default: // ButtonUp or no direction specified
g.Players[i].Action = component.ActionTaunt1
}
g.Players[i].ActionTicksLeft = len(component.AllPlayerFrames[g.Players[i].Action])
continue
}
}
@ -349,8 +399,14 @@ func (g *Game) UpdateByInputs(inputs []InputBits) {
// TODO handle invulnerability and blocking
var goToFrame int
allFrameData := component.FrameDataForActionTick(g.Players[i].Action, g.Players[i].ActionTicksLeft)
for _, frame := range allFrameData {
if frame.G != 0 {
goToFrame = frame.G
}
frameRect := component.FlipRect(frame.R, playerFlipped)
// Apply hitbox.
@ -370,15 +426,27 @@ func (g *Game) UpdateByInputs(inputs []InputBits) {
}
}
}
if !input.isButtonOn(ButtonTaunt) {
goToFrame = 0
}
// Advance to the next frame.
g.Players[i].ActionTicksLeft--
if goToFrame != 0 {
// Handle frame jump.
g.Players[i].ActionTicksLeft = len(component.AllPlayerFrames[g.Players[i].Action]) - goToFrame
} else {
// Advance to the next frame.
g.Players[i].ActionTicksLeft--
}
if g.Players[i].ActionTicksLeft == 0 {
// Return to the idle action.
g.Players[i].Action = component.ActionIdle
g.Players[i].ActionTicksLeft = len(component.AllPlayerFrames[component.ActionIdle]) // TODO
}
}
if world.Winner != 0 && input.isButtonOn(ButtonStart) {
g.Players[i].PlayAgain = true
}
}
g.applyPhysics()
@ -392,7 +460,13 @@ func (g *Game) ReadInputsP2() InputBits {
}
func (g *Game) playerStateUpdated() {
if g.Winner != 0 && g.Players[0].PlayAgain && g.Players[1].PlayAgain {
g.reset()
}
world.Player1, world.Player2 = g.Players[0], g.Players[1]
world.Winner = g.Winner
}
func (g *Game) RunFrame() {

View File

@ -21,6 +21,8 @@ const (
ButtonDown
ButtonUp
ButtonPunch
ButtonTaunt
ButtonStart
)
func (i *InputBits) isButtonOn(button InputButton) bool {

View File

@ -1,7 +1,6 @@
package system
import (
"image"
"image/color"
"code.rocketnine.space/tslocum/boxbrawl/component"
@ -41,14 +40,18 @@ func (s *MapSystem) Draw(e gohan.Entity, screen *ebiten.Image) error {
groundColor := color.RGBA{50, 50, 50, 255}
r := image.Rect(-world.GroundWidth/2, -world.ScreenHeight, world.GroundWidth/2, 0)
const groundTopHeight = 10
//groundTopColor := color.RGBA{100, 100, 100, 255}
for _, r := range world.PhysicsRects {
screen.SubImage(world.GameRectToScreen(r)).(*ebiten.Image).Fill(groundColor)
}
/*r := image.Rect(-world.GroundWidth/2, -world.ScreenHeight, world.GroundWidth/2, 0)
screen.SubImage(world.GameRectToScreen(r)).(*ebiten.Image).Fill(groundColor)
const groundTopHeight = 10
groundTopColor := color.RGBA{100, 100, 100, 255}
r = image.Rect(-world.GroundWidth/2, -groundTopHeight, world.GroundWidth/2, 0)
screen.SubImage(world.GameRectToScreen(r)).(*ebiten.Image).Fill(groundTopColor)
screen.SubImage(world.GameRectToScreen(r)).(*ebiten.Image).Fill(groundTopColor)*/
return nil
}

View File

@ -38,6 +38,8 @@ type UISystem struct {
buffer *etk.Text
updateTicks int
gameOverImg *ebiten.Image
hitboxImg *ebiten.Image
}
@ -53,6 +55,8 @@ func (u *UISystem) initialize() {
etk.SetRoot(inputDemo)
etk.Layout(world.InternalScreenWidth, world.InternalScreenHeight)
u.gameOverImg = ebiten.NewImage(250, 100)
u.hitboxImg = ebiten.NewImage(32, 32)
u.initialized = true
@ -244,7 +248,44 @@ func (u *UISystem) Draw(e gohan.Entity, screen *ebiten.Image) error {
}
}
}
}
if world.Winner != 0 {
u.gameOverImg.Clear()
label := "YOU LOSE!"
if world.Winner == world.CurrentPlayer {
label = "YOU WIN!"
}
ebitenutil.DebugPrint(u.gameOverImg, label)
width := float64(len(label) * 24)
height := float64(64) * 2
op := &ebiten.DrawImageOptions{}
op.GeoM.Scale(4, 4)
op.GeoM.Translate(world.InternalScreenWidth/2-width/2, world.InternalScreenHeight/2-height/2)
screen.DrawImage(u.gameOverImg, op)
u.gameOverImg.Clear()
label = "PRESS ENTER OR START TO PLAY AGAIN"
p := world.Player1
if world.CurrentPlayer == 2 {
p = world.Player2
}
if p.PlayAgain {
label = "WAITING FOR OPPONENT..."
}
ebitenutil.DebugPrint(u.gameOverImg, label)
width = float64(len(label) * 12)
height = float64(32)
op.GeoM.Reset()
op.GeoM.Scale(2, 2)
op.GeoM.Translate(world.InternalScreenWidth/2-width/2, world.InternalScreenHeight/2+height/2)
screen.DrawImage(u.gameOverImg, op)
}
if world.Debug != 0 {

View File

@ -17,11 +17,11 @@ const (
Gravity = 3
JumpVelocity = 30
JumpVelocity = 20
MaxDebug = 2
FloatValueThreshold = 0.00000001
FloatValueThreshold = 1 // This is required because image.Rectangle uses integers
GroundWidth = 600
GroundHeight = 100
@ -48,16 +48,22 @@ var (
WASM bool
Player1 component.Player
Player2 component.Player
CurrentPlayer = 1
Backend ggpo.Backend
// These variables are cached to prevent race conditions.
Player1 component.Player
Player2 component.Player
Winner int
)
var TPSPresets = []int{1, 2, 4, 10, 30, 60, 120}
var PhysicsRects = []image.Rectangle{
image.Rect(-GroundWidth/2, 0, GroundWidth/2, -GroundHeight),
}
func GameCoordsToScreen(x, y float64) (int, int) {
return int(x) - CamX + (ScreenWidth / 2), -int(y) - CamY + (ScreenHeight - GroundHeight)
}