func Paint(w wde.Window, rect image.Rectangle) { xOffset, yOffset := GetTopLeft() minX, maxX := rect.Min.X>>res.TileSize, (rect.Max.X-1)>>res.TileSize+1 minY, maxY := rect.Min.Y>>res.TileSize, (rect.Max.Y-1)>>res.TileSize+1 center := layout.Coord{ViewportWidth/2 - xOffset, ViewportHeight/2 - yOffset} for x := minX; x < maxX; x++ { for y := minY; y < maxY; y++ { res.Tile(space, res.Terrain, uint16(layout.GetSpace(x-xOffset, y-yOffset)), x, y) draw.Draw(scene, image.Rect(x<<res.TileSize, y<<res.TileSize, (x+1)<<res.TileSize, (y+1)<<res.TileSize), image.Transparent, image.ZP, draw.Src) if WireView() { tile := layout.Get(x-xOffset, y-yOffset) for i := len(tile) - 1; i > 0; i-- { res.Tile(scene, res.Terrain, uint16(tile[i]), x, y) } } else { for _, t := range layout.Get(x-xOffset, y-yOffset) { res.Tile(scene, res.Terrain, uint16(t), x, y) } } if VisibilityOn() && !layout.Visible(center, layout.Coord{x - xOffset, y - yOffset}) { res.Tile(scene, image.Black, 0, x, y) } } } mouseLock.Lock() if mouseValid { res.Tile(scene, res.Terrain, uint16(mouseTile), mouseCoord.X+xOffset, mouseCoord.Y+yOffset) } mouseLock.Unlock() draw.Draw(viewport, rect, space, rect.Min, draw.Src) draw.Draw(viewport, rect, scene, rect.Min, draw.Over) if LightsOn() { draw.DrawMask(viewport, rect, image.Black, image.ZP, light.Image(-xOffset, -yOffset), rect.Min.Add(light.Origin(-xOffset, -yOffset)), draw.Over) } w.Screen().CopyRGBA(viewport, viewport.Bounds()) w.FlushImage(rect) }
func (p *Player) dispatch(msgIn message.Receiver, messages message.Sender) { for msg := range msgIn { switch m := msg.(type) { case SetLocation: if p.x != m.X || p.y != m.Y { Invalidate(p.screenRect()) p.x, p.y = m.X, m.Y if p.isLocalPlayer { atomic.StoreUint32(&playerFlags, m.Flags) } paintLock.RLock() p.paint.Sprite = uint16(m.Flags & packet.FlagSpriteMask) if p.paint.Sprite == res.HumanSuit && layout.Get(p.x, p.y).Space() { p.paint.Sprite = res.HumanSuitHelm } if p.paint.Changed.IsZero() { p.paint.From.X, p.paint.From.Y = p.x, p.y } else { p.paint.From = p.paint.To } p.paint.To.X, p.paint.To.Y = p.x, p.y p.paint.Changed = time.Now() paintLock.RUnlock() if p.isLocalPlayer { atomic.StoreInt64(&topLeftX, ViewportWidth/2-int64(p.x)) atomic.StoreInt64(&topLeftY, ViewportHeight/2-int64(p.y)) } else { Invalidate(p.screenRect()) } } case packet.Despawn: paintLock.Lock() delete(paintContexts, &p.Actor) paintLock.Unlock() Invalidate(p.screenRect()) default: messages <- m } } close(messages) }
func (p *Player) Initialize() (message.Receiver, message.Sender) { msgIn, broadcast := p.Actor.Initialize() p.ID = <-nextPlayerID messages := make(chan message.Message) go func() { for msg := range msgIn { switch m := msg.(type) { case SendLocation: m <- packet.Packet{ Location: &packet.Location{ ID: p.ID, Coord: layout.Coord{p.x, p.y}, }, } case packet.Location: dx, dy := m.Coord.X, m.Coord.Y // TODO: space logic if layout.Get(p.x+dx, p.y+dy).Passable() { p.x += dx p.y += dy go func(m SetLocation) { world.Send <- m }(SetLocation{ ID: p.ID, Actor: &p.Actor, Coord: layout.Coord{p.x, p.y}, }) } default: messages <- m } } close(messages) }() return messages, broadcast }
func Paint(w wde.Window, rect image.Rectangle) { xOffset, yOffset := GetTopLeft() center := layout.Coord{ViewportWidth/2 - xOffset, ViewportHeight/2 - yOffset} if center != oldCenter || layout.Version() != oldVersion { oldCenter = center oldVersion = layout.Version() for x := 0; x <= ViewportWidth; x++ { for y := 0; y <= ViewportHeight; y++ { if layout.Visible(center, layout.Coord{x - xOffset, y - yOffset}) { res.Tile(terrain, res.Terrain, uint16(layout.GetSpace(x-xOffset, y-yOffset)), x, y) draw.Draw(terrain, image.Rect(x<<res.TileSize, y<<res.TileSize, (x+1)<<res.TileSize, (y+1)<<res.TileSize), image.Transparent, image.ZP, draw.Src) for _, t := range layout.Get(x-xOffset, y-yOffset) { if !t.NoClient() { res.Tile(terrain, res.Terrain, uint16(t), x, y) } } } else { res.Tile(terrain, image.Black, 0, x, y) } } } switch GetPlayerFlags() & packet.FlagSpriteMask { case packet.FlagEngineer: for x := 0; x <= ViewportWidth; x++ { for y := 0; y <= ViewportHeight; y++ { dx, dy := x-ViewportWidth/2, y-ViewportHeight/2 dist := dx*dx + dy*dy if dist <= 3*3 && layout.Visible(center, layout.Coord{x - xOffset, y - yOffset}) { for _, t := range layout.Get(x-xOffset, y-yOffset) { if t >= layout.WireW && t <= layout.WireS { res.Tile(terrain, res.Terrain, uint16(t), x, y) } } } } } } } minX, maxX := rect.Min.X>>res.TileSize, (rect.Max.X-1)>>res.TileSize+1 minY, maxY := rect.Min.Y>>res.TileSize, (rect.Max.Y-1)>>res.TileSize+1 draw.Draw(sprites, sprites.Bounds(), image.Transparent, image.ZP, draw.Src) var pixOffset image.Point var hasAnimation image.Rectangle paintLock.Lock() for _, p := range paintContexts { if layout.Visible(center, p.To) { x1, y1 := p.From.X+xOffset, p.From.Y+yOffset x2, y2 := p.To.X+xOffset, p.To.Y+yOffset if minX <= x2 && x2 <= maxX && minY <= y2 && y2 <= maxY { interp := float32(time.Since(p.Changed)*5) / float32(time.Second) if interp >= 1 { res.Tile(sprites, res.Actors, p.Sprite, x2, y2) } else { toInvalidate := image.Rect(x1, y1, x1+1, y1+1).Union(image.Rect(x2, y2, x2+1, y2+1)) if hasAnimation.Empty() { hasAnimation = toInvalidate } else { hasAnimation = hasAnimation.Union(toInvalidate) } if p == thePlayer.paint { pixOffset.X = int(float32((x1-x2)<<res.TileSize) * (1 - interp)) pixOffset.Y = int(float32((y1-y2)<<res.TileSize) * (1 - interp)) hasAnimation = viewport.Bounds() } res.TileFloat(sprites, res.Actors, p.Sprite, x1, y1, x2, y2, interp) } } } } paintLock.Unlock() draw.Draw(viewport, rect, terrain, rect.Min.Add(pixOffset), draw.Src) draw.Draw(viewport, rect, sprites, rect.Min.Add(pixOffset), draw.Over) draw.DrawMask(viewport, rect, image.Black, image.ZP, light.Image(-xOffset, -yOffset), rect.Min.Add(light.Origin(-xOffset, -yOffset)).Add(pixOffset), draw.Over) if image.Rect(0, 0, 1, 1).Overlaps(rect) { mouseTileLock.Lock() res.DrawString(viewport, mouseTileString, color.White, res.FontSmall, 1, 1) mouseTileLock.Unlock() } if !hasAnimation.Empty() { Invalidate(image.Rectangle{hasAnimation.Min.Mul(1 << res.TileSize), hasAnimation.Max.Mul(1 << res.TileSize)}) } paints++ /* // For debugging paints res.DrawString(viewport, strconv.FormatUint(paints, 10), color.White, res.FontSmall, 300, 1) draw.Draw(viewport, image.Rectangle{rect.Min, image.Pt(rect.Max.X+1, rect.Min.Y+1)}, image.White, image.ZP, draw.Src) draw.Draw(viewport, image.Rectangle{image.Pt(rect.Min.X-1, rect.Max.Y-1), rect.Max}, image.White, image.ZP, draw.Src) draw.Draw(viewport, image.Rectangle{rect.Min, image.Pt(rect.Min.X+1, rect.Max.Y+1)}, image.White, image.ZP, draw.Src) draw.Draw(viewport, image.Rectangle{image.Pt(rect.Max.X-1, rect.Min.Y-1), rect.Max}, image.White, image.ZP, draw.Src) //*/ w.Screen().CopyRGBA(viewport, viewport.Bounds()) w.FlushImage(rect) }
func writeMapTest() { minX, minY, maxX, maxY := 0, 0, 0, 0 layout.AllTiles(func(c layout.Coord, t layout.MultiTile) { if t.Space() { return } if c.X < minX { minX = c.X } if c.Y < minY { minY = c.Y } if c.X > maxX { maxX = c.X } if c.Y > maxY { maxY = c.Y } }) minX-- minY-- maxX++ maxY++ dx := maxX - minX dy := maxY - minY dx++ dy++ buf := make([]byte, dx*dy+dy-1) i := 0 for y := minY; y <= maxY; y++ { if i != 0 { buf[i] = '\n' i++ } for x := minX; x <= maxX; x++ { t := layout.Get(x, y) if t.Space() { buf[i] = ' ' } else if t.Door() { if t.Passable() { buf[i] = 'd' } else { buf[i] = 'D' } } else if t.Passable() { buf[i] = '_' } else if t.BlocksVision() { buf[i] = 'W' } else { buf[i] = 'G' } i++ } } f, err := os.Create("map_test.go") if err != nil { panic(err) } fmt.Fprint(f, beforeTest) fmt.Fprint(f, "\n\ttop = ", minY) fmt.Fprint(f, "\n\tleft = ", minX) fmt.Fprint(f, "\n\tcheck = `", string(buf), "`\n") fmt.Fprint(f, afterTest) f.Close() }