diff --git a/game.lisp b/lisp-version/game.lisp similarity index 61% rename from game.lisp rename to lisp-version/game.lisp index 2c86f94..ba7e62e 100644 --- a/game.lisp +++ b/lisp-version/game.lisp @@ -1,5 +1,5 @@ (eval-when (:compile-toplevel :load-toplevel :execute) - (load "~/.local/share/quicklisp/setup.lisp") + ;; (load "~/.local/share/quicklisp/setup.lisp") (ql:quickload :cl-raylib) (ql:quickload :livesupport)) @@ -10,6 +10,19 @@ (in-package :raylib-user) (defparameter *move-speed* 5.0) +(defparameter *tower-pos* (vec 80 150)) +(defparameter *tower-center* (vec 64 220)) +(defparameter *assets-path* "~/Development/tinyswords/assets/") +(defparameter *camera* (rl:make-camera2d :offset (vec 0 0) :target (vec 0 0) :rotation 0.0 :zoom 1.0)) + +(defparameter *mouse-drag-start-pos* (vec 0 0)) +(defparameter *camera-drag-start-pos* (vec 0 0)) +(defparameter *unit-select-drag-start-pos* (vec 0 0)) +(defparameter *camera-dragging?* nil) +(defparameter *unit-select-dragging?* nil) + +(defparameter *game-state* nil) +(defparameter *textures* (make-hash-table)) (defclass health () ((current-amount :initform 100.0 :accessor current-amount) @@ -29,6 +42,7 @@ (defclass soldier () ((pos :initarg :pos :initform (vec 0 0) :accessor pos) (anim-state :initform 0 :accessor anim-state) + (entity-type :initarg :entity-type :initform nil :accessor entity-type) (sprite :initarg :sprite :initform (make-instance 'sprite-class) :accessor sprite) (velocity :initform (vec 0 0) :accessor velocity) (health :initarg :health :initform (make-instance 'health) :accessor health))) @@ -36,6 +50,7 @@ (defparameter *knight* (make-instance 'soldier + :entity-type ':soldier :pos (vec 270 360) :sprite (make-instance 'sprite-class @@ -46,6 +61,7 @@ (defparameter *archer* (make-instance 'soldier + :entity-type :archer :pos (vec 145.0 253.0) :sprite (make-instance 'sprite-class @@ -53,6 +69,17 @@ :src-rect (rl:make-rectangle :x 0.0 :y 0.0 :width 192.0 :height 192.0) :origin (vec 95.0 128.0)))) +(defparameter *goblin* + (make-instance + 'soldier + :entity-type :goblin + :pos (vec 445.0 300.0) + :sprite (make-instance + 'sprite-class + :texture-key 'goblin + :src-rect (rl:make-rectangle :x 0.0 :y 0.0 :width 192.0 :height 192.0) + :origin (vec 95.0 128.0)))) + (defun deal-damage (obj damage) (with-accessors ((h health)) obj (setf h (- h damage)))) @@ -63,26 +90,44 @@ ((click-pos :initform nil :accessor click-pos) (entities :initform '() :accessor entities))) -(defparameter *game-state* nil) -(defparameter *textures* (make-hash-table)) - (defun bind-texture (key path) - (setf (gethash key *textures*) (rl:load-texture (uiop:native-namestring path)))) + (setf (gethash key *textures*) (rl:load-texture (uiop:native-namestring (merge-pathnames path *assets-path*))))) (defun game-init () (setf *game-state* (make-instance 'game-state)) - (setf (entities *game-state*) (list *knight* *archer*)) + (setf (entities *game-state*) (list *knight* *archer* *goblin*)) ;; (add-component (knight *game-state*) (make-instance 'transform)) - (bind-texture 'terrain "~/Development/tinyswords/assets/Terrain/Ground/Tilemap_Flat.png") - (bind-texture 'knight "~/Development/tinyswords/assets/Factions/Knights/Troops/Warrior/Blue/Warrior_Blue.png") - (bind-texture 'archer "~/Development/tinyswords/assets/Factions/Knights/Troops/Archer/Blue/Archer_Blue.png") - (bind-texture 'tower "~/Development/tinyswords/assets/Factions/Knights/Buildings/Tower/Tower_Blue.png")) + (bind-texture 'terrain "Terrain/Ground/Tilemap_Flat.png") + (bind-texture 'knight "Factions/Knights/Troops/Warrior/Blue/Warrior_Blue.png") + (bind-texture 'archer "Factions/Knights/Troops/Archer/Blue/Archer_Blue.png") + (bind-texture 'tower "Factions/Knights/Buildings/Tower/Tower_Blue.png") + (bind-texture 'goblin "Factions/Goblins/Troops/Torch/Red/Torch_Red.png")) (defun game-input () (when (rl:is-mouse-button-pressed 0) - (setf (click-pos *game-state*) (print (rl:get-mouse-position)))) - (when (rl:is-mouse-button-pressed 1) - (setf (click-pos *game-state*) (print (rl:get-mouse-position))))) + (if (rl:is-key-down :key-left-control) + (progn + (setf *camera-dragging?* t) + (v<- *camera-drag-start-pos* (rl:camera2d-target *camera*))) + (progn + (setf *unit-select-dragging?* t) + (v<- *unit-select-drag-start-pos* (rl:camera2d-target *camera*)))) + (v<- *mouse-drag-start-pos* (rl:get-mouse-position))) + ;; (princ (rl:get-mouse-wheel-move)) + (setf (rl:camera2d-zoom *camera*) + (alexandria:clamp (exp (+ (log (rl:camera2d-zoom *camera*)) + (* (rl:get-mouse-wheel-move) 0.1))) + 1.0 2.0)) + (when (rl:is-mouse-button-released 0) + (setf *camera-dragging?* nil) + (setf *unit-select-dragging?* nil)) + (when (rl:is-key-down :key-r) (setf (rl:camera2d-target *camera*) (vec 0 0)))) + +;; (defun game-input () +;; (when (rl:is-mouse-button-pressed 0) +;; (setf (click-pos *game-state*) (print (rl:get-mouse-position)))) +;; (when (rl:is-mouse-button-pressed 1) +;; (setf (click-pos *game-state*) (print (rl:get-mouse-position))))) ;; (with-slots ((pos archer-pos) (kpos knight-pos)) *game-state* ;; (let ((dx 0.0) (dy 0.0)) ;; (when (rl:is-key-down :key-right) (incf dx 1)) @@ -91,7 +136,22 @@ ;; (when (rl:is-key-down :key-down) (incf dy 1)) ;; (setf pos (v+ pos (v* (vunit* (vec dx dy)) *move-speed*)))))) +(defun goblin-fsm () + (dolist (entity (entities *game-state*)) + (when (eq (entity-type entity) :goblin) + (let* ((target-dist (v- (v+ *tower-pos* *tower-center*) (pos entity))) + (dir (vunit* target-dist))) + (setf (anim-idx (sprite entity)) 1) + (setf (pos entity) (v+ (pos entity) (v* dir 1))))))) + +(defun calculate-camera-drag () + (let* ((target-pos (v- (rl:get-mouse-position) + *mouse-drag-start-pos*))) + (setf (rl:camera2d-target *camera*) (v+ *camera-drag-start-pos* (v* -1 target-pos))))) + (defun game-update () + (when *camera-dragging?* + (calculate-camera-drag)) (with-accessors ((click-pos click-pos)) *game-state* (when click-pos (with-accessors ((kpos pos)) *knight* @@ -103,10 +163,11 @@ (setf kpos click-pos) ;; (setf (velocity *knight*) (vec 0 0)) (setf click-pos nil)) - (let ((vel (v* (* (rl:get-frame-time) 150.0) (vunit* dist)))) + (let ((vel (v* (* (rl:get-frame-time) 240.0) (vunit* dist)))) (setf (anim-idx (sprite *knight*)) 1) (setf (velocity *knight*) vel) (setf kpos (v+ kpos vel)))))))) + (goblin-fsm) (dolist (entity (entities *game-state*)) (tick-sprite-animation (sprite entity) (< (vx (velocity entity)) 0.0)))) @@ -157,22 +218,36 @@ :height (abs (rl:rectangle-height src-rect))))) (rl:draw-texture-pro (gethash texture-key *textures*) src-rect dst-rec origin 0.0 :white)))) +(defun draw-unit-select-rect () + (let* ((start-x (vx *mouse-drag-start-pos*)) + (start-y (vy *mouse-drag-start-pos*)) + (end-x (rl:get-mouse-x)) + (end-y (rl:get-mouse-y)) + (x (min start-x end-x)) + (y (min start-y end-y)) + (rect (rl:make-rectangle :x x :y y :width (abs (- end-x start-x)) :height (abs (- end-y start-y))))) + (rl:draw-rectangle-lines-ex rect 2.0 :raywhite))) + (defun game-draw () (rl:clear-background (rl:make-rgba 71 171 169 1)) - (draw-ground) - (rl:draw-texture-v (gethash 'tower *textures*) (vec 80 150) :white) - (dolist (entity (entities *game-state*)) - (draw-sprite (sprite entity) (pos entity))) + (rl:with-mode-2d (*camera*) + (draw-ground) + (rl:draw-texture-v (gethash 'tower *textures*) *tower-pos* :white) + (dolist (entity (entities *game-state*)) + (draw-sprite (sprite entity) (pos entity)))) + (when *unit-select-dragging?* + (draw-unit-select-rect)) (rl:draw-fps 10 10)) (defun game () - (let* ((screen-width 900) - (screen-height 500)) + (let* ((screen-width 1600) + (screen-height 900)) (rl:with-window (screen-width screen-height "RTS") - (rl:set-target-fps 240) + (rl:set-target-fps 60) (game-init) (loop :until (rl:window-should-close) - :do (livesupport:continuable (game-input) + :do (livesupport:continuable + (game-input) (game-update) (rl:with-drawing (game-draw))))