portaldacalheta.pt
  • หลัก
  • การเพิ่มขึ้นของระยะไกล
  • ผู้คนและทีมงาน
  • การวางแผนและการพยากรณ์
  • การออกแบบ Ux
เทคโนโลยี

สุดยอดคู่มือภาษาประมวลผลตอนที่ 2: การสร้างเกมง่ายๆ



นี่คือส่วนที่สองของคู่มือขั้นสูงสุดสำหรับภาษาประมวลผล ใน ส่วนแรก ฉันให้คำแนะนำแบบการประมวลผลภาษาพื้นฐาน ขั้นตอนต่อไปสำหรับคุณในการเรียนรู้การประมวลผลเป็นเพียงการเขียนโปรแกรมแบบลงมือปฏิบัติ

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



สร้างเกมง่ายๆด้วยภาษาประมวลผล



ก่อนที่เราจะเริ่มการสอนการประมวลผล ที่นี่ คือรหัสของแบบฝึกหัดโลโก้ DVD จากส่วนก่อนหน้า หากคุณมีคำถามใด ๆ อย่าลืมแสดงความคิดเห็น



บทช่วยสอนการประมวลผล: เกมง่ายๆ

เกม เราจะสร้างในบทช่วยสอนการประมวลผลนี้เป็นการผสมผสานระหว่าง Flappy Bird, Pong และ Brick Breaker เหตุผลที่ฉันเลือกเกมแบบนี้ก็คือมันมีแนวคิดส่วนใหญ่ที่ผู้เริ่มต้นต่อสู้ด้วยเมื่อเรียนรู้การพัฒนาเกม สิ่งนี้มาจากประสบการณ์ของฉันตั้งแต่ตอนที่ฉันเป็นผู้ช่วยสอนซึ่งช่วยให้โปรแกรมเมอร์มือใหม่เรียนรู้วิธีใช้การประมวลผล แนวคิดเหล่านี้รวมถึงแรงโน้มถ่วงการชนการรักษาคะแนนการจัดการหน้าจอที่แตกต่างกันและการโต้ตอบของแป้นพิมพ์ / เมาส์ Flappy Pong มีทั้งหมดอยู่ในนั้น

เล่นเกมเลย!



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

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



มาเริ่มกันเลย

ตึกเครื่องปัดโป่ง

บทช่วยสอนการประมวลผลขั้นตอนที่ # 1: เริ่มต้นและจัดการหน้าจอต่างๆ

ขั้นตอนแรกคือการเริ่มต้นโครงการของเรา สำหรับผู้เริ่มต้นเราจะเขียนการตั้งค่าและวาดบล็อกตามปกติไม่มีอะไรแปลกใหม่หรือแปลกใหม่ จากนั้นเราจะจัดการหน้าจอต่างๆ (หน้าจอเริ่มต้นหน้าจอเกมเกมบนหน้าจอ ฯลฯ ) จึงเกิดคำถามว่าเราจะให้ Processing แสดงหน้าที่ถูกต้องในเวลาที่ถูกต้องได้อย่างไร?



การทำงานนี้ให้สำเร็จนั้นค่อนข้างง่าย เราจะมีตัวแปรส่วนกลางที่เก็บข้อมูลของหน้าจอที่ใช้งานอยู่ในปัจจุบัน จากนั้นเราจะวาดเนื้อหาของหน้าจอที่ถูกต้องขึ้นอยู่กับตัวแปร ในบล็อกการวาดเราจะมีคำสั่ง if ที่ตรวจสอบตัวแปรและแสดงเนื้อหาของหน้าจอตามนั้น เมื่อใดก็ตามที่เราต้องการเปลี่ยนหน้าจอเราจะเปลี่ยนตัวแปรนั้นเป็นตัวระบุของหน้าจอที่เราต้องการให้แสดง จากที่กล่าวมานี่คือลักษณะของรหัสโครงกระดูกของเรา:

/********* VARIABLES *********/ // We control which screen is active by settings / updating // gameScreen variable. We display the correct screen according // to the value of this variable. // // 0: Initial Screen // 1: Game Screen // 2: Game-over Screen int gameScreen = 0; /********* SETUP BLOCK *********/ void setup() { size(500, 500); } /********* DRAW BLOCK *********/ void draw() { // Display the contents of the current screen if (gameScreen == 0) { initScreen(); } else if (gameScreen == 1) { gameScreen(); } else if (gameScreen == 2) { gameOverScreen(); } } /********* SCREEN CONTENTS *********/ void initScreen() { // codes of initial screen } void gameScreen() { // codes of game screen } void gameOverScreen() { // codes for game over screen } /********* INPUTS *********/ public void mousePressed() { // if we are on the initial screen when clicked, start the game if (gameScreen==0) { startGame(); } } /********* OTHER FUNCTIONS *********/ // This method sets the necessary variables to start the game void startGame() { gameScreen=1; }

สิ่งนี้อาจดูน่ากลัวในตอนแรก แต่ทั้งหมดที่เราทำคือสร้างโครงสร้างพื้นฐานและแยกส่วนต่างๆด้วยบล็อกความคิดเห็น



อย่างที่คุณเห็นเรากำหนดวิธีการที่แตกต่างกันสำหรับแต่ละหน้าจอที่จะแสดง ในบล็อกการวาดของเราเราเพียงแค่ตรวจสอบค่าของ gameScreen ของเรา ตัวแปรและเรียกใช้วิธีการที่เกี่ยวข้อง

ใน void mousePressed(){...} ส่วนหนึ่งเรากำลังฟังการคลิกเมาส์และถ้าหน้าจอที่ใช้งานเป็น 0 หน้าจอเริ่มต้นเราเรียกว่า startGame() วิธีการที่เริ่มเกมตามที่คุณคาดหวัง บรรทัดแรกของวิธีนี้เปลี่ยนไป gameScreen ตัวแปรเป็น 1 หน้าจอเกม



หากเข้าใจแล้วขั้นตอนต่อไปคือการใช้งานหน้าจอเริ่มต้นของเรา ในการทำเช่นนั้นเราจะแก้ไข initScreen() วิธี. นี่คือ:

void initScreen() { background(0); textAlign(CENTER); text('Click to start', height/2, width/2); }

ตอนนี้หน้าจอเริ่มต้นของเรามีพื้นหลังสีดำและข้อความง่ายๆ 'คลิกเพื่อเริ่ม' ซึ่งอยู่ตรงกลางและจัดให้อยู่ตรงกลาง แต่เมื่อเราคลิกไม่มีอะไรเกิดขึ้น เรายังไม่ได้ระบุเนื้อหาใด ๆ สำหรับหน้าจอเกมของเรา วิธีการ gameScreen() ไม่มีอะไรอยู่ในนั้นดังนั้นเราจึงไม่ครอบคลุมเนื้อหาก่อนหน้านี้ที่ดึงมาจากหน้าจอสุดท้าย (ข้อความ) โดยมี background() เป็นบรรทัดแรกของการวาด นั่นเป็นสาเหตุที่ยังคงมีข้อความอยู่แม้ว่า text() สายไม่ถูกเรียกอีกต่อไป (เช่นเดียวกับตัวอย่างลูกบอลเคลื่อนที่จากส่วนสุดท้ายซึ่งทิ้งร่องรอยไว้ข้างหลัง) . พื้นหลังยังคงเป็นสีดำด้วยเหตุผลเดิม มาเริ่มใช้งานหน้าจอเกมกันเลย

void gameScreen() { background(255); }

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

การสอนการประมวลผลขั้นตอนที่ # 2: การสร้างลูกบอลและการใช้แรงโน้มถ่วง

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

ขั้นแรกให้เพิ่มสิ่งต่อไปนี้:

วิธีรับ m3u8 url
... int ballX, ballY; int ballSize = 20; int ballColor = color(0); ... void setup() { ... ballX=width/4; ballY=height/5; } ... void gameScreen() { ... drawBall(); } ... void drawBall() { fill(ballColor); ellipse(ballX, ballY, ballSize, ballSize); }

เรากำหนดพิกัดเป็นตัวแปรทั่วโลกสร้างวิธีการวาดลูกบอลที่เรียกว่าจาก gameScreen วิธี. สิ่งเดียวที่เราต้องใส่ใจก็คือ เริ่มต้น พิกัด แต่เรากำหนดไว้ใน setup() เหตุผลที่เราทำเช่นนั้นคือเราต้องการให้ลูกบอลเริ่มต้นที่หนึ่งในสี่จากด้านซ้ายและหนึ่งในห้าจากด้านบน ไม่มีเหตุผลใดที่เราต้องการเป็นพิเศษ แต่นั่นเป็นจุดเริ่มต้นที่ดีสำหรับบอล ดังนั้นเราจึงจำเป็นต้องได้รับ width และ height ของร่างแบบไดนามิก ขนาดร่างถูกกำหนดเป็น setup() หลังจากบรรทัดแรก width และ height ไม่ได้ตั้งค่าไว้ก่อน setup() นั่นคือสาเหตุที่เราไม่สามารถบรรลุเป้าหมายนี้ได้หากเรากำหนดตัวแปรไว้ด้านบน

แรงโน้มถ่วง

ตอนนี้การใช้แรงโน้มถ่วงเป็นส่วนที่ง่าย มีเพียงเทคนิคเล็กน้อย นี่คือการนำไปใช้ก่อน:

... float gravity = 1; float ballSpeedVert = 0; ... void gameScreen() { ... applyGravity(); keepInScreen(); } ... void applyGravity() { ballSpeedVert += gravity; ballY += ballSpeedVert; } void makeBounceBottom(float surface) { ballY = surface-(ballSize/2); ballSpeedVert*=-1; } void makeBounceTop(float surface) { ballY = surface+(ballSize/2); ballSpeedVert*=-1; } // keep ball in the screen void keepInScreen() { // ball hits floor if (ballY+(ballSize/2) > height) { makeBounceBottom(height); } // ball hits ceiling if (ballY-(ballSize/2) <0) { makeBounceTop(0); } }

และผลลัพธ์คือ:

ลูกบอลที่กระเด้งไปเรื่อย ๆ ด้วยแรงโน้มถ่วงหลอก

ถือม้าของคุณนักฟิสิกส์ ฉันรู้ว่านั่นไม่ใช่ แรงโน้มถ่วงทำงานอย่างไรในชีวิตจริง . แต่นี่เป็นกระบวนการแอนิเมชั่นมากกว่าสิ่งอื่นใด ตัวแปรที่เรากำหนดเป็น gravity เป็นเพียงค่าตัวเลข - a float เพื่อให้เราสามารถใช้ค่าทศนิยมไม่ใช่แค่จำนวนเต็ม - ที่เราเพิ่มลงใน ballSpeedVert ในทุกวง และ ballSpeedVert คือความเร็วในแนวตั้งของลูกบอลซึ่งจะถูกเพิ่มเข้าไปในพิกัด Y ของลูกบอล (ballY) ในแต่ละลูป เราดูพิกัดของลูกบอลและตรวจสอบให้แน่ใจว่าอยู่ในหน้าจอ หากเราไม่ทำเช่นนั้นลูกบอลจะตกลงไปที่ไม่มีที่สิ้นสุด สำหรับตอนนี้ลูกบอลของเราเคลื่อนที่ในแนวตั้งเท่านั้น ดังนั้นเราจึงดูขอบเขตของพื้นและเพดานของหน้าจอ ด้วย keepInScreen() วิธีตรวจสอบว่า ballY ( + รัศมี) น้อยกว่า height และในทำนองเดียวกัน ballY ( - รัศมี) มากกว่า 0. หากไม่ตรงตามเงื่อนไขเราจะทำการตีกลับ (จากด้านล่างหรือด้านบน) ด้วย makeBounceBottom() และ makeBounceTop() วิธีการ ในการทำให้ลูกบอลเด้งเราเพียงแค่ย้ายลูกบอลไปยังตำแหน่งที่แน่นอนที่จะต้องเด้งและคูณความเร็วแนวตั้ง (ballSpeedVert) ด้วย -1 (การคูณด้วย -1 เปลี่ยนเครื่องหมาย) เมื่อค่าความเร็วมีเครื่องหมายลบการเพิ่มพิกัด Y ความเร็วจะกลายเป็น ballY + (-ballSpeedVert) ซึ่งก็คือ ballY - ballSpeedVert ดังนั้นลูกบอลจึงเปลี่ยนทิศทางทันทีด้วยความเร็วเท่ากัน จากนั้นเมื่อเราเพิ่ม gravity ถึง ballSpeedVert และ ballSpeedVert มีค่าเป็นลบเริ่มเข้าใกล้ 0 ในที่สุดจะกลายเป็น 0 และเริ่มเพิ่มขึ้นอีกครั้ง นั่นทำให้ลูกขึ้นขึ้นช้าลงหยุดและเริ่มล้ม

ลูกบอลกระดอนไปเรื่อย ๆ บนแร็กเกต

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

... float airfriction = 0.0001; float friction = 0.1; ... void applyGravity() { ... ballSpeedVert -= (ballSpeedVert * airfriction); } void makeBounceBottom(int surface) { ... ballSpeedVert -= (ballSpeedVert * friction); } void makeBounceTop(int surface) { ... ballSpeedVert -= (ballSpeedVert * friction); }

และตอนนี้กระบวนการแอนิเมชั่นของเราทำให้เกิดสิ่งนี้:

ลูกบอลกระดอน แต่มาหยุดลงเนื่องจากแรงเสียดทาน

ตามชื่อ, friction คือแรงเสียดทานพื้นผิวและ airfriction คือแรงเสียดทานของอากาศ เห็นได้ชัดว่า friction ต้องใช้ทุกครั้งที่ลูกบอลสัมผัสพื้นผิวใด ๆ airfriction อย่างไรก็ตามต้องใช้อย่างต่อเนื่อง นั่นคือสิ่งที่เราทำ applyGravity() วิธีการทำงานในแต่ละลูปดังนั้นเราจึงนำ 0.0001 เปอร์เซ็นต์ของมูลค่าปัจจุบันจาก ballSpeedVert ในทุกวง makeBounceBottom() และ makeBounceTop() วิธีการทำงานเมื่อลูกบอลสัมผัสพื้นผิวใด ๆ ดังนั้นในวิธีการเหล่านั้นเราได้ทำสิ่งเดียวกันในครั้งนี้ด้วย friction

การสอนการประมวลผลขั้นตอนที่ # 3: การสร้างไม้

ตอนนี้เราต้องการไม้เพื่อให้ลูกบอลกระเด้ง เราควรจะควบคุมแร็กเกต มาทำให้มันควบคุมได้ด้วยเมาส์ นี่คือรหัส:

... color racketColor = color(0); float racketWidth = 100; float racketHeight = 10; ... void gameScreen() { ... drawRacket(); ... } ... void drawRacket(){ fill(racketColor); rectMode(CENTER); rect(mouseX, mouseY, racketWidth, racketHeight); }

เรากำหนดสีความกว้างและความสูงของแร็กเกตเป็นตัวแปรสากลเราอาจต้องการให้เปลี่ยนระหว่างการเล่นเกม เราใช้วิธีการ drawRacket() ซึ่งทำในสิ่งที่ชื่อของมันแนะนำ เราตั้งค่า rectMode ไปที่กึ่งกลางดังนั้นแร็กเกตของเราจึงถูกจัดให้อยู่ตรงกลางเคอร์เซอร์ของเรา

ตอนนี้เราสร้างแร็กเกตแล้วเราต้องทำให้ลูกบอลเด้งขึ้นมา

... int racketBounceRate = 20; ... void gameScreen() { ... watchRacketBounce(); ... } ... void watchRacketBounce() { float overhead = mouseY - pmouseY; if ((ballX+(ballSize/2) > mouseX-(racketWidth/2)) && (ballX-(ballSize/2)

และนี่คือผลลัพธ์:

ลูกบอลกระเด้งบนแร็กเกต แต่หยุดลงเนื่องจากแรงเสียดทาน

แล้วอะไรล่ะ watchRacketBounce() ตรวจสอบให้แน่ใจหรือไม่ว่าแร็กเก็ตและลูกบอลชนกัน มีสองสิ่งที่ต้องตรวจสอบที่นี่ซึ่งก็คือถ้าลูกบอลและแร็กเกตเรียงกันทั้งแนวตั้งและแนวนอน คำสั่ง if แรกจะตรวจสอบว่าพิกัด X ของด้านขวาของลูกมากกว่าพิกัด X ของด้านซ้ายของไม้ (และอีกทางหนึ่ง) ถ้าเป็นเช่นนั้นคำสั่งที่สองจะตรวจสอบว่าระยะห่างระหว่างลูกบอลกับแร็กเกตน้อยกว่าหรือเท่ากับรัศมีของลูกบอลหรือไม่ (ซึ่งหมายความว่าพวกเขากำลังชนกัน) . ดังนั้นหากตรงตามเงื่อนไขเหล่านี้ makeBounceBottom() วิธีการเรียกและลูกบอลจะกระเด้งบนแร็กเกตของเรา (ที่ mouseY โดยที่แร็กเก็ตอยู่)

คุณสังเกตเห็นตัวแปร overhead ซึ่งคำนวณโดย mouseY - pmouseY? pmouseX และ pmouseY ตัวแปรเก็บพิกัดของเมาส์ไว้ที่เฟรมก่อนหน้า เนื่องจากเมาส์สามารถเคลื่อนที่ได้เร็วมากจึงมีโอกาสที่ดีที่เราจะตรวจไม่พบระยะห่างระหว่างลูกบอลและแร็กเก็ตอย่างถูกต้องในระหว่างเฟรมหากเมาส์เคลื่อนที่เข้าหาลูกบอลเร็วพอ ดังนั้นเราจึงนำความแตกต่างของพิกัดของเมาส์ระหว่างเฟรมมาพิจารณาในขณะที่ตรวจจับระยะทาง ยิ่งเมาส์เคลื่อนที่เร็วเท่าไหร่ก็ยิ่งยอมรับได้

เรายังใช้ overhead ด้วยเหตุผลอื่น เราตรวจจับได้ว่าเมาส์เคลื่อนที่ไปทางใดโดยการตรวจสอบเครื่องหมาย overhead หากค่าใช้จ่ายเป็นค่าลบเมาส์จะอยู่ด้านล่างของเฟรมก่อนหน้าดังนั้นเมาส์ (แร็กเก็ต) ของเราจึงเลื่อนขึ้น ในกรณีนี้เราต้องการเพิ่มความเร็วพิเศษให้กับลูกบอลและเคลื่อนที่ให้ไกลกว่าการตีกลับปกติเล็กน้อยเพื่อจำลองเอฟเฟกต์ของการตีลูกด้วยไม้ ถ้า overhead น้อยกว่า 0 เราเพิ่มลงใน ballY และ ballSpeedVert เพื่อให้ลูกบอลสูงขึ้นและเร็วขึ้น ดังนั้นยิ่งไม้ตีลูกเร็วเท่าไหร่ไม้นั้นก็จะเลื่อนขึ้นสูงและเร็วขึ้นเท่านั้น

บทช่วยสอนการประมวลผลขั้นตอนที่ # 4: การเคลื่อนที่ในแนวนอนและการควบคุมลูกบอล

ในส่วนนี้เราจะเพิ่มการเคลื่อนที่ในแนวนอนให้กับลูกบอล จากนั้นเราจะทำให้สามารถควบคุมลูกบอลในแนวนอนด้วยไม้ของเราได้ ไปเลย:

... // we will start with 0, but for we give 10 just for testing float ballSpeedHorizon = 10; ... void gameScreen() { ... applyHorizontalSpeed(); ... } ... void applyHorizontalSpeed(){ ballX += ballSpeedHorizon; ballSpeedHorizon -= (ballSpeedHorizon * airfriction); } void makeBounceLeft(float surface){ ballX = surface+(ballSize/2); ballSpeedHorizon*=-1; ballSpeedHorizon -= (ballSpeedHorizon * friction); } void makeBounceRight(float surface){ ballX = surface-(ballSize/2); ballSpeedHorizon*=-1; ballSpeedHorizon -= (ballSpeedHorizon * friction); } ... void keepInScreen() { ... if (ballX-(ballSize/2) width){ makeBounceRight(width); } }

และผลลัพธ์คือ:

ตอนนี้ลูกบอลที่กระดอนในแนวนอนเช่นกัน

แนวคิดตรงนี้เหมือนกับสิ่งที่เราทำสำหรับการเคลื่อนที่ในแนวตั้ง เราสร้างตัวแปรความเร็วแนวนอน ballSpeedHorizon เราได้สร้างวิธีการใช้ความเร็วแนวนอนกับ ballX และกำจัดแรงเสียดทานของอากาศ เราได้เพิ่มอีกสองคำสั่ง if ใน keepInScreen() วิธีการที่จะดูบอลสำหรับการตีขอบซ้ายและขวาของหน้าจอ ในที่สุดเราก็สร้าง makeBounceLeft() และ makeBounceRight() วิธีจัดการกับการตีกลับจากซ้ายและขวา

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

void watchRacketBounce() { ... if ((ballX+(ballSize/2) > mouseX-(racketWidth/2)) && (ballX-(ballSize/2)

ผลลัพธ์คือ:

ฟิสิกส์แนวนอนสไตล์ฝ่าวงล้อม

การเพิ่มบรรทัดง่ายๆลงใน watchRacketBounce() ได้งาน สิ่งที่เราทำคือเรากำหนดระยะห่างของจุดที่ลูกบอลกระทบจากกึ่งกลางไม้ด้วย ballX - mouseX จากนั้นเราทำให้เป็นความเร็วแนวนอน ความแตกต่างที่แท้จริงนั้นมากเกินไปดังนั้นฉันจึงลองสองสามครั้งและพบว่าหนึ่งในสิบของค่านี้ให้ความรู้สึกเป็นธรรมชาติที่สุด

บทช่วยสอนการประมวลผลขั้นตอนที่ # 5: การสร้างกำแพง

ภาพร่างของเราเริ่มดูเหมือนเกมมากขึ้นในแต่ละขั้นตอน ในขั้นตอนนี้เราจะเพิ่มกำแพงที่เคลื่อนไปทางซ้ายเช่นเดียวกับใน Flappy Bird:

... int wallSpeed = 5; int wallInterval = 1000; float lastAddTime = 0; int minGapHeight = 200; int maxGapHeight = 300; int wallWidth = 80; color wallColors = color(0); // This arraylist stores data of the gaps between the walls. Actuals walls are drawn accordingly. // [gapWallX, gapWallY, gapWallWidth, gapWallHeight] ArrayList walls = new ArrayList(); ... void gameScreen() { ... wallAdder(); wallHandler(); } ... void wallAdder() { if (millis()-lastAddTime > wallInterval) { int randHeight = round(random(minGapHeight, maxGapHeight)); int randY = round(random(0, height-randHeight)); // {gapWallX, gapWallY, gapWallWidth, gapWallHeight} int[] randWall = {width, randY, wallWidth, randHeight}; walls.add(randWall); lastAddTime = millis(); } } void wallHandler() { for (int i = 0; i

และสิ่งนี้ส่งผลให้:

ลูกบอลกระดอนผ่านระดับที่มีกำแพง

แม้ว่ารหัสจะดูยาวและน่ากลัว แต่ฉันสัญญาว่าไม่มีอะไรยากที่จะเข้าใจ สิ่งแรกที่ต้องสังเกตคือ ArrayList. สำหรับพวกคุณที่ไม่รู้ว่าอะไรเป็น ArrayList คือมันเป็นเพียงการนำ list ที่ทำหน้าที่เหมือน Array แต่มันก็มีข้อดีกว่า สามารถปรับขนาดได้มีวิธีการที่มีประโยชน์เช่น list.add(index), list.get(index) และ list.remove(index). เราเก็บข้อมูลผนังเป็นอาร์เรย์จำนวนเต็มภายในรายการอาร์เรย์ ข้อมูลที่เราเก็บไว้ในอาร์เรย์มีไว้สำหรับช่องว่างระหว่างสองผนัง อาร์เรย์ประกอบด้วยค่าต่อไปนี้:

[gap wall X, gap wall Y, gap wall width, gap wall height]

ผนังจริงวาดตามค่าผนังช่องว่าง โปรดทราบว่าสิ่งเหล่านี้สามารถจัดการได้ดีกว่าและสะอาดกว่าโดยใช้คลาส แต่เนื่องจากการใช้ Object Oriented Programming (OOP) ไม่ได้อยู่ในขอบเขตของบทช่วยสอนการประมวลผลนี้เราจึงจะจัดการกับมัน เรามีสองวิธีพื้นฐานในการจัดการกำแพง wallAdder() และ wallHandler.

wallAdder() เพียงแค่เพิ่มกำแพงใหม่ในทุกๆ wallInterval มิลลิวินาทีไปยังรายการอาร์เรย์ เรามีตัวแปรทั่วโลก lastAddTime ซึ่งเก็บเวลาที่เพิ่มกำแพงสุดท้าย (เป็นมิลลิวินาที) . หากปัจจุบันเป็นมิลลิวินาที millis() ลบมิลลิวินาทีที่เพิ่มล่าสุด lastAddTime มีขนาดใหญ่กว่าค่าช่วงเวลาของเรา wallInterval หมายความว่าถึงเวลาเพิ่มกำแพงใหม่แล้ว จากนั้นตัวแปรช่องว่างแบบสุ่มจะถูกสร้างขึ้นตามตัวแปรส่วนกลางที่กำหนดไว้ที่ด้านบนสุด จากนั้นวอลล์ใหม่ (อาร์เรย์จำนวนเต็มที่เก็บข้อมูล gap wall) จะถูกเพิ่มเข้าไปในรายการอาร์เรย์และ lastAddTime ถูกตั้งค่าเป็นมิลลิวินาทีปัจจุบัน millis()

ในการจัดทำคำชี้แจงปัญหา ผู้วิจัยจะพูดถึงแต่ละข้อต่อไปนี้ ยกเว้น

wallHandler() วนผ่านผนังปัจจุบันที่อยู่ในรายการอาร์เรย์ และสำหรับแต่ละรายการในแต่ละลูปจะเรียก wallRemover(i), wallMover(i) และ wallDrawer(i) ตามค่าดัชนีของรายการอาร์เรย์ วิธีการเหล่านี้ทำในสิ่งที่ชื่อแนะนำ wallDrawer() วาดผนังจริงตามข้อมูลผนังช่องว่าง มันจับอาร์เรย์ข้อมูลผนังจากรายการอาร์เรย์และเรียก rect() วิธีการวาดกำแพงตามที่ควรจะเป็น wallMover() วิธีการจับองค์ประกอบจากรายการอาร์เรย์เปลี่ยนตำแหน่ง X ตาม wallSpeed ตัวแปรส่วนกลาง สุดท้าย wallRemover() ลบกำแพงออกจากรายการอาร์เรย์ซึ่งอยู่นอกหน้าจอ หากเราไม่ทำเช่นนั้นการประมวลผลจะถือว่าพวกเขายังคงอยู่ในหน้าจอ และนั่นจะเป็นการสูญเสียประสิทธิภาพอย่างมาก ดังนั้นเมื่อนำกำแพงออกจากรายการอาร์เรย์ผนังจะไม่ถูกดึงออกจากลูปที่ตามมา

สิ่งที่ท้าทายสุดท้ายที่ต้องทำคือการตรวจจับการชนกันระหว่างลูกบอลกับกำแพง

void wallHandler() { for (int i = 0; i wallTopX) && (ballX-(ballSize/2)wallTopY) && (ballY-(ballSize/2)wallBottomX) && (ballX-(ballSize/2)wallBottomY) && (ballY-(ballSize/2)

watchWallCollision() วิธีการเรียกสำหรับแต่ละผนังในแต่ละวง เราจับพิกัดของกำแพงช่องว่างคำนวณพิกัดของผนังจริง (ด้านบนและด้านล่าง) และตรวจสอบว่าพิกัดของลูกบอลชนกับผนังหรือไม่

บทช่วยสอนการประมวลผลขั้นตอนที่ # 6: สุขภาพและคะแนน

ตอนนี้เราสามารถตรวจจับการชนกันของลูกบอลและกำแพงได้แล้วเราสามารถตัดสินใจเกี่ยวกับกลไกของเกมได้ หลังจากปรับแต่งเกมแล้วฉันก็สามารถทำให้เกมเล่นได้ แต่ถึงกระนั้นมันก็ยากมาก ความคิดแรกของฉันเกี่ยวกับเกมนี้คือทำให้มันเหมือน Flappy Bird เมื่อลูกบอลสัมผัสกำแพงเกมจะจบลง แต่แล้วฉันก็รู้ว่ามันเป็นไปไม่ได้ที่จะเล่น นี่คือสิ่งที่ฉันคิด:

ควรมีแถบสุขภาพอยู่ด้านบนของลูกบอล ลูกจะเสียสุขภาพในขณะที่สัมผัสกำแพง ด้วยตรรกะนี้จึงไม่สมเหตุสมผลที่จะทำให้ลูกบอลเด้งกลับจากกำแพง ดังนั้นเมื่อสุขภาพเป็น 0 เกมควรจะจบลงและเราควรเปลี่ยนเป็นเกมผ่านหน้าจอ ไปเลย:

int maxHealth = 100; float health = 100; float healthDecrease = 1; int healthBarWidth = 60; ... void gameScreen() { ... drawHealthBar(); ... } ... void drawHealthBar() { // Make it borderless: noStroke(); fill(236, 240, 241); rectMode(CORNER); rect(ballX-(healthBarWidth/2), ballY - 30, healthBarWidth, 5); if (health > 60) { fill(46, 204, 113); } else if (health > 30) { fill(230, 126, 34); } else { fill(231, 76, 60); } rectMode(CORNER); rect(ballX-(healthBarWidth/2), ballY - 30, healthBarWidth*(health/maxHealth), 5); } void decreaseHealth(){ health -= healthDecrease; if (health <= 0){ gameOver(); } }

และนี่คือการวิ่งง่ายๆ:

ลูกบอลที่มีแถบสุขภาพกระเด้งไปตามระดับทำให้เสียสุขภาพทุกครั้งที่ชนกับกำแพง

เราสร้างตัวแปรทั่วโลก health เพื่อรักษาสุขภาพของลูก จากนั้นสร้างเมธอด drawHealthBar() ซึ่งวาดรูปสี่เหลี่ยมสองอันที่ด้านบนของลูกบอล อันแรกคือแถบสุขภาพพื้นฐานอีกอันคือแถบที่แสดงสุขภาพปัจจุบัน ความกว้างของอันที่สองเป็นแบบไดนามิกและคำนวณด้วย healthBarWidth*(health/maxHealth) อัตราส่วนของสุขภาพปัจจุบันของเราเทียบกับความกว้างของแถบสุขภาพ สุดท้ายสีเติมจะถูกกำหนดตามค่าของสุขภาพ สุดท้าย แต่ไม่ท้ายสุด คะแนน :

... void gameOverScreen() { background(0); textAlign(CENTER); fill(255); textSize(30); text('Game Over', height/2, width/2 - 20); textSize(15); text('Click to Restart', height/2, width/2 + 10); } ... void wallAdder() { if (millis()-lastAddTime > wallInterval) { ... // added another value at the end of the array int[] randWall = {width, randY, wallWidth, randHeight, 0}; ... } } void watchWallCollision(int index) { ... int wallScored = wall[4]; ... if (ballX > gapWallX+(gapWallWidth/2) && wallScored==0) { wallScored=1; wall[4]=1; score(); } } void score() { score++; } void printScore(){ textAlign(CENTER); fill(0); textSize(30); text(score, height/2, 50); }

เราจำเป็นต้องทำประตูเมื่อบอลผ่านกำแพง แต่เราต้องเพิ่มสูงสุด 1 คะแนนต่อผนัง หมายความว่าหากลูกบอลผ่านกำแพงมากกว่าย้อนกลับและผ่านอีกครั้งไม่ควรเพิ่มคะแนนอื่น เพื่อให้บรรลุเป้าหมายนี้เราได้เพิ่มตัวแปรอื่นในอาร์เรย์ผนังช่องว่างภายในรายการอาร์เรย์ ตัวแปรใหม่เก็บ 0 หากลูกบอลยังไม่ผ่านกำแพงนั้นและ 1 ถ้าเป็นเช่นนั้น จากนั้นเราแก้ไข watchWallCollision() วิธี. เราได้เพิ่มเงื่อนไขที่ทำให้เกิดไฟ score() วิธีการและทำเครื่องหมายกำแพงว่าส่งผ่านเมื่อลูกบอลผ่านกำแพงที่ไม่ผ่านมาก่อน

ตอนนี้เราใกล้จะถึงจุดจบแล้ว สิ่งสุดท้ายที่ต้องทำคือใช้ click to restart บนเกมผ่านหน้าจอ เราจำเป็นต้องตั้งค่าตัวแปรทั้งหมดที่เราใช้เป็นค่าเริ่มต้นและเริ่มเกมใหม่ นี่คือ:

... public void mousePressed() { ... if (gameScreen==2){ restart(); } } ... void restart() { score = 0; health = maxHealth; ballX=width/4; ballY=height/5; lastAddTime = 0; walls.clear(); gameScreen = 0; }

มาเพิ่มสีสันกันดีกว่า

Flappy Pong ที่เสร็จสมบูรณ์ในสีเต็มรูปแบบ

โวลา! เรามี Flappy Pong!

คุณสามารถดูโค้ดเกมประมวลผลฉบับเต็มได้ ที่นี่ .

การพอร์ตประมวลผลโค้ดเกมไปยังเว็บโดยใช้ p5.js

p5.js เป็นไลบรารี JavaScript ที่มีไฟล์ คล้ายกันมาก ไวยากรณ์ของภาษาโปรแกรมการประมวลผล ไม่ใช่ไลบรารีที่สามารถเรียกใช้โค้ดการประมวลผลที่มีอยู่ได้ แทน p5.js ต้องการการเขียนโค้ด JavaScript จริงซึ่งคล้ายกับพอร์ต JavaScript ของการประมวลผลที่เรียกว่า Processing.js . หน้าที่ของเราคือการแปลงรหัสการประมวลผลเป็น JavaScript โดยใช้ p5.js API ไลบรารีมีชุดของฟังก์ชันและไวยากรณ์ที่คล้ายกับการประมวลผลและเราต้องทำการเปลี่ยนแปลงบางอย่างกับโค้ดของเราเพื่อให้ทำงานใน JavaScript ได้ แต่เนื่องจากทั้งการประมวลผลและ JavaScript มีความคล้ายคลึงกันกับ Java จึงเป็นการก้าวกระโดดน้อยกว่าที่คิด . แม้ว่าคุณจะไม่ได้เป็น นักพัฒนา JavaScript การเปลี่ยนแปลงเป็นเรื่องเล็กน้อยมากและคุณควรจะทำตามได้ดี

ก่อนอื่นเราต้องสร้าง index.html ง่ายๆ และเพิ่ม p5.min.js ไปยังส่วนหัวของเรา เราต้องสร้างไฟล์อื่นชื่อ flappy_pong.js ซึ่งจะเป็นที่ตั้งของรหัสที่แปลงแล้วของเรา

Flappy Pong canvas { box-shadow: 0 0 20px lightgray; }

กลยุทธ์ของเราในขณะแปลงรหัสควรคัดลอกและวางโค้ดทั้งหมดของเราลงใน flappy_pong.js แล้วทำการเปลี่ยนแปลงทั้งหมด และนั่นคือสิ่งที่ฉันทำ และนี่คือขั้นตอนที่ฉันดำเนินการเพื่ออัปเดตโค้ด:

  • Javascript เป็นภาษาที่ไม่ได้พิมพ์ (ไม่มีการประกาศประเภทเช่น int และ float) ดังนั้นเราจำเป็นต้องเปลี่ยนการประกาศประเภททั้งหมดเป็น var

  • ไม่มี void ใน Javascript เราควรเปลี่ยนทั้งหมดเป็น function.

  • เราจำเป็นต้องลบการประกาศประเภทของอาร์กิวเมนต์ออกจากลายเซ็นของฟังก์ชัน (เช่น. void wallMover(var index) { ถึง function wallMover(index) {)

  • ไม่มี ArrayList ใน JavaScript แต่เราสามารถบรรลุสิ่งเดียวกันได้โดยใช้อาร์เรย์ JavaScript เราทำการเปลี่ยนแปลงต่อไปนี้:

    • ArrayList walls = new ArrayList(); ถึง var walls = [];
    • walls.clear(); ถึง walls = [];
    • walls.add(randWall); ถึง walls.push(randWall);
    • walls.remove(index); ถึง walls.splice(index,1);
    • walls.get(index); ถึง walls[index]
    • walls.size() ถึง walls.length
  • เปลี่ยนการประกาศอาร์เรย์ var randWall = {width, randY, wallWidth, randHeight, 0}; ถึง var randWall = [width, randY, wallWidth, randHeight, 0];

  • ลบทั้งหมด public คำหลัก

  • ย้ายทั้งหมด color(0) ประกาศเป็น function setup() เพราะ color() จะไม่ถูกกำหนดไว้ก่อน setup() โทร.

  • เปลี่ยน size(500, 500); ถึง createCanvas(500, 500);

  • เปลี่ยนชื่อ function gameScreen(){ เป็นอย่างอื่นเช่น function gamePlayScreen(){ เพราะเรามีตัวแปร global ชื่อ gameScreen แล้ว เมื่อเราทำงานกับการประมวลผลหนึ่งคือฟังก์ชันและอีกฟังก์ชันหนึ่งคือ int ตัวแปร. แต่ JavaScript ทำให้สิ่งเหล่านี้สับสนเนื่องจากไม่ได้พิมพ์

  • สิ่งเดียวกันสำหรับ score(). ฉันเปลี่ยนชื่อเป็น addScore().

คุณสามารถดูโค้ด JavaScript ที่ครอบคลุมทุกอย่างในบทช่วยสอนการประมวลผลนี้ได้ ที่นี่ .

ประมวลผลรหัสเกม: คุณก็ทำได้เช่นกัน

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

ทำความเข้าใจพื้นฐาน

ภาษาประมวลผลมีพื้นฐานมาจากอะไร?

การประมวลผลขึ้นอยู่กับ Java เนื่องจาก JavaScript มีลักษณะคล้ายกับ Java บนพื้นผิวการพอร์ตการประมวลผลโค้ดไปยังเว็บจึงค่อนข้างตรงไปตรงมาโดยใช้ไลบรารี JavaScript p5.js

'โรคหลอดเลือดสมอง' ในการประมวลผลคืออะไร?

เส้นขีดหมายถึงเส้นขอบที่วาดรอบรูปร่าง

ลอยทำอะไรในการประมวลผล?

float ถือค่าทศนิยม ในทางตรงกันข้าม int สามารถเก็บค่าจำนวนเต็มได้เท่านั้น (จำนวนเต็มบวกหรือลบ)

การออกแบบที่ขับเคลื่อนด้วยข้อมูลและการออกแบบที่สร้างขึ้น - ภาพรวม

การออกแบบมือถือ

การออกแบบที่ขับเคลื่อนด้วยข้อมูลและการออกแบบที่สร้างขึ้น - ภาพรวม
Brutalist Web Design, Minimalist Web Design และอนาคตของ Web UX

Brutalist Web Design, Minimalist Web Design และอนาคตของ Web UX

การออกแบบ Ui

โพสต์ยอดนิยม
ความจริงเสมือนในอุตสาหกรรมยานยนต์
ความจริงเสมือนในอุตสาหกรรมยานยนต์
วิธีใช้ Bootstrap และสร้าง. NET Projects
วิธีใช้ Bootstrap และสร้าง. NET Projects
วิธีทำความเข้าใจและประเมินการลงทุนในกองทุนอสังหาริมทรัพย์ส่วนบุคคล
วิธีทำความเข้าใจและประเมินการลงทุนในกองทุนอสังหาริมทรัพย์ส่วนบุคคล
4 ไปวิจารณ์ภาษา
4 ไปวิจารณ์ภาษา
ข้อมูลเบื้องต้นเกี่ยวกับ Magento: การนำทางในระบบนิเวศอีคอมเมิร์ซยอดนิยม
ข้อมูลเบื้องต้นเกี่ยวกับ Magento: การนำทางในระบบนิเวศอีคอมเมิร์ซยอดนิยม
 
วีซ่า H-1B: การเดินทางของนักพัฒนา iOS จากฮอนดูรัสไปยัง Silicon Valley
วีซ่า H-1B: การเดินทางของนักพัฒนา iOS จากฮอนดูรัสไปยัง Silicon Valley
ข้อผิดพลาดทั่วไปในการสื่อสารกับลูกค้า: จะไม่ทำให้ลูกค้าของคุณผิดหวังได้อย่างไร
ข้อผิดพลาดทั่วไปในการสื่อสารกับลูกค้า: จะไม่ทำให้ลูกค้าของคุณผิดหวังได้อย่างไร
การออกแบบที่คาดหวัง: วิธีสร้างประสบการณ์ผู้ใช้ที่มีมนต์ขลัง
การออกแบบที่คาดหวัง: วิธีสร้างประสบการณ์ผู้ใช้ที่มีมนต์ขลัง
กราฟิก 3 มิติ: บทช่วยสอน WebGL
กราฟิก 3 มิติ: บทช่วยสอน WebGL
การออกแบบ VUI - Voice User Interface
การออกแบบ VUI - Voice User Interface
โพสต์ยอดนิยม
  • scrum vs คัมบัง vs ลีน
  • เพิ่มเงินในการแฮ็คบัตรเครดิต
  • กฎหกประการของการจัดระเบียบการรับรู้
  • c เรียนยากแค่ไหน
  • mysql_set_charset
  • วิธีเพิ่มทุนเริ่มต้น
  • กวดวิชาขั้นสูง c++
หมวดหมู่
  • การเพิ่มขึ้นของระยะไกล
  • ผู้คนและทีมงาน
  • การวางแผนและการพยากรณ์
  • การออกแบบ Ux
  • © 2022 | สงวนลิขสิทธิ์

    portaldacalheta.pt