質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.35%
canvas

HTML5の<canvas>要素用のタグです。CanvasはHTML5から導入された、二次元の図形描写が可能な要素です。

JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

Q&A

0回答

864閲覧

一人称視点のfpsゲームで自分の打った弾が視界から外れたら画面に見えなくなるようにしたい

teratera2

総合スコア3

canvas

HTML5の<canvas>要素用のタグです。CanvasはHTML5から導入された、二次元の図形描写が可能な要素です。

JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

0グッド

1クリップ

投稿2021/12/15 15:37

現状、常に視界の中心に打った弾が移るので視界をずらしたら横にずれて視界から消えたら画面から消えるようにしたいです。
p5.jsで実装中
視界はhitbeam(黄色い線)

javascript

1'use strict'; 2 3class Vec2 { 4 /** 5 * @param {number} x 6 * @param {number} y 7 */ 8 constructor(x, y) { 9 this.x = x; 10 this.y = y; 11 } 12 /** 13 * @param {Vec2} b 14 */ 15 add(b) { 16 let a = this; 17 return new Vec2(a.x+b.x, a.y+b.y); 18 } 19 /** 20 * @param {Vec2} b 21 */ 22 sub(b) { 23 let a = this; 24 return new Vec2(a.x-b.x, a.y-b.y); 25 } 26 copy() { 27 return new Vec2(this.x, this.y); 28 } 29 /** 30 * @param {number} s 31 */ 32 mult(s) { 33 return new Vec2(s*this.x, s*this.y); 34 } 35 mag() { 36 return sqrt(this.x ** 2 + this.y ** 2); 37 } 38} 39 40class Ray2 { 41 /** 42 * @param {Vec2} pos このレイの始点の位置ベクトル. 43 * @param {Vec2} way このレイの始点から伸びる方向ベクトル. 44 */ 45 constructor(pos, way) { 46 this.pos = pos; 47 this.way = way; 48 } 49 /** 50 * @param {Vec2} begin 51 * @param {Vec2} end 52 */ 53 static withPoints(begin, end) { 54 return new Ray2(begin, end.sub(begin)); 55 } 56 get begin() { 57 return this.pos; 58 } 59 get end() { 60 return this.pos.add(this.way); 61 } 62 /** 63 * @param {Ray2} r2 64 */ 65 intersection(r2) { 66 let r1 = this; 67 // Y軸並行の線分はこのコードでは扱えないので、並行の場合は微妙にずらす 68 // an dirty hack since this code cannot handle Y-axis parallel rays. 69 if (abs(r1.way.x) < 0.01) r1.way.x = 0.01; 70 if (abs(r2.way.x) < 0.01) r2.way.x = 0.01; 71 72 // r1,r2を直線として見て、その交点を求める 73 // Treat r1,r2 as straight lines and calc the intersection point. 74 let t1 = r1.way.y / r1.way.x; 75 let t2 = r2.way.y / r2.way.x; 76 let x1 = r1.pos.x; 77 let x2 = r2.pos.x; 78 let y1 = r1.pos.y; 79 let y2 = r2.pos.y; 80 let sx = (t1*x1 - t2*x2 - y1 + y2) / (t1 - t2); 81 let sy = t1 * (sx - x1) + y1; 82 83 // 交点が線分上にないときはnullを返す 84 // Return null if the intersection point is not on r1 and r2. 85 if ( 86 sx > min(r1.begin.x, r1.end.x) 87 && sx < max(r1.begin.x, r1.end.x) 88 && sx > min(r2.begin.x, r2.end.x) 89 && sx < max(r2.begin.x, r2.end.x) 90 ){ 91 return new Vec2(sx, sy); 92 }else{ 93 return null; 94 } 95 } 96} 97 98class Player { 99 constructor() { 100 this.pos = new Vec2(0, 0); 101 this.angle = 0; 102 } 103} 104 105class Game { 106 constructor() { 107 this.player = new Player(); 108 this.walls = []; 109 } 110 reset() { 111 this.player.pos = new Vec2(150, 250); 112 this.player.angle = 0; 113 114 this.walls = [ 115 Ray2.withPoints(new Vec2(50, 50), new Vec2(100, 300)), 116 Ray2.withPoints(new Vec2(100, 300), new Vec2(250, 200)), 117 Ray2.withPoints(new Vec2(250, 200), new Vec2(50, 50)), 118 ]; 119 } 120} 121 122class PlayerShot { 123 constructor() { 124 this.pos = new Vec2(0,0); 125 this.angle = 0; 126 this.sDistance = 0; 127 this.walls = []; 128 this.alive = false; 129 this.size = 0 130 } 131 132 set(p,angle,speed,walls,size) { 133 this.pos.x = p.x; 134 this.pos.y = p.y; 135 this.angle = angle; 136 this.speed = speed; 137 this.walls = walls; 138 this.alive = true; 139 this.size = size; 140 } 141 142 distance() { 143 let beam = new Ray2( 144 this.pos, 145 new Vec2(cos(this.angle), sin(this.angle)).mult(120) 146 ); 147 148 let allHitBeamWays = this.walls.map(wall => beam.intersection(wall)) 149 .filter(pos => pos !== null) 150 .map(pos => pos.sub(beam.begin)); 151 if (allHitBeamWays.length === 0) return 0; 152 let hitBeam = allHitBeamWays.reduce((a, b) => a.mag() < b.mag() ? a : b); 153 return hitBeam.mag(); 154 } 155 156 move() { 157 this.pos.x += this.speed * cos(this.angle); 158 this.pos.y += this.speed * sin(this.angle); 159 this.sDistance = this.distance(); 160 //print(this.sDistance); 161 if(this.sDistance == 0) { 162 //print("i"); 163 this.alive = false; 164 } 165 } 166 167} 168 169// グローバル変数 Global variables 170let game; 171let fire = false; 172let count = 0; 173var CHARA_COLOR = 'rgba(0, 0, 255, 0.75)'; 174var CHARA_SHOT_COLOR = 'rgba(0, 255, 0, 0.75)'; 175var CHARA_SHOT_MAX_COUNT = 10; 176let shotDist = new Vec2(0,0); 177 178let charaShot = new Array(CHARA_SHOT_MAX_COUNT); 179for(let i = 0; i < CHARA_SHOT_MAX_COUNT; i++){ 180 charaShot[i] = new PlayerShot(); 181} 182 183function setup() { 184 createCanvas(720, 480); 185 186 game = new Game(); 187 game.reset(); 188} 189 190function draw() { 191 noSmooth(); 192 193 // 背景 194 background(64); 195 196 // 壁を描画. Draw the walls 197 strokeWeight(3); 198 stroke('white'); 199 let walls = game.walls; 200 for(let wall of walls) { 201 line(wall.begin.x, wall.begin.y, wall.end.x, wall.end.y); 202 } 203 204 // プレイヤーを描画. Draw the player 205 stroke('yellow'); 206 strokeWeight(20); 207 let player = game.player; 208 point(player.pos.x, player.pos.y); 209 210 // キー入力. Key input 211 if (keyIsDown(LEFT_ARROW)) player.angle -= PI / 120; 212 if (keyIsDown(RIGHT_ARROW)) player.angle += PI / 120; 213 //Aキーで発射 214 if (keyIsDown(65)) {fire = true; } 215 216 // 3Dビューを描画. Draw the 3d view. 217 { 218 let viewRect = new Ray2(new Vec2(380, 40), new Vec2(320, 240)); 219 let fov = PI / 2; 220 let centerAngle = player.angle; 221 let leftAngle = centerAngle - fov/2; 222 let rightAngle = centerAngle + fov/2; 223 let beamTotal = 32; 224 let beamIndex = -1; 225 for(let angle=leftAngle; angle<rightAngle-0.01; angle+=fov/beamTotal) { 226 beamIndex++; 227 let beam = new Ray2( 228 player.pos.copy(), 229 new Vec2(cos(angle), sin(angle)).mult(120) 230 ); 231 232 stroke('yellow'); 233 strokeWeight(1); 234 line(beam.begin.x, beam.begin.y, beam.end.x, beam.end.y); 235 236 // 光線が2枚以上の壁にあたっていたら、一番近いものを採用する。 237 // Adapt the nearest beam. 238 let allHitBeamWays = walls.map(wall => beam.intersection(wall)) 239 .filter(pos => pos !== null) 240 .map(pos => pos.sub(beam.begin)); 241 if (allHitBeamWays.length === 0) continue; 242 let hitBeam = allHitBeamWays.reduce((a, b) => a.mag() < b.mag() ? a : b); 243 244 stroke('yellow'); 245 strokeWeight(8); 246 let hitPos = hitBeam.add(beam.begin); 247 point(hitPos.x, hitPos.y); 248 249 let wallDist = hitBeam.mag(); 250 let wallPerpDist = wallDist * cos(angle - centerAngle); 251 let lineHeight = constrain(2800 / wallPerpDist, 0, viewRect.way.y); 252 let lineBegin = viewRect.begin.add( 253 new Vec2( 254 viewRect.way.x/beamTotal*beamIndex, 255 viewRect.way.y/2-lineHeight/2 256 ) 257 ); 258 let lightness = 224; 259 strokeWeight(0); 260 fill(lightness); 261 rect(lineBegin.x, lineBegin.y, 7, lineHeight); 262 263 // fireフラグの値により分岐 264 if(fire){ 265 // すべての自機ショットを調査する 266 for(let i = 0; i < CHARA_SHOT_MAX_COUNT; i++){ 267 // 自機ショットが既に発射されているかチェック 268 if(!charaShot[i].alive){ 269 // 自機ショットを新規にセット 270 charaShot[i].set(player.pos,player.angle, 0.1 ,walls,3); 271 272 // ループを抜ける 273 break; 274 } 275 } 276 // フラグを降ろしておく 277 fire = false; 278 } 279 280 drawingContext.beginPath(); 281 // すべての自機ショットを調査する 282 for(let i = 0; i < CHARA_SHOT_MAX_COUNT; i++){ 283 // 自機ショットが既に発射されているかチェック 284 if(charaShot[i].alive){ 285 // 自機ショットを動かす 286 charaShot[i].move(); 287 288 // 自機ショットを描くパスを設定 289 drawingContext.arc( 290 charaShot[i].pos.x, 291 charaShot[i].pos.y, 292 charaShot[i].size, 293 0, Math.PI * 2, false 294 ); 295 296 let shotSize = constrain(charaShot[i].distance(), 0, viewRect.way.y); 297 let shotBegin = viewRect.begin.add( 298 new Vec2( 299 viewRect.way.x/2, 300 viewRect.way.y/2 301 ) 302 ); 303 drawingContext.moveTo(shotBegin.x,shotBegin.y); 304 305 //一人称視点のショットを表示 306 //後に修正 307 drawingContext.arc( 308 shotBegin.x, 309 shotBegin.y, 310 shotSize, 311 shotSize, 312 0, Math.PI * 2, false 313 ); 314 315 //frameRate(30); 316 drawingContext.closePath(); 317 } 318 319 } 320 // 自機ショットの色を設定する 321 drawingContext.fillStyle = CHARA_SHOT_COLOR; 322 323 // 自機ショットを描く 324 drawingContext.fill(); 325 } 326 327 // 3Dビューの枠を描画. Draw border lines of the 3d view. 328 noFill(); 329 stroke('cyan'); 330 strokeWeight(4); 331 rect(viewRect.pos.x, viewRect.pos.y, viewRect.way.x, viewRect.way.y); 332 } 333} 334 335function touchMoved(event) { 336 let player = game.player; 337 player.pos.x = event.clientX; 338 player.pos.y = event.clientY; 339}

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだ回答がついていません

会員登録して回答してみよう

アカウントをお持ちの方は

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.35%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問