當(dāng)前位置:首頁(yè) > 工業(yè)控制 > 電路設(shè)計(jì)項(xiàng)目集錦
[導(dǎo)讀]這個(gè)代碼提供了一個(gè)簡(jiǎn)單但引人入勝的坦克戰(zhàn)斗游戲體驗(yàn),結(jié)合了基本的移動(dòng),射擊和碰撞檢測(cè)機(jī)制。

這個(gè)代碼提供了一個(gè)簡(jiǎn)單但引人入勝的坦克戰(zhàn)斗游戲體驗(yàn),結(jié)合了基本的移動(dòng),射擊和碰撞檢測(cè)機(jī)制。

這段代碼使用Arduino和Adafruit SSD1306庫(kù)在OLED顯示器上實(shí)現(xiàn)了一個(gè)基本的坦克戰(zhàn)斗游戲。以下是游戲的主要特點(diǎn)和功能:

?玩家坦克:玩家控制一輛坦克,它可以通過(guò)連接到特定引腳的按鈕向上、向下、向左和向右移動(dòng)。坦克定時(shí)自動(dòng)發(fā)射子彈。

?敵人坦克:有6輛敵人坦克在屏幕上隨機(jī)移動(dòng)。每個(gè)敵方坦克也會(huì)向玩家的坦克發(fā)射子彈。

?子彈:玩家和敵人的坦克都會(huì)射擊子彈。子彈的速度是坦克移動(dòng)速度的兩倍。當(dāng)玩家的子彈擊中敵人的坦克時(shí),敵人的坦克就會(huì)被摧毀,玩家就會(huì)獲得一分。敵人的子彈不會(huì)影響其他敵人的坦克。

?碰撞檢測(cè):游戲檢查玩家的子彈與敵人坦克之間的碰撞,以及敵人的子彈與玩家坦克之間的碰撞。如果敵人的子彈擊中玩家的坦克,玩家就會(huì)失去一條生命。

?生命和得分:玩家一開始有三條生命。每摧毀一輛敵方坦克,玩家的分?jǐn)?shù)就會(huì)增加。如果玩家失去所有三條生命,游戲?qū)@示“游戲結(jié)束”并重置。

?游戲重置:當(dāng)玩家的生命值為零時(shí),游戲會(huì)顯示“游戲結(jié)束”屏幕,然后重新開始,重置分?jǐn)?shù)、玩家生命值和敵方坦克位置。

?顯示:游戲在OLED屏幕上顯示,游戲區(qū)和計(jì)分區(qū)用一條豎線隔開。得分區(qū)域顯示當(dāng)前得分和剩余命值。

?初始化和設(shè)置:在游戲開始時(shí),敵人的坦克會(huì)出現(xiàn),玩家的坦克會(huì)出現(xiàn)在屏幕的中下方。游戲以一個(gè)顯示“Tank Battle”的啟動(dòng)畫面開始。

圖表

坦克戰(zhàn)

這個(gè)代碼提供了一個(gè)簡(jiǎn)單但引人入勝的坦克戰(zhàn)斗游戲體驗(yàn),結(jié)合了基本的移動(dòng),射擊和碰撞檢測(cè)機(jī)制。

代碼

#include

#include

#include

// Define constants

const int ENEMY_COUNT = 6;

const int SCREEN_WIDTH = 128;

const int SCREEN_HEIGHT = 64;

const int GAME_AREA_WIDTH = 100; // Game area width

const int SCORE_AREA_WIDTH = SCREEN_WIDTH - GAME_AREA_WIDTH; // Score area width

const int TANK_WIDTH = 6; // Tank width reduced by 5 times

const int TANK_HEIGHT = 6; // Tank height reduced by 5 times

const int BULLET_SPEED = 5; // Bullet speed

const int PLAYER_SHOT_INTERVAL = 1000; // Player tank firing interval in milliseconds

const int LIVES = 3; // Initial number of player tank lives

// Define I2C address and reset pin

#define OLED_RESET -1 // Use default reset pin

#define SCREEN_ADDRESS 0x3C

// Initialize OLED display

Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);

// Define direction enumeration

enum Direction { LEFT, RIGHT, UP, DOWN };

// Enemy structure

struct Enemy {

int x, y; // Position

int dx, dy; // Increment per frame

Direction dir; // Current moving direction

unsigned long lastShotTime; // Last firing time

bool active; // Whether the enemy is active

};

// Bullet structure

struct Bullet {

int x, y; // Position

int dx, dy; // Increment per frame

Direction dir; // Bullet direction

bool active; // Whether activated

};

// Global variables

Enemy enemies[ENEMY_COUNT];

Bullet bullets[10]; // Assume a maximum of 10 bullets at the same time

int playerX = GAME_AREA_WIDTH / 2 - TANK_WIDTH / 2; // Initial position of the player tank

int playerY = SCREEN_HEIGHT - TANK_HEIGHT - 1;

Direction playerDir = UP; // Initial direction of the player tank

unsigned long lastPlayerShotTime = 0; // Last firing time of the player tank

int score = 0; // Score

int lives = LIVES; // Player tank lives

void setup() {

// Initialize serial communication for debugging information

Serial.begin(9600);

// Initialize display

if (!display.begin(SSD1306_SWITCHCAPVCC, SCREEN_ADDRESS)) {

Serial.println(F("SSD1306 allocation failed"));

for (;;); // If initialization fails, enter an infinite loop

}

display.clearDisplay();

// Show splash screen

showSplashScreen();

// Initialize enemies

for (int i = 0; i < ENEMY_COUNT; i++) {

spawnEnemy(i);

}

// Initialize bullets

for (int i = 0; i < sizeof(bullets) / sizeof(bullets[0]); i++) {

bullets[i].active = false;

}

}

void loop() {

// Clear screen

display.clearDisplay();

// Detect button input to control player tank movement

if (digitalRead(2) == HIGH) { // Assume pin 2 is connected to the up direction key

playerDir = UP;

playerY = max(playerY - 1, 0);

} else if (digitalRead(3) == HIGH) { // Assume pin 3 is connected to the down direction key

playerDir = DOWN;

playerY = min(playerY + 1, SCREEN_HEIGHT - TANK_HEIGHT);

} else if (digitalRead(4) == HIGH) { // Assume pin 4 is connected to the left direction key

playerDir = LEFT;

playerX = max(playerX - 1, 0);

} else if (digitalRead(5) == HIGH) { // Assume pin 5 is connected to the right direction key

playerDir = RIGHT;

playerX = min(playerX + 1, GAME_AREA_WIDTH - TANK_WIDTH);

}

// Automatically fire player tank's bullets

if (millis() - lastPlayerShotTime > PLAYER_SHOT_INTERVAL) {

fireBullet(playerX + TANK_WIDTH / 2, playerY + TANK_HEIGHT / 2, playerDir);

lastPlayerShotTime = millis();

}

// Move enemies

moveEnemies();

// Automatically fire enemy bullets

autoFireEnemies();

// Update and draw bullets

updateBullets();

drawBullets();

// Check collisions

checkCollisions();

// Draw player tank

drawMiniTank(playerX, playerY, playerDir, 0);

// Draw enemies

drawEnemies();

// Draw vertical line to separate game area and score area

display.drawLine(GAME_AREA_WIDTH, 0, GAME_AREA_WIDTH, SCREEN_HEIGHT, SSD1306_WHITE);

// Show score

displayScore();

// Display content

display.display();

// If player tank's lives are used up, restart the game

if (lives <= 0) {

resetGame();

}

// Wait for a while to simulate frame rate

delay(50);

}

void showSplashScreen() {

// Set font size

display.setTextSize(2);

display.setTextColor(SSD1306_WHITE);

// Clear screen

display.clearDisplay();

// Calculate the width and height of "Tank" text

int16_t x1, y1;

uint16_t w1, h1;

display.getTextBounds("Tank", 0, 0, &x1, &y1, &w1, &h1);

// Calculate the width and height of "Battle" text

int16_t x2, y2;

uint16_t w2, h2;

display.getTextBounds("Battle", 0, 0, &x2, &y2, &w2, &h2);

// Calculate the total height of the two lines of text

uint16_t totalHeight = h1 + h2 + 4; // Add some spacing

// Calculate the starting y-coordinate to center the two lines of text

int16_t startY = (SCREEN_HEIGHT - totalHeight) / 2;

// Display "Tank" text, centered

display.setCursor((SCREEN_WIDTH - w1) / 2, startY);

display.println("Tank");

// Display "Battle" text, centered

display.setCursor((SCREEN_WIDTH - w2) / 2, startY + h1 + 4); // Add the height of the previous line and spacing

display.println("Battle");

// Update display

display.display();

// Pause for a while to allow the user to see the splash screen

delay(2000);

}

void drawMiniTank(int x, int y, Direction dir, int rotation) {

// Define the position and size of the tank's body and turret (reduced by 5 times)

int turretWidth = 2; // Turret width reduced by 5 times

int turretHeight = 2; // Turret height reduced by 5 times

// Calculate the turret's position based on the tank's moving direction

int turretX, turretY;

switch (dir) {

case LEFT:

turretX = x - turretWidth / 2;

turretY = y + (TANK_HEIGHT - turretHeight) / 2;

break;

case RIGHT:

turretX = x + TANK_WIDTH - turretWidth / 2;

turretY = y + (TANK_HEIGHT - turretHeight) / 2;

break;

case UP:

turretX = x + (TANK_WIDTH - turretWidth) / 2;

turretY = y - turretHeight;

break;

case DOWN:

turretX = x + (TANK_WIDTH - turretWidth) / 2;

turretY = y + TANK_HEIGHT - turretHeight / 2;

break;

}

// Draw the tank's body (square)

display.fillRect(x, y, TANK_WIDTH, TANK_HEIGHT, SSD1306_WHITE);

// Draw the tank's turret (small rectangle above the body)

display.fillRect(turretX, turretY, turretWidth, turretHeight, SSD1306_WHITE);

}

void moveEnemies() {

for (int i = 0; i < ENEMY_COUNT; i++) {

if (enemies[i].active) {

// Move the enemy

enemies[i].x += enemies[i].dx;

enemies[i].y += enemies[i].dy;

// If the enemy moves out of the screen, re-enter from the other side

if (enemies[i].x > GAME_AREA_WIDTH || enemies[i].x < 0) {

enemies[i].dx *= -1; // Reverse direction

enemies[i].dir = (enemies[i].dx > 0) ? RIGHT : LEFT;

}

if (enemies[i].y > SCREEN_HEIGHT || enemies[i].y < 0) {

enemies[i].dy *= -1; // Reverse direction

enemies[i].dir = (enemies[i].dy > 0) ? DOWN: UP;

}

}

}

}

void autoFireEnemies() {

for (int i = 0; i < ENEMY_COUNT; i++) {

if (enemies[i].active) {

if (millis() - enemies[i].lastShotTime > PLAYER_SHOT_INTERVAL) {

fireBullet(enemies[i].x + (TANK_WIDTH / 2) - 1, enemies[i].y + (TANK_HEIGHT / 2) - 1, enemies[i].dir);

enemies[i].lastShotTime = millis();

}

}

}

}

void fireBullet(int x, int y, Direction dir) {

for (int i = 0; i < sizeof(bullets) / sizeof(bullets[0]); i++) {

if (!bullets[i].active) {

bullets[i].x = x;

bullets[i].y = y;

bullets[i].dir = dir;

bullets[i].active = true;

setBulletSpeed(bullets[i], dir);

break;

}

}

}

void setBulletSpeed(Bullet& bullet, Direction dir) {

switch (dir) {

case LEFT:

bullet.dx = -2 * BULLET_SPEED;

bullet.dy = 0;

break;

case RIGHT:

bullet.dx = 2 * BULLET_SPEED;

bullet.dy = 0;

break;

case UP:

bullet.dx = 0;

bullet.dy = -2 * BULLET_SPEED;

break;

case DOWN:

bullet.dx = 0;

bullet.dy = 2 * BULLET_SPEED;

break;

}

}

void drawEnemies() {

for (int i = 0; i < ENEMY_COUNT; i++) {

if (enemies[i].active) {

drawMiniTank(enemies[i].x, enemies[i].y, enemies[i].dir, 0);

}

}

}

void updateBullets() {

for (int i = 0; i < sizeof(bullets) / sizeof(bullets[0]); i++) {

if (bullets[i].active) {

bullets[i].x += bullets[i].dx;

bullets[i].y += bullets[i].dy;

if (bullets[i].x < 0 || bullets[i].x > GAME_AREA_WIDTH || bullets[i].y < 0 || bullets[i].y > SCREEN_HEIGHT) {

bullets[i].active = false;

}

}

}

}

void drawBullets() {

for (int i = 0; i < sizeof(bullets) / sizeof(bullets[0]); i++) {

if (bullets[i].active) {

display.fillRect(bullets[i].x, bullets[i].y, 2, 2, SSD1306_WHITE);

}

}

}

void checkCollisions() {

// Check for collisions between player bullets and enemies

for (int i = 0; i < sizeof(bullets) / sizeof(bullets[0]); i++) {

if (bullets[i].active && bullets[i].dir == playerDir) { // Ensure it's the player's bullet

for (int j = 0; j < ENEMY_COUNT; j++) {

if (enemies[j].active && bullets[i].x >= enemies[j].x && bullets[i].x < enemies[j].x + TANK_WIDTH &&

bullets[i].y >= enemies[j].y && bullets[i].y < enemies[j].y + TANK_HEIGHT) {

// Player bullet hits enemy

bullets[i].active = false;

enemies[j].active = false;

score++; // Increase score

spawnEnemy(j); // Spawn a new enemy tank

break; // Exit inner loop

}

}

}

}

// Check for collisions between enemy bullets and player tank

for (int i = 0; i < sizeof(bullets) / sizeof(bullets[0]); i++) {

if (bullets[i].active && bullets[i].dir != playerDir) { // Ensure it's the enemy's bullet

if (bullets[i].x >= playerX && bullets[i].x < playerX + TANK_WIDTH &&

bullets[i].y >= playerY && bullets[i].y < playerY + TANK_HEIGHT) {

// Enemy bullet hits player tank

bullets[i].active = false;

lives--; // Player tank loses a life

if (lives <= 0) {

resetGame(); // If lives are used up, restart the game

}

}

}

}

}

void spawnEnemy(int index) {

enemies[index].active = true;

if (index < ENEMY_COUNT / 2) {

enemies[index].x = random(0, GAME_AREA_WIDTH / 2);

enemies[index].y = random(0, SCREEN_HEIGHT);

enemies[index].dx = 1;

enemies[index].dy = 0;

enemies[index].dir = RIGHT;

} else {

enemies[index].x = random(0, GAME_AREA_WIDTH);

enemies[index].y = random(0, SCREEN_HEIGHT / 2);

enemies[index].dx = 0;

enemies[index].dy = 1;

enemies[index].dir = DOWN;

}

enemies[index].lastShotTime = millis() - PLAYER_SHOT_INTERVAL; // Ensure immediate firing

fireBullet(enemies[index].x + (TANK_WIDTH / 2) - 1, enemies[index].y + (TANK_HEIGHT / 2) - 1, enemies[index].dir);

}

void displayScore() {

display.setTextSize(1);

display.setTextColor(SSD1306_WHITE);

display.setCursor(GAME_AREA_WIDTH + 5, 0);

display.print("PTS");

display.setCursor(GAME_AREA_WIDTH + 10, 16);

display.println(score);

display.setCursor(GAME_AREA_WIDTH + 7, 32);

display.print("LV");

display.setCursor(GAME_AREA_WIDTH + 10, 48);

display.println(lives);

}

void resetGame() {

display.clearDisplay();

display.setTextSize(2);

display.setTextColor(SSD1306_WHITE);

int16_t x, y;

uint16_t w, h;

display.getTextBounds("Game Over", 0, 0, &x, &y, &w, &h);

display.setCursor((SCREEN_WIDTH - w) / 2, (SCREEN_HEIGHT - h) / 2);

display.println("Game Over");

display.display();

delay(3000);

for (int i = 0; i < ENEMY_COUNT; i++) {

spawnEnemy(i);

}

for (int i = 0; i < sizeof(bullets) / sizeof(bullets[0]); i++) {

bullets[i].active = false;

}

playerX = GAME_AREA_WIDTH / 2 - TANK_WIDTH / 2;

playerY = SCREEN_HEIGHT - TANK_HEIGHT - 1;

playerDir = UP;

score = 0;

lives = LIVES;

}

本文編譯自hackster.io

本站聲明: 本文章由作者或相關(guān)機(jī)構(gòu)授權(quán)發(fā)布,目的在于傳遞更多信息,并不代表本站贊同其觀點(diǎn),本站亦不保證或承諾內(nèi)容真實(shí)性等。需要轉(zhuǎn)載請(qǐng)聯(lián)系該專欄作者,如若文章內(nèi)容侵犯您的權(quán)益,請(qǐng)及時(shí)聯(lián)系本站刪除。
換一批
延伸閱讀

9月2日消息,不造車的華為或?qū)⒋呱龈蟮莫?dú)角獸公司,隨著阿維塔和賽力斯的入局,華為引望愈發(fā)顯得引人矚目。

關(guān)鍵字: 阿維塔 塞力斯 華為

倫敦2024年8月29日 /美通社/ -- 英國(guó)汽車技術(shù)公司SODA.Auto推出其旗艦產(chǎn)品SODA V,這是全球首款涵蓋汽車工程師從創(chuàng)意到認(rèn)證的所有需求的工具,可用于創(chuàng)建軟件定義汽車。 SODA V工具的開發(fā)耗時(shí)1.5...

關(guān)鍵字: 汽車 人工智能 智能驅(qū)動(dòng) BSP

北京2024年8月28日 /美通社/ -- 越來(lái)越多用戶希望企業(yè)業(yè)務(wù)能7×24不間斷運(yùn)行,同時(shí)企業(yè)卻面臨越來(lái)越多業(yè)務(wù)中斷的風(fēng)險(xiǎn),如企業(yè)系統(tǒng)復(fù)雜性的增加,頻繁的功能更新和發(fā)布等。如何確保業(yè)務(wù)連續(xù)性,提升韌性,成...

關(guān)鍵字: 亞馬遜 解密 控制平面 BSP

8月30日消息,據(jù)媒體報(bào)道,騰訊和網(wǎng)易近期正在縮減他們對(duì)日本游戲市場(chǎng)的投資。

關(guān)鍵字: 騰訊 編碼器 CPU

8月28日消息,今天上午,2024中國(guó)國(guó)際大數(shù)據(jù)產(chǎn)業(yè)博覽會(huì)開幕式在貴陽(yáng)舉行,華為董事、質(zhì)量流程IT總裁陶景文發(fā)表了演講。

關(guān)鍵字: 華為 12nm EDA 半導(dǎo)體

8月28日消息,在2024中國(guó)國(guó)際大數(shù)據(jù)產(chǎn)業(yè)博覽會(huì)上,華為常務(wù)董事、華為云CEO張平安發(fā)表演講稱,數(shù)字世界的話語(yǔ)權(quán)最終是由生態(tài)的繁榮決定的。

關(guān)鍵字: 華為 12nm 手機(jī) 衛(wèi)星通信

要點(diǎn): 有效應(yīng)對(duì)環(huán)境變化,經(jīng)營(yíng)業(yè)績(jī)穩(wěn)中有升 落實(shí)提質(zhì)增效舉措,毛利潤(rùn)率延續(xù)升勢(shì) 戰(zhàn)略布局成效顯著,戰(zhàn)新業(yè)務(wù)引領(lǐng)增長(zhǎng) 以科技創(chuàng)新為引領(lǐng),提升企業(yè)核心競(jìng)爭(zhēng)力 堅(jiān)持高質(zhì)量發(fā)展策略,塑強(qiáng)核心競(jìng)爭(zhēng)優(yōu)勢(shì)...

關(guān)鍵字: 通信 BSP 電信運(yùn)營(yíng)商 數(shù)字經(jīng)濟(jì)

北京2024年8月27日 /美通社/ -- 8月21日,由中央廣播電視總臺(tái)與中國(guó)電影電視技術(shù)學(xué)會(huì)聯(lián)合牽頭組建的NVI技術(shù)創(chuàng)新聯(lián)盟在BIRTV2024超高清全產(chǎn)業(yè)鏈發(fā)展研討會(huì)上宣布正式成立。 活動(dòng)現(xiàn)場(chǎng) NVI技術(shù)創(chuàng)新聯(lián)...

關(guān)鍵字: VI 傳輸協(xié)議 音頻 BSP

北京2024年8月27日 /美通社/ -- 在8月23日舉辦的2024年長(zhǎng)三角生態(tài)綠色一體化發(fā)展示范區(qū)聯(lián)合招商會(huì)上,軟通動(dòng)力信息技術(shù)(集團(tuán))股份有限公司(以下簡(jiǎn)稱"軟通動(dòng)力")與長(zhǎng)三角投資(上海)有限...

關(guān)鍵字: BSP 信息技術(shù)
關(guān)閉