diff --git a/Contribution.md b/Contribution.md index 9932bc4a..0e0787f6 100644 --- a/Contribution.md +++ b/Contribution.md @@ -12,13 +12,38 @@ - https://github.com/qianc62 - A simple website - + https://github.com/THUNLP + Tsinghua Bamboo Website + Perfect - GPT3.5 + + + + A Tetris Game + + Perfect + + A Plant vs Zombie Game + + Perfect + + + + A Race Car Game + + Perfect + + + + A Snake Game + + Perfect + + + + https://github.com/qianc62 FlappyBirds Game Perfect diff --git a/WareHouse/TsinghuaBambooWebsite_THUNLPDemo_2024/cultural-examination.html b/WareHouse/TsinghuaBambooWebsite_THUNLPDemo_2024/cultural-examination.html new file mode 100644 index 00000000..3e8f7aa0 --- /dev/null +++ b/WareHouse/TsinghuaBambooWebsite_THUNLPDemo_2024/cultural-examination.html @@ -0,0 +1,486 @@ + + + + + + ChatDev数字博物馆 + + + + + + + + + +
+
+
+
+ +
+ +
+ +
+
+

文物考察

+ +
+
+
+
+ 复原竹简拼图 +
复原竹简拼图
+
+
+
+
+ 集体会读史料 +
集体会读史料
+
+
+
+
+ 解读竹简文脉 +
解读竹简文脉
+
+
+
+
+ 古文字研究 +
古文字研究
+
+
+
+
+ 出土文献整理 +
出土文献整理
+
+
+
+
+ 清华简史料研讨 +
清华简史料研讨
+
+
+
+
+ 复原竹简拼图 +
复原竹简拼图
+
+
+
+
+ 集体会读史料 +
集体会读史料
+
+
+
+
+ 解读竹简文脉 +
解读竹简文脉
+
+
+
+
+ 古文字研究 +
古文字研究
+
+
+
+
+ 出土文献整理 +
出土文献整理
+
+
+
+
+ 清华简史料研讨 +
清华简史料研讨
+
+
+
+
+ +
+
+
+
+ 竹简修复技术 +
竹简修复技术
+
+
+
+
+ 挖掘算表奥秘 +
挖掘算表奥秘
+
+
+
+
+ 当代文物传承 +
当代文物传承
+
+
+
+
+ 文物成果发布 +
文物成果发布
+
+
+
+
+ 文物历史探秘 +
文物历史探秘
+
+
+
+
+ 数字化保护 +
数字化保护
+
+
+
+
+ 竹简修复技术 +
竹简修复技术
+
+
+
+
+ 挖掘算表奥秘 +
挖掘算表奥秘
+
+
+
+
+ 当代文物传承 +
当代文物传承
+
+
+
+
+ 文物成果发布 +
文物成果发布
+
+
+
+
+ 文物历史探秘 +
文物历史探秘
+
+
+
+
+ 数字化保护 +
数字化保护
+
+
+
+
+
+
+ + +
+
+
+ + + + + + + + + + diff --git a/WareHouse/TsinghuaBambooWebsite_THUNLPDemo_2024/images/examination/1.png b/WareHouse/TsinghuaBambooWebsite_THUNLPDemo_2024/images/examination/1.png new file mode 100644 index 00000000..c142a650 Binary files /dev/null and b/WareHouse/TsinghuaBambooWebsite_THUNLPDemo_2024/images/examination/1.png differ diff --git a/WareHouse/TsinghuaBambooWebsite_THUNLPDemo_2024/images/examination/10.png b/WareHouse/TsinghuaBambooWebsite_THUNLPDemo_2024/images/examination/10.png new file mode 100644 index 00000000..bf2c7b70 Binary files /dev/null and b/WareHouse/TsinghuaBambooWebsite_THUNLPDemo_2024/images/examination/10.png differ diff --git a/WareHouse/TsinghuaBambooWebsite_THUNLPDemo_2024/images/examination/11.png b/WareHouse/TsinghuaBambooWebsite_THUNLPDemo_2024/images/examination/11.png new file mode 100644 index 00000000..15ae41f7 Binary files /dev/null and b/WareHouse/TsinghuaBambooWebsite_THUNLPDemo_2024/images/examination/11.png differ diff --git a/WareHouse/TsinghuaBambooWebsite_THUNLPDemo_2024/images/examination/12.png b/WareHouse/TsinghuaBambooWebsite_THUNLPDemo_2024/images/examination/12.png new file mode 100644 index 00000000..4a865165 Binary files /dev/null and b/WareHouse/TsinghuaBambooWebsite_THUNLPDemo_2024/images/examination/12.png differ diff --git a/WareHouse/TsinghuaBambooWebsite_THUNLPDemo_2024/images/examination/13.png b/WareHouse/TsinghuaBambooWebsite_THUNLPDemo_2024/images/examination/13.png new file mode 100644 index 00000000..e6700602 Binary files /dev/null and b/WareHouse/TsinghuaBambooWebsite_THUNLPDemo_2024/images/examination/13.png differ diff --git a/WareHouse/TsinghuaBambooWebsite_THUNLPDemo_2024/images/examination/14.png b/WareHouse/TsinghuaBambooWebsite_THUNLPDemo_2024/images/examination/14.png new file mode 100644 index 00000000..31ea448a Binary files /dev/null and b/WareHouse/TsinghuaBambooWebsite_THUNLPDemo_2024/images/examination/14.png differ diff --git a/WareHouse/TsinghuaBambooWebsite_THUNLPDemo_2024/images/examination/15.png b/WareHouse/TsinghuaBambooWebsite_THUNLPDemo_2024/images/examination/15.png new file mode 100644 index 00000000..15c7fae4 Binary files /dev/null and b/WareHouse/TsinghuaBambooWebsite_THUNLPDemo_2024/images/examination/15.png differ diff --git a/WareHouse/TsinghuaBambooWebsite_THUNLPDemo_2024/images/examination/2.png b/WareHouse/TsinghuaBambooWebsite_THUNLPDemo_2024/images/examination/2.png new file mode 100644 index 00000000..1bb7560f Binary files /dev/null and b/WareHouse/TsinghuaBambooWebsite_THUNLPDemo_2024/images/examination/2.png differ diff --git a/WareHouse/TsinghuaBambooWebsite_THUNLPDemo_2024/images/examination/3.png b/WareHouse/TsinghuaBambooWebsite_THUNLPDemo_2024/images/examination/3.png new file mode 100644 index 00000000..836e3593 Binary files /dev/null and b/WareHouse/TsinghuaBambooWebsite_THUNLPDemo_2024/images/examination/3.png differ diff --git a/WareHouse/TsinghuaBambooWebsite_THUNLPDemo_2024/images/examination/4.png b/WareHouse/TsinghuaBambooWebsite_THUNLPDemo_2024/images/examination/4.png new file mode 100644 index 00000000..bc44d387 Binary files /dev/null and b/WareHouse/TsinghuaBambooWebsite_THUNLPDemo_2024/images/examination/4.png differ diff --git a/WareHouse/TsinghuaBambooWebsite_THUNLPDemo_2024/images/examination/5.png b/WareHouse/TsinghuaBambooWebsite_THUNLPDemo_2024/images/examination/5.png new file mode 100644 index 00000000..8812aa8e Binary files /dev/null and b/WareHouse/TsinghuaBambooWebsite_THUNLPDemo_2024/images/examination/5.png differ diff --git a/WareHouse/TsinghuaBambooWebsite_THUNLPDemo_2024/images/examination/6.png b/WareHouse/TsinghuaBambooWebsite_THUNLPDemo_2024/images/examination/6.png new file mode 100644 index 00000000..a1126cfd Binary files /dev/null and b/WareHouse/TsinghuaBambooWebsite_THUNLPDemo_2024/images/examination/6.png differ diff --git a/WareHouse/TsinghuaBambooWebsite_THUNLPDemo_2024/images/examination/7.png b/WareHouse/TsinghuaBambooWebsite_THUNLPDemo_2024/images/examination/7.png new file mode 100644 index 00000000..e7fea057 Binary files /dev/null and b/WareHouse/TsinghuaBambooWebsite_THUNLPDemo_2024/images/examination/7.png differ diff --git a/WareHouse/TsinghuaBambooWebsite_THUNLPDemo_2024/images/examination/8.png b/WareHouse/TsinghuaBambooWebsite_THUNLPDemo_2024/images/examination/8.png new file mode 100644 index 00000000..e44a4a70 Binary files /dev/null and b/WareHouse/TsinghuaBambooWebsite_THUNLPDemo_2024/images/examination/8.png differ diff --git a/WareHouse/TsinghuaBambooWebsite_THUNLPDemo_2024/images/examination/9.png b/WareHouse/TsinghuaBambooWebsite_THUNLPDemo_2024/images/examination/9.png new file mode 100644 index 00000000..83a6456c Binary files /dev/null and b/WareHouse/TsinghuaBambooWebsite_THUNLPDemo_2024/images/examination/9.png differ diff --git a/WareHouse/TsinghuaBambooWebsite_THUNLPDemo_2024/images/examination/cut.png b/WareHouse/TsinghuaBambooWebsite_THUNLPDemo_2024/images/examination/cut.png new file mode 100644 index 00000000..5a4ff34e Binary files /dev/null and b/WareHouse/TsinghuaBambooWebsite_THUNLPDemo_2024/images/examination/cut.png differ diff --git a/WareHouse/TsinghuaBambooWebsite_THUNLPDemo_2024/images/exhibitions/exhibition1.png b/WareHouse/TsinghuaBambooWebsite_THUNLPDemo_2024/images/exhibitions/exhibition1.png new file mode 100644 index 00000000..d0097625 Binary files /dev/null and b/WareHouse/TsinghuaBambooWebsite_THUNLPDemo_2024/images/exhibitions/exhibition1.png differ diff --git a/WareHouse/TsinghuaBambooWebsite_THUNLPDemo_2024/images/exhibitions/exhibition2.png b/WareHouse/TsinghuaBambooWebsite_THUNLPDemo_2024/images/exhibitions/exhibition2.png new file mode 100644 index 00000000..b93a50e6 Binary files /dev/null and b/WareHouse/TsinghuaBambooWebsite_THUNLPDemo_2024/images/exhibitions/exhibition2.png differ diff --git a/WareHouse/TsinghuaBambooWebsite_THUNLPDemo_2024/images/exhibitions/exhibition3.png b/WareHouse/TsinghuaBambooWebsite_THUNLPDemo_2024/images/exhibitions/exhibition3.png new file mode 100644 index 00000000..25a0c4a4 Binary files /dev/null and b/WareHouse/TsinghuaBambooWebsite_THUNLPDemo_2024/images/exhibitions/exhibition3.png differ diff --git a/WareHouse/TsinghuaBambooWebsite_THUNLPDemo_2024/images/logo/chatdev-logo.png b/WareHouse/TsinghuaBambooWebsite_THUNLPDemo_2024/images/logo/chatdev-logo.png new file mode 100644 index 00000000..d11ac1d4 Binary files /dev/null and b/WareHouse/TsinghuaBambooWebsite_THUNLPDemo_2024/images/logo/chatdev-logo.png differ diff --git a/WareHouse/TsinghuaBambooWebsite_THUNLPDemo_2024/images/research-achievements/1.png b/WareHouse/TsinghuaBambooWebsite_THUNLPDemo_2024/images/research-achievements/1.png new file mode 100644 index 00000000..48643fa1 Binary files /dev/null and b/WareHouse/TsinghuaBambooWebsite_THUNLPDemo_2024/images/research-achievements/1.png differ diff --git a/WareHouse/TsinghuaBambooWebsite_THUNLPDemo_2024/images/research-achievements/10.png b/WareHouse/TsinghuaBambooWebsite_THUNLPDemo_2024/images/research-achievements/10.png new file mode 100644 index 00000000..05fb8b87 Binary files /dev/null and b/WareHouse/TsinghuaBambooWebsite_THUNLPDemo_2024/images/research-achievements/10.png differ diff --git a/WareHouse/TsinghuaBambooWebsite_THUNLPDemo_2024/images/research-achievements/11.png b/WareHouse/TsinghuaBambooWebsite_THUNLPDemo_2024/images/research-achievements/11.png new file mode 100644 index 00000000..3530f342 Binary files /dev/null and b/WareHouse/TsinghuaBambooWebsite_THUNLPDemo_2024/images/research-achievements/11.png differ diff --git a/WareHouse/TsinghuaBambooWebsite_THUNLPDemo_2024/images/research-achievements/12.png b/WareHouse/TsinghuaBambooWebsite_THUNLPDemo_2024/images/research-achievements/12.png new file mode 100644 index 00000000..bc8ff1a5 Binary files /dev/null and b/WareHouse/TsinghuaBambooWebsite_THUNLPDemo_2024/images/research-achievements/12.png differ diff --git a/WareHouse/TsinghuaBambooWebsite_THUNLPDemo_2024/images/research-achievements/13.png b/WareHouse/TsinghuaBambooWebsite_THUNLPDemo_2024/images/research-achievements/13.png new file mode 100644 index 00000000..4cbba7b9 Binary files /dev/null and b/WareHouse/TsinghuaBambooWebsite_THUNLPDemo_2024/images/research-achievements/13.png differ diff --git a/WareHouse/TsinghuaBambooWebsite_THUNLPDemo_2024/images/research-achievements/14.png b/WareHouse/TsinghuaBambooWebsite_THUNLPDemo_2024/images/research-achievements/14.png new file mode 100644 index 00000000..47815282 Binary files /dev/null and b/WareHouse/TsinghuaBambooWebsite_THUNLPDemo_2024/images/research-achievements/14.png differ diff --git a/WareHouse/TsinghuaBambooWebsite_THUNLPDemo_2024/images/research-achievements/15.png b/WareHouse/TsinghuaBambooWebsite_THUNLPDemo_2024/images/research-achievements/15.png new file mode 100644 index 00000000..25d79bbd Binary files /dev/null and b/WareHouse/TsinghuaBambooWebsite_THUNLPDemo_2024/images/research-achievements/15.png differ diff --git a/WareHouse/TsinghuaBambooWebsite_THUNLPDemo_2024/images/research-achievements/2.png b/WareHouse/TsinghuaBambooWebsite_THUNLPDemo_2024/images/research-achievements/2.png new file mode 100644 index 00000000..2888cb1b Binary files /dev/null and b/WareHouse/TsinghuaBambooWebsite_THUNLPDemo_2024/images/research-achievements/2.png differ diff --git a/WareHouse/TsinghuaBambooWebsite_THUNLPDemo_2024/images/research-achievements/3.png b/WareHouse/TsinghuaBambooWebsite_THUNLPDemo_2024/images/research-achievements/3.png new file mode 100644 index 00000000..d490ab5b Binary files /dev/null and b/WareHouse/TsinghuaBambooWebsite_THUNLPDemo_2024/images/research-achievements/3.png differ diff --git a/WareHouse/TsinghuaBambooWebsite_THUNLPDemo_2024/images/research-achievements/4.png b/WareHouse/TsinghuaBambooWebsite_THUNLPDemo_2024/images/research-achievements/4.png new file mode 100644 index 00000000..4f5eabe4 Binary files /dev/null and b/WareHouse/TsinghuaBambooWebsite_THUNLPDemo_2024/images/research-achievements/4.png differ diff --git a/WareHouse/TsinghuaBambooWebsite_THUNLPDemo_2024/images/research-achievements/5.png b/WareHouse/TsinghuaBambooWebsite_THUNLPDemo_2024/images/research-achievements/5.png new file mode 100644 index 00000000..40e0b9d2 Binary files /dev/null and b/WareHouse/TsinghuaBambooWebsite_THUNLPDemo_2024/images/research-achievements/5.png differ diff --git a/WareHouse/TsinghuaBambooWebsite_THUNLPDemo_2024/images/research-achievements/6.png b/WareHouse/TsinghuaBambooWebsite_THUNLPDemo_2024/images/research-achievements/6.png new file mode 100644 index 00000000..1cdf935d Binary files /dev/null and b/WareHouse/TsinghuaBambooWebsite_THUNLPDemo_2024/images/research-achievements/6.png differ diff --git a/WareHouse/TsinghuaBambooWebsite_THUNLPDemo_2024/images/research-achievements/7.png b/WareHouse/TsinghuaBambooWebsite_THUNLPDemo_2024/images/research-achievements/7.png new file mode 100644 index 00000000..9912b016 Binary files /dev/null and b/WareHouse/TsinghuaBambooWebsite_THUNLPDemo_2024/images/research-achievements/7.png differ diff --git a/WareHouse/TsinghuaBambooWebsite_THUNLPDemo_2024/images/research-achievements/8.png b/WareHouse/TsinghuaBambooWebsite_THUNLPDemo_2024/images/research-achievements/8.png new file mode 100644 index 00000000..a37fb1a1 Binary files /dev/null and b/WareHouse/TsinghuaBambooWebsite_THUNLPDemo_2024/images/research-achievements/8.png differ diff --git a/WareHouse/TsinghuaBambooWebsite_THUNLPDemo_2024/images/research-achievements/9.png b/WareHouse/TsinghuaBambooWebsite_THUNLPDemo_2024/images/research-achievements/9.png new file mode 100644 index 00000000..c29973b0 Binary files /dev/null and b/WareHouse/TsinghuaBambooWebsite_THUNLPDemo_2024/images/research-achievements/9.png differ diff --git a/WareHouse/TsinghuaBambooWebsite_THUNLPDemo_2024/images/slider/slide1.png b/WareHouse/TsinghuaBambooWebsite_THUNLPDemo_2024/images/slider/slide1.png new file mode 100644 index 00000000..d93c8a56 Binary files /dev/null and b/WareHouse/TsinghuaBambooWebsite_THUNLPDemo_2024/images/slider/slide1.png differ diff --git a/WareHouse/TsinghuaBambooWebsite_THUNLPDemo_2024/images/slider/slide2.png b/WareHouse/TsinghuaBambooWebsite_THUNLPDemo_2024/images/slider/slide2.png new file mode 100644 index 00000000..161e285b Binary files /dev/null and b/WareHouse/TsinghuaBambooWebsite_THUNLPDemo_2024/images/slider/slide2.png differ diff --git a/WareHouse/TsinghuaBambooWebsite_THUNLPDemo_2024/images/slider/slide3.jpg b/WareHouse/TsinghuaBambooWebsite_THUNLPDemo_2024/images/slider/slide3.jpg new file mode 100644 index 00000000..16cfcc35 Binary files /dev/null and b/WareHouse/TsinghuaBambooWebsite_THUNLPDemo_2024/images/slider/slide3.jpg differ diff --git a/WareHouse/TsinghuaBambooWebsite_THUNLPDemo_2024/images/warring-states-bamboo-1.png b/WareHouse/TsinghuaBambooWebsite_THUNLPDemo_2024/images/warring-states-bamboo-1.png new file mode 100644 index 00000000..9d553342 Binary files /dev/null and b/WareHouse/TsinghuaBambooWebsite_THUNLPDemo_2024/images/warring-states-bamboo-1.png differ diff --git a/WareHouse/TsinghuaBambooWebsite_THUNLPDemo_2024/images/warring-states-bamboo-sub1.png b/WareHouse/TsinghuaBambooWebsite_THUNLPDemo_2024/images/warring-states-bamboo-sub1.png new file mode 100644 index 00000000..162beddd Binary files /dev/null and b/WareHouse/TsinghuaBambooWebsite_THUNLPDemo_2024/images/warring-states-bamboo-sub1.png differ diff --git a/WareHouse/TsinghuaBambooWebsite_THUNLPDemo_2024/images/warring-states-bamboo-sub2.png b/WareHouse/TsinghuaBambooWebsite_THUNLPDemo_2024/images/warring-states-bamboo-sub2.png new file mode 100644 index 00000000..d164ba8a Binary files /dev/null and b/WareHouse/TsinghuaBambooWebsite_THUNLPDemo_2024/images/warring-states-bamboo-sub2.png differ diff --git a/WareHouse/TsinghuaBambooWebsite_THUNLPDemo_2024/images/warring-states-bamboo-sub3.png b/WareHouse/TsinghuaBambooWebsite_THUNLPDemo_2024/images/warring-states-bamboo-sub3.png new file mode 100644 index 00000000..987f80ad Binary files /dev/null and b/WareHouse/TsinghuaBambooWebsite_THUNLPDemo_2024/images/warring-states-bamboo-sub3.png differ diff --git a/WareHouse/TsinghuaBambooWebsite_THUNLPDemo_2024/index.html b/WareHouse/TsinghuaBambooWebsite_THUNLPDemo_2024/index.html new file mode 100644 index 00000000..53380fec --- /dev/null +++ b/WareHouse/TsinghuaBambooWebsite_THUNLPDemo_2024/index.html @@ -0,0 +1,205 @@ + + + + + + ChatDev数字博物馆 + + + + + + + + + +
+
+
+
+ +
+ +
+ +
+
+
+
+
+
+ 清华简保护 +
+

科技保护

+

运用现代科技保护和研究战国竹简

+
+
+
+
+
+ 清华简展示 +
+

清华简

+

战国中晚期珍贵竹简,展现先秦古籍原貌

+
+
+
+
+
+ 清华简研究 +
+

文化传承

+

了解中华文化的初期面貌和发展脉络

+
+
+
+
+
+
+
+
+
+ +
+
+
+
+

"以科技演绎传统,以创新传承文明"

+
+
+
+
+ +
+
+
+
+ 0 + + +
+
枚竹简
+
+
+
+
+ 0 + + +
+
成果整理
+
+
+
+
+ 0 + + +
+
年历史
+
+
+
+
+ +
+
+

考古时间线

+
+
+
+

归来如初,竹简重现

+

流散海外的战国竹简终归故土,清华大学开启保护与研究之旅,揭开尘封千年的历史画卷。

+
2008年
+
+
+
+
+

初绽华光,文脉重接

+

出土文献中心成立,竹简首批成果问世,遗篇重现,周文王遗训与《系年》诉说千年往事。

+
2009年-2011年
+
+
+
+
+

简中有数,史韵悠长

+

竹简释读渐入佳境,文献涵盖诗乐、史事与算表,点亮先秦文明的璀璨星河。

+
2013年-2020年
+
+
+
+
+

弦歌不辍,古韵新生

+

深掘竹简之秘,释出《五纪》《三不韦》等珍贵篇章,重现礼乐风华,延续文化薪火。

+
2021年-2023年
+
+
+
+
+
+ +
+

研究与保护

+ +
+ +
+ + +
+
+
+ + + + + + + + + \ No newline at end of file diff --git a/WareHouse/TsinghuaBambooWebsite_THUNLPDemo_2024/research-achievements.html b/WareHouse/TsinghuaBambooWebsite_THUNLPDemo_2024/research-achievements.html new file mode 100644 index 00000000..daf2beb0 --- /dev/null +++ b/WareHouse/TsinghuaBambooWebsite_THUNLPDemo_2024/research-achievements.html @@ -0,0 +1,869 @@ + + + + + + ChatDev数字博物馆 + + + + + + + + +
+
+
+
+ +
+ +
+ +
+
+

全辑整理

+ + +
+
+ + +
+
+
+ +
+ +
+ +
+

+
+
+
+
+
+ + + + + + \ No newline at end of file diff --git a/WareHouse/TsinghuaBambooWebsite_THUNLPDemo_2024/script.js b/WareHouse/TsinghuaBambooWebsite_THUNLPDemo_2024/script.js new file mode 100644 index 00000000..11b0ce2a --- /dev/null +++ b/WareHouse/TsinghuaBambooWebsite_THUNLPDemo_2024/script.js @@ -0,0 +1,216 @@ +document.addEventListener('DOMContentLoaded', function() { + AOS.init({ + duration: 1000, + once: true, + offset: 100, + disable: '.parallax-section' // Disable AOS for parallax section + }); + + const swiper = new Swiper('.hero-slider', { + loop: true, + speed: 1000, + autoplay: { + delay: 5000, + disableOnInteraction: false, + }, + pagination: { + el: '.swiper-pagination', + clickable: true, + }, + navigation: { + nextEl: '.swiper-button-next', + prevEl: '.swiper-button-prev', + }, + }); + + const magneticLinks = document.querySelectorAll('.magnetic-link'); + + magneticLinks.forEach(link => { + link.addEventListener('mousemove', function(e) { + const bounds = this.getBoundingClientRect(); + const mouseX = e.clientX - bounds.left; + const mouseY = e.clientY - bounds.top; + const centerX = bounds.width / 2; + const centerY = bounds.height / 2; + const deltaX = mouseX - centerX; + const deltaY = mouseY - centerY; + + gsap.to(this, { + x: deltaX * 0.3, + y: deltaY * 0.3, + duration: 0.3 + }); + }); + + link.addEventListener('mouseleave', function() { + gsap.to(this, { + x: 0, + y: 0, + duration: 0.3 + }); + }); + }); + + gsap.registerPlugin(ScrollTrigger); + + const timelineItems = document.querySelectorAll('.timeline-item'); + timelineItems.forEach((item, index) => { + const tl = gsap.timeline({ + scrollTrigger: { + trigger: item, + start: "top center+=100", + end: "bottom center", + toggleActions: "play none none reverse" + } + }); + + tl.from(item.querySelector('::before'), { + scale: 0, + opacity: 0, + duration: 0.6, + ease: "back.out(1.7)" + }); + + tl.from(item.querySelector('.timeline-content'), { + x: index % 2 === 0 ? 50 : -50, + opacity: 0, + duration: 0.8, + ease: "power2.out" + }, "-=0.3"); + + tl.from(item.querySelector('.timeline-period'), { + y: 20, + opacity: 0, + duration: 0.5, + ease: "power2.out" + }, "-=0.4"); + }); + + VanillaTilt.init(document.querySelectorAll('.digital-card'), { + max: 15, + speed: 400, + glare: true, + 'max-glare': 0.2 + }); + + document.querySelectorAll('a[href^="#"]').forEach(anchor => { + anchor.addEventListener('click', function(e) { + e.preventDefault(); + const target = document.querySelector(this.getAttribute('href')); + if (target) { + window.scrollTo({ + top: target.offsetTop - 70, + behavior: 'smooth' + }); + } + }); + }); + + const patternOverlay = document.querySelector('.pattern-overlay'); + window.addEventListener('mousemove', (e) => { + const moveX = (e.clientX - window.innerWidth / 2) * 0.01; + const moveY = (e.clientY - window.innerHeight / 2) * 0.01; + gsap.to(patternOverlay, { + x: moveX, + y: moveY, + duration: 1, + ease: 'power2.out' + }); + }); + + const exhibitionCards = document.querySelectorAll('.exhibition-card'); + exhibitionCards.forEach(card => { + card.addEventListener('mouseenter', () => { + gsap.to(card, { + y: -10, + scale: 1.02, + duration: 0.3, + ease: 'power2.out' + }); + }); + + card.addEventListener('mouseleave', () => { + gsap.to(card, { + y: 0, + scale: 1, + duration: 0.3, + ease: 'power2.out' + }); + }); + }); + + function createParticles() { + const particleContainer = document.createElement('div'); + particleContainer.className = 'particle-container'; + document.body.appendChild(particleContainer); + + for (let i = 0; i < 50; i++) { + const particle = document.createElement('div'); + particle.className = 'particle'; + particle.style.left = Math.random() * 100 + 'vw'; + particle.style.animationDelay = Math.random() * 5 + 's'; + particleContainer.appendChild(particle); + } + } + + document.addEventListener('DOMContentLoaded', () => { + createParticles(); + + const scrollElements = document.querySelectorAll('.bamboo-content > *'); + scrollElements.forEach(element => { + element.style.opacity = '0'; + element.style.transform = 'translateX(-20px)'; + }); + + const revealOnScroll = () => { + scrollElements.forEach(element => { + const elementTop = element.getBoundingClientRect().top; + if (elementTop < window.innerHeight - 100) { + element.style.opacity = '1'; + element.style.transform = 'translateX(0)'; + element.style.transition = 'all 0.8s ease'; + } + }); + }; + + window.addEventListener('scroll', revealOnScroll); + revealOnScroll(); + }); + + function animateCounter(element) { + const target = parseInt(element.dataset.target); + const duration = 2000; + const step = target / (duration / 16); // 60fps + let current = 0; + + const updateCounter = () => { + current += step; + if (current < target) { + element.textContent = Math.floor(current); + requestAnimationFrame(updateCounter); + } else { + element.textContent = target; + } + }; + + updateCounter(); + } + + const observerOptions = { + threshold: 0.5 + }; + + const observer = new IntersectionObserver((entries) => { + entries.forEach(entry => { + if (entry.isIntersecting) { + const counters = entry.target.querySelectorAll('.counter'); + counters.forEach(counter => animateCounter(counter)); + observer.unobserve(entry.target); + } + }); + }, observerOptions); + + document.querySelectorAll('.stats-section').forEach(section => { + observer.observe(section); + }); +}); diff --git a/WareHouse/TsinghuaBambooWebsite_THUNLPDemo_2024/styles.css b/WareHouse/TsinghuaBambooWebsite_THUNLPDemo_2024/styles.css new file mode 100644 index 00000000..c12a8127 --- /dev/null +++ b/WareHouse/TsinghuaBambooWebsite_THUNLPDemo_2024/styles.css @@ -0,0 +1,1158 @@ +@import url('https://fonts.googleapis.com/css2?family=Noto+Serif+SC:wght@200;300;400;500;600&display=swap'); +@import url('https://fonts.googleapis.com/css2?family=Ma+Yen+Kai&display=swap'); + +:root { + --primary-color: #8B0000; + --accent-color: #FFD700; + --text-color: #2A2A2A; + --overlay-color: rgba(0, 0, 0, 0.8); + --transition-slow: 0.8s cubic-bezier(0.77, 0, 0.175, 1); + --transition-medium: 0.5s cubic-bezier(0.77, 0, 0.175, 1); + --transition-fast: 0.3s cubic-bezier(0.77, 0, 0.175, 1); + --chinese-red: #c41e3a; + --jade-green: #00a86b; + --bg-dark: #1a1a1a; + --bg-light: #ffffff; + --text-light: #ffffff; + --text-muted: #999999; +} + +* { + margin: 0; + padding: 0; + box-sizing: border-box; +} + +html { + scroll-behavior: smooth; +} + +body { + font-family: 'Ma Yen Kai', sans-serif; + line-height: 1.6; + background: linear-gradient(135deg, var(--bg-dark), #2a2a2a); + overflow-x: hidden; + color: var(--text-color); +} + +/* Header & Navigation */ +header { + background: rgba(26, 26, 26, 0.95); + backdrop-filter: blur(10px); + box-shadow: 0 2px 20px rgba(0,0,0,0.2); + position: fixed; + width: 100%; + top: 0; + z-index: 1000; + height: 70px; +} + +nav { + display: flex; + justify-content: space-between; + align-items: center; + padding: 1rem 5%; + max-width: 1200px; + margin: 0 auto; + height: 100%; +} + +.logo { + font-size: 1.8rem; + font-weight: 400; + letter-spacing: 2px; + color: var(--accent-color); +} + +nav ul { + display: flex; + list-style: none; + gap: 2rem; +} + +.magnetic-link { + text-decoration: none; + color: var(--text-light); + font-weight: 400; + position: relative; + padding: 0.5rem 0; + transition: color var(--transition-fast); +} + +.magnetic-link::after { + content: ''; + position: absolute; + bottom: 0; + left: 0; + width: 100%; + height: 1px; + background: var(--accent-color); + transform: scaleX(0); + transform-origin: right; + transition: transform var(--transition-medium); +} + +.magnetic-link:hover { + color: var(--accent-color); +} + +.magnetic-link:hover::after { + transform: scaleX(1); + transform-origin: left; +} + +/* Hero Section */ +#hero { + height: calc(100vh - 70px); + position: relative; + overflow: hidden; + margin-top: 70px; +} + +.hero-slider { + width: 100%; + height: 100%; + position: relative; +} + +.swiper-slide { + overflow: hidden; +} + +.slide-inner { + position: relative; + width: 100%; + height: 100%; + overflow: hidden; + background-color: #000; +} + +.slide-inner img { + width: 100%; + height: 100%; + object-fit: cover; + transform: scale(1); + transition: transform 8s ease; +} + +.swiper-slide-active .slide-inner img { + transform: scale(1.1); +} + +.slide-overlay { + position: absolute; + bottom: 0; + right: 0; + width: 40%; + padding: 3rem; + background: var(--overlay-color); + color: var(--text-light); + text-align: right; + transform: translateY(100%); + opacity: 0; + transition: all var(--transition-medium); + backdrop-filter: blur(10px); +} + +.swiper-slide-active .slide-overlay { + transform: translateY(0); + opacity: 1; +} + +.slide-overlay h2 { + font-size: 2.5rem; + margin-bottom: 1rem; + font-weight: 400; + transform: translateX(50px); + opacity: 0; + transition: all var(--transition-medium) 0.5s; + color: var(--accent-color); +} + +.slide-overlay p { + font-size: 1.2rem; + line-height: 1.6; + transform: translateX(50px); + opacity: 0; + transition: all var(--transition-medium) 0.7s; + color: var(--text-light); +} + +.swiper-slide-active .slide-overlay h2, +.swiper-slide-active .slide-overlay p { + transform: translateX(0); + opacity: 1; +} + +/* Navigation Controls */ +.swiper-button-prev, +.swiper-button-next { + width: 50px; + height: 50px; + color: white !important; + opacity: 0; + transition: all var(--transition-fast); +} + +.hero-slider:hover .swiper-button-prev, +.hero-slider:hover .swiper-button-next { + opacity: 1; +} + +.swiper-pagination-bullet { + width: 12px; + height: 12px; + background: rgba(255, 255, 255, 0.9); + opacity: 0.5; + transition: all var(--transition-fast); +} + +.swiper-pagination-bullet-active { + opacity: 1; + background: white; + transform: scale(1.2); +} + +/* Exhibitions Section */ +#exhibitions { + padding: 100px 0; + background: var(--bg-light); + position: relative; +} + +.section-title { + text-align: center; + font-size: 3rem; + font-weight: 400; + margin-bottom: 4rem; + color: var(--primary-color); + position: relative; + padding: 20px 0; +} + +.section-title::before { + content: ''; + position: absolute; + left: 0; + top: 50%; + width: 100%; + height: 2px; + background: repeating-linear-gradient( + 90deg, + var(--accent-color), + var(--accent-color) 4px, + transparent 4px, + transparent 8px + ); + opacity: 0.3; + transform: translateY(-50%); +} + +.exhibition-grid { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); + gap: 3rem; + padding: 0 5%; + max-width: 1400px; + margin: 0 auto; +} + +.exhibition-card { + position: relative; + background: white; + border-radius: 8px; + overflow: hidden; + box-shadow: 0 15px 45px rgba(0,0,0,0.1); + transition: all var(--transition-medium); + opacity: 0; + transform: translateY(30px); +} + +.exhibition-card.aos-animate { + opacity: 1; + transform: translateY(0); +} + +.exhibition-card:hover { + transform: translateY(-10px); + box-shadow: 0 25px 65px rgba(0,0,0,0.15); +} + +.card-image-wrapper { + position: relative; + overflow: hidden; + padding-top: 75%; +} + +.card-image-wrapper img { + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + object-fit: cover; + transition: transform var(--transition-medium); +} + +.exhibition-card:hover .card-image-wrapper img { + transform: scale(1.1); +} + +.card-content { + padding: 2rem; + background: white; +} + +.card-content h3 { + font-size: 1.5rem; + font-weight: 400; + margin-bottom: 0.5rem; + color: var(--primary-color); +} + +.card-content p { + color: var(--text-color); + font-size: 1rem; + line-height: 1.6; +} + +/* Footer */ +footer { + background: var(--bg-dark); + color: white; + padding: 5rem 5%; +} + +.footer-content { + max-width: 1200px; + margin: 0 auto; + display: grid; + grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); + gap: 3rem; +} + +.footer-content h3 { + font-size: 1.5rem; + font-weight: 400; + margin-bottom: 1.5rem; + color: var(--accent-color); +} + +.footer-content p { + color: var(--text-light); + margin-bottom: 0.5rem; +} + +/* Responsive Design */ +@media (max-width: 768px) { + nav { + flex-direction: column; + padding: 1rem; + } + + nav ul { + flex-direction: column; + text-align: center; + gap: 1rem; + } + + .slide-overlay { + width: 100%; + padding: 2rem; + } + + .slide-overlay h2 { + font-size: 2rem; + } + + .exhibition-grid { + gap: 2rem; + padding: 0 2rem; + } +} + +/* Animation Classes */ +[data-aos] { + opacity: 0; + transform: translateY(30px); + transition: all var(--transition-medium); +} + +[data-aos].aos-animate { + opacity: 1; + transform: translateY(0); +} + +/* Pattern Overlay */ +.pattern-overlay { + position: fixed; + top: 0; + left: 0; + width: 100%; + height: 100%; + background-image: + repeating-linear-gradient(45deg, + rgba(139, 0, 0, 0.03) 0px, + rgba(139, 0, 0, 0.03) 2px, + transparent 2px, + transparent 4px + ), + repeating-linear-gradient(-45deg, + rgba(255, 215, 0, 0.03) 0px, + rgba(255, 215, 0, 0.03) 2px, + transparent 2px, + transparent 4px + ); + pointer-events: none; + z-index: 1; +} + +/* Digital Experience Section */ +.digital-cards { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); + gap: 2rem; + padding: 0 5%; + perspective: 1000px; +} + +.digital-card { + height: 300px; + perspective: 1000px; + cursor: pointer; +} + +.card-inner { + position: relative; + width: 100%; + height: 100%; + transform-style: preserve-3d; + transition: transform 0.8s cubic-bezier(0.23, 1, 0.32, 1); +} + +.digital-card:hover .card-inner { + transform: rotateY(180deg); +} + +.card-front, +.card-back { + position: absolute; + width: 100%; + height: 100%; + backface-visibility: hidden; + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + padding: 2rem; + background: rgba(26, 26, 26, 0.9); + backdrop-filter: blur(10px); + border: 1px solid rgba(255, 215, 0, 0.2); + border-radius: 15px; + color: var(--text-light); +} + +.card-back { + transform: rotateY(180deg); + background: rgba(196, 161, 98, 0.2); +} + +.card-front h3 { + font-size: 1.8rem; + font-weight: 400; + margin-bottom: 1.5rem; + text-align: center; + color: var(--accent-color); +} + +.card-back p { + font-size: 1.2rem; + text-align: center; + line-height: 1.6; + margin-bottom: 1.5rem; +} + +.experience-btn { + display: inline-block; + padding: 0.8rem 1.5rem; + background: linear-gradient(45deg, var(--chinese-red), var(--primary-color)); + color: white; + text-decoration: none; + border-radius: 25px; + font-size: 1rem; + transition: all 0.3s ease; + border: 1px solid rgba(255, 255, 255, 0.2); + margin-top: 1rem; +} + +.experience-btn:hover { + transform: translateY(-2px); + box-shadow: 0 5px 15px rgba(139, 0, 0, 0.3); + background: linear-gradient(45deg, var(--primary-color), var(--chinese-red)); +} + +.section-content { + width: 100%; + max-width: 1200px; + margin: 0 auto; + padding: 2rem; +} + +.section-title { + text-align: center; + font-size: 2.5rem; + color: var(--accent-color); + margin-bottom: 3rem; + position: relative; +} + +.section-title::after { + content: ''; + position: absolute; + bottom: -10px; + left: 50%; + transform: translateX(-50%); + width: 100px; + height: 2px; + background: linear-gradient(90deg, transparent, var(--accent-color), transparent); +} + +@media (max-width: 768px) { + .digital-cards { + grid-template-columns: 1fr; + padding: 0 2rem; + } + + .digital-card { + height: 250px; + } + + .card-front h3 { + font-size: 1.5rem; + } + + .card-back p { + font-size: 1rem; + } + + .section-title { + font-size: 2rem; + } +} + +/* Add dot elastic animation */ +.dot-elastic { + position: relative; + width: 10px; + height: 10px; + border-radius: 5px; + background-color: var(--accent-color); + color: var(--accent-color); + animation: dot-elastic 1s infinite linear; + margin-top: 1rem; +} + +.dot-elastic::before, +.dot-elastic::after { + content: ''; + display: inline-block; + position: absolute; + top: 0; +} + +.dot-elastic::before { + left: -15px; + width: 10px; + height: 10px; + border-radius: 5px; + background-color: var(--accent-color); + color: var(--accent-color); + animation: dot-elastic-before 1s infinite linear; +} + +.dot-elastic::after { + left: 15px; + width: 10px; + height: 10px; + border-radius: 5px; + background-color: var(--accent-color); + color: var(--accent-color); + animation: dot-elastic-after 1s infinite linear; +} + +@keyframes dot-elastic-before { + 0% { transform: scale(1,1); } + 25% { transform: scale(1,1.5); } + 50% { transform: scale(1,0.67); } + 75% { transform: scale(1,1); } + 100% { transform: scale(1,1); } +} + +@keyframes dot-elastic { + 0% { transform: scale(1,1); } + 25% { transform: scale(1,1); } + 50% { transform: scale(1,1.5); } + 75% { transform: scale(1,1); } + 100% { transform: scale(1,1); } +} + +@keyframes dot-elastic-after { + 0% { transform: scale(1,1); } + 25% { transform: scale(1,1); } + 50% { transform: scale(1,0.67); } + 75% { transform: scale(1,1.5); } + 100% { transform: scale(1,1); } +} + +/* Cultural Heritage Section */ +#cultural-heritage { + padding: 100px 0; + background: linear-gradient(to bottom, var(--bg-light) 0%, rgba(139, 0, 0, 0.1) 100%); + position: relative; +} + +.heritage-container { + max-width: 1200px; + margin: 0 auto; + padding: 0 5%; + position: relative; +} + +.heritage-timeline { + position: relative; + padding: 4rem 0; +} + +.heritage-timeline::before { + content: ''; + position: absolute; + left: 50%; + top: 0; + width: 2px; + height: 100%; + background: linear-gradient(to bottom, var(--accent-color) 0%, rgba(196, 161, 98, 0.3) 100%); + transform: translateX(-50%); +} + +.timeline-item { + width: 50%; + padding: 1rem; + position: relative; + margin-bottom: -5rem; +} + +.timeline-item:last-child { + margin-bottom: 0; +} + +.timeline-item:nth-child(odd) { + margin-left: auto; + padding-left: 4rem; +} + +.timeline-item:nth-child(even) { + padding-right: 4rem; +} + +.timeline-item::before { + content: ''; + position: absolute; + width: 20px; + height: 20px; + background: var(--accent-color); + border-radius: 50%; + top: 50%; + transform: translateY(-50%); + box-shadow: 0 0 0 4px rgba(196, 161, 98, 0.2); + transition: all var(--transition-medium); + z-index: 1; +} + +.timeline-item:hover::before { + transform: translateY(-50%) scale(1.2); + box-shadow: 0 0 0 8px rgba(196, 161, 98, 0.2); +} + +.timeline-item:nth-child(odd)::before { + left: -10px; +} + +.timeline-item:nth-child(even)::before { + right: -10px; +} + +.timeline-content { + background: var(--bg-light); + padding: 2rem; + border-radius: 15px; + box-shadow: 0 10px 30px rgba(0, 0, 0, 0.15); + position: relative; + transition: transform var(--transition-medium); + border: 1px solid rgba(255, 215, 0, 0.2); +} + +.timeline-content::before { + content: ''; + position: absolute; + width: 0; + height: 0; + border-style: solid; + top: 50%; + transform: translateY(-50%); +} + +.timeline-item:nth-child(odd) .timeline-content::before { + border-width: 10px 0 10px 10px; + border-color: transparent transparent transparent rgba(255, 215, 0, 0.2); + left: -10px; +} + +.timeline-item:nth-child(even) .timeline-content::before { + border-width: 10px 10px 10px 0; + border-color: transparent rgba(255, 215, 0, 0.2) transparent transparent; + right: -10px; +} + +.timeline-content:hover { + transform: translateY(-5px); +} + +.timeline-content h3 { + color: var(--primary-color); + font-size: 1.8rem; + margin-bottom: 1rem; + font-weight: 400; +} + +.timeline-content p { + color: var(--text-color); + line-height: 1.8; + margin-bottom: 1rem; + font-size: 1.1rem; +} + +.timeline-period { + display: inline-block; + padding: 0.5rem 1rem; + background: rgba(139, 0, 0, 0.1); + border-radius: 20px; + font-size: 0.9rem; + color: var(--primary-color); + margin-top: 1rem; + font-weight: 500; +} + +@media (max-width: 768px) { + .heritage-timeline::before { + left: 0; + } + + .timeline-item { + width: 100%; + padding: 2rem 0 2rem 3rem; + margin-bottom: 3rem; + } + + .timeline-item:nth-child(odd), + .timeline-item:nth-child(even) { + margin-left: 0; + padding-left: 3rem; + padding-right: 1rem; + } + + .timeline-item::before { + left: -10px !important; + } + + .timeline-content h3 { + font-size: 1.5rem; + } + + .timeline-content p { + font-size: 1rem; + } +} + +/* Quote Section */ +.parallax-section { + position: relative; + height: 500px; + background: linear-gradient(135deg, var(--bg-dark) 0%, #2a2a2a 100%); + color: white; + overflow: hidden; + display: flex; + align-items: center; + justify-content: center; +} + +.quote-container { + width: 100%; + max-width: 800px; + margin: 0 auto; + padding: 4rem; + text-align: center; + z-index: 2; +} + +.cultural-slogan { + font-size: 5.5rem; + font-weight: 500; + background: linear-gradient(120deg, var(--accent-color), #FFA500); + -webkit-background-clip: text; + background-clip: text; + -webkit-text-fill-color: transparent; + text-shadow: 0 0 30px rgba(255, 215, 0, 0.3); + margin: 2rem 0; + text-align: center; + position: relative; + animation: glowPulse 3s infinite; +} + +/* Cultural Heritage Section Title */ +#cultural-heritage .section-title { + color: var(--chinese-red); +} + +@media (max-width: 768px) { + .parallax-section { + height: 400px; + } + + .quote-container { + padding: 2rem; + } + + .cultural-slogan { + font-size: 5rem; + padding: 0 1rem; + } +} + +/* Animation Classes */ +.fade-up { + opacity: 0; + transform: translateY(20px); + transition: opacity 0.6s ease, transform 0.6s ease; +} + +.fade-up.visible { + opacity: 1; + transform: translateY(0); +} + +/* Loading Animation */ +.dot-elastic { + position: relative; + width: 10px; + height: 10px; + border-radius: 5px; + background-color: var(--accent-color); + color: var(--accent-color); + animation: dot-elastic 1s infinite linear; +} + +.dot-elastic::before, +.dot-elastic::after { + content: ''; + display: inline-block; + position: absolute; + top: 0; +} + +.dot-elastic::before { + left: -15px; + width: 10px; + height: 10px; + border-radius: 5px; + background-color: var(--accent-color); + color: var(--accent-color); + animation: dot-elastic-before 1s infinite linear; +} + +.dot-elastic::after { + left: 15px; + width: 10px; + height: 10px; + border-radius: 5px; + background-color: var(--accent-color); + color: var(--accent-color); + animation: dot-elastic-after 1s infinite linear; +} + +@keyframes dot-elastic-before { + 0% { transform: scale(1,1); } + 25% { transform: scale(1,1.5); } + 50% { transform: scale(1,0.67); } + 75% { transform: scale(1,1); } + 100% { transform: scale(1,1); } +} + +@keyframes dot-elastic { + 0% { transform: scale(1,1); } + 25% { transform: scale(1,1); } + 50% { transform: scale(1,1.5); } + 75% { transform: scale(1,1); } + 100% { transform: scale(1,1); } +} + +@keyframes dot-elastic-after { + 0% { transform: scale(1,1); } + 25% { transform: scale(1,1); } + 50% { transform: scale(1,0.67); } + 75% { transform: scale(1,1.5); } + 100% { transform: scale(1,1); } +} + +.scroll-container { + width: 100%; + margin: 0 auto; +} + +.chinese-scroll { + width: 100%; +} + +.site-header { + position: relative; + padding: 20px 0; + background: linear-gradient( + to bottom, + rgba(139, 0, 0, 0.9), + transparent + ); + overflow: hidden; +} + +.site-header::after { + content: ''; + position: absolute; + top: -50%; + left: -50%; + width: 200%; + height: 200%; + background: linear-gradient( + 45deg, + transparent, + rgba(255, 215, 0, 0.1), + transparent + ); + animation: lightSweep 3s linear infinite; + transform: rotate(45deg); +} + +@keyframes lightSweep { + 0% { transform: rotate(45deg) translateY(-100%); } + 100% { transform: rotate(45deg) translateY(100%); } +} + +.site-header h1 { + color: var(--accent-color); + text-shadow: + 2px 2px 4px rgba(0, 0, 0, 0.3), + 0 0 20px rgba(255, 215, 0, 0.5); + font-weight: 300; + letter-spacing: 2px; + text-align: center; + position: relative; + z-index: 2; +} + +.chinese-knot { + position: absolute; + top: 20px; + right: 50px; + width: 40px; + height: 40px; + transform: rotate(45deg); +} + +.chinese-knot::before, +.chinese-knot::after { + content: ''; + position: absolute; + width: 100%; + height: 100%; + border: 2px solid var(--accent-color); + border-radius: 0 50% 50% 50%; + animation: knotFloat 3s ease-in-out infinite; +} + +.chinese-knot::after { + transform: rotate(90deg); + border-color: var(--primary-color); +} + +@keyframes knotFloat { + 0%, 100% { transform: rotate(90deg) scale(1); } + 50% { transform: rotate(90deg) scale(1.1); } +} + +.bamboo-content { + width: 100%; + position: relative; + background: + linear-gradient(45deg, rgba(255, 215, 0, 0.05) 25%, transparent 25%) -50px 0, + linear-gradient(-45deg, rgba(255, 215, 0, 0.05) 25%, transparent 25%) -50px 0, + linear-gradient(45deg, transparent 75%, rgba(255, 215, 0, 0.05) 75%), + linear-gradient(-45deg, transparent 75%, rgba(255, 215, 0, 0.05) 75%); + background-size: 100px 100px; + background-attachment: fixed; +} + +/* 动态数据统计部分 */ +.stats-section { + background: var(--overlay-color); + padding: 60px 0; + position: relative; + overflow: hidden; + margin: 40px 0; +} + +.stats-container { + display: flex; + justify-content: space-around; + flex-wrap: wrap; + max-width: 1200px; + margin: 0 auto; + gap: 40px; +} + +.stat-item { + position: relative; + color: var(--accent-color); + text-align: center; + padding: 30px; + min-width: 250px; + background: rgba(26, 26, 26, 0.9); + backdrop-filter: blur(10px); + border-radius: 15px; + border: 1px solid rgba(255, 215, 0, 0.2); + box-shadow: 0 0 20px rgba(255, 215, 0, 0.1); +} + +.stat-item:hover { + transform: translateY(-5px); + box-shadow: 0 5px 30px rgba(255, 215, 0, 0.2); + transition: all 0.3s ease; +} + +.stat-number { + font-size: 4rem; + font-weight: 400; + display: flex; + justify-content: center; + align-items: baseline; + text-shadow: 0 0 15px rgba(255, 215, 0, 0.4); + color: var(--accent-color); +} + +.stat-number .plus { + font-size: 2rem; + margin-left: 5px; +} + +.stat-label { + color: var(--text-light); + font-size: 1.2rem; + margin-top: 10px; + font-weight: 400; +} + +.stat-wave { + position: absolute; + bottom: 0; + left: 0; + width: 100%; + height: 3px; + background: linear-gradient(90deg, transparent, var(--accent-color), transparent); + animation: waveFlow 2s linear infinite; +} + +@keyframes waveFlow { + 0% { transform: translateX(-100%); } + 100% { transform: translateX(100%); } +} + +.experience-btn { + display: inline-block; + padding: 8px 20px; + margin-top: 15px; + background: linear-gradient(45deg, var(--chinese-red), var(--primary-color)); + color: white; + text-decoration: none; + border-radius: 25px; + font-size: 14px; + transition: all 0.3s ease; + border: 1px solid rgba(255, 255, 255, 0.2); +} + +.experience-btn:hover { + transform: translateY(-2px); + box-shadow: 0 5px 15px rgba(139, 0, 0, 0.3); + background: linear-gradient(45deg, var(--primary-color), var(--chinese-red)); +} + +.cultural-slogan { + font-size: 2.5rem; + font-weight: 500; + background: linear-gradient(120deg, var(--accent-color), #FFA500); + -webkit-background-clip: text; + background-clip: text; + -webkit-text-fill-color: transparent; + text-shadow: 0 0 30px rgba(255, 215, 0, 0.3); + margin: 1rem 0; + text-align: center; + position: relative; + animation: glowPulse 3s infinite; + transform: translateZ(0); + backface-visibility: hidden; + will-change: transform; +} + +@keyframes glowPulse { + 0%, 100% { + text-shadow: 0 0 30px rgba(255, 215, 0, 0.3); + } + 50% { + text-shadow: 0 0 50px rgba(255, 215, 0, 0.5); + } +} + +.cultural-slogan::before { + content: ''; + position: absolute; + bottom: -10px; + left: 50%; + transform: translateX(-50%); + width: 300px; + height: 2px; + background: linear-gradient(90deg, transparent, var(--accent-color), transparent); +} + +@media (max-width: 768px) { + .cultural-slogan { + font-size: 4rem; + padding: 0 1rem; + } +} + +/* Footer styles */ +.footer-left { + display: flex; + align-items: center; + gap: 20px; +} + +.footer-logo { + width: 300px; + height: auto; + object-fit: contain; +} + +.contact { + text-align: left; +} + +.opening-hours { + text-align: right; +} \ No newline at end of file diff --git a/WareHouse/TsinghuaBambooWebsite_THUNLPDemo_2024/warring-states-bamboo.html b/WareHouse/TsinghuaBambooWebsite_THUNLPDemo_2024/warring-states-bamboo.html new file mode 100644 index 00000000..95bc13c5 --- /dev/null +++ b/WareHouse/TsinghuaBambooWebsite_THUNLPDemo_2024/warring-states-bamboo.html @@ -0,0 +1,369 @@ + + + + + + ChatDev数字博物馆 + + + + + + + + +
+
+
+ +
+ +
+ +
+ +
+
+

战国文化

+ + +
+
+ + +
+
+
+ + + + + + + + \ No newline at end of file diff --git a/WareHouse/car_THUNLPDemo_2024/ChatChainConfig.json b/WareHouse/car_THUNLPDemo_2024/ChatChainConfig.json new file mode 100644 index 00000000..d82c6caf --- /dev/null +++ b/WareHouse/car_THUNLPDemo_2024/ChatChainConfig.json @@ -0,0 +1,90 @@ +{ + "chain": [ + { + "phase": "Coding", + "phaseType": "SimplePhase", + "max_turn_step": 1, + "need_reflect": "False" + }, + { + "phase": "CodeCompleteAll", + "phaseType": "ComposedPhase", + "cycleNum": 10, + "Composition": [{ + "phase": "CodeComplete", + "phaseType": "SimplePhase", + "max_turn_step": 1, + "need_reflect": "False" + }] + }, + { + "phase": "CodeReview", + "phaseType": "ComposedPhase", + "cycleNum": 2, + "Composition": [{ + "phase": "CodeReviewComment", + "phaseType": "SimplePhase", + "max_turn_step": 1, + "need_reflect": "False" + }, + { + "phase": "CodeReviewModification", + "phaseType": "SimplePhase", + "max_turn_step": 1, + "need_reflect": "False" + } + ] + }, + { + "phase": "Test", + "phaseType": "ComposedPhase", + "cycleNum": 2, + "Composition": [ + { + "phase": "TestErrorSummary", + "phaseType": "SimplePhase", + "max_turn_step": 1, + "need_reflect": "False" + }, + { + "phase": "TestModification", + "phaseType": "SimplePhase", + "max_turn_step": 1, + "need_reflect": "False" + } + ] + }, + { + "phase": "HumanAgentInteraction", + "phaseType": "ComposedPhase", + "cycleNum": 1, + "Composition": [ + { + "phase": "CodeReviewHuman", + "phaseType": "SimplePhase", + "max_turn_step": 2, + "need_reflect": "False" + } + ] + } + ], + "recruitments": [ + "Chief Executive Officer", + "Counselor", + "Chief Human Resource Officer", + "Chief Product Officer", + "Chief Technology Officer", + "Programmer", + "Code Reviewer", + "Software Test Engineer", + "Chief Creative Officer" + ], + "clear_structure": "True", + "gui_design": "True", + "git_management": "False", + "web_spider": "False", + "self_improve": "False", + "incremental_develop": "False", + "with_memory": "False", + "background_prompt": "ChatDev is a virtual LLM Agent software company aiming to build the best software with simple but robust code, maximizing the controllability and visual effect of the software in pure python." +} diff --git a/WareHouse/car_THUNLPDemo_2024/Demo.prompt b/WareHouse/car_THUNLPDemo_2024/Demo.prompt new file mode 100644 index 00000000..ea2ff929 --- /dev/null +++ b/WareHouse/car_THUNLPDemo_2024/Demo.prompt @@ -0,0 +1 @@ +仔细开发一个赛车小游戏 \ No newline at end of file diff --git a/WareHouse/car_THUNLPDemo_2024/Demo_DefaultOrganization_20241221131803.log b/WareHouse/car_THUNLPDemo_2024/Demo_DefaultOrganization_20241221131803.log new file mode 100644 index 00000000..d9b48552 --- /dev/null +++ b/WareHouse/car_THUNLPDemo_2024/Demo_DefaultOrganization_20241221131803.log @@ -0,0 +1,3045 @@ +[2024-21-12 13:18:03 INFO] Chief Technology Officer: **[Start Chat]** + +[ChatDev is a virtual LLM Agent software company aiming to build the best software with simple but robust code, maximizing the controllability and visual effect of the software in pure python. +You are Programmer. we are both working at ChatDev. We share a common interest in collaborating to successfully complete a task assigned by a new customer. +You can write/create computer software or applications by providing a specific programming language to the computer. You have extensive computing and coding experience in many varieties of programming languages and platforms, such as Python, Java, C, C++, HTML, CSS, JavaScript, XML, SQL, PHP, etc,. +Here is a new customer's task: 仔细开发一个赛车小游戏. +To complete the task, you must write a response that appropriately solves the requested instruction based on your expertise and customer's needs.] + +According to the new user's task and our software designs listed below: + +Task: "仔细开发一个赛车小游戏". + +Task description: "". + +Modality: "website or app, prefer app". + +Programming Language: "python for app, or html/css/js for website, prefer app" + +Ideas:"" + +We have decided to complete the task through a executable software with multiple files implemented via python for app, or html/css/js for website, prefer app. As the Programmer, to satisfy the new user's demands, you should write one or multiple files and make sure that every detail of the architecture is, in the end, implemented as code. The software should be equipped with graphical user interface (GUI) so that user can visually and graphically use it; so you must choose a GUI framework (e.g., in Python, you can implement GUI via tkinter, Pygame, Flexx, PyGUI, etc,). + +Think step by step and reason yourself to the right decisions to make sure we get it right. + +If you are using python to develop a software, develop it all in pure python, do not use assets such as images, videos, etc. The animation and GUI are necessary but should all implement in pure python. + +You will first lay out the names of the core classes, functions, methods that will be necessary, as well as a quick comment on their purpose. + +Then you will output the content of each file including complete code. Each file must strictly follow a markdown code block format, where the following tokens must be replaced such that "FILENAME" is the lowercase file name including the file extension, "LANGUAGE" in the programming language, "DOCSTRING" is a string literal specified in source code that is used to document a specific segment of code, and "CODE" is the original code: + +FILENAME + +```LANGUAGE + +''' + +DOCSTRING + +''' + +CODE + +``` + +You will start with the "main" file, then go to the ones that are imported by that file, and so on. + +Please note that the code should be fully functional. Ensure to implement all functions. No placeholders (such as 'pass' in Python). + +[2024-21-12 13:18:03 INFO] flask app.py did not start for online log +[2024-21-12 13:18:32 INFO] HTTP Request: POST https://yeysai.com/v1/chat/completions "HTTP/1.1 200 OK" +[2024-21-12 13:18:32 INFO] Programmer: **Programmer<->Chief Technology Officer on : Coding, turn 0** + +[ChatDev is a virtual LLM Agent software company aiming to build the best software with simple but robust code, maximizing the controllability and visual effect of the software in pure python. +You are Chief Technology Officer. we are both working at ChatDev. We share a common interest in collaborating to successfully complete a task assigned by a new customer. +You are very familiar to information technology. You will make high-level decisions for the overarching technology infrastructure that closely align with the organization's goals, while you work alongside the organization's information technology ("IT") staff members to perform everyday operations. +Here is a new customer's task: 仔细开发一个赛车小游戏. +To complete the task, You must write a response that appropriately solves the requested instruction based on your expertise and customer's needs.] + +I'll help create a simple racing game using Python and Pygame. Let's break this down step by step. + +Core Components Needed: +1. Main Game Class (game.py) + - Controls game loop, initialization, and state management +2. Player Car Class (car.py) + - Handles player car properties and movement +3. Track/Road Class (track.py) + - Manages the racing track and obstacles +4. Game Objects (gameobjects.py) + - Contains other game objects like opponent cars and obstacles + +Let's implement these files: + +main.py +```python +''' +Main game file that initializes the racing game and runs the game loop +''' + +import pygame +import sys +from car import PlayerCar +from track import Track +from gameobjects import OpponentCar + +class RacingGame: + def __init__(self): + pygame.init() + self.width = 800 + self.height = 600 + self.screen = pygame.display.set_mode((self.width, self.height)) + pygame.display.set_caption("Racing Game") + self.clock = pygame.time.Clock() + self.running = True + + # Create game objects + self.player = PlayerCar(self.width // 2, self.height - 100) + self.track = Track(self.width, self.height) + self.opponents = [OpponentCar(self.width) for _ in range(3)] + self.score = 0 + + def handle_events(self): + for event in pygame.event.get(): + if event.type == pygame.QUIT: + self.running = False + + keys = pygame.key.get_pressed() + self.player.handle_input(keys) + + def update(self): + self.player.update() + self.track.update() + for opponent in self.opponents: + opponent.update() + if self.player.check_collision(opponent): + self.running = False + self.score += 1 + + def render(self): + self.screen.fill((100, 100, 100)) # Gray background + self.track.draw(self.screen) + self.player.draw(self.screen) + for opponent in self.opponents: + opponent.draw(self.screen) + + # Draw score + font = pygame.font.Font(None, 36) + score_text = font.render(f'Score: {self.score}', True, (255, 255, 255)) + self.screen.blit(score_text, (10, 10)) + + pygame.display.flip() + + def run(self): + while self.running: + self.handle_events() + self.update() + self.render() + self.clock.tick(60) + + pygame.quit() + sys.exit() + +if __name__ == "__main__": + game = RacingGame() + game.run() +``` + +car.py +```python +''' +Player car class implementation +''' + +import pygame + +class PlayerCar: + def __init__(self, x, y): + self.x = x + self.y = y + self.width = 40 + self.height = 60 + self.speed = 5 + self.color = (255, 0, 0) # Red color + + def handle_input(self, keys): + if keys[pygame.K_LEFT] and self.x > 0: + self.x -= self.speed + if keys[pygame.K_RIGHT] and self.x < 800 - self.width: + self.x += self.speed + if keys[pygame.K_UP] and self.y > 0: + self.y -= self.speed + if keys[pygame.K_DOWN] and self.y < 600 - self.height: + self.y += self.speed + + def update(self): + pass # Movement is handled in handle_input + + def draw(self, screen): + pygame.draw.rect(screen, self.color, (self.x, self.y, self.width, self.height)) + + def check_collision(self, other): + return pygame.Rect(self.x, self.y, self.width, self.height).colliderect( + pygame.Rect(other.x, other.y, other.width, other.height) + ) +``` + +track.py +```python +''' +Track class for managing the racing environment +''' + +import pygame +import random + +class Track: + def __init__(self, width, height): + self.width = width + self.height = height + self.line_spacing = 100 + self.line_height = 30 + self.line_speed = 5 + self.lines = [] + self.initialize_lines() + + def initialize_lines(self): + for y in range(0, self.height, self.line_spacing): + self.lines.append(y) + + def update(self): + # Move lines down + self.lines = [(y + self.line_speed) % self.height for y in self.lines] + + def draw(self, screen): + for y in self.lines: + pygame.draw.rect(screen, (255, 255, 255), + (self.width // 3, y, 20, self.line_height)) + pygame.draw.rect(screen, (255, 255, 255), + (2 * self.width // 3, y, 20, self.line_height)) +``` + +gameobjects.py +```python +''' +Game objects implementation including opponent cars +''' + +import pygame +import random + +class OpponentCar: + def __init__(self, screen_width): + self.width = 40 + self.height = 60 + self.screen_width = screen_width + self.reset_position() + self.color = (0, 0, 255) # Blue color + self.speed = random.randint(3, 7) + + def reset_position(self): + self.x = random.randint(0, self.screen_width - self.width) + self.y = random.randint(-300, -100) + + def update(self): + self.y += self.speed + if self.y > 600: # If car goes off screen + self.reset_position() + + def draw(self, screen): + pygame.draw.rect(screen, self.color, (self.x, self.y, self.width, self.height)) +``` + +This implementation creates a simple racing game where: +1. The player controls a red car using arrow keys +2. Blue opponent cars move down the screen +3. The player must avoid colliding with opponent cars +4. The score increases as long as the player survives +5. The track is represented by white lines moving downward + +The game uses pure Python with Pygame for graphics, no external assets required. The game ends when the player collides with an opponent car. + +[2024-21-12 13:18:32 INFO] flask app.py did not start for online log +[2024-21-12 13:18:32 INFO] **[Seminar Conclusion]**: + + I'll help create a simple racing game using Python and Pygame. Let's break this down step by step. + +Core Components Needed: +1. Main Game Class (game.py) + - Controls game loop, initialization, and state management +2. Player Car Class (car.py) + - Handles player car properties and movement +3. Track/Road Class (track.py) + - Manages the racing track and obstacles +4. Game Objects (gameobjects.py) + - Contains other game objects like opponent cars and obstacles + +Let's implement these files: + +main.py +```python +''' +Main game file that initializes the racing game and runs the game loop +''' + +import pygame +import sys +from car import PlayerCar +from track import Track +from gameobjects import OpponentCar + +class RacingGame: + def __init__(self): + pygame.init() + self.width = 800 + self.height = 600 + self.screen = pygame.display.set_mode((self.width, self.height)) + pygame.display.set_caption("Racing Game") + self.clock = pygame.time.Clock() + self.running = True + + # Create game objects + self.player = PlayerCar(self.width // 2, self.height - 100) + self.track = Track(self.width, self.height) + self.opponents = [OpponentCar(self.width) for _ in range(3)] + self.score = 0 + + def handle_events(self): + for event in pygame.event.get(): + if event.type == pygame.QUIT: + self.running = False + + keys = pygame.key.get_pressed() + self.player.handle_input(keys) + + def update(self): + self.player.update() + self.track.update() + for opponent in self.opponents: + opponent.update() + if self.player.check_collision(opponent): + self.running = False + self.score += 1 + + def render(self): + self.screen.fill((100, 100, 100)) # Gray background + self.track.draw(self.screen) + self.player.draw(self.screen) + for opponent in self.opponents: + opponent.draw(self.screen) + + # Draw score + font = pygame.font.Font(None, 36) + score_text = font.render(f'Score: {self.score}', True, (255, 255, 255)) + self.screen.blit(score_text, (10, 10)) + + pygame.display.flip() + + def run(self): + while self.running: + self.handle_events() + self.update() + self.render() + self.clock.tick(60) + + pygame.quit() + sys.exit() + +if __name__ == "__main__": + game = RacingGame() + game.run() +``` + +car.py +```python +''' +Player car class implementation +''' + +import pygame + +class PlayerCar: + def __init__(self, x, y): + self.x = x + self.y = y + self.width = 40 + self.height = 60 + self.speed = 5 + self.color = (255, 0, 0) # Red color + + def handle_input(self, keys): + if keys[pygame.K_LEFT] and self.x > 0: + self.x -= self.speed + if keys[pygame.K_RIGHT] and self.x < 800 - self.width: + self.x += self.speed + if keys[pygame.K_UP] and self.y > 0: + self.y -= self.speed + if keys[pygame.K_DOWN] and self.y < 600 - self.height: + self.y += self.speed + + def update(self): + pass # Movement is handled in handle_input + + def draw(self, screen): + pygame.draw.rect(screen, self.color, (self.x, self.y, self.width, self.height)) + + def check_collision(self, other): + return pygame.Rect(self.x, self.y, self.width, self.height).colliderect( + pygame.Rect(other.x, other.y, other.width, other.height) + ) +``` + +track.py +```python +''' +Track class for managing the racing environment +''' + +import pygame +import random + +class Track: + def __init__(self, width, height): + self.width = width + self.height = height + self.line_spacing = 100 + self.line_height = 30 + self.line_speed = 5 + self.lines = [] + self.initialize_lines() + + def initialize_lines(self): + for y in range(0, self.height, self.line_spacing): + self.lines.append(y) + + def update(self): + # Move lines down + self.lines = [(y + self.line_speed) % self.height for y in self.lines] + + def draw(self, screen): + for y in self.lines: + pygame.draw.rect(screen, (255, 255, 255), + (self.width // 3, y, 20, self.line_height)) + pygame.draw.rect(screen, (255, 255, 255), + (2 * self.width // 3, y, 20, self.line_height)) +``` + +gameobjects.py +```python +''' +Game objects implementation including opponent cars +''' + +import pygame +import random + +class OpponentCar: + def __init__(self, screen_width): + self.width = 40 + self.height = 60 + self.screen_width = screen_width + self.reset_position() + self.color = (0, 0, 255) # Blue color + self.speed = random.randint(3, 7) + + def reset_position(self): + self.x = random.randint(0, self.screen_width - self.width) + self.y = random.randint(-300, -100) + + def update(self): + self.y += self.speed + if self.y > 600: # If car goes off screen + self.reset_position() + + def draw(self, screen): + pygame.draw.rect(screen, self.color, (self.x, self.y, self.width, self.height)) +``` + +This implementation creates a simple racing game where: +1. The player controls a red car using arrow keys +2. Blue opponent cars move down the screen +3. The player must avoid colliding with opponent cars +4. The score increases as long as the player survives +5. The track is represented by white lines moving downward + +The game uses pure Python with Pygame for graphics, no external assets required. The game ends when the player collides with an opponent car. + +[2024-21-12 13:18:32 INFO] flask app.py did not start for online log +[2024-21-12 13:18:32 INFO] **[Update Codes]** + +main.py updated. + + +``` +''' + +''' +--- Old ++++ New +@@ -1 +1,58 @@ +-# None ++''' ++Main game file that initializes the racing game and runs the game loop ++''' ++import pygame ++import sys ++from car import PlayerCar ++from track import Track ++from gameobjects import OpponentCar ++class RacingGame: ++ def __init__(self): ++ pygame.init() ++ self.width = 800 ++ self.height = 600 ++ self.screen = pygame.display.set_mode((self.width, self.height)) ++ pygame.display.set_caption("Racing Game") ++ self.clock = pygame.time.Clock() ++ self.running = True ++ # Create game objects ++ self.player = PlayerCar(self.width // 2, self.height - 100) ++ self.track = Track(self.width, self.height) ++ self.opponents = [OpponentCar(self.width) for _ in range(3)] ++ self.score = 0 ++ def handle_events(self): ++ for event in pygame.event.get(): ++ if event.type == pygame.QUIT: ++ self.running = False ++ keys = pygame.key.get_pressed() ++ self.player.handle_input(keys) ++ def update(self): ++ self.player.update() ++ self.track.update() ++ for opponent in self.opponents: ++ opponent.update() ++ if self.player.check_collision(opponent): ++ self.running = False ++ self.score += 1 ++ def render(self): ++ self.screen.fill((100, 100, 100)) # Gray background ++ self.track.draw(self.screen) ++ self.player.draw(self.screen) ++ for opponent in self.opponents: ++ opponent.draw(self.screen) ++ # Draw score ++ font = pygame.font.Font(None, 36) ++ score_text = font.render(f'Score: {self.score}', True, (255, 255, 255)) ++ self.screen.blit(score_text, (10, 10)) ++ pygame.display.flip() ++ def run(self): ++ while self.running: ++ self.handle_events() ++ self.update() ++ self.render() ++ self.clock.tick(60) ++ pygame.quit() ++ sys.exit() ++if __name__ == "__main__": ++ game = RacingGame() ++ game.run() +``` + +[2024-21-12 13:18:32 INFO] flask app.py did not start for online log +[2024-21-12 13:18:32 INFO] **[Update Codes]** + +car.py updated. + + +``` +''' + +''' +--- Old ++++ New +@@ -1 +1,29 @@ +-# None ++''' ++Player car class implementation ++''' ++import pygame ++class PlayerCar: ++ def __init__(self, x, y): ++ self.x = x ++ self.y = y ++ self.width = 40 ++ self.height = 60 ++ self.speed = 5 ++ self.color = (255, 0, 0) # Red color ++ def handle_input(self, keys): ++ if keys[pygame.K_LEFT] and self.x > 0: ++ self.x -= self.speed ++ if keys[pygame.K_RIGHT] and self.x < 800 - self.width: ++ self.x += self.speed ++ if keys[pygame.K_UP] and self.y > 0: ++ self.y -= self.speed ++ if keys[pygame.K_DOWN] and self.y < 600 - self.height: ++ self.y += self.speed ++ def update(self): ++ pass # Movement is handled in handle_input ++ def draw(self, screen): ++ pygame.draw.rect(screen, self.color, (self.x, self.y, self.width, self.height)) ++ def check_collision(self, other): ++ return pygame.Rect(self.x, self.y, self.width, self.height).colliderect( ++ pygame.Rect(other.x, other.y, other.width, other.height) ++ ) +``` + +[2024-21-12 13:18:32 INFO] flask app.py did not start for online log +[2024-21-12 13:18:32 INFO] **[Update Codes]** + +track.py updated. + + +``` +''' + +''' +--- Old ++++ New +@@ -1 +1,26 @@ +-# None ++''' ++Track class for managing the racing environment ++''' ++import pygame ++import random ++class Track: ++ def __init__(self, width, height): ++ self.width = width ++ self.height = height ++ self.line_spacing = 100 ++ self.line_height = 30 ++ self.line_speed = 5 ++ self.lines = [] ++ self.initialize_lines() ++ def initialize_lines(self): ++ for y in range(0, self.height, self.line_spacing): ++ self.lines.append(y) ++ def update(self): ++ # Move lines down ++ self.lines = [(y + self.line_speed) % self.height for y in self.lines] ++ def draw(self, screen): ++ for y in self.lines: ++ pygame.draw.rect(screen, (255, 255, 255), ++ (self.width // 3, y, 20, self.line_height)) ++ pygame.draw.rect(screen, (255, 255, 255), ++ (2 * self.width // 3, y, 20, self.line_height)) +``` + +[2024-21-12 13:18:32 INFO] flask app.py did not start for online log +[2024-21-12 13:18:32 INFO] **[Update Codes]** + +gameobjects.py updated. + + +``` +''' + +''' +--- Old ++++ New +@@ -1 +1,22 @@ +-# None ++''' ++Game objects implementation including opponent cars ++''' ++import pygame ++import random ++class OpponentCar: ++ def __init__(self, screen_width): ++ self.width = 40 ++ self.height = 60 ++ self.screen_width = screen_width ++ self.reset_position() ++ self.color = (0, 0, 255) # Blue color ++ self.speed = random.randint(3, 7) ++ def reset_position(self): ++ self.x = random.randint(0, self.screen_width - self.width) ++ self.y = random.randint(-300, -100) ++ def update(self): ++ self.y += self.speed ++ if self.y > 600: # If car goes off screen ++ self.reset_position() ++ def draw(self, screen): ++ pygame.draw.rect(screen, self.color, (self.x, self.y, self.width, self.height)) +``` + +[2024-21-12 13:18:32 INFO] flask app.py did not start for online log +[2024-21-12 13:18:32 INFO] **[Execute Detail]** + +execute SimplePhase:[CodeComplete] in ComposedPhase:[CodeCompleteAll], cycle 1 + +[2024-21-12 13:18:32 INFO] flask app.py did not start for online log +[2024-21-12 13:18:32 INFO] **[Execute Detail]** + +execute SimplePhase:[CodeReviewComment] in ComposedPhase:[CodeReview], cycle 1 + +[2024-21-12 13:18:32 INFO] flask app.py did not start for online log +[2024-21-12 13:18:32 INFO] Programmer: **[Start Chat]** + +[ChatDev is a virtual LLM Agent software company aiming to build the best software with simple but robust code, maximizing the controllability and visual effect of the software in pure python. +You are Code Reviewer. we are both working at ChatDev. We share a common interest in collaborating to successfully complete a task assigned by a new customer. +You can help programmers to assess source codes for software troubleshooting, fix bugs to increase code quality and robustness, and offer proposals to improve the source codes. +Here is a new customer's task: 仔细开发一个赛车小游戏. +To complete the task, you must write a response that appropriately solves the requested instruction based on your expertise and customer's needs.] + +According to the new user's task and our software designs: +Task: "仔细开发一个赛车小游戏". +Modality: "website or app, prefer app". +Programming Language: "python for app, or html/css/js for website, prefer app" +Ideas: "" +Codes: +"main.py +```python +''' +Main game file that initializes the racing game and runs the game loop +''' +import pygame +import sys +from car import PlayerCar +from track import Track +from gameobjects import OpponentCar +class RacingGame: + def __init__(self): + pygame.init() + self.width = 800 + self.height = 600 + self.screen = pygame.display.set_mode((self.width, self.height)) + pygame.display.set_caption("Racing Game") + self.clock = pygame.time.Clock() + self.running = True + # Create game objects + self.player = PlayerCar(self.width // 2, self.height - 100) + self.track = Track(self.width, self.height) + self.opponents = [OpponentCar(self.width) for _ in range(3)] + self.score = 0 + def handle_events(self): + for event in pygame.event.get(): + if event.type == pygame.QUIT: + self.running = False + keys = pygame.key.get_pressed() + self.player.handle_input(keys) + def update(self): + self.player.update() + self.track.update() + for opponent in self.opponents: + opponent.update() + if self.player.check_collision(opponent): + self.running = False + self.score += 1 + def render(self): + self.screen.fill((100, 100, 100)) # Gray background + self.track.draw(self.screen) + self.player.draw(self.screen) + for opponent in self.opponents: + opponent.draw(self.screen) + # Draw score + font = pygame.font.Font(None, 36) + score_text = font.render(f'Score: {self.score}', True, (255, 255, 255)) + self.screen.blit(score_text, (10, 10)) + pygame.display.flip() + def run(self): + while self.running: + self.handle_events() + self.update() + self.render() + self.clock.tick(60) + pygame.quit() + sys.exit() +if __name__ == "__main__": + game = RacingGame() + game.run() +``` + +car.py +```python +''' +Player car class implementation +''' +import pygame +class PlayerCar: + def __init__(self, x, y): + self.x = x + self.y = y + self.width = 40 + self.height = 60 + self.speed = 5 + self.color = (255, 0, 0) # Red color + def handle_input(self, keys): + if keys[pygame.K_LEFT] and self.x > 0: + self.x -= self.speed + if keys[pygame.K_RIGHT] and self.x < 800 - self.width: + self.x += self.speed + if keys[pygame.K_UP] and self.y > 0: + self.y -= self.speed + if keys[pygame.K_DOWN] and self.y < 600 - self.height: + self.y += self.speed + def update(self): + pass # Movement is handled in handle_input + def draw(self, screen): + pygame.draw.rect(screen, self.color, (self.x, self.y, self.width, self.height)) + def check_collision(self, other): + return pygame.Rect(self.x, self.y, self.width, self.height).colliderect( + pygame.Rect(other.x, other.y, other.width, other.height) + ) +``` + +track.py +```python +''' +Track class for managing the racing environment +''' +import pygame +import random +class Track: + def __init__(self, width, height): + self.width = width + self.height = height + self.line_spacing = 100 + self.line_height = 30 + self.line_speed = 5 + self.lines = [] + self.initialize_lines() + def initialize_lines(self): + for y in range(0, self.height, self.line_spacing): + self.lines.append(y) + def update(self): + # Move lines down + self.lines = [(y + self.line_speed) % self.height for y in self.lines] + def draw(self, screen): + for y in self.lines: + pygame.draw.rect(screen, (255, 255, 255), + (self.width // 3, y, 20, self.line_height)) + pygame.draw.rect(screen, (255, 255, 255), + (2 * self.width // 3, y, 20, self.line_height)) +``` + +gameobjects.py +```python +''' +Game objects implementation including opponent cars +''' +import pygame +import random +class OpponentCar: + def __init__(self, screen_width): + self.width = 40 + self.height = 60 + self.screen_width = screen_width + self.reset_position() + self.color = (0, 0, 255) # Blue color + self.speed = random.randint(3, 7) + def reset_position(self): + self.x = random.randint(0, self.screen_width - self.width) + self.y = random.randint(-300, -100) + def update(self): + self.y += self.speed + if self.y > 600: # If car goes off screen + self.reset_position() + def draw(self, screen): + pygame.draw.rect(screen, self.color, (self.x, self.y, self.width, self.height)) +``` + +" +As the Code Reviewer, to make the software directly operable without further coding, ChatDev have formulated the following regulations: +1) all referenced classes should be imported; +2) all methods should be implemented; +3) all methods need to have the necessary comments; +4) no potential bugs; +5) The entire project conforms to the tasks proposed by the user; +6) most importantly, do not only check the errors in the code, but also the logic of code. Make sure that user can interact with generated software without losing any feature in the requirement; +7) If you are using python to develop a software, develop it all in pure python, do not use assets such as images, videos, etc. The animation and GUI are necessary but should all implement in pure python. +Now, you should check the above regulations one by one and review the codes in detail, propose one comment with the highest priority about the codes, and give me instructions on how to fix. Tell me your comment with the highest priority and corresponding suggestions on revision. If the codes are perfect and you have no comment on them, return only one line like " Finished". + +[2024-21-12 13:18:32 INFO] flask app.py did not start for online log +[2024-21-12 13:18:53 INFO] HTTP Request: POST https://yeysai.com/v1/chat/completions "HTTP/1.1 200 OK" +[2024-21-12 13:18:53 INFO] Code Reviewer: **Code Reviewer<->Programmer on : CodeReviewComment, turn 0** + +[ChatDev is a virtual LLM Agent software company aiming to build the best software with simple but robust code, maximizing the controllability and visual effect of the software in pure python. +You are Programmer. we are both working at ChatDev. We share a common interest in collaborating to successfully complete a task assigned by a new customer. +You can write/create computer software or applications by providing a specific programming language to the computer. You have extensive computing and coding experience in many varieties of programming languages and platforms, such as Python, Java, C, C++, HTML, CSS, JavaScript, XML, SQL, PHP, etc,. +Here is a new customer's task: 仔细开发一个赛车小游戏. +To complete the task, you must write a response that appropriately solves the requested instruction based on your expertise and customer's needs.] + +After reviewing the code according to the regulations, I have one high-priority comment: + +**High Priority Issue**: The game lacks proper game over handling and restart functionality. When the player collides with an opponent car, the game simply exits without showing any game over message or giving the player a chance to restart. + +Here's how to fix this in the `main.py` file: + +```python:main.py +class RacingGame: + def __init__(self): + # ... existing init code ... + self.game_over = False + self.font = pygame.font.Font(None, 74) + + def handle_events(self): + for event in pygame.event.get(): + if event.type == pygame.QUIT: + self.running = False + # Add restart functionality + if event.type == pygame.KEYDOWN and self.game_over: + if event.key == pygame.K_SPACE: + self.reset_game() + + if not self.game_over: # Only handle movement if game is active + keys = pygame.key.get_pressed() + self.player.handle_input(keys) + + def reset_game(self): + self.player = PlayerCar(self.width // 2, self.height - 100) + self.opponents = [OpponentCar(self.width) for _ in range(3)] + self.score = 0 + self.game_over = False + + def update(self): + if not self.game_over: # Only update if game is active + self.player.update() + self.track.update() + for opponent in self.opponents: + opponent.update() + if self.player.check_collision(opponent): + self.game_over = True + self.score += 1 + + def render(self): + # ... existing render code ... + + if self.game_over: + game_over_text = self.font.render('GAME OVER', True, (255, 0, 0)) + restart_text = pygame.font.Font(None, 36).render('Press SPACE to restart', True, (255, 255, 255)) + text_rect = game_over_text.get_rect(center=(self.width//2, self.height//2)) + restart_rect = restart_text.get_rect(center=(self.width//2, self.height//2 + 50)) + self.screen.blit(game_over_text, text_rect) + self.screen.blit(restart_text, restart_rect) + + pygame.display.flip() +``` + +This improvement: +1. Adds a proper game over screen +2. Implements restart functionality +3. Prevents player movement and score increase during game over state +4. Maintains game loop for restart option instead of immediate exit +5. Improves user experience by providing clear feedback and continuation options + +These changes make the game more complete and user-friendly, better meeting the customer's requirements for a carefully developed racing game. + +[2024-21-12 13:18:53 INFO] flask app.py did not start for online log +[2024-21-12 13:18:53 INFO] **[Seminar Conclusion]**: + + After reviewing the code according to the regulations, I have one high-priority comment: + +**High Priority Issue**: The game lacks proper game over handling and restart functionality. When the player collides with an opponent car, the game simply exits without showing any game over message or giving the player a chance to restart. + +Here's how to fix this in the `main.py` file: + +```python:main.py +class RacingGame: + def __init__(self): + # ... existing init code ... + self.game_over = False + self.font = pygame.font.Font(None, 74) + + def handle_events(self): + for event in pygame.event.get(): + if event.type == pygame.QUIT: + self.running = False + # Add restart functionality + if event.type == pygame.KEYDOWN and self.game_over: + if event.key == pygame.K_SPACE: + self.reset_game() + + if not self.game_over: # Only handle movement if game is active + keys = pygame.key.get_pressed() + self.player.handle_input(keys) + + def reset_game(self): + self.player = PlayerCar(self.width // 2, self.height - 100) + self.opponents = [OpponentCar(self.width) for _ in range(3)] + self.score = 0 + self.game_over = False + + def update(self): + if not self.game_over: # Only update if game is active + self.player.update() + self.track.update() + for opponent in self.opponents: + opponent.update() + if self.player.check_collision(opponent): + self.game_over = True + self.score += 1 + + def render(self): + # ... existing render code ... + + if self.game_over: + game_over_text = self.font.render('GAME OVER', True, (255, 0, 0)) + restart_text = pygame.font.Font(None, 36).render('Press SPACE to restart', True, (255, 255, 255)) + text_rect = game_over_text.get_rect(center=(self.width//2, self.height//2)) + restart_rect = restart_text.get_rect(center=(self.width//2, self.height//2 + 50)) + self.screen.blit(game_over_text, text_rect) + self.screen.blit(restart_text, restart_rect) + + pygame.display.flip() +``` + +This improvement: +1. Adds a proper game over screen +2. Implements restart functionality +3. Prevents player movement and score increase during game over state +4. Maintains game loop for restart option instead of immediate exit +5. Improves user experience by providing clear feedback and continuation options + +These changes make the game more complete and user-friendly, better meeting the customer's requirements for a carefully developed racing game. + +[2024-21-12 13:18:53 INFO] flask app.py did not start for online log +[2024-21-12 13:18:53 INFO] **[Execute Detail]** + +execute SimplePhase:[CodeReviewModification] in ComposedPhase:[CodeReview], cycle 1 + +[2024-21-12 13:18:53 INFO] flask app.py did not start for online log +[2024-21-12 13:18:53 INFO] Code Reviewer: **[Start Chat]** + +[ChatDev is a virtual LLM Agent software company aiming to build the best software with simple but robust code, maximizing the controllability and visual effect of the software in pure python. +You are Programmer. we are both working at ChatDev. We share a common interest in collaborating to successfully complete a task assigned by a new customer. +You can write/create computer software or applications by providing a specific programming language to the computer. You have extensive computing and coding experience in many varieties of programming languages and platforms, such as Python, Java, C, C++, HTML, CSS, JavaScript, XML, SQL, PHP, etc,. +Here is a new customer's task: 仔细开发一个赛车小游戏. +To complete the task, you must write a response that appropriately solves the requested instruction based on your expertise and customer's needs.] + +According to the new user's task, our designed product modality, languages and ideas, our developed first-edition source codes are listed below: +Task: "仔细开发一个赛车小游戏". +Modality: "website or app, prefer app". +Programming Language: "python for app, or html/css/js for website, prefer app" +Ideas: "" +Codes: +"main.py +```python +''' +Main game file that initializes the racing game and runs the game loop +''' +import pygame +import sys +from car import PlayerCar +from track import Track +from gameobjects import OpponentCar +class RacingGame: + def __init__(self): + pygame.init() + self.width = 800 + self.height = 600 + self.screen = pygame.display.set_mode((self.width, self.height)) + pygame.display.set_caption("Racing Game") + self.clock = pygame.time.Clock() + self.running = True + # Create game objects + self.player = PlayerCar(self.width // 2, self.height - 100) + self.track = Track(self.width, self.height) + self.opponents = [OpponentCar(self.width) for _ in range(3)] + self.score = 0 + def handle_events(self): + for event in pygame.event.get(): + if event.type == pygame.QUIT: + self.running = False + keys = pygame.key.get_pressed() + self.player.handle_input(keys) + def update(self): + self.player.update() + self.track.update() + for opponent in self.opponents: + opponent.update() + if self.player.check_collision(opponent): + self.running = False + self.score += 1 + def render(self): + self.screen.fill((100, 100, 100)) # Gray background + self.track.draw(self.screen) + self.player.draw(self.screen) + for opponent in self.opponents: + opponent.draw(self.screen) + # Draw score + font = pygame.font.Font(None, 36) + score_text = font.render(f'Score: {self.score}', True, (255, 255, 255)) + self.screen.blit(score_text, (10, 10)) + pygame.display.flip() + def run(self): + while self.running: + self.handle_events() + self.update() + self.render() + self.clock.tick(60) + pygame.quit() + sys.exit() +if __name__ == "__main__": + game = RacingGame() + game.run() +``` + +car.py +```python +''' +Player car class implementation +''' +import pygame +class PlayerCar: + def __init__(self, x, y): + self.x = x + self.y = y + self.width = 40 + self.height = 60 + self.speed = 5 + self.color = (255, 0, 0) # Red color + def handle_input(self, keys): + if keys[pygame.K_LEFT] and self.x > 0: + self.x -= self.speed + if keys[pygame.K_RIGHT] and self.x < 800 - self.width: + self.x += self.speed + if keys[pygame.K_UP] and self.y > 0: + self.y -= self.speed + if keys[pygame.K_DOWN] and self.y < 600 - self.height: + self.y += self.speed + def update(self): + pass # Movement is handled in handle_input + def draw(self, screen): + pygame.draw.rect(screen, self.color, (self.x, self.y, self.width, self.height)) + def check_collision(self, other): + return pygame.Rect(self.x, self.y, self.width, self.height).colliderect( + pygame.Rect(other.x, other.y, other.width, other.height) + ) +``` + +track.py +```python +''' +Track class for managing the racing environment +''' +import pygame +import random +class Track: + def __init__(self, width, height): + self.width = width + self.height = height + self.line_spacing = 100 + self.line_height = 30 + self.line_speed = 5 + self.lines = [] + self.initialize_lines() + def initialize_lines(self): + for y in range(0, self.height, self.line_spacing): + self.lines.append(y) + def update(self): + # Move lines down + self.lines = [(y + self.line_speed) % self.height for y in self.lines] + def draw(self, screen): + for y in self.lines: + pygame.draw.rect(screen, (255, 255, 255), + (self.width // 3, y, 20, self.line_height)) + pygame.draw.rect(screen, (255, 255, 255), + (2 * self.width // 3, y, 20, self.line_height)) +``` + +gameobjects.py +```python +''' +Game objects implementation including opponent cars +''' +import pygame +import random +class OpponentCar: + def __init__(self, screen_width): + self.width = 40 + self.height = 60 + self.screen_width = screen_width + self.reset_position() + self.color = (0, 0, 255) # Blue color + self.speed = random.randint(3, 7) + def reset_position(self): + self.x = random.randint(0, self.screen_width - self.width) + self.y = random.randint(-300, -100) + def update(self): + self.y += self.speed + if self.y > 600: # If car goes off screen + self.reset_position() + def draw(self, screen): + pygame.draw.rect(screen, self.color, (self.x, self.y, self.width, self.height)) +``` + +" +Comments on Codes: +"After reviewing the code according to the regulations, I have one high-priority comment: + +**High Priority Issue**: The game lacks proper game over handling and restart functionality. When the player collides with an opponent car, the game simply exits without showing any game over message or giving the player a chance to restart. + +Here's how to fix this in the `main.py` file: + +```python:main.py +class RacingGame: + def __init__(self): + # ... existing init code ... + self.game_over = False + self.font = pygame.font.Font(None, 74) + + def handle_events(self): + for event in pygame.event.get(): + if event.type == pygame.QUIT: + self.running = False + # Add restart functionality + if event.type == pygame.KEYDOWN and self.game_over: + if event.key == pygame.K_SPACE: + self.reset_game() + + if not self.game_over: # Only handle movement if game is active + keys = pygame.key.get_pressed() + self.player.handle_input(keys) + + def reset_game(self): + self.player = PlayerCar(self.width // 2, self.height - 100) + self.opponents = [OpponentCar(self.width) for _ in range(3)] + self.score = 0 + self.game_over = False + + def update(self): + if not self.game_over: # Only update if game is active + self.player.update() + self.track.update() + for opponent in self.opponents: + opponent.update() + if self.player.check_collision(opponent): + self.game_over = True + self.score += 1 + + def render(self): + # ... existing render code ... + + if self.game_over: + game_over_text = self.font.render('GAME OVER', True, (255, 0, 0)) + restart_text = pygame.font.Font(None, 36).render('Press SPACE to restart', True, (255, 255, 255)) + text_rect = game_over_text.get_rect(center=(self.width//2, self.height//2)) + restart_rect = restart_text.get_rect(center=(self.width//2, self.height//2 + 50)) + self.screen.blit(game_over_text, text_rect) + self.screen.blit(restart_text, restart_rect) + + pygame.display.flip() +``` + +This improvement: +1. Adds a proper game over screen +2. Implements restart functionality +3. Prevents player movement and score increase during game over state +4. Maintains game loop for restart option instead of immediate exit +5. Improves user experience by providing clear feedback and continuation options + +These changes make the game more complete and user-friendly, better meeting the customer's requirements for a carefully developed racing game." +If you are using python to develop a software, develop it all in pure python, do not use assets such as images, videos, etc. The animation and GUI are necessary but should all implement in pure python. +In the software, each file must strictly follow a markdown code block format, where the following tokens must be replaced such that "FILENAME" is the lowercase file name including the file extension, "LANGUAGE" in the programming language, "DOCSTRING" is a string literal specified in source code that is used to document a specific segment of code, and "CODE" is the original code. Format: +FILENAME +```LANGUAGE +''' +DOCSTRING +''' +CODE +``` +As the Programmer, to satisfy the new user's demand and make the software creative, executive and robust, you should modify corresponding codes according to the comments. Then, output the full and complete codes with all bugs fixed based on the comments. Return all codes strictly following the required format. + +[2024-21-12 13:18:53 INFO] flask app.py did not start for online log +[2024-21-12 13:19:27 INFO] HTTP Request: POST https://yeysai.com/v1/chat/completions "HTTP/1.1 200 OK" +[2024-21-12 13:19:27 INFO] Programmer: **Programmer<->Code Reviewer on : CodeReviewModification, turn 0** + +[ChatDev is a virtual LLM Agent software company aiming to build the best software with simple but robust code, maximizing the controllability and visual effect of the software in pure python. +You are Code Reviewer. we are both working at ChatDev. We share a common interest in collaborating to successfully complete a task assigned by a new customer. +You can help programmers to assess source codes for software troubleshooting, fix bugs to increase code quality and robustness, and offer proposals to improve the source codes. +Here is a new customer's task: 仔细开发一个赛车小游戏. +To complete the task, you must write a response that appropriately solves the requested instruction based on your expertise and customer's needs.] + +I'll modify the code according to the comments to add proper game over handling and restart functionality. Here's the complete, improved version of all files: + +main.py +```python +''' +Main game file that initializes the racing game and runs the game loop +''' +import pygame +import sys +from car import PlayerCar +from track import Track +from gameobjects import OpponentCar + +class RacingGame: + def __init__(self): + pygame.init() + self.width = 800 + self.height = 600 + self.screen = pygame.display.set_mode((self.width, self.height)) + pygame.display.set_caption("Racing Game") + self.clock = pygame.time.Clock() + self.running = True + self.game_over = False + self.font = pygame.font.Font(None, 74) + self.reset_game() + + def reset_game(self): + self.player = PlayerCar(self.width // 2, self.height - 100) + self.track = Track(self.width, self.height) + self.opponents = [OpponentCar(self.width) for _ in range(3)] + self.score = 0 + self.game_over = False + + def handle_events(self): + for event in pygame.event.get(): + if event.type == pygame.QUIT: + self.running = False + if event.type == pygame.KEYDOWN and self.game_over: + if event.key == pygame.K_SPACE: + self.reset_game() + + if not self.game_over: + keys = pygame.key.get_pressed() + self.player.handle_input(keys) + + def update(self): + if not self.game_over: + self.player.update() + self.track.update() + for opponent in self.opponents: + opponent.update() + if self.player.check_collision(opponent): + self.game_over = True + self.score += 1 + + def render(self): + self.screen.fill((100, 100, 100)) # Gray background + self.track.draw(self.screen) + self.player.draw(self.screen) + for opponent in self.opponents: + opponent.draw(self.screen) + + # Draw score + font = pygame.font.Font(None, 36) + score_text = font.render(f'Score: {self.score}', True, (255, 255, 255)) + self.screen.blit(score_text, (10, 10)) + + if self.game_over: + game_over_text = self.font.render('GAME OVER', True, (255, 0, 0)) + restart_text = pygame.font.Font(None, 36).render('Press SPACE to restart', True, (255, 255, 255)) + text_rect = game_over_text.get_rect(center=(self.width//2, self.height//2)) + restart_rect = restart_text.get_rect(center=(self.width//2, self.height//2 + 50)) + self.screen.blit(game_over_text, text_rect) + self.screen.blit(restart_text, restart_rect) + + pygame.display.flip() + + def run(self): + while self.running: + self.handle_events() + self.update() + self.render() + self.clock.tick(60) + pygame.quit() + sys.exit() + +if __name__ == "__main__": + game = RacingGame() + game.run() +``` + +car.py +```python +''' +Player car class implementation with improved visual representation +''' +import pygame + +class PlayerCar: + def __init__(self, x, y): + self.x = x + self.y = y + self.width = 40 + self.height = 60 + self.speed = 5 + self.color = (255, 0, 0) # Red color + + def handle_input(self, keys): + if keys[pygame.K_LEFT] and self.x > 0: + self.x -= self.speed + if keys[pygame.K_RIGHT] and self.x < 800 - self.width: + self.x += self.speed + if keys[pygame.K_UP] and self.y > 0: + self.y -= self.speed + if keys[pygame.K_DOWN] and self.y < 600 - self.height: + self.y += self.speed + + def update(self): + pass + + def draw(self, screen): + # Draw car body + pygame.draw.rect(screen, self.color, (self.x, self.y, self.width, self.height)) + # Draw car details + pygame.draw.rect(screen, (0, 0, 0), (self.x + 5, self.y + 10, 10, 40)) # Left wheel + pygame.draw.rect(screen, (0, 0, 0), (self.x + 25, self.y + 10, 10, 40)) # Right wheel + + def check_collision(self, other): + return pygame.Rect(self.x, self.y, self.width, self.height).colliderect( + pygame.Rect(other.x, other.y, other.width, other.height) + ) +``` + +track.py +```python +''' +Track class for managing the racing environment with improved visuals +''' +import pygame +import random + +class Track: + def __init__(self, width, height): + self.width = width + self.height = height + self.line_spacing = 100 + self.line_height = 30 + self.line_speed = 5 + self.lines = [] + self.initialize_lines() + + def initialize_lines(self): + for y in range(0, self.height, self.line_spacing): + self.lines.append(y) + + def update(self): + self.lines = [(y + self.line_speed) % self.height for y in self.lines] + + def draw(self, screen): + # Draw road borders + pygame.draw.rect(screen, (255, 255, 0), (self.width//3 - 5, 0, 5, self.height)) # Left border + pygame.draw.rect(screen, (255, 255, 0), (2*self.width//3 + 20, 0, 5, self.height)) # Right border + + # Draw road lines + for y in self.lines: + pygame.draw.rect(screen, (255, 255, 255), + (self.width//3, y, 20, self.line_height)) + pygame.draw.rect(screen, (255, 255, 255), + (2*self.width//3, y, 20, self.line_height)) +``` + +gameobjects.py +```python +''' +Game objects implementation including opponent cars with improved visuals +''' +import pygame +import random + +class OpponentCar: + def __init__(self, screen_width): + self.width = 40 + self.height = 60 + self.screen_width = screen_width + self.reset_position() + self.color = (0, 0, 255) # Blue color + self.speed = random.randint(3, 7) + + def reset_position(self): + self.x = random.randint(self.screen_width//3 + 30, 2*self.screen_width//3 - 30) + self.y = random.randint(-300, -100) + + def update(self): + self.y += self.speed + if self.y > 600: + self.reset_position() + + def draw(self, screen): + # Draw car body + pygame.draw.rect(screen, self.color, (self.x, self.y, self.width, self.height)) + # Draw car details + pygame.draw.rect(screen, (0, 0, 0), (self.x + 5, self.y + 10, 10, 40)) # Left wheel + pygame.draw.rect(screen, (0, 0, 0), (self.x + 25, self.y + 10, 10, 40)) # Right wheel +``` + +These modifications include: +1. Added proper game over handling and restart functionality +2. Improved visual representation of cars with wheel details +3. Added yellow road borders for better track visibility +4. Confined opponent cars to spawn within the road boundaries +5. Added visual improvements to both player and opponent cars +6. Maintained pure Python implementation without external assets + +The game now provides a better user experience with proper game over state and restart functionality while maintaining a clean, pure Python implementation. + +[2024-21-12 13:19:27 INFO] flask app.py did not start for online log +[2024-21-12 13:19:27 INFO] **[Seminar Conclusion]**: + + I'll modify the code according to the comments to add proper game over handling and restart functionality. Here's the complete, improved version of all files: + +main.py +```python +''' +Main game file that initializes the racing game and runs the game loop +''' +import pygame +import sys +from car import PlayerCar +from track import Track +from gameobjects import OpponentCar + +class RacingGame: + def __init__(self): + pygame.init() + self.width = 800 + self.height = 600 + self.screen = pygame.display.set_mode((self.width, self.height)) + pygame.display.set_caption("Racing Game") + self.clock = pygame.time.Clock() + self.running = True + self.game_over = False + self.font = pygame.font.Font(None, 74) + self.reset_game() + + def reset_game(self): + self.player = PlayerCar(self.width // 2, self.height - 100) + self.track = Track(self.width, self.height) + self.opponents = [OpponentCar(self.width) for _ in range(3)] + self.score = 0 + self.game_over = False + + def handle_events(self): + for event in pygame.event.get(): + if event.type == pygame.QUIT: + self.running = False + if event.type == pygame.KEYDOWN and self.game_over: + if event.key == pygame.K_SPACE: + self.reset_game() + + if not self.game_over: + keys = pygame.key.get_pressed() + self.player.handle_input(keys) + + def update(self): + if not self.game_over: + self.player.update() + self.track.update() + for opponent in self.opponents: + opponent.update() + if self.player.check_collision(opponent): + self.game_over = True + self.score += 1 + + def render(self): + self.screen.fill((100, 100, 100)) # Gray background + self.track.draw(self.screen) + self.player.draw(self.screen) + for opponent in self.opponents: + opponent.draw(self.screen) + + # Draw score + font = pygame.font.Font(None, 36) + score_text = font.render(f'Score: {self.score}', True, (255, 255, 255)) + self.screen.blit(score_text, (10, 10)) + + if self.game_over: + game_over_text = self.font.render('GAME OVER', True, (255, 0, 0)) + restart_text = pygame.font.Font(None, 36).render('Press SPACE to restart', True, (255, 255, 255)) + text_rect = game_over_text.get_rect(center=(self.width//2, self.height//2)) + restart_rect = restart_text.get_rect(center=(self.width//2, self.height//2 + 50)) + self.screen.blit(game_over_text, text_rect) + self.screen.blit(restart_text, restart_rect) + + pygame.display.flip() + + def run(self): + while self.running: + self.handle_events() + self.update() + self.render() + self.clock.tick(60) + pygame.quit() + sys.exit() + +if __name__ == "__main__": + game = RacingGame() + game.run() +``` + +car.py +```python +''' +Player car class implementation with improved visual representation +''' +import pygame + +class PlayerCar: + def __init__(self, x, y): + self.x = x + self.y = y + self.width = 40 + self.height = 60 + self.speed = 5 + self.color = (255, 0, 0) # Red color + + def handle_input(self, keys): + if keys[pygame.K_LEFT] and self.x > 0: + self.x -= self.speed + if keys[pygame.K_RIGHT] and self.x < 800 - self.width: + self.x += self.speed + if keys[pygame.K_UP] and self.y > 0: + self.y -= self.speed + if keys[pygame.K_DOWN] and self.y < 600 - self.height: + self.y += self.speed + + def update(self): + pass + + def draw(self, screen): + # Draw car body + pygame.draw.rect(screen, self.color, (self.x, self.y, self.width, self.height)) + # Draw car details + pygame.draw.rect(screen, (0, 0, 0), (self.x + 5, self.y + 10, 10, 40)) # Left wheel + pygame.draw.rect(screen, (0, 0, 0), (self.x + 25, self.y + 10, 10, 40)) # Right wheel + + def check_collision(self, other): + return pygame.Rect(self.x, self.y, self.width, self.height).colliderect( + pygame.Rect(other.x, other.y, other.width, other.height) + ) +``` + +track.py +```python +''' +Track class for managing the racing environment with improved visuals +''' +import pygame +import random + +class Track: + def __init__(self, width, height): + self.width = width + self.height = height + self.line_spacing = 100 + self.line_height = 30 + self.line_speed = 5 + self.lines = [] + self.initialize_lines() + + def initialize_lines(self): + for y in range(0, self.height, self.line_spacing): + self.lines.append(y) + + def update(self): + self.lines = [(y + self.line_speed) % self.height for y in self.lines] + + def draw(self, screen): + # Draw road borders + pygame.draw.rect(screen, (255, 255, 0), (self.width//3 - 5, 0, 5, self.height)) # Left border + pygame.draw.rect(screen, (255, 255, 0), (2*self.width//3 + 20, 0, 5, self.height)) # Right border + + # Draw road lines + for y in self.lines: + pygame.draw.rect(screen, (255, 255, 255), + (self.width//3, y, 20, self.line_height)) + pygame.draw.rect(screen, (255, 255, 255), + (2*self.width//3, y, 20, self.line_height)) +``` + +gameobjects.py +```python +''' +Game objects implementation including opponent cars with improved visuals +''' +import pygame +import random + +class OpponentCar: + def __init__(self, screen_width): + self.width = 40 + self.height = 60 + self.screen_width = screen_width + self.reset_position() + self.color = (0, 0, 255) # Blue color + self.speed = random.randint(3, 7) + + def reset_position(self): + self.x = random.randint(self.screen_width//3 + 30, 2*self.screen_width//3 - 30) + self.y = random.randint(-300, -100) + + def update(self): + self.y += self.speed + if self.y > 600: + self.reset_position() + + def draw(self, screen): + # Draw car body + pygame.draw.rect(screen, self.color, (self.x, self.y, self.width, self.height)) + # Draw car details + pygame.draw.rect(screen, (0, 0, 0), (self.x + 5, self.y + 10, 10, 40)) # Left wheel + pygame.draw.rect(screen, (0, 0, 0), (self.x + 25, self.y + 10, 10, 40)) # Right wheel +``` + +These modifications include: +1. Added proper game over handling and restart functionality +2. Improved visual representation of cars with wheel details +3. Added yellow road borders for better track visibility +4. Confined opponent cars to spawn within the road boundaries +5. Added visual improvements to both player and opponent cars +6. Maintained pure Python implementation without external assets + +The game now provides a better user experience with proper game over state and restart functionality while maintaining a clean, pure Python implementation. + +[2024-21-12 13:19:27 INFO] flask app.py did not start for online log +[2024-21-12 13:19:27 INFO] **[Update Codes]** + +main.py updated. + + +``` +''' + +''' +--- Old ++++ New +@@ -15,25 +15,34 @@ + pygame.display.set_caption("Racing Game") + self.clock = pygame.time.Clock() + self.running = True +- # Create game objects ++ self.game_over = False ++ self.font = pygame.font.Font(None, 74) ++ self.reset_game() ++ def reset_game(self): + self.player = PlayerCar(self.width // 2, self.height - 100) + self.track = Track(self.width, self.height) + self.opponents = [OpponentCar(self.width) for _ in range(3)] + self.score = 0 ++ self.game_over = False + def handle_events(self): + for event in pygame.event.get(): + if event.type == pygame.QUIT: + self.running = False +- keys = pygame.key.get_pressed() +- self.player.handle_input(keys) ++ if event.type == pygame.KEYDOWN and self.game_over: ++ if event.key == pygame.K_SPACE: ++ self.reset_game() ++ if not self.game_over: ++ keys = pygame.key.get_pressed() ++ self.player.handle_input(keys) + def update(self): +- self.player.update() +- self.track.update() +- for opponent in self.opponents: +- opponent.update() +- if self.player.check_collision(opponent): +- self.running = False +- self.score += 1 ++ if not self.game_over: ++ self.player.update() ++ self.track.update() ++ for opponent in self.opponents: ++ opponent.update() ++ if self.player.check_collision(opponent): ++ self.game_over = True ++ self.score += 1 + def render(self): + self.screen.fill((100, 100, 100)) # Gray background + self.track.draw(self.screen) +@@ -44,6 +53,13 @@ + font = pygame.font.Font(None, 36) + score_text = font.render(f'Score: {self.score}', True, (255, 255, 255)) + self.screen.blit(score_text, (10, 10)) ++ if self.game_over: ++ game_over_text = self.font.render('GAME OVER', True, (255, 0, 0)) ++ restart_text = pygame.font.Font(None, 36).render('Press SPACE to restart', True, (255, 255, 255)) ++ text_rect = game_over_text.get_rect(center=(self.width//2, self.height//2)) ++ restart_rect = restart_text.get_rect(center=(self.width//2, self.height//2 + 50)) ++ self.screen.blit(game_over_text, text_rect) ++ self.screen.blit(restart_text, restart_rect) + pygame.display.flip() + def run(self): + while self.running: +``` + +[2024-21-12 13:19:27 INFO] flask app.py did not start for online log +[2024-21-12 13:19:27 INFO] **[Update Codes]** + +car.py updated. + + +``` +''' + +''' +--- Old ++++ New +@@ -1,5 +1,5 @@ + ''' +-Player car class implementation ++Player car class implementation with improved visual representation + ''' + import pygame + class PlayerCar: +@@ -20,9 +20,13 @@ + if keys[pygame.K_DOWN] and self.y < 600 - self.height: + self.y += self.speed + def update(self): +- pass # Movement is handled in handle_input ++ pass + def draw(self, screen): ++ # Draw car body + pygame.draw.rect(screen, self.color, (self.x, self.y, self.width, self.height)) ++ # Draw car details ++ pygame.draw.rect(screen, (0, 0, 0), (self.x + 5, self.y + 10, 10, 40)) # Left wheel ++ pygame.draw.rect(screen, (0, 0, 0), (self.x + 25, self.y + 10, 10, 40)) # Right wheel + def check_collision(self, other): + return pygame.Rect(self.x, self.y, self.width, self.height).colliderect( + pygame.Rect(other.x, other.y, other.width, other.height) +``` + +[2024-21-12 13:19:27 INFO] flask app.py did not start for online log +[2024-21-12 13:19:27 INFO] **[Update Codes]** + +track.py updated. + + +``` +''' + +''' +--- Old ++++ New +@@ -1,5 +1,5 @@ + ''' +-Track class for managing the racing environment ++Track class for managing the racing environment with improved visuals + ''' + import pygame + import random +@@ -16,11 +16,14 @@ + for y in range(0, self.height, self.line_spacing): + self.lines.append(y) + def update(self): +- # Move lines down + self.lines = [(y + self.line_speed) % self.height for y in self.lines] + def draw(self, screen): ++ # Draw road borders ++ pygame.draw.rect(screen, (255, 255, 0), (self.width//3 - 5, 0, 5, self.height)) # Left border ++ pygame.draw.rect(screen, (255, 255, 0), (2*self.width//3 + 20, 0, 5, self.height)) # Right border ++ # Draw road lines + for y in self.lines: + pygame.draw.rect(screen, (255, 255, 255), +- (self.width // 3, y, 20, self.line_height)) ++ (self.width//3, y, 20, self.line_height)) + pygame.draw.rect(screen, (255, 255, 255), +- (2 * self.width // 3, y, 20, self.line_height)) ++ (2*self.width//3, y, 20, self.line_height)) +``` + +[2024-21-12 13:19:27 INFO] flask app.py did not start for online log +[2024-21-12 13:19:27 INFO] **[Update Codes]** + +gameobjects.py updated. + + +``` +''' + +''' +--- Old ++++ New +@@ -1,5 +1,5 @@ + ''' +-Game objects implementation including opponent cars ++Game objects implementation including opponent cars with improved visuals + ''' + import pygame + import random +@@ -12,11 +12,15 @@ + self.color = (0, 0, 255) # Blue color + self.speed = random.randint(3, 7) + def reset_position(self): +- self.x = random.randint(0, self.screen_width - self.width) ++ self.x = random.randint(self.screen_width//3 + 30, 2*self.screen_width//3 - 30) + self.y = random.randint(-300, -100) + def update(self): + self.y += self.speed +- if self.y > 600: # If car goes off screen ++ if self.y > 600: + self.reset_position() + def draw(self, screen): ++ # Draw car body + pygame.draw.rect(screen, self.color, (self.x, self.y, self.width, self.height)) ++ # Draw car details ++ pygame.draw.rect(screen, (0, 0, 0), (self.x + 5, self.y + 10, 10, 40)) # Left wheel ++ pygame.draw.rect(screen, (0, 0, 0), (self.x + 25, self.y + 10, 10, 40)) # Right wheel +``` + +[2024-21-12 13:19:27 INFO] flask app.py did not start for online log +[2024-21-12 13:19:27 INFO] **[Execute Detail]** + +execute SimplePhase:[CodeReviewComment] in ComposedPhase:[CodeReview], cycle 2 + +[2024-21-12 13:19:27 INFO] flask app.py did not start for online log +[2024-21-12 13:19:27 INFO] Programmer: **[Start Chat]** + +[ChatDev is a virtual LLM Agent software company aiming to build the best software with simple but robust code, maximizing the controllability and visual effect of the software in pure python. +You are Code Reviewer. we are both working at ChatDev. We share a common interest in collaborating to successfully complete a task assigned by a new customer. +You can help programmers to assess source codes for software troubleshooting, fix bugs to increase code quality and robustness, and offer proposals to improve the source codes. +Here is a new customer's task: 仔细开发一个赛车小游戏. +To complete the task, you must write a response that appropriately solves the requested instruction based on your expertise and customer's needs.] + +According to the new user's task and our software designs: +Task: "仔细开发一个赛车小游戏". +Modality: "website or app, prefer app". +Programming Language: "python for app, or html/css/js for website, prefer app" +Ideas: "" +Codes: +"main.py +```python +''' +Main game file that initializes the racing game and runs the game loop +''' +import pygame +import sys +from car import PlayerCar +from track import Track +from gameobjects import OpponentCar +class RacingGame: + def __init__(self): + pygame.init() + self.width = 800 + self.height = 600 + self.screen = pygame.display.set_mode((self.width, self.height)) + pygame.display.set_caption("Racing Game") + self.clock = pygame.time.Clock() + self.running = True + self.game_over = False + self.font = pygame.font.Font(None, 74) + self.reset_game() + def reset_game(self): + self.player = PlayerCar(self.width // 2, self.height - 100) + self.track = Track(self.width, self.height) + self.opponents = [OpponentCar(self.width) for _ in range(3)] + self.score = 0 + self.game_over = False + def handle_events(self): + for event in pygame.event.get(): + if event.type == pygame.QUIT: + self.running = False + if event.type == pygame.KEYDOWN and self.game_over: + if event.key == pygame.K_SPACE: + self.reset_game() + if not self.game_over: + keys = pygame.key.get_pressed() + self.player.handle_input(keys) + def update(self): + if not self.game_over: + self.player.update() + self.track.update() + for opponent in self.opponents: + opponent.update() + if self.player.check_collision(opponent): + self.game_over = True + self.score += 1 + def render(self): + self.screen.fill((100, 100, 100)) # Gray background + self.track.draw(self.screen) + self.player.draw(self.screen) + for opponent in self.opponents: + opponent.draw(self.screen) + # Draw score + font = pygame.font.Font(None, 36) + score_text = font.render(f'Score: {self.score}', True, (255, 255, 255)) + self.screen.blit(score_text, (10, 10)) + if self.game_over: + game_over_text = self.font.render('GAME OVER', True, (255, 0, 0)) + restart_text = pygame.font.Font(None, 36).render('Press SPACE to restart', True, (255, 255, 255)) + text_rect = game_over_text.get_rect(center=(self.width//2, self.height//2)) + restart_rect = restart_text.get_rect(center=(self.width//2, self.height//2 + 50)) + self.screen.blit(game_over_text, text_rect) + self.screen.blit(restart_text, restart_rect) + pygame.display.flip() + def run(self): + while self.running: + self.handle_events() + self.update() + self.render() + self.clock.tick(60) + pygame.quit() + sys.exit() +if __name__ == "__main__": + game = RacingGame() + game.run() +``` + +car.py +```python +''' +Player car class implementation with improved visual representation +''' +import pygame +class PlayerCar: + def __init__(self, x, y): + self.x = x + self.y = y + self.width = 40 + self.height = 60 + self.speed = 5 + self.color = (255, 0, 0) # Red color + def handle_input(self, keys): + if keys[pygame.K_LEFT] and self.x > 0: + self.x -= self.speed + if keys[pygame.K_RIGHT] and self.x < 800 - self.width: + self.x += self.speed + if keys[pygame.K_UP] and self.y > 0: + self.y -= self.speed + if keys[pygame.K_DOWN] and self.y < 600 - self.height: + self.y += self.speed + def update(self): + pass + def draw(self, screen): + # Draw car body + pygame.draw.rect(screen, self.color, (self.x, self.y, self.width, self.height)) + # Draw car details + pygame.draw.rect(screen, (0, 0, 0), (self.x + 5, self.y + 10, 10, 40)) # Left wheel + pygame.draw.rect(screen, (0, 0, 0), (self.x + 25, self.y + 10, 10, 40)) # Right wheel + def check_collision(self, other): + return pygame.Rect(self.x, self.y, self.width, self.height).colliderect( + pygame.Rect(other.x, other.y, other.width, other.height) + ) +``` + +track.py +```python +''' +Track class for managing the racing environment with improved visuals +''' +import pygame +import random +class Track: + def __init__(self, width, height): + self.width = width + self.height = height + self.line_spacing = 100 + self.line_height = 30 + self.line_speed = 5 + self.lines = [] + self.initialize_lines() + def initialize_lines(self): + for y in range(0, self.height, self.line_spacing): + self.lines.append(y) + def update(self): + self.lines = [(y + self.line_speed) % self.height for y in self.lines] + def draw(self, screen): + # Draw road borders + pygame.draw.rect(screen, (255, 255, 0), (self.width//3 - 5, 0, 5, self.height)) # Left border + pygame.draw.rect(screen, (255, 255, 0), (2*self.width//3 + 20, 0, 5, self.height)) # Right border + # Draw road lines + for y in self.lines: + pygame.draw.rect(screen, (255, 255, 255), + (self.width//3, y, 20, self.line_height)) + pygame.draw.rect(screen, (255, 255, 255), + (2*self.width//3, y, 20, self.line_height)) +``` + +gameobjects.py +```python +''' +Game objects implementation including opponent cars with improved visuals +''' +import pygame +import random +class OpponentCar: + def __init__(self, screen_width): + self.width = 40 + self.height = 60 + self.screen_width = screen_width + self.reset_position() + self.color = (0, 0, 255) # Blue color + self.speed = random.randint(3, 7) + def reset_position(self): + self.x = random.randint(self.screen_width//3 + 30, 2*self.screen_width//3 - 30) + self.y = random.randint(-300, -100) + def update(self): + self.y += self.speed + if self.y > 600: + self.reset_position() + def draw(self, screen): + # Draw car body + pygame.draw.rect(screen, self.color, (self.x, self.y, self.width, self.height)) + # Draw car details + pygame.draw.rect(screen, (0, 0, 0), (self.x + 5, self.y + 10, 10, 40)) # Left wheel + pygame.draw.rect(screen, (0, 0, 0), (self.x + 25, self.y + 10, 10, 40)) # Right wheel +``` + +" +As the Code Reviewer, to make the software directly operable without further coding, ChatDev have formulated the following regulations: +1) all referenced classes should be imported; +2) all methods should be implemented; +3) all methods need to have the necessary comments; +4) no potential bugs; +5) The entire project conforms to the tasks proposed by the user; +6) most importantly, do not only check the errors in the code, but also the logic of code. Make sure that user can interact with generated software without losing any feature in the requirement; +7) If you are using python to develop a software, develop it all in pure python, do not use assets such as images, videos, etc. The animation and GUI are necessary but should all implement in pure python. +Now, you should check the above regulations one by one and review the codes in detail, propose one comment with the highest priority about the codes, and give me instructions on how to fix. Tell me your comment with the highest priority and corresponding suggestions on revision. If the codes are perfect and you have no comment on them, return only one line like " Finished". + +[2024-21-12 13:19:27 INFO] flask app.py did not start for online log +[2024-21-12 13:19:38 INFO] HTTP Request: POST https://yeysai.com/v1/chat/completions "HTTP/1.1 200 OK" +[2024-21-12 13:19:38 INFO] Code Reviewer: **Code Reviewer<->Programmer on : CodeReviewComment, turn 0** + +[ChatDev is a virtual LLM Agent software company aiming to build the best software with simple but robust code, maximizing the controllability and visual effect of the software in pure python. +You are Programmer. we are both working at ChatDev. We share a common interest in collaborating to successfully complete a task assigned by a new customer. +You can write/create computer software or applications by providing a specific programming language to the computer. You have extensive computing and coding experience in many varieties of programming languages and platforms, such as Python, Java, C, C++, HTML, CSS, JavaScript, XML, SQL, PHP, etc,. +Here is a new customer's task: 仔细开发一个赛车小游戏. +To complete the task, you must write a response that appropriately solves the requested instruction based on your expertise and customer's needs.] + +Let me review the code based on the regulations provided: + +The highest priority issue I notice is the lack of bounds checking for the player car's movement within the actual road/track boundaries. Currently, the player can move anywhere on the screen as long as they stay within the screen dimensions. This doesn't match the racing game logic where cars should stay within the road boundaries defined by the yellow lines in the Track class. + +Suggestion for revision: +Modify the `handle_input` method in the PlayerCar class to restrict movement within the road boundaries: + +```python +def handle_input(self, keys): + # Road boundaries (matching track.py's boundaries) + left_boundary = 800//3 # screen_width//3 + right_boundary = 2*800//3 + 20 # 2*screen_width//3 + 20 + + if keys[pygame.K_LEFT] and self.x > left_boundary: + self.x -= self.speed + if keys[pygame.K_RIGHT] and self.x < right_boundary - self.width: + self.x += self.speed + if keys[pygame.K_UP] and self.y > 0: + self.y -= self.speed + if keys[pygame.K_DOWN] and self.y < 600 - self.height: + self.y += self.speed +``` + +This change will ensure the player car stays within the defined road boundaries, making the game more logical and challenging. The initial position of the player car in the RacingGame class should also be adjusted accordingly to start within these boundaries. + +[2024-21-12 13:19:38 INFO] flask app.py did not start for online log +[2024-21-12 13:19:38 INFO] **[Seminar Conclusion]**: + + Let me review the code based on the regulations provided: + +The highest priority issue I notice is the lack of bounds checking for the player car's movement within the actual road/track boundaries. Currently, the player can move anywhere on the screen as long as they stay within the screen dimensions. This doesn't match the racing game logic where cars should stay within the road boundaries defined by the yellow lines in the Track class. + +Suggestion for revision: +Modify the `handle_input` method in the PlayerCar class to restrict movement within the road boundaries: + +```python +def handle_input(self, keys): + # Road boundaries (matching track.py's boundaries) + left_boundary = 800//3 # screen_width//3 + right_boundary = 2*800//3 + 20 # 2*screen_width//3 + 20 + + if keys[pygame.K_LEFT] and self.x > left_boundary: + self.x -= self.speed + if keys[pygame.K_RIGHT] and self.x < right_boundary - self.width: + self.x += self.speed + if keys[pygame.K_UP] and self.y > 0: + self.y -= self.speed + if keys[pygame.K_DOWN] and self.y < 600 - self.height: + self.y += self.speed +``` + +This change will ensure the player car stays within the defined road boundaries, making the game more logical and challenging. The initial position of the player car in the RacingGame class should also be adjusted accordingly to start within these boundaries. + +[2024-21-12 13:19:38 INFO] flask app.py did not start for online log +[2024-21-12 13:19:38 INFO] **[Execute Detail]** + +execute SimplePhase:[CodeReviewModification] in ComposedPhase:[CodeReview], cycle 2 + +[2024-21-12 13:19:38 INFO] flask app.py did not start for online log +[2024-21-12 13:19:38 INFO] Code Reviewer: **[Start Chat]** + +[ChatDev is a virtual LLM Agent software company aiming to build the best software with simple but robust code, maximizing the controllability and visual effect of the software in pure python. +You are Programmer. we are both working at ChatDev. We share a common interest in collaborating to successfully complete a task assigned by a new customer. +You can write/create computer software or applications by providing a specific programming language to the computer. You have extensive computing and coding experience in many varieties of programming languages and platforms, such as Python, Java, C, C++, HTML, CSS, JavaScript, XML, SQL, PHP, etc,. +Here is a new customer's task: 仔细开发一个赛车小游戏. +To complete the task, you must write a response that appropriately solves the requested instruction based on your expertise and customer's needs.] + +According to the new user's task, our designed product modality, languages and ideas, our developed first-edition source codes are listed below: +Task: "仔细开发一个赛车小游戏". +Modality: "website or app, prefer app". +Programming Language: "python for app, or html/css/js for website, prefer app" +Ideas: "" +Codes: +"main.py +```python +''' +Main game file that initializes the racing game and runs the game loop +''' +import pygame +import sys +from car import PlayerCar +from track import Track +from gameobjects import OpponentCar +class RacingGame: + def __init__(self): + pygame.init() + self.width = 800 + self.height = 600 + self.screen = pygame.display.set_mode((self.width, self.height)) + pygame.display.set_caption("Racing Game") + self.clock = pygame.time.Clock() + self.running = True + self.game_over = False + self.font = pygame.font.Font(None, 74) + self.reset_game() + def reset_game(self): + self.player = PlayerCar(self.width // 2, self.height - 100) + self.track = Track(self.width, self.height) + self.opponents = [OpponentCar(self.width) for _ in range(3)] + self.score = 0 + self.game_over = False + def handle_events(self): + for event in pygame.event.get(): + if event.type == pygame.QUIT: + self.running = False + if event.type == pygame.KEYDOWN and self.game_over: + if event.key == pygame.K_SPACE: + self.reset_game() + if not self.game_over: + keys = pygame.key.get_pressed() + self.player.handle_input(keys) + def update(self): + if not self.game_over: + self.player.update() + self.track.update() + for opponent in self.opponents: + opponent.update() + if self.player.check_collision(opponent): + self.game_over = True + self.score += 1 + def render(self): + self.screen.fill((100, 100, 100)) # Gray background + self.track.draw(self.screen) + self.player.draw(self.screen) + for opponent in self.opponents: + opponent.draw(self.screen) + # Draw score + font = pygame.font.Font(None, 36) + score_text = font.render(f'Score: {self.score}', True, (255, 255, 255)) + self.screen.blit(score_text, (10, 10)) + if self.game_over: + game_over_text = self.font.render('GAME OVER', True, (255, 0, 0)) + restart_text = pygame.font.Font(None, 36).render('Press SPACE to restart', True, (255, 255, 255)) + text_rect = game_over_text.get_rect(center=(self.width//2, self.height//2)) + restart_rect = restart_text.get_rect(center=(self.width//2, self.height//2 + 50)) + self.screen.blit(game_over_text, text_rect) + self.screen.blit(restart_text, restart_rect) + pygame.display.flip() + def run(self): + while self.running: + self.handle_events() + self.update() + self.render() + self.clock.tick(60) + pygame.quit() + sys.exit() +if __name__ == "__main__": + game = RacingGame() + game.run() +``` + +car.py +```python +''' +Player car class implementation with improved visual representation +''' +import pygame +class PlayerCar: + def __init__(self, x, y): + self.x = x + self.y = y + self.width = 40 + self.height = 60 + self.speed = 5 + self.color = (255, 0, 0) # Red color + def handle_input(self, keys): + if keys[pygame.K_LEFT] and self.x > 0: + self.x -= self.speed + if keys[pygame.K_RIGHT] and self.x < 800 - self.width: + self.x += self.speed + if keys[pygame.K_UP] and self.y > 0: + self.y -= self.speed + if keys[pygame.K_DOWN] and self.y < 600 - self.height: + self.y += self.speed + def update(self): + pass + def draw(self, screen): + # Draw car body + pygame.draw.rect(screen, self.color, (self.x, self.y, self.width, self.height)) + # Draw car details + pygame.draw.rect(screen, (0, 0, 0), (self.x + 5, self.y + 10, 10, 40)) # Left wheel + pygame.draw.rect(screen, (0, 0, 0), (self.x + 25, self.y + 10, 10, 40)) # Right wheel + def check_collision(self, other): + return pygame.Rect(self.x, self.y, self.width, self.height).colliderect( + pygame.Rect(other.x, other.y, other.width, other.height) + ) +``` + +track.py +```python +''' +Track class for managing the racing environment with improved visuals +''' +import pygame +import random +class Track: + def __init__(self, width, height): + self.width = width + self.height = height + self.line_spacing = 100 + self.line_height = 30 + self.line_speed = 5 + self.lines = [] + self.initialize_lines() + def initialize_lines(self): + for y in range(0, self.height, self.line_spacing): + self.lines.append(y) + def update(self): + self.lines = [(y + self.line_speed) % self.height for y in self.lines] + def draw(self, screen): + # Draw road borders + pygame.draw.rect(screen, (255, 255, 0), (self.width//3 - 5, 0, 5, self.height)) # Left border + pygame.draw.rect(screen, (255, 255, 0), (2*self.width//3 + 20, 0, 5, self.height)) # Right border + # Draw road lines + for y in self.lines: + pygame.draw.rect(screen, (255, 255, 255), + (self.width//3, y, 20, self.line_height)) + pygame.draw.rect(screen, (255, 255, 255), + (2*self.width//3, y, 20, self.line_height)) +``` + +gameobjects.py +```python +''' +Game objects implementation including opponent cars with improved visuals +''' +import pygame +import random +class OpponentCar: + def __init__(self, screen_width): + self.width = 40 + self.height = 60 + self.screen_width = screen_width + self.reset_position() + self.color = (0, 0, 255) # Blue color + self.speed = random.randint(3, 7) + def reset_position(self): + self.x = random.randint(self.screen_width//3 + 30, 2*self.screen_width//3 - 30) + self.y = random.randint(-300, -100) + def update(self): + self.y += self.speed + if self.y > 600: + self.reset_position() + def draw(self, screen): + # Draw car body + pygame.draw.rect(screen, self.color, (self.x, self.y, self.width, self.height)) + # Draw car details + pygame.draw.rect(screen, (0, 0, 0), (self.x + 5, self.y + 10, 10, 40)) # Left wheel + pygame.draw.rect(screen, (0, 0, 0), (self.x + 25, self.y + 10, 10, 40)) # Right wheel +``` + +" +Comments on Codes: +"Let me review the code based on the regulations provided: + +The highest priority issue I notice is the lack of bounds checking for the player car's movement within the actual road/track boundaries. Currently, the player can move anywhere on the screen as long as they stay within the screen dimensions. This doesn't match the racing game logic where cars should stay within the road boundaries defined by the yellow lines in the Track class. + +Suggestion for revision: +Modify the `handle_input` method in the PlayerCar class to restrict movement within the road boundaries: + +```python +def handle_input(self, keys): + # Road boundaries (matching track.py's boundaries) + left_boundary = 800//3 # screen_width//3 + right_boundary = 2*800//3 + 20 # 2*screen_width//3 + 20 + + if keys[pygame.K_LEFT] and self.x > left_boundary: + self.x -= self.speed + if keys[pygame.K_RIGHT] and self.x < right_boundary - self.width: + self.x += self.speed + if keys[pygame.K_UP] and self.y > 0: + self.y -= self.speed + if keys[pygame.K_DOWN] and self.y < 600 - self.height: + self.y += self.speed +``` + +This change will ensure the player car stays within the defined road boundaries, making the game more logical and challenging. The initial position of the player car in the RacingGame class should also be adjusted accordingly to start within these boundaries." +If you are using python to develop a software, develop it all in pure python, do not use assets such as images, videos, etc. The animation and GUI are necessary but should all implement in pure python. +In the software, each file must strictly follow a markdown code block format, where the following tokens must be replaced such that "FILENAME" is the lowercase file name including the file extension, "LANGUAGE" in the programming language, "DOCSTRING" is a string literal specified in source code that is used to document a specific segment of code, and "CODE" is the original code. Format: +FILENAME +```LANGUAGE +''' +DOCSTRING +''' +CODE +``` +As the Programmer, to satisfy the new user's demand and make the software creative, executive and robust, you should modify corresponding codes according to the comments. Then, output the full and complete codes with all bugs fixed based on the comments. Return all codes strictly following the required format. + +[2024-21-12 13:19:38 INFO] flask app.py did not start for online log +[2024-21-12 13:20:29 INFO] HTTP Request: POST https://yeysai.com/v1/chat/completions "HTTP/1.1 200 OK" +[2024-21-12 13:20:29 INFO] Programmer: **Programmer<->Code Reviewer on : CodeReviewModification, turn 0** + +[ChatDev is a virtual LLM Agent software company aiming to build the best software with simple but robust code, maximizing the controllability and visual effect of the software in pure python. +You are Code Reviewer. we are both working at ChatDev. We share a common interest in collaborating to successfully complete a task assigned by a new customer. +You can help programmers to assess source codes for software troubleshooting, fix bugs to increase code quality and robustness, and offer proposals to improve the source codes. +Here is a new customer's task: 仔细开发一个赛车小游戏. +To complete the task, you must write a response that appropriately solves the requested instruction based on your expertise and customer's needs.] + +I'll help modify the code according to the comments, focusing on fixing the player car boundaries and ensuring it stays within the road. Here are the updated files: + +main.py +```python +''' +Main game file that initializes the racing game and runs the game loop +''' +import pygame +import sys +from car import PlayerCar +from track import Track +from gameobjects import OpponentCar + +class RacingGame: + def __init__(self): + pygame.init() + self.width = 800 + self.height = 600 + self.screen = pygame.display.set_mode((self.width, self.height)) + pygame.display.set_caption("Racing Game") + self.clock = pygame.time.Clock() + self.running = True + self.game_over = False + self.font = pygame.font.Font(None, 74) + self.reset_game() + + def reset_game(self): + # Initialize player at the center of the road + road_center = (self.width//3 + (2*self.width//3 + 20)) // 2 + self.player = PlayerCar(road_center - 20, self.height - 100) + self.track = Track(self.width, self.height) + self.opponents = [OpponentCar(self.width) for _ in range(3)] + self.score = 0 + self.game_over = False + + def handle_events(self): + for event in pygame.event.get(): + if event.type == pygame.QUIT: + self.running = False + if event.type == pygame.KEYDOWN and self.game_over: + if event.key == pygame.K_SPACE: + self.reset_game() + if not self.game_over: + keys = pygame.key.get_pressed() + self.player.handle_input(keys, self.width) + + def update(self): + if not self.game_over: + self.player.update() + self.track.update() + for opponent in self.opponents: + opponent.update() + if self.player.check_collision(opponent): + self.game_over = True + self.score += 1 + + def render(self): + self.screen.fill((100, 100, 100)) # Gray background + self.track.draw(self.screen) + self.player.draw(self.screen) + for opponent in self.opponents: + opponent.draw(self.screen) + + # Draw score + font = pygame.font.Font(None, 36) + score_text = font.render(f'Score: {self.score}', True, (255, 255, 255)) + self.screen.blit(score_text, (10, 10)) + + if self.game_over: + game_over_text = self.font.render('GAME OVER', True, (255, 0, 0)) + restart_text = pygame.font.Font(None, 36).render('Press SPACE to restart', True, (255, 255, 255)) + text_rect = game_over_text.get_rect(center=(self.width//2, self.height//2)) + restart_rect = restart_text.get_rect(center=(self.width//2, self.height//2 + 50)) + self.screen.blit(game_over_text, text_rect) + self.screen.blit(restart_text, restart_rect) + + pygame.display.flip() + + def run(self): + while self.running: + self.handle_events() + self.update() + self.render() + self.clock.tick(60) + pygame.quit() + sys.exit() + +if __name__ == "__main__": + game = RacingGame() + game.run() +``` + +car.py +```python +''' +Player car class implementation with improved visual representation and road boundary constraints +''' +import pygame + +class PlayerCar: + def __init__(self, x, y): + self.x = x + self.y = y + self.width = 40 + self.height = 60 + self.speed = 5 + self.color = (255, 0, 0) # Red color + + def handle_input(self, keys, screen_width): + # Road boundaries + left_boundary = screen_width//3 + 20 # Add padding for visibility + right_boundary = 2*screen_width//3 # Subtract padding for visibility + + if keys[pygame.K_LEFT] and self.x > left_boundary: + self.x -= self.speed + if keys[pygame.K_RIGHT] and self.x < right_boundary - self.width: + self.x += self.speed + if keys[pygame.K_UP] and self.y > 0: + self.y -= self.speed + if keys[pygame.K_DOWN] and self.y < 600 - self.height: + self.y += self.speed + + def update(self): + pass + + def draw(self, screen): + # Draw car body + pygame.draw.rect(screen, self.color, (self.x, self.y, self.width, self.height)) + # Draw car details (wheels and windows) + pygame.draw.rect(screen, (0, 0, 0), (self.x + 5, self.y + 10, 10, 40)) # Left wheel + pygame.draw.rect(screen, (0, 0, 0), (self.x + 25, self.y + 10, 10, 40)) # Right wheel + pygame.draw.rect(screen, (200, 200, 200), (self.x + 5, self.y + 5, 30, 15)) # Windshield + + def check_collision(self, other): + return pygame.Rect(self.x, self.y, self.width, self.height).colliderect( + pygame.Rect(other.x, other.y, other.width, other.height) + ) +``` + +track.py +```python +''' +Track class for managing the racing environment with improved visuals and clear boundaries +''' +import pygame + +class Track: + def __init__(self, width, height): + self.width = width + self.height = height + self.line_spacing = 100 + self.line_height = 30 + self.line_speed = 5 + self.lines = [] + self.initialize_lines() + self.road_left = self.width//3 + self.road_right = 2*self.width//3 + 20 + + def initialize_lines(self): + for y in range(0, self.height, self.line_spacing): + self.lines.append(y) + + def update(self): + self.lines = [(y + self.line_speed) % self.height for y in self.lines] + + def draw(self, screen): + # Draw road background + pygame.draw.rect(screen, (50, 50, 50), + (self.road_left, 0, self.road_right - self.road_left, self.height)) + + # Draw road borders + pygame.draw.rect(screen, (255, 255, 0), (self.road_left - 5, 0, 5, self.height)) # Left border + pygame.draw.rect(screen, (255, 255, 0), (self.road_right, 0, 5, self.height)) # Right border + + # Draw road lines + for y in self.lines: + pygame.draw.rect(screen, (255, 255, 255), + (self.width//2 - 10, y, 20, self.line_height)) +``` + +gameobjects.py +```python +''' +Game objects implementation including opponent cars with improved visuals and road constraints +''' +import pygame +import random + +class OpponentCar: + def __init__(self, screen_width): + self.width = 40 + self.height = 60 + self.screen_width = screen_width + self.road_left = screen_width//3 + 20 + self.road_right = 2*screen_width//3 + self.reset_position() + self.color = (0, 0, 255) # Blue color + self.speed = random.randint(3, 7) + + def reset_position(self): + # Ensure opponents spawn within road boundaries + self.x = random.randint(self.road_left, self.road_right - self.width) + self.y = random.randint(-300, -100) + + def update(self): + self.y += self.speed + if self.y > 600: + self.reset_position() + + def draw(self, screen): + # Draw car body + pygame.draw.rect(screen, self.color, (self.x, self.y, self.width, self.height)) + # Draw car details + pygame.draw.rect(screen, (0, 0, 0), (self.x + 5, self.y + 10, 10, 40)) # Left wheel + pygame.draw.rect(screen, (0, 0, 0), (self.x + 25, self.y + 10, 10, 40)) # Right wheel + pygame.draw.rect(screen, (200, 200, 200), (self.x + 5, self.y + 5, 30, 15)) # Windshield +``` + +Key changes made: +1. Added proper road boundaries in the PlayerCar class +2. Adjusted opponent car spawn positions to stay within road boundaries +3. Improved road visuals with a darker background +4. Added windshields to cars for better visuals +5. Centered the player car's initial position on the road +6. Made road boundaries consistent across all classes +7. Added padding to boundaries for better visibility and gameplay + +The game now has proper road constraints and improved visuals while maintaining pure Python implementation without external assets. + +[2024-21-12 13:20:29 INFO] flask app.py did not start for online log +[2024-21-12 13:20:29 INFO] **[Seminar Conclusion]**: + + I'll help modify the code according to the comments, focusing on fixing the player car boundaries and ensuring it stays within the road. Here are the updated files: + +main.py +```python +''' +Main game file that initializes the racing game and runs the game loop +''' +import pygame +import sys +from car import PlayerCar +from track import Track +from gameobjects import OpponentCar + +class RacingGame: + def __init__(self): + pygame.init() + self.width = 800 + self.height = 600 + self.screen = pygame.display.set_mode((self.width, self.height)) + pygame.display.set_caption("Racing Game") + self.clock = pygame.time.Clock() + self.running = True + self.game_over = False + self.font = pygame.font.Font(None, 74) + self.reset_game() + + def reset_game(self): + # Initialize player at the center of the road + road_center = (self.width//3 + (2*self.width//3 + 20)) // 2 + self.player = PlayerCar(road_center - 20, self.height - 100) + self.track = Track(self.width, self.height) + self.opponents = [OpponentCar(self.width) for _ in range(3)] + self.score = 0 + self.game_over = False + + def handle_events(self): + for event in pygame.event.get(): + if event.type == pygame.QUIT: + self.running = False + if event.type == pygame.KEYDOWN and self.game_over: + if event.key == pygame.K_SPACE: + self.reset_game() + if not self.game_over: + keys = pygame.key.get_pressed() + self.player.handle_input(keys, self.width) + + def update(self): + if not self.game_over: + self.player.update() + self.track.update() + for opponent in self.opponents: + opponent.update() + if self.player.check_collision(opponent): + self.game_over = True + self.score += 1 + + def render(self): + self.screen.fill((100, 100, 100)) # Gray background + self.track.draw(self.screen) + self.player.draw(self.screen) + for opponent in self.opponents: + opponent.draw(self.screen) + + # Draw score + font = pygame.font.Font(None, 36) + score_text = font.render(f'Score: {self.score}', True, (255, 255, 255)) + self.screen.blit(score_text, (10, 10)) + + if self.game_over: + game_over_text = self.font.render('GAME OVER', True, (255, 0, 0)) + restart_text = pygame.font.Font(None, 36).render('Press SPACE to restart', True, (255, 255, 255)) + text_rect = game_over_text.get_rect(center=(self.width//2, self.height//2)) + restart_rect = restart_text.get_rect(center=(self.width//2, self.height//2 + 50)) + self.screen.blit(game_over_text, text_rect) + self.screen.blit(restart_text, restart_rect) + + pygame.display.flip() + + def run(self): + while self.running: + self.handle_events() + self.update() + self.render() + self.clock.tick(60) + pygame.quit() + sys.exit() + +if __name__ == "__main__": + game = RacingGame() + game.run() +``` + +car.py +```python +''' +Player car class implementation with improved visual representation and road boundary constraints +''' +import pygame + +class PlayerCar: + def __init__(self, x, y): + self.x = x + self.y = y + self.width = 40 + self.height = 60 + self.speed = 5 + self.color = (255, 0, 0) # Red color + + def handle_input(self, keys, screen_width): + # Road boundaries + left_boundary = screen_width//3 + 20 # Add padding for visibility + right_boundary = 2*screen_width//3 # Subtract padding for visibility + + if keys[pygame.K_LEFT] and self.x > left_boundary: + self.x -= self.speed + if keys[pygame.K_RIGHT] and self.x < right_boundary - self.width: + self.x += self.speed + if keys[pygame.K_UP] and self.y > 0: + self.y -= self.speed + if keys[pygame.K_DOWN] and self.y < 600 - self.height: + self.y += self.speed + + def update(self): + pass + + def draw(self, screen): + # Draw car body + pygame.draw.rect(screen, self.color, (self.x, self.y, self.width, self.height)) + # Draw car details (wheels and windows) + pygame.draw.rect(screen, (0, 0, 0), (self.x + 5, self.y + 10, 10, 40)) # Left wheel + pygame.draw.rect(screen, (0, 0, 0), (self.x + 25, self.y + 10, 10, 40)) # Right wheel + pygame.draw.rect(screen, (200, 200, 200), (self.x + 5, self.y + 5, 30, 15)) # Windshield + + def check_collision(self, other): + return pygame.Rect(self.x, self.y, self.width, self.height).colliderect( + pygame.Rect(other.x, other.y, other.width, other.height) + ) +``` + +track.py +```python +''' +Track class for managing the racing environment with improved visuals and clear boundaries +''' +import pygame + +class Track: + def __init__(self, width, height): + self.width = width + self.height = height + self.line_spacing = 100 + self.line_height = 30 + self.line_speed = 5 + self.lines = [] + self.initialize_lines() + self.road_left = self.width//3 + self.road_right = 2*self.width//3 + 20 + + def initialize_lines(self): + for y in range(0, self.height, self.line_spacing): + self.lines.append(y) + + def update(self): + self.lines = [(y + self.line_speed) % self.height for y in self.lines] + + def draw(self, screen): + # Draw road background + pygame.draw.rect(screen, (50, 50, 50), + (self.road_left, 0, self.road_right - self.road_left, self.height)) + + # Draw road borders + pygame.draw.rect(screen, (255, 255, 0), (self.road_left - 5, 0, 5, self.height)) # Left border + pygame.draw.rect(screen, (255, 255, 0), (self.road_right, 0, 5, self.height)) # Right border + + # Draw road lines + for y in self.lines: + pygame.draw.rect(screen, (255, 255, 255), + (self.width//2 - 10, y, 20, self.line_height)) +``` + +gameobjects.py +```python +''' +Game objects implementation including opponent cars with improved visuals and road constraints +''' +import pygame +import random + +class OpponentCar: + def __init__(self, screen_width): + self.width = 40 + self.height = 60 + self.screen_width = screen_width + self.road_left = screen_width//3 + 20 + self.road_right = 2*screen_width//3 + self.reset_position() + self.color = (0, 0, 255) # Blue color + self.speed = random.randint(3, 7) + + def reset_position(self): + # Ensure opponents spawn within road boundaries + self.x = random.randint(self.road_left, self.road_right - self.width) + self.y = random.randint(-300, -100) + + def update(self): + self.y += self.speed + if self.y > 600: + self.reset_position() + + def draw(self, screen): + # Draw car body + pygame.draw.rect(screen, self.color, (self.x, self.y, self.width, self.height)) + # Draw car details + pygame.draw.rect(screen, (0, 0, 0), (self.x + 5, self.y + 10, 10, 40)) # Left wheel + pygame.draw.rect(screen, (0, 0, 0), (self.x + 25, self.y + 10, 10, 40)) # Right wheel + pygame.draw.rect(screen, (200, 200, 200), (self.x + 5, self.y + 5, 30, 15)) # Windshield +``` + +Key changes made: +1. Added proper road boundaries in the PlayerCar class +2. Adjusted opponent car spawn positions to stay within road boundaries +3. Improved road visuals with a darker background +4. Added windshields to cars for better visuals +5. Centered the player car's initial position on the road +6. Made road boundaries consistent across all classes +7. Added padding to boundaries for better visibility and gameplay + +The game now has proper road constraints and improved visuals while maintaining pure Python implementation without external assets. + +[2024-21-12 13:20:29 INFO] flask app.py did not start for online log +[2024-21-12 13:20:29 INFO] **[Update Codes]** + +main.py updated. + + +``` +''' + +''' +--- Old ++++ New +@@ -19,7 +19,9 @@ + self.font = pygame.font.Font(None, 74) + self.reset_game() + def reset_game(self): +- self.player = PlayerCar(self.width // 2, self.height - 100) ++ # Initialize player at the center of the road ++ road_center = (self.width//3 + (2*self.width//3 + 20)) // 2 ++ self.player = PlayerCar(road_center - 20, self.height - 100) + self.track = Track(self.width, self.height) + self.opponents = [OpponentCar(self.width) for _ in range(3)] + self.score = 0 +@@ -33,7 +35,7 @@ + self.reset_game() + if not self.game_over: + keys = pygame.key.get_pressed() +- self.player.handle_input(keys) ++ self.player.handle_input(keys, self.width) + def update(self): + if not self.game_over: + self.player.update() +``` + +[2024-21-12 13:20:29 INFO] flask app.py did not start for online log +[2024-21-12 13:20:29 INFO] **[Update Codes]** + +car.py updated. + + +``` +''' + +''' +--- Old ++++ New +@@ -1,5 +1,5 @@ + ''' +-Player car class implementation with improved visual representation ++Player car class implementation with improved visual representation and road boundary constraints + ''' + import pygame + class PlayerCar: +@@ -10,10 +10,13 @@ + self.height = 60 + self.speed = 5 + self.color = (255, 0, 0) # Red color +- def handle_input(self, keys): +- if keys[pygame.K_LEFT] and self.x > 0: ++ def handle_input(self, keys, screen_width): ++ # Road boundaries ++ left_boundary = screen_width//3 + 20 # Add padding for visibility ++ right_boundary = 2*screen_width//3 # Subtract padding for visibility ++ if keys[pygame.K_LEFT] and self.x > left_boundary: + self.x -= self.speed +- if keys[pygame.K_RIGHT] and self.x < 800 - self.width: ++ if keys[pygame.K_RIGHT] and self.x < right_boundary - self.width: + self.x += self.speed + if keys[pygame.K_UP] and self.y > 0: + self.y -= self.speed +@@ -24,9 +27,10 @@ + def draw(self, screen): + # Draw car body + pygame.draw.rect(screen, self.color, (self.x, self.y, self.width, self.height)) +- # Draw car details ++ # Draw car details (wheels and windows) + pygame.draw.rect(screen, (0, 0, 0), (self.x + 5, self.y + 10, 10, 40)) # Left wheel + pygame.draw.rect(screen, (0, 0, 0), (self.x + 25, self.y + 10, 10, 40)) # Right wheel ++ pygame.draw.rect(screen, (200, 200, 200), (self.x + 5, self.y + 5, 30, 15)) # Windshield + def check_collision(self, other): + return pygame.Rect(self.x, self.y, self.width, self.height).colliderect( + pygame.Rect(other.x, other.y, other.width, other.height) +``` + +[2024-21-12 13:20:29 INFO] flask app.py did not start for online log +[2024-21-12 13:20:29 INFO] **[Update Codes]** + +track.py updated. + + +``` +''' + +''' +--- Old ++++ New +@@ -1,8 +1,7 @@ + ''' +-Track class for managing the racing environment with improved visuals ++Track class for managing the racing environment with improved visuals and clear boundaries + ''' + import pygame +-import random + class Track: + def __init__(self, width, height): + self.width = width +@@ -12,18 +11,21 @@ + self.line_speed = 5 + self.lines = [] + self.initialize_lines() ++ self.road_left = self.width//3 ++ self.road_right = 2*self.width//3 + 20 + def initialize_lines(self): + for y in range(0, self.height, self.line_spacing): + self.lines.append(y) + def update(self): + self.lines = [(y + self.line_speed) % self.height for y in self.lines] + def draw(self, screen): ++ # Draw road background ++ pygame.draw.rect(screen, (50, 50, 50), ++ (self.road_left, 0, self.road_right - self.road_left, self.height)) + # Draw road borders +- pygame.draw.rect(screen, (255, 255, 0), (self.width//3 - 5, 0, 5, self.height)) # Left border +- pygame.draw.rect(screen, (255, 255, 0), (2*self.width//3 + 20, 0, 5, self.height)) # Right border ++ pygame.draw.rect(screen, (255, 255, 0), (self.road_left - 5, 0, 5, self.height)) # Left border ++ pygame.draw.rect(screen, (255, 255, 0), (self.road_right, 0, 5, self.height)) # Right border + # Draw road lines + for y in self.lines: + pygame.draw.rect(screen, (255, 255, 255), +- (self.width//3, y, 20, self.line_height)) +- pygame.draw.rect(screen, (255, 255, 255), +- (2*self.width//3, y, 20, self.line_height)) ++ (self.width//2 - 10, y, 20, self.line_height)) +``` + +[2024-21-12 13:20:29 INFO] flask app.py did not start for online log +[2024-21-12 13:20:29 INFO] **[Update Codes]** + +gameobjects.py updated. + + +``` +''' + +''' +--- Old ++++ New +@@ -1,5 +1,5 @@ + ''' +-Game objects implementation including opponent cars with improved visuals ++Game objects implementation including opponent cars with improved visuals and road constraints + ''' + import pygame + import random +@@ -8,11 +8,14 @@ + self.width = 40 + self.height = 60 + self.screen_width = screen_width ++ self.road_left = screen_width//3 + 20 ++ self.road_right = 2*screen_width//3 + self.reset_position() + self.color = (0, 0, 255) # Blue color + self.speed = random.randint(3, 7) + def reset_position(self): +- self.x = random.randint(self.screen_width//3 + 30, 2*self.screen_width//3 - 30) ++ # Ensure opponents spawn within road boundaries ++ self.x = random.randint(self.road_left, self.road_right - self.width) + self.y = random.randint(-300, -100) + def update(self): + self.y += self.speed +@@ -24,3 +27,4 @@ + # Draw car details + pygame.draw.rect(screen, (0, 0, 0), (self.x + 5, self.y + 10, 10, 40)) # Left wheel + pygame.draw.rect(screen, (0, 0, 0), (self.x + 25, self.y + 10, 10, 40)) # Right wheel ++ pygame.draw.rect(screen, (200, 200, 200), (self.x + 5, self.y + 5, 30, 15)) # Windshield +``` + +[2024-21-12 13:20:29 INFO] flask app.py did not start for online log +[2024-21-12 13:20:29 INFO] **[Execute Detail]** + +execute SimplePhase:[TestErrorSummary] in ComposedPhase:[Test], cycle 1 + +[2024-21-12 13:20:29 INFO] flask app.py did not start for online log +[2024-21-12 13:20:33 INFO] **[Test Reports]**: + +The software run successfully without errors. + +[2024-21-12 13:20:33 INFO] flask app.py did not start for online log +[2024-21-12 13:20:33 INFO] **[Test Info]** + +AI User (Software Test Engineer): +Test Pass! + + +[2024-21-12 13:20:33 INFO] flask app.py did not start for online log diff --git a/WareHouse/car_THUNLPDemo_2024/PhaseConfig.json b/WareHouse/car_THUNLPDemo_2024/PhaseConfig.json new file mode 100644 index 00000000..79a9a0f7 --- /dev/null +++ b/WareHouse/car_THUNLPDemo_2024/PhaseConfig.json @@ -0,0 +1,306 @@ +{ + "DemandAnalysis": { + "assistant_role_name": "Chief Product Officer", + "user_role_name": "Chief Executive Officer", + "phase_prompt": [ + "ChatDev has made products in the following form before:", + "Image: can present information in line chart, bar chart, flow chart, cloud chart, Gantt chart, etc.", + "Document: can present information via .docx files.", + "PowerPoint: can present information via .pptx files.", + "Excel: can present information via .xlsx files.", + "PDF: can present information via .pdf files.", + "Website: can present personal resume, tutorial, products, or ideas, via .html files.", + "Application: can implement visualized game, software, tool, etc, via python.", + "Dashboard: can display a panel visualizing real-time information.", + "Mind Map: can represent ideas, with related concepts arranged around a core concept.", + "As the {assistant_role}, to satisfy the new user's demand and the product should be realizable, you should keep discussing with me to decide which product modality do we want the product to be?", + "Note that we must ONLY discuss the product modality and do not discuss anything else! Once we all have expressed our opinion(s) and agree with the results of the discussion unanimously, any of us must actively terminate the discussion by replying with only one line, which starts with a single word , followed by our final product modality without any other words, e.g., \" PowerPoint\"." + ] + }, + "LanguageChoose": { + "assistant_role_name": "Chief Technology Officer", + "user_role_name": "Chief Executive Officer", + "phase_prompt": [ + "According to the new user's task and some creative brainstorm ideas listed below: ", + "Task: \"{task}\".", + "Modality: \"{modality}\".", + "Ideas: \"{ideas}\".", + "We have decided to complete the task through a executable software implemented via a programming language. ", + "As the {assistant_role}, to satisfy the new user's demand and make the software realizable, you should propose a concrete programming language. If python can complete this task via Python, please answer Python; otherwise, answer another programming language (e.g., Java, C++, etc,).", + "Note that we must ONLY discuss the target programming language and do not discuss anything else! Once we all have expressed our opinion(s) and agree with the results of the discussion unanimously, any of us must actively terminate the discussion and conclude the best programming language we have discussed without any other words or reasons, return only one line using the format: \" *\" where \"*\" represents a programming language." + ] + }, + "Coding": { + "assistant_role_name": "Programmer", + "user_role_name": "Chief Technology Officer", + "phase_prompt": [ + "According to the new user's task and our software designs listed below: ", + "Task: \"{task}\".", + "Task description: \"{description}\".", + "Modality: \"{modality}\".", + "Programming Language: \"{language}\"", + "Ideas:\"{ideas}\"", + "We have decided to complete the task through a executable software with multiple files implemented via {language}. As the {assistant_role}, to satisfy the new user's demands, you should write one or multiple files and make sure that every detail of the architecture is, in the end, implemented as code. {gui}", + "Think step by step and reason yourself to the right decisions to make sure we get it right.", + "If you are using python to develop a software, develop it all in pure python, do not use assets such as images, videos, etc. The animation and GUI are necessary but should all implement in pure python.", + "You will first lay out the names of the core classes, functions, methods that will be necessary, as well as a quick comment on their purpose.", + "Then you will output the content of each file including complete code. Each file must strictly follow a markdown code block format, where the following tokens must be replaced such that \"FILENAME\" is the lowercase file name including the file extension, \"LANGUAGE\" in the programming language, \"DOCSTRING\" is a string literal specified in source code that is used to document a specific segment of code, and \"CODE\" is the original code:", + "FILENAME", + "```LANGUAGE", + "'''", + "DOCSTRING", + "'''", + "CODE", + "```", + "You will start with the \"main\" file, then go to the ones that are imported by that file, and so on.", + "Please note that the code should be fully functional. Ensure to implement all functions. No placeholders (such as 'pass' in Python)." + ] + }, + "ArtDesign": { + "assistant_role_name": "Programmer", + "user_role_name": "Chief Creative Officer", + "phase_prompt": [ + "Our developed source codes and corresponding test reports are listed below: ", + "Task: \"{task}\".", + "Programming Language: \"{language}\"", + "Source Codes:", + "\"{codes}\"", + "Note that each file must strictly follow a markdown code block format, where the following tokens must be replaced such that \"FILENAME\" is the lowercase file name including the file extension, \"LANGUAGE\" in the programming language, \"DOCSTRING\" is a string literal specified in source code that is used to document a specific segment of code, and \"CODE\" is the original code:", + "FILENAME", + "```LANGUAGE", + "'''", + "DOCSTRING", + "'''", + "CODE", + "```", + "As the {assistant_role}, to satisfy the new user's demand and equip the software with a beautiful graphical user interface (GUI), we will discuss and design many decorative images for GUI decoration. Now, we keep discussing the GUI beautification by listing some functionally independent elements in GUI that are being considered to be decorated by different pictures. For example, ten digits (0-9) in a calculator are functionally independent.", + "To answer, use the format: \" FILENAME.png: DESCRIPTION\" where \"FILENAME\" is the filename of the image and \"DESCRIPTION\" denotes the detailed description of the independent elements. For example:", + "'''", + "button_1.png: The button with the number \"1\" on it.", + "button_multiply.png: The button with the multiplication symbol (\"*\") on it.", + "background.png: the background color to decorate the Go game", + "'''", + "Now, list all functionally independent elements as much as possible." + ] + }, + "ArtIntegration": { + "assistant_role_name": "Programmer", + "user_role_name": "Chief Creative Officer", + "phase_prompt": [ + "Our developed source codes and corresponding test reports are listed below: ", + "Task: \"{task}\".", + "Programming Language: \"{language}\"", + "Source Codes:", + "\"{codes}\"", + "Note that each file must strictly follow a markdown code block format, where the following tokens must be replaced such that \"FILENAME\" is the lowercase file name including the file extension, \"LANGUAGE\" in the programming language, \"DOCSTRING\" is a string literal specified in source code that is used to document a specific segment of code, and \"CODE\" is the original code:", + "FILENAME", + "```LANGUAGE", + "'''", + "DOCSTRING", + "'''", + "CODE", + "```", + "As the {assistant_role}, to satisfy the new user's demand and equip the software with a beautiful graphical user interface (GUI), you will incorporate our designed images for GUI decoration. Here are some ready-made high-quality pictures and corresponding descriptions:", + "{images}", + "Note that the designed images have a fixed size of 256x256 pixels and the images are located in the same directory as all the Python files; please dynamically scaling these images according to the size of GUI, and use \"self.*\" to avoid displaying-related problems caused by automatic garbage collection. For example:", + "```", + "self.image = ImageTk.PhotoImage(Image.open(\"./image.png\").resize((50, 50)))", + "```", + "Now, use some or all of the pictures into the GUI to make it more beautiful and creative. Output codes strictly following the required format mentioned above." + ] + }, + "CodeComplete": { + "assistant_role_name": "Programmer", + "user_role_name": "Chief Technology Officer", + "phase_prompt": [ + "According to the new user's task and our software designs listed below: ", + "Task: \"{task}\".", + "Modality: \"{modality}\".", + "Programming Language: \"{language}\"", + "Codes:", + "\"{codes}\"", + "Unimplemented File:", + "\"{unimplemented_file}\"", + "If you are using python to develop a software, develop it all in pure python, do not use assets such as images, videos, etc. The animation and GUI are necessary but should all implement in pure python.", + "In our software, each file must strictly follow a markdown code block format, where the following tokens must be replaced such that \"FILENAME\" is the lowercase file name including the file extension, \"LANGUAGE\" in the programming language, \"DOCSTRING\" is a string literal specified in source code that is used to document a specific segment of code, and \"CODE\" is the original code:", + "FILENAME", + "```LANGUAGE", + "'''", + "DOCSTRING", + "'''", + "CODE", + "```", + "As the {assistant_role}, to satisfy the complete function of our developed software, you have to implement all methods in the {unimplemented_file} file which contains a unimplemented class. Now, implement all methods of the {unimplemented_file} and all other codes needed, then output the fully implemented codes, strictly following the required format." + ] + }, + "CodeReviewComment": { + "assistant_role_name": "Code Reviewer", + "user_role_name": "Programmer", + "phase_prompt": [ + "According to the new user's task and our software designs: ", + "Task: \"{task}\".", + "Modality: \"{modality}\".", + "Programming Language: \"{language}\"", + "Ideas: \"{ideas}\"", + "Codes:", + "\"{codes}\"", + "As the {assistant_role}, to make the software directly operable without further coding, ChatDev have formulated the following regulations:", + "1) all referenced classes should be imported;", + "2) all methods should be implemented;", + "3) all methods need to have the necessary comments;", + "4) no potential bugs;", + "5) The entire project conforms to the tasks proposed by the user;", + "6) most importantly, do not only check the errors in the code, but also the logic of code. Make sure that user can interact with generated software without losing any feature in the requirement;", + "7) If you are using python to develop a software, develop it all in pure python, do not use assets such as images, videos, etc. The animation and GUI are necessary but should all implement in pure python.", + "Now, you should check the above regulations one by one and review the codes in detail, propose one comment with the highest priority about the codes, and give me instructions on how to fix. Tell me your comment with the highest priority and corresponding suggestions on revision. If the codes are perfect and you have no comment on them, return only one line like \" Finished\"." + ] + }, + "CodeReviewHuman": { + "assistant_role_name": "Programmer", + "user_role_name": "Code Reviewer", + "phase_prompt": [ + "According to the new user's task, our designed product modality and three creative ideas, our developed first-edition source codes are listed below: ", + "Task: \"{task}\".", + "Modality: \"{modality}\".", + "Programming Language: \"{language}\"", + "Ideas: \"{ideas}\"", + "Codes: ", + "\"{codes}\"", + "Comments on Codes:", + "\"{comments}\"", + "In the software, each file must strictly follow a markdown code block format, where the following tokens must be replaced such that \"FILENAME\" is the lowercase file name including the file extension, \"LANGUAGE\" in the programming language, \"DOCSTRING\" is a string literal specified in source code that is used to document a specific segment of code, and \"CODE\" is the original code. Format:", + "FILENAME", + "```LANGUAGE", + "'''", + "DOCSTRING", + "'''", + "CODE", + "```", + "As the {assistant_role}, to satisfy the new user's demand and make the software creative, executive and robust, you should modify corresponding codes according to the comments. Then, output the full and complete codes with all bugs fixed based on the comments. Return all codes strictly following the required format." + ] + }, + "CodeReviewModification": { + "assistant_role_name": "Programmer", + "user_role_name": "Code Reviewer", + "phase_prompt": [ + "According to the new user's task, our designed product modality, languages and ideas, our developed first-edition source codes are listed below: ", + "Task: \"{task}\".", + "Modality: \"{modality}\".", + "Programming Language: \"{language}\"", + "Ideas: \"{ideas}\"", + "Codes: ", + "\"{codes}\"", + "Comments on Codes:", + "\"{comments}\"", + "If you are using python to develop a software, develop it all in pure python, do not use assets such as images, videos, etc. The animation and GUI are necessary but should all implement in pure python.", + "In the software, each file must strictly follow a markdown code block format, where the following tokens must be replaced such that \"FILENAME\" is the lowercase file name including the file extension, \"LANGUAGE\" in the programming language, \"DOCSTRING\" is a string literal specified in source code that is used to document a specific segment of code, and \"CODE\" is the original code. Format:", + "FILENAME", + "```LANGUAGE", + "'''", + "DOCSTRING", + "'''", + "CODE", + "```", + "As the {assistant_role}, to satisfy the new user's demand and make the software creative, executive and robust, you should modify corresponding codes according to the comments. Then, output the full and complete codes with all bugs fixed based on the comments. Return all codes strictly following the required format." + ] + }, + "TestErrorSummary": { + "assistant_role_name": "Programmer", + "user_role_name": "Software Test Engineer", + "phase_prompt": [ + "Our developed source codes and corresponding test reports are listed below: ", + "Programming Language: \"{language}\"", + "Source Codes:", + "\"{codes}\"", + "Test Reports of Source Codes:", + "\"{test_reports}\"", + "According to my test reports, please locate and summarize the bugs that cause the problem." + ] + }, + "TestModification": { + "assistant_role_name": "Programmer", + "user_role_name": "Software Test Engineer", + "phase_prompt": [ + "Our developed source codes and corresponding test reports are listed below: ", + "Programming Language: \"{language}\"", + "Source Codes:", + "\"{codes}\"", + "Test Reports of Source Codes:", + "\"{test_reports}\"", + "Error Summary of Test Reports:", + "\"{error_summary}\"", + "Note that each file must strictly follow a markdown code block format, where the following tokens must be replaced such that \"FILENAME\" is the lowercase file name including the file extension, \"LANGUAGE\" in the programming language, \"DOCSTRING\" is a string literal specified in source code that is used to document a specific segment of code, and \"CODE\" is the original code:", + "FILENAME", + "```LANGUAGE", + "'''", + "DOCSTRING", + "'''", + "CODE", + "```", + "As the {assistant_role}, to satisfy the new user's demand and make the software execute smoothly and robustly, you should modify the codes based on the error summary. Now, use the format exemplified above and modify the problematic codes based on the error summary. Output the codes that you fixed based on the test reported and corresponding explanations (strictly follow the format defined above, including FILENAME, LANGUAGE, DOCSTRING and CODE; incomplete \"TODO\" codes are strictly prohibited). If no bugs are reported, please return only one line like \" Finished\"." + ] + }, + "EnvironmentDoc": { + "assistant_role_name": "Programmer", + "user_role_name": "Chief Technology Officer", + "phase_prompt": [ + "The new user's task and our developed codes are listed: ", + "Task: \"{task}\".", + "Modality: \"{modality}\".", + "Programming Language: \"{language}\"", + "Ideas: \"{ideas}\"", + "Codes: ", + "\"{codes}\"", + "As the {assistant_role}, you should write a requirements.txt file, which is commonly used in Python projects to specify the dependencies or packages required for the project to run properly. It serves as a way to document and manage the project's dependencies in a standardized format. For example:", + "requirements.txt", + "```", + "numpy==1.19.2", + "pandas>=1.1.4", + "```", + "According to the codes and file format listed above, write a requirements.txt file to specify the dependencies or packages required for the project to run properly." + ] + }, + "Manual": { + "assistant_role_name": "Chief Product Officer", + "user_role_name": "Chief Executive Officer", + "phase_prompt": [ + "The new user's task, our developed codes and required dependencies are listed: ", + "Task: \"{task}\".", + "Modality: \"{modality}\".", + "Programming Language: \"{language}\"", + "Ideas: \"{ideas}\"", + "Codes: ", + "\"{codes}\"", + "Requirements:", + "\"{requirements}\"", + "As the {assistant_role}, by using Markdown, you should write a manual.md file which is a detailed user manual to use the software, including introducing main functions of the software, how to install environment dependencies and how to use/play it. For example:", + "manual.md", + "```", + "# LangChain", + "Building applications with LLMs through composability", + "Looking for the JS/TS version? Check out LangChain.js.", + "**Production Support:** As you move your LangChains into production, we'd love to offer more comprehensive support.", + "Please fill out this form and we'll set up a dedicated support Slack channel.", + "## Quick Install", + "`pip install langchain`", + "or", + "`conda install langchain -c conda-forge`", + "## 🤔 What is this?", + "Large language models (LLMs) are emerging as a transformative technology, enabling developers to build applications that they previously could not. However, using these LLMs in isolation is often insufficient for creating a truly powerful app - the real power comes when you can combine them with other sources of computation or knowledge.", + "This library aims to assist in the development of those types of applications. Common examples of these applications include:", + "**❓ Question Answering over specific documents**", + "- Documentation", + "- End-to-end Example: Question Answering over Notion Database", + "**🤖 Agents**", + "- Documentation", + "- End-to-end Example: GPT+WolframAlpha", + "## 📖 Documentation", + "Please see [here](https://python.langchain.com) for full documentation on:", + "- Getting started (installation, setting up the environment, simple examples)", + "- How-To examples (demos, integrations, helper functions)", + "- Reference (full API docs)", + "- Resources (high-level explanation of core concepts)", + "```" + ] + } +} \ No newline at end of file diff --git a/WareHouse/car_THUNLPDemo_2024/RoleConfig.json b/WareHouse/car_THUNLPDemo_2024/RoleConfig.json new file mode 100644 index 00000000..cd09e45a --- /dev/null +++ b/WareHouse/car_THUNLPDemo_2024/RoleConfig.json @@ -0,0 +1,65 @@ +{ + "Chief Executive Officer": [ + "{chatdev_prompt}", + "You are Chief Executive Officer. Now, we are both working at ChatDev and we share a common interest in collaborating to successfully complete a task assigned by a new customer.", + "Your main responsibilities include being an active decision-maker on users' demands and other key policy issues, leader, manager, and executor. Your decision-making role involves high-level decisions about policy and strategy; and your communicator role can involve speaking to the organization's management and employees.", + "Here is a new customer's task: {task}.", + "To complete the task, I will give you one or more instructions, and you must help me to write a specific solution that appropriately solves the requested instruction based on your expertise and my needs." + ], + "Chief Product Officer": [ + "{chatdev_prompt}", + "You are Chief Product Officer. we are both working at ChatDev. We share a common interest in collaborating to successfully complete a task assigned by a new customer.", + "You are responsible for all product-related matters in ChatDev. Usually includes product design, product strategy, product vision, product innovation, project management and product marketing.", + "Here is a new customer's task: {task}.", + "To complete the task, you must write a response that appropriately solves the requested instruction based on your expertise and customer's needs." + ], + "Counselor": [ + "{chatdev_prompt}", + "You are Counselor. Now, we share a common interest in collaborating to successfully complete a task assigned by a new customer.", + "Your main responsibilities include asking what user and customer think and provide your valuable suggestions. ", + "Here is a new customer's task: {task}.", + "To complete the task, I will give you one or more instructions, and you must help me to write a specific solution that appropriately solves the requested instruction based on your expertise and my needs." + ], + "Chief Technology Officer": [ + "{chatdev_prompt}", + "You are Chief Technology Officer. we are both working at ChatDev. We share a common interest in collaborating to successfully complete a task assigned by a new customer.", + "You are very familiar to information technology. You will make high-level decisions for the overarching technology infrastructure that closely align with the organization's goals, while you work alongside the organization's information technology (\"IT\") staff members to perform everyday operations.", + "Here is a new customer's task: {task}.", + "To complete the task, You must write a response that appropriately solves the requested instruction based on your expertise and customer's needs." + ], + "Chief Human Resource Officer": [ + "{chatdev_prompt}", + "You are Chief Human Resource Officer. Now, we are both working at ChatDev and we share a common interest in collaborating to successfully complete a task assigned by a new customer.", + "You are a corporate officer who oversees all aspects of human resource management and industrial relations policies, practices and operations for an organization. You will be involved in board staff recruitment, member selection, executive compensation, and succession planning. Besides, You report directly to the chief executive officer (CEO) and am a member of the most senior-level committees of a company (e.g., executive committee or office of CEO).", + "Here is a new customer's task: {task}.", + "To complete the task, you must write a response that appropriately solves the requested instruction based on your expertise and customer's needs." + ], + "Programmer": [ + "{chatdev_prompt}", + "You are Programmer. we are both working at ChatDev. We share a common interest in collaborating to successfully complete a task assigned by a new customer.", + "You can write/create computer software or applications by providing a specific programming language to the computer. You have extensive computing and coding experience in many varieties of programming languages and platforms, such as Python, Java, C, C++, HTML, CSS, JavaScript, XML, SQL, PHP, etc,.", + "Here is a new customer's task: {task}.", + "To complete the task, you must write a response that appropriately solves the requested instruction based on your expertise and customer's needs." + ], + "Code Reviewer": [ + "{chatdev_prompt}", + "You are Code Reviewer. we are both working at ChatDev. We share a common interest in collaborating to successfully complete a task assigned by a new customer.", + "You can help programmers to assess source codes for software troubleshooting, fix bugs to increase code quality and robustness, and offer proposals to improve the source codes.", + "Here is a new customer's task: {task}.", + "To complete the task, you must write a response that appropriately solves the requested instruction based on your expertise and customer's needs." + ], + "Software Test Engineer": [ + "{chatdev_prompt}", + "You are Software Test Engineer. we are both working at ChatDev. We share a common interest in collaborating to successfully complete a task assigned by a new customer.", + "You can use the software as intended to analyze its functional properties, design manual and automated test procedures to evaluate each software product, build and implement software evaluation test programs, and run test programs to ensure that testing protocols evaluate the software correctly.", + "Here is a new customer's task: {task}.", + "To complete the task, you must write a response that appropriately solves the requested instruction based on your expertise and customer's needs." + ], + "Chief Creative Officer": [ + "{chatdev_prompt}", + "You are Chief Creative Officer. we are both working at ChatDev. We share a common interest in collaborating to successfully complete a task assigned by a new customer.", + "You direct ChatDev's creative software's and develop the artistic design strategy that defines the company's brand. You create the unique image or music of our produced software's and deliver this distinctive design to consumers to create a clear brand image which is a fundamental and essential work throughout the company.", + "Here is a new customer's task: {task}.", + "To complete the task, you must write a response that appropriately solves the requested instruction based on your expertise and customer's needs." + ] +} \ No newline at end of file diff --git a/WareHouse/car_THUNLPDemo_2024/car.py b/WareHouse/car_THUNLPDemo_2024/car.py new file mode 100644 index 00000000..efbf7ad2 --- /dev/null +++ b/WareHouse/car_THUNLPDemo_2024/car.py @@ -0,0 +1,37 @@ +''' +Player car class implementation with improved visual representation and road boundary constraints +''' +import pygame +class PlayerCar: + def __init__(self, x, y): + self.x = x + self.y = y + self.width = 40 + self.height = 60 + self.speed = 5 + self.color = (255, 0, 0) # Red color + def handle_input(self, keys, screen_width): + # Road boundaries + left_boundary = screen_width//3 + 20 # Add padding for visibility + right_boundary = 2*screen_width//3 # Subtract padding for visibility + if keys[pygame.K_LEFT] and self.x > left_boundary: + self.x -= self.speed + if keys[pygame.K_RIGHT] and self.x < right_boundary - self.width: + self.x += self.speed + if keys[pygame.K_UP] and self.y > 0: + self.y -= self.speed + if keys[pygame.K_DOWN] and self.y < 600 - self.height: + self.y += self.speed + def update(self): + pass + def draw(self, screen): + # Draw car body + pygame.draw.rect(screen, self.color, (self.x, self.y, self.width, self.height)) + # Draw car details (wheels and windows) + pygame.draw.rect(screen, (0, 0, 0), (self.x + 5, self.y + 10, 10, 40)) # Left wheel + pygame.draw.rect(screen, (0, 0, 0), (self.x + 25, self.y + 10, 10, 40)) # Right wheel + pygame.draw.rect(screen, (200, 200, 200), (self.x + 5, self.y + 5, 30, 15)) # Windshield + def check_collision(self, other): + return pygame.Rect(self.x, self.y, self.width, self.height).colliderect( + pygame.Rect(other.x, other.y, other.width, other.height) + ) \ No newline at end of file diff --git a/WareHouse/car_THUNLPDemo_2024/gameobjects.py b/WareHouse/car_THUNLPDemo_2024/gameobjects.py new file mode 100644 index 00000000..759f245f --- /dev/null +++ b/WareHouse/car_THUNLPDemo_2024/gameobjects.py @@ -0,0 +1,30 @@ +''' +Game objects implementation including opponent cars with improved visuals and road constraints +''' +import pygame +import random +class OpponentCar: + def __init__(self, screen_width): + self.width = 40 + self.height = 60 + self.screen_width = screen_width + self.road_left = screen_width//3 + 20 + self.road_right = 2*screen_width//3 + self.reset_position() + self.color = (0, 0, 255) # Blue color + self.speed = random.randint(3, 7) + def reset_position(self): + # Ensure opponents spawn within road boundaries + self.x = random.randint(self.road_left, self.road_right - self.width) + self.y = random.randint(-300, -100) + def update(self): + self.y += self.speed + if self.y > 600: + self.reset_position() + def draw(self, screen): + # Draw car body + pygame.draw.rect(screen, self.color, (self.x, self.y, self.width, self.height)) + # Draw car details + pygame.draw.rect(screen, (0, 0, 0), (self.x + 5, self.y + 10, 10, 40)) # Left wheel + pygame.draw.rect(screen, (0, 0, 0), (self.x + 25, self.y + 10, 10, 40)) # Right wheel + pygame.draw.rect(screen, (200, 200, 200), (self.x + 5, self.y + 5, 30, 15)) # Windshield \ No newline at end of file diff --git a/WareHouse/car_THUNLPDemo_2024/main.py b/WareHouse/car_THUNLPDemo_2024/main.py new file mode 100644 index 00000000..954c6682 --- /dev/null +++ b/WareHouse/car_THUNLPDemo_2024/main.py @@ -0,0 +1,76 @@ +''' +Main game file that initializes the racing game and runs the game loop +''' +import pygame +import sys +from car import PlayerCar +from track import Track +from gameobjects import OpponentCar +class RacingGame: + def __init__(self): + pygame.init() + self.width = 800 + self.height = 600 + self.screen = pygame.display.set_mode((self.width, self.height)) + pygame.display.set_caption("赛车游戏") + self.clock = pygame.time.Clock() + self.running = True + self.game_over = False + self.font = pygame.font.Font(None, 74) + self.reset_game() + def reset_game(self): + # Initialize player at the center of the road + road_center = (self.width//3 + (2*self.width//3 + 20)) // 2 + self.player = PlayerCar(road_center - 20, self.height - 100) + self.track = Track(self.width, self.height) + self.opponents = [OpponentCar(self.width) for _ in range(3)] + self.score = 0 + self.game_over = False + def handle_events(self): + for event in pygame.event.get(): + if event.type == pygame.QUIT: + self.running = False + if event.type == pygame.KEYDOWN and self.game_over: + if event.key == pygame.K_SPACE: + self.reset_game() + if not self.game_over: + keys = pygame.key.get_pressed() + self.player.handle_input(keys, self.width) + def update(self): + if not self.game_over: + self.player.update() + self.track.update() + for opponent in self.opponents: + opponent.update() + if self.player.check_collision(opponent): + self.game_over = True + self.score += 1 + def render(self): + self.screen.fill((100, 100, 100)) # Gray background + self.track.draw(self.screen) + self.player.draw(self.screen) + for opponent in self.opponents: + opponent.draw(self.screen) + # Draw score + font = pygame.font.Font(None, 36) + score_text = font.render(f'Score: {self.score}', True, (255, 255, 255)) + self.screen.blit(score_text, (10, 10)) + if self.game_over: + game_over_text = self.font.render('GAME OVER', True, (255, 0, 0)) + restart_text = pygame.font.Font(None, 36).render('Press SPACE to restart', True, (255, 255, 255)) + text_rect = game_over_text.get_rect(center=(self.width//2, self.height//2)) + restart_rect = restart_text.get_rect(center=(self.width//2, self.height//2 + 50)) + self.screen.blit(game_over_text, text_rect) + self.screen.blit(restart_text, restart_rect) + pygame.display.flip() + def run(self): + while self.running: + self.handle_events() + self.update() + self.render() + self.clock.tick(60) + pygame.quit() + sys.exit() +if __name__ == "__main__": + game = RacingGame() + game.run() \ No newline at end of file diff --git a/WareHouse/car_THUNLPDemo_2024/meta.txt b/WareHouse/car_THUNLPDemo_2024/meta.txt new file mode 100644 index 00000000..02478e98 --- /dev/null +++ b/WareHouse/car_THUNLPDemo_2024/meta.txt @@ -0,0 +1,33 @@ +Task: +仔细开发一个赛车小游戏 + +Config: +ChatEnvConfig.with_memory: False +ChatEnvConfig.clear_structure: True +ChatEnvConfig.git_management: False +ChatEnvConfig.gui_design: True +ChatEnvConfig.incremental_develop: False +ChatEnvConfig.background_prompt: ChatDev is a virtual LLM Agent software company aiming to build the best software with simple but robust code, maximizing the controllability and visual effect of the software in pure python. + + +Roster: +Chief Executive Officer, Counselor, Chief Human Resource Officer, Chief Product Officer, Chief Technology Officer, Programmer, Code Reviewer, Software Test Engineer, Chief Creative Officer + +Modality: +website or app, prefer app + +Ideas: + + +Language: +python for app, or html/css/js for website, prefer app + +Code_Version: +3.0 + +Proposed_images: +0 + +Incorporated_images: +0 + diff --git a/WareHouse/car_THUNLPDemo_2024/track.py b/WareHouse/car_THUNLPDemo_2024/track.py new file mode 100644 index 00000000..badc7d42 --- /dev/null +++ b/WareHouse/car_THUNLPDemo_2024/track.py @@ -0,0 +1,31 @@ +''' +Track class for managing the racing environment with improved visuals and clear boundaries +''' +import pygame +class Track: + def __init__(self, width, height): + self.width = width + self.height = height + self.line_spacing = 100 + self.line_height = 30 + self.line_speed = 5 + self.lines = [] + self.initialize_lines() + self.road_left = self.width//3 + self.road_right = 2*self.width//3 + 20 + def initialize_lines(self): + for y in range(0, self.height, self.line_spacing): + self.lines.append(y) + def update(self): + self.lines = [(y + self.line_speed) % self.height for y in self.lines] + def draw(self, screen): + # Draw road background + pygame.draw.rect(screen, (50, 50, 50), + (self.road_left, 0, self.road_right - self.road_left, self.height)) + # Draw road borders + pygame.draw.rect(screen, (255, 255, 0), (self.road_left - 5, 0, 5, self.height)) # Left border + pygame.draw.rect(screen, (255, 255, 0), (self.road_right, 0, 5, self.height)) # Right border + # Draw road lines + for y in self.lines: + pygame.draw.rect(screen, (255, 255, 255), + (self.width//2 - 10, y, 20, self.line_height)) \ No newline at end of file diff --git a/WareHouse/pvz_THUNLPDemo_2024/assets/music/bgm.mp3 b/WareHouse/pvz_THUNLPDemo_2024/assets/music/bgm.mp3 new file mode 100644 index 00000000..552edeab Binary files /dev/null and b/WareHouse/pvz_THUNLPDemo_2024/assets/music/bgm.mp3 differ diff --git a/WareHouse/pvz_THUNLPDemo_2024/constants.py b/WareHouse/pvz_THUNLPDemo_2024/constants.py new file mode 100644 index 00000000..230409d0 --- /dev/null +++ b/WareHouse/pvz_THUNLPDemo_2024/constants.py @@ -0,0 +1,63 @@ +import pygame +from enum import Enum + +# Window Settings +WINDOW_WIDTH = 1080 +WINDOW_HEIGHT = 900 +CELL_SIZE = 100 +GRID_ROWS = 7 +GRID_COLS = 9 +TOP_MARGIN = 100 +FPS = 60 + +# Colors +WHITE = (255, 255, 255) +BLACK = (0, 0, 0) +GREEN = (0, 255, 0) +DARK_GREEN = (0, 100, 0) +BROWN = (139, 69, 19) +YELLOW = (255, 255, 0) +LAWN_GREEN = (124, 252, 0) +GRAY = (128, 128, 128) +RED = (255, 0, 0) + +# Game States +class GameState(Enum): + MENU = 1 + PLAYING = 2 + PAUSED = 3 + GAME_OVER = 4 + +# Plant Types +class PlantType(Enum): + SUNFLOWER = 1 + PEASHOOTER = 2 + ROSE_SHOOTER = 3 + CHOMPER = 4 + SNOW_PEA = 5 + +# Zombie Types +class ZombieType(Enum): + NORMAL = 1 + CONE = 2 + BUCKET = 3 + NEWSPAPER = 4 + DANCING = 5 + +# Plant Stats +PLANT_STATS = { + PlantType.SUNFLOWER: {"health": 100, "cost": 50, "color": YELLOW}, + PlantType.PEASHOOTER: {"health": 120, "cost": 100, "color": GREEN}, + PlantType.ROSE_SHOOTER: {"health": 140, "cost": 150, "color": (255, 192, 203)}, + PlantType.CHOMPER: {"health": 180, "cost": 175, "color": (148, 0, 211)}, + PlantType.SNOW_PEA: {"health": 130, "cost": 175, "color": (0, 191, 255)} +} + +# Zombie Stats +ZOMBIE_STATS = { + ZombieType.NORMAL: {"health": 300, "speed": 0.4, "damage": 0.4}, + ZombieType.CONE: {"health": 450, "speed": 0.45, "damage": 0.3}, + ZombieType.BUCKET: {"health": 550, "speed": 0.35, "damage": 0.5}, + ZombieType.NEWSPAPER: {"health": 200, "speed": 0.6, "damage": 0.3}, + ZombieType.DANCING: {"health": 350, "speed": 0.5, "damage": 0.35} +} \ No newline at end of file diff --git a/WareHouse/pvz_THUNLPDemo_2024/entities.py b/WareHouse/pvz_THUNLPDemo_2024/entities.py new file mode 100644 index 00000000..67e9a2bb --- /dev/null +++ b/WareHouse/pvz_THUNLPDemo_2024/entities.py @@ -0,0 +1,285 @@ +import pygame +import math +from constants import * +from sprites import PLANT_DRAWINGS, ZOMBIE_DRAWINGS + +class Plant: + def __init__(self, x, y, plant_type): + self.x = x + self.y = y + self.type = plant_type + stats = PLANT_STATS[plant_type] + self.health = stats["health"] + self.max_health = stats["health"] + self.cost = stats["cost"] + self.rect = pygame.Rect(x * CELL_SIZE, y * CELL_SIZE + TOP_MARGIN, CELL_SIZE, CELL_SIZE) + self.shoot_timer = 0 + self.shoot_cooldown = 150 # Frames between shots + self.eating_timer = 0 + self.eating_cooldown = 300 # Frames between chomps + self.sun_timer = 0 + self.animation_state = "idle" + self.damaged_state = 0 + + # Special abilities + self.is_freezing = plant_type == PlantType.SNOW_PEA + self.can_eat = plant_type == PlantType.CHOMPER + self.is_rose = plant_type == PlantType.ROSE_SHOOTER + + def update(self): + if self.type in [PlantType.PEASHOOTER, PlantType.SNOW_PEA, PlantType.ROSE_SHOOTER]: + self.shoot_timer += 1 + elif self.type == PlantType.SUNFLOWER: + self.sun_timer += 1 + elif self.type == PlantType.CHOMPER and self.eating_timer > 0: + self.eating_timer -= 1 + + # Update damage state + health_percentage = self.health / self.max_health + if health_percentage <= 0.3: + self.damaged_state = 2 + elif health_percentage <= 0.6: + self.damaged_state = 1 + + def can_shoot(self): + if self.type == PlantType.PEASHOOTER: + return self.shoot_timer >= 90 + elif self.type == PlantType.SNOW_PEA: + return self.shoot_timer >= 90 + elif self.type == PlantType.ROSE_SHOOTER: + return self.shoot_timer >= 100 # Slightly slower fire rate + return False + + def can_produce_sun(self): + return self.type == PlantType.SUNFLOWER and self.sun_timer >= 360 + + def can_eat_zombie(self): + return self.type == PlantType.CHOMPER and self.eating_timer <= 0 + + def start_eating(self): + self.eating_timer = 300 # 5 seconds cooldown + + def reset_timer(self): + if self.type in [PlantType.PEASHOOTER, PlantType.SNOW_PEA, PlantType.ROSE_SHOOTER]: + self.shoot_timer = 0 + elif self.type == PlantType.SUNFLOWER: + self.sun_timer = 0 + + def draw(self, screen): + # Draw shadow + shadow_surface = pygame.Surface((CELL_SIZE, CELL_SIZE//4), pygame.SRCALPHA) + pygame.draw.ellipse(shadow_surface, (0, 0, 0, 64), (0, 0, CELL_SIZE, CELL_SIZE//4)) + screen.blit(shadow_surface, (self.rect.x, self.rect.y + CELL_SIZE - CELL_SIZE//8)) + + # Draw plant using the corresponding drawing function + if self.type in PLANT_DRAWINGS: + PLANT_DRAWINGS[self.type](screen, self.rect.x, self.rect.y, CELL_SIZE) + + # Draw health bar when damaged + if self.health < self.max_health: + health_width = max(0, (self.rect.width * self.health) // self.max_health) + health_rect = pygame.Rect(self.rect.x, self.rect.y - 5, health_width, 3) + pygame.draw.rect(screen, (255, 0, 0), health_rect) + +class Zombie: + def __init__(self, row, zombie_type): + self.x = WINDOW_WIDTH / CELL_SIZE + self.y = row + self.type = zombie_type + stats = ZOMBIE_STATS[zombie_type] + self.health = stats["health"] + self.max_health = stats["health"] + self.speed = stats["speed"] + self.damage = stats["damage"] + self.rect = pygame.Rect( + self.x * CELL_SIZE, + self.y * CELL_SIZE + TOP_MARGIN, + CELL_SIZE, + CELL_SIZE + ) + self.eating = False + self.stun_timer = 0 + self.frozen_timer = 0 + self.frozen = False + self.intoxicated_timer = 0 + self.intoxicated = False + self.animation_state = "walking" + + # Special abilities for newspaper zombie + if self.type == ZombieType.NEWSPAPER: + self.has_newspaper = True + self.enraged = False + else: + self.has_newspaper = False + self.enraged = False + + # Special abilities for dancing zombie + if self.type == ZombieType.DANCING: + self.summon_timer = 300 + else: + self.summon_timer = 0 + + def move(self): + if not self.eating and self.stun_timer <= 0: + actual_speed = self.speed + if self.frozen: + actual_speed *= 0.5 + if self.intoxicated: + actual_speed *= 0.3 + if self.type == ZombieType.NEWSPAPER and self.enraged: + actual_speed *= 1.5 + + self.x -= actual_speed / FPS + self.rect.x = self.x * CELL_SIZE + + if self.stun_timer > 0: + self.stun_timer -= 1 + + if self.frozen: + self.frozen_timer -= 1 + if self.frozen_timer <= 0: + self.frozen = False + + if self.intoxicated: + self.intoxicated_timer -= 1 + if self.intoxicated_timer <= 0: + self.intoxicated = False + + def intoxicate(self): + self.intoxicated = True + self.intoxicated_timer = 300 + + def take_damage(self, damage): + self.health -= damage + if self.type == ZombieType.NEWSPAPER and self.has_newspaper and self.health <= self.max_health * 0.5: + self.has_newspaper = False + self.enraged = True + self.speed *= 1.5 + + def freeze(self): + self.frozen = True + self.frozen_timer = 300 + + def draw(self, screen): + # Draw shadow + shadow_surface = pygame.Surface((CELL_SIZE, CELL_SIZE//3), pygame.SRCALPHA) + pygame.draw.ellipse(shadow_surface, (0, 0, 0, 64), (0, 0, CELL_SIZE, CELL_SIZE//3)) + screen.blit(shadow_surface, (self.rect.x, self.rect.y + CELL_SIZE - CELL_SIZE//6)) + + # Draw zombie using the corresponding drawing function + if self.type in ZOMBIE_DRAWINGS: + ZOMBIE_DRAWINGS[self.type](screen, self.rect.x, self.rect.y, CELL_SIZE) + + # Draw frozen effect + if self.frozen: + ice_surface = pygame.Surface((CELL_SIZE, CELL_SIZE), pygame.SRCALPHA) + ice_surface.fill((150, 217, 255, 128)) + screen.blit(ice_surface, self.rect) + + # Draw intoxicated effect + if self.intoxicated: + love_surface = pygame.Surface((CELL_SIZE, CELL_SIZE), pygame.SRCALPHA) + time = pygame.time.get_ticks() + for i in range(3): + heart_x = self.rect.x + CELL_SIZE//2 + math.cos(time * 0.003 + i * 2) * 15 + heart_y = self.rect.y + CELL_SIZE//3 + math.sin(time * 0.003 + i * 2) * 10 + # Draw heart shape + pygame.draw.circle(screen, (255, 192, 203, 200), (int(heart_x - 5), int(heart_y)), 5) + pygame.draw.circle(screen, (255, 192, 203, 200), (int(heart_x + 5), int(heart_y)), 5) + pygame.draw.polygon(screen, (255, 192, 203, 200), [ + (heart_x, heart_y + 8), + (heart_x - 10, heart_y), + (heart_x + 10, heart_y) + ]) + + # Health bar + health_width = max(0, (self.rect.width * self.health) // self.max_health) + health_rect = pygame.Rect(self.rect.x, self.rect.y - 10, health_width, 5) + pygame.draw.rect(screen, (255, 0, 0), health_rect) + +class Projectile: + def __init__(self, x, y, damage=20, speed=5, freezing=False, is_rose=False): + self.x = (x + 0.5) * CELL_SIZE + self.y = y * CELL_SIZE + TOP_MARGIN + CELL_SIZE // 2 + self.damage = damage + self.speed = speed + self.freezing = freezing + self.is_rose = is_rose + self.active = True + self.size = 10 # Set all projectiles to the same size + self.rect = pygame.Rect(self.x - self.size//2, self.y - self.size//2, self.size, self.size) + self.trail_positions = [] + self.trail_lifetime = 15 if is_rose else 10 + self.glow_offset = 0 + self.rotation = 0 + self.color = (255, 192, 203) if is_rose else ((0, 191, 255) if freezing else (0, 255, 0)) + self.alpha = 255 + + def move(self): + # Store current position for trail + self.trail_positions.append((self.rect.x, self.rect.y)) + if len(self.trail_positions) > self.trail_lifetime: + self.trail_positions.pop(0) + + self.rect.x += self.speed + self.rotation += 15 # Rotate 15 degrees per frame + + # Update glow effect + self.glow_offset = abs(math.sin(pygame.time.get_ticks() * 0.01)) * 2 + + if self.rect.x > WINDOW_WIDTH: + self.active = False + + def draw(self, screen): + # Draw trail with rose petals or regular trail + for i, (x, y) in enumerate(self.trail_positions): + alpha = int(255 * (i / len(self.trail_positions)) * 0.5) + size = int(4 * (i / len(self.trail_positions))) # Same size for all trails + + trail_surface = pygame.Surface((12, 12), pygame.SRCALPHA) # Same size for all trails + if self.is_rose: + # Draw rose petal trail + petal_color = (255, 192, 203, alpha) # Pink with alpha + # Draw multiple petals for a more detailed trail + for angle in range(0, 360, 72): + rad = math.radians(angle + self.rotation) + petal_x = 6 + math.cos(rad) * size # Center at 6 (half of 12) + petal_y = 6 + math.sin(rad) * size + pygame.draw.circle(trail_surface, petal_color, (int(petal_x), int(petal_y)), size) + else: + color = (0, 191, 255, alpha) if self.freezing else (0, 255, 0, alpha) + pygame.draw.circle(trail_surface, color, (6, 6), size) + screen.blit(trail_surface, (x - 6, y - 6)) + + # Draw main projectile + if self.is_rose: + # Draw rose projectile at same size as others + glow_surface = pygame.Surface((20, 20), pygame.SRCALPHA) + glow_radius = 8 + self.glow_offset + glow_color = (255, 192, 203, 64) # Pink with transparency + pygame.draw.circle(glow_surface, glow_color, (10, 10), glow_radius) + screen.blit(glow_surface, (self.rect.x - 10, self.rect.y - 10)) + + # Main projectile + pygame.draw.circle(screen, (255, 192, 203), (self.rect.x, self.rect.y), 6) # Same size as others + pygame.draw.circle(screen, (255, 105, 180), (self.rect.x, self.rect.y), 4) # Inner color + + # Add highlight + highlight_pos = (self.rect.x - 2, self.rect.y - 2) + pygame.draw.circle(screen, (255, 255, 255, 180), highlight_pos, 2) + else: + # Draw regular projectile + glow_color = (0, 191, 255, 64) if self.freezing else (0, 255, 0, 64) + main_color = (0, 191, 255) if self.freezing else (0, 200, 0) + inner_color = (173, 216, 230) if self.freezing else (150, 255, 150) + + glow_surface = pygame.Surface((20, 20), pygame.SRCALPHA) + glow_radius = 8 + self.glow_offset + pygame.draw.circle(glow_surface, glow_color, (10, 10), glow_radius) + screen.blit(glow_surface, (self.rect.x - 10, self.rect.y - 10)) + + pygame.draw.circle(screen, main_color, (self.rect.x, self.rect.y), 6) + pygame.draw.circle(screen, inner_color, (self.rect.x, self.rect.y), 4) + + highlight_pos = (self.rect.x - 2, self.rect.y - 2) + pygame.draw.circle(screen, (255, 255, 255, 180), highlight_pos, 2) \ No newline at end of file diff --git a/WareHouse/pvz_THUNLPDemo_2024/main.py b/WareHouse/pvz_THUNLPDemo_2024/main.py new file mode 100644 index 00000000..7a8fda06 --- /dev/null +++ b/WareHouse/pvz_THUNLPDemo_2024/main.py @@ -0,0 +1,817 @@ +import pygame +import sys +import random +import math +from constants import * +from entities import Plant, Zombie, Projectile +from sprites import PLANT_DRAWINGS, ZOMBIE_DRAWINGS + +class Sun: + def __init__(self, x, y, from_sky=True): + self.x = x + self.y = y + self.initial_x = x + self.initial_y = y + self.value = 25 + self.rect = pygame.Rect(x, y, 40, 40) + self.collected = False + self.from_sky = from_sky + self.fall_speed = 1.5 + self.lifetime = 300 if from_sky else 450 + self.hover_offset = 0 + self.hover_speed = 0.03 + self.hover_range = 5 + self.fade_start = 60 + self.alpha = 0 + self.fade_in = 255 + self.glow_offset = 0 + self.size = 40 + self.collect_speed = 5 + self.collecting = False + + def move(self): + if self.from_sky and self.y < self.initial_y + WINDOW_HEIGHT//3: + self.y += self.fall_speed + self.rect.y = self.y + + self.hover_offset = math.sin(pygame.time.get_ticks() * self.hover_speed) * self.hover_range + self.rect.y = self.y + self.hover_offset + + self.glow_offset = abs(math.sin(pygame.time.get_ticks() * 0.002)) * 5 + + if self.fade_in > 0: + self.alpha = min(255, self.alpha + 10) + self.fade_in -= 10 + + self.lifetime -= 1 + if self.lifetime <= self.fade_start: + self.alpha = max(0, int(255 * (self.lifetime / self.fade_start))) + + def draw(self, screen): + sun_surface = pygame.Surface((50, 50), pygame.SRCALPHA) + glow_radius = 25 + self.glow_offset + pygame.draw.circle(sun_surface, (255, 255, 100, int(self.alpha * 0.3)), (25, 25), glow_radius) + pygame.draw.circle(sun_surface, (255, 255, 0, self.alpha), (25, 25), 20) + pygame.draw.circle(sun_surface, (255, 255, 200, self.alpha), (25, 25), 15) + pygame.draw.circle(sun_surface, (255, 255, 255, int(self.alpha * 0.7)), (25, 25), 8) + + screen.blit(sun_surface, (self.rect.x - 5, self.rect.y - 5)) + +class Game: + def __init__(self): + pygame.init() + pygame.mixer.init() + # Set window mode with fixed resolution + self.screen = pygame.display.set_mode((WINDOW_WIDTH, WINDOW_HEIGHT)) + pygame.display.set_caption("植物大战僵尸 - ChatDev制作") + self.clock = pygame.time.Clock() + self.state = GameState.MENU + # Set scale factors based on window size + self.base_width = WINDOW_WIDTH + self.base_height = WINDOW_HEIGHT + self.scale_x = 1.0 + self.scale_y = 1.0 + + # Load and play background music + self.load_music() + # Add Chinese font + try: + self.font = pygame.font.Font("/System/Library/Fonts/PingFang.ttc", 36) + self.large_font = pygame.font.Font("/System/Library/Fonts/PingFang.ttc", 74) + self.small_font = pygame.font.Font("/System/Library/Fonts/PingFang.ttc", 24) + except: + try: + self.font = pygame.font.Font("/System/Library/Fonts/STHeiti Light.ttc", 36) + self.large_font = pygame.font.Font("/System/Library/Fonts/STHeiti Light.ttc", 74) + self.small_font = pygame.font.Font("/System/Library/Fonts/STHeiti Light.ttc", 24) + except: + try: + self.font = pygame.font.Font("/System/Library/Fonts/Arial Unicode.ttf", 36) + self.large_font = pygame.font.Font("/System/Library/Fonts/Arial Unicode.ttf", 74) + self.small_font = pygame.font.Font("/System/Library/Fonts/Arial Unicode.ttf", 24) + except: + print("Warning: Could not load Chinese font, falling back to default font") + self.font = pygame.font.Font(None, 36) + self.large_font = pygame.font.Font(None, 74) + self.small_font = pygame.font.Font(None, 24) + self.reset_game() + + def load_music(self): + try: + pygame.mixer.music.load("assets/music/bgm.mp3") + pygame.mixer.music.set_volume(0.5) # Set volume to 50% + pygame.mixer.music.play(-1) # -1 means loop indefinitely + except: + print("Warning: Could not load background music") + + def reset_game(self): + self.plants = [] + self.zombies = [] + self.projectiles = [] + self.suns = [] + self.particles = [] + self.sun_points = 2025 + self.selected_plant = None + self.spawn_timer = 0 + self.sun_spawn_timer = 0 + self.wave_number = 1 + self.wave_timer = 600 + self.score = 0 + self.game_over = False + + def spawn_sun(self): + if self.sun_spawn_timer <= 0: + x = random.randint(100, WINDOW_WIDTH - 100) + self.suns.append(Sun(x, -40)) + self.sun_spawn_timer = random.randint(300, 500) + self.sun_spawn_timer -= 1 + + def spawn_zombie(self): + if self.spawn_timer <= 0: + # Ensure minimum number of zombies (5) are present + if len(self.zombies) < 5 + self.wave_number: + # Spawn multiple zombies at once if below minimum + zombies_to_spawn = max(2, 5 + self.wave_number - len(self.zombies)) + for _ in range(zombies_to_spawn): + row = random.randint(0, GRID_ROWS - 1) + + # Zombie type selection based on wave number + zombie_types = [ + ZombieType.NORMAL, + ZombieType.CONE, + ZombieType.BUCKET, + ZombieType.NEWSPAPER, + ZombieType.DANCING + ] + + zombie_type = random.choice(zombie_types) + self.zombies.append(Zombie(row, zombie_type)) + else: + # Regular spawn for maintaining zombie presence + row = random.randint(0, GRID_ROWS - 1) + zombie_types = [ + ZombieType.NORMAL, + ZombieType.CONE, + ZombieType.BUCKET, + ZombieType.NEWSPAPER, + ZombieType.DANCING + ] + + zombie_type = random.choice(zombie_types) + self.zombies.append(Zombie(row, zombie_type)) + + # Adjust spawn timer based on wave - make it faster + base_timer = max(100, 300 - (self.wave_number * 40)) # Reduced from 500 to 300 + variation = random.randint(-30, 30) # Add some randomness + self.spawn_timer = base_timer + variation + self.spawn_timer -= 1 + + def handle_resize(self, event): + # Update screen size + width, height = event.size + self.screen = pygame.display.set_mode((width, height), pygame.RESIZABLE) + # Calculate new scale factors + self.scale_x = width / self.base_width + self.scale_y = height / self.base_height + # Update font sizes based on scale + scale = min(self.scale_x, self.scale_y) + try: + self.font = pygame.font.Font("/System/Library/Fonts/PingFang.ttc", int(36 * scale)) + self.large_font = pygame.font.Font("/System/Library/Fonts/PingFang.ttc", int(74 * scale)) + self.small_font = pygame.font.Font("/System/Library/Fonts/PingFang.ttc", int(24 * scale)) + except: + try: + self.font = pygame.font.Font("/System/Library/Fonts/STHeiti Light.ttc", int(36 * scale)) + self.large_font = pygame.font.Font("/System/Library/Fonts/STHeiti Light.ttc", int(74 * scale)) + self.small_font = pygame.font.Font("/System/Library/Fonts/STHeiti Light.ttc", int(24 * scale)) + except: + try: + self.font = pygame.font.Font("/System/Library/Fonts/Arial Unicode.ttf", int(36 * scale)) + self.large_font = pygame.font.Font("/System/Library/Fonts/Arial Unicode.ttf", int(74 * scale)) + self.small_font = pygame.font.Font("/System/Library/Fonts/Arial Unicode.ttf", int(24 * scale)) + except: + self.font = pygame.font.Font(None, int(36 * scale)) + self.large_font = pygame.font.Font(None, int(74 * scale)) + self.small_font = pygame.font.Font(None, int(24 * scale)) + + def get_scaled_rect(self, rect): + # Helper function to scale rectangles + return pygame.Rect( + rect.x * self.scale_x, + rect.y * self.scale_y, + rect.width * self.scale_x, + rect.height * self.scale_y + ) + + def get_real_pos(self, pos): + # Convert screen position to game logic position + return (pos[0] / self.scale_x, pos[1] / self.scale_y) + + def handle_click(self, pos): + # Convert screen position to game logic position + x, y = self.get_real_pos(pos) + + # Check if clicking on a sun + for sun in self.suns[:]: + if sun.rect.collidepoint(x, y) and not sun.collected: + self.sun_points += sun.value + self.suns.remove(sun) + continue + + # Plant placement + # Calculate grid position + grid_x = int(x // CELL_SIZE) + grid_y = int((y - TOP_MARGIN) // CELL_SIZE) + + # Check if click is within the planting area + if 0 <= grid_x < GRID_COLS and 0 <= grid_y < GRID_ROWS: + # Check if there's already a plant there + plant_exists = any(p.x == grid_x and p.y == grid_y for p in self.plants) + + if not plant_exists and self.selected_plant: + cost = PLANT_STATS[self.selected_plant]["cost"] + if self.sun_points >= cost: + self.plants.append(Plant(grid_x, grid_y, self.selected_plant)) + self.sun_points -= cost + self.selected_plant = None + + def update_plants(self): + for plant in self.plants: + plant.update() + if plant.can_shoot(): + if plant.type == PlantType.SNOW_PEA: + self.projectiles.append(Projectile(plant.x, plant.y, freezing=True)) + elif plant.type == PlantType.ROSE_SHOOTER: + # Shoot in current lane and adjacent lanes + lanes = [plant.y] # Current lane + if plant.y > 0: # Add lane above if exists + lanes.append(plant.y - 1) + if plant.y < GRID_ROWS - 1: # Add lane below if exists + lanes.append(plant.y + 1) + for lane in lanes: + # Create rose projectile with special properties + proj = Projectile(plant.x, lane, damage=20, speed=6, is_rose=True) + self.projectiles.append(proj) + else: + self.projectiles.append(Projectile(plant.x, plant.y)) + plant.reset_timer() + elif plant.can_produce_sun(): + self.suns.append(Sun(plant.rect.x, plant.rect.y, from_sky=False)) + plant.reset_timer() + elif plant.can_eat_zombie(): + # Check for zombies in range for Chomper + for zombie in self.zombies[:]: + if zombie.y == plant.y and abs(zombie.x - plant.x) <= 1: + self.zombies.remove(zombie) + plant.start_eating() + self.score += 100 + break + + def update_combat(self): + # Update projectiles and check collisions + for projectile in self.projectiles[:]: + if not projectile.active: + self.projectiles.remove(projectile) + continue + + projectile.move() + for zombie in self.zombies[:]: + if projectile.rect.colliderect(zombie.rect): + # Create impact effect based on projectile type + if projectile.is_rose: + # Rose shooter effect (pink petals) + color = (255, 192, 203) # Pink for rose + for _ in range(12): + angle = random.uniform(0, 2 * math.pi) + speed = random.uniform(3, 6) + size = random.uniform(4, 7) + self.particles.append({ + 'x': projectile.rect.x, + 'y': projectile.rect.y, + 'dx': math.cos(angle) * speed, + 'dy': math.sin(angle) * speed, + 'lifetime': 45, + 'color': (255, 192, 203), + 'size': size, + 'rotation': random.uniform(0, 360), + 'is_petal': True, + 'shape': 'petal' + }) + # Add sparkle particle + self.particles.append({ + 'x': projectile.rect.x, + 'y': projectile.rect.y, + 'dx': math.cos(angle) * (speed * 0.7), + 'dy': math.sin(angle) * (speed * 0.7), + 'lifetime': 30, + 'color': (255, 255, 255), + 'size': size * 0.5, + 'is_petal': False + }) + zombie.intoxicate() + elif projectile.freezing: + # Snow pea effect (ice crystals) + color = (0, 191, 255) # Ice blue + for _ in range(12): + angle = random.uniform(0, 2 * math.pi) + speed = random.uniform(3, 6) + size = random.uniform(4, 7) + self.particles.append({ + 'x': projectile.rect.x, + 'y': projectile.rect.y, + 'dx': math.cos(angle) * speed, + 'dy': math.sin(angle) * speed, + 'lifetime': 40, + 'color': (0, 191, 255), + 'size': size, + 'rotation': random.uniform(0, 360), + 'is_petal': True, + 'shape': 'snowflake' + }) + # Add sparkle particle + self.particles.append({ + 'x': projectile.rect.x, + 'y': projectile.rect.y, + 'dx': math.cos(angle) * (speed * 0.7), + 'dy': math.sin(angle) * (speed * 0.7), + 'lifetime': 25, + 'color': (255, 255, 255), + 'size': size * 0.4, + 'is_petal': False + }) + zombie.freeze() + else: + # Regular peashooter effect (leaves and splashes) + color = (0, 255, 0) # Green + for _ in range(12): + angle = random.uniform(0, 2 * math.pi) + speed = random.uniform(3, 6) + size = random.uniform(4, 7) + self.particles.append({ + 'x': projectile.rect.x, + 'y': projectile.rect.y, + 'dx': math.cos(angle) * speed, + 'dy': math.sin(angle) * speed, + 'lifetime': 35, + 'color': (0, 200, 0), + 'size': size, + 'rotation': random.uniform(0, 360), + 'is_petal': True, + 'shape': 'leaf' + }) + # Add splash particle + self.particles.append({ + 'x': projectile.rect.x, + 'y': projectile.rect.y, + 'dx': math.cos(angle) * (speed * 0.8), + 'dy': math.sin(angle) * (speed * 0.8), + 'lifetime': 20, + 'color': (150, 255, 150), + 'size': size * 0.6, + 'is_petal': False + }) + + zombie.take_damage(projectile.damage) + if projectile.freezing: + zombie.freeze() + zombie.stun_timer = 2 + if zombie.health <= 0: + # Add death particles + for _ in range(12): + angle = random.uniform(0, 2 * math.pi) + speed = random.uniform(3, 6) + self.particles.append({ + 'x': zombie.rect.x + CELL_SIZE//2, + 'y': zombie.rect.y + CELL_SIZE//2, + 'dx': math.cos(angle) * speed, + 'dy': math.sin(angle) * speed, + 'lifetime': 30, + 'color': (139, 69, 19), # Brown for zombie parts + 'size': random.uniform(3, 6) + }) + self.zombies.remove(zombie) + self.score += 100 + if projectile in self.projectiles: + self.projectiles.remove(projectile) + break + + # Update particles + for particle in self.particles[:]: + particle['x'] += particle['dx'] + particle['y'] += particle['dy'] + particle['lifetime'] -= 1 + if particle['lifetime'] <= 0: + self.particles.remove(particle) + + # Check zombie-plant interactions + for zombie in self.zombies: + for plant in self.plants[:]: + if zombie.rect.colliderect(plant.rect): + zombie.eating = True + plant.health -= zombie.damage + if plant.health <= 0: + # Add plant death particles + for _ in range(8): + angle = random.uniform(0, 2 * math.pi) + speed = random.uniform(2, 4) + self.particles.append({ + 'x': plant.rect.x + CELL_SIZE//2, + 'y': plant.rect.y + CELL_SIZE//2, + 'dx': math.cos(angle) * speed, + 'dy': math.sin(angle) * speed, + 'lifetime': 25, + 'color': (0, 100, 0), # Dark green for plant parts + 'size': random.uniform(2, 5) + }) + self.plants.remove(plant) + zombie.eating = False + break + else: + zombie.eating = False + + def draw_lawn(self): + # Create a surface for the lawn at base size + lawn_surface = pygame.Surface((self.base_width, self.base_height)) + lawn_surface.fill(LAWN_GREEN) + + # Draw grid with better visuals + for row in range(GRID_ROWS): + for col in range(GRID_COLS): + rect = pygame.Rect( + col * CELL_SIZE, + row * CELL_SIZE + TOP_MARGIN, + CELL_SIZE, + CELL_SIZE + ) + if (row + col) % 2 == 0: + pygame.draw.rect(lawn_surface, (115, 235, 0), rect) + pygame.draw.rect(lawn_surface, (100, 200, 0), rect, 1) + + # Scale and blit to screen + scaled_surface = pygame.transform.scale(lawn_surface, self.screen.get_size()) + self.screen.blit(scaled_surface, (0, 0)) + + def draw_plant_menu(self): + menu_height = 100 * self.scale_y + menu_surface = pygame.Surface((self.screen.get_width(), menu_height), pygame.SRCALPHA) + pygame.draw.rect(menu_surface, (139, 69, 19, 200), (0, 0, self.screen.get_width(), menu_height)) + + # Get mouse position for hover effect + mouse_x, mouse_y = pygame.mouse.get_pos() + menu_y = mouse_y - (self.screen.get_height() - menu_height) + + # Plant cards + cards = [ + (PlantType.SUNFLOWER, YELLOW, 50), + (PlantType.PEASHOOTER, GREEN, 100), + (PlantType.ROSE_SHOOTER, (255, 192, 203), 125), # Pink color for rose + (PlantType.CHOMPER, (148, 0, 211), 150), + (PlantType.SNOW_PEA, (0, 191, 255), 175) + ] + + card_width = 70 * self.scale_x + card_height = 80 * self.scale_y + card_spacing = 90 * self.scale_x + + for i, (plant_type, color, cost) in enumerate(cards): + card_x = 10 * self.scale_x + i * card_spacing + card_rect = pygame.Rect(card_x, 10 * self.scale_y, card_width, card_height) + + # Check if card is hovered or selected + is_hovered = (0 <= menu_y <= card_height + 20 * self.scale_y and + card_x <= mouse_x <= card_x + card_width) + is_selected = self.selected_plant == plant_type + + # Draw card background with hover/selected effect + if is_selected: + # Glowing effect for selected card + glow_surface = pygame.Surface((card_width + 4, card_height + 4), pygame.SRCALPHA) + pygame.draw.rect(glow_surface, (*PLANT_STATS[plant_type]["color"], 128), + (0, 0, card_width + 4, card_height + 4)) + menu_surface.blit(glow_surface, (card_rect.x - 2, card_rect.y - 2)) + pygame.draw.rect(menu_surface, WHITE, + (card_rect.x - 2, card_rect.y - 2, card_width + 4, card_height + 4), + max(1, int(2 * self.scale_x))) + elif is_hovered: + # Hover effect + pygame.draw.rect(menu_surface, (255, 255, 255, 30), card_rect) + + pygame.draw.rect(menu_surface, color, card_rect) + + # Draw plant image on card + if plant_type in PLANT_DRAWINGS: + # Create a smaller surface for the plant + plant_surface = pygame.Surface((CELL_SIZE, CELL_SIZE), pygame.SRCALPHA) + PLANT_DRAWINGS[plant_type](plant_surface, 0, 0, CELL_SIZE) + # Scale it down to fit the card + scaled_size = (int(50 * self.scale_x), int(50 * self.scale_y)) + scaled_surface = pygame.transform.scale(plant_surface, scaled_size) + menu_surface.blit(scaled_surface, + (card_rect.x + 10 * self.scale_x, + card_rect.y + 5 * self.scale_y)) + + # Cost indicator with sun icon + sun_size = 10 * min(self.scale_x, self.scale_y) + pygame.draw.circle(menu_surface, YELLOW, + (card_rect.x + sun_size, card_rect.bottom - sun_size), + sun_size) + cost_text = self.small_font.render(str(cost), True, BLACK) + menu_surface.blit(cost_text, + (card_rect.x + sun_size * 2, + card_rect.bottom - sun_size * 1.5)) + + # Gray out if can't afford + if self.sun_points < cost: + gray_surface = pygame.Surface((card_width, card_height), pygame.SRCALPHA) + pygame.draw.rect(gray_surface, (128, 128, 128, 180), + (0, 0, card_width, card_height)) + menu_surface.blit(gray_surface, card_rect) + + self.screen.blit(menu_surface, (0, self.screen.get_height() - menu_height)) + + def draw_hud(self): + # Sun points + sun_size = 30 * min(self.scale_x, self.scale_y) + sun_icon = pygame.Surface((sun_size, sun_size), pygame.SRCALPHA) + pygame.draw.circle(sun_icon, YELLOW, (sun_size/2, sun_size/2), sun_size/2) + self.screen.blit(sun_icon, (10 * self.scale_x, 10 * self.scale_y)) + + sun_text = self.font.render(str(self.sun_points), True, BLACK) + self.screen.blit(sun_text, (45 * self.scale_x, 15 * self.scale_y)) + + # Wave number + wave_text = self.font.render(f"第 {self.wave_number} 波僵尸", True, BLACK) + self.screen.blit(wave_text, + (self.screen.get_width() - 200 * self.scale_x, + 15 * self.scale_y)) + + # Score + score_text = self.font.render(f"得分: {self.score}", True, BLACK) + self.screen.blit(score_text, + (self.screen.get_width()//2 - score_text.get_width()//2, + 15 * self.scale_y)) + + def draw_watermark(self): + watermark = self.small_font.render("ChatDev制作", True, (0, 0, 0, 128)) + watermark.set_alpha(128) # Make it semi-transparent + self.screen.blit(watermark, + (self.screen.get_width() - watermark.get_width() - 10, + self.screen.get_height() - watermark.get_height() - 10)) + + def run(self): + while True: + if self.state == GameState.MENU: + self.run_menu() + elif self.state == GameState.PLAYING: + self.run_game() + elif self.state == GameState.GAME_OVER: + self.run_game_over() + + def run_menu(self): + while self.state == GameState.MENU: + for event in pygame.event.get(): + if event.type == pygame.QUIT: + pygame.quit() + sys.exit() + elif event.type == pygame.MOUSEBUTTONDOWN: + if event.button == 1: # Left click + # Start game button area + button_rect = pygame.Rect( + self.screen.get_width()//2 - 100 * self.scale_x, + self.screen.get_height()//2, + 200 * self.scale_x, + 50 * self.scale_y + ) + if button_rect.collidepoint(event.pos): + self.state = GameState.PLAYING + self.reset_game() + elif event.type == pygame.VIDEORESIZE: + self.handle_resize(event) + + # Draw menu + self.screen.fill(LAWN_GREEN) + + # Draw title + title = self.large_font.render("植物大战僵尸", True, BLACK) + self.screen.blit(title, + (self.screen.get_width()//2 - title.get_width()//2, + self.screen.get_height()//4)) + + # Draw start button + button_rect = pygame.Rect( + self.screen.get_width()//2 - 100 * self.scale_x, + self.screen.get_height()//2, + 200 * self.scale_x, + 50 * self.scale_y + ) + pygame.draw.rect(self.screen, GREEN, button_rect) + pygame.draw.rect(self.screen, BLACK, button_rect, 2) + + start_text = self.font.render("开始游戏", True, BLACK) + self.screen.blit(start_text, + (self.screen.get_width()//2 - start_text.get_width()//2, + self.screen.get_height()//2 + 5 * self.scale_y)) + + self.draw_watermark() + + pygame.display.flip() + self.clock.tick(FPS) + + def run_game(self): + while self.state == GameState.PLAYING and not self.game_over: + for event in pygame.event.get(): + if event.type == pygame.QUIT: + pygame.quit() + sys.exit() + elif event.type == pygame.VIDEORESIZE: + self.handle_resize(event) + elif event.type == pygame.MOUSEBUTTONDOWN: + mouse_pos = pygame.mouse.get_pos() + real_pos = self.get_real_pos(mouse_pos) + if self.base_height - 100 <= real_pos[1] <= self.base_height: + menu_y = real_pos[1] - (self.base_height - 100) + if 10 <= menu_y <= 90: + card_x = int((real_pos[0] - 10) // 90) # Convert to integer + if 0 <= card_x <= 4: + plant_types = [ + PlantType.SUNFLOWER, + PlantType.PEASHOOTER, + PlantType.ROSE_SHOOTER, + PlantType.CHOMPER, + PlantType.SNOW_PEA + ] + if card_x < len(plant_types): + plant_type = plant_types[card_x] + if self.sun_points >= PLANT_STATS[plant_type]["cost"]: + self.selected_plant = plant_type + else: + self.handle_click(mouse_pos) + + # Update game state + self.spawn_zombie() + self.spawn_sun() + self.update_plants() + self.update_combat() + + # Wave management + self.wave_timer -= 1 + if self.wave_timer <= 0: + self.wave_number += 1 + self.wave_timer = 600 + + # Move entities + for zombie in self.zombies: + zombie.move() + if zombie.x <= 0: + self.game_over = True + self.state = GameState.GAME_OVER + + for sun in self.suns[:]: + sun.move() + if sun.lifetime <= 0: + self.suns.remove(sun) + + # Draw everything + self.draw_lawn() + + # Create a game surface at base size and draw everything on it + game_surface = pygame.Surface((self.base_width, self.base_height), pygame.SRCALPHA) + + for plant in self.plants: + plant.draw(game_surface) + + for zombie in self.zombies: + zombie.draw(game_surface) + + for projectile in self.projectiles: + projectile.draw(game_surface) + + for sun in self.suns: + sun.draw(game_surface) + + # Draw particles + for particle in self.particles: + if particle.get('is_petal', False): + # Draw shaped particles based on type + shape = particle.get('shape', 'petal') + particle_surface = pygame.Surface((particle['size'] * 2, particle['size'] * 2), pygame.SRCALPHA) + center = (particle['size'], particle['size']) + + if shape == 'petal': + # Draw rose petal shape + for angle in range(0, 360, 72): + rad = math.radians(angle + particle['rotation']) + petal_x = center[0] + math.cos(rad) * particle['size'] + petal_y = center[1] + math.sin(rad) * particle['size'] + pygame.draw.circle(particle_surface, particle['color'], + (int(petal_x), int(petal_y)), + int(particle['size'] * 0.6)) + + elif shape == 'snowflake': + # Draw snowflake shape + for angle in range(0, 360, 45): + rad = math.radians(angle + particle['rotation']) + # Draw main line + end_x = center[0] + math.cos(rad) * particle['size'] + end_y = center[1] + math.sin(rad) * particle['size'] + pygame.draw.line(particle_surface, particle['color'], + center, (int(end_x), int(end_y)), 2) + # Draw side branches + branch_length = particle['size'] * 0.5 + mid_x = center[0] + math.cos(rad) * particle['size'] * 0.6 + mid_y = center[1] + math.sin(rad) * particle['size'] * 0.6 + side_angle1 = rad + math.pi / 4 + side_angle2 = rad - math.pi / 4 + pygame.draw.line(particle_surface, particle['color'], + (int(mid_x), int(mid_y)), + (int(mid_x + math.cos(side_angle1) * branch_length), + int(mid_y + math.sin(side_angle1) * branch_length)), 2) + pygame.draw.line(particle_surface, particle['color'], + (int(mid_x), int(mid_y)), + (int(mid_x + math.cos(side_angle2) * branch_length), + int(mid_y + math.sin(side_angle2) * branch_length)), 2) + + elif shape == 'leaf': + # Draw leaf shape + points = [] + leaf_length = particle['size'] * 1.5 + leaf_width = particle['size'] * 0.8 + rad = math.radians(particle['rotation']) + + # Create leaf shape points + for t in range(0, 360, 10): + t_rad = math.radians(t) + x = center[0] + math.cos(rad) * leaf_length * math.cos(t_rad) - \ + math.sin(rad) * leaf_width * math.sin(t_rad) + y = center[1] + math.sin(rad) * leaf_length * math.cos(t_rad) + \ + math.cos(rad) * leaf_width * math.sin(t_rad) + points.append((int(x), int(y))) + + if len(points) > 2: + pygame.draw.polygon(particle_surface, particle['color'], points) + # Draw leaf vein + vein_start = center + vein_end = (int(center[0] + math.cos(rad) * leaf_length), + int(center[1] + math.sin(rad) * leaf_length)) + pygame.draw.line(particle_surface, (0, 150, 0), + vein_start, vein_end, 1) + + # Add fade out effect + alpha = int(255 * (particle['lifetime'] / 45)) + particle_surface.set_alpha(alpha) + game_surface.blit(particle_surface, + (particle['x'] - particle['size'], + particle['y'] - particle['size'])) + else: + # Draw regular circular particles + alpha = int(255 * (particle['lifetime'] / 30)) + color = (*particle['color'][:3], alpha) + pygame.draw.circle(game_surface, color, + (int(particle['x']), int(particle['y'])), + int(particle['size'])) + + # Scale and blit the game surface + scaled_surface = pygame.transform.scale(game_surface, self.screen.get_size()) + self.screen.blit(scaled_surface, (0, 0)) + + self.draw_plant_menu() + self.draw_hud() + self.draw_watermark() + + pygame.display.flip() + self.clock.tick(FPS) + + def run_game_over(self): + while self.state == GameState.GAME_OVER: + for event in pygame.event.get(): + if event.type == pygame.QUIT: + pygame.quit() + sys.exit() + elif event.type == pygame.MOUSEBUTTONDOWN: + if event.button == 1: # Left click + self.state = GameState.MENU + elif event.type == pygame.VIDEORESIZE: + self.handle_resize(event) + + # Draw game over screen + self.screen.fill((0, 0, 0)) # Black background + + # Draw game over text + game_over_text = self.large_font.render("游戏结束", True, RED) + score_text = self.font.render(f"最终得分: {self.score}", True, WHITE) + + self.screen.blit(game_over_text, + (self.screen.get_width()//2 - game_over_text.get_width()//2, + self.screen.get_height()//3)) + self.screen.blit(score_text, + (self.screen.get_width()//2 - score_text.get_width()//2, + self.screen.get_height()//2)) + + self.draw_watermark() + + pygame.display.flip() + self.clock.tick(FPS) + +if __name__ == "__main__": + game = Game() + game.run() \ No newline at end of file diff --git a/WareHouse/pvz_THUNLPDemo_2024/requirements.txt b/WareHouse/pvz_THUNLPDemo_2024/requirements.txt new file mode 100644 index 00000000..6ada1975 --- /dev/null +++ b/WareHouse/pvz_THUNLPDemo_2024/requirements.txt @@ -0,0 +1 @@ +pygame==2.5.2 \ No newline at end of file diff --git a/WareHouse/pvz_THUNLPDemo_2024/sprites.py b/WareHouse/pvz_THUNLPDemo_2024/sprites.py new file mode 100644 index 00000000..cc31f82a --- /dev/null +++ b/WareHouse/pvz_THUNLPDemo_2024/sprites.py @@ -0,0 +1,561 @@ +import pygame +import math +from constants import * + +def draw_sunflower(surface, x, y, size): + # Get animation offset based on time + time = pygame.time.get_ticks() + sway = math.sin(time * 0.003) * 3 + petal_spin = time * 0.002 + + # Draw stem with swaying animation + stem_points = [ + (x + size//2 + sway, y + size*3//4), + (x + size//2, y + size*7//8), + (x + size//2, y + size) + ] + pygame.draw.lines(surface, GREEN, False, stem_points, 3) + + # Draw leaves + leaf_color = (34, 139, 34) # Forest green + leaf_points = [ + (x + size//2, y + size*3//4), + (x + size//3, y + size*7//8), + (x + size//2, y + size*13//16) + ] + pygame.draw.polygon(surface, leaf_color, leaf_points) + leaf_points = [ + (x + size//2, y + size*3//4), + (x + size*2//3, y + size*7//8), + (x + size//2, y + size*13//16) + ] + pygame.draw.polygon(surface, leaf_color, leaf_points) + + # Draw center with gradient + center_x, center_y = x + size//2 + sway, y + size//2 + pygame.draw.circle(surface, (160, 82, 45), (center_x, center_y), size//4) # Dark brown + pygame.draw.circle(surface, (139, 69, 19), (center_x, center_y), size//5) # Medium brown + pygame.draw.circle(surface, (101, 67, 33), (center_x, center_y), size//6) # Light brown + + # Draw petals with rotation animation + petal_colors = [(255, 218, 0), (255, 200, 0), (255, 182, 0)] # Different yellow shades + for i, angle in enumerate(range(0, 360, 45)): + rad = math.radians(angle + petal_spin) + petal_x = center_x + math.cos(rad) * size//3 + petal_y = center_y + math.sin(rad) * size//3 + # Draw each petal with multiple layers for depth + pygame.draw.circle(surface, petal_colors[i % 3], (int(petal_x), int(petal_y)), size//6) + pygame.draw.circle(surface, petal_colors[(i + 1) % 3], (int(petal_x), int(petal_y)), size//8) + +def draw_peashooter(surface, x, y, size): + # Get animation offset + time = pygame.time.get_ticks() + sway = math.sin(time * 0.003) * 3 + + # Draw stem with swaying animation + stem_points = [ + (x + size//2 + sway, y + size*2//3), + (x + size//2, y + size*7//8), + (x + size//2, y + size) + ] + pygame.draw.lines(surface, GREEN, False, stem_points, 3) + + # Draw leaves + leaf_color = (34, 139, 34) + leaf_points = [ + (x + size//2, y + size*3//4), + (x + size//3, y + size*7//8), + (x + size//2, y + size*13//16) + ] + pygame.draw.polygon(surface, leaf_color, leaf_points) + + # Draw head with gradient + head_x = x + size//2 + sway + head_color = (0, 200, 0) + pygame.draw.ellipse(surface, head_color, (head_x - size//4, y + size//4, size//2, size//2)) + pygame.draw.ellipse(surface, (0, 180, 0), (head_x - size//5, y + size//3, size//2.5, size//2.5)) + + # Draw shooter with highlight + shooter_x = head_x + size//4 + shooter_color = (0, 100, 0) + pygame.draw.circle(surface, shooter_color, (int(shooter_x), y + size//2), size//7) + pygame.draw.circle(surface, (0, 150, 0), (int(shooter_x), y + size//2), size//10) + + # Draw eyes + eye_color = (0, 0, 0) + eye_x = head_x - size//8 + pygame.draw.ellipse(surface, eye_color, (eye_x, y + size//3, size//10, size//8)) + pygame.draw.ellipse(surface, eye_color, (eye_x + size//6, y + size//3, size//10, size//8)) + +def draw_wallnut(surface, x, y, size): + # Get animation offset + time = pygame.time.get_ticks() + wobble = math.sin(time * 0.004) * 2 + + # Draw main body with gradient and texture + nut_colors = [(139, 69, 19), (160, 82, 45), (205, 133, 63)] + for i, color in enumerate(nut_colors): + offset = i * 4 + pygame.draw.ellipse(surface, color, + (x + size//6 + offset + wobble, + y + size//6 + offset, + size*2//3 - offset*2, + size*2//3 - offset*2)) + + # Draw crack details + crack_color = (101, 67, 33) + crack_points = [ + (x + size//2, y + size//4), + (x + size*2//3, y + size//3), + (x + size//2, y + size//2) + ] + pygame.draw.lines(surface, crack_color, False, crack_points, 2) + + # Draw face with expression + eye_color = BLACK + blink = (time % 3000) < 200 # Blink every 3 seconds + if not blink: + # Draw eyes + pygame.draw.ellipse(surface, eye_color, (x + size//3, y + size//3, size//6, size//6)) + pygame.draw.ellipse(surface, eye_color, (x + size//2, y + size//3, size//6, size//6)) + # Draw white highlights in eyes + pygame.draw.circle(surface, WHITE, (x + size//3 + size//12, y + size//3 + size//12), size//20) + pygame.draw.circle(surface, WHITE, (x + size//2 + size//12, y + size//3 + size//12), size//20) + else: + # Draw closed eyes + pygame.draw.line(surface, eye_color, (x + size//3, y + size//3), (x + size//3 + size//6, y + size//3), 2) + pygame.draw.line(surface, eye_color, (x + size//2, y + size//3), (x + size//2 + size//6, y + size//3), 2) + + # Draw smile that changes with wobble + smile_rect = pygame.Rect(x + size//3 + wobble, y + size//2, size//3, size//6) + pygame.draw.arc(surface, eye_color, smile_rect, 0, math.pi, 2) + +def draw_chomper(surface, x, y, size): + # Get animation offset + time = pygame.time.get_ticks() + chomp = abs(math.sin(time * 0.004)) * size//4 + sway = math.sin(time * 0.003) * 3 + + # Draw stem with swaying animation + stem_points = [ + (x + size//2 + sway, y + size*2//3), + (x + size//2, y + size*7//8), + (x + size//2, y + size) + ] + pygame.draw.lines(surface, GREEN, False, stem_points, 4) + + # Draw head + head_color = (148, 0, 211) # Purple + head_x = x + size//2 + sway + + # Draw back of mouth + pygame.draw.ellipse(surface, (101, 0, 148), + (head_x - size//3, y + size//4, size*2//3, size//2)) + + # Draw tongue + tongue_color = (255, 105, 180) + tongue_points = [ + (head_x, y + size//2), + (head_x - size//4, y + size//2 + size//4), + (head_x + size//4, y + size//2 + size//4) + ] + pygame.draw.polygon(surface, tongue_color, tongue_points) + + # Draw mouth (upper and lower jaw) + jaw_points_upper = [ + (head_x - size//3, y + size//3), + (head_x + size//3, y + size//3), + (head_x + size//2, y + size//2), + (head_x - size//2, y + size//2) + ] + jaw_points_lower = [ + (head_x - size//3, y + size//2 + chomp), + (head_x + size//3, y + size//2 + chomp), + (head_x + size//2, y + size*2//3 + chomp), + (head_x - size//2, y + size*2//3 + chomp) + ] + pygame.draw.polygon(surface, head_color, jaw_points_upper) + pygame.draw.polygon(surface, head_color, jaw_points_lower) + + # Draw teeth + teeth_color = WHITE + tooth_width = size//8 + for tooth_x in range(int(head_x - size//3), int(head_x + size//3), tooth_width): + # Upper teeth + pygame.draw.polygon(surface, teeth_color, [ + (tooth_x, y + size//2), + (tooth_x + tooth_width//2, y + size//2 - size//8), + (tooth_x + tooth_width, y + size//2) + ]) + # Lower teeth + pygame.draw.polygon(surface, teeth_color, [ + (tooth_x, y + size//2 + chomp), + (tooth_x + tooth_width//2, y + size//2 + size//8 + chomp), + (tooth_x + tooth_width, y + size//2 + chomp) + ]) + +def draw_snow_pea(surface, x, y, size): + # Get animation offset + time = pygame.time.get_ticks() + sway = math.sin(time * 0.003) * 3 + ice_spin = time * 0.003 + + # Draw stem with swaying animation + stem_points = [ + (x + size//2 + sway, y + size*2//3), + (x + size//2, y + size*7//8), + (x + size//2, y + size) + ] + pygame.draw.lines(surface, GREEN, False, stem_points, 3) + + # Draw leaves with frost effect + leaf_color = (150, 200, 150) + leaf_points = [ + (x + size//2, y + size*3//4), + (x + size//3, y + size*7//8), + (x + size//2, y + size*13//16) + ] + pygame.draw.polygon(surface, leaf_color, leaf_points) + + # Draw head with ice effect + head_x = x + size//2 + sway + head_colors = [(0, 191, 255), (135, 206, 235), (176, 224, 230)] + for i, color in enumerate(head_colors): + offset = i * 3 + pygame.draw.ellipse(surface, color, + (head_x - size//4 + offset, + y + size//4 + offset, + size//2 - offset*2, + size//2 - offset*2)) + + # Draw ice crystals with rotation + crystal_color = (200, 232, 255) + for i in range(4): + angle = ice_spin + i * (math.pi/2) + crystal_x = head_x + math.cos(angle) * size//3 + crystal_y = y + size//2 + math.sin(angle) * size//3 + crystal_points = [ + (crystal_x, crystal_y - size//8), + (crystal_x + size//8, crystal_y), + (crystal_x, crystal_y + size//8), + (crystal_x - size//8, crystal_y) + ] + pygame.draw.polygon(surface, crystal_color, crystal_points) + + # Draw frost particles + for i in range(3): + particle_x = head_x + math.cos(time * 0.001 + i * 2) * size//4 + particle_y = y + size//2 + math.sin(time * 0.001 + i * 2) * size//4 + pygame.draw.circle(surface, (255, 255, 255, 128), + (int(particle_x), int(particle_y)), size//16) + +def draw_normal_zombie(surface, x, y, size): + # Get animation offset + time = pygame.time.get_ticks() + wobble = math.sin(time * 0.004) * 3 + + # Draw shadow + shadow_surface = pygame.Surface((size*2//3, size//4), pygame.SRCALPHA) + pygame.draw.ellipse(shadow_surface, (0, 0, 0, 64), (0, 0, size*2//3, size//4)) + surface.blit(shadow_surface, (x + size//6, y + size - size//8)) + + # Draw legs with walking animation + leg_color = (100, 100, 100) + leg_offset = abs(math.sin(time * 0.004)) * 5 + pygame.draw.line(surface, leg_color, + (x + size//2, y + size*2//3), + (x + size//3, y + size - leg_offset), 4) + pygame.draw.line(surface, leg_color, + (x + size//2, y + size*2//3), + (x + size*2//3, y + size - leg_offset), 4) + + # Draw tattered clothes + clothes_color = (50, 50, 50) + clothes_points = [ + (x + size//3, y + size//2), + (x + size*2//3, y + size//2), + (x + size*2//3, y + size*3//4), + (x + size//3, y + size*3//4) + ] + pygame.draw.polygon(surface, clothes_color, clothes_points) + + # Draw arms with swaying animation + arm_color = (100, 100, 100) + arm_sway = math.sin(time * 0.004) * 10 + pygame.draw.line(surface, arm_color, + (x + size//2, y + size//2), + (x + size//4 + arm_sway, y + size*2//3), 4) + pygame.draw.line(surface, arm_color, + (x + size//2, y + size//2), + (x + size*3//4 + arm_sway, y + size*2//3), 4) + + # Draw body with details + body_color = (169, 169, 169) + pygame.draw.ellipse(surface, body_color, + (x + size//3 + wobble, y + size//3, size//3, size//2)) + + # Draw head with details + head_color = (169, 169, 169) + pygame.draw.circle(surface, head_color, + (int(x + size//2 + wobble), int(y + size//3)), size//4) + + # Draw facial features + eye_color = (255, 0, 0) # Red eyes + pygame.draw.circle(surface, eye_color, + (int(x + size//2 - size//8 + wobble), int(y + size//3)), size//12) + pygame.draw.circle(surface, eye_color, + (int(x + size//2 + size//8 + wobble), int(y + size//3)), size//12) + + # Draw mouth + mouth_color = (100, 0, 0) + mouth_points = [ + (x + size//2 - size//6 + wobble, y + size//3 + size//6), + (x + size//2 + size//6 + wobble, y + size//3 + size//6), + (x + size//2 + wobble, y + size//3 + size//4) + ] + pygame.draw.polygon(surface, mouth_color, mouth_points) + +def draw_cone_zombie(surface, x, y, size): + # Draw base zombie + draw_normal_zombie(surface, x, y, size) + + # Get animation offset + time = pygame.time.get_ticks() + wobble = math.sin(time * 0.004) * 3 + + # Draw cone with details and shading + cone_colors = [(139, 69, 19), (160, 82, 45), (205, 133, 63)] # Different shades of brown + for i, color in enumerate(cone_colors): + offset = i * 2 + points = [ + (x + size//2 + wobble, y - size//6 + offset), + (x + size//3 + offset, y + size//3), + (x + size*2//3 - offset, y + size//3) + ] + pygame.draw.polygon(surface, color, points) + + # Draw cone damage (dents and scratches) + scratch_color = (101, 67, 33) + scratch_points = [ + (x + size//2 - size//8 + wobble, y + size//6), + (x + size//2 + size//8 + wobble, y + size//4) + ] + pygame.draw.lines(surface, scratch_color, False, scratch_points, 2) + +def draw_bucket_zombie(surface, x, y, size): + # Draw base zombie + draw_normal_zombie(surface, x, y, size) + + # Get animation offset + time = pygame.time.get_ticks() + wobble = math.sin(time * 0.004) * 3 + + # Draw bucket with metallic effect + bucket_colors = [(192, 192, 192), (169, 169, 169), (128, 128, 128)] + for i, color in enumerate(bucket_colors): + offset = i * 2 + pygame.draw.rect(surface, color, + (x + size//4 + offset + wobble, + y - size//6 + offset, + size//2 - offset*2, + size//3)) + + # Draw bucket rim + rim_color = (211, 211, 211) + pygame.draw.rect(surface, rim_color, + (x + size//4 - 2 + wobble, y - size//6, size//2 + 4, 4)) + + # Draw bucket highlights + highlight_color = (255, 255, 255) + pygame.draw.line(surface, highlight_color, + (x + size//3 + wobble, y), + (x + size*2//3 + wobble, y), 2) + + # Draw dents and damage + dent_color = (128, 128, 128) + pygame.draw.arc(surface, dent_color, + (x + size//3 + wobble, y, size//4, size//6), + 0, math.pi, 2) + +def draw_newspaper_zombie(surface, x, y, size): + # Draw base zombie + draw_normal_zombie(surface, x, y, size) + + # Get animation offset + time = pygame.time.get_ticks() + wobble = math.sin(time * 0.004) * 3 + paper_shake = math.sin(time * 0.008) * 2 + + # Draw newspaper with animated shaking + paper_color = (255, 255, 255) + pygame.draw.rect(surface, paper_color, + (x + size//6 + paper_shake, + y + size//3, + size//2, + size//2)) + + # Draw newspaper content (headlines and text) + text_color = (0, 0, 0) + for i in range(4): + y_pos = y + size//3 + i*size//8 + pygame.draw.line(surface, text_color, + (x + size//5 + paper_shake, y_pos), + (x + size*2//3 + paper_shake, y_pos), 1) + + # Draw newspaper damage + if time % 2000 < 1000: # Animate paper damage + tear_points = [ + (x + size//3 + paper_shake, y + size//3), + (x + size//2 + paper_shake, y + size//2), + (x + size//3 + paper_shake, y + size*2//3) + ] + pygame.draw.lines(surface, (200, 200, 200), False, tear_points, 2) + +def draw_dancing_zombie(surface, x, y, size): + # Get animation offset + time = pygame.time.get_ticks() + dance_move = math.sin(time * 0.006) * 10 + spin = math.sin(time * 0.003) * 0.3 + + # Draw shadow + shadow_surface = pygame.Surface((size*2//3, size//4), pygame.SRCALPHA) + pygame.draw.ellipse(shadow_surface, (0, 0, 0, 64), (0, 0, size*2//3, size//4)) + surface.blit(shadow_surface, (x + size//6, y + size - size//8)) + + # Draw legs in dancing pose + leg_color = (100, 100, 100) + pygame.draw.line(surface, leg_color, + (x + size//2, y + size//2), + (x + size//4 + dance_move, y + size), 4) + pygame.draw.line(surface, leg_color, + (x + size//2, y + size//2), + (x + size*3//4 - dance_move, y + size), 4) + + # Draw disco outfit + outfit_color = (148, 0, 211) # Purple + outfit_points = [ + (x + size//3 + dance_move/2, y + size//3), + (x + size*2//3 + dance_move/2, y + size//3), + (x + size*2//3 - dance_move/2, y + size*3//4), + (x + size//3 - dance_move/2, y + size*3//4) + ] + pygame.draw.polygon(surface, outfit_color, outfit_points) + + # Draw arms in dancing pose + arm_color = (100, 100, 100) + pygame.draw.line(surface, arm_color, + (x + size//2, y + size//2), + (x + size//4 - dance_move, y + size//3), 4) + pygame.draw.line(surface, arm_color, + (x + size//2, y + size//2), + (x + size*3//4 + dance_move, y + size//3), 4) + + # Draw body with disco moves + body_color = (169, 169, 169) + body_rect = pygame.Rect(x + size//3 + dance_move/2, y + size//4, + size//3, size//2) + rotated_surface = pygame.Surface((size, size), pygame.SRCALPHA) + pygame.draw.ellipse(rotated_surface, body_color, body_rect) + + # Draw head with cool hair + head_color = (169, 169, 169) + pygame.draw.circle(rotated_surface, head_color, + (int(x + size//2 + dance_move/2), int(y + size//3)), + size//4) + + # Draw spiky hair with animation + hair_color = (0, 0, 0) + for i in range(6): + angle = i * math.pi/3 + spin + hair_x = x + size//2 + math.cos(angle) * size//3 + dance_move/2 + hair_y = y + size//3 + math.sin(angle) * size//4 + pygame.draw.line(surface, hair_color, + (x + size//2 + dance_move/2, y + size//3), + (hair_x, hair_y), 3) + + # Draw sunglasses + glasses_color = (0, 0, 0) + pygame.draw.rect(surface, glasses_color, + (x + size//3 + dance_move/2, y + size//4, + size//3, size//8)) + + # Draw disco ball effect + for i in range(8): + angle = i * math.pi/4 + time * 0.01 + sparkle_x = x + size//2 + math.cos(angle) * size//2 + sparkle_y = y + size//3 + math.sin(angle) * size//2 + pygame.draw.circle(surface, (255, 255, 255), + (int(sparkle_x), int(sparkle_y)), 2) + +def draw_rose_shooter(surface, x, y, size): + # Get animation offset + time = pygame.time.get_ticks() + sway = math.sin(time * 0.003) * 3 + petal_spin = time * 0.002 + + # Draw stem with swaying animation + stem_points = [ + (x + size//2 + sway, y + size*2//3), + (x + size//2, y + size*7//8), + (x + size//2, y + size) + ] + pygame.draw.lines(surface, GREEN, False, stem_points, 3) + + # Draw leaves + leaf_color = (34, 139, 34) # Forest green + leaf_points = [ + (x + size//2, y + size*3//4), + (x + size//3, y + size*7//8), + (x + size//2, y + size*13//16) + ] + pygame.draw.polygon(surface, leaf_color, leaf_points) + + # Draw thorns + thorn_color = (139, 69, 19) # Brown + thorn_points = [ + [(x + size//2 - 5, y + size*3//4), (x + size//2 - 10, y + size*3//4 - 5), (x + size//2 - 5, y + size*3//4 - 5)], + [(x + size//2 + 5, y + size*3//4), (x + size//2 + 10, y + size*3//4 - 5), (x + size//2 + 5, y + size*3//4 - 5)] + ] + for points in thorn_points: + pygame.draw.polygon(surface, thorn_color, points) + + # Draw rose head with gradient + head_x = x + size//2 + sway + head_y = y + size//2 + rose_colors = [(255, 192, 203), (255, 182, 193), (255, 105, 180)] # Pink gradients + + # Draw petals in layers + for i, color in enumerate(rose_colors): + offset = i * 3 + for angle in range(0, 360, 45): + rad = math.radians(angle + petal_spin) + petal_x = head_x + math.cos(rad) * (size//4 - offset) + petal_y = head_y + math.sin(rad) * (size//4 - offset) + pygame.draw.circle(surface, color, (int(petal_x), int(petal_y)), size//6 - offset) + + # Draw center + pygame.draw.circle(surface, (139, 0, 0), (int(head_x), int(head_y)), size//8) # Dark red center + + # Draw shooter with highlight + shooter_x = head_x + size//4 + shooter_color = (255, 20, 147) # Deep pink + pygame.draw.circle(surface, shooter_color, (int(shooter_x), head_y), size//7) + pygame.draw.circle(surface, (255, 105, 180), (int(shooter_x), head_y), size//10) # Highlight + +# Dictionary mapping plant types to their drawing functions +PLANT_DRAWINGS = { + PlantType.SUNFLOWER: draw_sunflower, + PlantType.PEASHOOTER: draw_peashooter, + PlantType.ROSE_SHOOTER: draw_rose_shooter, + PlantType.CHOMPER: draw_chomper, + PlantType.SNOW_PEA: draw_snow_pea +} + +# Dictionary mapping zombie types to their drawing functions +ZOMBIE_DRAWINGS = { + ZombieType.NORMAL: draw_normal_zombie, + ZombieType.CONE: draw_cone_zombie, + ZombieType.BUCKET: draw_bucket_zombie, + ZombieType.NEWSPAPER: draw_newspaper_zombie, + ZombieType.DANCING: draw_dancing_zombie +} \ No newline at end of file diff --git a/WareHouse/snake_THUNLPDemo_2024/main.py b/WareHouse/snake_THUNLPDemo_2024/main.py new file mode 100644 index 00000000..44ffb2ba --- /dev/null +++ b/WareHouse/snake_THUNLPDemo_2024/main.py @@ -0,0 +1,251 @@ +import pygame +import random +import sys +import math + +# Initialize Pygame +pygame.init() + +# Colors +WHITE = (255, 255, 255) +RED = (255, 50, 50) +GREEN = (50, 255, 50) +BLUE = (50, 50, 255) +BLACK = (0, 0, 0) +DARK_GREEN = (34, 139, 34) +GOLD = (255, 215, 0) + +# Game settings +WINDOW_SIZE = 800 +GRID_SIZE = 20 +GRID_COUNT = WINDOW_SIZE // GRID_SIZE +GAME_SPEED = 10 + +# Create window +screen = pygame.display.set_mode((WINDOW_SIZE, WINDOW_SIZE)) +pygame.display.set_caption('贪吃蛇') +clock = pygame.time.Clock() + +# Load and create background texture +background = pygame.Surface((WINDOW_SIZE, WINDOW_SIZE)) +for y in range(0, WINDOW_SIZE, 4): + for x in range(0, WINDOW_SIZE, 4): + shade = random.randint(0, 20) + pygame.draw.rect(background, (shade, shade, shade), (x, y, 4, 4)) + +class Particle: + def __init__(self, x, y): + self.x = x + self.y = y + self.vx = random.uniform(-2, 2) + self.vy = random.uniform(-2, 2) + self.lifetime = 30 + self.color = (random.randint(200, 255), random.randint(200, 255), random.randint(0, 50)) + + def update(self): + self.x += self.vx + self.y += self.vy + self.lifetime -= 1 + + def draw(self, surface): + alpha = int((self.lifetime / 30) * 255) + particle_surface = pygame.Surface((4, 4), pygame.SRCALPHA) + particle_surface.fill((*self.color, alpha)) + surface.blit(particle_surface, (int(self.x), int(self.y))) + +class Snake: + def __init__(self): + self.body = [(GRID_COUNT//2, GRID_COUNT//2)] + self.direction = (1, 0) + self.grow = False + self.angle = 0 # For snake movement animation + + def move(self): + head = self.body[0] + new_head = (head[0] + self.direction[0], head[1] + self.direction[1]) + + if not self.grow: + self.body.pop() + else: + self.grow = False + + self.body.insert(0, new_head) + self.angle += 0.2 # Update movement animation + + def draw(self): + for i, segment in enumerate(self.body): + x = segment[0] * GRID_SIZE + y = segment[1] * GRID_SIZE + + # Create snake skin pattern with gradient + base_color = (34, max(50, 255 - (i * 8)), 34) + + # Add wave effect to snake body + offset = math.sin(self.angle + i * 0.3) * 2 + + # Draw main body segment with gradient + pygame.draw.rect(screen, base_color, (x, y + offset, GRID_SIZE-2, GRID_SIZE-2)) + + # Add scale pattern + if i > 0: + scale_color = (max(20, base_color[0] - 20), + max(20, base_color[1] - 20), + max(20, base_color[2] - 20)) + pygame.draw.arc(screen, scale_color, + (x + 2, y + offset + 2, GRID_SIZE-6, GRID_SIZE-6), + 0, 3.14, 2) + + # Draw head with special details + if i == 0: + # Draw eyes with shine effect + eye_size = GRID_SIZE // 4 + # Left eye + pygame.draw.circle(screen, WHITE, + (x + GRID_SIZE//3, y + offset + GRID_SIZE//3), eye_size) + pygame.draw.circle(screen, BLACK, + (x + GRID_SIZE//3, y + offset + GRID_SIZE//3), eye_size//2) + pygame.draw.circle(screen, WHITE, + (x + GRID_SIZE//3 - 1, y + offset + GRID_SIZE//3 - 1), eye_size//4) + + # Right eye + pygame.draw.circle(screen, WHITE, + (x + 2*GRID_SIZE//3, y + offset + GRID_SIZE//3), eye_size) + pygame.draw.circle(screen, BLACK, + (x + 2*GRID_SIZE//3, y + offset + GRID_SIZE//3), eye_size//2) + pygame.draw.circle(screen, WHITE, + (x + 2*GRID_SIZE//3 - 1, y + offset + GRID_SIZE//3 - 1), eye_size//4) + +class Food: + def __init__(self): + self.position = self.get_random_position() + self.angle = 0 + self.particles = [] + + def get_random_position(self): + return (random.randint(0, GRID_COUNT-1), random.randint(0, GRID_COUNT-1)) + + def update(self): + self.angle += 0.1 + + # Update particles + self.particles = [p for p in self.particles if p.lifetime > 0] + for particle in self.particles: + particle.update() + + def draw(self): + x = self.position[0] * GRID_SIZE + y = self.position[1] * GRID_SIZE + + # Draw particles + for particle in self.particles: + particle.draw(screen) + + # Draw apple with pulsing effect + size_mod = math.sin(self.angle) * 2 + apple_size = GRID_SIZE//2 - 2 + size_mod + + # Draw apple shadow + shadow_pos = (x + GRID_SIZE//2 + 2, y + GRID_SIZE//2 + 2) + pygame.draw.circle(screen, (20, 20, 20), shadow_pos, apple_size) + + # Draw apple body + apple_pos = (x + GRID_SIZE//2, y + GRID_SIZE//2) + pygame.draw.circle(screen, RED, apple_pos, apple_size) + + # Draw apple highlight + highlight_pos = (x + GRID_SIZE//2 - 2, y + GRID_SIZE//2 - 2) + pygame.draw.circle(screen, (255, 150, 150), highlight_pos, apple_size//3) + + # Draw leaf with animation + leaf_x = x + GRID_SIZE//2 + math.sin(self.angle) * 2 + leaf_y = y + math.cos(self.angle) * 2 + pygame.draw.ellipse(screen, GREEN, (leaf_x, leaf_y, GRID_SIZE//4, GRID_SIZE//3)) + +def draw_title_and_score(score): + # Draw game title + title_font = pygame.font.Font(None, 74) + title_text = title_font.render('Snake Game', True, GOLD) + title_shadow = title_font.render('Snake Game', True, (50, 50, 50)) + + # Add shadow effect + screen.blit(title_shadow, (WINDOW_SIZE//2 - title_text.get_width()//2 + 2, + 42)) + screen.blit(title_text, (WINDOW_SIZE//2 - title_text.get_width()//2, + 40)) + + # Draw score with fancy styling + score_font = pygame.font.Font(None, 48) + score_text = score_font.render(f'Score: {score}', True, WHITE) + score_shadow = score_font.render(f'Score: {score}', True, (50, 50, 50)) + + screen.blit(score_shadow, (12, 12)) + screen.blit(score_text, (10, 10)) + +def main(): + snake = Snake() + food = Food() + score = 0 + + while True: + for event in pygame.event.get(): + if event.type == pygame.QUIT: + pygame.quit() + sys.exit() + if event.type == pygame.KEYDOWN: + if event.key == pygame.K_UP and snake.direction != (0, 1): + snake.direction = (0, -1) + if event.key == pygame.K_DOWN and snake.direction != (0, -1): + snake.direction = (0, 1) + if event.key == pygame.K_LEFT and snake.direction != (1, 0): + snake.direction = (-1, 0) + if event.key == pygame.K_RIGHT and snake.direction != (-1, 0): + snake.direction = (1, 0) + + # Move snake + snake.move() + + # Update food animation + food.update() + + # Check collision with food + if snake.body[0] == food.position: + snake.grow = True + food.position = food.get_random_position() + score += 1 + # Add particles on food collection + x = food.position[0] * GRID_SIZE + y = food.position[1] * GRID_SIZE + for _ in range(20): + food.particles.append(Particle(x + GRID_SIZE//2, y + GRID_SIZE//2)) + + # Check collision with walls + head = snake.body[0] + if head[0] < 0 or head[0] >= GRID_COUNT or head[1] < 0 or head[1] >= GRID_COUNT: + pygame.quit() + sys.exit() + + # Check collision with self + if head in snake.body[1:]: + pygame.quit() + sys.exit() + + # Draw everything + screen.blit(background, (0, 0)) + + # Draw grid lines with fade effect + for i in range(GRID_COUNT): + alpha = abs(math.sin(i * 0.1 + pygame.time.get_ticks() * 0.001)) * 30 + 20 + grid_surface = pygame.Surface((WINDOW_SIZE, 1), pygame.SRCALPHA) + grid_surface.fill((50, 50, 50, int(alpha))) + screen.blit(grid_surface, (0, i * GRID_SIZE)) + screen.blit(grid_surface, (i * GRID_SIZE, 0)) + + snake.draw() + food.draw() + draw_title_and_score(score) + + pygame.display.flip() + clock.tick(GAME_SPEED) + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/WareHouse/tetris_THUNLPDemo_2024/README.md b/WareHouse/tetris_THUNLPDemo_2024/README.md new file mode 100644 index 00000000..1470e765 --- /dev/null +++ b/WareHouse/tetris_THUNLPDemo_2024/README.md @@ -0,0 +1,35 @@ +# Modern Tetris Game + +A feature-rich Tetris implementation in Python using Pygame. + +## Features +- Modern GUI with smooth animations +- Score system and levels +- Ghost piece preview +- Next piece preview +- Hold piece functionality +- Particle effects for line clears +- Background music and sound effects +- High score system + +## Controls +- Left/Right Arrow: Move piece +- Up Arrow: Rotate piece clockwise +- Z: Rotate piece counter-clockwise +- Down Arrow: Soft drop +- Space: Hard drop +- C: Hold piece +- P: Pause game +- ESC: Quit game + +## Installation +1. Install Python 3.8+ +2. Install dependencies: +```bash +pip install -r requirements.txt +``` + +3. Run the game: +```bash +python tetris.py +``` \ No newline at end of file diff --git a/WareHouse/tetris_THUNLPDemo_2024/highscore.txt b/WareHouse/tetris_THUNLPDemo_2024/highscore.txt new file mode 100644 index 00000000..cdb660b8 --- /dev/null +++ b/WareHouse/tetris_THUNLPDemo_2024/highscore.txt @@ -0,0 +1 @@ +700 \ No newline at end of file diff --git a/WareHouse/tetris_THUNLPDemo_2024/main.py b/WareHouse/tetris_THUNLPDemo_2024/main.py new file mode 100644 index 00000000..0f61aa44 --- /dev/null +++ b/WareHouse/tetris_THUNLPDemo_2024/main.py @@ -0,0 +1,680 @@ +import pygame +import random +import numpy as np +from typing import List, Tuple, Optional +import os +import math +import time + +# Initialize Pygame +pygame.init() +pygame.mixer.init() + +# Constants +BLOCK_SIZE = 30 +GRID_WIDTH = 10 +GRID_HEIGHT = 20 +PREVIEW_SIZE = 4 + +# Calculate window size +SIDE_PANEL_WIDTH = 200 +WINDOW_WIDTH = BLOCK_SIZE * GRID_WIDTH + SIDE_PANEL_WIDTH +WINDOW_HEIGHT = BLOCK_SIZE * GRID_HEIGHT + +# Colors +BLACK = (0, 0, 0) +WHITE = (255, 255, 255) +GRAY = (128, 128, 128) +COLORS = { + 'I': (0, 255, 255), # Cyan + 'O': (255, 255, 0), # Yellow + 'T': (128, 0, 128), # Purple + 'S': (0, 255, 0), # Green + 'Z': (255, 0, 0), # Red + 'J': (0, 0, 255), # Blue + 'L': (255, 165, 0), # Orange +} + +# Game settings +INITIAL_FALL_SPEED = 0.8 # Initial time between falls in seconds +SOFT_DROP_SPEED = 0.05 # Time between falls when soft dropping +SPEED_UP_FACTOR = 0.08 # How much to speed up per level +MIN_FALL_SPEED = 0.1 # Minimum fall speed +LOCK_DELAY = 0.5 # Time in seconds before piece locks in place +MAX_LOCK_RESETS = 15 # Maximum number of lock delay resets + +# Animation settings +MOVE_ANIMATION_SPEED = 0.05 # seconds (faster horizontal movement) +ROTATION_ANIMATION_SPEED = 0.08 # seconds +LINE_CLEAR_ANIMATION_TIME = 0.3 # seconds +FLASH_SPEED = 0.05 # seconds + +# Tetromino shapes +SHAPES = { + 'I': [[1, 1, 1, 1]], + 'O': [[1, 1], [1, 1]], + 'T': [[0, 1, 0], [1, 1, 1]], + 'S': [[0, 1, 1], [1, 1, 0]], + 'Z': [[1, 1, 0], [0, 1, 1]], + 'J': [[1, 0, 0], [1, 1, 1]], + 'L': [[0, 0, 1], [1, 1, 1]] +} + +class AnimationState: + def __init__(self): + self.move_progress = 0 + self.rotation_progress = 0 + self.line_clear_progress = 0 + self.flash_progress = 0 + self.last_pos = None + self.last_shape = None + self.target_pos = None + self.target_shape = None + self.lines_being_cleared = [] + self.flash_active = False + +class Particle: + def __init__(self, x: int, y: int, color: Tuple[int, int, int]): + self.x = x + self.y = y + self.color = color + self.velocity = [random.uniform(-3, 3), random.uniform(-8, -4)] + self.life = 255 + self.size = random.randint(2, 6) + self.rotation = random.uniform(0, 360) + self.rotation_speed = random.uniform(-5, 5) + + def update(self): + self.x += self.velocity[0] + self.y += self.velocity[1] + self.velocity[1] += 0.2 # Gravity + self.velocity[0] *= 0.99 # Air resistance + self.life -= 3 + self.rotation += self.rotation_speed + return self.life > 0 + + def draw(self, screen): + if self.life <= 0: + return + + alpha = max(0, min(255, self.life)) + color = (*self.color, alpha) + + # Create rotated particle + surface = pygame.Surface((self.size * 2, self.size * 2), pygame.SRCALPHA) + points = [ + (self.size + math.cos(math.radians(self.rotation)) * self.size, + self.size + math.sin(math.radians(self.rotation)) * self.size), + (self.size + math.cos(math.radians(self.rotation + 120)) * self.size, + self.size + math.sin(math.radians(self.rotation + 120)) * self.size), + (self.size + math.cos(math.radians(self.rotation + 240)) * self.size, + self.size + math.sin(math.radians(self.rotation + 240)) * self.size) + ] + pygame.draw.polygon(surface, color, points) + screen.blit(surface, (self.x - self.size, self.y - self.size)) + +class Tetris: + def __init__(self): + self.screen = pygame.display.set_mode((WINDOW_WIDTH, WINDOW_HEIGHT)) + pygame.display.set_caption('俄罗斯方块') + + self.clock = pygame.time.Clock() + self.grid = [[None for _ in range(GRID_WIDTH)] for _ in range(GRID_HEIGHT)] + self.current_piece = None + self.current_shape = None + self.current_pos = None + self.held_piece = None + self.can_hold = True + self.next_piece = self._get_random_piece() + self.game_over = False + self.score = 0 + self.level = 1 + self.lines_cleared = 0 + self.particles = [] + self.fall_speed = INITIAL_FALL_SPEED + self.current_fall_speed = INITIAL_FALL_SPEED + self.last_fall_time = time.time() + self.lock_delay_time = 0 + self.lock_delay_active = False + self.lock_reset_count = 0 + self.last_move_time = time.time() + self.paused = False + self.combo = 0 + self.force_down = False # New flag for forcing piece down + + # Animation state + self.animation = AnimationState() + + # Load high score + self.high_score = self._load_high_score() + + # Initialize fonts + self.font_big = pygame.font.Font(None, 48) + self.font_small = pygame.font.Font(None, 36) + + # Load sounds + self._load_sounds() + + # Background gradient + self.background = self._create_background() + + def _load_sounds(self): + # Create sounds directory if it doesn't exist + if not os.path.exists('sounds'): + os.makedirs('sounds') + + # Initialize empty/silent sounds + empty_sound = pygame.mixer.Sound(buffer=bytes([0]*44)) # Minimal silent sound + self.sounds = { + 'move': empty_sound, + 'rotate': empty_sound, + 'drop': empty_sound, + 'clear': empty_sound, + 'game_over': empty_sound + } + + def _create_background(self): + surface = pygame.Surface((WINDOW_WIDTH, WINDOW_HEIGHT)) + for y in range(WINDOW_HEIGHT): + progress = y / WINDOW_HEIGHT + color = ( + int(20 + 20 * math.sin(progress * math.pi)), + int(10 + 10 * math.sin(progress * math.pi * 2)), + int(40 + 20 * math.sin(progress * math.pi * 0.5)) + ) + pygame.draw.line(surface, color, (0, y), (WINDOW_WIDTH, y)) + return surface + + def _load_high_score(self) -> int: + try: + if os.path.exists('highscore.txt'): + with open('highscore.txt', 'r') as f: + return int(f.read()) + except: + pass + return 0 + + def _save_high_score(self): + with open('highscore.txt', 'w') as f: + f.write(str(self.high_score)) + + def _get_random_piece(self) -> str: + return random.choice(list(SHAPES.keys())) + + def new_piece(self): + self.current_piece = self.next_piece + self.next_piece = self._get_random_piece() + self.current_shape = SHAPES[self.current_piece] + self.current_pos = [0, GRID_WIDTH//2 - len(self.current_shape[0])//2] + self.can_hold = True + + # Reset animation state + self.animation.move_progress = 0 + self.animation.rotation_progress = 0 + self.animation.last_pos = self.current_pos.copy() + self.animation.last_shape = [row[:] for row in self.current_shape] + self.animation.target_pos = self.current_pos.copy() + self.animation.target_shape = [row[:] for row in self.current_shape] + + # Check if game over + if self._check_collision(): + self.game_over = True + self.sounds['game_over'].play() + + def hold_piece(self): + if not self.can_hold: + return + + self.sounds['rotate'].play() + + if self.held_piece is None: + self.held_piece = self.current_piece + self.new_piece() + else: + self.held_piece, self.current_piece = self.current_piece, self.held_piece + self.current_shape = SHAPES[self.current_piece] + self.current_pos = [0, GRID_WIDTH//2 - len(self.current_shape[0])//2] + + self.can_hold = False + + def rotate_piece(self, clockwise: bool = True): + if self.current_piece == 'O': + return + + self.sounds['rotate'].play() + + old_shape = self.current_shape + self.current_shape = np.rot90(self.current_shape, 1 if not clockwise else -1).tolist() + + # Update animation state + self.animation.last_shape = old_shape + self.animation.target_shape = self.current_shape + self.animation.rotation_progress = 0 + + if self._check_collision(): + self.current_shape = old_shape + self.animation.target_shape = old_shape + + def _check_collision(self) -> bool: + for y, row in enumerate(self.current_shape): + for x, cell in enumerate(row): + if cell: + grid_y = self.current_pos[0] + y + grid_x = self.current_pos[1] + x + + if (grid_x < 0 or grid_x >= GRID_WIDTH or + grid_y >= GRID_HEIGHT or + (grid_y >= 0 and self.grid[grid_y][grid_x] is not None)): + return True + return False + + def _get_ghost_position(self) -> List[int]: + ghost_pos = self.current_pos.copy() + temp = self.current_pos.copy() + + while True: + ghost_pos[0] += 1 + self.current_pos = ghost_pos.copy() + if self._check_collision(): + ghost_pos[0] -= 1 + self.current_pos = temp + break + return ghost_pos + + def move(self, dx: int, dy: int): + old_pos = self.current_pos.copy() + self.current_pos[1] += dx + self.current_pos[0] += dy + + if dx != 0: + self.sounds['move'].play() + + collision = self._check_collision() + if collision: + self.current_pos[1] -= dx + self.current_pos[0] -= dy + + if dy > 0: # If moving down caused collision + if not self.lock_delay_active: + # Start lock delay when piece first touches ground + self.lock_delay_active = True + self.lock_delay_time = time.time() + self.lock_reset_count = 0 + elif time.time() - self.lock_delay_time > LOCK_DELAY or self.force_down: + # Lock piece if lock delay expired or forced down + self._place_piece() + self._clear_lines() + self.new_piece() + self.lock_delay_active = False + self.force_down = False + return True + else: + # Reset lock delay if piece moved successfully and still touching ground + if self.lock_delay_active and self.lock_reset_count < MAX_LOCK_RESETS: + # Check if still touching ground after move + self.current_pos[0] += 1 + if self._check_collision(): + self.lock_delay_time = time.time() + self.lock_reset_count += 1 + self.current_pos[0] -= 1 + else: + # If piece is not touching ground, deactivate lock delay + self.current_pos[0] += 1 + if not self._check_collision(): + self.lock_delay_active = False + self.current_pos[0] -= 1 + + # Update animation state for horizontal movement only + if dx != 0: + self.animation.last_pos = old_pos + self.animation.target_pos = self.current_pos.copy() + self.animation.move_progress = 0 + return False + + def hard_drop(self): + self.sounds['drop'].play() + ghost_pos = self._get_ghost_position() + self.current_pos = ghost_pos + self.force_down = True # Force the piece to lock immediately + self.move(0, 1) # This will trigger the locking process + + def _place_piece(self): + for y, row in enumerate(self.current_shape): + for x, cell in enumerate(row): + if cell: + grid_y = self.current_pos[0] + y + grid_x = self.current_pos[1] + x + if 0 <= grid_y < GRID_HEIGHT: + self.grid[grid_y][grid_x] = self.current_piece + + # Create landing particles + for x in range(len(self.current_shape[0])): + color = COLORS[self.current_piece] + px = (self.current_pos[1] + x) * BLOCK_SIZE + py = (self.current_pos[0] + len(self.current_shape) - 1) * BLOCK_SIZE + for _ in range(5): + self.particles.append(Particle(px, py, color)) + + def _clear_lines(self): + lines_to_clear = [] + for y in range(GRID_HEIGHT): + if all(cell is not None for cell in self.grid[y]): + lines_to_clear.append(y) + + if not lines_to_clear: + self.combo = 0 + return + + self.sounds['clear'].play() + self.animation.lines_being_cleared = lines_to_clear + self.animation.line_clear_progress = 0 + self.animation.flash_active = True + self.animation.flash_progress = 0 + + # Create particles for cleared lines + for y in lines_to_clear: + for x in range(GRID_WIDTH): + color = COLORS[self.grid[y][x]] + px = x * BLOCK_SIZE + py = y * BLOCK_SIZE + for _ in range(5): # 5 particles per block + self.particles.append(Particle(px, py, color)) + + # Clear lines and update score + for y in lines_to_clear: + self.grid.pop(y) + self.grid.insert(0, [None] * GRID_WIDTH) + + lines_count = len(lines_to_clear) + self.lines_cleared += lines_count + + # Calculate score with combo bonus + self.combo += 1 + combo_multiplier = min(self.combo, 10) # Cap combo at 10x + base_score = [100, 300, 500, 800][lines_count - 1] + self.score += base_score * self.level * combo_multiplier + + self.level = self.lines_cleared // 10 + 1 + self.fall_speed = max(MIN_FALL_SPEED, + INITIAL_FALL_SPEED - (self.level - 1) * SPEED_UP_FACTOR) + + if self.score > self.high_score: + self.high_score = self.score + self._save_high_score() + + def _interpolate_position(self, progress: float) -> List[int]: + if self.animation.last_pos is None or self.animation.target_pos is None: + return self.current_pos + + # Only interpolate horizontal movement + return [ + self.current_pos[0], # Vertical position is always current + self.animation.last_pos[1] + (self.animation.target_pos[1] - self.animation.last_pos[1]) * progress + ] + + def draw(self): + # Draw background + self.screen.blit(self.background, (0, 0)) + + # Draw grid + for y in range(GRID_HEIGHT): + for x in range(GRID_WIDTH): + pygame.draw.rect(self.screen, GRAY, + (x * BLOCK_SIZE, y * BLOCK_SIZE, BLOCK_SIZE, BLOCK_SIZE), 1) + + # Draw placed pieces + for y in range(GRID_HEIGHT): + for x in range(GRID_WIDTH): + if self.grid[y][x]: + if y in self.animation.lines_being_cleared: + # Skip drawing blocks in lines being cleared during animation + if self.animation.line_clear_progress < LINE_CLEAR_ANIMATION_TIME: + continue + color = COLORS[self.grid[y][x]] + pygame.draw.rect(self.screen, color, + (x * BLOCK_SIZE, y * BLOCK_SIZE, BLOCK_SIZE, BLOCK_SIZE)) + pygame.draw.rect(self.screen, WHITE, + (x * BLOCK_SIZE, y * BLOCK_SIZE, BLOCK_SIZE, BLOCK_SIZE), 1) + + # Draw ghost piece + if self.current_piece: + ghost_pos = self._get_ghost_position() + for y, row in enumerate(self.current_shape): + for x, cell in enumerate(row): + if cell: + color = (*COLORS[self.current_piece], 128) + ghost_x = (ghost_pos[1] + x) * BLOCK_SIZE + ghost_y = (ghost_pos[0] + y) * BLOCK_SIZE + surface = pygame.Surface((BLOCK_SIZE, BLOCK_SIZE), pygame.SRCALPHA) + pygame.draw.rect(surface, color, (0, 0, BLOCK_SIZE, BLOCK_SIZE)) + self.screen.blit(surface, (ghost_x, ghost_y)) + + # Draw current piece with animation + if self.current_piece: + pos = self._interpolate_position(min(1, self.animation.move_progress / MOVE_ANIMATION_SPEED)) + + for y, row in enumerate(self.current_shape): + for x, cell in enumerate(row): + if cell: + color = COLORS[self.current_piece] + block_x = (pos[1] + x) * BLOCK_SIZE + block_y = (pos[0] + y) * BLOCK_SIZE + + # Apply rotation animation + if self.animation.rotation_progress < ROTATION_ANIMATION_SPEED: + progress = self.animation.rotation_progress / ROTATION_ANIMATION_SPEED + scale = 1 - math.sin(progress * math.pi) * 0.2 + + # Calculate center of rotation + center_x = pos[1] * BLOCK_SIZE + len(row) * BLOCK_SIZE / 2 + center_y = pos[0] * BLOCK_SIZE + len(self.current_shape) * BLOCK_SIZE / 2 + + # Adjust block position for rotation + block_x = center_x + (block_x - center_x) * scale + block_y = center_y + (block_y - center_y) * scale + + pygame.draw.rect(self.screen, color, + (block_x, block_y, BLOCK_SIZE, BLOCK_SIZE)) + pygame.draw.rect(self.screen, WHITE, + (block_x, block_y, BLOCK_SIZE, BLOCK_SIZE), 1) + + # Draw side panel + panel_x = GRID_WIDTH * BLOCK_SIZE + 10 + + # Draw next piece preview + next_text = self.font_small.render('Next:', True, WHITE) + self.screen.blit(next_text, (panel_x, 20)) + next_shape = SHAPES[self.next_piece] + for y, row in enumerate(next_shape): + for x, cell in enumerate(row): + if cell: + color = COLORS[self.next_piece] + pygame.draw.rect(self.screen, color, + (panel_x + x * BLOCK_SIZE, + 60 + y * BLOCK_SIZE, + BLOCK_SIZE, BLOCK_SIZE)) + pygame.draw.rect(self.screen, WHITE, + (panel_x + x * BLOCK_SIZE, + 60 + y * BLOCK_SIZE, + BLOCK_SIZE, BLOCK_SIZE), 1) + + # Draw held piece + held_text = self.font_small.render('Hold:', True, WHITE) + self.screen.blit(held_text, (panel_x, 160)) + if self.held_piece: + held_shape = SHAPES[self.held_piece] + for y, row in enumerate(held_shape): + for x, cell in enumerate(row): + if cell: + color = COLORS[self.held_piece] + if not self.can_hold: + color = tuple(c//2 for c in color) # Darken color + pygame.draw.rect(self.screen, color, + (panel_x + x * BLOCK_SIZE, + 200 + y * BLOCK_SIZE, + BLOCK_SIZE, BLOCK_SIZE)) + pygame.draw.rect(self.screen, WHITE, + (panel_x + x * BLOCK_SIZE, + 200 + y * BLOCK_SIZE, + BLOCK_SIZE, BLOCK_SIZE), 1) + + # Draw score and level + score_text = self.font_small.render(f'Score: {self.score}', True, WHITE) + self.screen.blit(score_text, (panel_x, 300)) + + high_score_text = self.font_small.render(f'High: {self.high_score}', True, WHITE) + self.screen.blit(high_score_text, (panel_x, 340)) + + level_text = self.font_small.render(f'Level: {self.level}', True, WHITE) + self.screen.blit(level_text, (panel_x, 380)) + + lines_text = self.font_small.render(f'Lines: {self.lines_cleared}', True, WHITE) + self.screen.blit(lines_text, (panel_x, 420)) + + if self.combo > 1: + combo_text = self.font_small.render(f'Combo: x{self.combo}', True, WHITE) + self.screen.blit(combo_text, (panel_x, 460)) + + # Draw particles + self.particles = [p for p in self.particles if p.update()] + for particle in self.particles: + particle.draw(self.screen) + + # Draw line clear flash effect + if self.animation.flash_active and self.animation.lines_being_cleared: + flash_alpha = int(255 * (1 - self.animation.flash_progress / FLASH_SPEED)) + if flash_alpha > 0: + flash_surface = pygame.Surface((WINDOW_WIDTH, WINDOW_HEIGHT), pygame.SRCALPHA) + for y in self.animation.lines_being_cleared: + pygame.draw.rect(flash_surface, (255, 255, 255, flash_alpha), + (0, y * BLOCK_SIZE, GRID_WIDTH * BLOCK_SIZE, BLOCK_SIZE)) + self.screen.blit(flash_surface, (0, 0)) + + # Draw game over or pause screen + if self.game_over: + self._draw_overlay("Game Over! Press R to restart") + elif self.paused: + self._draw_overlay("Paused") + + pygame.display.flip() + + def _draw_overlay(self, text: str): + overlay = pygame.Surface((WINDOW_WIDTH, WINDOW_HEIGHT)) + overlay.set_alpha(128) + overlay.fill(BLACK) + self.screen.blit(overlay, (0, 0)) + + text_surface = self.font_big.render(text, True, WHITE) + text_rect = text_surface.get_rect(center=(WINDOW_WIDTH//2, WINDOW_HEIGHT//2)) + self.screen.blit(text_surface, text_rect) + + def reset(self): + self.grid = [[None for _ in range(GRID_WIDTH)] for _ in range(GRID_HEIGHT)] + self.current_piece = None + self.current_shape = None + self.current_pos = None + self.held_piece = None + self.can_hold = True + self.next_piece = self._get_random_piece() + self.game_over = False + self.score = 0 + self.level = 1 + self.lines_cleared = 0 + self.particles = [] + self.fall_speed = INITIAL_FALL_SPEED + self.current_fall_speed = INITIAL_FALL_SPEED + self.last_fall_time = time.time() + self.lock_delay_time = 0 + self.lock_delay_active = False + self.lock_reset_count = 0 + self.combo = 0 + self.animation = AnimationState() + self.paused = False + self.new_piece() + + def update_animations(self, dt: float): + # Update move animation + if self.animation.move_progress < MOVE_ANIMATION_SPEED: + self.animation.move_progress += dt + + # Update rotation animation + if self.animation.rotation_progress < ROTATION_ANIMATION_SPEED: + self.animation.rotation_progress += dt + + # Update line clear animation + if self.animation.line_clear_progress < LINE_CLEAR_ANIMATION_TIME: + self.animation.line_clear_progress += dt + + # Update flash animation + if self.animation.flash_active: + self.animation.flash_progress += dt + if self.animation.flash_progress >= FLASH_SPEED: + self.animation.flash_active = False + self.animation.flash_progress = 0 + + def run(self): + self.new_piece() + last_time = time.time() + + while True: + current_time = time.time() + dt = current_time - last_time + last_time = current_time + + self.clock.tick(60) + + for event in pygame.event.get(): + if event.type == pygame.QUIT: + pygame.quit() + return + + if event.type == pygame.KEYDOWN: + if event.key == pygame.K_ESCAPE: + pygame.quit() + return + + if self.game_over: + if event.key == pygame.K_r: + self.reset() + continue + + if event.key == pygame.K_p: + self.paused = not self.paused + continue + + if self.paused: + continue + + if event.key == pygame.K_LEFT: + self.move(-1, 0) + elif event.key == pygame.K_RIGHT: + self.move(1, 0) + elif event.key == pygame.K_DOWN: + self.current_fall_speed = SOFT_DROP_SPEED + elif event.key == pygame.K_UP: + self.rotate_piece() + elif event.key == pygame.K_z: + self.rotate_piece(False) + elif event.key == pygame.K_SPACE: + self.hard_drop() + elif event.key == pygame.K_c: + self.hold_piece() + + elif event.type == pygame.KEYUP: + if event.key == pygame.K_DOWN: + self.current_fall_speed = self.fall_speed + + if not self.game_over and not self.paused: + # Update animations + self.update_animations(dt) + + # Handle automatic falling + if current_time - self.last_fall_time > self.current_fall_speed: + self.move(0, 1) # Move down one grid + self.last_fall_time = current_time + + self.draw() + +if __name__ == '__main__': + game = Tetris() + game.run() \ No newline at end of file diff --git a/WareHouse/tetris_THUNLPDemo_2024/requirements.txt b/WareHouse/tetris_THUNLPDemo_2024/requirements.txt new file mode 100644 index 00000000..79d7dcd9 --- /dev/null +++ b/WareHouse/tetris_THUNLPDemo_2024/requirements.txt @@ -0,0 +1,2 @@ +pygame==2.5.2 +numpy==1.24.3 \ No newline at end of file diff --git a/misc/car_game.png b/misc/car_game.png new file mode 100644 index 00000000..d62fd6f4 Binary files /dev/null and b/misc/car_game.png differ diff --git a/misc/pvz.png b/misc/pvz.png new file mode 100644 index 00000000..f47ae5f7 Binary files /dev/null and b/misc/pvz.png differ diff --git a/misc/snake_game.png b/misc/snake_game.png new file mode 100644 index 00000000..e4869004 Binary files /dev/null and b/misc/snake_game.png differ diff --git a/misc/tetris.png b/misc/tetris.png new file mode 100644 index 00000000..c12c7670 Binary files /dev/null and b/misc/tetris.png differ diff --git a/misc/tsinghua_bamboo_website.png b/misc/tsinghua_bamboo_website.png new file mode 100644 index 00000000..18b32d12 Binary files /dev/null and b/misc/tsinghua_bamboo_website.png differ