ChatGPT4に作ってもらったRPGゲームの素その2。~イベント~
前回
Block版
マップのオブジェクトを増やし、プレイヤーに反応してイベントを発動するようにした。否、してもらった。してって言ったらChatGPTがしてくれた。
増えたマップオブジェクトは、敷き詰めるためだけの何もしないCellBase。
プレイヤーが進入できないBlock。
ソース全部
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Game</title>
<style>
canvas {
display: block;
margin: 0 auto;
background-color: #f0f0f0;
}
</style>
</head>
<body>
<canvas id="gameCanvas" width="320" height="320"></canvas>
<script>
let objectIdCounter = 0;
class MapObject {
constructor(x, y) {
this.x = x;
this.y = y;
this.onObjectEnter = null;
}
draw(context2d) {
// 基本の描画処理は何もしない
}
triggerEvent(object) {
if (this.onObjectEnter) {
return this.onObjectEnter(object);
}
return true; // Default behavior is to allow the object to enter
}
}
class CellBase extends MapObject {
constructor(x, y) {
super(x, y);
}
draw(context2d) {
context2d.fillStyle = 'gray';
context2d.fillRect(this.x * 32, this.y * 32, 32, 32);
}
}
class Block extends MapObject {
constructor(x, y) {
super(x, y);
this.onObjectEnter = (object) => {
// Block the object from entering the block
return false;
};
}
draw(context2d) {
context2d.fillStyle = 'black';
context2d.fillRect(this.x * 32, this.y * 32, 32, 32);
}
}
class Player extends MapObject {
constructor(x, y) {
super(x, y);
}
move(direction) {
let newX = this.x;
let newY = this.y;
switch (direction) {
case 1:
newX -= 1;
newY += 1;
break;
case 2:
newY += 1;
break;
case 3:
newX += 1;
newY += 1;
break;
case 4:
newX -= 1;
break;
case 6:
newX += 1;
break;
case 7:
newX -= 1;
newY -= 1;
break;
case 8:
newY -= 1;
break;
case 9:
newX += 1;
newY -= 1;
break;
default:
console.log("Invalid direction. Please enter a valid number (1-9, excluding 5).");
break;
}//switch
if (gameMap.triggerEvent(newX, newY, this)) {
this.x = newX;
this.y = newY;
}
}//move
draw(context2d) {
context2d.fillStyle = 'blue';
context2d.fillRect(this.x * 32, this.y * 32, 32, 32);
}
}//player
class Map {
constructor(w, h) {
this.Width = w;
this.Height = h;
this.GameBoard = Array.from({ length: this.Height }, () => Array(this.Width).fill(null));
this.MapObjects = [];
// Fill the map with CellBase objects
for (let y = 0; y < this.Height; y++) {
for (let x = 0; x < this.Width; x++) {
const cell = new CellBase(x, y);
this.addObject(cell);
}
}
// Surround the map with Block objects
for (let y = 0; y < this.Height; y++) {
for (let x = 0; x < this.Width; x++) {
if (y === 0 || y === this.Height - 1 || x === 0 || x === this.Width - 1) {
const block = new Block(x, y);
this.addObject(block);
}
}
}
// Add some Block objects randomly on the map
const randomBlockPositions = [
{ x: 3, y: 3 },
{ x: 6, y: 2 },
{ x: 2, y: 5 }
];
for (const position of randomBlockPositions) {
const block = new Block(position.x, position.y);
this.addObject(block);
}
}
addObject(mapObject) {
if (mapObject instanceof MapObject) {
this.MapObjects.push(mapObject);
this.GameBoard[mapObject.y][mapObject.x] = mapObject;
}
}
removeObject(mapObject) {
if (mapObject instanceof MapObject) {
const index = this.MapObjects.indexOf(mapObject);
if (index > -1) {
this.MapObjects.splice(index, 1);
this.GameBoard[mapObject.y][mapObject.x] = null;
}
}
}
draw(context2d) {
// Draw background
context2d.fillStyle = 'white';
context2d.fillRect(0, 0, this.Width * 32, this.Height * 32);
// Draw grid
context2d.strokeStyle = 'black';
context2d.lineWidth = 1;
for (let y = 0; y <= this.Height; y++) {
context2d.beginPath();
context2d.moveTo(0, y * 32);
context2d.lineTo(this.Width * 32, y * 32);
context2d.stroke();
}
for (let x = 0; x <= this.Width; x++) {
context2d.beginPath();
context2d.moveTo(x * 32, 0);
context2d.lineTo(x * 32, this.Height * 32);
context2d.stroke();
}
// Draw objects
for (const obj of this.MapObjects) {
obj.draw(context2d);
}
}//draw
triggerEvent(x, y, object) {
const mapObject = this.GameBoard[y][x];
if (mapObject) {
return mapObject.triggerEvent(object);
}
return true; // Default behavior is to allow the object to enter
}
}//Map
const canvas = document.getElementById('gameCanvas');
const context2d = canvas.getContext('2d');
const gameMap = new Map(10, 10);
const player = new Player(4, 4);
gameMap.addObject(player);
let lastFrameTime = performance.now();
const targetFrameDuration = 1000 / 60; // 60FPSの場合のフレーム間隔(ミリ秒)
const keyStates = {};
function gameLoop(currentTime) {
const deltaTime = currentTime - lastFrameTime;
if (deltaTime >= targetFrameDuration) {
update(deltaTime);
draw();
lastFrameTime = currentTime;
}
requestAnimationFrame(gameLoop);
}
function update(deltaTime) {
for (const key in keyStates) {
const state = keyStates[key];
if (state === 'pressed') {
const direction = directionKeyMap[key];
if (direction) {
player.move(direction);
}
keyStates[key] = 'holding';
}
}
}
function keydownHandler(event) {
if (!keyStates[event.code]) {
keyStates[event.code] = 'pressed';
}
}
function keyupHandler(event) {
delete keyStates[event.code];
}
function draw() {
gameMap.draw(context2d);
}
const directionKeyMap = {
'Numpad1': 1,
'Numpad2': 2,
'Numpad3': 3,
'Numpad4': 4,
'Numpad6': 6,
'Numpad7': 7,
'Numpad8': 8,
'Numpad9': 9,
'ArrowDown': 2,
'ArrowUp': 8,
'ArrowLeft': 4,
'ArrowRight': 6,
};
document.addEventListener("keydown", keydownHandler);
document.addEventListener("keyup", keyupHandler);
requestAnimationFrame(gameLoop);
</script>
</body>
</html>
レイヤー多層化
グリッドの各セルが、MapObjectを複数格納する。
描画は下から順に、イベントは上から順に反応するものとする。
class MapObject {
// ... (MapObject, CellBase, Block, Playerクラスに変更はありません)
}
class Blank extends MapObject {
constructor(x, y) {
super(x, y);
}
}
class Map {
constructor(w, h) {
this.Width = w;
this.Height = h;
this.GameBoard = Array.from({ length: this.Height }, () => Array(this.Width).fill([]));
this.MapObjects = [];
// ... (マップの初期化処理に変更はありません)
}
addObject(mapObject) {
if (mapObject instanceof MapObject) {
this.MapObjects.push(mapObject);
this.GameBoard[mapObject.y][mapObject.x] = [...this.GameBoard[mapObject.y][mapObject.x], mapObject];
}
}
removeObject(mapObject) {
if (mapObject instanceof MapObject) {
const index = this.MapObjects.indexOf(mapObject);
if (index > -1) {
this.MapObjects.splice(index, 1);
this.GameBoard[mapObject.y][mapObject.x] = this.GameBoard[mapObject.y][mapObject.x].filter(obj => obj !== mapObject);
}
}
}
draw(context2d) {
// ... (背景とグリッドの描画処理に変更はありません)
// Draw objects from bottom to top
for (let y = 0; y < this.Height; y++) {
for (let x = 0; x < this.Width; x++) {
const objectsInCell = this.GameBoard[y][x];
for (const obj of objectsInCell) {
obj.draw(context2d);
}
}
}
}
triggerEvent(x, y, object) {
const objectsInCell = this.GameBoard[y][x];
for (let i = objectsInCell.length - 1; i >= 0; i--) {
const mapObject = objectsInCell[i];
if (mapObject) {
const result = mapObject.triggerEvent(object);
if (!result) {
return false;
}
}
}
return true; // Default behavior is to allow the object to enter
}
}
Player.Moveの変更
class Player extends MapObject {
// ...
move(direction) {
let newX = this.x;
let newY = this.y;
// ... (座標の更新処理に変更はありません)
if (gameMap.triggerEvent(newX, newY, this)) {
gameMap.removeObject(this); // 追加: 古いセルからプレイヤーを削除
this.x = newX;
this.y = newY;
gameMap.addObject(this); // 追加: 新しいセルにプレイヤーを追加
}
}
// ...
}
ソース全部
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Game</title>
<style>
canvas {
display: block;
margin: 0 auto;
background-color: #f0f0f0;
}
</style>
</head>
<body>
<canvas id="gameCanvas" width="320" height="320"></canvas>
<script>
let objectIdCounter = 0;
class MapObject {
constructor(x, y) {
this.x = x;
this.y = y;
this.onObjectEnter = null;
}
draw(context2d) {
// 基本の描画処理は何もしない
}
triggerEvent(object) {
if (this.onObjectEnter) {
return this.onObjectEnter(object);
}
return true; // Default behavior is to allow the object to enter
}
}
class CellBase extends MapObject {
constructor(x, y) {
super(x, y);
}
draw(context2d) {
context2d.fillStyle = 'gray';
context2d.fillRect(this.x * 32, this.y * 32, 32, 32);
}
}
class Block extends MapObject {
constructor(x, y) {
super(x, y);
this.onObjectEnter = (object) => {
// Block the object from entering the block
return false;
};
}
draw(context2d) {
context2d.fillStyle = 'black';
context2d.fillRect(this.x * 32, this.y * 32, 32, 32);
}
}
class Blank extends MapObject {
constructor(x, y) {
super(x, y);
}
}
class Player extends MapObject {
constructor(x, y) {
super(x, y);
}
move(direction) {
let newX = this.x;
let newY = this.y;
switch (direction) {
case 1:
newX -= 1;
newY += 1;
break;
case 2:
newY += 1;
break;
case 3:
newX += 1;
newY += 1;
break;
case 4:
newX -= 1;
break;
case 6:
newX += 1;
break;
case 7:
newX -= 1;
newY -= 1;
break;
case 8:
newY -= 1;
break;
case 9:
newX += 1;
newY -= 1;
break;
default:
console.log("Invalid direction. Please enter a valid number (1-9, excluding 5).");
break;
}//switch
if (gameMap.triggerEvent(newX, newY, this)) {
gameMap.removeObject(this); // 追加: 古いセルからプレイヤーを削除
this.x = newX;
this.y = newY;
gameMap.addObject(this); // 追加: 新しいセルにプレイヤーを追加
}
}//move
draw(context2d) {
context2d.fillStyle = 'blue';
context2d.fillRect(this.x * 32, this.y * 32, 32, 32);
}
}//player
class Map {
constructor(w, h) {
this.Width = w;
this.Height = h;
this.GameBoard = Array.from({ length: this.Height }, () => Array(this.Width).fill([]));
this.MapObjects = [];
// Fill the map with CellBase objects
for (let y = 0; y < this.Height; y++) {
for (let x = 0; x < this.Width; x++) {
const cell = new CellBase(x, y);
this.addObject(cell);
}
}
// Surround the map with Block objects
for (let y = 0; y < this.Height; y++) {
for (let x = 0; x < this.Width; x++) {
if (y === 0 || y === this.Height - 1 || x === 0 || x === this.Width - 1) {
const block = new Block(x, y);
this.addObject(block);
}
}
}
// Add some Block objects randomly on the map
const randomBlockPositions = [
{ x: 3, y: 3 },
{ x: 6, y: 2 },
{ x: 2, y: 5 }
];
for (const position of randomBlockPositions) {
const block = new Block(position.x, position.y);
this.addObject(block);
}
}//constructor
addObject(mapObject) {
if (mapObject instanceof MapObject) {
this.MapObjects.push(mapObject);
this.GameBoard[mapObject.y][mapObject.x] = [...this.GameBoard[mapObject.y][mapObject.x], mapObject];
}
}
removeObject(mapObject) {
if (mapObject instanceof MapObject) {
const index = this.MapObjects.indexOf(mapObject);
if (index > -1) {
this.MapObjects.splice(index, 1);
this.GameBoard[mapObject.y][mapObject.x] = this.GameBoard[mapObject.y][mapObject.x].filter(obj => obj !== mapObject);
}
}
}
draw(context2d) {
// Draw background
context2d.fillStyle = 'white';
context2d.fillRect(0, 0, this.Width * 32, this.Height * 32);
// Draw grid
context2d.strokeStyle = 'black';
context2d.lineWidth = 1;
for (let y = 0; y <= this.Height; y++) {
context2d.beginPath();
context2d.moveTo(0, y * 32);
context2d.lineTo(this.Width * 32, y * 32);
context2d.stroke();
}
for (let x = 0; x <= this.Width; x++) {
context2d.beginPath();
context2d.moveTo(x * 32, 0);
context2d.lineTo(x * 32, this.Height * 32);
context2d.stroke();
}
// Draw objects from bottom to top
for (let y = 0; y < this.Height; y++) {
for (let x = 0; x < this.Width; x++) {
const objectsInCell = this.GameBoard[y][x];
for (const obj of objectsInCell) {
obj.draw(context2d);
}
}
}
}//draw
triggerEvent(x, y, object) {
const objectsInCell = this.GameBoard[y][x];
for (let i = objectsInCell.length - 1; i >= 0; i--) {
const mapObject = objectsInCell[i];
if (mapObject) {
const result = mapObject.triggerEvent(object);
if (!result) {
return false;
}
}
}
return true; // Default behavior is to allow the object to enter
}
}//Map
const canvas = document.getElementById('gameCanvas');
const context2d = canvas.getContext('2d');
const gameMap = new Map(10, 10);
const player = new Player(4, 4);
gameMap.addObject(player);
let lastFrameTime = performance.now();
const targetFrameDuration = 1000 / 60; // 60FPSの場合のフレーム間隔(ミリ秒)
const keyStates = {};
function gameLoop(currentTime) {
const deltaTime = currentTime - lastFrameTime;
if (deltaTime >= targetFrameDuration) {
update(deltaTime);
draw();
lastFrameTime = currentTime;
}
requestAnimationFrame(gameLoop);
}
function update(deltaTime) {
for (const key in keyStates) {
const state = keyStates[key];
if (state === 'pressed') {
const direction = directionKeyMap[key];
if (direction) {
player.move(direction);
}
keyStates[key] = 'holding';
}
}
}
function keydownHandler(event) {
if (!keyStates[event.code]) {
keyStates[event.code] = 'pressed';
}
}
function keyupHandler(event) {
delete keyStates[event.code];
}
function draw() {
gameMap.draw(context2d);
}
const directionKeyMap = {
'Numpad1': 1,
'Numpad2': 2,
'Numpad3': 3,
'Numpad4': 4,
'Numpad6': 6,
'Numpad7': 7,
'Numpad8': 8,
'Numpad9': 9,
'ArrowDown': 2,
'ArrowUp': 8,
'ArrowLeft': 4,
'ArrowRight': 6,
};
document.addEventListener("keydown", keydownHandler);
document.addEventListener("keyup", keyupHandler);
requestAnimationFrame(gameLoop);
</script>
</body>
</html>
イベント発動、メッセージウィンドウ追加
メッセージウィンドウ
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Game</title>
<style>
canvas {
display: block;
margin: 0 auto;
background-color: #f0f0f0;
}
#messageWindow {
width: 320px;
height: 50px;
margin: 10px auto 0;
border: 1px solid black;
text-align: center;
line-height: 50px;
}
</style>
</head>
<body>
<canvas id="gameCanvas" width="320" height="320"></canvas>
<div id="messageWindow"></div>
<!-- 以下の JavaScript コードは以前と同様です。 -->
踏んだらイベント発動Blankセル
class Blank extends MapObject {
constructor(x, y) {
super(x, y);
this.onObjectEnter = (object) => {
showMessage('test');
return true; // Allow the object to enter
};
}
}
showMessageおよびMapコンストラクタ内でのBlank作成
// Add a message window
const messageWindow = document.getElementById('messageWindow');
function showMessage(message) {
messageWindow.textContent = message;
}
class Map {
constructor(w, h) {
// ... (以前のコード)
// Add a Blank object with a "test" message at a random accessible position
let randomX, randomY;
do {
randomX = Math.floor(Math.random() * (this.Width - 2)) + 1;
randomY = Math.floor(Math.random() * (this.Height - 2)) + 1;
} while (this.GameBoard[randomY][randomX] instanceof Block);
const blank = new Blank(randomX, randomY);
this.addObject(blank);
}
// ...
}
ソース全部
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Game</title>
<style>
canvas {
display: block;
margin: 0 auto;
background-color: #f0f0f0;
}
#messageWindow {
width: 320px;
height: 50px;
margin: 10px auto 0;
border: 1px solid black;
text-align: center;
line-height: 50px;
}
</style>
</head>
<body>
<canvas id="gameCanvas" width="320" height="320"></canvas>
<div id="messageWindow"></div>
<script>
let objectIdCounter = 0;
class MapObject {
constructor(x, y) {
this.x = x;
this.y = y;
this.onObjectEnter = null;
}
draw(context2d) {
// 基本の描画処理は何もしない
}
triggerEvent(object) {
if (this.onObjectEnter) {
return this.onObjectEnter(object);
}
return true; // Default behavior is to allow the object to enter
}
}
class CellBase extends MapObject {
constructor(x, y) {
super(x, y);
}
draw(context2d) {
context2d.fillStyle = 'gray';
context2d.fillRect(this.x * 32, this.y * 32, 32, 32);
}
}
class Block extends MapObject {
constructor(x, y) {
super(x, y);
this.onObjectEnter = (object) => {
// Block the object from entering the block
return false;
};
}
draw(context2d) {
context2d.fillStyle = 'black';
context2d.fillRect(this.x * 32, this.y * 32, 32, 32);
}
}
class Blank extends MapObject {
constructor(x, y) {
super(x, y);
this.onObjectEnter = (object) => {
showMessage('test');
return true; // Allow the object to enter
};
}
}
class Player extends MapObject {
constructor(x, y) {
super(x, y);
}
move(direction) {
let newX = this.x;
let newY = this.y;
switch (direction) {
case 1:
newX -= 1;
newY += 1;
break;
case 2:
newY += 1;
break;
case 3:
newX += 1;
newY += 1;
break;
case 4:
newX -= 1;
break;
case 6:
newX += 1;
break;
case 7:
newX -= 1;
newY -= 1;
break;
case 8:
newY -= 1;
break;
case 9:
newX += 1;
newY -= 1;
break;
default:
console.log("Invalid direction. Please enter a valid number (1-9, excluding 5).");
break;
}//switch
if (gameMap.triggerEvent(newX, newY, this)) {
gameMap.removeObject(this); // 追加: 古いセルからプレイヤーを削除
this.x = newX;
this.y = newY;
gameMap.addObject(this); // 追加: 新しいセルにプレイヤーを追加
}
}//move
draw(context2d) {
context2d.fillStyle = 'blue';
context2d.fillRect(this.x * 32, this.y * 32, 32, 32);
}
}//player
// Add a message window
const messageWindow = document.getElementById('messageWindow');
function showMessage(message) {
messageWindow.textContent = message;
}
class Map {
constructor(w, h) {
this.Width = w;
this.Height = h;
this.GameBoard = Array.from({ length: this.Height }, () => Array(this.Width).fill([]));
this.MapObjects = [];
// Fill the map with CellBase objects
for (let y = 0; y < this.Height; y++) {
for (let x = 0; x < this.Width; x++) {
const cell = new CellBase(x, y);
this.addObject(cell);
}
}
// Surround the map with Block objects
for (let y = 0; y < this.Height; y++) {
for (let x = 0; x < this.Width; x++) {
if (y === 0 || y === this.Height - 1 || x === 0 || x === this.Width - 1) {
const block = new Block(x, y);
this.addObject(block);
}
}
}
// Add some Block objects randomly on the map
const randomBlockPositions = [
{ x: 3, y: 3 },
{ x: 6, y: 2 },
{ x: 2, y: 5 }
];
for (const position of randomBlockPositions) {
const block = new Block(position.x, position.y);
this.addObject(block);
}
// Add a Blank object with a "test" message at a random accessible position
let randomX, randomY;
do {
randomX = Math.floor(Math.random() * (this.Width - 2)) + 1;
randomY = Math.floor(Math.random() * (this.Height - 2)) + 1;
} while (this.GameBoard[randomY][randomX] instanceof Block);
const blank = new Blank(randomX, randomY);
this.addObject(blank);
}
addObject(mapObject) {
if (mapObject instanceof MapObject) {
this.MapObjects.push(mapObject);
this.GameBoard[mapObject.y][mapObject.x] = [...this.GameBoard[mapObject.y][mapObject.x], mapObject];
}
}
removeObject(mapObject) {
if (mapObject instanceof MapObject) {
const index = this.MapObjects.indexOf(mapObject);
if (index > -1) {
this.MapObjects.splice(index, 1);
this.GameBoard[mapObject.y][mapObject.x] = this.GameBoard[mapObject.y][mapObject.x].filter(obj => obj !== mapObject);
}
}
}
draw(context2d) {
// Draw background
context2d.fillStyle = 'white';
context2d.fillRect(0, 0, this.Width * 32, this.Height * 32);
// Draw grid
context2d.strokeStyle = 'black';
context2d.lineWidth = 1;
for (let y = 0; y <= this.Height; y++) {
context2d.beginPath();
context2d.moveTo(0, y * 32);
context2d.lineTo(this.Width * 32, y * 32);
context2d.stroke();
}
for (let x = 0; x <= this.Width; x++) {
context2d.beginPath();
context2d.moveTo(x * 32, 0);
context2d.lineTo(x * 32, this.Height * 32);
context2d.stroke();
}
// Draw objects from bottom to top
for (let y = 0; y < this.Height; y++) {
for (let x = 0; x < this.Width; x++) {
const objectsInCell = this.GameBoard[y][x];
for (const obj of objectsInCell) {
obj.draw(context2d);
}
}
}
}//draw
triggerEvent(x, y, object) {
const objectsInCell = this.GameBoard[y][x];
for (let i = objectsInCell.length - 1; i >= 0; i--) {
const mapObject = objectsInCell[i];
if (mapObject) {
const result = mapObject.triggerEvent(object);
if (!result) {
return false;
}
}
}
return true; // Default behavior is to allow the object to enter
}
}//Map
const canvas = document.getElementById('gameCanvas');
const context2d = canvas.getContext('2d');
const gameMap = new Map(10, 10);
const player = new Player(4, 4);
gameMap.addObject(player);
let lastFrameTime = performance.now();
const targetFrameDuration = 1000 / 60; // 60FPSの場合のフレーム間隔(ミリ秒)
const keyStates = {};
function gameLoop(currentTime) {
const deltaTime = currentTime - lastFrameTime;
if (deltaTime >= targetFrameDuration) {
update(deltaTime);
draw();
lastFrameTime = currentTime;
}
requestAnimationFrame(gameLoop);
}
function update(deltaTime) {
for (const key in keyStates) {
const state = keyStates[key];
if (state === 'pressed') {
const direction = directionKeyMap[key];
if (direction) {
player.move(direction);
}
keyStates[key] = 'holding';
}
}
}
function keydownHandler(event) {
if (!keyStates[event.code]) {
keyStates[event.code] = 'pressed';
}
}
function keyupHandler(event) {
delete keyStates[event.code];
}
function draw() {
gameMap.draw(context2d);
}
const directionKeyMap = {
'Numpad1': 1,
'Numpad2': 2,
'Numpad3': 3,
'Numpad4': 4,
'Numpad6': 6,
'Numpad7': 7,
'Numpad8': 8,
'Numpad9': 9,
'ArrowDown': 2,
'ArrowUp': 8,
'ArrowLeft': 4,
'ArrowRight': 6,
};
document.addEventListener("keydown", keydownHandler);
document.addEventListener("keyup", keyupHandler);
requestAnimationFrame(gameLoop);
</script>
</body>
</html>
この記事が気に入ったらサポートをしてみませんか?