summaryrefslogtreecommitdiff
path: root/lisparuga/actor.scm
blob: c7caab29712a9e08e25dd8b8e13268da99a154ad (plain)
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
;;; Lisparuga
;;; Copyright © 2020 David Thompson <dthompson2@worcester.edu>
;;;
;;; Lisparuga is free software: you can redistribute it and/or modify
;;; it under the terms of the GNU General Public License as published
;;; by the Free Software Foundation, either version 3 of the License,
;;; or (at your option) any later version.
;;;
;;; Lisparuga is distributed in the hope that it will be useful, but
;;; WITHOUT ANY WARRANTY; without even the implied warranty of
;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
;;; General Public License for more details.
;;;
;;; You should have received a copy of the GNU General Public License
;;; along with Lisparuga.  If not, see <http://www.gnu.org/licenses/>.

;;; Commentary:
;;
;; A class representing a scripted or player-controller object in the
;; game world.  Actors can emit bullets and have many hitboxes.
;;
;;; Code:


(define-module (lisparuga actor)
  #:use-module (chickadee math vector)
  #:use-module (chickadee math rect)
  #:use-module (lisparuga node)
  #:use-module (lisparuga node-2d)
  #:use-module (oop goops)
  #:use-module (srfi srfi-9)
  #:export (make-hitbox
            hitbox?
            hitbox-name
            hitbox-rect

            world-hitbox?
            world-hitbox-collision?
            world-hitbox-parent

            <actor>
            polarity
            velocity
            hitboxes
            world-hitboxes
            on-collision
            bullet-field))


;;;
;;; Hitboxes
;;;

(define-record-type <hitbox>
  (make-hitbox name rect)
  hitbox?
  (name hitbox-name)
  (rect hitbox-rect))

(define-record-type <world-hitbox>
  (%make-world-hitbox parent rect)
  world-hitbox?
  (parent world-hitbox-parent)
  (rect world-hitbox-rect))

(define (make-world-hitbox parent)
  (let ((r (hitbox-rect parent)))
    (%make-world-hitbox parent
                        (make-rect 0.0 0.0 (rect-width r) (rect-height r)))))

(define (sync-world-hitbox world-hitbox position)
  (rect-move-vec2! (world-hitbox-rect world-hitbox) position))

(define (world-hitbox-collision? a b)
  (if (world-hitbox? b)
      (rect-intersects? (world-hitbox-rect a) (world-hitbox-rect b))
      (rect-intersects? (world-hitbox-rect a) b)))


;;;
;;; Actors
;;;

(define-class <actor> (<node-2d>)
  (polarity #:accessor polarity #:init-form 'none #:init-keyword #:polarity)
  (velocity #:getter velocity #:init-form (vec2 0.0 0.0))
  (hitboxes #:accessor hitboxes #:init-form '() #:init-keyword #:hitboxes)
  (world-hitboxes #:accessor world-hitboxes #:init-form '())
  (bullet-field #:accessor bullet-field #:init-keyword #:bullet-field))

(define-method (initialize (actor <actor>) initargs)
  (next-method)
  (set! (world-hitboxes actor)
    (map make-world-hitbox (hitboxes actor))))

(define-method (update (actor <actor>) dt)
  (let ((v (velocity actor)))
    (unless (and (= (vec2-x v) 0.0)
                 (= (vec2-y v) 0.0))
      ;; Move by current velocity.
      (vec2-add! (position actor) v)
      ;; Sync hitboxes to world coordinates.
      (let ((pos (position actor)))
        (for-each (lambda (world-hitbox)
                    (sync-world-hitbox world-hitbox pos))
                  (world-hitboxes actor)))
      ;; Mark for matrix updates.
      (dirty! actor))))

;; Actor-actor collision event.
(define-method (on-collision (actor <actor>) (other-actor <actor>)
                             hitbox other-hitbox)
  #t)