70 lines
2.6 KiB
Go
70 lines
2.6 KiB
Go
package westworldwithwoman
|
|
|
|
// Entity is what every game object in the world must be able to do.
|
|
// The C++ code used a pure virtual function (Update()=0) to force
|
|
// every subclass to write its own Update. Go has no subclasses, so
|
|
// instead we say: "anything with an Update() and an ID() method
|
|
// counts as an Entity." A type only satisfies this interface once
|
|
// it has its own Update method - just like the C++ version couldn't
|
|
// be used until Update was implemented.
|
|
type Entity interface {
|
|
Update()
|
|
ID() int
|
|
}
|
|
|
|
// nextValidID plays the role of the C++ "static int m_iNextValidID".
|
|
// In C++, "static" on a class member means "one shared copy for the
|
|
// whole class, not one per object." Go doesn't have that keyword for
|
|
// structs, so we just use a normal package-level variable - it's
|
|
// shared by every BaseGameEntity for the same reason: there's only
|
|
// one of it.
|
|
var nextValidID int
|
|
|
|
// BaseGameEntity is the Go version of the C++ class BaseGameEntity.
|
|
// Go doesn't have "classes" or "inheritance" - instead, other types
|
|
// (like a Miner or a Wife later in the book) will embed this struct
|
|
// inside themselves to borrow its fields and methods, and then add
|
|
// their own Update method on top.
|
|
type BaseGameEntity struct {
|
|
id int // was "m_ID" - the entity's own unique number
|
|
}
|
|
|
|
// NewBaseGameEntity replaces the C++ constructor:
|
|
//
|
|
// BaseGameEntity(int id) { SetID(id); }
|
|
//
|
|
// Go structs don't run any code automatically when you create them,
|
|
// so we write a plain function that builds one correctly. Any code
|
|
// that wants a BaseGameEntity should call this instead of building
|
|
// the struct by hand.
|
|
func NewBaseGameEntity(id int) *BaseGameEntity {
|
|
e := &BaseGameEntity{}
|
|
e.setID(id)
|
|
return e
|
|
}
|
|
|
|
// setID is the Go version of the private C++ method SetID. It does
|
|
// exactly what the comment in the book says: check the requested ID
|
|
// isn't lower than the next free one, store it, then move the
|
|
// "next free ID" counter past it.
|
|
//
|
|
// The C++ code used assert() for the check, which only runs in
|
|
// debug builds and does nothing in a release build. Go has no
|
|
// assert, so we use panic - it always runs, and it stops the
|
|
// program immediately if this ever happens, which is exactly what
|
|
// a broken invariant like this deserves.
|
|
func (e *BaseGameEntity) setID(val int) {
|
|
if val < nextValidID {
|
|
panic("BaseGameEntity.setID: invalid ID")
|
|
}
|
|
e.id = val
|
|
nextValidID = e.id + 1
|
|
}
|
|
|
|
// ID returns the entity's unique number. This is the Go version of
|
|
// the C++ "int ID() const { return m_ID; }" - a small read-only
|
|
// accessor for the private field.
|
|
func (e *BaseGameEntity) ID() int {
|
|
return e.id
|
|
}
|