【Unity】エディタ拡張でゲームを作る
エディタ上で動くゲームをつくりました。かんたんなシューティングです。
ゲーム制作に疲れたときに遊べるのでおすすめです(?)
youtu.be
制作のポイント
Event.current
OnGUIがどのイベントで呼ばれているか取得できる&キー入力などを検知できる
EditorGUI.DrawPreviewTexture
Rectクラスを使って位置が指定できるので、テクスチャを動かせる
Repaint()
Repaintイベントを呼び出せるので、Update関数内で使うと作ったゲームがエディタで動くようになる
動かし方
以下のソースコード6つをEditorフォルダに入れて、Resourcesフォルダに画像ファイルを二つ入れます。
imagePath1、imagePath2の宣言部分に画像の名前を同じものを入れてください。
ソースコード
EditorGame.cs
using System.Collections.Generic; using UnityEngine; using UnityEditor; using EditorShootingGame; public class EditorGame : EditorWindow { private static bool gameStarted; private static bool gameEnded; private static bool changeRoutineFlag; private static Player player; private static EnemyGenerator enemyGenerator; private static List<Bullet> bullets = new List<Bullet>(); private static List<Enemy> enemies = new List<Enemy>(); private static string imagePath1 = "Assets/Resources/Rect.png"; private static string imagePath2 = "Assets/Resources/Rect2.png"; private static Texture2D image1; private static Texture2D image2; public static Event _event; private static int Score; //スコア [MenuItem("EditorGame/Shooting")] public static void Open () { var window = CreateInstance<EditorGame>(); window.Show(); Initialize(); } /// <summary> /// 初期化 /// </summary> private static void Initialize () { gameStarted = false; gameEnded = false; changeRoutineFlag = false; player = new Player(image1,Vector2.zero); enemyGenerator = new EnemyGenerator(); bullets = new List<Bullet>(); enemies = new List<Enemy>(); image1 = AssetDatabase.LoadAssetAtPath<Texture2D>(imagePath1); image2 = AssetDatabase.LoadAssetAtPath<Texture2D>(imagePath2); Score = 0; } private void OnGUI () { ShowBackground(); _event = Event.current; if(!gameStarted) { if(GUILayout.Button("START",GUILayout.Width(position.width - 5))) { gameStarted = true; player.Pos = new Vector2(position.width / 2,position.height / 2); } } else { if(!gameEnded) { //プレイヤーがないならリターン if(player == null) return; LogicPlayer(); LogicEnemy(); LogicBullet(); ShowPlayer(); ShowEnemy(); ShowBullet(); ShowScore(20,20,TextAnchor.MiddleCenter); CheckCollideEnemyToBullet(); CheckCollidePlayerToEnemy(); } else { //イベントタイプのチェック if(!IsRunEventType(EventType.Layout)) { return; } if(GUILayout.Button("RESTART",GUILayout.Width(position.width - 5))) { Initialize(); } ShowScore(position.y / 2,(int)position.size.x / 10,TextAnchor.MiddleCenter); } } } private void Update () { //再描画 Repaint(); } //======================================================================== /// <summary> /// プレイヤー処理 /// </summary> private void LogicPlayer () { player.Move(_event); player.CheckEdge(new Vector2(position.width,position.height)); } //======================================================================== /// <summary> /// 敵処理 /// </summary> private void LogicEnemy () { Enemy tmpEnemy = enemyGenerator.GenerateEnemy(image1,new Vector2(position.width / 2 + Random.Range(-position.width / 2,position.width),0),Score); if(!(tmpEnemy == null)) { enemies.Add(tmpEnemy); } for(int i = enemies.Count - 1;i >= 0;i--) { enemies[i].Move(); } for(int i = enemies.Count - 1;i >= 0;i--) { if(enemies[i].CheckUnderEdge(new Vector2(position.width,position.height))) { enemies.RemoveAt(i); } } } //======================================================================== /// <summary> /// 弾処理 /// </summary> private void LogicBullet () { Bullet tmpBullet = player.GenerateBullet(image1); if(!(tmpBullet == null)) { bullets.Add(tmpBullet); } for(int i = bullets.Count - 1;i >= 0;i--) { bullets[i].Move(); if(bullets[i].CheckEdge(new Vector2(position.width,position.height))) { bullets.RemoveAt(i); } } } //======================================================================== /// <summary> /// プレイヤー描画 /// </summary> private void ShowPlayer () { EditorGUI.DrawPreviewTexture(new Rect(player.Pos,player.Size),player.Image); } //======================================================================== /// <summary> /// 敵描画 /// </summary> private void ShowEnemy () { foreach(Enemy e in enemies) { EditorGUI.DrawPreviewTexture(new Rect(e.Pos,e.Size),e.Image); } } //======================================================================== /// <summary> /// 弾描画 /// </summary> private void ShowBullet () { foreach(Bullet b in bullets) { EditorGUI.DrawPreviewTexture(new Rect(b.Pos,b.Size),b.Image); } } //======================================================================== /// <summary> /// 背景描画 /// </summary> private void ShowBackground () { EditorGUI.DrawPreviewTexture(new Rect(0,0,position.width,position.height),image2); } //======================================================================== /// <summary> /// スコア描画 /// </summary> private void ShowScore (float yPos,int size,TextAnchor ta) { GUILayout.Space(yPos); GUIStyle myStyle = new GUIStyle(); myStyle.normal.textColor = Color.white; myStyle.fontSize = size; myStyle.alignment = ta; EditorGUILayout.LabelField("スコア:" + Score,myStyle); } //======================================================================== /// <summary> /// 敵と弾の衝突判定 /// </summary> private void CheckCollideEnemyToBullet () { for(int i = enemies.Count - 1;i >= 0;i--) { for(int j = bullets.Count - 1;j >= 0;j--) { if(enemies[i].IsCollide(bullets[j])) { enemies.RemoveAt(i); bullets.RemoveAt(j); Score++; break; } } } } //======================================================================== /// <summary> /// プレイヤーと敵の衝突判定 /// </summary> private void CheckCollidePlayerToEnemy () { for(int i = enemies.Count - 1;i >= 0;i--) { if(player.IsCollide(enemies[i])) { player = null; gameEnded = true; changeRoutineFlag = true; break; } } } //======================================================================== /// <summary> /// 特定のイベントが動いているかどうか /// </summary> private bool IsRunEventType (EventType e) { if(changeRoutineFlag) { if(!(_event.type == EventType.Layout)) { return false; } changeRoutineFlag = false; } return true; } }
BaseRect.cs
using UnityEngine; namespace EditorShootingGame { public class BaseRect { public Texture2D Image; public Vector2 Pos; public Vector2 Size; public BaseRect (Texture2D image,Vector2 size) { Image = image; Pos = Vector2.zero; Size = size; } public BaseRect (Texture2D image,Vector2 pos,Vector2 size) { Image = image; Pos = pos; Size = size; } //================================================================================== /// <summary> /// 端チェック /// </summary> public bool CheckEdge (Vector2 basePos) { bool isEdge = false; if(Pos.x >= (basePos.x - Size.x)) { Pos.x = basePos.x - Size.x; isEdge = true; } if(Pos.x <= 0) { Pos.x = 0; isEdge = true; } if(Pos.y >= (basePos.y - Size.y)) { Pos.y = basePos.y - Size.y; isEdge = true; } if(Pos.y <= 0) { Pos.y = 0; isEdge = true; } return isEdge; } //================================================================================== /// <summary> /// 下端のチェック /// </summary> public bool CheckUnderEdge (Vector2 basePos) { bool isEdge = false; if(Pos.y >= (basePos.y - Size.y)) { Pos.y = basePos.y - Size.y; isEdge = true; } return isEdge; } //================================================================================== /// <summary> /// 他BaseRectとの衝突判定 /// </summary> /// <param name="enemy"></param> public bool IsCollide (BaseRect baseRect) { if(Vector2.Distance(Pos,baseRect.Pos) < (Size.x + Size.y + baseRect.Size.x + baseRect.Size.y) / 4) { return true; } return false; } } }
Player.cs
using UnityEngine; namespace EditorShootingGame { public class Player : BaseRect { public float Speed; private float firstPosY = 0.9f; private int generateBulletTime; private const int GENERATE_BULLET_TIME_LENGTH = 100; public Player (Texture2D image,Vector2 midPos) : base(image,new Vector2(20,20)) { Pos = new Vector2(midPos.x / 2 - Size.x / 2,midPos.y * firstPosY - Size.y); Speed = 6; } //================================================================================== /// <summary> /// 移動 /// </summary> public void Move (Event e) { //右 if(e.keyCode == KeyCode.RightArrow) { Pos += Vector2.right * Speed; } //左 if(e.keyCode == KeyCode.LeftArrow) { Pos += Vector2.left * Speed; } //上(上下逆) if(e.keyCode == KeyCode.UpArrow) { Pos += Vector2.up * Speed * (-1); } //下(上下逆) if(e.keyCode == KeyCode.DownArrow) { Pos += Vector2.down * Speed * (-1); } } //================================================================================== /// <summary> /// 弾の生成 /// </summary> /// <param name="image"></param> public Bullet GenerateBullet (Texture2D image) { generateBulletTime++; if(generateBulletTime >= GENERATE_BULLET_TIME_LENGTH) { generateBulletTime = 0; } if(generateBulletTime > 0) return null; return new Bullet(image,Pos + Size / 2); } } }
Bullet.cs
using UnityEngine; namespace EditorShootingGame { public class Bullet : BaseRect { public float Speed; public Bullet (Texture2D image,Vector2 pos) : base(image,pos,new Vector2(10,10)) { Pos -= Size / 2; Speed = 4; } public void Move () { //上移動(逆) Pos += Vector2.up * Speed * (-1); } } }
EnemyGenerator.cs
using UnityEngine; namespace EditorShootingGame { public class EnemyGenerator { private int generateBulletTime; private int generateBulletTimeLength = 120; /// <summary> /// 敵の生成 /// </summary> public Enemy GenerateEnemy (Texture2D image,Vector2 pos,float speed) { generateBulletTime++; if(generateBulletTime >= generateBulletTimeLength - speed) { generateBulletTime = 0; } if(generateBulletTime > 0) return null; return new Enemy(image,pos); } } }
Enemy.cs
using UnityEngine; namespace EditorShootingGame { public class Enemy : BaseRect { public float Speed; public Enemy (Texture2D image,Vector2 pos):base(image,pos,new Vector2(20,20)) { Pos -= Size / 2; Speed = 0.3f; } public void Move () { //上移動(逆) Pos += Vector2.down * Speed * (-1); } } }