▶ 実 行
▶ 実行
クリア
OpenAI-GymのCarRacingのGYM環境本体
by てぃふと@うぇいく
# OpenAI Gym CarRacing # AWAIT命令のプラグインを取り込む !「https://n3s.nadesi.com/plain/1899.js」を取り込む URL_PLANCKとは変数 URL_PLANCKは「https://cdn.jsdelivr.net/npm/planck-js@0.4.0-alpha.1/dist/planck.min.js」 PLとは変数 GYMENVとは変数 PLはNULL GYMENVはNULL STATE_Wは96 STATE_Hは96 WINDOW_Wは1000 WINDOW_Hは800 SCALEは6 TRACK_RADは900/SCALE PLAYFIELDは2000/SCALE FPSは50 ZOOMは2.7 ZOOM_FOLLOWはオン TRACK_DETAIL_STEPは21/SCALE TRACK_TURN_RATEは0.31 TRACK_WIDTHは40/SCALE BORDERは8/SCALE BORDER_MIN_COUNTは4 GRASS_DIMはPLAYFIELD/20 MAX_SHAPE_DIMはMAX(MAX(GRASS_DIM,TRACK_WIDTH),TRACK_DETAIL_STEP)*SQRT(2)*ZOOM*SCALE SIZEは0.02 ENGINE_POWERは100000000 * SIZE * SIZE WHEEL_MOMENT_OF_INERTIAは4000 * SIZE * SIZE # friction ~= mass ~= size^2 (calculated implicitly using density) FRICTION_LIMITは(1000000 * SIZE * SIZE) WHEEL_Rは27 WHEEL_Wは14 WHEELPOSは[[-55, 80], [55, 80], [-55, -82], [55, -82]] HULL_POLY1は[[-60, 130], [60, 130], [60, 110], [-60, 110]] HULL_POLY2は[[-15, 120], [15, 120], [20, 20], [-20, 20]] HULL_POLY3は[ [25, 20], [50, -10], [50, -40], [20, -90], [-20, -90], [-50, -40], [-50, -10], [-25, 20], ] HULL_POLY4は[[-50, -120], [50, -120], [50, -90], [-50, -90]] WHEEL_COLORは"#000000" # 0,0,0 WHEEL_WHITEは"#4D4D4D" # 77, 77, 77 MUD_COLORは"#666600" # 102, 102, 0 ●(PLISTから倍率で)Polygon作成補助とは POLYは[] PLISTをPOSで反復する PはVec2(POS[0]*倍率, POS[1]*倍率) POLYにPを配列追加 ここまで POLYのPolygon作成で戻る ここまで ●(WORLDのXYにANGLEで)車作成とは 車とは変数 車は{ "World": WORLD, 車体: NULL, 車輪: [], } Pとは変数 OPTSとは変数 形とは変数 車体とは変数 PはVec2(XY[0], XY[1]) 車体はWORLDに[P, ANGLE]で動的Body作成 OPTSは{ "density":1, } 形はHULL_POLY1からSIZEでPolygon作成補助 車体に形をOPTSで造形登録 形はHULL_POLY2からSIZEでPolygon作成補助 車体に形をOPTSで造形登録 形はHULL_POLY3からSIZEでPolygon作成補助 車体に形をOPTSで造形登録 形はHULL_POLY4からSIZEでPolygon作成補助 車体に形をOPTSで造形登録 車体["色"]は"#CC0000" 車["車体"]は車体 車["燃料"]は0 車["タイヤ痕描画"]はオン 車["横滑跡リスト"]は[] WHEEL_POLYとは変数 車輪OPTSとは変数 WHEEL_POLYは[ [ -WHEEL_W, WHEEL_R], [ WHEEL_W, WHEEL_R], [ WHEEL_W, -WHEEL_R], [ -WHEEL_W, -WHEEL_R], ] 車輪OPTSは{ "density": 0.1, "filterCategoryBits": 32, "filterMaskBits": 1, "restitution": 0, } 車軸OPTSは{ "lowerAngle": -0.4, # 約23度 "upperAngle": 0.4, # 約23度 "enableMotor": (1=1), "enableLimit": (1=1), "maxMotorTorque": 180*900*SIZE*SIZE, "motorSpeed": 0, } Iは0 WHEELPOSをPOSで反復する XはXY[0]+POS[0]*SIZE*COS(ANGLE)+POS[1]*SIZE*SIN(ANGLE) YはXY[1]+POS[0]*SIZE*SIN(ANGLE)-POS[1]*SIZE*COS(ANGLE) PはVec2(X, Y) 車輪はWORLDに[P, ANGLE]で動的Body作成 形はWHEEL_POLYからSIZEでPolygon作成補助 造形は車輪に形を車輪OPTSで造形登録 OBJは{ "車輪Index": I, } 造形にOBJをUserData設定 車輪["車輪半径"]はWHEEL_R * SIZE 車輪["色"]はWHEEL_COLOR 車輪["燃料"]は0.0 車輪["ブレーキ"]は0.0 車輪["操舵"]は0.0 車輪["位相"]は0.0 車輪["Ω"]は0.0 車輪["横滑開始"]はNULL 車輪["横滑跡"]はNULL 車軸は車軸OPTSで車体から車輪をPに回転Joint作成 WORLDに車軸をJoint登録 車輪["Joint"]は車軸 車輪["タイルI"]は[] 車輪を車["車輪"]に配列追加 IはI+1 ここまで 車["操舵輪"]は[車["車輪"][2], 車["車輪"][3]] 車["駆動輪"]は[車["車輪"][0], 車["車輪"][1]] 車で戻る ここまで ●(車をGASで)車アクセルとは GASはCLIP(GAS, 0, 1) 車["駆動輪"]を車輪で反復する 差異はGAS-車輪["燃料"] もし、差異>0.1ならば、 差異は0.1 ここまで 車輪["燃料"]は車輪["燃料"]+差異 ここまで ここまで ●(車をBRAKEで)車ブレーキとは BRAKEはCLIP(BRAKE, 0, 1) 車["車輪"]を車輪で反復する 車輪["ブレーキ"]はBRAKE ここまで ここまで ●(車をSTEERで)車操舵とは STEERはCLIP(STEER, -1, 1) 車["操舵輪"]を車輪で反復する 車輪["操舵"]はSTEER ここまで ここまで ●(車をDTだけ)車ステップとは 車["車輪"]を車輪で反復する # 車輪の方向を操舵に追従させる 車輪方向は車輪["Joint"]のJoint回転角度取得 方向はSIGN(車輪["操舵"]-車輪方向) 値はABS(車輪["操舵"]-車輪方向) 車輪["Joint"]に方向*MIN(50.0*値, 3.0)でモーター速設定 # 車輪の乗っている地面の判定と摩擦上限を求める ラフはオン 摩擦上限はFRICTION_LIMIT * 0.6 # タイルに乗っていない場合はラフ タイルIで車輪["タイルI"]を反復する タイルはGYMENV["コース"][タイルI] 摩擦上限はMAX(摩擦上限, FRICTION_LIMIT * タイル["路面摩擦"]) ラフはオフ ここまで # 推進力を求める 縦VはVec2(0,1) 横VはVec2(1,0) 前方向は車輪の縦Vからワールドベクトル取得 横方向は車輪の横Vからワールドベクトル取得 Vは車輪の線速度取得 前速さは前方向["x"]*V["x"]+前方向["y"]*V["y"] 横速さは横方向["x"]*V["x"]+横方向["y"]*V["y"] # 車輪["Ω"]は車輪["Ω"]+(DT*ENGINE_POWER*車輪["燃料"]/WHEEL_MOMENT_OF_INERTIA/(ABS(車輪["Ω"])+5)) 車["燃料"]は車["燃料"]+DT*ENGINE_POWER*車輪["燃料"] もし、車輪["ブレーキ"]≧0.9ならば、 車輪["Ω"]は0 違えばもし、車輪["ブレーキ"]>0ならば、 BRAKE_FORCEは15 # radians per second 方向は0-SIGN(車輪["Ω"]) 値はBRAKE_FORCE * 車輪["ブレーキ"] もし、ABS(値)>ABS(車輪["Ω"])ならば、 値はABS(車輪["Ω"]) ここまで 車輪["Ω"]は車輪["Ω"]+方向*値 ここまで 車輪["位相"]は車輪["位相"]+車輪["Ω"]*DT VRは車輪["Ω"]*車輪["車輪半径"] 前力は0-前速さ+VR 横力は0-横速さ 前力は前力*205000*SIZE*SIZE 横力は横力*205000*SIZE*SIZE 力計はSQRT(前力*前力+横力*横力) # 車輪の横滑り判定・処理 もし、ABS(力計)>2*摩擦上限ならば、 POSは車輪の位置取得 POSは[POS["x"], POS["y"]] もし、車輪["横滑跡"]≠NULL&&車輪["横滑跡"]["ラフ"]=ラフ&&(車輪["横滑跡"]["形状"]の配列要素数)<30ならば、 POSを車輪["横滑跡"]["形状"]に配列追加 違えばもし、車輪["横滑開始"]=NULLならば、 車輪["横滑開始"]はPOS 違えば、 横滑跡は車輪["横滑開始"]からPOSにラフの横滑跡作成 車輪["横滑跡"]は横滑跡 横滑跡を車["横滑跡リスト"]に配列追加 ((車["横滑跡リスト"]の配列要素数)>30)の間繰り返す 車["横滑跡リスト"]から配列ポップ ここまで 車輪["横滑開始"]はNULL ここまで 違えば、 車輪["横滑開始"]はNULL 車輪["横滑跡"]はNULL ここまで もし、ABS(力計)>摩擦上限ならば、 前力は前力/力計 横力は横力/力計 力計は摩擦上限 前力は前力*力計 横力は横力*力計 ここまで 車輪["Ω"]は車輪["Ω"]-(DT*前力*車輪["車輪半径"]/WHEEL_MOMENT_OF_INERTIA) VはVec2(横力*横方向["x"]+前力*前方向["x"],横力*横方向["y"]+前力*前方向["y"]) 車輪をVに重心押す ここまで ここまで ●(車を)車描画とは もし、車["タイヤ痕描画"]ならば、 キャンバス状態保存 太さとは変数 Pとは変数 太さは描画中コンテキスト["lineWidth"] 太さ*2に線太さ設定 Pで車["横滑跡リスト"]を反復する P["色"]に線色設定 P["形状"][0]からP["形状"][1]まで線描画 ここまで キャンバス状態復元 ここまで 描画リストとは変数 描画リストは[ 車["車体"], 車["車輪"][0], 車["車輪"][1], 車["車輪"][2], 車["車輪"][3], ] 描画リストをPLANCK一括描画 ここまで ●(車を)車破棄とは 車["World"]から車["車体"]をBody破棄 車["車体"]はNULL 車輪とは変数 車["車輪"]を車輪で反復する 車["World"]から車輪をBody破棄 ここまで 車["車輪"]は[] 車["操舵輪"]は[] 車["駆動輪"]は[] ここまで ●(POS1からPOS2にラフの)横滑跡作成とは 横滑跡とは変数 カラーとは変数 POLYとは変数 もし、ラフならば、 カラーはMUD_COLOR 違えば、 カラーはWHEEL_COLOR ここまで POLYは[POS1, POS2] 横滑跡は{ 色:カラー, 持続時間:1, ラフ:ラフ 形状:POLY, } 横滑跡で戻る ここまで ●GYM作成とは もし、GYMENV≠NULLならば、 「このGym環境は1回のみ1つしか作成できません」でエラー発生 ここまで もし、PL=NULLならば、 Planckライブラリ読込 ここまで ENVとは変数 ENVは{ "ランダムカラー": (0=1), "訪問率": 0.95, "FPS": 50, "報酬": 0, "前回報酬": 0, "STATEキャンバス": NULL, } OPTSとは変数 OPTSは{ "gravity":Vec2(0,0) } ENV["車"]はNULL ENV["コース"]はNULL ENVの色初期値設定 ENV["World"]はOPTSでNewWorld ENV["World"]の"begin-contact"にONイベント設定には(contact) contactにオンで走路処理 ここまで ENV["World"]の"end-contact"にONイベント設定には(contact) contactにオフで走路処理 ここまで GYMENVはENV ENVで戻る ここまで ●GYM破棄とは GYM環境破棄 もし、GYMENV["World"]≠NULLならば、 # なにもない ここまで ここまで ●GYM環境破棄とは worldとは変数 worldはGYMENV["World"] もし、GYMENV["コース"]≠NULLならば、 worldのGYMENV["コース"]をPLANCK一括破棄 ここまで GYMENV["コース"]はNULL もし、GYMENV["車"]≠NULLならば、 GYMENV["車"]を車破棄 GYMENV["車"]はNULL ここまで ここまで ●GYMリセットとは ENVとは変数 ENVはGYMENV GYM環境破棄 ENVの色再設定 ENV["背景色"]はENV["背景色基準"]から色スタイル ENV["道路色"]はENV["道路色基準"]から色スタイル ENV["芝生色"]はENV["芝生色基準"]から色スタイル ENV["経過"]は1 ENV["報酬"]は0 ENV["前回報酬"]は0 ENV["コース形状"]は[] ENV["タイル訪問数"]は0 ENV["新ラップ"]はオフ ENV["現必要訪問率"]はENV["訪問率"] ENV["STATEキャンバス"]は"CANVAS"をDOM要素作成 ENV["STATEキャンバス"]["width"]はSTATE_W ENV["STATEキャンバス"]["height"]はSTATE_H ENV["STATE原寸キャンバス"]は"CANVAS"をDOM要素作成 ENV["STATE原寸キャンバス"]["width"]はWINDOW_W ENV["STATE原寸キャンバス"]["height"]はWINDOW_H オンの間 成否はENVのトラック作成 もし、成否がオンならば、 抜ける ここまで 「トラック生成失敗... リトライ」を表示 ここまで POSとは変数 向きとは変数 POSは[ENV["トラック"][0][2], ENV["トラック"][0][3]] 向きはENV["トラック"][0][1] ENV["車"]はENV["World"]のPOSに向きで車作成 結果とは変数 結果はNULLでGYMステップ 結果[0]で戻る ここまで ●(ACTIONで)GYMステップとは ENVとは変数 ENVはGYMENV worldとは変数 worldはGYMENV["World"] ENV["ACTION"]はACTION もし、ACTION≠NULLならば、 ENV["車"]を(0-ACTION[0])で車操舵 ENV["車"]をACTION[1]で車アクセル ENV["車"]をACTION[2]で車ブレーキ ここまで ENV["車"]を(1/ENV["FPS"])だけ車ステップ worldを[1.0 / ENV["FPS"], 6 * 30, 2 * 30]でPLStep ENV["経過"]はENV["経過"]+1/ENV["FPS"] 現キャンバスとは変数 現キャンバスは描画中キャンバス ENV["STATE原寸キャンバス"]へ描画開始 GYM描画 ENV["STATEキャンバス"]へ描画開始 ENV["STATE原寸キャンバス"]を[0,0,WINDOW_W,WINDOW_H,0,0,STATE_W,STATE_H]に画像描画 イメージデータは[0,0,STATE_W,STATE_H]をイメージデータ取得 現キャンバスへ描画開始 STATEはイメージデータ["data"] 報酬は0 終了フラグはオフ 打切りフラグはオフ もし、ACTION≠NULLならば、 ENV["報酬"]はENV["報酬"]-0.1 報酬はENV["報酬"]-ENV["前回報酬"] ENV["前回報酬"]はENV["報酬"] もし、ENV["タイル訪問数"]=(ENV["トラック"]の配列要素数)||ENV["新ラップ"]ならば、 打切りフラグはオン 終了フラグはオン ここまで POSはENV["車"]["車体"]の位置取得 もし、ABS(POS["x"])>PLAYFIELD||ABS(POS["y"])>PLAYFIELDならば、 終了フラグはオン 報酬は-100 ここまで ここまで [STATE, 報酬, 終了フラグ, 打切フラグ,{}]で戻る ここまで ●(OPTSを)イメージデータ取得とは 描画中コンテキストの"getImageData"をOPTSでJSメソッド実行で戻る ここまで ●GYM描画とは キャンバス状態保存 描画情報はGYMENV["車"]で描画情報算出 描画情報で描画準備 GYMENVのコース描画 GYMENV["車"]を車描画 キャンバス状態復元 GYMENVの[描画中キャンバス["width"], 描画中キャンバス["height"]]に車インジケーター描画 もし、描画中キャンバス≠GYMENV["STATE原寸キャンバス"]ならば、 キャンバス状態保存 "36px san-serif"に描画フォント設定 白色に塗り色設定 描画中コンテキスト["textAlign"]は"center" 描画中コンテキスト["textBaseline"]は"middle" 報酬はGYMENV["報酬"]の整数部分 正負はSIGN(報酬) 報酬は「000{ABS(報酬)}」の4だけ文字右部分 もし、正負<0ならば、 報酬は「-{報酬}」 違えば、 報酬は「 {報酬}」 ここまで [60, 描画中キャンバス["height"]-描画中キャンバス["height"]*2.5/40]に報酬を文字描画 キャンバス状態復元 # [0,0]にGYMENV["STATEキャンバス"]を画像描画 ここまで ここまで ### 内部関数 ●(ENVのWHに)車インジケーター描画とは W1とは変数 H1とは変数 W1はWH[0]/40 H1はWH[1]/40 黒色に塗り色設定 空に線色設定 [0, WH[1]-5*H1, WH[0], 5*H1]に四角描画 Vとは変数 スピードとは変数 VはENV["車"]["車体"]の線速度取得 スピードはSQRT(V["x"]*V["x"]+V["y"]*V["y"]) OPTSとは変数 OPTSは{ 倍率: 0.01, 色: "#0000FF", 種類: "縦", W1: W1, H1: H1, W: WH[0], H: WH[1], } OPTS["値"]はENV["車"]["車輪"][0]["Ω"] OPTS["位置"]は7 OPTSでインジケーター描画 OPTS["値"]はENV["車"]["車輪"][1]["Ω"] OPTS["位置"]は8 OPTSでインジケーター描画 OPTS["値"]はENV["車"]["車輪"][2]["Ω"] OPTS["位置"]は9 OPTS["色"]は"#3300FF" OPTSでインジケーター描画 OPTS["値"]はENV["車"]["車輪"][3]["Ω"] OPTS["位置"]は10 OPTSでインジケーター描画 角度はENV["車"]["車輪"][0]["Joint"]のJoint回転角度取得 OPTS["値"]は角度 OPTS["倍率"]は-10 OPTS["位置"]は20 OPTS["色"]は"#00FF00" OPTS["種類"]は"横" OPTSでインジケーター描画 角度はENV["車"]["車体"]の回転速度取得 OPTS["値"]は角度 OPTS["倍率"]は-0.8 OPTS["位置"]は30 OPTS["色"]は"#FF0000" OPTSでインジケーター描画 ここまで ●(OPTSで)インジケーター描画とは もし、OPTS["値"]<0.0001ならば、 戻る ここまで 値とは変数 値はOPTS["値"]*OPTS["倍率"] OPTS["色"]に塗り色設定 Iとは変数 IはOPTS["位置"] POLYとは変数 もし、OPTS["種類"]="縦"ならば、 POLYは[ I*OPTS["W1"] , OPTS["H"]-(1+値)*OPTS["H1"] , OPTS["W1"]-1, 値*OPTS["H1"]-1, ] 違えば、 POLYは[ I*OPTS["W1"] , OPTS["H"]-4*OPTS["H1"], 値*OPTS["W1"]-1, 2*OPTS["H1"]-1 ] ここまで POLYに四角描画 ここまで ●(ENVの)色再設定とは もし、ENV["ランダムカラー"]ならば、 ENVの色ランダム値設定 ここまで ここまで ●(ENVの)色初期値設定とは もし、ENV["ランダムカラー"]ならば、 ENVの色ランダム値設定 違えば、 ENV["背景色基準"]は[102,204,102] ENV["道路色基準"]は[102,102,102] ENV["芝生色基準"]は[102,230,102] ここまで ここまで ●(ENVの)色ランダム値設定とは ENV["背景色基準"]は[210の乱数, 210の乱数, 210の乱数] ENV["道路色基準"]は[210の乱数, 210の乱数, 210の乱数] ENV["芝生色基準"]は[ENV["背景色基準"][0], ENV["背景色基準"][1], ENV["背景色基準"][2]] IDXとは変数 IDXは3の乱数 ENV["芝生色基準"][IDX]はENV["芝生色基準"]+20 ここまで ●(contactにflagで)走路処理とは F1とは変数 F2とは変数 F1はcontactの構造A取得 F2はcontactの構造B取得 O1とは変数 O2とは変数 O1はNULL O2はNULL もし、F1≠NULLならば、 O1はF1からUserData取得 ここまで もし、F2≠NULLならば、 O2はF2からUserData取得 ここまで 地面Oとは変数 車輪Oとは変数 もし、O1≠NULL&&O1["トラックIndex"]≠NULLならば、 地面OはO1 車輪OはO2 違えばもし、O2≠NULL&&O2["トラックIndex"]≠NULLならば、 地面OはO1 車輪OはO2 違えば、 #「不用コンタクト({flag}):地面無し」を表示 戻る ここまで 地面Iとは変数 地面とは変数 地面Iは地面O["トラックIndex"] 地面はGYMENV["コース"][地面I] 地面["色"]はGYMENV["道路色"] もし、車輪O=NULL||車輪O["車輪Index"]=NULLならば、 #「不用コンタクト({flag}):車輪無し」を表示 戻る ここまで 車輪Iとは変数 車輪Iは車輪O["車輪Index"] #「タイヤ接地({flag}) {車輪I}-{地面I}」を表示 車輪とは変数 車輪はGYMENV["車"]["車輪"][車輪I] Iとは変数 もし、flagならば、 地面Iを車輪["タイルI"]に配列追加 Iは地面Iを車輪["タイルI"]から配列検索 もし、I=(-1)ならば、 地面Iを車輪["タイルI"]に配列追加 ここまで もし、地面["訪問"]=オフならば、 地面["訪問"]はオン GYMENV["報酬"]はGYMENV["報酬"]+1000.0/(GYMENV["トラック"]の配列要素数) GYMENV["タイル訪問数"]はGYMENV["タイル訪問数"]+1 もし、地面I=0&&GYMENV["タイル訪問数"]/(GYMENV["トラック"]の配列要素数)>GYMENV["現必要訪問率"]ならば、 GYMENV["新ラップ"]はオン ここまで ここまで 違えば Iは地面Iを車輪["タイルI"]から配列検索 もし、I>(-1)ならば、 Iを車輪["タイルI"]から配列削除 ここまで ここまで ここまで ●(ENVの)トラック作成とは worldはENV["World"] CHECKPOINTSは12 チェックポイントは[] (CHECKPOINTS)回繰り返す Cは回数-1 ノイズは2*PI/CHECKPOINTS*RND アルファは2*PI*C/CHECKPOINTS+ノイズ RはTRACK_RAD/3+(TRACK_RAD*2/3)*RND もし、Cが0ならば、 アルファは0 Rは1.5*TRACK_RAD 違えばもし、CがCHECKPOINTS-1ならば、 アルファは2*PI*C/CHECKPOINTS ENV["開始アルファ"]は2*PI*(-0.5)/CHECKPOINTS Rは1.5*TRACK_RAD ここまで POSは[アルファ, R*COS(アルファ), R*SIN(アルファ)] チェックポイントにPOSを配列追加 ここまで ENV["コース"]は[] ENV["コース形状"]は[] Xは1.5*TRACK_RAD Yは0 ベータは0 目的地Iは0 ラップ数は0 トラックは[] フリーズ防止カウンタは2500 反対側到達はオフ オンの間、 アルファはATAN2(Y,X) もし、反対側到達&&アルファ>0ならば、 ラップ数はラップ数+1 反対側到達はオフ ここまで もし、アルファ<0ならば、 反対側到達はオン アルファはアルファ+2*PI ここまで オンの間、 失敗フラグはオン オンの間、 POSはチェックポイント[目的地I % (チェックポイントの配列要素数)] 目的地アルファはPOS[0] 目的地XはPOS[1] 目的地YはPOS[2] もし、アルファ≦目的地アルファならば、 失敗フラグはオフ 抜ける ここまで 目的地Iは目的地I+1 もし、(目的地I % (チェックポイントの配列要素数))=0ならば、 抜ける ここまで ここまで もし、失敗フラグがオフならば、 抜ける ここまで アルファはアルファ-2*PI ここまで R1XはCOS(ベータ) R1YはSIN(ベータ) P1Xは-R1Y P1YはR1X 目的地DXは目的地X-X 目的地DYは目的地Y-Y PROJはR1X*目的地DX+R1Y*目的地DY (ベータ-アルファ>1.5*PI)の間、 ベータはベータ-2*PI ここまで (ベータ-アルファ<-1.5*PI)の間、 ベータはベータ+2*PI ここまで 元ベータはベータ PROJはPROJ*SCALE もし、PROJ>0.3ならば、 ベータはベータ-MIN(TRACK_TURN_RATE, ABS(0.001*PROJ)) ここまで もし、PROJ<(-0.3)ならば、 ベータはベータ+MIN(TRACK_TURN_RATE, ABS(0.001*PROJ)) ここまで XはX+P1X*TRACK_DETAIL_STEP YはY+P1Y*TRACK_DETAIL_STEP POSは[アルファ, 元ベータ*0.5+ベータ*0.5, X, Y] トラックにPOSを配列追加 もし、ラップ数>4ならば、 抜ける ここまで フリーズ防止カウンタはフリーズ防止カウンタ-1 もし、フリーズ防止カウンタ=0ならば、 抜ける ここまで ここまで I1は-1 I2は-1 Iはトラックの配列要素数 オンの間、 IはI-1 もし、I=0ならば、 オフで戻る ここまで 通過開始はトラック[I][0]>ENV["開始アルファ"]&&トラック[I-1][0]≦ENV["開始アルファ"] もし、通過開始&&I2=(-1)ならば、 I2はI 違えばもし、通過開始&&I1=(-1)ならば、 I1はI 抜ける ここまで ここまで トラック長はI2-I1+1 新トラックは[] (トラック長)回繰り返す Iは回数-1+I1 新トラックにトラック[I]を配列追加 ここまで トラックは新トラック 開始ベータはトラック[0][1] 開始XはCOS(開始ベータ) 開始YはSIN(開始ベータ) DXは開始X*(トラック[0][2]-トラック[トラック長-1][2]) DYは開始Y*(トラック[0][3]-トラック[トラック長-1][3]) 接続距離はSQRT(DX*DX+DY*DY) もし、接続距離>TRACK_DETAIL_STEPならば、 オフで戻る ここまで ボーダーは[] (トラック長)回繰り返す Iは回数-1 判定はオン 片側は0 (BORDER_MIN_COUNT)回繰り返す Jは回数-1 ベータ1はトラック[(I - J - 0 + トラック長) % トラック長][1] ベータ2はトラック[(I - J - 1 + トラック長) % トラック長][1] もし、ABS(ベータ1 - ベータ2) < TRACK_TURN_RATE * 0.2ならば、 判定はオフ ここまで 片側は片側+SIGN(ベータ1 - ベータ2) ここまで もし、ABS(片側)≠BORDER_MIN_COUNTならば、 判定はオフ ここまで ボーダー[I]は判定 ここまで (トラック長)回繰り返す Iは回数-1 (BORDER_MIN_COUNT)回繰り返す Jは回数-1 Jは(I - J + トラック長) % トラック長 ボーダー[J]はOR(ボーダー[J],ボーダー[I]) ここまで ここまで (トラック長)回繰り返す Iは回数-1 アルファ1はトラック[I][0] ベータ1はトラック[I][1] X1はトラック[I][2] Y1はトラック[I][3] Jは(I-1+トラック長)%トラック長 アルファ2はトラック[J][0] ベータ2はトラック[J][1] X2はトラック[J][2] Y2はトラック[J][3] P1Lは[X1-TRACK_WIDTH*COS(ベータ1), Y1-TRACK_WIDTH*SIN(ベータ1)] P1Rは[X1+TRACK_WIDTH*COS(ベータ1), Y1+TRACK_WIDTH*SIN(ベータ1)] P2Lは[X2-TRACK_WIDTH*COS(ベータ2), Y2-TRACK_WIDTH*SIN(ベータ2)] P2Rは[X2+TRACK_WIDTH*COS(ベータ2), Y2+TRACK_WIDTH*SIN(ベータ2)] Xは(X1+X2)/2 Yは(Y1+Y2)/2 POLYは[ Vec2(P1L[0]-X, P1L[1]-Y), Vec2(P1R[0]-X, P1R[1]-Y), Vec2(P2R[0]-X, P2R[1]-Y), Vec2(P2L[0]-X, P2L[1]-Y), ] 形はPOLYのPolygon作成 PはVec2(X,Y) 地面はworldに[P]でBody作成 造形は地面に形を{"isSensor":(1=1)}で造形登録 Cは(0.01*(I % 3) * 255)+5の整数部分 地面["色"]は[ENV["道路色基準"][0]+C, ENV["道路色基準"][1]+C, ENV["道路色基準"][2]+C]から色スタイル 地面["訪問"]はオフ 地面["路面摩擦"]は1.0 OBJは{ "トラックIndex": I, } 造形にOBJをUserData設定 カラーは地面["色"] POLYは[[P1L, P1R, P2R, P2L], カラー, I] POLYをENV["コース形状"]に配列追加 地面をENV["コース"]に配列追加 もし、ボーダー[I]ならば、 SIDEはSIGN(ベータ2 - ベータ1) カラーは[255, 255*(I % 2), 255*(I % 2)]から色スタイル POLYは[[ [ X1+SIDE*TRACK_WIDTH*COS(ベータ1), Y1+SIDE*TRACK_WIDTH*SIN(ベータ1)], [ X1+SIDE*(TRACK_WIDTH+BORDER)*COS(ベータ1), Y1+SIDE*(TRACK_WIDTH+BORDER)*SIN(ベータ1)], [ X2+SIDE*(TRACK_WIDTH+BORDER)*COS(ベータ2), Y2+SIDE*(TRACK_WIDTH+BORDER)*SIN(ベータ2)], [ X2+SIDE*TRACK_WIDTH*COS(ベータ2), Y2+SIDE*TRACK_WIDTH*SIN(ベータ2)], ], カラー, 0-1 ] POLYをENV["コース形状"]に配列追加 ここまで ここまで ENV["トラック"]はトラック オンで戻る ここまで ●(車で)描画情報算出とは ズームは0.1*SCALE*MAX(1-GYMENV["経過"],0)+ZOOM*SCALE*MIN(GYMENV["経過"],1) POSは車["車体"]の位置取得 向きは0-(車["車体"]の回転角取得) スクロールXは0-POS["x"] スクロールYは0-POS["y"] 描画情報は{ CENTER:[ スクロールX, スクロールY, ], OFFSET:[ 描画中キャンバス["width"] /2/ズーム, 描画中キャンバス["height"]/4/ズーム, ], ANGLE:向き, SCALE:ズーム, } 描画情報で戻る ここまで ●(描画情報で)描画準備とは 全描画クリア [描画中キャンバス["width"]/2,描画中キャンバス["height"]/2]に描画起点設定 [1,-1]に描画拡大 [-描画中キャンバス["width"]/2,-描画中キャンバス["height"]/2]に描画起点設定 空に線色設定 黒色に塗り色設定 [0,0,描画中キャンバス["width"],描画中キャンバス["height"]]に四角描画 [描画情報["SCALE"], 描画情報["SCALE"]]に描画拡大 描画情報["OFFSET"]に描画起点設定 (RAD2DEG(描画情報["ANGLE"]))に描画回転 描画情報["CENTER"]に描画起点設定 (1/描画情報["SCALE"])に線太さ設定 ここまで ●(ENVの)コース描画とは POLYとは変数 POLYは[ [-PLAYFIELD, -PLAYFIELD], [ PLAYFIELD, -PLAYFIELD], [ PLAYFIELD, PLAYFIELD], [-PLAYFIELD, PLAYFIELD], ] 空に線色設定 ENV["背景色"]に塗色設定 POLYを多角形描画 芝とは変数 Xとは変数 Yとは変数 芝は[] 19回繰り返す Xは回数*2-20 19回繰り返す Yは回数*2-20 POLYは[ [GRASS_DIM * X + GRASS_DIM , GRASS_DIM * Y + 0 ], [GRASS_DIM * X + 0 , GRASS_DIM * Y + 0 ], [GRASS_DIM * X + 0 , GRASS_DIM * Y + GRASS_DIM], [GRASS_DIM * X + GRASS_DIM , GRASS_DIM * Y + GRASS_DIM], ] 芝にPOLYを配列追加 ここまで ここまで ENV["芝生色"]に塗色設定 芝をPOLYで反復する POLYを多角形描画 ここまで 地面とは変数 ENV["コース形状"]を地面で反復する POLYは地面[0] もし、地面[2]>(0-1)ならば、 ENV["コース"][地面[2]]["色"]に塗り色設定 違えば、 地面[1]に塗り色設定 ここまで POLYを多角形描画 ここまで ここまで ●(物リストを)PLANCK一括描画とは 物とは変数 位置とは変数 回転とは変数 構造とは変数 形とは変数 型とは変数 POSとは変数 PREVPOSとは変数 物リストを物で反復する もし、(物がIsBody)でなければ、 続ける ここまで 位置は物の位置取得 回転は物の回転角取得 構造は物の構造リスト取得 (構造≠NULL)の間、 形は構造の形取得 型は形の形名取得 型で条件分岐 "polygon"ならば、 POLYとは変数 POLYは[] 形["m_vertices"]をPOSで反復する POLYに[POS["x"],POS["y"]]を配列追加 ここまで キャンバス状態保存 [位置["x"],位置["y"]]に描画起点設定 RAD2DEG(回転)に描画回転 もし、物["色"]≠NULLならば、 物["色"]に線色設定 物["色"]に塗り色設定 違えば、 物["色L"]に線色設定 物["色F"]に塗り色設定 ここまで POLYを多角形描画 位相表示フラグはオフ もし、物["位相"]≠NULLならば、 位相表示フラグはオン ここまで もし、位相表示フラグならば、 A1は物["位相"] A2は物["位相"]+1.2 # 1.2rad = 約70度 S1はSIN(A1) S2はSIN(A2) C1はCOS(A1) C2はCOS(A2) もし、S1>0&&S2>0ならば、 位相表示フラグはオフ ここまで ここまで もし、位相表示フラグならば、 もし、S1>0ならば、 C1はSIGN(C1) ここまで もし、S2>0ならば、 C2はSIGN(C2) ここまで POLYは[ [0-WHEEL_W*SIZE, WHEEL_R*C1*SIZE], [0+WHEEL_W*SIZE, WHEEL_R*C1*SIZE], [0+WHEEL_W*SIZE, WHEEL_R*C2*SIZE], [0-WHEEL_W*SIZE, WHEEL_R*C2*SIZE], ] WHEEL_WHITEに塗り色設定 WHEEL_WHITEに線色設定 POLYを多角形描画 ここまで キャンバス状態復元 ここまで "chain"ならば、 Iとは変数 状態とは変数 状態は0 Iは0 PREVPOSはNULL 形["m_vertices"]をPOSで反復する もし、PREVPOS≠NULLならば、 もし、物["色"]≠NULLならば、 物["色"]に線色設定 違えば、 もし、Iが0ならば、 物["色E"]に線色設定 違えば 物["色O"]に線色設定 ここまで ここまで [PREVPOS["x"],PREVPOS["y"]]から[POS["x"],POS["y"]]まで線描画 ここまで Iは1-I PREVPOSはPOS ここまで 違えば、 「グループ描画に未対応の型({型})が含まれています」でエラー発生 ここまで ここまで 構造は構造の次構造取得 ここまで ここまで ここまで ●(WORLDの物リストを)PLANCK一括破棄とは 何とは変数 何で物リストを反復する もし、(何がIsBody)ならば WORLDから何をBody破棄 ここまで ここまで ここまで ### Planckライブラリ呼び出し支援 ●Planckライブラリ読込とは MODULEとは変数 URL_PLANCKを動的インポートをAWAIT PLはWINDOW["planck"] ここまで ●(X,Y)Vec2とは PLの"Vec2"を[X,Y]でJSメソッド実行で戻る ここまで ●(WORLDにARGSで)Body作成とは WORLDの"createBody"をARGSでJSメソッド実行で戻る ここまで ●(WORLDにARGSで)動的Body作成とは WORLDの"createDynamicBody"をARGSでJSメソッド実行で戻る ここまで ●(WORLDからBODYを)Body破棄とは WORLDの"destroyBody"を[BODY]でJSメソッド実行 ここまで ●(Oが)IsBodyとは 『(function(pl,obj){return obj instanceof pl.Body;})』を[PL, O]でJS関数実行で戻る ここまで ●(POLYの)Polygon作成とは PLの"Polygon"を[POLY]でJSメソッド実行で戻る ここまで ●(LINESの)Chain作成とは PLの"Chain"を[LINES]でJSメソッド実行で戻る ここまで ●(WHの)Box作成とは PLの"Box"をWHでJSメソッド実行で戻る ここまで ●(OPTSでBODY1からBODY2をPOSに)回転Joint作成とは PLの"RevoluteJoint"を[OPTS,BODY1,BODY2,POS]でJSメソッド実行で戻る ここまで ●(BODYにSHAPEをOPTSで)造形登録とは BODYの"createFixture"を[SHAPE, OPTS]でJSメソッド実行で戻る ここまで ●(WORLDにJOINTを)Joint登録とは WORLDの"createJoint"を[JOINT]でJSメソッド実行 ここまで ●(BODYをVに)重心押とは BODYの"applyForceToCenter"を[V,(1=1)]でJSメソッド実行 ここまで ●(BODYのVから)ワールドベクトル取得とは BODYの"getWorldVector"を[V]でJSメソッド実行で戻る ここまで ●(BODYの)位置取得とは BODYの"getPosition"を[]でJSメソッド実行で戻る ここまで ●(BODYの)回転角取得とは BODYの"getAngle"を[]でJSメソッド実行で戻る ここまで ●(BODYの)線速度取得とは BODYの"getLinearVelocity"を[]でJSメソッド実行で戻る ここまで ●(BODYの)回転速度取得とは BODYの"getAngularVelocity"を[]でJSメソッド実行で戻る ここまで ●(BODYの)構造リスト取得とは BODYの"getFixtureList"を[]でJSメソッド実行で戻る ここまで ●(FIXTUREの)次構造取得とは FIXTUREの"getNext"を[]でJSメソッド実行で戻る ここまで ●(BODYの)構造A取得とは BODYの"getFixtureA"を[]でJSメソッド実行で戻る ここまで ●(BODYの)構造B取得とは BODYの"getFixtureB"を[]でJSメソッド実行で戻る ここまで ●(FIXTUREの)Body取得とは FIXTUREの"getBody"を[]でJSメソッド実行で戻る ここまで ●(FIXTUREの)形取得とは FIXTUREの"getShape"を[]でJSメソッド実行で戻る ここまで ●(JOINTの)Joint回転角度取得とは JOINTの"getJointAngle"を[]でJSメソッド実行で戻る ここまで ●(JOINTの)Joint角速度取得とは JOINTの"getJointSpeed"を[]でJSメソッド実行で戻る ここまで ●(BODYにOBJを)UserData設定とは BODYの"setUserData"を[OBJ]でJSメソッド実行 ここまで ●(BODYから)UserData取得とは BODYの"getUserData"を[]でJSメソッド実行で戻る ここまで ●(JOINTにSPEEDで)モーター速設定とは JOINTの"setMotorSpeed"を[SPEED]でJSメソッド実行 ここまで ●(JOINTにTORQUEで)モーター最大トルク設定とは JOINTの"setMaxMotorTorque"を[TORQUE]でJSメソッド実行 ここまで ●(SHAPEの)形名取得とは SHAPEの"getType"を[]でJSメソッド実行で戻る ここまで ●(WORLDをOPTSで)PLStepとは WORLDの"step"をOPTSでJSメソッド実行 ここまで ●(OPTSで)NewWorldとは 『(function(pl,o){return new pl.World(o);})』を[PL,OPTS]でJS関数実行で戻る ここまで ●(FUNCをWORLDのP1からP2に)WorldRayCastとは WORLDの"rayCast"を[P1,P2,FUNC]でJSメソッド実行 ここまで ●(FUNCをTARGETのEVTNAMEに)ONイベント設定とは TARGETの"on"を[EVTNAME, FUNC]でJSメソッド実行 ここまで ### 汎用命令 ●(Sを)動的インポートとは 『(function(s) {return import(s);})』を[S]でJS関数実行で戻る ここまで ●RNDとは 『(function(){return Math.random();})』を[]でJS関数実行で戻る ここまで ●(AをIMINからIMAXまで)CLIPとは もし、A<IMINならば、 IMINで戻る 違えばもし、A>IMAXならば、 IMAXで戻る ここまで Aで戻る ここまで ●(A,B)MINとは もし、A<Bならば、 Aで戻る ここまで Bで戻る ここまで ●(A,B)MAXとは もし、A>Bならば、 Aで戻る ここまで Bで戻る ここまで ●(N,L)NumToFixedとは 『(function(n,l){return n.toFixed(l);})』を[N, L]でJS関数実行で戻る ここまで ●(Aから)色スタイルとは "rgb({A[0]},{A[1]},{A[2]})"で戻る ここまで # CarRacingはトップビューのカーレースゲーム。 # ハンドル操作、アクセル操作、ブレーキ操作が可能。 # フィールドをはみ出したらゲームオーバー。 # また、コースを一周回った場合もゲームクリアの扱いで # ゲーム終了(打切り) # クリアの判定は、いかのいずれか。 # 95%以上のタイル(道路)を踏んでスタート地点を踏む。 # すべてのタイル(道路)を踏む。 # タイルは踏むと色が少し変わる(暗くなる) # 現在の状態はGYMステップから返されるSTATEとしてあらわされる。 # STATEは96*96*4の配列になる。 # 横96pixel,縦96pixel,R,G,B,A4チャンネルのPixel画像を表す。 # 必要に応じてアルファチャンネルの除外や0-1.0へのノーマライズを # 実施して利用すること。 # 行動はGYMステップへ与えるACTIONとしてあらわす。 # ACTIONは要素3の配列。 # 0:ハンドル。中立が0.0。左へ最大-1.0、右へ最大+1.0で操作する。 # 1:アクセル。0から1.0の間の値で指定する。 # 2:ブレーキ。0から1.0の間の値で指定する。0.9を超えるとタイヤがロックする。 # タイヤと路面の間に大きな力が加わるとスリップする。 # ラフは路面よりも滑りやすい。 # 以下はカーソルキーで人間が直接操作するロジック(本家のOpenAI Gymと同じもの)。 # 本来は各操作はアナログ値で柔軟に操作可能なものの、キーボードで操作する # 都合上、力加減は固定になっている。 # 左上の小さな画像がSATEの内容。インジケータ類は含まれないようにしている。 ●走行テストとは 描画中キャンバスにキーパッドイベント設定 GYM作成 GYMリセット 継続フラグはオン 継続フラグの間 ボタン状態更新 Aは[0,0,0] もし、(中断チェック)ならば、 抜ける ここまで もし、(12の保持チェック)ならば、 # アクセルの踏み込み強さ。0から1.0の範囲 # 0.2ぐらいにすると操作しやすい A[1]は1 ここまで もし、(13の保持チェック)ならば、 # ブレーキの踏み込み強さ。0から1.0の範囲 # タイヤがロックしない範囲で強めの値 A[2]は0.8 ここまで もし、(14の保持チェック)ならば、 # ハンドルを左に切る時の強さ。0から-1.0の範囲 # -0.6ぐらいにすると操作しやすい A[0]は-1 ここまで もし、(15の保持チェック)ならば、 # ハンドルを右に切る時の強さ。0から1.0の範囲 # 0.6ぐらいにすると操作しやすい A[0]は1 ここまで 結果はAでGYMステップ もし、結果[2]ならば、 継続フラグはオフ ここまで GYM描画 (1.0/FPS)秒待つ ここまで GYM破棄 キーパッドイベント解除 ここまで # キーパッド機能 キーマッピングは{ "ArrowDown":13, "ArrowRight":15, "ArrowLeft":14, "ArrowUp":12, "40":13, "39":15, "37":14, "38":12, "KeyZ":0, "KeyX":1, "KeyA":2, "KeyS":3, "90":0, "89":1, "65":2, "83":3, "Escape":-1, "27":-1 } ボタン状態は0 前回ボタン状態は0 現在ボタン状態は0 キーパッドイベント対象は0 ゲーム中断キーはオフ ●(対象に)キーパッドイベント設定とは キーパッドイベント対象は対象 もし、対象["tagName"]が「CANVAS」ならば、 対象["tabIndex"]は0 []で対象の"focus"をJSメソッド実行 ここまで 対象の「keydown」に「キー押」をDOMイベント追加 対象の「keyup」に「キー離」をDOMイベント追加 ここまで ●キーパッドイベント解除とは キーパッドイベント対象の「keydown」から「キー押」をDOMイベント削除 キーパッドイベント対象の「keyup」から「キー離」をDOMイベント削除 ここまで ●キー押すとは EVTはWINDOW["event"] もし、EVT["code"]ならば、 コードはEVT["code"] キーはキーマッピング[コード] 違えば、 コードはEVT["keyCode"] キーはキーマッピング[コード] ここまで もし、(キーの変数型確認)が"undefined"でなければ、 もし、キー≧0ならば、 値は1をキーでSHIFT_L ボタン状態はボタン状態と値のOR 違えば、 ゲーム中断キーはオン ここまで EVTのDOMイベント処理停止 ここまで ここまで ●キー離すとは EVTはWINDOW["event"] もし、EVT["code"]ならば、 コードはEVT["code"] キーはキーマッピング[コード] 違えば、 コードはEVT["keyCode"] キーはキーマッピング[コード] ここまで もし、(キーの変数型確認)が"undefined"でなければ、 もし、キー≧0ならば、 値は1をキーでSHIFT_LのNOT ボタン状態はボタン状態と値のAND EVTのDOMイベント処理停止 ここまで ここまで ここまで ●ボタン状態更新とは 前回ボタン状態は現在ボタン状態 現在ボタン状態はボタン状態 ここまで ●(INDEXの)押下チェックとは 値は1をINDEXでSHIFT_L ((値と現在ボタン状態のAND)と(前回ボタン状態のNOT)のAND)で戻る ここまで ●(INDEXの)保持チェックとは 値は1をINDEXでSHIFT_L (値と現在ボタン状態のAND)≠0で戻る ここまで ●中断チェックとは ゲーム中断キーで戻る ここまで もし、プラグイン名が『メイン』ならば、 走行テスト ここまで