Add kick action

This commit is contained in:
Trevor Slocum 2023-01-30 15:49:05 -08:00
parent 361529de18
commit 0860c30cfd
7 changed files with 210 additions and 28 deletions

View File

@ -32,6 +32,36 @@ are bypassed, and port forwarding is usually not required.
Only multiplayer over a local network (whether truly local or virtual) has been
tested successfully.
#### Multiplayer guide
You and your opponent will need to choose a port on which you will accept UDP
traffic from the other person. This is referred to as your local port,
which can specified when playing Box Brawl using the `--local` argument.
In the following examples, user A has the IP address `1.1.1.1` and user B has
the IP address `2.2.2.2`. User A will listen for a connection on port `17000`.
User B will listen for a connection on port `19000`.
Simply replace the example IP addresses and ports with actual IP addresses and
ports, and run the command specified (depending on whether you are the host or
the guest).
User A (who has IP `1.1.1.1`) should run the following command:
```
boxbrawl --local 17000 --host 2.2.2.2:19000
```
User B (who has IP `2.2.2.2`) should run the following command:
```
boxbrawl --local 19000 --connect 1.1.1.1:17000
```
In the above commands, each user first specifies which port to listen for
connections from the opponent, then specifies the IP address and port where
their opponent is listening for connections.
### Compile
Install the dependencies listed for [your platform](https://github.com/hajimehoshi/ebiten/blob/main/README.md#platforms),

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

After

Width:  |  Height:  |  Size: 18 KiB

View File

@ -102,6 +102,39 @@ var AllPlayerFrames = [][][]FrameData{
},
},
}, { // ActionPunch
{
stdHit(asset.FrameAt(asset.ImgPlayer, 1, 1)),
},
{
stdHit(asset.FrameAt(asset.ImgPlayer, 2, 1)),
},
{
stdHit(asset.FrameAt(asset.ImgPlayer, 3, 1)),
},
{
stdHit(asset.FrameAt(asset.ImgPlayer, 4, 1)),
},
{
stdHit(asset.FrameAt(asset.ImgPlayer, 5, 1)),
},
{
stdHit(asset.FrameAt(asset.ImgPlayer, 6, 1)),
},
{
stdHit(asset.FrameAt(asset.ImgPlayer, 7, 1)),
},
{
stdHit(asset.FrameAt(asset.ImgPlayer, 8, 1)),
},
{
stdHit(asset.FrameAt(asset.ImgPlayer, 9, 1)),
},
{
stdHit(asset.FrameAt(asset.ImgPlayer, 10, 1)),
},
{
stdHit(asset.FrameAt(asset.ImgPlayer, 11, 1)),
},
{
{
T: HitboxNormal,
@ -151,7 +184,92 @@ var AllPlayerFrames = [][][]FrameData{
},
}, { // ActionKick
{
// TODO
stdHit(asset.FrameAt(asset.ImgPlayer, 1, 12)),
},
{
stdHit(asset.FrameAt(asset.ImgPlayer, 2, 12)),
},
{
stdHit(asset.FrameAt(asset.ImgPlayer, 3, 12)),
},
{
stdHit(asset.FrameAt(asset.ImgPlayer, 4, 12)),
},
{
stdHit(asset.FrameAt(asset.ImgPlayer, 5, 12)),
},
{
stdHit(asset.FrameAt(asset.ImgPlayer, 6, 12)),
},
{
stdHit(asset.FrameAt(asset.ImgPlayer, 7, 12)),
},
{
stdHit(asset.FrameAt(asset.ImgPlayer, 8, 12)),
},
{
stdHit(asset.FrameAt(asset.ImgPlayer, 9, 12)),
},
{
stdHit(asset.FrameAt(asset.ImgPlayer, 10, 12)),
},
{
stdHit(asset.FrameAt(asset.ImgPlayer, 11, 12)),
},
{
stdHit(asset.FrameAt(asset.ImgPlayer, 12, 12)),
},
{
stdHit(asset.FrameAt(asset.ImgPlayer, 13, 12)),
},
{
stdHit(asset.FrameAt(asset.ImgPlayer, 14, 12)),
{
T: HitboxHurt,
R: image.Rect(-5, -5, PlayerSize+10, PlayerSize+10),
},
},
{
stdHit(asset.FrameAt(asset.ImgPlayer, 13, 12)),
},
{
stdHit(asset.FrameAt(asset.ImgPlayer, 12, 12)),
},
{
stdHit(asset.FrameAt(asset.ImgPlayer, 11, 12)),
},
{
stdHit(asset.FrameAt(asset.ImgPlayer, 10, 12)),
},
{
stdHit(asset.FrameAt(asset.ImgPlayer, 9, 12)),
},
{
stdHit(asset.FrameAt(asset.ImgPlayer, 8, 12)),
},
{
stdHit(asset.FrameAt(asset.ImgPlayer, 7, 12)),
},
{
stdHit(asset.FrameAt(asset.ImgPlayer, 6, 12)),
},
{
stdHit(asset.FrameAt(asset.ImgPlayer, 5, 12)),
},
{
stdHit(asset.FrameAt(asset.ImgPlayer, 4, 12)),
},
{
stdHit(asset.FrameAt(asset.ImgPlayer, 3, 12)),
},
{
stdHit(asset.FrameAt(asset.ImgPlayer, 2, 12)),
},
{
stdHit(asset.FrameAt(asset.ImgPlayer, 1, 12)),
},
{
stdHit(asset.FrameAt(asset.ImgPlayer, 0, 12)),
},
}, { // ActionBlock
{

View File

@ -103,6 +103,7 @@ type Player struct {
ActionTicksLeft int
NoPunch bool
NoKick bool
PlayAgain bool
}

View File

@ -328,7 +328,12 @@ func (g *Game) applyPhysics() {
}
func (g *Game) UpdateByInputs(inputs []InputBits) {
const punchStunTicks = 15
const (
punchHitStrength = 4.0
punchStunTicks = 15
kickHitStrength = 7.0
KickStunTicks = 19
)
var player, opponent *component.Player
var playerFlipped, oppFlipped bool
@ -381,18 +386,27 @@ func (g *Game) UpdateByInputs(inputs []InputBits) {
}
}
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 {
if g.Players[i].NoPunch && !input.isButtonOn(ButtonPunch) {
g.Players[i].NoPunch = false
}
if g.Players[i].NoKick && !input.isButtonOn(ButtonKick) {
g.Players[i].NoKick = false
}
if input.isButtonOn(ButtonPunch) && !g.Players[i].NoPunch {
g.Players[i].Action = component.ActionPunch
g.Players[i].ActionTicksLeft = len(component.AllPlayerFrames[component.ActionPunch])
g.Players[i].NoPunch = true
continue
}
if input.isButtonOn(ButtonKick) && !g.Players[i].NoKick {
g.Players[i].Action = component.ActionKick
g.Players[i].ActionTicksLeft = len(component.AllPlayerFrames[component.ActionKick])
g.Players[i].NoKick = true
continue
}
if input.isButtonOn(ButtonUp) && !component.TranslateRect(playerRect, 0, -1).Overlaps(oppRect) {
var grounded bool
@ -438,9 +452,16 @@ func (g *Game) UpdateByInputs(inputs []InputBits) {
if frame.T == component.HitboxHurt {
// Hit opponent.
if oppRect.Overlaps(component.TranslateRect(frameRect, int(player.X), int(player.Y))) {
hitStrength := 4.0
hitStrength := punchHitStrength
stunTicks := punchStunTicks
if player.Action == component.ActionKick {
hitStrength = kickHitStrength
stunTicks = KickStunTicks
}
// Apply blocking.
if g.Players[opp].Action == component.ActionBlock {
hitStrength = 1.0
hitStrength /= 4.0
}
// Send the opponent flying in some direction.
@ -453,7 +474,7 @@ func (g *Game) UpdateByInputs(inputs []InputBits) {
// Stun the opponent.
if g.Players[opp].Action != component.ActionBlock {
opponent.Action = component.ActionStunned
opponent.ActionTicksLeft = punchStunTicks
opponent.ActionTicksLeft = stunTicks
}
}
}

View File

@ -114,6 +114,7 @@ var (
botTicks int
botWait bool
botLastPunch int
botLastKick int
botBlockTicks int
botTaunt component.PlayerAction
botTauntTicks int
@ -131,9 +132,11 @@ func botInput() InputBits {
botMaxActionTime = 20
botWaitChance = 3
botPunchDistance = 25
botBlockDistance = 25
botBlockTime = 17
botBlockChance = 4
botKickDistance = 30
botKickChance = 7
botBlockDistance = 30
botBlockTime = 25
botBlockChance = 3
botTauntMinTime = 60
botTauntTime = 200
botTauntMaxTime = 550
@ -146,6 +149,7 @@ func botInput() InputBits {
botTicks--
}
if !botWait {
// Handle taunting.
if (botTauntTicks > 0 || world.Winner == 2) && botTauntTotalTicks < botTauntMaxTime {
if botTauntTicks == 0 {
if p.Action == component.ActionIdle {
@ -194,24 +198,32 @@ func botInput() InputBits {
} else {
input.setButtonOn(ButtonLeft)
}
}
if botBlockTicks > 0 || (math.Abs(p.X-o.X) < botBlockDistance && o.Action == component.ActionPunch && rand.Intn(botBlockChance) != 0) {
input.setButtonOn(ButtonBlock)
if botBlockTicks > 0 {
botBlockTicks--
} else {
botBlockTicks = botBlockTime
opponentAttacking := o.Action == component.ActionPunch || o.Action == component.ActionKick
if botBlockTicks > 0 || (math.Abs(p.X-o.X) < botBlockDistance && opponentAttacking && rand.Intn(botBlockChance) == 0) {
input.setButtonOn(ButtonBlock)
if botBlockTicks > 0 {
botBlockTicks--
} else {
botBlockTicks = botBlockTime
}
} else if p.Action == component.ActionIdle && math.Abs(p.X-o.X) < botKickDistance && rand.Intn(botKickChance) == 0 && botLastKick > 1 {
input.setButtonOn(ButtonKick)
botLastKick = 0
} else if p.Action == component.ActionIdle && math.Abs(p.X-o.X) < botPunchDistance && botLastPunch > 1 {
input.setButtonOn(ButtonPunch)
botLastPunch = 0
}
} else if math.Abs(p.X-o.X) < botPunchDistance && botLastPunch > 1 {
input.setButtonOn(ButtonPunch)
botLastPunch = 0
}
}
if !input.isButtonOn(ButtonPunch) {
botLastPunch++
}
if !input.isButtonOn(ButtonKick) {
botLastKick++
}
return input
}