-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathmap.py
215 lines (183 loc) · 8.8 KB
/
map.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
import logging
logger = logging.getLogger('map')
import pygame
from pygame.locals import *
import lib.common
import lib
from tiles import tile
#these are global objects created by load_map.py or programmer.create_programming_gui() respectivly
map=None
cur_map=None
## .==. .==.
## //`^\\ //^`\\
## // ^ ^\(\__/)/^ ^^\\
## //^ ^^ ^/6 6\ ^^ ^ \\
## //^ ^^ ^/( .. )\^ ^ ^ \\
## // ^^ ^/\| v""v |/\^ ^ ^\\
## // ^^/\/ / `~~` \ \/\^ ^\\
## -----------------------------
### HERE BE DRAGONS
class MAP(object):
'''self.map={(x,y):(tile,rect,border color}
third data point is left in as the possibility remains
that i might want to use it for some random tile data...
possibly creature/objects on said tile?'''
def __init__(self,r_c=(160,121),sub_rect=pygame.Rect((0,0),(50,50)),main_rect=pygame.Rect((0,0),(475,475)),tclass=tile):
if lib.common.debug() > 0:
import os
self.font = lib.common.font
self.map_size=r_c
self.sub_rect=sub_rect
self.main_rect=main_rect
self.show_grid = False
self.map={}
for x in range(self.map_size[0]):
for y in range(self.map_size[1]):
tmp=pygame.Rect(self.sub_rect.topleft,self.sub_rect.size)
tmp.topleft=((self.sub_rect.width*x)+self.main_rect.left,(self.sub_rect.height*y)+self.main_rect.top)
#set map items::: tile class, rect, and grid color
self.map[(x,y)]=[tclass(),tmp]
self.surf=pygame.Surface((self.main_rect.width,self.main_rect.height))
##set location _AND_ render! (remember @propset)
self.loc=(0,0)
self.overlays={}
self.timer=pygame.time.Clock()
def add_overlay(self,loc,obj):
##simple test for now, maybe have it just silently ignore the error? what should i do? i will wait untill i develop more
if loc in self.overlays:
logger.error('what? overlay exists::%s %s'%(loc,obj))
return
##finaly, add location/object pairing
self.overlays[loc]=obj
def remove_overlay(self,loc):
del self.overlays[loc]
def update_overlays(self,screen):
'''if overlay time ticker doesnt pan out, we /can/ just iterate through self.overlays.iteritems()-->obj.ticktime
note, should we also draw the overlays here? for now we will, for it is mighty convieniant placement
for draw code, we pass:
1: screen
2: loc
3: map[loc][1].center
4: actual time from time tick (time since last update)
5: map (self here)
'''
##calculate timetick first...
diff=self.timer.tick()
for loc in self.overlays.iterkeys():
#calculate center of tile (because self.render only updates tiles in view)
tmp_r=self.get_tile(loc)[1]
diff+=self.timer.tick()##incase an overlay takes a long time to update, add time to diff
self.overlays[loc].update(screen,loc,tmp_r.center,diff,self)
#logger.info("%s::%s"%(self.overlays[loc],self.map[loc][1].center))
if lib.common.debug() > 2:
logger.debug('overlay update time:%s'%diff)
def render(self):
'''iterate through every tile and move it and draw the contents'''
logger.debug('rendering map::(%s,%s)'%(self.loc))
if lib.common.debug()>1:
lib.common.p_rents(logger)
self.surf.fill((0,0,0))
for x in range(self.main_rect.width/self.sub_rect.width):
for y in range(self.main_rect.height/self.sub_rect.height):
try:
#set current grid x and y locations
xx=self._loc[0]+x
yy=self._loc[1]+y
#move the rectangle
tmp_r=self.map[(xx,yy)][1]
tmp_r.topleft=(x*self.sub_rect.width,
y*self.sub_rect.height )
#create copy to move and check against...
r_check = pygame.Rect(tmp_r)
r_check.topleft=((self.main_rect.left +(x*self.sub_rect.width )),
(self.main_rect.top +(y*self.sub_rect.height )))
if self.main_rect.contains(r_check):
#if the rect fits, draw it, else dont
self.map[(xx,yy)][0].draw(self.surf,tmp_r)
##enable to draw rect outlines
if self.show_grid:
pygame.draw.rect(self.surf, self.map[(xx,yy)][0].color, tmp_r, 1)
if lib.common.debug() > 0:
#render tile number text...
text = self.font.render(str((xx,yy)),True,(0,0,255)).convert_alpha()
self.surf.blit(text,tmp_r)
except KeyError:
#key that doesnt exist? how and why?
#keys that go out of the map is what happens when we have a blank tile in the viewport...
if (xx >= 0 and yy >= 0):
if lib.common.debug() >2:
logger.debug('map location temp:%s,%s'%(x,y))
logger.debug('missing tile :%s,%s'%(xx,yy))
if lib.common.debug() > 0:
self.surf.blit(self.font.render(str((xx,yy)),True,(0,0,255)).convert_alpha(),(0,24))
self.surf.blit(self.font.render(str(self.loc)
,True,(0,0,255)).convert_alpha(),(0,12))
if lib.common.debug() > 1:
#draw rect around main map area... disabled until i need it for the multi interface...
pygame.draw.rect(self.surf, (0,255,255), self.main_rect, 1)
def draw(self,screen):
'''fast draw function.
i use a surface buffer for the "real" draw function
and re-blit it here.
TODO:: known bug: if main_rect.topleft != (0,0) the position of the blocks falls apart'''
screen.blit(self.surf,self.main_rect)
def click_engine(self,pos):
'''return what tile was clicked. (tile pos only?)'''
if self.main_rect.collidepoint(pos):
#fix pos for how far away from tl of screen we are...
#must be done thanks to psudo surface
pos=(pos[0]-self.main_rect.left,pos[1]-self.main_rect.top)
for x in range(self.main_rect.width/self.sub_rect.width):
for y in range(self.main_rect.height/self.sub_rect.height):
try:
#set current grid x and y locations
xx=self._loc[0]+(x)
yy=self._loc[1]+(y)
if self.map[(xx,yy)][1].collidepoint(pos):
logger.debug("%s,%s clicked"%(xx,yy))
return (xx,yy)
except KeyError:
pass
return (-1,-1)
@lib.decorators.propget
def loc(self):
'''this is perhaps one of my favorite little python hidden secrets:
object attribute decorators... whenever i "get" the variable
"self.loc" this function runs'''
return self._loc
@lib.decorators.propset
def loc(self, value):
'''but, when i "set" self.loc, this function runs! even more, this
way, when i move the map, (changing the top left number self.loc)
i re-render it!!
now, if only there was a way to get pydev to understand this...'''
self._loc=value
self.render()
def get_tile(self,loc):
tile=self.map[loc]
tile[1]=pygame.Rect(tile[1])#new rect, because we update the location of it...
#xx=self._loc[0]+loc[0]
xx=loc[0]-self._loc[0]
#yy=self._loc[1]+loc[1]
yy=loc[1]-self._loc[1]
#move the rectangle
tile[1].topleft=(xx*self.sub_rect.width,
yy*self.sub_rect.height )
return tile
def tile_gen(self):
'''a generator using <yeild> to help with iterating over _every_ tile'''
for x in range(self.map_size[0]-1):
for y in range(self.map_size[1]-1):
yield self.map[(x,y)],(x,y)
def __getstate__(self):
state = self.__dict__.copy()
state.pop('surf')
state.pop('timer')
state.pop('font')
return state
def __setstate__(self,state):
self.__dict__=state
self.surf=pygame.Surface((self.main_rect.width,self.main_rect.height))
self.timer=pygame.time.Clock()
self.font=lib.common.font
self.render()