-
-
Save yusuke/ea1f20c1284690322a558af3e560d853 to your computer and use it in GitHub Desktop.
Night Bird
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//****************************************************************************** | |
// NightBirdFrame.java: JFrame | |
// Copyright Kishida Naoki | |
//****************************************************************************** | |
import java.awt.Color; | |
import java.awt.Graphics; | |
import java.awt.Image; | |
import java.awt.image.BufferedImage; | |
import java.io.Serial; | |
import java.util.ArrayList; | |
import java.util.Collections; | |
import java.util.List; | |
import java.util.stream.Collector; | |
import javax.swing.JFrame; | |
import javax.swing.Timer; | |
//============================================================================== | |
// アプレット NightBird のメインクラス | |
// | |
//============================================================================== | |
public class NightBirdFrame extends JFrame{ | |
public static void main(String[] args) { | |
new NightBirdFrame().init(); | |
} | |
// | |
//--- 鳥の形のデータ --- | |
// | |
//胴体 | |
record PolyPoint(double x, double y){ | |
static PolyPoint of(double x, double y){ | |
return new PolyPoint(x, y); | |
} | |
} | |
static final List<PolyPoint> bPolyBodyHalf = List.of( | |
PolyPoint.of(0, 0), | |
PolyPoint.of(0, 2), | |
PolyPoint.of(1, 5), | |
PolyPoint.of(4, 11), | |
PolyPoint.of(9, 14), | |
PolyPoint.of(18, 14), | |
PolyPoint.of(22, 13), | |
PolyPoint.of(24, 9), | |
PolyPoint.of(24, 6), | |
PolyPoint.of(22, 3), | |
PolyPoint.of(21, 0) | |
); | |
static final List<PolyPoint> bPolyBody; | |
static{ | |
bPolyBody = new ArrayList<>(bPolyBodyHalf); | |
for (int i = bPolyBodyHalf.size() - 1; i >= 0; i--) { | |
var e = bPolyBodyHalf.get(i); | |
bPolyBody.add(PolyPoint.of(e.x, -e.y)); | |
} | |
} | |
//はね | |
static final PolyPoint[] bPolyWing = { | |
PolyPoint.of(6,-4), | |
PolyPoint.of(12,-4), | |
PolyPoint.of(10, -20), | |
PolyPoint.of(6,-10)}; | |
@Serial | |
private static final long serialVersionUID = 1L; | |
List<PolyPoint> polyBody; | |
PolyPoint[] polyLWing = new PolyPoint[4]; | |
PolyPoint[] polyRWing = new PolyPoint[4]; | |
// | |
//--- 定数 --- | |
// | |
static final double pai = 6.283; | |
static final double eyeY = 100; //視点の高さ | |
static final double scrZ = 100; //画面の距離 | |
static final int rotMax = 300; //回転の精度 | |
static final int wingMax = 5; //はねの動きの精度 | |
static final double birdY = 40; //鳥の高さ | |
static final double birdRate = 1.8;//鳥の大きさ | |
// | |
//--- 変数 --- | |
// | |
transient Image backbuf; | |
transient Graphics backbufgra; //内部描画バッファ | |
int m_width, m_height; //画面の大きさ | |
int centerX, centerY; //画面の中心 | |
double rot; | |
double eyeX; //視点の座標 | |
int[][] ground = new int[80][80];//地面のつぶつぶ | |
double birdX; //鳥の位置 | |
int roll; //回転の長さ | |
int birdmove; //鳥の動き | |
int wing; //はねの角度 | |
//-------------------------------------------------------------------------- | |
public void init() { | |
setTitle("Night Duke"); | |
setSize(600, 400); | |
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); | |
m_width = getSize().width; | |
m_height = getSize().height; | |
centerX = m_width / 2; | |
centerY = m_height / 2; | |
rot = rotMax / 8d; | |
//内部描画バッファの用意 | |
if (backbuf == null) { | |
backbuf = new BufferedImage(m_width, m_height, BufferedImage.TYPE_INT_RGB); | |
backbufgra = backbuf.getGraphics(); | |
} | |
//地面 | |
for (int i = 0; i < 80; i++) { | |
for (int j = 0; j < 80; j++) { | |
if (Math.random() > .99) { | |
ground[i][j] = 1; | |
} else { | |
ground[i][j] = 0; | |
} | |
} | |
} | |
//鳥のデータ | |
polyBody = bPolyBody.stream().map(e -> PolyPoint.of(e.x * birdRate, e.y * birdRate)).toList(); | |
for (int i = 0; i < 4; i++) { | |
polyLWing[i] = PolyPoint.of(bPolyWing[i].x * birdRate, | |
bPolyWing[i].y * birdRate); | |
polyRWing[i] = PolyPoint.of(polyLWing[i].x, -polyLWing[i].y); | |
} | |
new Timer(50, ev -> draw()).start(); | |
setVisible(true); | |
} | |
// NightBird 描画ハンドラ | |
//-------------------------------------------------------------------------- | |
@Override | |
public void paint(Graphics g) { | |
g.drawImage(backbuf, 0, 0, this); | |
} | |
//描画 | |
//---------------------------------------------------------------------------- | |
public void draw() { | |
double co, si; | |
//前に進む | |
eyeX += 4; | |
while (eyeX > 80) { | |
eyeX -= 80; | |
} | |
//視点の回転 | |
if (roll > 0) { | |
//回転中 | |
rot++; | |
if (rot >= rotMax) { | |
rot = 0; | |
} | |
roll--; | |
} else { | |
if (Math.random() > .98) { | |
//回転開始 | |
roll = (int) (Math.random() * 20) + 10; | |
} | |
} | |
if (birdmove == 0) { | |
//鳥がはばたいているとき | |
wing++; | |
if (wing >= wingMax) { | |
wing = 0; | |
//後ろに下がるかどうか判定 | |
if (Math.random() > .92) { | |
birdmove = (int) (Math.random() * 15) + 10; | |
} | |
} | |
if (birdX < 0) { | |
birdX += 1; | |
} | |
} else { | |
//鳥が後ろに下がっているとき | |
birdmove--; | |
birdX -= 1; | |
} | |
// | |
//--- 画面描画 --- | |
// | |
//画面のクリア | |
backbufgra.setColor(Color.black); | |
backbufgra.fillRect(0, 0, m_width, m_height); | |
//地面の描画 | |
backbufgra.setColor(Color.red); | |
co = Math.cos(Math.PI * 2 * rot / rotMax); | |
si = Math.sin(Math.PI * 2 * rot / rotMax); | |
for (int y = centerY + 20; y < m_height; y++) { | |
double dispx, dispy; | |
double groundx, groundz; | |
double matx, matz; | |
int meshx, meshz; | |
dispy = centerY - y; | |
groundz = -eyeY * scrZ / dispy; | |
if (groundz > 250) { | |
continue; | |
} | |
for (int x = 0; x < m_width; x++) { | |
dispx = x - centerX; | |
groundx = (dispx * groundz / scrZ); | |
matz = (groundx * co + (groundz - scrZ) * si + scrZ) / 4; | |
while (matz < 0) { | |
matz += 80; | |
} | |
meshz = (int) matz % 80; | |
matx = (-groundx * si + groundz * co) / 4 + eyeX; | |
while (matx < 0) { | |
matx += 80; | |
} | |
meshx = (int) matx % 80; | |
if (ground[meshx][meshz] == 1) { | |
//backbufgra.drawRect(x,y,1,1); | |
backbufgra.drawLine(x, y, x, y); | |
} | |
} | |
} | |
//鳥の描画 | |
backbufgra.setColor(new Color(192, 192, 192)); | |
int[] polyX = new int[polyBody.size()]; | |
int[] polyY = new int[polyBody.size()]; | |
double bx, by, bz; | |
double px, py, pz; | |
double ax, ay, az;//計算用 | |
double wco, wsi; | |
double wpi;//はねの角度 | |
double bodyY;//胴体の位置 | |
//はねの角度の計算 | |
wpi = pai * (.22 * Math.sin(pai * wing / wingMax) + .25); | |
wsi = Math.sin(wpi); | |
wco = Math.cos(wpi); | |
//鳥の上下運動 | |
bodyY = -wco * 2; | |
//胴体 | |
for (int i = 0; i < polyBody.size(); i++) { | |
var bodyPoint = polyBody.get(i); | |
bx = -bodyPoint.x + birdX; | |
bz = bodyPoint.y; | |
px = -bx * si + bz * co; | |
pz = bx * co + bz * si; | |
polyX[i] = (int) (px * scrZ / (scrZ + pz)) + centerX; | |
polyY[i] = -(int) ((birdY + bodyY) * scrZ / (scrZ + pz)) + centerY; | |
} | |
backbufgra.fillPolygon(polyX, polyY, polyBody.size()); | |
//右の翼 | |
for (int i = 0; i < 4; i++) { | |
bx = -polyRWing[i].x + birdX; | |
bz = polyRWing[i].y; | |
az = bz - polyRWing[0].y; | |
ay = 0; | |
bz = wsi * az + polyRWing[0].y; | |
by = wco * az; | |
px = -bx * si + bz * co; | |
pz = bx * co + bz * si; | |
polyX[i] = (int) (px * scrZ / (scrZ + pz)) + centerX; | |
polyY[i] = -(int) ((birdY + by + bodyY) * scrZ / (scrZ + pz)) + centerY; | |
} | |
backbufgra.fillPolygon(polyX, polyY, 4); | |
//左の翼 | |
for (int i = 0; i < 4; i++) { | |
bx = -polyLWing[i].x + birdX; | |
bz = polyLWing[i].y; | |
az = bz - polyLWing[0].y; | |
ay = 0; | |
bz = wsi * az + polyLWing[0].y; | |
by = -wco * az; | |
px = -bx * si + bz * co; | |
pz = bx * co + bz * si; | |
polyX[i] = (int) (px * scrZ / (scrZ + pz)) + centerX; | |
polyY[i] = -(int) ((birdY + by + bodyY) * scrZ / (scrZ + pz)) + centerY; | |
} | |
backbufgra.fillPolygon(polyX, polyY, 4); | |
repaint(); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment