จะไปเกี่ยวกับองค์ประกอบ GUI ได้อย่างไร


12

หมายเหตุ: ฉันวางแผนที่จะสร้างระบบ GUI ของตัวเอง มันจะเป็นการดีสำหรับการเรียนรู้น้ำหนักเบามีเพียงบิตที่ฉันต้องการผูกติดกับเกมเป็นต้น

ฉันกำลังคิดเกี่ยวกับวิธีการทำ องค์ประกอบที่ฉันหมายถึงคือ:

  • ปุ่มตัวเลือก
  • ป้อนข้อความที่นี่กล่อง
  • ปุ่ม
  • sliders
  • ช่องทำเครื่องหมาย

ฉันไม่ได้มองว่าจะทำอย่างไร แต่พวกเขาจะไปได้อย่างไร

ความคิด

ฉันจะมีแต่ละรัฐที่ต้องการสิ่งต่าง ๆ ดังนั้นเกือบทั้งหมดมีคอนเทนเนอร์ขององค์ประกอบ องค์ประกอบแต่ละชิ้นเป็น GUI

แต่ละคนมีตำแหน่งกราฟิก ฯลฯ

บิตที่ฉันติดมากขึ้นคือตรรกะของพวกเขา

ความคิดของฉันสำหรับสิ่งนั้นเพื่อให้เป็นโมดุลและความเรียบง่ายคือการหลีกเลี่ยง MainMenuStartButton a OptionsOneBackButton เป็นต้นและสามารถใช้ Slider slider1 แทน หรือปุ่มเริ่ม;

แต่แต่ละรายการจะมีฟังก์ชั่น boost :: ไปยังฟังก์ชันในเนมสเปซ GUI เช่น Gui :: StartButtonClick หรือ GUI :: ColourSliderHover

ฉันแค่สงสัยว่ามันจะช้าเป็นพิเศษหรือไม่

และสำหรับเรื่องนั้นมีผู้ใดบ้าง ง่ายและเรียบง่ายในการทำ GUI สำหรับเกมหรือไม่? ไม่มี Qt, wxWidgets หรืออะไร

คำตอบ:


15

GUI ไม่ใช่ปัญหาง่าย ๆ โดยเฉพาะเมื่อคุณเข้าเกมและต้องการมีเมนูที่น่าสนใจ

สิ่งหนึ่งที่ "ง่าย" ที่คุณสามารถทำได้คือพยายามใช้มิดเดิลแวร์ มีคำถามที่นี่นี่

หากคุณกำลังจะม้วนมันด้วยตัวเองมีบางสิ่งที่ฉันอยากจะแนะนำ

  • องค์ประกอบ GUI โดยทั่วไปจะมี "ผู้ปกครอง" ไม่ว่าจะเป็นองค์ประกอบ GUI หรือ "หน้าต่าง" อื่น ๆ หรืออะไรทำนองนั้น การชี้ขึ้นหรือให้ผู้ปกครองชี้ลงหมายความว่าคุณสามารถกำหนดสถานะ / ตำแหน่ง / ฯลฯ ในทุกสิ่งที่เป็นลูกได้

  • คุณสามารถสร้างองค์ประกอบ GUI ตามองค์ประกอบ วิดเจ็ตจำนวนมากมีเลเบล (ค่อนข้างมากทั้งหมด) และอาจเหมาะสมที่จะทำแนวคิดของเลเบลคอมโพเนนต์หรือลูกขององค์ประกอบ UI อื่น ๆ ของคุณแทนที่จะคัดลอก / วางรหัสหรือพยายามสืบทอดจากคลาสพื้นฐาน ด้วยฟังก์ชั่นฉลาก

  • วิดเจ็ตพิเศษที่เรียกว่าจำนวนมากเป็นเพียงปุ่มปลอม ช่องทำเครื่องหมายเป็นเพียงปุ่มที่มีรัฐและภาพพิเศษ ปุ่มตัวเลือกเป็นเพียงช่องทำเครื่องหมายที่มี meta-state (ปุ่มเดียวมีการใช้งานเพียงปุ่มเดียวในเวลาที่กำหนด) พร้อมปุ่มตัวเลือกอื่น ๆ ใช้สิ่งนี้เพื่อประโยชน์ของคุณ ในเกมหนึ่งที่ฉันทำงาน "ช่องทำเครื่องหมาย" ถูกสร้างขึ้นด้วยปุ่มปกติทั้งหมดผ่านสคริปต์และงานศิลปะ

  • สำหรับโครงการแรกของคุณให้พิจารณาใช้เส้นทางที่ตรงมากขึ้น ใช่ทำให้ผู้รับมอบอำนาจเหตุการณ์ที่สามารถดำเนินการได้ของคุณและกำหนดสิ่งที่คุณต้องการในการสร้างองค์ประกอบ (เช่น onMouseButtonDown, onMouseButtonUp, onHover ฯลฯ ) แต่พิจารณาการเข้ารหัสอย่างหนักสิ่งที่คุณต้องการที่จะเกิดขึ้นมิฉะนั้น (เช่นเลื่อนการเปลี่ยนสีปุ่มกดเสียง) การทำงาน. เมื่อถึงจุดนั้นให้ลองสร้างข้อมูลพฤติกรรมนั้น (เช่นมีปุ่มบนตัวแปรสำหรับ "กดเสียง" หรืออาจพิจารณาว่ามีองค์ประกอบที่องค์ประกอบ UI ของคุณใช้เพื่อกำหนดพฤติกรรมที่คุณเพิ่งแนบไปกับพวกเขาเมื่อคุณสร้างพวกเขา

  • ผู้ได้รับมอบหมายไม่ได้ช้าคุณอาจไม่มีวิดเจ็ตจำนวนมากที่เป็นปัญหาและรหัสเมนูโดยทั่วไปจะไม่ส่งผลกระทบสูงนัก ฉันไม่ต้องกังวลเกี่ยวกับประสิทธิภาพการทำงานมากเกินไป ณ จุดนี้ในเกม อย่าเลือกอัลกอริธึมและโปรไฟล์ที่ไร้เดียงสาเมื่อคุณได้รับรหัสและใช้งาน


2
สำหรับสิ่งที่ซับซ้อนของ GUI คุณจะต้องมีการจัดการเลย์เอาต์ในไม่ช้า เลย์เอาต์พื้นฐานเช่น HBox และ VBox นั้นใช้งานง่ายกว่าการวางตำแหน่งองค์ประกอบทั้งหมดด้วยพิกัดที่สมบูรณ์ ตัวอย่าง: web.archive.org/web/20100410150433/http://doc.qt.nokia.com/4.6/…นั่นทำให้ GUI ของคุณใช้งานได้ง่ายขึ้น แต่ไม่ใช่เรื่องง่ายที่จะติดตั้ง;)
bummzack

8

มีความก้าวหน้าที่น่าสนใจในชุดเครื่องมือ UI หลัก ๆ ในช่วงไม่กี่ปีที่ผ่านมา เกม UIs ก็ได้รับการพัฒนาเช่นกัน แต่ก็ค่อนข้างช้าลง สิ่งนี้อาจเป็นเพราะการพัฒนาระบบย่อย UI ที่มีคุณสมบัติครบถ้วนนั้นมีความสำคัญในตัวเองและเป็นการยากที่จะพิสูจน์การลงทุนด้านทรัพยากร

ระบบ UI ที่ฉันโปรดปรานส่วนตัวคือ Windows Presentation Foundation (WPF) มันใช้ศักยภาพในการสร้างความแตกต่างของ UI ไปอีกระดับ นี่คือคุณสมบัติที่น่าสนใจ:

  1. การควบคุมคือ "ดูน้อย" โดยค่าเริ่มต้น ตรรกะและลักษณะที่ปรากฏของตัวควบคุมโดยทั่วไปจะแยกออก ทุกการควบคุมมาพร้อมกับสไตล์เริ่มต้นและเทมเพลตซึ่งอธิบายลักษณะที่ปรากฏที่เป็นค่าเริ่มต้น ตัวอย่างเช่นปุ่มอาจแสดงเป็นรูปสี่เหลี่ยมผืนผ้าโค้งมนที่มีเส้นขีดด้านนอกสีทึบหรือพื้นหลังไล่ระดับสีและผู้นำเสนอเนื้อหา (เพื่อนำเสนอคำบรรยาย) นักพัฒนา (หรือนักออกแบบ) สามารถสร้างเทมเพลตสไตล์ที่กำหนดเองซึ่งเปลี่ยนลักษณะที่ปรากฏและ (ในขอบเขต) ลักษณะการทำงานของตัวควบคุม ลักษณะสามารถใช้เพื่อแทนที่คุณสมบัติอย่างง่ายของตัวควบคุมเช่นสีพื้นหน้า / สีพื้นหลังแม่แบบ ฯลฯ แม่แบบเปลี่ยนโครงสร้างภาพที่แท้จริง

  2. สไตล์และเทมเพลตอาจรวมถึง "ทริกเกอร์" ทริกเกอร์สามารถฟังเหตุการณ์บางอย่างหรือค่าคุณสมบัติ (หรือการรวมกันของค่า) และแก้ไขลักษณะของสไตล์หรือเทมเพลต ตัวอย่างเช่นเทมเพลตปุ่มโดยทั่วไปจะมีทริกเกอร์ในคุณสมบัติ "IsMouseOver" เพื่อวัตถุประสงค์ในการเปลี่ยนสีพื้นหลังเมื่อเมาส์อยู่เหนือปุ่ม

  3. มี "ระดับ" ขององค์ประกอบ UI ที่แตกต่างกันเล็กน้อยตั้งแต่องค์ประกอบที่มีน้ำหนักเบาพร้อมฟังก์ชันการทำงานที่น้อยที่สุดไปจนถึงการควบคุมน้ำหนักอย่างหนัก สิ่งนี้จะช่วยให้คุณมีความยืดหยุ่นในการจัดโครงสร้าง UI ของคุณ คลาสองค์ประกอบ UI ที่ง่ายที่สุดUIElementไม่มีสไตล์หรือเทมเพลตและรองรับการป้อนข้อมูลเหตุการณ์ที่ง่ายที่สุดเท่านั้น สำหรับองค์ประกอบอย่างง่ายเช่นตัวบ่งชี้สถานะการทำงานนี้อาจเป็นสิ่งที่คุณต้องการ หากคุณต้องการการสนับสนุนอินพุทที่ครอบคลุมมากขึ้นคุณสามารถได้รับFrameworkElement(ซึ่งขยายUIElement) โดยทั่วไปแล้ววิดเจ็ตแบบดั้งเดิมนั้นมาจากการControlขยายFrameworkElementและเพิ่มสไตล์ที่กำหนดเองและการสนับสนุนแม่แบบ (เหนือสิ่งอื่นใด)

  4. WPF ใช้โมเดลกราฟิกแบบเวกเตอร์ที่มีความละเอียดและไม่ขึ้นกับความละเอียด บน Windows แอ็พพลิเคชัน WPF ถูกเรนเดอร์และสร้างโดยใช้ Direct3D

  5. การแนะนำ WPF รวมถึงการเขียนโปรแกรมภาษาใหม่ที่เรียกว่า Xaml Xaml ใช้ Xml เป็นภาษาที่ต้องการสำหรับการประกาศ UI "ฉาก" จริง ๆ แล้วมันค่อนข้างเนียนและแม้ว่ามันอาจจะดูคล้ายกันในตอนแรก แต่มันก็แตกต่างจากภาษาที่มีอยู่อย่าง XUL (และมีพลังมากกว่า)

  6. WPF มีระบบย่อยข้อความขั้นสูงมาก รองรับส่วนใหญ่หากไม่ใช่คุณลักษณะแบบอักษร OpenType ทั้งหมดการลดรอยหยัก ClearType สองทิศทางการวางตำแหน่งพิกเซลย่อย ฯลฯ

"โอเคเยี่ยมเลยตอนนี้เกี่ยวข้องกับการพัฒนาเกมอย่างไร"

ย้อนกลับไปเมื่อ WPF ยังอยู่ในการพัฒนา (และรู้จักกันในนาม "Avalon") ฉันกำลังเรียนหลักสูตรการออกแบบวิดีโอเกมที่ Georgia Tech โปรเจ็กต์สุดท้ายของฉันคือเกมวางแผนการเลี้ยวและฉันต้องการ UI ที่มีความสามารถมาก WPF / Avalon ดูเหมือนเป็นเส้นทางที่ดีที่จะไปเพราะมันมีชุดควบคุมเต็มรูปแบบที่สมบูรณ์และมันทำให้ฉันมีความสามารถในการเปลี่ยนรูปลักษณ์และความรู้สึกของการควบคุมเหล่านั้นได้อย่างสมบูรณ์ ผลที่ได้คือเกมที่มี UI ที่สวยงามและคมชัดพร้อมระดับการทำงานที่ปกติคุณจะเห็นในแอปพลิเคชันเต็มรูปแบบเท่านั้น

ตอนนี้ปัญหาเกี่ยวกับการใช้ WPF สำหรับเกมคือมีน้ำหนักค่อนข้างมากและแสดงผลใน "แซนด์บ็อกซ์" ของตัวเอง โดยที่ฉันหมายความว่าไม่มีวิธีการสนับสนุนการโฮสต์ WPF ภายในสภาพแวดล้อม Direct3D หรือ OpenGL เกม เป็นไปได้ที่จะโฮสต์เนื้อหา Direct3D ภายในแอปพลิเคชัน WPF แต่คุณจะถูก จำกัด โดยอัตราเฟรมของแอปพลิเคชัน WPF ซึ่งโดยทั่วไปจะต่ำกว่าที่คุณต้องการ สำหรับเกมบางประเภทเช่นเกมกลยุทธ์ 2D (ภาพหน้าจอของโครงการเกม WPF ปัจจุบันของฉัน) มันก็ยังใช้งานได้ดี สำหรับสิ่งอื่นไม่มาก แต่คุณยังคงสามารถใช้แนวคิดสถาปัตยกรรมที่น่าสนใจกว่าของ WPF ในการพัฒนาเฟรมเวิร์ก UI ของคุณเอง

นอกจากนี้ยังมีการใช้งาน C ++ / Direct3D ของโอเพ่นซอร์สที่ไม่มีการจัดการของ WPF เรียกว่า "WPF / G (WPF สำหรับเกม)"] ( http://wpfg.codeplex.com/ ) ซึ่งได้รับการออกแบบมาโดยเฉพาะสำหรับใช้ในเกมบน Win32 ทั้งสอง และ Windows Mobile การพัฒนาที่แอคทีฟดูเหมือนจะหยุดลง แต่ครั้งสุดท้ายที่ฉันตรวจสอบมันเป็นการใช้งานที่ค่อนข้างสมบูรณ์ ระบบย่อยข้อความเป็นหนึ่งในพื้นที่ที่ขาดจริง ๆ เมื่อเปรียบเทียบกับการใช้ WPF ของ Microsoft แต่นั่นเป็นปัญหาสำหรับเกมน้อยกว่า ฉันคิดว่าการรวม WPF / G เข้ากับเอ็นจิ้นเกมที่ใช้ Direct3D จะค่อนข้างตรงไปตรงมา การไปตามเส้นทางนี้จะช่วยให้คุณมีกรอบงาน UI ที่มีความสามารถอย่างอิสระและมีความละเอียดสูงพร้อมการสนับสนุนอย่างกว้างขวางสำหรับการปรับแต่ง UI

เพียงเพื่อให้คุณทราบว่า UI เกมที่ใช้ WPF เป็นอย่างไรต่อไปนี้เป็นภาพหน้าจอจากโครงการสัตว์เลี้ยงของฉัน:

ภาพหน้าจอจากโครงการเกมที่ใช้ WPF ของฉัน


NoesisGUI ใช้ WPF มันค่อนข้างดี แต่ฉันไม่รู้ WPF และฉันพบว่ามันเจ็บปวดในการเรียนรู้ ฉันต้องการใช้เว็บสแต็กเป็นการส่วนตัว
user441521

2

ฉันจะไปหา GUI ทันทีเช่นนี้: http://code.google.com/p/nvidia-widgets/

วิดเจ็ต nVidia ใช้ IMGUI (Immediate GUI) จาก MollyRocket

ฉันคิดว่านั่นเป็นเรื่องง่ายเหมือน GUI ที่จะได้รับ

ทั้งหมดขึ้นอยู่กับความต้องการของคุณ


1
ง่ายใช่และเหมาะสำหรับการแก้ไขข้อบกพร่องอย่างรวดเร็วในการทำงานหรือการสร้างต้นแบบ แต่จำนวนการเชื่อมต่อระหว่าง UI และตรรกะเกมของคุณใน GUI แบบทันทีทำให้ฉันกลัว
tenpn

2

ในเกมที่ฉันกำลังทำเรามีกรอบ GUI ที่กำหนดเองของเราเอง ฉันพบว่ามันง่ายมาก แต่ก็ยังทำทุกสิ่งที่ฉันอยากทำ ฉันไม่รู้ว่ามันเป็น "รูปแบบ" ที่คนอื่นใช้กันหรือเปล่า แต่มันใช้ได้ดีสำหรับเรา

โดยพื้นฐานแล้วปุ่มทั้งหมดช่องทำเครื่องหมาย ฯลฯ เป็นคลาสย่อยขององค์ประกอบคลาส และองค์ประกอบมีกิจกรรม จากนั้นเรามี CompoundElements (ซึ่งเป็นคลาสย่อยของ Element) ซึ่งมีองค์ประกอบอื่น ๆ ในแต่ละรอบจะมีสามวิธีที่เรียกว่า: processEvent (เหตุการณ์), ขีด (เวลา) และวาด (พื้นผิว) แต่ละ CompoundElement แล้วเรียกวิธีการเหล่านั้นในองค์ประกอบของเด็ก ในการเรียกเหล่านั้น (โดยเฉพาะอย่างยิ่งวิธีการ processEvent) เราจะปิดเหตุการณ์ที่เกี่ยวข้อง

ทั้งหมดนี้อยู่ใน Python (ภาษาที่ช้ากว่า C ++) และมันก็ทำงานได้อย่างสมบูรณ์แบบ


2

หากคุณต้องการ UIs ที่ค่อนข้างซับซ้อนตัวเลือกที่ดีที่สุดน่าจะเป็นเพียงแค่ฝัง HTML renderer - คุณจะได้รับพื้นฐาน UI ทั่วไปทั้งหมดที่คุณคุ้นเคยและคุณสามารถเพิ่ม UI ที่ซับซ้อนให้กับเกมของคุณ ผู้ใช้คาดหวังให้ดูดีและทำงานเร็ว (เนื่องจากเบราว์เซอร์มีท่อส่งเรนเดอร์ที่ได้รับการปรับปรุงให้ดีที่สุดในตอนนี้)

มีห้องสมุดไม่กี่แห่งที่มีการฝัง Webkit ในเกม: Berkelium เป็นสิ่งที่ฉันแนะนำและฉันได้ยินว่า Awesomium ค่อนข้างดี (ใช้โดย EVE Online) และ CEF (ใช้โดย Steam) นอกจากนี้คุณยังสามารถลองฝัง Gecko ได้ - มันทำยากกว่ามาก แต่ก็มีข้อดีที่ยอดเยี่ยมเช่นกัน ขณะนี้ฉันกำลังใช้ Berkelium สำหรับ UI เกมทั้งหมดของฉัน (แทนที่การรวมกันขององค์ประกอบ UI ที่กำหนดเองและ UI ดั้งเดิมและลดจำนวนรหัสที่ฉันต้องเขียนเพื่อให้ทำงานได้อย่างน่าทึ่ง)


^ นี่ 100% ฉันเสียใจที่ไม่มีเว็บสแต็กที่ดีสำหรับการติดตั้งเกมที่นั่น เว็บสแต็คนั้นยอดเยี่ยมสำหรับ UI และต้องเริ่มพบเห็นได้ทั่วไปในทุกเกมสำหรับ UI ของพวกเขา จนถึงตอนนี้ห้องสมุดที่ฉันพยายามทำงานด้วยนั้นมีความเจ็บปวดในการใช้หรือไม่จริง 100% html / css / javascript ตอนนี้ฉันกำลังดู Coherent Labs อยู่และมันก็ดูดี แต่มันมีราคาพอใช้ แต่มีอินดิเคชั่นสำหรับเครื่องยนต์คู่
user441521

2

ตรวจสอบให้แน่ใจว่าคุณต้องการระบบ GUI ที่ซับซ้อนสำหรับเกมของคุณ หากคุณกำลังสร้างเกมคอมพิวเตอร์ RPG ขึ้นมาแน่นอนว่ามันเป็นข้อกำหนด แต่สำหรับเกมแข่งรถอย่าทำอะไรที่ซับซ้อนเกินไป บางครั้งเพียงแค่แสดงพื้นผิว (ภาพปุ่มที่กำหนดเอง) และมีคำสั่ง "ถ้า" พร้อมพิกัดฮาร์ดโค้ดในฟังก์ชั่นอินพุตของคุณสามารถทำงานให้เสร็จได้ เครื่องสถานะเกม (FSM) ช่วยด้วยวิธีการง่าย ๆ นี้ หรือบางแห่งที่อยู่ตรงกลางลืมลำดับชั้นที่ซับซ้อนและกราฟฉากและเพียงแค่มีคลาส "ปุ่ม" ซึ่งแพ็คเกจพื้นผิวดังกล่าวข้างต้นและการตรวจสอบการป้อนข้อมูลในการเรียกฟังก์ชั่นที่เรียบง่าย แต่ไม่ได้ทำอะไรซับซ้อน

การตอกย้ำความต้องการของคุณเป็นสิ่งสำคัญ หากคุณไม่แน่ใจเพียงแค่เตือนตัวเองYAGNI


1

นี่คือตัวอย่างหนึ่ง (ซอร์สโค้ดและทั้งหมด) ของ GUI ที่สร้างขึ้นสำหรับ OpenGL โดยเฉพาะสำหรับSlick2Dชื่อThingleซึ่งเป็นพอร์ตของThinlet Thinlet

GUI อื่นสำหรับ Slick2D คือSUIที่คุณอาจต้องการดู

ฉันจะทำตามตัวอย่างเหล่านี้และไปกับ GUI ที่ใช้ XML แม้ว่าโครงการเหล่านี้จะเก่า / ตายคุณอาจสามารถรับแนวคิดบางอย่างจากพวกเขา


1

ฉันคิดว่าหนึ่งในวิธีที่ดีที่สุดในการ "คิดออก" คือดูว่ากรอบงาน GUI ที่พัฒนาขึ้นอย่างสูงเช่น Windows Forms ใน. NET

ตัวอย่างเช่นพวกเขาคือการควบคุมทั้งหมดซึ่งมีที่ตั้งขนาดรายการของการควบคุมเด็กอ้างอิงถึงผู้ปกครองของตน Textคุณสมบัติสำหรับสิ่งที่ตัวควบคุมอาจใช้สำหรับเช่นเดียวกับฟังก์ชั่น overridable ต่างๆและการกระทำที่กำหนดไว้ล่วงหน้า

พวกเขาทั้งหมดมีเหตุการณ์ต่างๆเช่นClick, MouseOverและResizingและ

ตัวอย่างเช่นเมื่อมีการเปลี่ยนแปลงการควบคุมลูกมันจะส่งการแจ้งเตือนขึ้นห่วงโซ่ที่มีการเปลี่ยนแปลงรูปแบบและผู้ปกครองทั้งหมดแล้วโทร PerformLayout()ตัวอย่างเช่นเมื่อมีการควบคุมเด็กมีการเปลี่ยนแปลงก็จะส่งการแจ้งเตือนขึ้นห่วงโซ่ที่รูปแบบที่มีการเปลี่ยนแปลงและผู้ปกครองทุกคนแล้วโทร

นอกจากนี้การปรับขนาดอัตโนมัติและการจัดเรียงอัตโนมัติยังเป็นคุณสมบัติทั่วไปของ GUI เหล่านี้ช่วยให้โปรแกรมเมอร์สามารถเพิ่มการควบคุมและตัวควบคุมหลักจะปรับหรือจัดเรียงโดยอัตโนมัติ


1

เพื่อเห็นแก่ผลประโยชน์ที่ฉันคิดว่าฉันจะโยนออกScaleform โดยพื้นฐานแล้วศิลปินสามารถใช้ Illustrator, Photoshop และอื่น ๆ จากนั้นผู้ออกแบบ UI จะใช้ Flash เพื่อจัดวางการโต้ตอบทั้งหมด จากนั้น Scaleform จะแปลงให้เป็นรหัสสำหรับเครื่องยนต์ของคุณ (นั่นคือความเข้าใจของฉันเพราะฉันไม่ได้ใช้) Crysis Warhead ใช้ระบบนี้ในล็อบบี้

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.