当前位置:首页 > 工业控制 > 电路设计项目集锦
[导读]这个代码提供了一个简单但引人入胜的坦克战斗游戏体验,结合了基本的移动,射击和碰撞检测机制。

这个代码提供了一个简单但引人入胜的坦克战斗游戏体验,结合了基本的移动,射击和碰撞检测机制。

这段代码使用Arduino和Adafruit SSD1306库在OLED显示器上实现了一个基本的坦克战斗游戏。以下是游戏的主要特点和功能:

•玩家坦克:玩家控制一辆坦克,它可以通过连接到特定引脚的按钮向上、向下、向左和向右移动。坦克定时自动发射子弹。

•敌人坦克:有6辆敌人坦克在屏幕上随机移动。每个敌方坦克也会向玩家的坦克发射子弹。

•子弹:玩家和敌人的坦克都会射击子弹。子弹的速度是坦克移动速度的两倍。当玩家的子弹击中敌人的坦克时,敌人的坦克就会被摧毁,玩家就会获得一分。敌人的子弹不会影响其他敌人的坦克。

•碰撞检测:游戏检查玩家的子弹与敌人坦克之间的碰撞,以及敌人的子弹与玩家坦克之间的碰撞。如果敌人的子弹击中玩家的坦克,玩家就会失去一条生命。

•生命和得分:玩家一开始有三条生命。每摧毁一辆敌方坦克,玩家的分数就会增加。如果玩家失去所有三条生命,游戏将显示“游戏结束”并重置。

•游戏重置:当玩家的生命值为零时,游戏会显示“游戏结束”屏幕,然后重新开始,重置分数、玩家生命值和敌方坦克位置。

•显示:游戏在OLED屏幕上显示,游戏区和计分区用一条竖线隔开。得分区域显示当前得分和剩余命值。

•初始化和设置:在游戏开始时,敌人的坦克会出现,玩家的坦克会出现在屏幕的中下方。游戏以一个显示“Tank Battle”的启动画面开始。

图表

坦克战

这个代码提供了一个简单但引人入胜的坦克战斗游戏体验,结合了基本的移动,射击和碰撞检测机制。

代码

#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

本站声明: 本文章由作者或相关机构授权发布,目的在于传递更多信息,并不代表本站赞同其观点,本站亦不保证或承诺内容真实性等。需要转载请联系该专栏作者,如若文章内容侵犯您的权益,请及时联系本站删除。
换一批
延伸阅读

9月2日消息,不造车的华为或将催生出更大的独角兽公司,随着阿维塔和赛力斯的入局,华为引望愈发显得引人瞩目。

关键字: 阿维塔 塞力斯 华为

加利福尼亚州圣克拉拉县2024年8月30日 /美通社/ -- 数字化转型技术解决方案公司Trianz今天宣布,该公司与Amazon Web Services (AWS)签订了...

关键字: AWS AN BSP 数字化

伦敦2024年8月29日 /美通社/ -- 英国汽车技术公司SODA.Auto推出其旗舰产品SODA V,这是全球首款涵盖汽车工程师从创意到认证的所有需求的工具,可用于创建软件定义汽车。 SODA V工具的开发耗时1.5...

关键字: 汽车 人工智能 智能驱动 BSP

北京2024年8月28日 /美通社/ -- 越来越多用户希望企业业务能7×24不间断运行,同时企业却面临越来越多业务中断的风险,如企业系统复杂性的增加,频繁的功能更新和发布等。如何确保业务连续性,提升韧性,成...

关键字: 亚马逊 解密 控制平面 BSP

8月30日消息,据媒体报道,腾讯和网易近期正在缩减他们对日本游戏市场的投资。

关键字: 腾讯 编码器 CPU

8月28日消息,今天上午,2024中国国际大数据产业博览会开幕式在贵阳举行,华为董事、质量流程IT总裁陶景文发表了演讲。

关键字: 华为 12nm EDA 半导体

8月28日消息,在2024中国国际大数据产业博览会上,华为常务董事、华为云CEO张平安发表演讲称,数字世界的话语权最终是由生态的繁荣决定的。

关键字: 华为 12nm 手机 卫星通信

要点: 有效应对环境变化,经营业绩稳中有升 落实提质增效举措,毛利润率延续升势 战略布局成效显著,战新业务引领增长 以科技创新为引领,提升企业核心竞争力 坚持高质量发展策略,塑强核心竞争优势...

关键字: 通信 BSP 电信运营商 数字经济

北京2024年8月27日 /美通社/ -- 8月21日,由中央广播电视总台与中国电影电视技术学会联合牵头组建的NVI技术创新联盟在BIRTV2024超高清全产业链发展研讨会上宣布正式成立。 活动现场 NVI技术创新联...

关键字: VI 传输协议 音频 BSP

北京2024年8月27日 /美通社/ -- 在8月23日举办的2024年长三角生态绿色一体化发展示范区联合招商会上,软通动力信息技术(集团)股份有限公司(以下简称"软通动力")与长三角投资(上海)有限...

关键字: BSP 信息技术
关闭