** PR ** 目がかすむ、ぼやける。目の悩み解消解消に。
いよいよ、コンソール画面型シューティングゲームの完成に向けて最後の調整です。
ここで、前回のソースコードと追加仕様を提示してプロンプトとしました。
Rustでゲームを作ります。コードはこれを基本に
use std::io::{self, Write};
use std::thread;
use std::time::Duration;
use rand::Rng;
use std::sync::mpsc;
use std::sync::mpsc::{Sender, Receiver};
use crossterm::{ExecutableCommand, cursor, terminal, event::{self, KeyCode, KeyEvent, Event}};const WIDTH: usize = 10;
const HEIGHT: usize = 10;fn main() {
let (tx, rx): (Sender, Receiver) = mpsc::channel();// スレッドを作成してユーザー入力を非同期に処理 thread::spawn(move || { loop { if event::poll(Duration::from_millis(100)).unwrap() { if let Event::Key(key_event) = event::read().unwrap() { tx.send(Event::Key(key_event)).expect("送信に失敗しました"); } } } }); let mut player_pos = WIDTH / 2; let mut enemy_pos = (0, rand::thread_rng().gen_range(0..WIDTH)); let mut bullets: Vec<(usize, usize)> = Vec::new(); let mut score = 0; let mut stdout = io::stdout(); stdout.execute(terminal::Clear(terminal::ClearType::All)).unwrap(); stdout.execute(cursor::Hide).unwrap(); loop { // 画面をクリア stdout.execute(cursor::MoveTo(0, 0)).unwrap(); // 敵の位置を更新 enemy_pos.0 += 1; if enemy_pos.0 >= HEIGHT { enemy_pos = (0, rand::thread_rng().gen_range(0..WIDTH)); } // 弾の位置を更新 bullets.retain(|&(y, _)| y > 0); for bullet in &mut bullets { bullet.0 -= 1; } // 弾が敵に当たったかチェック if bullets.iter().any(|&bullet| bullet == enemy_pos) { score += 1; enemy_pos = (0, rand::thread_rng().gen_range(0..WIDTH)); bullets.retain(|&bullet| bullet != enemy_pos); } // 敵とプレイヤーが衝突したかチェック if enemy_pos == (HEIGHT - 1, player_pos) { println!("ゲームオーバー!"); break; } // 画面を描画 for y in 0..HEIGHT { for x in 0..WIDTH { if (y, x) == (HEIGHT - 1, player_pos) { print!("P"); } else if (y, x) == enemy_pos { print!("E"); } else if bullets.contains(&(y, x)) { print!("|"); } else { print!("."); } } println!(); } println!("Score: {}", score); // プレイヤーの入力を処理 if let Ok(event) = rx.try_recv() { if let Event::Key(KeyEvent { code, .. }) = event { match code { KeyCode::Char('a') => { if player_pos > 0 { player_pos -= 1; } } KeyCode::Char('d') => { if player_pos < WIDTH - 1 { player_pos += 1; } } KeyCode::Char(' ') => { bullets.push((HEIGHT - 2, player_pos)); } KeyCode::Char('q') => break, _ => {} } } } // 少し待つ thread::sleep(Duration::from_millis(100)); } stdout.execute(cursor::Show).unwrap();
}
※
\|/
イメージで半角で衝突したことを表すキャラクターとします。
以上をプロンプトとして投下しました。
コパイロット君の回答は。
面白いゲームですね!衝突を表すキャラクターを追加するために、以下のようにコードを変更してみてください。衝突時に「\|/」と「※」を表示するようにします。
Rust
use std::io::{self, Write};
use std::thread;
use std::time::Duration;
use rand::Rng;
use std::sync::mpsc;
use std::sync::mpsc::{Sender, Receiver};
use crossterm::{ExecutableCommand, cursor, terminal, event::{self, KeyCode, KeyEvent, Event}};
const WIDTH: usize = 10;
const HEIGHT: usize = 10;
fn main() {
let (tx, rx): (Sender, Receiver) = mpsc::channel();
// スレッドを作成してユーザー入力を非同期に処理
thread::spawn(move || {
loop {
if event::poll(Duration::from_millis(100)).unwrap() {
if let Event::Key(key_event) = event::read().unwrap() {
tx.send(Event::Key(key_event)).expect("送信に失敗しました");
}
}
}
});
let mut player_pos = WIDTH / 2;
let mut enemy_pos = (0, rand::thread_rng().gen_range(0..WIDTH));
let mut bullets: Vec<(usize, usize)> = Vec::new();
let mut score = 0;
let mut collision = false;
let mut stdout = io::stdout();
stdout.execute(terminal::Clear(terminal::ClearType::All)).unwrap();
stdout.execute(cursor::Hide).unwrap();
loop {
// 画面をクリア
stdout.execute(cursor::MoveTo(0, 0)).unwrap();
// 敵の位置を更新
enemy_pos.0 += 1;
if enemy_pos.0 >= HEIGHT {
enemy_pos = (0, rand::thread_rng().gen_range(0..WIDTH));
}
// 弾の位置を更新
bullets.retain(|&(y, _)| y > 0);
for bullet in &mut bullets {
bullet.0 -= 1;
}
// 弾が敵に当たったかチェック
if bullets.iter().any(|&bullet| bullet == enemy_pos) {
score += 1;
enemy_pos = (0, rand::thread_rng().gen_range(0..WIDTH));
bullets.retain(|&bullet| bullet != enemy_pos);
}
// 敵とプレイヤーが衝突したかチェック
if enemy_pos == (HEIGHT - 1, player_pos) {
collision = true;
break;
}
// 画面を描画
for y in 0..HEIGHT {
for x in 0..WIDTH {
if (y, x) == (HEIGHT - 1, player_pos) {
print!("P");
} else if (y, x) == enemy_pos {
print!("E");
} else if bullets.contains(&(y, x)) {
print!("|");
} else {
print!(".");
}
}
println!();
}
println!("Score: {}", score);
// プレイヤーの入力を処理
if let Ok(event) = rx.try_recv() {
if let Event::Key(KeyEvent { code, .. }) = event {
match code {
KeyCode::Char('a') => {
if player_pos > 0 {
player_pos -= 1;
}
}
KeyCode::Char('d') => {
if player_pos < WIDTH - 1 {
player_pos += 1;
}
}
KeyCode::Char(' ') => {
bullets.push((HEIGHT - 2, player_pos));
}
KeyCode::Char('q') => break,
_ => {}
}
}
}
// 少し待つ
thread::sleep(Duration::from_millis(100));
}
stdout.execute(cursor::Show).unwrap();
if collision {
println!("\|/");
println!(" ※ ");
println!("ゲームオーバー!");
}
}
これで、敵とプレイヤーが衝突したときに「\|/」と「※」が表示されるようになります。ゲームの進行に合わせて、さらに改良を加えて楽しんでください!
追加のコードは、randとcrosstermクレートがプロジェクトに追加されていないためです。Cargo.tomlファイルにこれらの依存関係を追加する必要があります。
以下のようにCargo.tomlファイルを更新してください:
[dependencies]
rand = “0.8”
crossterm = “0.22”
これで、randとcrosstermクレートがプロジェクトに追加され、解消されるはずです。再度ビルドしてみてください。

\|/….
※ …..
ゲームオーバー!
……….
…|……
……….
…|……
…E……
…P……
Score: 0
という感じでPのプレイヤーの位置で
\|/….
※ …..と表示できれば完璧です。
AIがプロンプトを理解して「会話として回答してくる」このあたりが凄い
全角文字が原因で文字化けしてしまったのですね。半角文字で表示するように修正します。以下のようにコードを変更してください:
Rust
use std::io::{self, Write};
use std::thread;
use std::time::Duration;
use rand::Rng;
use std::sync::mpsc;
use std::sync::mpsc::{Sender, Receiver};
use crossterm::{ExecutableCommand, cursor, terminal, event::{self, KeyCode, KeyEvent, Event}};
const WIDTH: usize = 10;
const HEIGHT: usize = 10;
fn main() {
let (tx, rx): (Sender<Event>, Receiver<Event>) = mpsc::channel();
// スレッドを作成してユーザー入力を非同期に処理
thread::spawn(move || {
loop {
if event::poll(Duration::from_millis(100)).unwrap() {
if let Event::Key(key_event) = event::read().unwrap() {
tx.send(Event::Key(key_event)).expect("送信に失敗しました");
}
}
}
});
let mut player_pos = WIDTH / 2;
let mut enemy_pos = (0, rand::thread_rng().gen_range(0..WIDTH));
let mut bullets: Vec<(usize, usize)> = Vec::new();
let mut score = 0;
let mut collision = false;
let mut stdout = io::stdout();
stdout.execute(terminal::Clear(terminal::ClearType::All)).unwrap();
stdout.execute(cursor::Hide).unwrap();
loop {
// 画面をクリア
stdout.execute(cursor::MoveTo(0, 0)).unwrap();
// 敵の位置を更新
enemy_pos.0 += 1;
if enemy_pos.0 >= HEIGHT {
enemy_pos = (0, rand::thread_rng().gen_range(0..WIDTH));
}
// 弾の位置を更新
bullets.retain(|&(y, _)| y > 0);
for bullet in &mut bullets {
bullet.0 -= 1;
}
// 弾が敵に当たったかチェック
if bullets.iter().any(|&bullet| bullet == enemy_pos) {
score += 1;
enemy_pos = (0, rand::thread_rng().gen_range(0..WIDTH));
bullets.retain(|&bullet| bullet != enemy_pos);
}
// 敵とプレイヤーが衝突したかチェック
if enemy_pos == (HEIGHT - 1, player_pos) {
collision = true;
break;
}
// 画面を描画
for y in 0..HEIGHT {
for x in 0..WIDTH {
if (y, x) == (HEIGHT - 1, player_pos) {
print!("P");
} else if (y, x) == enemy_pos {
print!("E");
} else if bullets.contains(&(y, x)) {
print!("|");
} else {
print!(".");
}
}
println!();
}
println!("Score: {}", score);
// プレイヤーの入力を処理
if let Ok(event) = rx.try_recv() {
if let Event::Key(KeyEvent { code, .. }) = event {
match code {
KeyCode::Char('a') => {
if player_pos > 0 {
player_pos -= 1;
}
}
KeyCode::Char('d') => {
if player_pos < WIDTH - 1 {
player_pos += 1;
}
}
KeyCode::Char(' ') => {
bullets.push((HEIGHT - 2, player_pos));
}
KeyCode::Char('q') => break,
_ => {}
}
}
}
// 少し待つ
thread::sleep(Duration::from_millis(100));
}
stdout.execute(cursor::Show).unwrap();
if collision {
stdout.execute(cursor::MoveTo(HEIGHT as u16, 0)).unwrap();
println!(r"\|/....");
println!(" * .....");
println!("ゲームオーバー!");
}
}
AI で生成されたコード。ご確認のうえ、慎重にご使用ください。FAQ で詳細を確認。
これで、プレイヤーの位置で半角文字の「\|/」と「*」が表示されるようになります。再度ビルドして試してみてください!
| \\*// このキャラクタをPの位置で表示に変更ください。
了解しました!プレイヤーの位置で「|」と「\*//」を表示するようにコードを変更します。以下のように修正してください:
Rust
use std::io::{self, Write};
use std::thread;
use std::time::Duration;
use rand::Rng;
use std::sync::mpsc;
use std::sync::mpsc::{Sender, Receiver};
use crossterm::{ExecutableCommand, cursor, terminal, event::{self, KeyCode, KeyEvent, Event}};
const WIDTH: usize = 10;
const HEIGHT: usize = 10;
fn main() {
let (tx, rx): (Sender<Event>, Receiver<Event>) = mpsc::channel();
// スレッドを作成してユーザー入力を非同期に処理
thread::spawn(move || {
loop {
if event::poll(Duration::from_millis(100)).unwrap() {
if let Event::Key(key_event) = event::read().unwrap() {
tx.send(Event::Key(key_event)).expect("送信に失敗しました");
}
}
}
});
let mut player_pos = WIDTH / 2;
let mut enemy_pos = (0, rand::thread_rng().gen_range(0..WIDTH));
let mut bullets: Vec<(usize, usize)> = Vec::new();
let mut score = 0;
let mut collision = false;
let mut stdout = io::stdout();
stdout.execute(terminal::Clear(terminal::ClearType::All)).unwrap();
stdout.execute(cursor::Hide).unwrap();
loop {
// 画面をクリア
stdout.execute(cursor::MoveTo(0, 0)).unwrap();
// 敵の位置を更新
enemy_pos.0 += 1;
if enemy_pos.0 >= HEIGHT {
enemy_pos = (0, rand::thread_rng().gen_range(0..WIDTH));
}
// 弾の位置を更新
bullets.retain(|&(y, _)| y > 0);
for bullet in &mut bullets {
bullet.0 -= 1;
}
// 弾が敵に当たったかチェック
if bullets.iter().any(|&bullet| bullet == enemy_pos) {
score += 1;
enemy_pos = (0, rand::thread_rng().gen_range(0..WIDTH));
bullets.retain(|&bullet| bullet != enemy_pos);
}
// 敵とプレイヤーが衝突したかチェック
if enemy_pos == (HEIGHT - 1, player_pos) {
collision = true;
break;
}
// 画面を描画
for y in 0..HEIGHT {
for x in 0..WIDTH {
if (y, x) == (HEIGHT - 1, player_pos) {
print!("P");
} else if (y, x) == enemy_pos {
print!("E");
} else if bullets.contains(&(y, x)) {
print!("|");
} else {
print!(".");
}
}
println!();
}
println!("Score: {}", score);
// プレイヤーの入力を処理
if let Ok(event) = rx.try_recv() {
if let Event::Key(KeyEvent { code, .. }) = event {
match code {
KeyCode::Char('a') => {
if player_pos > 0 {
player_pos -= 1;
}
}
KeyCode::Char('d') => {
if player_pos < WIDTH - 1 {
player_pos += 1;
}
}
KeyCode::Char(' ') => {
bullets.push((HEIGHT - 2, player_pos));
}
KeyCode::Char('q') => break,
_ => {}
}
}
}
// 少し待つ
thread::sleep(Duration::from_millis(100));
}
stdout.execute(cursor::Show).unwrap();
if collision {
stdout.execute(cursor::MoveTo(HEIGHT as u16 - 1, player_pos as u16)).unwrap();
println!("|");
stdout.execute(cursor::MoveTo(HEIGHT as u16, player_pos as u16 - 1)).unwrap();
println!("\\*//");
println!("ゲームオーバー!");
}
}
AI で生成されたコード。ご確認のうえ、慎重にご使用ください。FAQ で詳細を確認。
これで、プレイヤーと敵が衝突したときに、プレイヤーの位置で「|」と「\*//」が表示されるようになります。再度ビルドして試してみてください!
残念です。
……….
..|…….*//
繧イ繝シ繝繧ェ繝シ繝舌・・・
PS C:\Users\\rust\sohtgun3>
……….
……….
……….
……….
..E…….
..P…….
Score: 0
となります。
文字化けが発生してしまったようですね。衝突時の表示を修正して、正しく表示されるようにします。以下のようにコードを変更してください:
Rust
use std::io::{self, Write};
use std::thread;
use std::time::Duration;
use rand::Rng;
use std::sync::mpsc;
use std::sync::mpsc::{Sender, Receiver};
use crossterm::{ExecutableCommand, cursor, terminal, event::{self, KeyCode, KeyEvent, Event}};
const WIDTH: usize = 10;
const HEIGHT: usize = 10;
fn main() {
let (tx, rx): (Sender<Event>, Receiver<Event>) = mpsc::channel();
// スレッドを作成してユーザー入力を非同期に処理
thread::spawn(move || {
loop {
if event::poll(Duration::from_millis(100)).unwrap() {
if let Event::Key(key_event) = event::read().unwrap() {
tx.send(Event::Key(key_event)).expect("送信に失敗しました");
}
}
}
});
let mut player_pos = WIDTH / 2;
let mut enemy_pos = (0, rand::thread_rng().gen_range(0..WIDTH));
let mut bullets: Vec<(usize, usize)> = Vec::new();
let mut score = 0;
let mut collision = false;
let mut stdout = io::stdout();
stdout.execute(terminal::Clear(terminal::ClearType::All)).unwrap();
stdout.execute(cursor::Hide).unwrap();
loop {
// 画面をクリア
stdout.execute(cursor::MoveTo(0, 0)).unwrap();
// 敵の位置を更新
enemy_pos.0 += 1;
if enemy_pos.0 >= HEIGHT {
enemy_pos = (0, rand::thread_rng().gen_range(0..WIDTH));
}
// 弾の位置を更新
bullets.retain(|&(y, _)| y > 0);
for bullet in &mut bullets {
bullet.0 -= 1;
}
// 弾が敵に当たったかチェック
if bullets.iter().any(|&bullet| bullet == enemy_pos) {
score += 1;
enemy_pos = (0, rand::thread_rng().gen_range(0..WIDTH));
bullets.retain(|&bullet| bullet != enemy_pos);
}
// 敵とプレイヤーが衝突したかチェック
if enemy_pos == (HEIGHT - 1, player_pos) {
collision = true;
break;
}
// 画面を描画
for y in 0..HEIGHT {
for x in 0..WIDTH {
if (y, x) == (HEIGHT - 1, player_pos) {
print!("P");
} else if (y, x) == enemy_pos {
print!("E");
} else if bullets.contains(&(y, x)) {
print!("|");
} else {
print!(".");
}
}
println!();
}
println!("Score: {}", score);
// プレイヤーの入力を処理
if let Ok(event) = rx.try_recv() {
if let Event::Key(KeyEvent { code, .. }) = event {
match code {
KeyCode::Char('a') => {
if player_pos > 0 {
player_pos -= 1;
}
}
KeyCode::Char('d') => {
if player_pos < WIDTH - 1 {
player_pos += 1;
}
}
KeyCode::Char(' ') => {
bullets.push((HEIGHT - 2, player_pos));
}
KeyCode::Char('q') => break,
_ => {}
}
}
}
// 少し待つ
thread::sleep(Duration::from_millis(100));
}
stdout.execute(cursor::Show).unwrap();
if collision {
stdout.execute(cursor::MoveTo(HEIGHT as u16 - 1, 0)).unwrap();
println!("..........\n..|.......\n.\\*//......");
println!("ゲームオーバー!");
}
}
AI で生成されたコード。ご確認のうえ、慎重にご使用ください。FAQ で詳細を確認。
これで、プレイヤーと敵が衝突したときに、プレイヤーの位置で「|」と「\*//」が正しく表示されるようになります。再度ビルドして試してみてください!
……………….
..|…….
.*//……
繧イ繝シ繝繧ェ繝シ繝舌・・・
PS C:\Users\\rust\sohtgun3> a
……….
……….
……….
E………
P………
Score: 0
どうも、衝突したタイミングで、Pの位置を取得し、そこから割り出し、Pの位置にを表示しその周りに他文字をイメージ通りに配置する配列 この配列の中心をPの位置と同期すればいいのでは?
その通りです!プレイヤーの位置を中心にして、衝突時に「|」と「\*//」を表示するように配列を使って配置する方法を試してみましょう。
以下のようにコードを修正してみてください:
Rust
use std::io::{self, Write};
use std::thread;
use std::time::Duration;
use rand::Rng;
use std::sync::mpsc;
use std::sync::mpsc::{Sender, Receiver};
use crossterm::{ExecutableCommand, cursor, terminal, event::{self, KeyCode, KeyEvent, Event}};
const WIDTH: usize = 10;
const HEIGHT: usize = 10;
fn main() {
let (tx, rx): (Sender<Event>, Receiver<Event>) = mpsc::channel();
// スレッドを作成してユーザー入力を非同期に処理
thread::spawn(move || {
loop {
if event::poll(Duration::from_millis(100)).unwrap() {
if let Event::Key(key_event) = event::read().unwrap() {
tx.send(Event::Key(key_event)).expect("送信に失敗しました");
}
}
}
});
let mut player_pos = WIDTH / 2;
let mut enemy_pos = (0, rand::thread_rng().gen_range(0..WIDTH));
let mut bullets: Vec<(usize, usize)> = Vec::new();
let mut score = 0;
let mut collision = false;
let mut stdout = io::stdout();
stdout.execute(terminal::Clear(terminal::ClearType::All)).unwrap();
stdout.execute(cursor::Hide).unwrap();
loop {
// 画面をクリア
stdout.execute(cursor::MoveTo(0, 0)).unwrap();
// 敵の位置を更新
enemy_pos.0 += 1;
if enemy_pos.0 >= HEIGHT {
enemy_pos = (0, rand::thread_rng().gen_range(0..WIDTH));
}
// 弾の位置を更新
bullets.retain(|&(y, _)| y > 0);
for bullet in &mut bullets {
bullet.0 -= 1;
}
// 弾が敵に当たったかチェック
if bullets.iter().any(|&bullet| bullet == enemy_pos) {
score += 1;
enemy_pos = (0, rand::thread_rng().gen_range(0..WIDTH));
bullets.retain(|&bullet| bullet != enemy_pos);
}
// 敵とプレイヤーが衝突したかチェック
if enemy_pos == (HEIGHT - 1, player_pos) {
collision = true;
break;
}
// 画面を描画
for y in 0..HEIGHT {
for x in 0..WIDTH {
if (y, x) == (HEIGHT - 1, player_pos) {
print!("P");
} else if (y, x) == enemy_pos {
print!("E");
} else if bullets.contains(&(y, x)) {
print!("|");
} else {
print!(".");
}
}
println!();
}
println!("Score: {}", score);
// プレイヤーの入力を処理
if let Ok(event) = rx.try_recv() {
if let Event::Key(KeyEvent { code, .. }) = event {
match code {
KeyCode::Char('a') => {
if player_pos > 0 {
player_pos -= 1;
}
}
KeyCode::Char('d') => {
if player_pos < WIDTH - 1 {
player_pos += 1;
}
}
KeyCode::Char(' ') => {
bullets.push((HEIGHT - 2, player_pos));
}
KeyCode::Char('q') => break,
_ => {}
}
}
}
// 少し待つ
thread::sleep(Duration::from_millis(100));
}
stdout.execute(cursor::Show).unwrap();
if collision {
let collision_pattern = [
" | ",
"\\*//"
];
for (i, line) in collision_pattern.iter().enumerate() {
stdout.execute(cursor::MoveTo((player_pos as u16).saturating_sub(1), (HEIGHT as u16).saturating_sub(2) + i as u16)).unwrap();
println!("{}", line);
}
println!("ゲームオーバー!");
}
}
AI で生成されたコード。ご確認のうえ、慎重にご使用ください。FAQ で詳細を確認。
これで、プレイヤーと敵が衝突したときに、プレイヤーの位置で「|」と「\*//」が正しく表示されるようになります。再度ビルドして試してみてください!
仕様通りに完成ですが、
….*//..
の下に、たぶんゲームオーバーの日本語が表示?
だとしたら、これを英語ASCII文字にしてしまえばOKではGAME OVER!! とかかっこよい文字列で!……….
……….
……….
……|…
……….
……|…
……….
……….
…. | …
….*//..
繧イ繝シ繝繧ェ繝シ繝舌・・・thread ‘
PS C:\Users\\rust\sohtgun3>

了解しました!「GAME OVER!!」のような英語のASCII文字を表示するように変更します。以下のようにコードを修正してください:
Rust
use std::io::{self, Write};
use std::thread;
use std::time::Duration;
use rand::Rng;
use std::sync::mpsc;
use std::sync::mpsc::{Sender, Receiver};
use crossterm::{ExecutableCommand, cursor, terminal, event::{self, KeyCode, KeyEvent, Event}};
const WIDTH: usize = 10;
const HEIGHT: usize = 10;
fn main() {
let (tx, rx): (Sender<Event>, Receiver<Event>) = mpsc::channel();
// スレッドを作成してユーザー入力を非同期に処理
thread::spawn(move || {
loop {
if event::poll(Duration::from_millis(100)).unwrap() {
if let Event::Key(key_event) = event::read().unwrap() {
tx.send(Event::Key(key_event)).expect("送信に失敗しました");
}
}
}
});
let mut player_pos = WIDTH / 2;
let mut enemy_pos = (0, rand::thread_rng().gen_range(0..WIDTH));
let mut bullets: Vec<(usize, usize)> = Vec::new();
let mut score = 0;
let mut collision = false;
let mut stdout = io::stdout();
stdout.execute(terminal::Clear(terminal::ClearType::All)).unwrap();
stdout.execute(cursor::Hide).unwrap();
loop {
// 画面をクリア
stdout.execute(cursor::MoveTo(0, 0)).unwrap();
// 敵の位置を更新
enemy_pos.0 += 1;
if enemy_pos.0 >= HEIGHT {
enemy_pos = (0, rand::thread_rng().gen_range(0..WIDTH));
}
// 弾の位置を更新
bullets.retain(|&(y, _)| y > 0);
for bullet in &mut bullets {
bullet.0 -= 1;
}
// 弾が敵に当たったかチェック
if bullets.iter().any(|&bullet| bullet == enemy_pos) {
score += 1;
enemy_pos = (0, rand::thread_rng().gen_range(0..WIDTH));
bullets.retain(|&bullet| bullet != enemy_pos);
}
// 敵とプレイヤーが衝突したかチェック
if enemy_pos == (HEIGHT - 1, player_pos) {
collision = true;
break;
}
// 画面を描画
for y in 0..HEIGHT {
for x in 0..WIDTH {
if (y, x) == (HEIGHT - 1, player_pos) {
print!("P");
} else if (y, x) == enemy_pos {
print!("E");
} else if bullets.contains(&(y, x)) {
print!("|");
} else {
print!(".");
}
}
println!();
}
println!("Score: {}", score);
// プレイヤーの入力を処理
if let Ok(event) = rx.try_recv() {
if let Event::Key(KeyEvent { code, .. }) = event {
match code {
KeyCode::Char('a') => {
if player_pos > 0 {
player_pos -= 1;
}
}
KeyCode::Char('d') => {
if player_pos < WIDTH - 1 {
player_pos += 1;
}
}
KeyCode::Char(' ') => {
bullets.push((HEIGHT - 2, player_pos));
}
KeyCode::Char('q') => break,
_ => {}
}
}
}
// 少し待つ
thread::sleep(Duration::from_millis(100));
}
stdout.execute(cursor::Show).unwrap();
if collision {
let collision_pattern = [
" | ",
"\\*//"
];
for (i, line) in collision_pattern.iter().enumerate() {
stdout.execute(cursor::MoveTo((player_pos as u16).saturating_sub(1), (HEIGHT as u16).saturating_sub(2) + i as u16)).unwrap();
println!("{}", line);
}
stdout.execute(cursor::MoveTo(HEIGHT as u16, 0)).unwrap();
println!("GAME OVER!!");
}
}
AI で生成されたコード。ご確認のうえ、慎重にご使用ください。FAQ で詳細を確認。
これで、プレイヤーと敵が衝突したときに、「|」と「\*//」の下に「GAME OVER!!」が表示されるようになります。再度ビルドして試してみてください!
残念
………
a a
……….
…….|..
……….
……..|.
……..|.
……….
…….. |
……..*//
Score: 21
ゲームオーバの時点で、Score:の下の行にカーソルを移動、そこに
.GAME OVER!!
PS C:\Users\mz808\rust\sohtgun3>
の表示でいいのでは?
了解しました!ゲームオーバーの時点で、スコアの下に「GAME OVER!!」を表示するようにコードを修正します。以下のように変更してください:
Rust
use std::io::{self, Write};
use std::thread;
use std::time::Duration;
use rand::Rng;
use std::sync::mpsc;
use std::sync::mpsc::{Sender, Receiver};
use crossterm::{ExecutableCommand, cursor, terminal, event::{self, KeyCode, KeyEvent, Event}};
const WIDTH: usize = 10;
const HEIGHT: usize = 10;
fn main() {
let (tx, rx): (Sender<Event>, Receiver<Event>) = mpsc::channel();
// スレッドを作成してユーザー入力を非同期に処理
thread::spawn(move || {
loop {
if event::poll(Duration::from_millis(100)).unwrap() {
if let Event::Key(key_event) = event::read().unwrap() {
tx.send(Event::Key(key_event)).expect("送信に失敗しました");
}
}
}
});
let mut player_pos = WIDTH / 2;
let mut enemy_pos = (0, rand::thread_rng().gen_range(0..WIDTH));
let mut bullets: Vec<(usize, usize)> = Vec::new();
let mut score = 0;
let mut collision = false;
let mut stdout = io::stdout();
stdout.execute(terminal::Clear(terminal::ClearType::All)).unwrap();
stdout.execute(cursor::Hide).unwrap();
loop {
// 画面をクリア
stdout.execute(cursor::MoveTo(0, 0)).unwrap();
// 敵の位置を更新
enemy_pos.0 += 1;
if enemy_pos.0 >= HEIGHT {
enemy_pos = (0, rand::thread_rng().gen_range(0..WIDTH));
}
// 弾の位置を更新
bullets.retain(|&(y, _)| y > 0);
for bullet in &mut bullets {
bullet.0 -= 1;
}
// 弾が敵に当たったかチェック
if bullets.iter().any(|&bullet| bullet == enemy_pos) {
score += 1;
enemy_pos = (0, rand::thread_rng().gen_range(0..WIDTH));
bullets.retain(|&bullet| bullet != enemy_pos);
}
// 敵とプレイヤーが衝突したかチェック
if enemy_pos == (HEIGHT - 1, player_pos) {
collision = true;
break;
}
// 画面を描画
for y in 0..HEIGHT {
for x in 0..WIDTH {
if (y, x) == (HEIGHT - 1, player_pos) {
print!("P");
} else if (y, x) == enemy_pos {
print!("E");
} else if bullets.contains(&(y, x)) {
print!("|");
} else {
print!(".");
}
}
println!();
}
println!("Score: {}", score);
// プレイヤーの入力を処理
if let Ok(event) = rx.try_recv() {
if let Event::Key(KeyEvent { code, .. }) = event {
match code {
KeyCode::Char('a') => {
if player_pos > 0 {
player_pos -= 1;
}
}
KeyCode::Char('d') => {
if player_pos < WIDTH - 1 {
player_pos += 1;
}
}
KeyCode::Char(' ') => {
bullets.push((HEIGHT - 2, player_pos));
}
KeyCode::Char('q') => break,
_ => {}
}
}
}
// 少し待つ
thread::sleep(Duration::from_millis(100));
}
stdout.execute(cursor::Show).unwrap();
if collision {
let collision_pattern = [
" | ",
"\\*//"
];
for (i, line) in collision_pattern.iter().enumerate() {
stdout.execute(cursor::MoveTo((player_pos as u16).saturating_sub(1), (HEIGHT as u16).saturating_sub(2) + i as u16)).unwrap();
println!("{}", line);
}
stdout.execute(cursor::MoveTo(HEIGHT as u16 + 1, 0)).unwrap();
println!("GAME OVER!!");
}
}
AI で生成されたコード。ご確認のうえ、慎重にご使用ください。FAQ で詳細を確認。
これで、ゲームオーバーの時点でスコアの下に「GAME OVER!!」が表示されるようになります。再度ビルドして試してみてください!
………. GAME OVER!!
PS C:\Users\\rust\sohtgun3>
……….
……….
……….
……….
……….
……….
…. | …
….*//..
Score: 0
カーソル位置の取得がうまくいっていないようですね。スコアの下に「GAME OVER!!」を表示するために、カーソルの位置を正確に設定する必要があります。以下のようにコードを修正してみてください:
Rust
use std::io::{self, Write};
use std::thread;
use std::time::Duration;
use rand::Rng;
use std::sync::mpsc;
use std::sync::mpsc::{Sender, Receiver};
use crossterm::{ExecutableCommand, cursor, terminal, event::{self, KeyCode, KeyEvent, Event}};
const WIDTH: usize = 10;
const HEIGHT: usize = 10;
fn main() {
let (tx, rx): (Sender<Event>, Receiver<Event>) = mpsc::channel();
// スレッドを作成してユーザー入力を非同期に処理
thread::spawn(move || {
loop {
if event::poll(Duration::from_millis(100)).unwrap() {
if let Event::Key(key_event) = event::read().unwrap() {
tx.send(Event::Key(key_event)).expect("送信に失敗しました");
}
}
}
});
let mut player_pos = WIDTH / 2;
let mut enemy_pos = (0, rand::thread_rng().gen_range(0..WIDTH));
let mut bullets: Vec<(usize, usize)> = Vec::new();
let mut score = 0;
let mut collision = false;
let mut stdout = io::stdout();
stdout.execute(terminal::Clear(terminal::ClearType::All)).unwrap();
stdout.execute(cursor::Hide).unwrap();
loop {
// 画面をクリア
stdout.execute(cursor::MoveTo(0, 0)).unwrap();
// 敵の位置を更新
enemy_pos.0 += 1;
if enemy_pos.0 >= HEIGHT {
enemy_pos = (0, rand::thread_rng().gen_range(0..WIDTH));
}
// 弾の位置を更新
bullets.retain(|&(y, _)| y > 0);
for bullet in &mut bullets {
bullet.0 -= 1;
}
// 弾が敵に当たったかチェック
if bullets.iter().any(|&bullet| bullet == enemy_pos) {
score += 1;
enemy_pos = (0, rand::thread_rng().gen_range(0..WIDTH));
bullets.retain(|&bullet| bullet != enemy_pos);
}
// 敵とプレイヤーが衝突したかチェック
if enemy_pos == (HEIGHT - 1, player_pos) {
collision = true;
break;
}
// 画面を描画
for y in 0..HEIGHT {
for x in 0..WIDTH {
if (y, x) == (HEIGHT - 1, player_pos) {
print!("P");
} else if (y, x) == enemy_pos {
print!("E");
} else if bullets.contains(&(y, x)) {
print!("|");
} else {
print!(".");
}
}
println!();
}
println!("Score: {}", score);
// プレイヤーの入力を処理
if let Ok(event) = rx.try_recv() {
if let Event::Key(KeyEvent { code, .. }) = event {
match code {
KeyCode::Char('a') => {
if player_pos > 0 {
player_pos -= 1;
}
}
KeyCode::Char('d') => {
if player_pos < WIDTH - 1 {
player_pos += 1;
}
}
KeyCode::Char(' ') => {
bullets.push((HEIGHT - 2, player_pos));
}
KeyCode::Char('q') => break,
_ => {}
}
}
}
// 少し待つ
thread::sleep(Duration::from_millis(100));
}
stdout.execute(cursor::Show).unwrap();
if collision {
let collision_pattern = [
" | ",
"\\*//"
];
for (i, line) in collision_pattern.iter().enumerate() {
stdout.execute(cursor::MoveTo((player_pos as u16).saturating_sub(1), (HEIGHT as u16).saturating_sub(2) + i as u16)).unwrap();
println!("{}", line);
}
// スコアの下にカーソルを移動して「GAME OVER!!」を表示
stdout.execute(cursor::MoveTo(0, (HEIGHT + 2) as u16)).unwrap();
println!("GAME OVER!!");
}
}
AI で生成されたコード。ご確認のうえ、慎重にご使用ください。FAQ で詳細を確認。
これで、ゲームオーバーの時点でスコアの下に「GAME OVER!!」が表示されるようになります。再度ビルドして試してみてください!

無事見事に仕様どおりに完成です。本当に素晴らしいと思います。
素晴らしいですね!ゲームが無事に動作して、衝突時の表示も期待通りになったようで良かったです。おめでとうございます!
他に何かお手伝いできることがあれば、いつでも教えてくださいね。楽しんでゲーム開発を続けてください!
—————————————————————————————————————
//// PR ///

取扱いコース が豊富! 無料体験コースあります!
・Web制作&デザインコース
・Web制作コース
・Webデザインコース
・動画編集コース
・Pythonコース
・Javaコース
・Rubyコース
・Shopifyコース
————————————————————————————————————–
過去記事は下記を参照ください。2013年からミリタリー同人活動を行っています。
サイトマップ | ミリタリーグッズ工房「猫・工・艦」 (necokoucan.com)
【ブログ記事一覧】 | ミリタリーグッズ工房「猫・工・艦」 (necokoucan.com)

