using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.IO;
public class SaveManager
{
const string location = "Assets/Resources/Data";
public static void SaveData<T>(string fileName, T template)
{
if (!Directory.Exists(location))
{
Directory.CreateDirectory(location);
}
string data = JsonUtility.ToJson(template);
string path = Path.Combine(location, fileName);
using (FileStream stream = new FileStream(path, FileMode.Create))
{
using (StreamWriter writer = new StreamWriter(stream))
{
writer.Write(data);
}
stream.Close();
}
Debug.Log("game saved");
}
public static T LoadData<T>(string fileName) where T : class
{
T load = null;
string read = "";
string path = Path.Combine(location, fileName);
if(!File.Exists(path))
{
return null;
}
using (FileStream stream=new FileStream(path,FileMode.Open))
{
using (StreamReader reader=new StreamReader(stream))
{
read = reader.ReadToEnd();
}
stream.Close();
}
load = JsonUtility.FromJson<T>(read);
return load;
}
}
タグ: programming
Unity C# Stats.cs
using UnityEngine;
[System.Serializable]
public class Stats // ← MonoBehaviourを削除
{
public int Level = 1;
public int maxHp = 1;
public int atk = 1;
public int def = 1;
public int mana = 1;
public int manaXSecond = 5;
public CharacterClass charClass = CharacterClass.warrior;
}
public enum CharacterClass
{
warrior,
maga,
priest,
paladin,
shamano,
druid,
rogue,
ranger
}
Unity player.cs
using Photon.Pun;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Player : Entity
{
CameraFollow follow;
[SerializeField]
float rotSpeed = 2;
[SerializeField]
float scrollAmount = 3;
[SerializeField]
float minZoom = 10, maxZoom = 120;
ActionController controller;
const float second = 1;
float manaCounter = 1;
public SaveData data = new SaveData();
// Start is called before the first frame update
public override void Init()
{
base.Init();
if (!photonView.IsMine) return;
data = SaveManager.LoadData<SaveData>(data.characterName);
if(data==null)
{
data = new SaveData();
}
controller = GetComponent<ActionController>();
controller.sync = sync;
controller.Init(this);
var f = Resources.Load<CameraFollow>(StaticStrings.follow);
follow = Instantiate(f, transform.position, transform.rotation);
follow.Init(transform);
WorldManager.instance.playerList.Add(transform);
UIManager.instance.player = this;
onDeathEvent = () =>
{
UIManager.instance.deathPanel.SetActive(true);
};
}
public override void Tick()
{
UseCamera();
if(controller.mana<stats.mana)
{
manaCounter -= Time.deltaTime;
if (manaCounter<=0)
{
manaCounter = second;
controller.mana += stats.manaXSecond;
if (controller.mana > stats.mana) controller.mana = stats.mana;
}
}
if (!CanMove()) return;
float x = Input.GetAxisRaw(StaticStrings.horizontal);
float y = Input.GetAxisRaw(StaticStrings.vertical);
Vector3 move = (transform.right * x) + (transform.forward * y);
move *= Time.deltaTime * moveMultipler * moveSpeed;
move.y = rb.velocity.y;
rb.velocity = move;
sync.Move(x, y);
controller.Tick(follow.transform,x,y);
}
void UseCamera()
{
float x = Input.GetAxis(StaticStrings.mouseX);
float scroll = Input.GetAxisRaw(StaticStrings.scroll);
Vector3 rot = follow.arm.rotation.eulerAngles;
follow.transform.rotation = Quaternion.Euler(rot.x, rot.y + x * rotSpeed, rot.z);
if(scroll!=0)
{
float val = scrollAmount * scroll;
val += follow.cam.fieldOfView;
val = Mathf.Clamp(val, minZoom, maxZoom);
follow.cam.fieldOfView = val;
}
}
bool CanMove()
{
if (isDeath) return false;
return true;
}
public void Respawn()
{
transform.position = WorldManager.instance.respawnPoint.position;
isDeath = false;
hp = stats.maxHp;
sync.IsDead(false);
if(Photon.Pun.PhotonNetwork.IsConnected)
{
view.RPC("SyncronizeStat", Photon.Pun.RpcTarget.All, hp);
}
}
}
UE5soulslikeGame
15パズル javascript
index.html
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="utf-8">
<title>15Puzzle</title>
<style>
canvas {
background: pink;
display: block;
margin: 0 auto;
cursor: pointer;
}
</style>
</head>
<body>
<canvas width="280" height="280">
Canvas not supported.
</canvas>
<script src="js/main.js"></script>
</body>
</html>
main.js
'use strict';
(() => {
class PuzzleRenderer {
constructor(puzzle, canvas) {
this.puzzle = puzzle;
this.canvas = canvas;
this.ctx = this.canvas.getContext('2d');
this.TILE_SIZE = 70;
this.img = document.createElement('img');
this.img.src = 'img/animal1.png';
this.img.addEventListener('load', () => {
this.render();
});
this.canvas.addEventListener('click', e => {
if (this.puzzle.getCompletedStatus()) {
return;
}
const rect = this.canvas.getBoundingClientRect();
const col = Math.floor((e.clientX - rect.left) / this.TILE_SIZE);
const row = Math.floor((e.clientY - rect.top) / this.TILE_SIZE);
this.puzzle.swapTiles(col, row);
this.render();
if (this.puzzle.isComplete()) {
this.puzzle.setCompletedStatus(true);
this.renderGameClear();
}
});
}
renderGameClear() {
this.ctx.fillStyle = 'rgba(0, 0, 0, 0.4)';
this.ctx.fillRect(0, 0, this.canvas.width, this.canvas.height);
this.ctx.font = '28px Arial';
this.ctx.fillStyle = '#fff';
this.ctx.fillText('GAME CLEAR!!', 40, 150);
}
render() {
for (let row = 0; row < this.puzzle.getBoardSize(); row++) {
for (let col = 0; col < this.puzzle.getBoardSize(); col++) {
this.renderTile(this.puzzle.getTile(row, col), col, row);
}
}
}
renderTile(n, col, row) {
if (n === this.puzzle.getBlankIndex()) {
this.ctx.fillStyle = '#eeeeee';
this.ctx.fillRect(
col * this.TILE_SIZE,
row * this.TILE_SIZE,
this.TILE_SIZE,
this.TILE_SIZE
);
} else {
this.ctx.drawImage(
this.img,
(n % this.puzzle.getBoardSize()) * this.TILE_SIZE,
Math.floor(n / this.puzzle.getBoardSize()) * this.TILE_SIZE,
this.TILE_SIZE,
this.TILE_SIZE,
col * this.TILE_SIZE,
row * this.TILE_SIZE,
this.TILE_SIZE,
this.TILE_SIZE
);
}
}
}
class Puzzle {
constructor(level) {
this.level = level;
this.tiles = [
[0, 1, 2, 3],
[4, 5, 6, 7],
[8, 9, 10, 11],
[12, 13, 14, 15],
];
this.UDLR = [
[0, -1], // up
[0, 1], // down
[-1, 0], // left
[1, 0], // right
];
this.isCompleted = false;
this.BOARD_SIZE = this.tiles.length;
this.BLANK_INDEX = this.BOARD_SIZE ** 2 - 1;
do {
this.shuffle(this.level);
} while (this.isComplete());
}
getBoardSize() {
return this.BOARD_SIZE;
}
getBlankIndex() {
return this.BLANK_INDEX;
}
getCompletedStatus() {
return this.isCompleted;
}
setCompletedStatus(value) {
this.isCompleted = value;
}
getTile(row, col) {
return this.tiles[row][col];
}
shuffle(n) {
let blankCol = this.BOARD_SIZE - 1;
let blankRow = this.BOARD_SIZE - 1;
for (let i = 0; i < n; i++) {
let destCol;
let destRow;
do {
const dir = Math.floor(Math.random() * this.UDLR.length);
destCol = blankCol + this.UDLR[dir][0];
destRow = blankRow + this.UDLR[dir][1];
} while (this.isOutside(destCol, destRow));
[
this.tiles[blankRow][blankCol],
this.tiles[destRow][destCol],
] = [
this.tiles[destRow][destCol],
this.tiles[blankRow][blankCol],
];
[blankCol, blankRow] = [destCol, destRow];
}
}
swapTiles(col, row) {
if (this.tiles[row][col] === this.BLANK_INDEX) {
return;
}
for (let i = 0; i < this.UDLR.length; i++) {
const destCol = col + this.UDLR[i][0];
const destRow = row + this.UDLR[i][1];
if (this.isOutside(destCol, destRow)) {
continue;
}
if (this.tiles[destRow][destCol] === this.BLANK_INDEX) {
[
this.tiles[row][col],
this.tiles[destRow][destCol],
] = [
this.tiles[destRow][destCol],
this.tiles[row][col],
];
break;
}
}
}
isOutside(destCol, destRow) {
return (
destCol < 0 || destCol > this.BOARD_SIZE - 1 ||
destRow < 0 || destRow > this.BOARD_SIZE - 1
);
}
isComplete() {
let i = 0;
for (let row = 0; row < this.BOARD_SIZE; row++) {
for (let col = 0; col < this.BOARD_SIZE; col++) {
if (this.tiles[row][col] !== i++) {
return false;
}
}
}
return true;
}
}
const canvas = document.querySelector('canvas');
if (typeof canvas.getContext === 'undefined') {
return;
}
new PuzzleRenderer(new Puzzle(2), canvas);
})();
Javascript 迷路
index.html
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="utf-8">
<title>My Maze</title>
</head>
<body>
<canvas>
Canvas not supported ...
</canvas>
<script src="js/main.js"></script>
</body>
</html>
main.js
'use strict';
(() => {
class MazeRenderer {
constructor(canvas) {
this.ctx = canvas.getContext('2d');
this.WALL_SIZE = 10;
}
render(data) {
canvas.height = data.length * this.WALL_SIZE;
canvas.width = data[0].length * this.WALL_SIZE;
for (let row = 0; row < data.length; row++) {
for (let col = 0; col < data[0].length; col++) {
if (data[row][col] === 1) {
this.ctx.fillRect(
col * this.WALL_SIZE,
row * this.WALL_SIZE,
this.WALL_SIZE,
this.WALL_SIZE
);
}
}
}
}
}
class Maze {
constructor(row, col, renderer) {
if (row < 5 || col < 5 || row % 2 === 0 || col % 2 === 0) {
alert('Size not valid!');
return;
}
this.renderer = renderer;
this.row = row;
this.col = col;
this.data = this.getData();
}
getData() {
const data = [];
for (let row = 0; row < this.row; row++) {
data[row] = [];
for (let col = 0; col < this.col; col++) {
data[row][col] = 1;
}
}
for (let row = 1; row < this.row - 1; row++) {
for (let col = 1; col < this.col - 1; col++) {
data[row][col] = 0;
}
}
for (let row = 2; row < this.row - 2; row += 2) {
for (let col = 2; col < this.col - 2; col += 2) {
data[row][col] = 1;
}
}
for (let row = 2; row < this.row - 2; row += 2) {
for (let col = 2; col < this.col - 2; col += 2) {
let destRow;
let destCol;
do {
const dir = row === 2 ?
Math.floor(Math.random() * 4) :
Math.floor(Math.random() * 3) + 1;
switch (dir) {
case 0: // up
destRow = row - 1;
destCol = col;
break;
case 1: // down
destRow = row + 1;
destCol = col;
break;
case 2: // left
destRow = row;
destCol = col - 1;
break;
case 3: // right
destRow = row;
destCol = col + 1;
break;
}
} while (data[destRow][destCol] === 1);
data[destRow][destCol] = 1;
}
}
return data;
}
render() {
this.renderer.render(this.data);
}
}
const canvas = document.querySelector('canvas');
if (typeof canvas.getContext === 'undefined') {
return;
}
const maze = new Maze(21, 15, new MazeRenderer(canvas));
maze.render();
})();
SNS
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>究極SNS</title>
<style>
* {
box-sizing: border-box;
margin: 0;
padding: 0;
}
body {
font-family: 'Segoe UI', Arial, sans-serif;
background-color: #f0f2f5;
color: #1c1e21;
line-height: 1.5;
transition: background-color 0.3s, color 0.3s;
}
body.dark-mode {
background-color: #18191a;
color: #e4e6eb;
}
.header {
background-color: #1877f2;
color: white;
padding: 10px 20px;
display: flex;
align-items: center;
justify-content: space-between;
position: sticky;
top: 0;
z-index: 100;
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
}
.header input {
padding: 10px 15px;
border: none;
border-radius: 25px;
width: 350px;
font-size: 14px;
background-color: #ffffff;
}
.nav {
display: flex;
align-items: center;
}
.nav a, .nav button {
color: white;
margin-left: 25px;
text-decoration: none;
font-weight: 500;
background: none;
border: none;
cursor: pointer;
position: relative;
}
.nav a:hover::after, .nav button:hover::after {
content: '';
position: absolute;
width: 50%;
height: 2px;
background-color: white;
bottom: -5px;
left: 25%;
}
.container {
display: flex;
max-width: 1400px;
margin: 20px auto;
gap: 25px;
}
.sidebar-left {
width: 25%;
padding: 15px;
position: sticky;
top: 70px;
height: fit-content;
}
.sidebar-card {
background-color: white;
border-radius: 10px;
padding: 20px;
box-shadow: 0 2px 6px rgba(0,0,0,0.05);
margin-bottom: 20px;
}
body.dark-mode .sidebar-card {
background-color: #242526;
}
.profile-pic {
width: 60px;
height: 60px;
border-radius: 50%;
background-color: #ddd;
margin: 0 auto 15px;
}
.badge {
display: inline-block;
background-color: #1877f2;
color: white;
padding: 2px 8px;
border-radius: 12px;
font-size: 12px;
margin-left: 5px;
}
.sidebar-left a {
display: block;
color: #1877f2;
text-decoration: none;
margin: 12px 0;
font-size: 15px;
}
.main-content {
width: 50%;
}
.sidebar-right {
width: 25%;
padding: 15px;
position: sticky;
top: 70px;
height: fit-content;
}
.post-box {
background-color: white;
padding: 20px;
border-radius: 10px;
box-shadow: 0 2px 6px rgba(0,0,0,0.05);
margin-bottom: 25px;
}
body.dark-mode .post-box {
background-color: #242526;
}
.post-input {
width: 100%;
padding: 12px 15px;
border: none;
border-radius: 25px;
background-color: #f0f2f5;
resize: none;
font-size: 16px;
outline: none;
}
body.dark-mode .post-input {
background-color: #3a3b3c;
color: #e4e6eb;
}
.post-actions {
display: flex;
justify-content: space-between;
margin-top: 15px;
flex-wrap: wrap;
gap: 10px;
}
.post-actions button {
background-color: #e4e6eb;
color: #050505;
border: none;
padding: 8px 15px;
border-radius: 6px;
cursor: pointer;
font-weight: 500;
transition: background-color 0.2s;
}
body.dark-mode .post-actions button {
background-color: #3a3b3c;
color: #e4e6eb;
}
.post-actions button:hover {
background-color: #d8dade;
}
body.dark-mode .post-actions button:hover {
background-color: #4a4b4c;
}
.post-actions .submit-btn {
background-color: #1877f2;
color: white;
}
.post {
background-color: white;
padding: 20px;
border-radius: 10px;
margin-bottom: 25px;
box-shadow: 0 2px 6px rgba(0,0,0,0.05);
position: relative;
}
body.dark-mode .post {
background-color: #242526;
}
.post-header {
display: flex;
align-items: center;
margin-bottom: 15px;
}
.post-header .profile-pic {
width: 40px;
height: 40px;
margin-right: 12px;
}
.post-header h3 {
margin: 0;
font-size: 16px;
font-weight: 600;
}
.post-header small {
color: #65676b;
font-size: 12px;
}
body.dark-mode .post-header small {
color: #b0b3b8;
}
.post-options {
position: absolute;
top: 10px;
right: 10px;
cursor: pointer;
color: #65676b;
}
.post-options:hover .options-menu {
display: block;
}
.options-menu {
display: none;
position: absolute;
top: 20px;
right: 0;
background-color: white;
border-radius: 8px;
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
padding: 10px;
z-index: 10;
}
body.dark-mode .options-menu {
background-color: #3a3b3c;
}
.options-menu a {
display: block;
color: #050505;
text-decoration: none;
padding: 5px 10px;
}
body.dark-mode .options-menu a {
color: #e4e6eb;
}
.post-image {
width: 100%;
height: 300px;
background-color: #ddd;
border-radius: 8px;
margin: 15px 0;
}
.reactions {
position: relative;
display: inline-block;
}
.reactions:hover .reaction-menu {
display: flex;
}
.reaction-menu {
display: none;
position: absolute;
top: -45px;
left: 0;
background-color: white;
padding: 8px;
border-radius: 25px;
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
gap: 8px;
z-index: 10;
}
body.dark-mode .reaction-menu {
background-color: #3a3b3c;
}
.reaction {
font-size: 22px;
cursor: pointer;
transition: transform 0.2s;
}
.reaction:hover {
transform: scale(1.2);
}
.reaction-stats {
margin-top: 5px;
font-size: 14px;
color: #65676b;
}
body.dark-mode .reaction-stats {
color: #b0b3b8;
}
.post-actions-bar {
display: flex;
justify-content: space-around;
padding: 10px 0;
border-top: 1px solid #e4e6eb;
border-bottom: 1px solid #e4e6eb;
color: #65676b;
font-size: 14px;
}
body.dark-mode .post-actions-bar {
border-color: #3a3b3c;
color: #b0b3b8;
}
.post-actions-bar span {
cursor: pointer;
padding: 5px 10px;
border-radius: 5px;
}
.post-actions-bar span:hover {
background-color: #f2f3f5;
}
body.dark-mode .post-actions-bar span:hover {
background-color: #3a3b3c;
}
.comment-section {
margin-top: 15px;
}
.comment {
display: flex;
align-items: flex-start;
margin-top: 12px;
}
.comment .profile-pic {
width: 32px;
height: 32px;
margin-right: 10px;
}
.comment-text {
background-color: #f2f3f5;
padding: 8px 12px;
border-radius: 18px;
font-size: 14px;
}
body.dark-mode .comment-text {
background-color: #3a3b3c;
color: #e4e6eb;
}
.comment-input {
width: 100%;
padding: 10px 15px;
border: none;
border-radius: 25px;
background-color: #f0f2f5;
font-size: 14px;
margin-top: 10px;
}
body.dark-mode .comment-input {
background-color: #3a3b3c;
color: #e4e6eb;
}
.chat-window {
background-color: white;
border-radius: 10px;
padding: 15px;
box-shadow: 0 2px 6px rgba(0,0,0,0.05);
}
body.dark-mode .chat-window {
background-color: #242526;
}
.chat-message {
margin: 10px 0;
}
.chat-message.sent .comment-text {
background-color: #1877f2;
color: white;
margin-left: auto;
}
.notification-popup {
position: fixed;
bottom: 20px;
right: 20px;
background-color: white;
padding: 15px;
border-radius: 8px;
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
z-index: 200;
}
body.dark-mode .notification-popup {
background-color: #242526;
}
.modal {
display: none;
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: rgba(0,0,0,0.5);
justify-content: center;
align-items: center;
z-index: 200;
}
.modal-content {
background-color: white;
padding: 25px;
border-radius: 10px;
width: 600px;
max-height: 80vh;
overflow-y: auto;
box-shadow: 0 4px 12px rgba(0,0,0,0.15);
}
body.dark-mode .modal-content {
background-color: #242526;
}
.footer {
background-color: white;
padding: 20px;
text-align: center;
color: #65676b;
border-top: 1px solid #e4e6eb;
font-size: 13px;
}
body.dark-mode .footer {
background-color: #18191a;
color: #b0b3b8;
border-color: #3a3b3c;
}
.footer a {
color: #65676b;
text-decoration: none;
margin: 0 10px;
}
body.dark-mode .footer a {
color: #b0b3b8;
}
.mobile-menu {
display: none;
position: fixed;
top: 60px;
left: 0;
width: 100%;
background-color: #1877f2;
padding: 15px;
z-index: 99;
}
.mobile-menu a {
color: white;
display: block;
margin: 10px 0;
text-decoration: none;
}
@media (max-width: 900px) {
.container {
flex-direction: column;
margin: 10px;
}
.sidebar-left, .main-content, .sidebar-right {
width: 100%;
position: static;
}
.header input {
width: 150px;
}
.nav {
display: none;
}
.mobile-menu {
display: block;
}
}
</style>
</head>
<body>
<!-- ヘッダー -->
<div class="header">
<h1>究極SNS</h1>
<input type="text" placeholder="友達、投稿、グループを検索">
<div class="nav">
<a href="#">ホーム</a>
<a href="#">友達</a>
<a href="#">メッセージ</a>
<a href="#">通知</a>
<a href="#">プロフィール</a>
<button onclick="document.body.classList.toggle('dark-mode')">ダークモード</button>
</div>
</div>
<div class="mobile-menu">
<a href="#">ホーム</a>
<a href="#">友達</a>
<a href="#">メッセージ</a>
<a href="#">通知</a>
<a href="#">プロフィール</a>
<a href="#" onclick="document.body.classList.toggle('dark-mode')">ダークモード</a>
</div>
<!-- メインコンテンツ -->
<div class="container">
<!-- 左サイドバー -->
<div class="sidebar-left">
<div class="sidebar-card">
<div class="profile-pic"></div>
<h3>ユーザー名 <span class="badge">認証済み</span></h3>
<a href="#">プロフィールを見る</a>
<a href="#">友達 (128)</a>
<a href="#">フォロワー (350)</a>
</div>
<div class="sidebar-card">
<h4>メニュー</h4>
<a href="#">グループ</a>
<a href="#">イベント</a>
<a href="#">マーケットプレイス</a>
<a href="#">設定</a>
</div>
</div>
<!-- 中央(投稿エリア) -->
<div class="main-content">
<!-- 投稿入力エリア -->
<div class="post-box">
<textarea class="post-input" rows="3" placeholder="何を思ってる?"></textarea>
<div class="post-actions">
<button>写真/動画</button>
<button>タグ友達</button>
<button>ライブ配信</button>
<button>イベント作成</button>
<button class="submit-btn" onclick="document.getElementById('postModal').style.display='flex'">投稿</button>
</div>
</div>
<!-- 投稿1 -->
<div class="post">
<div class="post-header">
<div class="profile-pic"></div>
<div>
<h3>山田太郎 <span class="badge">管理者</span></h3>
<small>2025年3月29日 10:30 ・ 公開</small>
</div>
<div class="post-options">⋯
<div class="options-menu">
<a href="#">編集</a>
<a href="#">削除</a>
<a href="#">非表示</a>
</div>
</div>
</div>
<p>新しいプロジェクトの進捗報告!チームで頑張ってます。</p>
<div class="post-image"></div>
<div class="reactions">
<div class="reaction-stats">👍 12 ❤️ 5 😂 3 😮 2</div>
<div class="reaction-menu">
<span class="reaction">👍</span>
<span class="reaction">❤️</span>
<span class="reaction">😂</span>
<span class="reaction">Grav😮</span>
<span class="reaction">😢</span>
</div>
</div>
<div class="post-actions-bar">
<span>リアクション</span>
<span>コメント</span>
<span>シェア</span>
</div>
<div class="comment-section">
<div class="comment">
<div class="profile-pic"></div>
<div class="comment-text"><strong>佐藤花子</strong>: すごい進捗だね!</div>
</div>
<div class="comment">
<div class="profile-pic"></div>
<div class="comment-text"><strong>鈴木次郎</strong>: お疲れ様!</div>
</div>
<input type="text" class="comment-input" placeholder="コメントを入力...">
</div>
</div>
<!-- 投稿2 -->
<div class="post">
<div class="post-header">
<div class="profile-pic"></div>
<div>
<h3>田中優子</h3>
<small>2025年3月29日 09:15 ・ 友達のみ</small>
</div>
<div class="post-options">⋯
<div class="options-menu">
<a href="#">編集</a>
<a href="#">削除</a>
<a href="#">非表示</a>
</div>
</div>
</div>
<p>週末の温泉旅行が楽しみすぎる!</p>
<div class="reactions">
<div class="reaction-stats">👍 8 ❤️ 6 😢 1</div>
<div class="reaction-menu">
<span class="reaction">👍</span>
<span class="reaction">❤️</span>
<span class="reaction">😂</span>
<span class="reaction">😮</span>
<span class="reaction">😢</span>
</div>
</div>
<div class="post-actions-bar">
<span>リアクション</span>
<span>コメント</span>
<span>シェア</span>
</div>
</div>
</div>
<!-- 右サイドバー -->
<div class="sidebar-right">
<div class="sidebar-card">
<h4>友達リスト</h4>
<p><strong>佐藤花子</strong> - オンライン</p>
<p><strong>鈴木次郎</strong> - 5分前</p>
<p><strong>高橋健太</strong> - オフライン</p>
</div>
<div class="sidebar-card">
<h4>グループ</h4>
<p><a href="#">プロジェクトチーム</a> - 15人</p>
<p><a href="#">温泉旅行クラブ</a> - 32人</p>
</div>
<div class="chat-window">
<h4>チャット - 佐藤花子</h4>
<div class="chat-message">
<div class="comment-text">おはよう!週末の予定は?</div>
</div>
<div class="chat-message sent">
<div class="comment-text">おはよう!温泉行くよ!</div>
</div>
<input type="text" class="comment-input" placeholder="メッセージを入力...">
</div>
</div>
</div>
<!-- 投稿モーダル -->
<div id="postModal" class="modal">
<div class="modal-content">
<h3>投稿を作成</h3>
<textarea rows="6" placeholder="詳細を書いてね" style="width: 100%; padding: 10px;"></textarea>
<div style="margin: 15px 0;">
<label>公開範囲: </label>
<select style="padding: 5px;">
<option>公開</option>
<option>友達のみ</option>
<option>自分のみ</option>
</select>
</div>
<div class="post-actions">
<button onclick="document.getElementById('postModal').style.display='none'">キャンセル</button>
<button class="submit-btn">投稿</button>
</div>
</div>
</div>
<!-- 通知ポップアップ -->
<div class="notification-popup">
<p><strong>佐藤花子</strong>があなたの投稿にリアクションしました。</p>
</div>
<!-- フッター -->
<div class="footer">
<p>© 2025 究極SNS. All rights reserved.</p>
<p><a href="#">プライバシー</a> | <a href="#">利用規約</a> | <a href="#">サポート</a> | <a href="#">言語</a></p>
</div>
<script>
// 簡易的な通知ポップアップの表示制御(サンプル)
setTimeout(() => {
document.querySelector('.notification-popup').style.display = 'block';
setTimeout(() => {
document.querySelector('.notification-popup').style.display = 'none';
}, 3000);
}, 2000);
</script>
</body>
</html>
ダンジョンのギミック
1. ダンジョンの構成要素
- 入口・出口
- プレイヤーがダンジョンに入るポイントと、クリアのために到達する出口。
- 部屋(Room)
- 敵との戦闘やイベントが起こる場所。
- 宝箱やNPCとの出会いが配置可能。
- 通路(Corridor)
- 部屋同士を繋ぐ経路。
- 単純な一本道、迷路、あるいは分岐などが考えられる。
- 罠(Trap)
- プレイヤーの行動を制限・妨害する仕掛け。
- 鍵や扉
- 特定のアイテムや条件を満たさないと先へ進めない仕掛け。
2. 敵の出現パターン
- 固定配置型
- 敵が決まった場所に存在。
- ランダムエンカウント型
- 移動時や特定条件でランダムに敵が出現。
- 条件トリガー型
- 宝箱を開けたりスイッチを押すと敵が出現。
3. アイテム配置ロジック
- 宝箱の配置
- 回復アイテムや装備、重要な鍵アイテムを適度に分散。
- ドロップアイテム
- 敵がランダムで落とすアイテム。
4. 探索と謎解き要素
- パズルギミック
- スイッチやレバー、順番通りに動かすパズルなど。
- ヒントの設置
- 壁画やメモ、NPCの会話などでプレイヤーに手がかりを与える。
5. 難易度調整ロジック
- ダンジョン階層
- 下に行くほど敵が強くなるような階層型。
- プレイヤーレベル連動
- プレイヤーのレベルに応じて敵や報酬の内容が変わる。
6. 報酬のロジック
- ボス討伐時の報酬
- 装備品、経験値、特別なスキル。
- クリア後のリプレイ性
- 特定条件を満たしてクリアすると追加報酬や新規ルートが解放。
CSS メディアクエリー
style.css
@charset "utf-8";
.card {
border: 1px solid #ccc;
box-sizing: border-box;
padding: 16px;
max-width: 600px;
margin: 0 auto;
&:hover {
box-shadow: 0 0 8px rgb(0 0 0 / 0.3);
}
h2 {
margin: 0;
border-bottom: 1px solid #ccc;
text-align: center;
font-size: 18px;
padding-bottom: 8px;
}
p {
margin: 16px 0 0;
line-height: 1.6;
}
}
@media (width >=600px) {
.card h2 {
text-align: left;
}
}
index.html
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>My CSS Nesting</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<section class="card">
<h2>こんにちは</h2>
<p>こんにちは。こんにちは。こんにちは。こんにちは。こんにちは。こんにちは。こんにちは。こんにちは。こんにちは。こんにちは。こんにちは。こんにちは。</p>
</section>
</body>
</html>
PS6企画書
PlayStation 6(PS6)企画書
1. コンセプト
次世代ゲーミング体験を創造する、革新的で没入感の高いゲームプラットフォーム。
2. 製品概要
- 名称:PlayStation 6 (PS6)
- 発売予定年:2028年
- コンセプトフレーズ:「境界を超えたリアル」
3. 特徴と機能
- 超リアルグラフィック:8K~16K対応、高度なレイトレーシング技術。
- フルダイブ型VR対応:完全没入型のVR体験を提供。
- ハプティックと触覚技術:全身で感じられる振動フィードバックシステム。
- クラウド統合:高速クラウドストリーミングとAIベースのインタラクション。
- 環境連動型ゲームプレイ:プレイヤーの環境に応じてゲーム内環境が動的に変化。
4. 技術仕様
- プロセッサ:次世代AMDカスタムプロセッサ(Zen 6ベース)
- グラフィック:次世代RDNA 5アーキテクチャ
- メモリ:64GB GDDR7
- ストレージ:SSD 4TB(超高速ロード技術)
- 接続性:Wi-Fi 7、Bluetooth 6.0、USB-C 4.0、Thunderbolt 5
- VRデバイス:専用フルダイブVRヘッドセット「PS VR Dive」対応
5. ソフトウェアラインナップ(仮)
- ファーストパーティタイトル
- 新規AAAオープンワールドRPG
- グランツーリスモ 8
- ホライゾン:新章
- サードパーティタイトル
- 大手サードパーティ各社と協力した大型IPタイトルの新作
6. マーケティング戦略
- グローバルイベントを開催し、実機体験型プロモーションを展開。
- SNSや動画プラットフォームを駆使したバイラルマーケティング。
- 世界各地の主要都市でVR体験イベントを開催。
7. ターゲットユーザー
- ゲーム愛好家(コアゲーマー)
- テクノロジーに関心の高い若年層から中年層
- VR/AR市場の新規ユーザー層
8. 市場目標
- 世界累計販売台数:初年度1500万台
- VR市場シェアの拡大
以上をもって、PlayStation 6の新たなゲーム体験を世界に提供します。
