追記
諸事情によりJavaではなくJavascriptになりました
こんな
操作方法
操作 | キー |
---|---|
視線移動 | 方向キー |
加速 | A |
減速 | Z |
ズーム | 左クリック |
視点切り替え | 右クリック |
紙飛行機 | 1 |
お楽しみ | 2 |
プログラム
PaperPlane.js
//画角
let fov = 3
//視点切り替え
let cameraView = true
//紙飛行機クラス
let pp
// カメラ視点
let camera
let cloudPosArray = []
function setup() {
createCanvas(600, 600, WEBGL)
background(100)
pp = new PaperPlane()
camera = createCamera()
let length = 100
for(let i=0; i<length;i++){
cloudPosArray.push(new createVector(random(0,TWO_PI), random(-5000,500), random(2000,3000)));
}
}
function draw() {
background(50,50,100)
//モードで視点切り替え
if(cameraView)
{
camera.setPosition(150, -500, 1000)
camera.lookAt(pp.pos.x, pp.pos.y, pp.pos.z)
let dis = pp.pos.copy().sub(150, -500, 1000).mag()
perspective(PI/max(2,min(10,dis/100)), width/height,10,10000)
}
else
{
camera.setPosition(pp.pos.x, pp.pos.y, pp.pos.z)
camera.lookAt(pp.nextPos.x, pp.nextPos.y, pp.nextPos.z + (pp.speed === 0 ? 1 : 0))
perspective(PI/3, width/height,10,10000)
}
push()
rotateX(PI/2)
lights()
pop()
let inputDire = createVector()
if(keyIsPressed){
switch(key){
case "a":
pp.SpeedUp()
break
case "z":
pp.SpeedDown()
break
case "ArrowUp":
inputDire.y += 1
break
case "ArrowRight":
inputDire.x += 1
break
case "ArrowDown":
inputDire.y -= 1
break
case "ArrowLeft":
inputDire.x -= 1
break
case "r":
pp.Reset()
break
case "1":
pp.SetMode(1)
break
case "2":
pp.SetMode(2)
break
}
}
pp.Control(inputDire)
pp.Move()
pp.Draw()
drawEnv()
}
function drawEnv() {
drawFlor()
drawCloud()
//床
function drawFlor(){
fill(0,150,0)
strokeWeight(1)
for(let i= -5;i<= 5;i++){
for(let j= -10;j<=10;j++){
push()
translate(i*300,0,j*300)
box(180,10,180)
pop()
}
}
}
function drawCloud(){
//雲
fill(255)
strokeWeight(1)
for(let i=0; i<cloudPosArray.length;i++){
push()
let pos = cloudPosArray[i]
rotateY(pos.x)
translate(0,pos.y,pos.z)
box(200,50,100)
pop()
}
}
}
function ClampPI(rotate){
// 半回転したら逆からの回転値を返す
// 例:[3.15 => -3.13 ] = sign(-x) * (3.14 - (abs(x)-3.14)) =sign(-x) * (3.14 -abs(x) + 3.14)) =sign(-x) * (2*PI-abs(x))
if(abs(rotate) >= PI) return Sign(-rotate) * (2 * PI - abs(rotate))
return rotate
}
function Sign(a){
if(a > 0) return 1
else if(a < 0) return -1
else return 0
}
function mousePressed(){
//画角切り替え
if(mouseButton === LEFT) {
if(fov == 36) fov = 3;
else fov = 36;
}
//視点切り替え
if(mouseButton === RIGHT){
cameraView = !cameraView;
}
}
// コンテキストメニューを無効化する
document.oncontextmenu = (e) => {
e.preventDefault();
}
paperPlane.js
class PaperPlane{
constructor(){
this.Reset()
}
Reset(){
this.pos = createVector(0, -300 , -1000)
this.nextPos = this.pos.copy()
this.direction = createVector(0,0,0.01)
this.rotate = createVector()
this.speed = this.wy = this.wr = 0
this.wx = 30
this.wingR = PI/90//翼のはばたき速度
this.mode = 1
}
SpeedUp(){
this.speed += 0.05
}
SpeedDown(){
if(this.speed > 0.1) this.speed -= 0.05
else this.speed = 0
}
SetMode(num){
switch(num){
case 1:
case 2:
this.mode = num
break
default:
console.log("対応してないモードです")
break
}
}
Control(inputVec){
if(inputVec.magSq() < 1){
//水平との誤差が1度なら(2*PI/360=PI/180)機体を水平とする
if(abs(this.rotate.x) < PI/180) this.rotate.x = 0
else this.rotate.x -= Sign(this.rotate.x) * PI / 360
if(abs(this.rotate.z) < PI/180) this.rotate.z = 0
else this.rotate.z -= Sign(this.rotate.z) * PI / 360
}else{
// 入力と回転がずれてるのでxにyで減算する
this.rotate.x -= inputVec.y * PI / 180
this.rotate.y -= inputVec.x * PI / 180
// 傾きを与える
if(abs(this.rotate.z) < PI/3) this.rotate.z -= Sign(inputVec.x) * PI/360
// PIを超えた回転を修正
this.rotate.x = ClampPI(this.rotate.x)
this.rotate.y = ClampPI(this.rotate.y)
this.rotate.z = ClampPI(this.rotate.z)
}
this.direction.x = sin(this.rotate.y)
this.direction.y = sin(this.rotate.x)
this.direction.z = cos(this.rotate.x) * cos(this.rotate.y)
}
Move(){
//位置移動
let dire = this.direction.copy().normalize()
this.pos = this.pos.add(dire.mult(this.speed))
this.nextPos = this.pos.copy().add(dire.mult(max(this.speed,1)))
}
Draw(){
push()
translate(this.pos)
rotateX(this.rotate.x * Sign(cos(this.rotate.y)) * -1)
rotateY(this.rotate.y)
rotateZ(this.rotate.z)
strokeWeight(0.5)
switch(this.mode){
case 1: this.paperPlane()
break
case 2: this.paperClane()
break
}
pop()
}
paperPlane(){
beginShape(TRIANGLE_FAN)
vertex(0,0,0)
vertex(-30,5,-50)
vertex(-5,0,-50)
vertex(0,20,-50)
vertex(5,0,-50)
vertex(30,5,-50)
endShape()
}
//おりづる
paperClane(){
//ツバサバサバサ
this.wr += this.wingR * this.speed * 0.5
if(abs(this.wr) > radians(30)){
this.wingR *= -1
this.wr += this.wingR
}
this.wx = 40 * cos(this.wr)
this.wy = 40 * sin(this.wr)
//頭
beginShape(TRIANGLE_FAN)
vertex(0,0,10)
vertex(-2,-7,5)
vertex(0,-5,2)
vertex(2,-7,5)
endShape()
//首
beginShape(QUAD_STRIP)
vertex(-2,-7,5)
vertex(-3,10,-2)
vertex(0,-5,2)
vertex(0,7,-4)
vertex(2,-7,5)
vertex(3,10,-2)
endShape()
//左右胴体
for(let i=-1;i<=1;i+=2){
beginShape(QUAD_STRIP)
vertex(0,17,-7)
vertex(0,7,-4)
vertex(3*i,17,-5)
vertex(3*i,10,-2)
vertex(2*i,17,-13)
vertex(4*i,10,-13)
vertex(3*i,17,-21)
vertex(3*i,10,-23)
vertex(0,17,-20)
vertex(0,7,-22)
endShape()
}
//背中のとんがり
beginShape(TRIANGLE_FAN)
vertex(0,6,-13)
vertex(0,7,-4)
vertex(3,10,-2)
vertex(4,10,-13)
vertex(3,10,-23)
vertex(0,7,-22)
vertex(-3,10,-23)
vertex(-4,10,-13)
vertex(-3,10,-2)
vertex(0,7,-4)
endShape()
//下側
beginShape(TRIANGLE_FAN)
vertex(0,17,-13)
vertex(0,17,-7)
vertex(3,17,-5)
vertex(2,17,-13)
vertex(3,17,-21)
vertex(0,17,-20)
vertex(-3,17,-21)
vertex(-2,17,-13)
vertex(-3,17,-5)
vertex(0,17,-7)
endShape()
//尾
beginShape(TRIANGLE_FAN)
vertex(0,-10,-30)
vertex(3,10,-23)
vertex(0,7,-22)
vertex(-3,10,-22)
endShape()
//翼
for(let i=-1;i<=1;i+=2){
push()
translate(0,10,0)
beginShape(TRIANGLE_FAN)
vertex(this.wx*i,this.wy,-13)
vertex(3*i,0,-2)
vertex(4*i,0,-13)
vertex(3*i,0,-23)
endShape()
pop()
}
}
}