loading...
Cover image for A Stab At Roguish Go Part 03

A Stab At Roguish Go Part 03

shindakun profile image Steve Layton Updated on ・4 min read

ATLG Rogue (4 Part Series)

1) A Stab At Roguish Go Part 01 2) A Stab At Roguish Go Part 02 3) A Stab At Roguish Go Part 03 4) A Stab At Roguish Go Part 04

ATLG Rogue

Decisions

foreshadowing

Welcome back to another post in my rogue-ish Golang series. This week is going to be a very short post which doesn't cover much of the "game" itself. It's more a bit of a brain dump as I'm trying to decide on how I want to tackle adding creatures to the game.

There are a bunch of ways to do this. I'm trying to figure out what would be most appropriate for this and not complicate the code. We don't need any real display code since we'll just write our tests out to the console. We'll need to iterate on this throughout the next several weeks until we arrive at what we're looking for. And now...


Code Walkthrough

We are keeping everything very basic for this code we're not going to include tcell or anything other than a die roller.

package main

import (
  "fmt"
  "math/rand"
  "time"

  "github.com/shindakun/die"
)

One of the things we want to be able to do is a loop through our entire set of actors. So, we have an Actors struct which is a slice of the Actor struct. Actor is going to hold our basic "creature" information. That is the position (x,y), what floor they are on, and the Creature interface.

type Actors struct {
  Actors []Actor
}

type Actor struct {
  X        int
  Y        int
  Floor    int
  Creature Creature
}

Now we can create a simple method to "create" actors. We call newActor() and pass in where we want the actor to start on our stage and which floor. Our creature is also created and given "life" in this step. We'll see that a bit later on though...

func newActor(x, y, f int, c Creature) Actor {
  return Actor{
    X:        x,
    Y:        y,
    Floor:    f,
    Creature: c,
  }
}

The creature interface declares all the methods a creature contains. We're trying it this way so each creature can have its own set of functions. We could move the methods on to Actor if this doesn't work. Which it may not. This way leads to a bit of code duplication since we're rewriting the same methods for each creature type.

type Creature interface {
  GetRune() rune
  GetHealth() int
  GetDescription() string
  TakeDamage(int)
}

Here we have the majestic pig struct! I've already added JSON tags since I can imagine us loading basic creature data from disk. Currently, we have a rune (p), health (10), and a description (I'm a pig!). Not too exciting but it should work for now.

type Pig struct {
  R           rune   `json:"r,omitempty"`
  Health      int    `json:"health,omitempty"`
  Description string `json:"description,omitempty"`
}

To complete our pig "creature" we need to implement the parts of our Creature interface. The code is pretty descriptive so we won't touch on it too much.

func (p *Pig) GetRune() rune {
  return p.R
}

func (p *Pig) GetHealth() int {
  return p.Health
}

func (p *Pig) GetDescription() string {
  return p.Description
}
func (p *Pig) TakeDamage(i int) {
  p.Health = p.Health - i
}

We need to be thinking about our actors moving around the world. So, I've created a basic Move() method which will allow our "pig" to move about. To do this we roll a four-sided die and move our pig based on the roll. 1 for North, 2 for East, 3 for South, 4 for West. We could update this at some point to allow for eight-way movement but for simplicity, we'll keep it at four for now.

Again, the code is pretty self-explanatory so we'll keep it brief. We roll for our direction and update the actor's position based on the results.

func (a *Actor) Move(floor int) {
  if floor == a.Floor {
    /*
        1
       4+2
        3
    */
    rand.Seed(time.Now().UTC().UnixNano())
    var xx, yy int
    d, err := die.Roll("1d4")
    if err != nil {
      panic("die roll")
    }
    switch d {
    case 1:
      xx = -1
    case 2:
      yy = 1
    case 3:
      xx = 1
    case 4:
      yy = -1
    }
    a.X = a.X + xx
    a.Y = a.Y + yy
  }
}

We come now to the main() of our test. We will create our a "Actors".

func main() {
  a := &Actors{}

Then take a.Actors and start appending "new actors" to it. We create the new actor and setup the creature all in one go. Then we just print some stuff to the screen to test.

  a.Actors = append(a.Actors, newActor(1, 1, 1, &Pig{'p', 10, "From the realm of Paradox... the Pig."}))
  a.Actors = append(a.Actors, newActor(2, 2, 1, &Pig{'p', 10, "Oink."}))

  fmt.Printf("%#v\n\n", a)

  fmt.Printf("%#v\n\n", a.Actors[0])

  fmt.Printf("%#v\n\n", string(a.Actors[0].Creature.GetRune()))

  fmt.Printf("%#v\n\n", a.Actors[0].Creature.GetHealth())

  a.Actors[0].Creature.TakeDamage(5)

  fmt.Printf("%#v\n\n", a.Actors[0].Creature.GetHealth())

  fmt.Printf("%#v\n\n", a.Actors[1].Creature.GetDescription())

  for i := range a.Actors {
    a.Actors[i].Move(1)
  }

  fmt.Printf("%#v\n\n", a.Actors)
}

Nothing fancy

Wrapping Up

Seems to work alright, which is nice. If I have some time in the next day or so I'll try and work this into our code from last week to see how it goes.


You can find the code for this and most of the other Attempting to Learn Go posts in the repo on GitHub.



ATLG Rogue (4 Part Series)

1) A Stab At Roguish Go Part 01 2) A Stab At Roguish Go Part 02 3) A Stab At Roguish Go Part 03 4) A Stab At Roguish Go Part 04

Posted on by:

shindakun profile

Steve Layton

@shindakun

I've been known to write some code from time to time.

Discussion

markdown guide