Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ClojureScript yasunori block #113

Merged
merged 31 commits into from
Oct 12, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
ba58497
first commit
conao3 Oct 12, 2024
a6ec891
use rebel-readline-cljs
conao3 Oct 12, 2024
8e35b7e
follow tutorial
conao3 Oct 12, 2024
0248857
use :fig alias
conao3 Oct 12, 2024
905e8c8
define app
conao3 Oct 12, 2024
e9f9abf
use run as function name
conao3 Oct 12, 2024
7e550be
change title
conao3 Oct 12, 2024
3d7a70c
use first reagent state
conao3 Oct 12, 2024
eadf5ce
add timer
conao3 Oct 12, 2024
96b3ad2
add event loop
conao3 Oct 12, 2024
3a4c0f1
add ball calc logic
conao3 Oct 12, 2024
eb1a8a8
paddle is moveable
conao3 Oct 12, 2024
31e4e4a
draw block
conao3 Oct 12, 2024
2d1d4b8
collision with block
conao3 Oct 12, 2024
04a0ae5
add game win check
conao3 Oct 12, 2024
2fe96aa
update cljs
conao3 Oct 12, 2024
0675c7d
refine paddle refrection
conao3 Oct 12, 2024
1769abe
use h
conao3 Oct 12, 2024
3b59fe0
use math/PI insead of js/Math.PI
conao3 Oct 12, 2024
b740bbe
refine const
conao3 Oct 12, 2024
a1fd2de
add README
conao3 Oct 12, 2024
e8f018b
remove unneeded gitignore entry
conao3 Oct 12, 2024
feb5db4
remove unneeded debug print
conao3 Oct 12, 2024
4c098b6
refine let
conao3 Oct 12, 2024
e844169
use dist as production directory
conao3 Oct 12, 2024
5717452
change js path in production HTML
conao3 Oct 12, 2024
bf0f612
use python as simple HTPP server
conao3 Oct 12, 2024
aad0c1a
output optimized file to the same relationship position as dev
conao3 Oct 12, 2024
8ee75b2
use strict dot form
conao3 Oct 12, 2024
df79f05
Create wrangler.toml for deploy
tomoya Oct 12, 2024
3cabb3d
Create Cljs Breakout workflow
tomoya Oct 12, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 49 additions & 0 deletions .github/workflows/cljs-breakout.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
name: Cljs Breakout

on:
push:
branches:
- main
paths:
- '.github/workflows/cljs-breakout.yml'
- 'packages/cljs-yasunori-block/**'
pull_request:
paths:
- '.github/workflows/cljs-breakout.yml'
- 'packages/cljs-yasunori-block/**'
types: [opened, synchronize, reopened, ready_for_review]

jobs:
deploy-cljs-breakout:
name: Deploy Cljs Breakout
if: github.event.pull_request.draft == false
runs-on: ubuntu-latest
defaults:
run:
working-directory: packages/cljs-yasunori-block
steps:
- uses: actions/checkout@v4
- uses: actions/setup-java@v4
with:
distribution: 'graalvm'
java-version: '22'
- uses: DeLaGuardo/setup-clojure@12.5
with:
cli: 1.11.4.1474
- uses: actions/cache@v4
with:
path: |
~/.m2/repository
~/.gitlibs
~/.deps.clj
key: cljdeps-${{ hashFiles('deps.edn') }}
restore-keys: cljdeps-
- name: Build
run: make yasunori
- name: Deploy
uses: cloudflare/wrangler-action@v3
with:
workingDirectory: packages/cljs-yasunori-block # working-directoryを付けていても必要
apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }}
accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
command: pages deploy
3 changes: 3 additions & 0 deletions packages/cljs-yasunori-block/.dir-locals.el
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
((clojure-mode . ((cider-clojure-cli-aliases . ":fig")
(cider-default-cljs-repl . figwheel-main)
(cider-figwheel-main-default-options . "dev"))))
5 changes: 5 additions & 0 deletions packages/cljs-yasunori-block/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
/.cpcache
/target
/.nrepl-port
/cljs-yasunori-block.iml
/dist
14 changes: 14 additions & 0 deletions packages/cljs-yasunori-block/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
all:

.PHONY: dev
dev:
clojure -A:fig -M -m figwheel.main --build dev --repl

.PHONY: yasunori
yasunori:
clojure -A:fig -M -m figwheel.main --optimizations advanced --output-to dist/public/cljs-out/dev-main.js --build-once dev
rsync -av resources/ dist

.PHONY: clean
clean:
rm -rf target dist
16 changes: 16 additions & 0 deletions packages/cljs-yasunori-block/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# cljs-yasunori-block

![](https://github.com/user-attachments/assets/7a1ff289-b342-4ba1-b664-cbdb0b402a33)

# Start dev server

```bash
make dev
```

# Build

```bash
make yasunori
python -m http.server -d dist/public
```
11 changes: 11 additions & 0 deletions packages/cljs-yasunori-block/deps.edn
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{:deps {org.clojure/clojure {:mvn/version "1.12.0"}
org.clojure/clojurescript {:mvn/version "1.11.132"}
cljsjs/react {:mvn/version "17.0.2-0"}
cljsjs/react-dom {:mvn/version "17.0.2-0"}
reagent/reagent {:mvn/version "1.1.1"}}
:paths ["src" "resources"]
:aliases {:fig {:extra-deps
{com.bhauman/figwheel-main {:mvn/version "0.2.18"}
com.bhauman/rebel-readline-cljs {:mvn/version "0.1.4"}
org.slf4j/slf4j-nop {:mvn/version "1.7.30"}}
:extra-paths ["target"]}}}
1 change: 1 addition & 0 deletions packages/cljs-yasunori-block/dev.cljs.edn
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{:main yasunori-block.core}
11 changes: 11 additions & 0 deletions packages/cljs-yasunori-block/resources/public/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
</head>
<body>
<div id="app">
</div>
<script src="cljs-out/dev-main.js" type="text/javascript"></script>
</body>
</html>
209 changes: 209 additions & 0 deletions packages/cljs-yasunori-block/src/yasunori_block/app.cljs
Original file line number Diff line number Diff line change
@@ -0,0 +1,209 @@
(ns yasunori-block.app
(:require
[cljs.math :as math]
[reagent.core :as reagent]))

(def yasunori
["xxxx xxxx xxx xxxxxxxx xx xx xxx xxx xxxxxx xxxxxxx xx"
" xxxx xxxx xxxxx xxxxxxxxxxxxx xxxx xxxx xxx xxxxxxxx xxx xxx xxxx"
" xxxxxxxx xxx xxx xxxxxxx xxxx xxxx xxxxxxxxx xxxx xxxx xxx xxx xxxx"
" xxxxxx xxx xxx xxxxx xxxx xxxx xxxxxxxxx xxxx xxxx xxxxxxx xxxx"
" xxxx xxxxxxxxxxx xxxxxxx xxxxxxxxxx xxx xxxx xxxxxxxxxx xxx xxx xxxx"
" xxxx xxxx xxxx xxxxxxx xxxxxxxx xxx xxx xxxxxxxx xxx xxxx xxxx"])

(defn Timer [{:keys [:seconds-elapsed]}]
[:div
[:p "Seconds Elapsed: " seconds-elapsed "s"]])

(defn h [arg]
(/ arg 2))

(defn Title []
[:h1 "cljs-yasunori-block"])

(defn initial-state [width height]
{:ball {:cx (h width) :cy height :radius 5 :dx -4 :dy -5}
:paddle {:cx (h width) :cy height :width 200 :height 20}
:speed-multiplier 1.2
:speed-max 15
:blocks (let [blpadding 60 ; block-left-padding
btpadding 100 ; block-top-padding
bwidth 10
bwidth-gap 1
bheight 10
bheight-gap 1]
(->> yasunori
(map-indexed
(fn [iinx ielm]
(map-indexed
(fn [jinx jelm]
(when (= \x jelm)
{:cx (+ blpadding
(* (+ bwidth bwidth-gap) jinx))
:cy (+ btpadding
(* (+ bheight bheight-gap) iinx))
:width bwidth
:height bheight}))
ielm)))
flatten))})

(defn Main []
(let [canvas (atom nil)
width 1000
height 500
is-running (reagent/atom false)
state (reagent/atom (initial-state width height))
ticks (reagent/atom 0)
seconds-elapsed (reagent/atom 0)
seconds-timeout-id (reagent/atom nil)]
(letfn [(debounce []
(= 0 (mod @ticks 50)))

(draw-centered-rect [ctx {:keys [:cx :cy :width :height]}]
(. ctx fillRect (- cx (h width)) (- cy (h height)) width height))

(draw-centered-circle [ctx {:keys [:cx :cy :radius]}]
(. ctx beginPath)
(. ctx arc cx cy radius 0 (* js/Math.PI 2))
(. ctx fill)
(. ctx closePath))

(draw-ball [ctx]
(let [{:keys [:ball]} @state]
(set! (. ctx -fillStyle) "0095DD")
(draw-centered-circle ctx ball)))

(draw-paddle [ctx]
(let [{:keys [:paddle]} @state]
(set! (. ctx -fillStyle) "#0095DD")
(draw-centered-rect ctx paddle)))

(draw-blocks [ctx]
(let [{:keys [:blocks]} @state]
(set! (. ctx -fillStyle) "0095DD")
(doseq [elm blocks]
(draw-centered-rect ctx elm))))

(draw-1 [ctx]
;; 初期化
(. ctx clearRect 0 0 width height)

;; 現在の状態を描く
(draw-paddle ctx)
(draw-ball ctx)
(draw-blocks ctx)

;; 左右の壁との衝突 -> dxを符号反転
(let [{:keys [:cx :radius :dx]} (:ball @state)]
(when (or (< width (+ cx dx radius))
(< (+ cx dx (- radius)) 0))
(swap! state update-in [:ball :dx] -)))

;; 上の壁との衝突 -> dyを符号反転
(let [{:keys [:cy :radius :dy]} (:ball @state)]
(when (< (+ cy dy (- radius)) 0)
(swap! state update-in [:ball :dy] -)))

;; 下の壁との衝突
;; - パドル: dyを符号反転
;; - それ以外: ゲームオーバー
(let [{:keys [:speed-max :speed-multiplier :ball :paddle]} @state
{:keys [:cx :cy :radius :dx :dy]} ball
{pcx :cx pwidth :width} paddle]
(when (< height (+ cy dy radius))
(if (and (< (- pcx (h pwidth)) cx) (< cx (+ pcx (h pwidth))))
(swap! state update :ball
#(let [relative-pos (/ (- cx pcx) (h width))
reflect-rad (* relative-pos (/ math/PI 4))
speed (min speed-max
(* (math/sqrt (+ (* dx dx) (* dy dy)))
speed-multiplier))]
(-> %
(assoc :dx (* (math/sin reflect-rad) speed))
(assoc :dy (- (* (math/cos reflect-rad) speed))))))
(end-game))))

;; ブロックとの衝突
(let [{:keys [:dx :dy] :as ball} (:ball @state)
;; FIXME: 面倒なのでボールが一旦動いたとして、その中心座標がブロックの内部にあるか検査することにする
;; : ボールがある程度速い場合、当たり判定なしにすり抜けることがある
;; : ボールがある程度大きい場合、半径を無視していることに気付く可能性がある
{:keys [:cx :cy]} (-> ball
(update :cx + dx)
(update :cy + dy))
before-blocks-cnt (count (:blocks @state))]
(swap! state update :blocks
#(->> %
(filter
(complement
(fn [{bcx :cx bcy :cy bwidth :width bheight :height}]
(and (< (- bcx (h bwidth)) cx) (< cx (+ bcx (h bwidth)))
(< (- bcy (h bheight)) cy) (< cy (+ bcy (h bheight)))))))))

;; ボールが減っている場合、dyを符号反転
(when-not (= before-blocks-cnt (count (:blocks @state)))
(swap! state update-in [:ball :dy] -)))

;; 終了判定
(when (= 0 (count (:blocks @state)))
(js/alert "Congratulations! :tada:")
(end-game))

;; ボールを動かす
(swap! state update :ball #(-> %
(update :cx + (:dx %))
(update :cy + (:dy %)))))

(draw []
(when (debounce)
(println @state))
(when @canvas
(draw-1 (. @canvas getContext "2d")))
(when @is-running
(swap! ticks inc)
(reagent.core/next-tick draw)))

(on-mouse-move [e]
(when @is-running
(swap! state update-in [:paddle :cx] (constantly (. e -clientX)))))

(start-game []
(reset! is-running true)
(reset! seconds-timeout-id
(js/setInterval #(swap! seconds-elapsed inc) 1000))
(reset! state (initial-state width height))
(reset! ticks 0)
(reset! seconds-elapsed 0)
(draw))

(end-game []
(reset! is-running false)
(when @seconds-timeout-id
(js/clearInterval @seconds-timeout-id)
(reset! seconds-timeout-id nil)))]
(fn []
[:div
[:div
[Timer {:seconds-elapsed @seconds-elapsed}]
[:div
"Ticks: " (print-str @ticks)]]
[:div
[:canvas {:ref #(reset! canvas %)
:width width
:height height
:style {:width (str width "px")
:height (str height "x")
:border "1px solid black"}
:on-mouse-move on-mouse-move}]]
[:div {:style {:text-align "center"}}
[:button {:on-click #(if (not @is-running)
(start-game)
(end-game))}
(if (not @is-running)
"Start YASUNORI"
"Stop YASUNORI")]]]))))

(defn App []
[:div {:style {:max-width "1000px"}}
[Title]
[Main]])
14 changes: 14 additions & 0 deletions packages/cljs-yasunori-block/src/yasunori_block/core.cljs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
(ns ^:figwheel-hooks yasunori-block.core
(:require
[reagent.dom :as rdom]
[yasunori-block.app :as y.app]))

(enable-console-print!)

(defn run []
(rdom/render [y.app/App] (js/document.getElementById "app")))

(run)

(defn ^:after-load on-reload []
(run))
2 changes: 2 additions & 0 deletions packages/cljs-yasunori-block/wrangler.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
name = "yasunori-cljs-breakout"
pages_build_output_dir = "./dist/public"