Gabriel Pariat
2 years ago
21 changed files with 540 additions and 222 deletions
@ -1,65 +1,24 @@ |
|||||||
(in-package :pong.client) |
(in-package :pong.client) |
||||||
|
|
||||||
(defparameter *client* nil) |
(defun main () |
||||||
|
(let* ((last-time nil) |
||||||
(defclass client () |
(current-time (get-internal-real-time))) |
||||||
((ip :initarg :ip :initform nil :reader client-ip) |
(r:with-window (800 600 "Pariatech's Pong") |
||||||
(port :initarg :port :initform nil :reader client-port) |
(gui:with-gui |
||||||
(running-p :initform nil :accessor client-running-p) |
(open-main-menu) |
||||||
(socket :initform nil :accessor client-socket))) |
|
||||||
|
(r:set-config-flags r:+flag-window-resizable+) |
||||||
(defmethod listen-to ((self client)) |
(r:set-target-fps 60) |
||||||
(with-slots (running-p socket) self |
(r:set-exit-key 0) |
||||||
(when (and running-p (usocket:wait-for-input socket :timeout 5) running-p) |
(loop |
||||||
(let ((data (cpk:decode-stream (usocket:socket-stream socket)))) |
until (or (r:window-should-close) (scene-should-close *scene*)) |
||||||
(format t "[CLIENT] Data received: ~a~%" data))))) |
do (setf last-time current-time) |
||||||
|
(setf current-time (/ (get-internal-real-time) internal-time-units-per-second)) |
||||||
(defmethod start ((self client)) |
|
||||||
(with-slots (ip port running-p socket) self |
(let ((timelapse (- current-time last-time))) |
||||||
(format t "uh?~%") |
(on-update *scene* timelapse)) |
||||||
(unless running-p |
(r:with-drawing |
||||||
(setf running-p t) |
(r:clear-background r:+gray+) |
||||||
(setf socket (usocket:socket-connect ip port :element-type 'unsigned-byte))))) |
(on-draw *scene*) |
||||||
|
(r:draw-fps 20 20))))))) |
||||||
(defmethod stop ((self client)) |
|
||||||
(with-slots (running-p socket) self |
|
||||||
(setf running-p nil) |
|
||||||
(when socket |
|
||||||
(usocket:socket-close socket)) |
|
||||||
(setf socket nil))) |
|
||||||
|
|
||||||
(defmethod write-to ((self client) data) |
|
||||||
(let ((stream (usocket:socket-stream (client-socket self)))) |
|
||||||
(format t "[CLIENT] Data sent: ~a~%" data) |
|
||||||
(cpk:encode data :stream stream) |
|
||||||
(force-output stream))) |
|
||||||
|
|
||||||
(defun handle-client () |
|
||||||
(loop while (and *client* (client-running-p *client*)) |
|
||||||
do (let ((data (listen-to *client*)))))) |
|
||||||
|
|
||||||
(defun start-client (ip port) |
|
||||||
(unless *client* |
|
||||||
(setf *client* (make-instance 'client :ip ip :port port)) |
|
||||||
(start *client*) |
|
||||||
(bt:make-thread #'handle-client))) |
|
||||||
|
|
||||||
(defun stop-client () |
|
||||||
(when *client* |
|
||||||
(stop *client*)) |
|
||||||
(setf *client* nil)) |
|
||||||
|
|
||||||
(defun send-data-to-server (data) |
|
||||||
(write-to *client* data)) |
|
||||||
|
|
||||||
(defun test-client () |
|
||||||
(start-client "127.0.0.1" 54321) |
|
||||||
(write-to *client* "hello!") |
|
||||||
(sleep 1.015) |
|
||||||
(write-to *client* "bye!") |
|
||||||
(stop-client)) |
|
||||||
|
|
||||||
;; (test-client) |
|
||||||
|
|
||||||
;; (stop-client) |
|
||||||
|
|
||||||
|
@ -0,0 +1,53 @@ |
|||||||
|
(in-package #:gui) |
||||||
|
|
||||||
|
(defclass text-field (text) |
||||||
|
((focusp :initarg :focusp :initform nil :accessor focusp) |
||||||
|
(border :initarg :border :initform :solid :accessor border) |
||||||
|
(border-color :initarg :border-color :initform r:+black+ :accessor border-color) |
||||||
|
(border-thickness :initarg :border-thickness :initform 1 :accessor border-thickness) |
||||||
|
(cursor :initarg :cursor :initform nil :accessor cursor) |
||||||
|
(padding :initarg :padding :initform 0 :accessor padding))) |
||||||
|
|
||||||
|
(defmethod calculate-size ((txt text-field)) |
||||||
|
(with-slots (w h font font-size text spacing padding) txt |
||||||
|
(when (and font text) |
||||||
|
(let ((size (r:measure-text-ex (load-font font font-size) |
||||||
|
text |
||||||
|
(float font-size) |
||||||
|
spacing))) |
||||||
|
(setf w (+ (v:vx size) (* padding 2))) |
||||||
|
(setf h (+ (v:vy size) (* padding 2))) |
||||||
|
(update-x txt) |
||||||
|
(update-y txt))))) |
||||||
|
|
||||||
|
(defmethod draw ((self text-field)) |
||||||
|
(with-slots (font font-size text screen-x screen-y w h color spacing visible focusp border border-thickness border-color cursor padding) self |
||||||
|
(when visible |
||||||
|
(when border |
||||||
|
(r:draw-rectangle-lines-ex (r:make-rectangle :x screen-x |
||||||
|
:y screen-y |
||||||
|
:width w |
||||||
|
:height h) |
||||||
|
(float border-thickness) |
||||||
|
border-color)) |
||||||
|
(when focusp |
||||||
|
(r:draw-line-e) |
||||||
|
(r:draw-text-ex (load-font font font-size) |
||||||
|
(concatenate 'string |
||||||
|
(str:repeat cursor " ") |
||||||
|
(string #\left_one_eighth_block)) |
||||||
|
(v:vec (float (+ screen-x padding)) (float (+ screen-y padding))) |
||||||
|
(float font-size) |
||||||
|
spacing |
||||||
|
color)) |
||||||
|
(when text |
||||||
|
(r:draw-text-ex (load-font font font-size) |
||||||
|
text |
||||||
|
(v:vec (float (+ screen-x padding)) (float (+ screen-y padding))) |
||||||
|
(float font-size) |
||||||
|
spacing |
||||||
|
color))))) |
||||||
|
|
||||||
|
(defmacro make-text-field (&rest args) |
||||||
|
`(make-instance 'text-field ,@args)) |
||||||
|
|
@ -0,0 +1,81 @@ |
|||||||
|
(in-package :pong.client) |
||||||
|
|
||||||
|
(defclass join-online-game-scene (scene) |
||||||
|
((name :initform "" :accessor join-online-game-scene-name) |
||||||
|
(code :initform "" :accessor join-online-game-scene-code) |
||||||
|
(title :initarg :title :initform nil :reader join-online-game-scene-title) |
||||||
|
(name-field :initarg :name-field |
||||||
|
:initform nil |
||||||
|
:reader join-online-game-scene-name-field) |
||||||
|
(name-prompt :initarg :name-prompt |
||||||
|
:initform nil |
||||||
|
:reader join-online-game-scene-name-prompt) |
||||||
|
(code-field :initarg :code-field |
||||||
|
:initform nil |
||||||
|
:reader join-online-game-scene-code-field) |
||||||
|
(code-prompt :initarg :code-prompt |
||||||
|
:initform nil |
||||||
|
:reader join-online-game-scene-code-prompt) |
||||||
|
(join-button :initarg :join-button |
||||||
|
:initform nil |
||||||
|
:reader join-online-game-scene-join-button))) |
||||||
|
|
||||||
|
(defun open-join-online-game-scene () |
||||||
|
(let ((root-element (gui:make-rectangle :color r:+darkgray+ |
||||||
|
:h-align :center |
||||||
|
:v-align :middle)) |
||||||
|
(title (gui:make-text :color r:+white+ |
||||||
|
:font +menu-font+ |
||||||
|
:font-size +menu-title-font-size+ |
||||||
|
:y +title-top-padding+ |
||||||
|
:h-align :center |
||||||
|
:text "Join online game")) |
||||||
|
(name-field (gui:make-text-field :color r:+white+ |
||||||
|
:font +menu-font+ |
||||||
|
:font-size +menu-font-size+ |
||||||
|
:focusp t |
||||||
|
:border :solid |
||||||
|
:border-color r:+white+ |
||||||
|
:border-thickness 1 |
||||||
|
:cursor 0 |
||||||
|
:padding 5)) |
||||||
|
(name-prompt (gui:make-text :color r:+white+ |
||||||
|
:font +menu-font+ |
||||||
|
:font-size +menu-font-size+ |
||||||
|
:h-align :right |
||||||
|
:v-align :middle |
||||||
|
:text "What is your name?:"))) |
||||||
|
|
||||||
|
(gui:add-children root-element title name-field name-prompt) |
||||||
|
|
||||||
|
(set-scene (make-instance 'join-online-game-scene :root-element root-element |
||||||
|
:title title |
||||||
|
:name-field name-field |
||||||
|
:name-prompt name-prompt)))) |
||||||
|
|
||||||
|
(defmethod on-update ((scene join-online-game-scene) timelapse) |
||||||
|
(with-slots (name move-back) scene |
||||||
|
;; Might be interesting to add repeating keys, but I don't care. |
||||||
|
(loop for key = (r:get-key-pressed) |
||||||
|
while (plusp key) |
||||||
|
do (format t "~a~%" key) |
||||||
|
when (= key r:+key-escape+) |
||||||
|
do (open-main-menu) |
||||||
|
when (= key r:+key-backspace+) |
||||||
|
do (setf name (str:substring 0 -1 name)) |
||||||
|
;; when (= key r:+key-enter+) |
||||||
|
;; do (create-online-game name) |
||||||
|
when (and (>= key 32) (<= key 96)) |
||||||
|
do (setf name (str:concat name (string (code-char key)))))) |
||||||
|
) |
||||||
|
|
||||||
|
(defmethod on-draw ((scene join-online-game-scene)) |
||||||
|
(with-slots (name code root-element title name-field name-prompt) scene |
||||||
|
(position-root root-element) |
||||||
|
(setf (gui:x title) (floor (gui:w root-element) 2)) |
||||||
|
(setf (gui:text name-field) name) |
||||||
|
(setf (gui:x name-field) (+ (floor (gui:w root-element) 2) +score-padding+)) |
||||||
|
(setf (gui:x name-prompt) (- (floor (gui:w root-element) 2) +score-padding+)) |
||||||
|
(setf (gui:y name-field) (floor (gui:h root-element) 2)) |
||||||
|
(setf (gui:y name-prompt) (floor (gui:h root-element) 2))) |
||||||
|
) |
@ -1,5 +1,4 @@ |
|||||||
(defpackage :pong.client |
(defpackage :pong.client |
||||||
(:use :cl) |
(:use :cl) |
||||||
(:local-nicknames (:r :raylib) |
(:local-nicknames (:r :raylib) |
||||||
(:v :3d-vectors) |
(:v :3d-vectors))) |
||||||
(:g :pong.game))) |
|
||||||
|
@ -0,0 +1,31 @@ |
|||||||
|
(in-package :pong.game) |
||||||
|
|
||||||
|
(defclass game-action-message () |
||||||
|
((game-code :initarg :game-code :initform nil :reader game-code) |
||||||
|
(game-action :initarg :game-action :initform nil :reader game-action))) |
||||||
|
|
||||||
|
(defclass state-updated-message () |
||||||
|
((game-state :initarg :game-state :initform nil :reader game-state))) |
||||||
|
|
||||||
|
(defclass create-game-message () |
||||||
|
((player-name :initarg :player-name :initform nil :reader player-name))) |
||||||
|
|
||||||
|
(defclass join-game-message () |
||||||
|
((game-code :initarg :game-code :initform nil :reader game-code) |
||||||
|
(player-name :initarg :player-name :initform nil :reader player-name))) |
||||||
|
|
||||||
|
(defclass game-created-message () |
||||||
|
((game-code :initarg :game-code :initform nil :reader game-code) |
||||||
|
(player-paddle :initarg :player-paddle :initform nil :reader player-paddle) |
||||||
|
(game-state :initarg :game-state :initform nil :reader game-state))) |
||||||
|
|
||||||
|
(defclass game-joined-message () |
||||||
|
((player-paddle :initarg :player-paddle :initform nil :reader player-paddle) |
||||||
|
(game-state :initarg :game-state :initform nil :reader game-state))) |
||||||
|
|
||||||
|
(cpk:defencoding game-action-message game-code game-action) |
||||||
|
(cpk:defencoding state-updated-message game-state) |
||||||
|
(cpk:defencoding create-game-message player-name) |
||||||
|
(cpk:defencoding join-game-message game-code player-name) |
||||||
|
(cpk:defencoding game-created-message game-code player-paddle game-state) |
||||||
|
(cpk:defencoding game-joined-message player-paddle game-state) |
@ -0,0 +1,14 @@ |
|||||||
|
(defun print-object-readably (object) |
||||||
|
(let ((slots (map 'list #'c2mop:slot-definition-name (c2mop:class-slots (class-of object)))) |
||||||
|
(class (class-name (class-of object)))) |
||||||
|
(cons class (remove-if #'null |
||||||
|
(loop for slot in slots |
||||||
|
collect (if (slot-boundp object slot) |
||||||
|
(cons slot (slot-value object slot)))))))) |
||||||
|
|
||||||
|
(defun read-object (sexp) |
||||||
|
(let* ((class (car sexp)) |
||||||
|
(object (make-instance class))) |
||||||
|
(loop for slot in (cdr sexp) |
||||||
|
do (setf (slot-value object (car slot)) (cdr slot))) |
||||||
|
object)) |
@ -1,3 +1,3 @@ |
|||||||
(defpackage :pong.server |
(defpackage :pong.server |
||||||
(:use :cl) |
(:use :cl) |
||||||
(:local-nicknames (:g :pong.game))) |
(:nicknames :s)) |
||||||
|
Loading…
Reference in new issue