Unity 3d and OpenAI Codex
This was by asking Codex to make Ideas for Unity, and remembered Conway’s “Game of Life”… Here is the tell…
What I Learned
- Codex works well for functions and short and specific task.
- Seems to work just as good for Unity and C# as anything else.
Setup to run OpenAI Codex and Unity3D
(I am sure there is a better way.)
- Create a Python Script …
import openai
openai.api_key = "YOUR_OPEN_AI_CODEX_KEY"
with open(args.file, "r") as text_file:
inputCode = text_file.read()
response = openai.Completion.create(
engine="davinci-codex",
prompt=inputCode,
temperature=0,
max_tokens=3090,
top_p=0.2,
frequency_penalty=0.0,
presence_penalty=0.0,
)
append_file(args.file, response["choices"][0]["text"])
I am using arguments to pass in the file path to read and save to so it will append the returned choice.
Note 1: I asked the Codex to create the append_file function (it also created overwrite_file and read_file on it’s own.
Note 2: “top_p=0.2” is changed from “top_p=1.0” to create more randomness (but it seems not to be that effective.)
- Unity Setup
a. Start a New Scene add a blank Game Object
b. Add “GameOfLifeObj.cs” to a new “Empty Object”
c. Add a saved prefab (I just used a cube with a new Material to set Transparent On
Unity 3D Script
- Asking Codex to create “Game of Life” (You should change the class name to “GameOfLifeObj” or rename the “.cs” file to the returned class name.)
a) Open the .cs file…
b) I entered in and saved …
/*
C Sharp Language
- Unity 3D Scene
1. create game of Life
2. use green plane as the grid
3. GameObject for the cell
*/
c) run it threw the python file (file with the choice added...)
public class GameOfLife : MonoBehaviour {
public int gridSizeX = 10;
public int gridSizeY = 10;
public float cellSize = 1.0f;
public GameObject cellPrefab;
private GameObject[,] grid;
// Use this for initialization
void Start () {
grid = new GameObject[gridSizeX, gridSizeY];
for (int x = 0; x < gridSizeX; x++) {
for (int y = 0; y < gridSizeY; y++) {
GameObject cell = (GameObject)Instantiate(cellPrefab);
cell.transform.parent = transform;
cell.transform.localPosition = new Vector3(x, y, 0);
cell.name = "Cell " + x + "," + y;
grid[x, y] = cell;
}
}
}
void Update() {
}
}
Well it looks like it has the base but no updating…
d) So I deleted everything below “void update() {” line and added …
Here i where I learned that to update existing code, it is best to take the function you want made and add it to the end, then delete everything else, so that Codex has to finish the code completely. (If not then it might ignore it.)
/*
Add the math needed to update the Game OF Life check of the grid cells
*/
Aligned with the void Update so it was a comment of the function.
And ran the it threw Python again and got this good append to the file…
for (int x = 0; x < gridSizeX; x++) {
for (int y = 0; y < gridSizeY; y++) {
GameObject cell = grid[x, y];
int aliveNeighbors = GetAliveNeighbors(x, y);
if (aliveNeighbors < 2 || aliveNeighbors > 3) {
cell.GetComponent<Renderer>().material.color = Color.black;
} else if (aliveNeighbors == 3) {
cell.GetComponent<Renderer>().material.color = Color.white;
}
}
}
}
private int GetAliveNeighbors(int x, int y) {
int aliveNeighbors = 0;
for (int neighborX = x - 1; neighborX <= x + 1; neighborX++) {
for (int neighborY = y - 1; neighborY <= y + 1; neighborY++) {
if (neighborX >= 0 && neighborX < gridSizeX && neighborY >= 0 && neighborY < gridSizeY) {
if (neighborX != x || neighborY != y) {
if (grid[neighborX, neighborY].GetComponent<Renderer>().material.color == Color.white) {
aliveNeighbors++;
}
}
}
}
}
return aliveNeighbors;
}
}
Well that looks the code I need right there!
I will end it there, but before I over complicated the project to the point of broken, I also added a 3rd loop to make a Z direction to make “3D Game of Life”, and asked Codex to make UI components, here is a rough process I used for that…
// ======================================================================================================================
// Part 1
// ======================================================================================================================
/*
C Sharp Language
- Unity 3D
Add on screen buttons to rotate this GameObject
*/
using UnityEngine;
using System.Collections;
public class Rotate : MonoBehaviour {
// Use this for initialization
void Start () {
}
// Update is called once per frame
void Update () {
}
void OnGUI()
{
if(GUI.Button(new Rect(10,10,100,100),"Rotate Left"))
{
transform.Rotate(0,0,90);
}
if(GUI.Button(new Rect(110,10,100,100),"Rotate Right"))
{
transform.Rotate(0,0,-90);
}
}
}
// ======================================================================================================================
// Part 2
// ======================================================================================================================
/*
C Sharp Language
- Unity 3D
Add GUI buttons to rotate this GameObject by X Y and Z axis, also add a keyboard shourtcut to hide the GUI all items.
*/
using UnityEngine;
using System.Collections;
public class Rotate : MonoBehaviour {
// Use this for initialization
void Start () {
}
void OnGUI()
{
if(GUI.Button(new Rect(10,10,100,50),"Rotate X"))
{
transform.Rotate(Vector3.right * 90);
}
if(GUI.Button(new Rect(10,70,100,50),"Rotate Y"))
{
transform.Rotate(Vector3.up * 90);
}
if(GUI.Button(new Rect(10,130,100,50),"Rotate Z"))
{
transform.Rotate(Vector3.forward * 90);
}
if(GUI.Button(new Rect(10,190,100,50),"Hide GUI"))
{
GUI.enabled = false;
}
}
// Update is called once per frame
void Update () {
/*
Add Key input to show GUI if Hidden or Hide it.
*/
if(Input.GetKeyDown(KeyCode.Escape))
{
GUI.enabled = true;
}
}
}
// ======================================================================================================================
// Part 3
// ======================================================================================================================
/*
C Sharp Language
- Unity 3D
Add GUI Text for the variables "WorldGenerations" and "currentWorldPopulation".
*/
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class WorldGeneration : MonoBehaviour {
public int WorldGenerations = 0;
public int currentWorldPopulation = 0;
// Use this for initialization
void Start () {
}
// Update is called once per frame
void Update () {
}
void OnGUI() {
GUI.Label(new Rect(10, 10, 100, 20), "World Generations: " + WorldGenerations);
GUI.Label(new Rect(10, 30, 100, 20), "Current World Population: " + currentWorldPopulation);
}
}
// ======================================================================================================================
// Part 4
// ======================================================================================================================
/*
C Sharp Language
- Unity 3D
*/
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class ToggleScript : MonoBehaviour {
void OnGUI() {
/*
Add add Text saying "Auto :", then Toggle, Text saying "Amount :", a TextField for Amount, Text saying "Speed :", and a TextField for Speed.
*/
// Auto
GUI.Label(new Rect(10, 10, 100, 20), "Auto :");
// Auto Toggle
if (GUI.Toggle(new Rect(100, 10, 100, 20), GUI.tooltip, "Auto", "Button")) {
// Amount
GUI.Label(new Rect(10, 40, 100, 20), "Amount :");
// Amount TextField
GUI.TextField(new Rect(100, 40, 100, 20), GUI.tooltip, "Amount");
// Speed
GUI.Label(new Rect(10, 70, 100, 20), "Speed :");
// Speed TextField
GUI.TextField(new Rect(100, 70, 100, 20), GUI.tooltip, "Speed");
}
}
void Update() {
/*
Save the GUI.Toggle, and the GUI.TextFields to variables.
*/
// Auto
bool auto = GUI.Toggle(new Rect(100, 10, 100, 20), GUI.tooltip, "Auto", "Button");
// Amount
string amount = GUI.TextField(new Rect(100, 40, 100, 20), GUI.tooltip, "Amount");
// Speed
string speed = GUI.TextField(new Rect(100, 70, 100, 20), GUI.tooltip, "Speed");
/*
If Auto is true, then set the amount to the amount TextField, and the speed to the speed TextField.
*/
if (auto) {
// Amount
amount = GUI.TextField(new Rect(100, 40, 100, 20), GUI.tooltip, "Amount");
// Speed
speed = GUI.TextField(new Rect(100, 70, 100, 20), GUI.tooltip, "Speed");
}
}
}
Also I had to add a function to add points to the world, so I started with random points, but then tried Perlin Noise (Here are those attempts…)
// ======================================================================================================================
// Part 1 (Looks pretty, but Mathf.PerlinNoise only accpets Vector2 (x, y)
// ======================================================================================================================
/*
C Sharp Language
- Unity 3D
- Add functions for Diffrent Noises i.e. Perlin?
*/
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Noise : MonoBehaviour {
public float scale = 1;
public int octaves = 1;
public float persistance = 0.5f;
public float lacunarity = 2;
public int seed;
public Vector2 offset;
public float GetNoise(float x, float y)
{
float total = 0;
float frequency = 1;
float amplitude = 1;
float maxValue = 0;
for (int i = 0; i < octaves; i++)
{
total += Mathf.PerlinNoise(x * frequency + offset.x, y * frequency + offset.y) * amplitude;
maxValue += amplitude;
amplitude *= persistance;
frequency *= lacunarity;
}
return total / maxValue;
}
public float GetNoise(float x, float y, float z)
{
float total = 0;
float frequency = 1;
float amplitude = 1;
float maxValue = 0;
for (int i = 0; i < octaves; i++)
{
total += Mathf.PerlinNoise(x * frequency + offset.x, y * frequency + offset.y, z * frequency + offset.z) * amplitude;
maxValue += amplitude;
amplitude *= persistance;
frequency *= lacunarity;
}
return total / maxValue;
}
public float GetNoise(float x, float y, float z, float w)
{
float total = 0;
float frequency = 1;
float amplitude = 1;
float maxValue = 0;
for (int i = 0; i < octaves; i++)
{
total += Mathf.PerlinNoise(x * frequency + offset.x, y * frequency + offset.y, z * frequency + offset.z, w * frequency + offset.w) * amplitude;
maxValue += amplitude;
amplitude *= persistance;
frequency *= lacunarity;
}
return total / maxValue;
}
}
// ======================================================================================================================
// Part 2 (Codex just couldn't handle it, so I got "Procedural Toolkit" by Syomus on the Asset Store)
// ======================================================================================================================
As noted, I just couldn’t get 3D Perlin working but “Procedural Toolkit” by Syomus is great for this and other task like it.
From there, I wanted to try and speed it up so I ask Codex for some co-routine examples (top comments are what I sent to Codex)…
/*
C Sharp Language
- Unity 3D
1. Create a coroutine to say hello. and Repeat.
*/
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class HelloWorld : MonoBehaviour
{
// Start is called before the first frame update
void Start()
{
StartCoroutine(SayHello());
}
IEnumerator SayHello()
{
while (true)
{
Debug.Log("Hello World");
yield return new WaitForSeconds(1);
}
}
}
All was well (although good speed was only at 10x10x10 grid due to slow PC, but looked good at 40x40x40) Then I had an Idea can I get the cubes to only exist if it is inside another object. So I asked for Object Collision… (So I added Objects and added Colliders and Rigid Bodies, as for my original “prefab cube” I just added a box collider, no rigid body (speed))
/*
C Sharp Language
Unity 3D
1. Check if a child GameObject intersets another GameObject
*/
using UnityEngine;
using System.Collections;
public class CheckIntersection : MonoBehaviour {
// Use this for initialization
void Start () {
}
// Update is called once per frame
void Update () {
}
void OnTriggerEnter(Collider other) {
Debug.Log("Intersected with " + other.gameObject.name);
}
}
// ======================================================================================================================
// Step 2 (Added Update Tigger event to get the Stay and Exit functions made
// ======================================================================================================================
/*
C Sharp Language
Unity 3D
*/
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class CellObj : MonoBehaviour
{
public bool useCell = false;
void OnTriggerEnter(Collider other) {
bool otherFound = false;
if (other.gameObject.name != "CellObj(Clone)") {
useCell = true;
otherFound = true;
}
if (!otherFound) {
useCell = false;
}
}
/*
Update trigger event
*/
void OnTriggerStay(Collider other) {
if (other.gameObject.name != "CellObj(Clone)") {
useCell = true;
}
}
/*
Update trigger event
*/
void OnTriggerExit(Collider other) {
if (other.gameObject.name != "CellObj(Clone)") {
useCell = false;
}
}
}
Had to comment out “OnTriggerStay” function due to speed.
So then I added code to enable and disable the cells, then It wasn’t fast enough and went to Threading and shaders, and my PC was couldn’t handle this project any longer
Conclusion?
It seems that Codex did everything I asked after trying many iterations of asking it, but that is also compared to looking it up on google and trying again and again (as long as you can read code, or else Codex might give you something you didn’t want.)So after a week I made about 3 times farther then my other failed test projects, so I will have to add this to my toolbox.