Skip to content

Instantly share code, notes, and snippets.

@unitycoder
Last active January 29, 2024 06:14
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save unitycoder/a10c215ec9c477ff0e04c964dff3208f to your computer and use it in GitHub Desktop.
Save unitycoder/a10c215ec9c477ff0e04c964dff3208f to your computer and use it in GitHub Desktop.
Pong-Wars in Unity c#
// original JS source https://github.com/vnglst/pong-wars/blob/main/index.html
// https://unitycoder.com/blog/2024/01/29/pong-wars-in-unity/
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PongWars : MonoBehaviour
{
Color DAY_COLOR = Color.white;
Color DAY_BALL_COLOR = Color.black;
Color NIGHT_COLOR = Color.black;
Color NIGHT_BALL_COLOR = Color.white;
const int SQUARE_SIZE = 8 + 8;
const int canvasWidth = 512;
const int canvasHeight = 512;
const int numSquaresX = canvasWidth / SQUARE_SIZE;
const int numSquaresY = canvasHeight / SQUARE_SIZE;
Color[,] squares = new Color[numSquaresX, numSquaresY];
Texture2D tex;
float x1 = 0, y1 = 0;
float x2 = 0, y2 = 0;
float dx1 = 0, dy1 = 0;
float dx2 = 0, dy2 = 0;
public AudioClip hitSound;
private void Start()
{
tex = new Texture2D(canvasWidth, canvasHeight, TextureFormat.RGB24, false, false);
GetComponent<Renderer>().material.mainTexture = tex;
tex.filterMode = FilterMode.Point;
tex.wrapMode = TextureWrapMode.Clamp;
for (var i = 0; i < numSquaresX; i++)
{
//squares[i] = new Color[numSquaresY];
for (var j = 0; j < numSquaresY; j++)
{
squares[i, j] = i < numSquaresX / 2 ? DAY_COLOR : NIGHT_COLOR;
}
}
x1 = canvasWidth / 4;
y1 = canvasHeight / 2;
dx1 = 12.5f;
dy1 = -12.5f;
x2 = (canvasWidth / 4) * 3;
y2 = canvasHeight / 2;
dx2 = -12.5f;
dy2 = 12.5f;
var iteration = 0;
}
void drawBall(int cx, int cy, Color color)
{
//ctx.beginPath();
//ctx.arc(x, y, SQUARE_SIZE / 2, 0, Math.PI * 2, false);
//ctx.fillStyle = color;
//ctx.fill();
//ctx.closePath();
// TODO draw circle
for (var x = cx - SQUARE_SIZE / 2; x < cx + SQUARE_SIZE / 2; x++)
{
for (var y = cy - SQUARE_SIZE / 2; y < cy + SQUARE_SIZE / 2; y++)
{
tex.SetPixel(x, y, color);
}
}
tex.Apply(false);
}
void drawSquares()
{
for (var i = 0; i < numSquaresX; i++)
{
for (var j = 0; j < numSquaresY; j++)
{
//ctx.fillStyle = squares[i][j];
//ctx.fillRect(i * SQUARE_SIZE, j * SQUARE_SIZE, SQUARE_SIZE, SQUARE_SIZE);
for (var x = i * SQUARE_SIZE; x < i * SQUARE_SIZE + SQUARE_SIZE; x++)
{
for (var y = j * SQUARE_SIZE; y < j * SQUARE_SIZE + SQUARE_SIZE; y++)
{
tex.SetPixel(x, y, squares[i, j]);
}
}
}
}
tex.Apply(false);
}
float randomNum(float min, float max)
{
return Random.Range(min, max);
}
(float, float) updateSquareAndBounce(float x, float y, float dx, float dy, Color color)
{
float updatedDx = dx;
float updatedDy = dy;
// Check multiple points around the ball's circumference
for (float angle = 0; angle < Mathf.PI * 2; angle += Mathf.PI / 4)
{
var checkX = x + Mathf.Cos(angle) * (SQUARE_SIZE / 2);
var checkY = y + Mathf.Sin(angle) * (SQUARE_SIZE / 2);
int i = Mathf.FloorToInt(checkX / SQUARE_SIZE);
int j = Mathf.FloorToInt(checkY / SQUARE_SIZE);
if (i >= 0 && i < numSquaresX && j >= 0 && j < numSquaresY)
{
if (squares[i, j] != color)
{
squares[i, j] = color;
// Determine bounce direction based on the angle
if (Mathf.Abs(Mathf.Cos(angle)) > Mathf.Abs(Mathf.Sin(angle)))
{
updatedDx = -updatedDx;
AudioSource.PlayClipAtPoint(hitSound, new Vector3(0, 0, 0));
}
else
{
updatedDy = -updatedDy;
AudioSource.PlayClipAtPoint(hitSound, new Vector3(0, 0, 0));
}
// Add some randomness to the bounce to prevent the balls from getting stuck in a loop
updatedDx += randomNum(-0.01f, 0.01f);
updatedDy += randomNum(-0.01f, 0.01f);
}
}
}
return (updatedDx, updatedDy);
//return { dx: updatedDx, dy: updatedDy };
} // updateSquareAndBounce
//void updateScoreElement()
//{
// var dayScore = 0;
// var nightScore = 0;
// for (var i = 0; i < numSquaresX; i++)
// {
// for (var j = 0; j < numSquaresY; j++)
// {
// if (squares[i][j] === DAY_COLOR)
// {
// dayScore++;
// }
// else if (squares[i][j] === NIGHT_COLOR)
// {
// nightScore++;
// }
// }
// }
// scoreElement.textContent = `day ${ dayScore} | night ${ nightScore}`;
//}
(float, float) checkBoundaryCollision(float x, float y, float dx, float dy)
{
if (x + dx > canvasWidth - SQUARE_SIZE / 2 || x + dx < SQUARE_SIZE / 2)
{
dx = -dx;
// TODO different sound for 1/2
AudioSource.PlayClipAtPoint(hitSound, new Vector3(0, 0, 0));
}
if (
y + dy > canvasHeight - SQUARE_SIZE / 2 ||
y + dy < SQUARE_SIZE / 2
)
{
dy = -dy;
AudioSource.PlayClipAtPoint(hitSound, new Vector3(0, 0, 0));
}
return (dx, dy);
//return { dx: dx, dy: dy };
}
int iteration = 0;
private void Update()
{
draw();
}
void draw()
{
//ctx.clearRect(0, 0, canvasWidth, canvasHeight);
drawSquares();
drawBall((int)x2, (int)y2, NIGHT_BALL_COLOR);
var bounce2 = updateSquareAndBounce(x2, y2, dx2, dy2, NIGHT_COLOR);
dx2 = bounce2.Item1;
dy2 = bounce2.Item2;
drawBall((int)x1, (int)y1, DAY_BALL_COLOR);
var bounce1 = updateSquareAndBounce(x1, y1, dx1, dy1, DAY_COLOR);
dx1 = bounce1.Item1;
dy1 = bounce1.Item2;
var boundary1 = checkBoundaryCollision(x1, y1, dx1, dy1);
dx1 = boundary1.Item1;
dy1 = boundary1.Item2;
var boundary2 = checkBoundaryCollision(x2, y2, dx2, dy2);
dx2 = boundary2.Item1;
dy2 = boundary2.Item2;
x1 += dx1;
y1 += dy1;
x2 += dx2;
y2 += dy2;
//iteration++;
//if (iteration % 1_000 === 0) console.log("interation", iteration);
//updateScoreElement();
//requestAnimationFrame(draw);
}
void clearRect(int x, int y, int width, int height)
{
for (var i = x; i < x + width; i++)
{
for (var j = y; j < y + height; j++)
{
tex.SetPixel(i, j, Color.clear);
}
}
tex.Apply(false);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment