A Stab At Roguish Go Part 03

shindakun

Steve Layton

Posted on April 14, 2019

A Stab At Roguish Go Part 03

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"
)
Enter fullscreen mode Exit fullscreen mode

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
}
Enter fullscreen mode Exit fullscreen mode

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,
  }
}
Enter fullscreen mode Exit fullscreen mode

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)
}
Enter fullscreen mode Exit fullscreen mode

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"`
}
Enter fullscreen mode Exit fullscreen mode

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
}
Enter fullscreen mode Exit fullscreen mode

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
  }
}
Enter fullscreen mode Exit fullscreen mode

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

func main() {
  a := &Actors{}
Enter fullscreen mode Exit fullscreen mode

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)
}
Enter fullscreen mode Exit fullscreen mode

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.



💖 💪 🙅 🚩
shindakun
Steve Layton

Posted on April 14, 2019

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related