Upload
kunemata
View
1.343
Download
4
Embed Size (px)
Citation preview
Outline• 2D Graphics in Java
• OOP concepts in Graphics
• Complexity Graphics
• 2D Animations
• Timer APIs
Graphics• Graphic = สิ่งที่ถูกเขียนขึ้น
• Graphic != Animation != รูปภาพ
• Computer Graphics– กล่าวถึงการแสดงสิ่งที่ถูกเขียนบนคอมพิวเตอร์
– วิชา 01418482
• Graphical User Interface (GUI)
Graphics
Graphics
Graphics• ใน Java มี API ส าหรับกราฟฟิกโดยเฉพาะ
– ไม่ต้องเขียนสมการยาก ๆ กับการ์ดจอ
• ส่วนใหญ่อยู่ใน package java.awt
• สามารถแสดงผลได้ทั้ง 2D และ 3D– ในคอร์สนี้จะกล่าวถึง 2D เท่านั้น
– 3D จ าเป็นต้องศึกษาด้วยตนเอง
Computer’s 2D Space• การวาดภาพในคอมพิวเตอร์มีข้อตกลงที่ซับซ้อน
– ผลจากการใช้คณิตศาสตร์
• เมื่อวาดภาพจ าเป็นต้องรู้ต าแหน่งที่แน่นอน– จะให้เริ่มต้นวาดที่ไหนและจบที่ไหน
• การบอกต าแหน่งใช้พิกัดเป็นสื่อกลาง– x แทนแนวนอน, y แทนแนวตั้ง
• จุดก าเนิดอยู่ที่มุมซ้ายบนสุด– แตกต่างจากคณิตศาสตร์ที่เคยเรียนมา
Computer’s 2D Space(0, 0) +𝑥
+𝑦
Java Graphics API• การวาดรูปควรวาดใน Canvas หรือ JPanel
– JFrame เหมาะส าหรับใส่ component อื่นมากกว่า
– เกิดปัญหาเมื่อท างานกับ component จ านวนมาก
• อธิบายขั้นตอนการวาดใน paintComponent(g: Graphics)
– component ไม่มี s
– ใช้วิธีการ override method
• ส าหรับคลาส Canvas อธิบายใน paint(g: Graphics)– ปัจจุบันไม่นิยมใช้
Java Graphics API
JPanel panel = new JPanel() {
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
// TODO: Describe draw algorithm here
}
};
Java Graphics API• Graphics เป็น abstract class
– Provide method ไม่ค่อยเพียงพอต่อการวาดภาพ
• ใน JFrame g จะส่งวัตถุของคลาส sun.java2d.SunGraphics2D– SunGraphics2D inherited Graphics2D
– Graphics2D inherited Graphics
• สามารถ cast g เป็น Graphics2D– อ้างอิง method ใน Graphics2D ได้
– Provide method เพียงพอกับการวาดภาพสองมิติ
Java Graphics API
JPanel panel = new JPanel() {
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
// TODO: Describe draw algorithm here
}
};
Drawing Shape by Calling• Graphics2D สามารถวาดรูปเรขาคณิตผ่าน method
– ใช้เมื่อต้องการวาดรูปอย่างเดียว
– ไม่จ าเป็นต้องอ้างถึงรูปนั้นอีก
• Method การวาดส่วนใหญ่ขึ้นต้นด้วย draw– Ctrl + Space ดูได้ว่ามีอะไรบ้าง
• รูปที่วาดทีหลังจะแสดงอยู่เหนือรูปที่วาดก่อน– หลักการวาดทับ
– ล าดับของค าสั่ง
Drawing Shape by Calling (1)Method หน้าที่
drawLine(x1: int, y1: int, x2: int, y2: int)
วาดเส้นจากจุด 𝑥1, 𝑦1 ไปยัง 𝑥2, 𝑦2
drawOval(x: int, y: int,width: int, height: int)
วาดวงรีโดยก าหนดให้มุมซ้ายบนอยู่ที่ต าแหน่ง 𝑥, 𝑦 มีความกว้าง widthและสูง height
drawRect(x: int, y: int,width: int, height: int)
วาดสี่เหลี่ยมโดยก าหนดให้มุมซ้ายบนอยู่ที่ต าแหน่ง 𝑥, 𝑦 มีความกว้าง widthและสูง height
Drawing Shape by Calling (2)Method หน้าที่
drawString(str: String, x: int, y: int)
วาดตัวอักษร str โดยก าหนดให้ 𝑥, 𝑦
เป็น baseline ของตัวอักษรdrawArc(x: int, y: int,width: int, height: int, startAngle: int, arcAngle: int)
วาดส่วนโค้งโดยก าหนดความกว้าง, สูง, พิกัดที่อยู,่ องศาการเริ่มวาดส่วนโค้งและสิ้นสุดส่วนโค้ง
drawPolygon(xPoints: int[], yPoints: int[], nPoints: int)
วาดรูปหลายเหลี่ยมโดยก าหนดพิกัดและจ านวนพิกัด
Drawing Shape• การวาดรูปให้นึกถึงพิกัดเสมอ
• หากนึกไม่ออกให้ลองวาดบนกระดาษก่อน– สังเกตว่ามีจุดใดเริ่มต้น, สิ้นสุด และใช้เรขาคณิตแบบใด
• รูปที่ใช้บ่อยสามารถสร้างเป็นคลาสใหม่ได้– extends JPanel , override paintComponent(g: Graphics)
– override getPreferredSize(): Dimension เพื่อบอกขนาดขั้นต่ าของรูป
Drawing Shape by Object• เราสามารถสั่งให้ Graphics2D วาดรูปจาก object ได้
– ส่วนใหญ่สร้างจากคลาสใน package java.awt.geom
– สั่งวาดผ่าน method draw(s: Shape)
• สามารถก าหนดรูปร่างได้หลากหลายมากขึ้น– เพิ่มความยืดหยุ่น
• สามารถอ้างถึงรูปร่างที่วาดได้– มีประโยชน์ในการอ้างอิงถึงรูปร่างที่วาด
– ท า animation ได้ง่ายขึ้น
Drawing Shape by ObjectMethod Object
drawLine(x1: int, y1: int, x2: int, y2: int)
Line2D.DoubleLine2D.Float
drawOval(x: int, y: int,width: int, height: int)
Ellipse2D.DoubleEllipse2D.Float
drawRect(x: int, y: int,width: int, height: int)
Rectangle2D.DoubleRectangle2D.Float
drawPolygon(xPoints: int[], yPoints: int[], nPoints: int)
Polygon
drawArc(x: int, y: int,width: int, height: int, startAngle: int, arcAngle: int)
Arc2D.DoubleArc2D.Float
Fill Shape• หากเข้าใจการวาด การเทสีจะไม่มีปัญหา• g2d.fill…(…)
– เปลี่ยนจาก draw… เป็น fill…
– ยกเว้น fillLine, fillString
• สั่งเทสีผ่าน method fill(s: Shape)
g2d.fillRect(0, 0, 100, 100);g2d.fill(
new Rectangle2D.Double(100, 100, 100, 100));
Area• บางรูปไม่สามารถวาดด้วยวิธีการตรง
– ถึงแม้ polygon อาจจะเป็นไปยาก
• พยายามมองให้เป็นรูปเรขาคณิต– รูปเรขาคณิตที่ซ้อนทับกัน
• สามารถใช้คลาส Area ช่วยวาดรูปได้– java.awt.geom
– Area implements Shape
– สามารถวาดเส้นหรือเทสีได้
Area Operation
Area
?
Transformation• รูปร่างหน่ึงสามารถเปลี่ยนเป็นรูปร่างอ่ืนได้
• Transform = การแปลง– Linear Transform ในวิชา 01417322
• ใช้วัตถุของคลาส AffineTransform ในการแปลง– แปลงได้ทั้ง g2d และ object รูปร่าง
– ช่วยจัดการเรื่องคณิตศาสตร์ที่ซับซ้อน
Transformation
Transformation in g2d• การแปลงใน g2d ท าให้พิกัดการเริ่มต้นวาดรูปเปลี่ยนไป
– เปลี่ยนแปลงตามการแปลง
• การแปลงมีผลต่อการวาดรูปถัดไป– ล าดับก่อนหลังของค าสั่ง
– แปลงไปแล้วอย่าลืมแปลงกลับ
• ดูการแปลงด้วย g2d.getTransform(): AffineTransform
Transformation in g2dGraphics2D g2d = (Graphics2D) g;g2d.setColor(Color.BLUE);g2d.fillRect(0, 0, 100, 100);
g2d.setColor(Color.GREEN);g2d.translate(100, 100);g2d.fillRect(0, 0, 100, 100);
AffineTransform t = g2d.getTransform();System.out.println(t.getTranslateX());System.out.println(t.getTranslateY());
Transformation in g2dGraphics2D g2d = (Graphics2D) g;g2d.setColor(Color.BLUE);g2d.fillRect(0, 0, 100, 100);
g2d.setColor(Color.GREEN);g2d.translate(100, 100);g2d.fillRect(0, 0, 100, 100);
g2d.setColor(Color.BLACK);g2d.fillOval(-100, 0, 100, 100);
AffineTransform t = g2d.getTransform();System.out.println(t.getTranslateX());System.out.println(t.getTranslateY());
Transformation in Shape• การแปลงของ Shape object ต้องใช้ Area object ช่วย
– คลาส AffineTransform– + new(s: Shape)
• area.transform(t: AffineTransform)
– สร้างและก าหนดรูปแบบการแปลงก่อน
Transformation in ShapeGraphics2D g2d = (Graphics2D) g;g2d.setColor(new Color(0, 150, 200));
Area area = new Area(new Rectangle2D.Double(0, 0, 100, 100)
);AffineTransform t = new AffineTransform();
t.translate(150, 150);t.scale(2, 2);t.rotate(Math.toRadians(45));area.transform(t);
g2d.fill(area);
Animation• Animation = ภาพเคลื่อนไหว
• การเคลื่อนไหวเกิดขึ้นเมื่อมีแรงมากระท าหรือเคลื่อนไหวได้เอง– คน, สัตว์, สิ่งของ
• การวาดภาพสามารถท าภาพเคลื่อนไหวได้– แต่ละภาพวัตถุอยู่ต าแหน่งที่ต่างกัน
– Stop motion
– การสร้างภาพเคลื่อนไหวของกล้องวิดีโอ
Animation
http://9gag.com/gag/a44LqEd/car-race-stop-motion
Animation• ภาพเคลื่อนไหวคอมพิวเตอร์ใช้รูปแบบเดียวกับกล้องวิดีโอ
• เกิดเมื่อมีบางสิ่งเปลี่ยนพิกัด– เคลื่อนที่
– หมุน
– เปลี่ยนขนาด
– เปลี่ยนสี
– ...
Computer’s Animation• 1 รูปของภาพเคลื่อนไหว = 1 frame
• คอมพิวเตอร์วาดและลบรูปออกจากหน้าจอ– เหตุการณ์นี้เกิดขึ้นเร็วมาก
– หากช้าจอจะกระพริบหรือกระตุก
• Frame per second (FPS)– จ านวนรูปภาพที่วาดภายใน 1 วินาที
– มาตรวัดความลื่นของเกมและภาพยนตร์
– 30 ~ 60 FPS
Computer’s Animation
Animation in Java 2D• ใน Java สามารถสร้างภาพเคลื่อนไหวด้วยวิธีเดียวกัน
• เมื่อพิกัดเปลี่ยนแปลง ลบแล้ววาดรูปใหม่– เรียก method repaint()
• รูปที่เป็นภาพเคลื่อนไหวต้องอ้างถึงได้– เปลี่ยนแปลงพิกัดได้
– ปรับเปลี่ยนรูปทรงได้
– แปลงได้
Animation in Java 2D
Graphics2D g2d = (Graphics2D) g;
g2d.fillRect(0, 0, 100, 100);
g2d.fillRect(x, y, 100, 100);
g2d.fillRect(0, 0, width, height);
g2d.fillRect(x, y, width, height);
อ้างถึงไม่ได้
เปลี่ยนต าแหน่งได้เท่าน้ัน
เปลี่ยนขนาดได้เท่านั้นอ้างถึงได้ทั้งหมด
Animation in Java 2D• การลบและวาดภาพใหม่เป็นสิ่งที่ต้องท าตลอดเวลา
• คอมพิวเตอร์ท างานได้เพียง 1 อย่างเท่านั้น– โปรแกรมต้องท างาน รูปก็ต้องวาด
– เป็นไปไม่ได้ ?
• Multithreading– สร้าง thread ส าหรับจัดการการวาดโดยเฉพาะ
Timer API• Package javax.swing.Timer• คลาสส าหรับจัดการสิ่งที่ต้องท าเป็นช่วงก าหนดเวลา
– ทุก ๆ 1 วินาที
• สามารถใช้ Timer ในการสั่งลบและวาดได้– สิ่งที่ต้องท า: ลบแล้ววาดใหม่– อาจต้องอัพเดตค่าบางอย่าง
• สิ่งที่จะท า เขียนในคลาสที่ implements ActionListener– Anonymous class, Inner class, class ปกติ– ตามความเหมาะสมของสิ่งที่จะท า
Timer API
final int ONE_SECOND = 1000;Timer t = new Timer(ONE_SECOND, new ActionListener() {
@Overridepublic void actionPerformed(ActionEvent e) {
// TODO: Implement update algorithm and logic here
// TODO: Repaint}
});
Timer API• Timer object สามารถสั่งเริ่มและหยุดได้
– t.start()
– t.stop()
– ไม่ต้องกังวลเรื่องการ interrupt ของ thread
• พยายามสั่งหยุด Timer เมื่อจบโปรแกรมทุกครั้ง– บางครั้ง process ไม่หยุดการท างาน
Timer API
final int ONE_SECOND = 1000;Timer t = new Timer(ONE_SECOND, new ActionListener() {
@Overridepublic void actionPerformed(ActionEvent e) {
System.out.println(new java.util.Date());}
});
t.start();
Translation• การเปลี่ยนแปลงรูปร่างเพ่ือสร้างภาพเคลื่อนไหว
– หาสมการที่สามารถบอกต าแหน่งได้โดยใช้หมายเลข frame
– ก าหนดระยะการเปลี่ยนแปลงต่อ frame
• ขึ้นกับความง่ายและเหมาะสม– หมายเลข frame overflow ได้
– การเคลื่อนที่บางประเภทมองระยะการเปลี่ยนแปลงยาก
Translation• การเลื่อนขนานแบบเส้นตรง
– การเดินทางเป็นแนวเส้นตรง
– สมการเชิงเส้นตัวแปรเดียว
𝑥𝑡 = 𝑠𝑥𝑡 + 𝑥0𝑦𝑡 = 𝑠𝑦𝑡 + 𝑦0
𝑑𝑥𝑡𝑑𝑡
= 𝑑𝑥 = 𝑠𝑥𝑑𝑦𝑡𝑑𝑡
= 𝑑𝑦 = 𝑠𝑦
Translation
𝑥𝑡 = 2𝑡𝑦𝑡 = 𝑡
𝑥0 = 0𝑑𝑥 = 2
𝑦0 = 0𝑑𝑦 = 1
Rectangle2D.Double rect = new Rectangle2D.Double(0, 0, 2, 2);// Initial Initial Initialpublic void actionPerformed(ActionEvent e) {
rect.x += 2;rect.y += 1;
screenPanel.repaint();t++;
}
𝑑𝑥𝑑𝑦
Translation• การเลื่อนขนานแบบวงกลม, วงรี
– สามารถใช้เรื่องวงกลม 1 หน่วยในการแก้ปัญหา
𝑥𝑡2 + 𝑦𝑡
2 = 𝑟
𝑥𝑡 = 𝑟𝑥 cos 𝑠𝑡 + 𝜃 + 𝑥0𝑦𝑡 = 𝑟𝑦sin 𝑠𝑡 + 𝜃 + 𝑦0
𝑑𝑥 = −𝑟𝑥𝑠 sin 𝑠𝑡 + 𝜃𝑑𝑦 = 𝑟𝑦𝑠cos 𝑠𝑡 + 𝜃
Translation𝑥𝑡 = 100 cos 𝑡 + 45° + 100𝑦𝑡 = 100sin 𝑡 + 45° + 100
𝑑𝑥 = −100 sin 𝑡 + 45°𝑑𝑦 = 100cos 𝑡 + 45°
𝑥0 = 100𝑦0 = 100
Collision
http://www.doubledogmusic.com/images/2008/collision.jpg
Collision• การชนของวัตถุสองมิติเกิดขึ้นเมื่อวัตถุซ้อนกัน
• การชนกันขึ้นกับความเป็นจริงของวัตถุ– ขึ้นกับ policy ว่าเป็นอย่างไร
– อะไรทะลุได้ ทะลุไม่ได้
• บางครั้งเมื่อวัตถุชนกันท าให้ความเร็วเปลี่ยนไป– 𝑑𝑥, 𝑑𝑦 ต้องเปลี่ยนแปลงค่าได้
Collision• การตรวจสอบการชนมีได้สองวิธี
– ตรวจสอบพิกัดสองรูปว่าซ้อนทับหรือไม่
– ใช้สมบัติ intersect ของ Area object
• ขึ้นกับลักษณะ– ชนเฉพาะด้านหรือชนได้รอบทิศ
– รูปซับซ้อนหรือไม่
• FPS มาก ยิ่งท าให้การตรวจสอบเหมือนจริงย่ิงขึ้น
Collisionif (rect.getMinX() < 0) {
dx = speed;} else if (rect.getMaxX() > screenPanel.getWidth()) {
dx = -speed;}
if (rect.getMinY() < 0) {dy = speed;
} else if (rect.getMaxY() > screenPanel.getHeight()) {dy = -speed;
}
rect.x += dx;rect.y += dy;
screenPanel.repaint();