This repository has been archived by the owner on Jul 4, 2021. It is now read-only.
forked from orlp/PyGG2
-
Notifications
You must be signed in to change notification settings - Fork 0
/
collision.py
279 lines (158 loc) · 6.31 KB
/
collision.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
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
from __future__ import division
from functions import place_free, sign, point_direction
import pygame
import math
def objectCheckCollision(character): pass
def characterHitObstacle(character, frametime): pass
"""
def objectCheckCollision(character):
# Check if a the Character has hit the wall:
hasCollided = False
character.rect.centerx = character.x-character.xRectOffset
character.rect.centery = character.y-character.yRectOffset
clip = character.rect.clip(character.root.map.rect)
# find where clip's top-left point is in both rectangles
x1 = clip.left - character.root.map.rect.left
y1 = clip.top - character.root.map.rect.top
# cycle through clip's area of the hitmasks
for x in range(clip.width):
for y in range(clip.height):
# returns True if neither pixel is blank
if character.root.map.mask.get_at((x1+x, y1+y)) == 1:
hasCollided = True
return hasCollided
def characterHitObstacle(character, frametime):
# THIS IS THE NEW VERSION; STILL WITH x/y
newX = character.x
newY = character.y
hspeed = character.hspeed
vspeed = character.vspeed
length = math.hypot(hspeed, vspeed)
if length == 0:# You haven't moved; if this happens something went wrong
print "You haven't moved, yet managed to collide with something."
return False
# hs and vs is the normalized vector of hspeed and vspeed.
hs = character.hspeed/length
vs = character.vspeed/length
while True:
if not objectCheckCollision(character):
break
character.x -= hs * frametime
character.y -= vs * frametime
if hspeed == 0 or vspeed == 0:
return True
# This is the left-over velocity.
hs = hspeed
vs = vspeed
# The character got pushed out, but now we need to let him move in the directions he's allowed to move.
character.x += sign(hs) * frametime
if not objectCheckCollision(character) and abs(hs) > 0:
# There's still room to move on the left/right
i = 1
while i <= abs(hs) and not objectCheckCollision(character):
character.x += sign(hs) * frametime
i += 1
if objectCheckCollision(character):
character.x -= sign(hs) * frametime
return True
else:
# Stop horizontal movement
character.hspeed = 0
character.hs = 0
character.x -= sign(hs) * frametime
character.y += sign(vs) * frametime
if not objectCheckCollision(character) and abs(vs) > 0:
# There's still room to move on the left/right
i = 1
while i <= abs(vs) and not objectCheckCollision(character):
character.y += sign(vs) * frametime
i += 1
if objectCheckCollision(character):
character.y -= sign(vs) * frametime
return True
else:
# INSERT STAIR CODE; SEE BELOW
# Stop vertical movement
character.vspeed = 0
character.vs = 0
character.y -= sign(vs) * frametime
return True
# STAIRS CODE; INSERT IN "STAIR CODE" ONCE FIXED
'''
character.y -= 6
if not objectCheckCollision(character):
character.y += 6# This is to compensate for the loop.
character.x -= sign(character.hspeed)*6
while hs*sign(character.hspeed) > 0:
character.y -= 6
character.x += sign(character.hspeed)*6
hs -= sign(character.hspeed)*6
if objectCheckCollision(character):
character.y += 6
character.x -= sign(character.hspeed)*6
break
else:'''
"""
'''
# THIS IS THE ORIGNAL GG2 COLLISION CODE, PORTED FRESH FROM GMK. Not needed.
# The Character has collided; Push him back out:
# This code was written for a situation before the character actually moved, but I want to keep this compatible with our structure.
# Hence; move everything back, and move forward as far as we can.
character.x -= character.hspeed
character.y -= character.vspeed
hleft = character.hspeed
vleft = character.vspeed
loopCounter = 0
stuck = 0
collisionRectified = True
while((abs(hleft) >= 1 or abs(vleft) >= 1) and stuck == 0): # while we still have distance to travel
loopCounter += 1
if(loopCounter > 10):
# After 10 loops, it's assumed we're stuck. Stop all vertical movement.
stuck = 1
collisionRectified = False # set this to true when we fix a collision problem
# (eg. detect hitting the ceiling and setting vspeed = 0)
# if, after checking for all our possible collisions, we realize that we haven't
# been able to fix a collision problem, then we probably hit a corner or something,
# and we should try to fix that
prevX = character.x
prevY = character.y
# move as far as we can without hitting something
# In GMK, this was "move_contact_solid(point_direction(x, y, x + hleft, y + vleft), point_distance(x, y, x + hleft, y + vleft))"
length = functions.lengthdir(hleft, vleft)
distance = 0
while distance < length:
character.x = character.x+hleft*distance
character.y = character.y+vleft*distance
if objectCheckCollision(character, wallmask):
character.x = character.x-hleft*distance
character.y = character.y-vleft*distance
break
distance += length/20
# deduct that movement from our remaining movement
hleft -= (character.x - prevX)
vleft -= (character.y - prevY)
# determine what we hit, and act accordingly
if(vleft != 0 and not functions.place_free(character.x, character.y + functions.sign(vleft), wallmask)): # we hit a ceiling or floor
if(vleft>0):
moveStatus = 0 # floors, not ceilings, reset moveStatus
vleft = 0 # don't go up or down anymore
character.vspeed = 0 # don't try it next frame, either
collisionRectified = True
if(hleft != 0 and not functions.place_free(character.x + functions.sign(hleft), character.y, wallmask)): # we hit a wall on the left or right
moveStatus = 0
if(functions.place_free(character.x + functions.sign(hleft), character.y - 6, wallmask)): # if we could just walk up the step
character.y -= 6 # hop up the step.
collisionRectified = True
# elif(functions.place_free(character.x + functions.sign(hleft), character.y + 6, wallmask) and abs(character.hspeed) >= abs(character.vspeed)): # ceiling sloping
#
# character.y += 6
# collisionRectified = True
else: # it's not just a step, we've actually gotta stop
hleft = 0 # don't go left or right anymore
characterhspeed = 0 # don't try it next frame, either
collisionRectified = True
if(not collisionRectified and (abs(hleft) >= 1 or abs(vleft) >= 1)):
# uh-oh, no collisions fixed, try stopping all vertical movement and see what happens
charactervspeed = 0
vleft = 0'''