Skip to content

Commit bbecde2

Browse files
committed
changed the Line.raycast
1 parent e77cf60 commit bbecde2

File tree

7 files changed

+75
-151
lines changed

7 files changed

+75
-151
lines changed

geometry.pyi

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,7 @@ class Line(Sequence[float]):
9898
def collidecircle(self, circle: CircleValue) -> bool: ...
9999
@overload
100100
def collidecircle(self, x: float, y: float, r: float) -> bool: ...
101-
def raycast(self, second: Sequence[LineValue]) -> Optional[Tuple[float, float]]: ...
101+
def raycast(self, sequence: Sequence[LineValue]) -> Optional[Tuple[float, float]]: ...
102102

103103
class Circle:
104104
x: float
@@ -116,9 +116,3 @@ class Circle:
116116
def __init__(self, single_arg: CircleValue) -> None: ...
117117
def __copy__(self) -> "Circle": ...
118118
copy = __copy__
119-
120-
121-
def raycast(
122-
first: Sequence[LineValue],
123-
second: Sequence[LineValue]
124-
) -> List[Optional[Tuple[float, float]]]: ...

setup.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,4 +29,3 @@ def build() -> None:
2929
sys.exit(subprocess.call(cmd))
3030

3131
build()
32-

src_c/collisions.c

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -62,10 +62,8 @@ pgIntersection_LineLine(pgLineBase *A, pgLineBase *B, double *X, double *Y)
6262
double u = -(u1 / den);
6363

6464
if (t >= 0 && t <= 1 && u >= 0 && u <= 1) {
65-
if (X)
66-
*X = x1 + t * (x2 - x1);
67-
if (Y)
68-
*Y = y1 + t * (y2 - y1);
65+
*X = x1 + t * (x2 - x1);
66+
*Y = y1 + t * (y2 - y1);
6967
return 1;
7068
}
7169
return 0;

src_c/geometry.c

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,10 @@
11
#include "line.c"
22
#include "circle.c"
33
#include "collisions.c"
4-
#include "methods.c"
54

65
#define PYGAMEAPI_GEOMETRY_NUMSLOTS 17
76

8-
static PyMethodDef _pg_module_methods[] = {
9-
{"raycast", (PyCFunction)pg_geometry_raycast, METH_FASTCALL, NULL},
10-
{NULL, NULL, 0, NULL}};
7+
static PyMethodDef _pg_module_methods[] = {{NULL, NULL, 0, NULL}};
118

129
MODINIT_DEFINE(geometry)
1310
{
@@ -97,3 +94,10 @@ MODINIT_DEFINE(geometry)
9794
}
9895
return module;
9996
}
97+
98+
99+
100+
101+
102+
103+

src_c/line.c

Lines changed: 43 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
#include "include/pygame.h"
22
#include "include/geometry.h"
33
#include "include/collisions.h"
4-
#include "include/methods.h"
54

65
#include <limits.h>
76
#include <math.h>
@@ -210,29 +209,55 @@ pg_line_copy(pgLineObject *self, PyObject *_null)
210209
}
211210

212211
static PyObject *
213-
pg_line_raycast(pgLineObject *self, PyObject *sequence)
212+
pg_line_raycast(pgLineObject *self, PyObject* const* args, Py_ssize_t nargs)
214213
{
215-
PyObject *list = PyList_New(1);
214+
PyObject **farr;
215+
Py_ssize_t loop;
216216

217-
if (list == NULL) {
218-
return NULL;
217+
if (nargs != 1) {
218+
return RAISE(PyExc_TypeError, "raycast() takes exactly 1 argument");
219+
}
220+
if (!PySequence_FAST_CHECK(args[0])) {
221+
return RAISE(PyExc_TypeError,
222+
"raycast() first argument must be a sequence");
223+
}
224+
225+
Py_ssize_t length = PySequence_Fast_GET_SIZE(args[0]);
226+
227+
if (length == 0) {
228+
Py_RETURN_NONE;
219229
}
220230

221-
PyList_SET_ITEM(list, 0, (PyObject *)self);
231+
farr = PySequence_Fast_ITEMS(args[0]);
232+
233+
pgLineBase other_line;
222234

223-
PyObject *args[2] = {
224-
list,
225-
sequence,
226-
};
227-
PyObject *delete_list =
228-
pg_geometry_raycast(NULL, (PyObject *const *)args, 2);
229-
PyObject *ret = PyList_GET_ITEM(delete_list, 0);
230-
Py_INCREF(ret);
235+
double record = DBL_MAX;
236+
double closest_x = 0, closest_y = 0;
237+
double x = 0, y = 0;
231238

232-
Py_DECREF(delete_list);
233-
Py_DECREF(list);
239+
for (loop = 0; loop < length; loop++) {
240+
if (!pgLine_FromObject(farr[loop], &other_line)) {
241+
return RAISE(
242+
PyExc_TypeError,
243+
"raycast() first argument must be a sequence of Line or "
244+
"LineLike objects");
245+
}
246+
247+
if (pgIntersection_LineLine(&(self->line), &other_line, &x, &y)) {
248+
double xxyy = sqrt(x * x + y * y);
249+
if (xxyy < record) {
250+
record = xxyy;
251+
closest_x = x;
252+
closest_y = y;
253+
}
254+
}
255+
}
234256

235-
return ret;
257+
if (record == DBL_MAX) {
258+
Py_RETURN_NONE;
259+
}
260+
return Py_BuildValue("(dd)", closest_x, closest_y);
236261
}
237262

238263
static PyObject *
@@ -307,7 +332,7 @@ pg_line_update(pgLineObject *self, PyObject *const *args, Py_ssize_t nargs)
307332
static struct PyMethodDef pg_line_methods[] = {
308333
{"__copy__", (PyCFunction)pg_line_copy, METH_NOARGS, NULL},
309334
{"copy", (PyCFunction)pg_line_copy, METH_NOARGS, NULL},
310-
{"raycast", (PyCFunction)pg_line_raycast, METH_O, NULL},
335+
{"raycast", (PyCFunction)pg_line_raycast, METH_FASTCALL, NULL},
311336
{"collideline", (PyCFunction)pg_line_collideline, METH_FASTCALL, NULL},
312337
{"collidepoint", (PyCFunction)pg_line_collidepoint, METH_FASTCALL, NULL},
313338
{"collidecircle", (PyCFunction)pg_line_collidecircle, METH_FASTCALL, NULL},

src_c/methods.c

Lines changed: 0 additions & 102 deletions
This file was deleted.

tests/raycast_test.py

Lines changed: 21 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,37 +1,43 @@
1-
from shapes import raycast
2-
from shapes.line import LineSegment
1+
import geometry
32

43
import pygame
5-
import math
64
import random
5+
import math
76

87
screen = pygame.display.set_mode((800, 800))
98
collisions = []
109

10+
1111
def generate_random_lines(amt):
1212
def random_pos():
13-
return (random.randrange(0, 800), random.randrange(0, 800))
13+
return random.randrange(0, 800), random.randrange(0, 800)
1414

1515
for x in range(amt):
16-
line = LineSegment(random_pos(), random_pos())
16+
line = geometry.Line(random_pos(), random_pos())
1717
collisions.append(line)
1818

19-
generate_random_lines(55)
2019

21-
while True:
22-
for e in pygame.event.get():
23-
if e.type == pygame.QUIT:
24-
pygame.quit()
25-
20+
generate_random_lines(10)
21+
22+
running = True
23+
24+
while running:
2625
screen.fill((0, 0, 0))
2726

2827
for x in range(90):
2928
origin_pos = pygame.mouse.get_pos()
3029
ray_endpoint = pygame.Vector2(math.sin(math.degrees(x)), math.cos(math.degrees(x))) * 125 + origin_pos
31-
endpoint = raycast.raycast(origin_pos, ray_endpoint, collisions)
32-
pygame.draw.line(screen, (255, 0, 0), origin_pos, endpoint, 1)
30+
ray = geometry.Line(origin_pos, ray_endpoint)
31+
32+
point = ray.raycast(collisions) or ray_endpoint
33+
pygame.draw.line(screen, (255, 0, 0), origin_pos, point, 1)
3334

34-
for c in collisions:
35-
pygame.draw.line(screen, (0, 0, 255), c.point1, c.point2, 5)
35+
for line in collisions:
36+
pygame.draw.line(screen, (0, 0, 255), line.a, line.b, 5)
3637

3738
pygame.display.flip()
39+
40+
for e in pygame.event.get():
41+
if e.type == pygame.QUIT:
42+
pygame.quit()
43+
running = False

0 commit comments

Comments
 (0)