Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
id_rsa
id_rsa.pub
sshtron
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ SSHTron is a multiplayer lightcycle game that runs through SSH. Just run the com

$ ssh sshtron.zachlatta.com

_Controls: WASD or vim keybindings to move (**do not use your arrow keys**). Escape or Ctrl+C to exit._
_Controls: WASD, arrow keys or vim keybindings to move. Escape or Ctrl+C to exit._

![Demo](static/img/gameplay.gif)

Expand Down
90 changes: 68 additions & 22 deletions game.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ func (h *Hub) Run(g *Game) {
h.Sessions[s] = struct{}{}
case s := <-h.Unregister:
if _, ok := h.Sessions[s]; ok {
fmt.Fprint(s, "\r\n\r\n~ End of Line ~ \r\n\r\nRemember to use WASD to move!\r\n\r\n")
fmt.Fprint(s, "\r\n\r\n ~ Bye! ~ \r\n\r\n")

// Unhide the cursor
fmt.Fprint(s, "\033[?25h")
Expand Down Expand Up @@ -77,18 +77,26 @@ func (p Position) RoundY() int {
type PlayerDirection int

const (
verticalPlayerSpeed = 0.007
horizontalPlayerSpeed = 0.01
speedMultiplier = 1
verticalPlayerSpeed = 0.007 * speedMultiplier
horizontalPlayerSpeed = 0.01 * speedMultiplier
playerCountScoreMultiplier = 1.25
playerTimeout = 15 * time.Second

playerUpRune = '⇡'
playerLeftRune = '⇠'
playerDownRune = '⇣'
playerRightRune = '⇢'
//playerUpRune = '⇡'
//playerLeftRune = '⇠'
//playerDownRune = '⇣'
//playerRightRune = '⇢'
playerUpRune = '↑'
playerLeftRune = '←'
playerDownRune = '↓'
playerRightRune = '→'

//playerTrailHorizontal = '╌'
//playerTrailVertical = '┆'
playerTrailHorizontal = '─'
playerTrailVertical = '│'

playerTrailHorizontal = '┄'
playerTrailVertical = '┆'
playerTrailLeftCornerUp = '╭'
playerTrailLeftCornerDown = '╰'
playerTrailRightCornerDown = '╯'
Expand Down Expand Up @@ -145,6 +153,7 @@ type Player struct {
Name string
CreatedAt time.Time
Direction PlayerDirection
InitDir PlayerDirection
Marker rune
Color color.Attribute
Pos *Position
Expand Down Expand Up @@ -172,6 +181,7 @@ func NewPlayer(s *Session, worldWidth, worldHeight int,
CreatedAt: time.Now(),
Marker: playerDownRune,
Direction: PlayerDown,
InitDir: PlayerDown,
Color: color,
Pos: &Position{startX, startY},
}
Expand All @@ -192,38 +202,34 @@ func (p *Player) calculateScore(delta float64, playerCount int) float64 {
}

func (p *Player) HandleUp() {
if p.Direction == PlayerDown {
if p.InitDir == PlayerDown {
return
}
p.Direction = PlayerUp
p.Marker = playerUpRune
p.s.didAction()
}

func (p *Player) HandleLeft() {
if p.Direction == PlayerRight {
if p.InitDir == PlayerRight {
return
}
p.Direction = PlayerLeft
p.Marker = playerLeftRune
p.s.didAction()
}

func (p *Player) HandleDown() {
if p.Direction == PlayerUp {
if p.InitDir == PlayerUp {
return
}
p.Direction = PlayerDown
p.Marker = playerDownRune
p.s.didAction()
}

func (p *Player) HandleRight() {
if p.Direction == PlayerLeft {
if p.InitDir == PlayerLeft {
return
}
p.Direction = PlayerRight
p.Marker = playerRightRune
p.s.didAction()
}

Expand All @@ -249,6 +255,21 @@ func (p *Player) Update(g *Game, delta float64) {

// If we moved, add a trail segment.
if endX != startX || endY != startY {
// Update initial direction
// Needed to prevent players from doing a 180 in one frame
p.InitDir = p.Direction
// Update player direction only after a new frame
switch p.InitDir {
case PlayerUp:
p.Marker = playerUpRune
case PlayerLeft:
p.Marker = playerLeftRune
case PlayerDown:
p.Marker = playerDownRune
case PlayerRight:
p.Marker = playerRightRune
}

var lastSeg *PlayerTrailSegment
var lastSegX, lastSegY int
if len(p.Trail) > 0 {
Expand Down Expand Up @@ -320,7 +341,7 @@ type Tile struct {
}

const (
gameWidth = 78
gameWidth = 82
gameHeight = 22

keyW = 'w'
Expand All @@ -337,6 +358,12 @@ const (
keyK = 'k'
keyL = 'l'

// https://gist.github.com/fnky/458719343aabd01cfb17a3a4f7296797#list-of-keyboard-strings
keyUp = 'A'
keyDown = 'B'
keyRight = 'C'
keyLeft = 'D'

keyComma = ','
keyO = 'o'
keyE = 'e'
Expand Down Expand Up @@ -417,15 +444,34 @@ func (gm *GameManager) HandleNewChannel(c ssh.Channel, color string) {
fmt.Println(err)
break
}
if r == keyEscape {
has_more := reader.Buffered()
// not just escape
if has_more > 0 {
r1, _, err := reader.ReadRune()
if err != nil {
fmt.Println(err)
break
}
// Then goes arrow key
if r1 == '[' {
r, _, err = reader.ReadRune()
if err != nil {
fmt.Println(err)
break
}
}
}
}

switch r {
case keyW, keyZ, keyK, keyComma:
case keyUp, keyW, keyZ, keyK, keyComma:
session.Player.HandleUp()
case keyA, keyQ, keyH:
case keyLeft, keyA, keyQ, keyH:
session.Player.HandleLeft()
case keyS, keyJ, keyO:
case keyDown, keyS, keyJ, keyO:
session.Player.HandleDown()
case keyD, keyL, keyE:
case keyRight, keyD, keyL, keyE:
session.Player.HandleRight()
case keyCtrlC, keyEscape:
if g.SessionCount() == 1 {
Expand Down
11 changes: 8 additions & 3 deletions sshtron.sh
Original file line number Diff line number Diff line change
@@ -1,7 +1,12 @@
#!/bin/sh

cd "$SNAP_DATA"
if [ -d "$SNAP_DATA" ]; then
cd "$SNAP_DATA"
[ -f id_rsa ] || "$SNAP"/usr/bin/ssh-keygen -t rsa -N '' -f id_rsa

[ -f id_rsa ] || $SNAP/usr/bin/ssh-keygen -t rsa -N '' -f id_rsa
sshtron > "$SNAP_DATA/sshtron.log" 2>&1
else
[ -f id_rsa ] || ssh-keygen -t rsa -N '' -f id_rsa

sshtron > "$SNAP_DATA/sshtron.log" 2>&1
./sshtron > sshtron.log 2>&1
fi
2 changes: 1 addition & 1 deletion static/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ <h1 class="title">SSH Tron</h1>
be playing in seconds.
</p>
<p class="description"><code><span class="no-copy">$</span> ssh sshtron.zachlatta.com</code></p>
<p class="subtext">(WASD or vim keybindings for movement, <b>do not use arrow keys</b>)</p>
<p class="subtext">(WASD, arrow keys or vim keybindings for movement)</p>
<img class="gameplay-image" src="/img/gameplay.gif">
<p class="subtext">
By <a href="https://github.com/maxwofford">@MaxWofford</a> and
Expand Down