package westworld // 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 }