Im trying to write an Software Renderer using this tutorial series: https://www.youtube.com/watch?v=2U-4_vpw1lQ&list=PLEETnX-uPtBUbVOok816vTl1K9vV1GgH5&index=13
But the problem is I try to render a Ico Sphere but it doesn't look right. See image: Rendered Sphere
The code for the rasterizer is:
void GRE_Edge(GTE_Vec4* MinVertY, GTE_Vec4* MaxVertY, GRE_EdgeData* Data)
{
Data->EdgeStartY = (uint32_t)ceilf(MinVertY->y);
Data->EdgeEndY = (uint32_t)ceilf(MaxVertY->y);
Data->EdgeStepX = (MaxVertY->x - MinVertY->x) / (MaxVertY->y - MinVertY->y);
Data->EdgeCurX = MinVertY->x + (Data->EdgeStartY - MinVertY->y) * Data->EdgeStepX;
}
void GRE_ScanEdge(GRE_EdgeData* a, GRE_EdgeData* b, bool Handedness, GRE_Framebuffer* Framebuffer)
{
GRE_EdgeData Left = *a;
GRE_EdgeData Right = *b;
if (Handedness)
{
GRE_EdgeData Temp = Left;
Left = Right;
Right = Temp;
}
for (uint32_t y = b->EdgeStartY; y < b->EdgeEndY; y++)
{
for (uint32_t x = (uint32_t)ceilf(Left.EdgeCurX); x < (uint32_t)ceilf(Right.EdgeCurX); x++)
GRE_DrawPixel(x, y, 255, 0, 255, Framebuffer);
Left.EdgeCurX += Left.EdgeStepX;
Right.EdgeCurX += Right.EdgeStepX;
}
}
void GRE_ScanTriangle(GTE_Vec4* MinVertY, GTE_Vec4* MidVertY, GTE_Vec4* MaxVertY, bool Handedness, GRE_Framebuffer* Framebuffer)
{
GRE_EdgeData TopToBottom;
GRE_Edge(MinVertY, MaxVertY, &TopToBottom);
GRE_EdgeData TopToMiddle;
GRE_Edge(MinVertY, MidVertY, &TopToMiddle);
GRE_EdgeData MiddleToBottom;
GRE_Edge(MidVertY, MaxVertY, &MiddleToBottom);
GRE_ScanEdge(&TopToBottom, &TopToMiddle, Handedness, Framebuffer);
GRE_ScanEdge(&TopToBottom, &MiddleToBottom, Handedness, Framebuffer);
}
float GRE_TriangleAreaTimesTwo(GTE_Vec4* a, GTE_Vec4* b, GTE_Vec4* c)
{
return ((b->x - a->x) * (c->y - a->y) - (c->x - a->x) * (b->y - a->y));
}
void GRE_FillTriangle(GTE_Vec4* v1, GTE_Vec4* v2, GTE_Vec4* v3, GRE_Framebuffer* Framebuffer)
{
GTE_Mat4 ScreenSpaceMatrix;
GTE_Mat4LoadScreenSpaceTransform(&ScreenSpaceMatrix, Framebuffer->Width * 0.5, Framebuffer->Height * 0.5);
GTE_Vec4 MinVertY;
GTE_Vec4MultiplyMat4(v1, &ScreenSpaceMatrix, &MinVertY);
GTE_Vec4PerspectiveDivide(&MinVertY);
GTE_Vec4 MidVertY;
GTE_Vec4MultiplyMat4(v2, &ScreenSpaceMatrix, &MidVertY);
GTE_Vec4PerspectiveDivide(&MidVertY);
GTE_Vec4 MaxVertY;
GTE_Vec4MultiplyMat4(v3, &ScreenSpaceMatrix, &MaxVertY);
GTE_Vec4PerspectiveDivide(&MaxVertY);
//Backface Culling
if (GRE_TriangleAreaTimesTwo(&MinVertY, &MaxVertY, &MidVertY) >= 0)
return;
GTE_Vec4 TmpVec;
if (MaxVertY.y < MidVertY.y)
{
TmpVec = MaxVertY;
MaxVertY = MidVertY;
MidVertY = TmpVec;
}
if (MidVertY.y < MinVertY.y)
{
TmpVec = MidVertY;
MidVertY = MinVertY;
MinVertY = TmpVec;
}
if (MaxVertY.y < MidVertY.y)
{
TmpVec = MaxVertY;
MaxVertY = MidVertY;
MidVertY = TmpVec;
}
GRE_ScanTriangle(&MinVertY, &MidVertY, &MaxVertY, GRE_TriangleAreaTimesTwo(&MinVertY, &MaxVertY, &MidVertY) >= 0, Framebuffer);
}
I can't find any problems with this code, so I hope someone can help me.
Related
I am trying to de-pixellate an image over time, which is working. However when this has finished, I want the mouse to go back to its original point and start again, forever. I have tried loop commands with no luck.
I can only get this code to work in version 2.2.1
import java.awt.Robot;
PImage img;
int pixls = 0;
int x, y, yinc;
int XOffset = 0;
int YOffset = 30;
int counter = YOffset;
Robot robot;
void setup() {
size(900, 900);
//noCursor();
noStroke();
img = loadImage("p.jpg");
img.resize(900, 900);
//surface.setLocation(XOffset, YOffset);
}
void draw() {
loadPixels();
frameRate(14);
pixls = (int)map(mouseY, height, 20, 250, 20); //pixellation
for (int i = 0; i < pixls; i++) {
for (int j = 0; j < pixls; j++) {
float r = red(img.pixels[(height/pixls)*j*width+(width/pixls)*i]);
float g = green(img.pixels[(height/pixls)*j*width+(width/pixls)*i]);
float b = blue(img.pixels[(height/pixls)*j*width+(width/pixls)*i]);
fill(r, g, b);
rect((width/pixls)*i, (height/pixls)*j, width/pixls, height/pixls);
yinc = (height/pixls)*j;
}
}
try {
robot = new Robot();
robot.mouseMove(XOffset*2, counter); //counter is start of mouse
if (counter > height + YOffset)
{
counter = YOffset + 30; // +30 for menubar
}
}
catch (Exception e) {
//println("error = ", e);
}
counter++;
}
The following should work in Processing 2.2.1. It uses an old method for finding the XOffset and YOffset of the app's window.
/*
Will work in Processing 2.2.1
*/
import java.awt.Robot;
Robot robot;
PImage img;
int pixls = 0;
int x, y, yinc;
int XOffset = 0;
int YOffset = 0;
int counter = 0;
void setup() {
size(710, 710);
// noCursor();
noStroke();
img = loadImage("myImage.jpg");
img.resize(710, 710);
}
void draw() {
int XOffset = frame.getLocationOnScreen().x;
int YOffset = frame.getLocationOnScreen().y;
pixls = (int)map(mouseY, 0, height, 5, 350);
for (int i = 0; i < pixls; i++) {
for (int j = 0; j < pixls; j++) {
float r = red(img.pixels[(height/pixls)*j*width+(width/pixls)*i]);
float g = green(img.pixels[(height/pixls)*j*width+(width/pixls)*i]);
float b = blue(img.pixels[(height/pixls)*j*width+(width/pixls)*i]);
fill(r, g, b);
rect((width/pixls)*i, (height/pixls)*j, width/pixls, height/pixls);
yinc = (height/pixls)*j;
}
}
try {
robot = new Robot();
robot.mouseMove(XOffset + 10, counter);
if (counter > height + YOffset + 30) {
counter = YOffset + 30; // + 30 for menubar
}
} catch (Exception e) {
println("error = ", e);
}
counter++;
}
I was working in a University C project (first sem), in which our group wanted to make a simple pong game, we decided to use raylib, as it seemed easy. But here is the problem, in the following code:
void UpdatePad(Pad* pad)
{
int height = GetScreenHeight();
if (IsKeyDown(pad->Scheme.DownButton)) {
printf("Down = %d\n", pad->Scheme.DownButton);
pad->Position.y += GetFrameTime() * pad->Speed;
if ( pad->Position.y + pad->Size.y/2 > height ) {
pad->Position.y = height - pad->Size.y /2;
}
}
if (IsKeyDown(pad->Scheme.UpButton)) {
printf("Up = %d\n", pad->Scheme.UpButton);
pad->Position.y -= GetFrameTime() * pad -> Speed;
if (pad->Position.y - pad->Size.y/2 < 0 ) {
pad->Position.y = pad->Size.y /2;
}
}
}
The function IsKeyDown of raylib always returns true, whatever I do. Even if I replace pad->Scheme.DownButton to KEY_UP or something, it always returns true and executes the code block, Is there any solution for this?
Full script is:
#include <raylib.h>
#include <stdio.h>
#include "pad.h"
#include "main.h"
void DrawPad(Pad* pad);
void UpdatePad(Pad* pad);
void Update();
void DrawUpdate();
void Loop();
int main()
{
int screenWidth = 800;
int screenHeight = 450;
InitWindow(screenWidth, screenHeight, "Table Tennis");
SetTargetFPS(12);
Loop();
return 0;
}
void Loop()
{
while (!WindowShouldClose()) {
DrawUpdate();
}
}
void UpdatePad(Pad* pad)
{
int height = GetScreenHeight();
if (IsKeyDown(pad->Scheme.DownButton)) {
printf("Down = %d\n", pad->Scheme.DownButton);
pad->Position.y += GetFrameTime() * pad->Speed;
if ( pad->Position.y + pad->Size.y/2 > height ) {
pad->Position.y = height - pad->Size.y /2;
}
}
if (IsKeyDown(pad->Scheme.UpButton)) {
printf("Up = %d\n", pad->Scheme.UpButton);
pad->Position.y -= GetFrameTime() * pad -> Speed;
if (pad->Position.y - pad->Size.y/2 < 0 ) {
pad->Position.y = pad->Size.y /2;
}
}
}
void DrawPad(Pad* pad)
{
DrawRectangle(pad->Position.x, pad->Position.y - (pad->Size.y /2), pad->Size.x, pad->Size.y, WHITE);
}
void DrawUpdate()
{
const char* scoreLeft = TextFormat("%d", 10);
int scoreSizeLeft = MeasureText(scoreLeft, 20);
InputScheme Input = { .DownButton = KEY_S, .UpButton = KEY_W };
Vector2 paddySize = { .x = 5, .y = 50 };
Vector2 paddyPos = { .x = GetScreenWidth() - paddySize.x , .y = GetScreenHeight() - paddySize.y };
Pad pad = { .Size = paddySize, .Speed = 50, .Scheme = Input , .Position = paddyPos };
Vector2 from = {.x = (GetScreenWidth() / (float) 2), .y = 5};
Vector2 to = { .x = (GetScreenWidth() / (float) 2), .y = ( GetScreenHeight() - (float) 5 ) };
UpdatePad(&pad);
BeginDrawing();
ClearBackground(BLACK);
DrawLineEx(from, to, 2, LIGHTGRAY);
DrawText(scoreLeft, (GetScreenWidth()/2) - 10 -scoreSizeLeft, 10, 20, LIGHTGRAY);
DrawPad(&pad);
EndDrawing();
}
The pad is:-
#include <raylib.h>
typedef struct {
int UpButton;
int DownButton;
} InputScheme;
typedef struct {
InputScheme Scheme;
int Score;
float Speed;
Vector2 Position;
Vector2 Size;
} Pad;
I'm writing a raytracer in C and I'm having trouble perfecting the shadows on my cone. I think the problem I have is in the calculation of the normal of the cone at the intersection point. Here is a rendering of what I currently have.
The scene described as follows:
resolution: 500, 500
scene:
{
light:
{
position: 0, -10, -40
intensity: 20000
color: white
}
camera:
{
position: -5, -7, -40
direction: 0, 0, 1
fov: 50
}
plane:
{
position: 0, 0, 0
direction: 0, 0, 1
color: white
}
cone:
{
position: 0, 0, -2.5
direction: -5, -8, 0
color: white
radius: 5
height: 20
}
cylinder:
{
position: 10, 0, 0
direction: -5, -8, 0
color: white
radius: 5
height: 20
}
}
Note that the light is between the objects and the camera.
The issue there is that I think the cone should be more illuminated, at least, in some areas, as illuminated as the cylinder to the right.
I calculated the normal based on this post's answer as follows:
static void get_cone_normal(t_raytracing_tools *r, t_ray *ray, t_object *obj)
{
//nhit is the normal at hit point.
ray->nhit.x = (ray->hit.x - obj->pos.x) * (obj->height / obj->rad);
ray->nhit.y = obj->rad / obj->height;
ray->nhit.z = (ray->hit.z - obj->pos.z) * (obj->height / obj->rad);
ray->nhit = v_norm(ray->nhit);
}
I also thought of the direction of the normal depending on what side of the cone is hit by the ray. After I solve the quadratic equation and get two potential answers, I test each one to figure out if it is within my finite cone (parametric equation is for infinite cone) and according to how the ray hits the cone, I have an int variable n_dir which is either 1 or -1 which I use to invert the normal if the ray hits the inside of the cone. Here is the code for that part:
bool get_finite_cone_intersection(t_raytracing_tools *r, t_ray *ray, t_object *obj, t_intersection_tools *i)
{
bool r1_too_low;
bool r1_too_high;
bool r2_too_low;
bool r2_too_high;
//i->r1 and i->r2 are the two roots (solutions of quadratic eq.)
r1_too_low = lower_than_min(i->r1, i, obj, ray);
r1_too_high = higher_than_max(i->r1, i, obj, ray);
r2_too_low = lower_than_min(i->r2, i, obj, ray);
r2_too_high = higher_than_max(i->r2, i, obj, ray);
if (r1_too_low)
{
i->r1 = NAN; //I set roots to NAN if they are not valid solutions
if (r2_too_low || r2_too_high)
i->r2 = NAN;
else
i->n_dir = 1;
}
else if (r1_too_high)
{
i->r1 = NAN;
if (r2_too_low || r2_too_high)
i->r2 = NAN;
else
i->n_dir = -1;
}
else if (!r1_too_low && !r1_too_high)
{
i->r2 = NAN;
if (r2_too_low)
i->n_dir = -1;
else
i->n_dir = 1;
}
return (true);
}
bool lower_than_min(double r, t_intersection_tools *i, t_object *obj, t_ray *ray)
{
if (r > 0)
{
if (v_dot(obj->dir, v_sub(v_add(ray->origin, v_scale(ray->dir, r)), obj->pos)) < 0.0)
return (true);
}
return (false);
}
bool higher_than_max(double r, t_intersection_tools *i, t_object *obj, t_ray *ray)
{
if (r > 0)
{
if (v_dot(obj->dir, v_sub(v_add(ray->origin, v_scale(ray->dir, r)),
v_add(obj->pos, v_scale(obj->dir, obj->height)))) > 0.0)
return (true);
}
return (false);
}
Also, what the heck, here's the code for my cone intersection:
bool get_cone_intersection(t_raytracing_tools *r, t_ray *ray, t_object *cone)
{
t_intersection_tools i;
t_vec3 ori_cen;
double k;
int n_dir;
i.n_dir = 1;
k = tan(cone->angle);
ori_cen = v_sub(ray->origin, cone->pos);
i.q.x = v_dot(ray->dir, ray->dir) - (1.0 + k * k) * powf(v_dot(ray->dir, cone->dir), 2.0);
i.q.y = 2 * (v_dot(ray->dir, ori_cen) - (1.0 + k * k) * v_dot(ray->dir, cone->dir)
* v_dot(ori_cen, cone->dir));
i.q.z = v_dot(ori_cen, ori_cen) - (1.0 + k * k) * powf(v_dot(ori_cen,
cone->dir), 2.0);
if (!solve_quadratic(i.q, &i.r1, &i.r2))
return (0);
(i.r2 < i.r1) ? ft_swapd(&i.r1, &i.r2) : 0;
get_finite_cone_intersection(r, ray, cone, &i);
if (i.r1 < 0 || isnan(i.r1)) //the smallest one is negative, thus take the other one
{
i.r1 = i.r2;
}
if (i.r1 < 0 || isnan(i.r1))
return (false);
if (r->t > i.r1)
{
ray->t = i.r1;
if (ray->type == R_PRIMARY)
{
ray->hit_obj = cone;
ray->hit_type = T_CONE;
ray->n_dir = i.n_dir;
}
}
return (true);
}
Hope that's not too much info at once! Again, would love it if someone could shed some light (haha) on the situation.
I'm working on a boids flocking project.
My goal is to have several draggable objects which have to be avoided by the boids.
There are several different flocks with a different starting position.
I managed to get the boids to avoid one draggable object. But I can't seem to make them avoid all. (using a for loop)
I really can't figure out why this won't do the trick..
I hope you could give me some suggestions.
the code:
int initBoidNum = 100; //amount of boids to start the program with
BoidList flock1, flock2, flock3;
Draggable draggable;
NullDraggableObject nullDraggableObject;
ArrayList draggables;
int id;
float[] xposs= new float[10];
float[] yposs= new float[10];
String turn;
void setup() {
size(1000, 700);
//create and fill the list of boids
flock1 = new BoidList(150, 0, 10, 100);
flock2 = new BoidList(150, 255, 10, 200);
flock3 = new BoidList(150, 150, 10, 300);
turn = "turn";
nullDraggableObject = new NullDraggableObject();
draggables = new ArrayList();
for (int i = 0; i < 10; i++) {
draggables.add(new DraggableObject(random(width), random(height/2)));
}
}
void draw() {
background(100, 60);
flock1.run();
flock2.run();
flock3.run();
stroke(255);
noFill();
draggable = nullDraggableObject;
for (id = 0; id < draggables.size (); id++) {
Draggable d = (Draggable)draggables.get(id);
d.draw();
if (d.isBeingMouseHovered()) {
draggable = d;
}
}
}
void mousePressed() {
draggable.mousePressed();
}
void mouseDragged() {
draggable.mouseDragged();
}
void mouseReleased() {
draggable.mouseReleased();
}
interface Draggable {
boolean isBeingMouseHovered();
boolean inside(float ix, float iy);
void draw();
void mousePressed();
void mouseDragged();
void mouseReleased();
}
class NullDraggableObject implements Draggable {
boolean isBeingMouseHovered() {
return false;
}
boolean inside(float ix, float iy) {
return false;
}
void draw() {
}
void mousePressed() {
}
void mouseDragged() {
}
void mouseReleased() {
}
}
public class DraggableObject implements Draggable {
float XX, YY;
float radius;
boolean drag;
float dragX, dragY;
DraggableObject(float _x, float _y) {
XX = _x;
YY = _y;
radius = 50;
drag = false;
dragX = 0;
dragY = 0;
}
boolean isBeingMouseHovered() {
return inside(mouseX, mouseY);
}
boolean inside(float ix, float iy) {
return (dist(XX, YY, ix, iy) < radius);
}
void draw() {
ellipseMode(CENTER);
ellipse(XX, YY, 2*radius, 2*radius);
String space = "__";
println(id);
println(XX);
println(YY);
xposs[id] = XX;
yposs[id] = YY;
}
void mousePressed() {
drag = inside(mouseX, mouseY);
if (drag) {
dragX = mouseX - XX;
dragY = mouseY - YY;
}
}
void mouseDragged() {
if (drag) {
XX = mouseX - dragX;
YY = mouseY - dragY;
}
}
void mouseReleased() {
drag = false;
}
}
class Boid {
//fields
PVector pos, vel, acc, ali, coh, sep; //pos, velocity, and acceleration in a vector datatype
float neighborhoodRadius; //radius in which it looks for fellow boids
float maxSpeed = 1; //maximum magnitude for the velocity vector
float maxSteerForce = .05; //maximum magnitude of the steering vector
float sMod, aMod, cMod; //modifiers for the three forces on the boid
float h; //hue
Boid(PVector inPos) {
pos = new PVector();
pos.set(inPos);
vel = new PVector(random(-1, 1), random(-1, 1));
acc = new PVector(0, 0);
neighborhoodRadius = 20;
sMod = 1;
aMod = 1;
cMod = 4;
}
Boid(PVector inPos, PVector inVel, float r) {
pos = new PVector();
pos.set(inPos);
vel = new PVector();
vel.set(inVel);
acc = new PVector(0, 0);
neighborhoodRadius = r;
}
void run(ArrayList bl) {
for (int i =0; i < 10; i++) {
acc.add(attract(new PVector(width/2, height/2), true));
acc.add(avoid(new PVector(xposs[i], yposs[i]), true));
if (i == 10) i = 0;
}
if (pos.x>width-10)acc.add(bounce(new PVector(width, pos.y), true));
if (pos.x<10) acc.add(bounce(new PVector(0, pos.y), true));
if (pos.y>height-10) acc.add(bounce(new PVector(pos.x, height), true));
if (pos.y<10) acc.add(bounce(new PVector(pos.x, 0), true));
ali = alignment(bl);
coh = cohesion(bl);
sep = seperation(bl);
for (int i =0; i < 10; i++) {
if (PVector.dist(new PVector(xposs[i], yposs[i]), pos)>180) {
acc.add(PVector.mult(ali, aMod));
acc.add(PVector.mult(coh, cMod));
acc.add(PVector.mult(sep, sMod));
}
if (PVector.dist(new PVector(xposs[i], yposs[i]), pos)<80) maxSpeed = 1000;
if (i == 10) i = 0;
}
if (PVector.dist(new PVector(width, height), pos)<60) maxSpeed = 1000;
if (PVector.dist(new PVector(0, 0), pos)<50) {
maxSpeed = 1000;
} else {
maxSpeed = 1;
}
move();
checkBounds();
render();
}
void move() {
vel.add(acc); //add acceleration to velocity
vel.limit(maxSpeed); //make sure the velocity vector magnitude does not exceed maxSpeed
pos.add(vel); //add velocity to position
acc.mult(0); //reset acceleration
}
void checkBounds() {
}
void render() {
pushMatrix();
translate(pos.x, pos.y);
rotate(atan2(vel.y, vel.x)); //rotate drawing matrix to direction of velocity
stroke(0);
noFill();
ellipse(0, 0, neighborhoodRadius/2, neighborhoodRadius/2);
noStroke();
fill(h);
//draw triangle
beginShape(TRIANGLES);
rect(0, 0, 6, 2);
endShape();
popMatrix();
}
//steering. If arrival==true, the boid slows to meet the target. Credit to Craig Reynolds
PVector steer(PVector target, boolean arrival) {
PVector steer = new PVector(); //creates vector for steering
if (!arrival) {
steer.set(PVector.sub(target, pos)); //steering vector points towards target (switch target and pos for avoiding)
steer.limit(maxSteerForce); //limits the steering force to maxSteerForce
} else {
PVector targetOffset = PVector.sub(target, pos);
float distance=targetOffset.mag();
float rampedSpeed = maxSpeed*(distance/100);
float clippedSpeed = min(rampedSpeed, maxSpeed);
PVector desiredVelocity = PVector.mult(targetOffset, (clippedSpeed/distance));
steer.set(PVector.sub(desiredVelocity, vel));
}
return steer;
}
//avoid. If weight == true avoidance vector is larger the closer the boid is to the target
PVector avoid(PVector target, boolean weight) {
PVector steer = new PVector(); //creates vector for steering
steer.set(PVector.sub(pos, target)); //steering vector points away from target
if (weight) steer.mult(1/sq(PVector.dist(pos, target)));
//steer.limit(maxSteerForce); //limits the steering force to maxSteerForce
return steer;
}
PVector attract(PVector target, boolean weight) {
PVector steer = new PVector(); //creates vector for steering
steer.set(PVector.sub(target, pos)); //steering vector points away from target
if (weight) steer.mult(1/sq(PVector.dist(target, pos)));
//steer.limit(maxSteerForce); //limits the steering force to maxSteerForce
return steer;
}
PVector bounce(PVector target, boolean weight) {
PVector steer = new PVector(); //creates vector for steering
steer.set(PVector.sub(pos, target)); //steering vector points away from target
if (weight) steer.mult(1/sq(PVector.dist(pos, target)));
//steer.limit(maxSteerForce); //limits the steering force to maxSteerForce
return steer;
}
PVector seperation(ArrayList boids) {
PVector posSum = new PVector(0, 0);
PVector repulse;
for (int i=0; i<boids.size (); i++) {
Boid b = (Boid)boids.get(i);
float d = PVector.dist(pos, b.pos);
if (d>0&&d<=neighborhoodRadius) {
repulse = PVector.sub(pos, b.pos);
repulse.normalize();
repulse.div(d);
posSum.add(repulse);
}
}
return posSum;
}
PVector alignment(ArrayList boids) {
PVector velSum = new PVector(0, 0);
int count = 0;
for (int i=0; i<boids.size (); i++) {
Boid b = (Boid)boids.get(i);
float d = PVector.dist(pos, b.pos);
if (d>0&&d<=neighborhoodRadius) {
velSum.add(b.vel);
count++;
}
}
if (count>0) {
velSum.div((float)count);
velSum.limit(maxSteerForce);
}
return velSum;
}
PVector cohesion(ArrayList boids) {
PVector posSum = new PVector(0, 0);
PVector steer = new PVector(0, 0);
int count = 0;
for (int i=0; i<boids.size (); i++) {
Boid b = (Boid)boids.get(i);
float d = dist(pos.x, pos.y, b.pos.x, b.pos.y);
if (d>0&&d<=neighborhoodRadius) {
posSum.add(b.pos);
count++;
}
}
if (count>0) posSum.div((float)count);
steer = PVector.sub(posSum, pos);
steer.limit(maxSteerForce);
return steer;
}
}
class BoidList {
ArrayList boids; //will hold the boids in this BoidList
float h; //for color
BoidList(int n, float ih, int xstart, int ystart) {
boids = new ArrayList();
h = ih;
for (int i=0; i<n; i++) {
boids.add(new Boid(new PVector(xstart, ystart)));
}
}
void run() {
for (int i=0; i<boids.size (); i++) {
Boid tempBoid = (Boid)boids.get(i); //create a temporary boid to process and make it the current boid in the list
tempBoid.h = h;
tempBoid.run(boids); //tell the temporary boid to execute its run method
}
}
}
My program that I built using Unity3D sporadically freezes, and this action freezes my computer. I'm unable to pinpoint the root cause. I had placed logs all over my project, but the game failed to freeze.
Has any Unity3D developer experience their apps sporadically freeze in the manner in which I am describing? Does anyone have any ideas or suggestions?
Due to a 30K character limit, the below object has been modified slightly. This is the object I believe contains a flaw, but I am unable to identify this flaw.
public class gamePlayController : MonoBehaviour {
void Start () {
int i = 0;
int selectedPlayers = PlayerPrefs.GetInt("TotalPlayers");
foreach( GameObject touchable in GameObject.FindGameObjectsWithTag("Touchable") )
{
touchable.SetActive(false);
touchable.AddComponent(typeof(PlayerCollisionDispatcher));
PlayerCollisionDispatcher nextDispatcher = touchable.GetComponent<PlayerCollisionDispatcher>();
nextDispatcher.currentGameObject = touchable;
nextDispatcher.gameObject.AddComponent("AudioSource");
for(i = 0; i < this.m_Players.Count; i++)
{
if(string.Compare(touchable.name, this.m_Players[i].name) < 0)
{
break;
}
}
if(i < this.m_Players.Count)
{
this.m_Players.Insert(i, touchable);
}
else
{
this.m_Players.Add(touchable);
}
}
while(this.m_Players.Count > selectedPlayers)
{
this.m_Players.RemoveRange(selectedPlayers, this.m_Players.Count - selectedPlayers);
}
this.restartGame();
}
void OnGameTimer(object sender, ElapsedEventArgs e)
{
}
void Update() {
Vector3 vector = m_ArialCamera.camera.transform.position;
vector.x = Mathf.Abs((1500 * this.m_ArialView.x) - 1500) + 250;
vector.y = (600 * this.m_ArialView.y) + 100;
vector.z = (1500 * this.m_ArialView.z) + 250;
m_ArialCamera.camera.transform.position = vector;
if(this.m_IsGameOver)
{
Application.LoadLevel("Replay Screen");
}
else if(this.m_SimulateCamera)
{
this.SimulateCamera();
}
else if(m_AutoPluck)
{
this.AutoPluck();
}
else if(Time.timeScale != 0.0f && this.m_Dispatcher && this.m_Dispatcher.didObjectStop)
{
this.determineTurnOutcome();
}
else if(Time.timeScale != 0.0f && this.m_Dispatcher && this.m_Dispatcher.didObjectMove)
{
this.m_Dispatcher.trackMovementProgress();
}
else if(Time.timeScale != 0.0f && this.m_Dispatcher
&& this.m_Players[this.m_PlayerIndex].rigidbody.velocity.magnitude > 15.0f
&& this.m_Dispatcher.didPluck)
{
this.m_Dispatcher.didObjectMove = true;
}
}
void restartGame()
{
this.m_PlayerIndex = -1;
foreach( GameObject touchable in this.m_Players)
{
GameObject startField = GameObject.FindWithTag ("StartField");
touchable.SetActive(false);
touchable.rigidbody.useGravity = false;
touchable.rigidbody.velocity = Vector3.zero;
touchable.rigidbody.AddForce(Vector3.zero);
touchable.rigidbody.AddTorque(Vector3.zero);
if(startField)
{
Vector3 nextPoint = startField.renderer.bounds.center;
nextPoint.y = 11.0f;
touchable.transform.position = nextPoint;
}
touchable.rigidbody.useGravity = true;
}
this.startNextPlayer();
}
void startNextPlayer()
{
bool isActivePlayerReady = true;
do{
if(this.m_PlayerIndex != -1)
{
audioPlayer.PlayAudio("Audio/Next Player");
}
this.m_PlayerIndex = (this.m_PlayerIndex + 1)%this.m_Players.Count;
this.m_Dispatcher = this.m_Players[this.m_PlayerIndex].GetComponent<PlayerCollisionDispatcher>();
if(this.m_Dispatcher && !this.m_Dispatcher.isGameOver && !this.m_Dispatcher.didEnterMud)
{
if(!this.m_Players[this.m_PlayerIndex].activeSelf)
{
this.m_Dispatcher.startGame();
this.m_Players[this.m_PlayerIndex].SetActive(true);
}
this.m_Dispatcher.startTurn();
}
}
while(!isActivePlayerReady);
Vector3 vector = this.m_Players[this.m_PlayerIndex].transform.position;
vector.x = (1500 * this.m_ArialView.x) + 250;
vector.y = 300;
vector.z = (1500 * this.m_ArialView.z) + 250;
m_ArialCamera.camera.transform.position = vector;
this.setAnnouncement("Player " + this.m_Players[this.m_PlayerIndex].name + "'s Turn");
if(this.m_PlayerIndex != 0)
{
this.m_IsSimulating = PlayerPrefs.GetInt("SimulatePlayer" + this.m_Players[this.m_PlayerIndex].name);
this.m_IsSimulating = 1;
}
else
{
this.m_IsSimulating = 0;
}
GameObject mainCamera = GameObject.FindWithTag ("MainCamera");
MouseOrbit mo = null;
if(mainCamera)
{
mo = mainCamera.GetComponent<MouseOrbit>();
}
if(this.m_IsSimulating >= 1)
{
this.StartSimulation();
if(mo)
{
mo.DoFreeze = true;
}
}
else
{
if(mo)
{
mo.DoFreeze = false;
}
}
}
void StartSimulation()
{
System.Random random = new System.Random();
StringBuilder sb = new StringBuilder();
int randomNumber = 0;
//determine either the player object or the next block
if(this.m_Dispatcher.isKiller)
{
m_SimulateToObject = this.m_Players[randomNumber%this.m_Players.Count];
randomNumber = random.Next(0, 100);
}
else
{
sb.AppendFormat("{0:D2}", this.m_Dispatcher.targetScore);
Debug.Log("target score=" + sb.ToString());
foreach(GameObject scoreField in GameObject.FindGameObjectsWithTag("ScoreField"))
{
if(scoreField.name == sb.ToString())
{
m_SimulateToObject = scoreField;
break;
}
}
}
this.m_IsTargetInitiallyVisible = false;
this.m_SimulationTimer = new System.Timers.Timer();
this.m_SimulationTimer.Elapsed+=new ElapsedEventHandler(TriggerCameraSimulation);
this.m_SimulationTimer.Interval=2500;
this.m_SimulationTimer.Enabled=true;
}
void TriggerCameraSimulation(object sender, ElapsedEventArgs e)
{
this.m_SimulationTimer.Enabled = false;
this.m_SimulationTimer.Dispose();
this.m_SimulateCamera = true;
}
void SimulateCamera()
{
GameObject mainCamera = GameObject.FindWithTag ("MainCamera");
MouseOrbit mo = null;
this.m_SimulationTimer.Enabled = false;
this.m_SimulationTimer.Dispose();
if(mainCamera)
{
mo = mainCamera.GetComponent<MouseOrbit>();
if(!this.m_IsTargetInitiallyVisible)
{
mo.IsManualMove = true;
mainCamera.transform.position = this.m_Players[this.m_PlayerIndex].transform.position;
mainCamera.transform.LookAt(this.m_SimulateToObject.transform, Vector3.up);
this.m_IsTargetInitiallyVisible = true;
}
else if(this.m_SimulateCamera)
{
if(mo.getDistance() >= 10.0f)
{
this.m_SimulateCamera = false;
}
mo.setDistance(-0.001f);
}
}
if(!this.m_SimulateCamera)
{
this.m_SimulationTimer = new System.Timers.Timer();
this.m_SimulationTimer.Elapsed+=new ElapsedEventHandler(TriggerSimulatedPluck);
this.m_SimulationTimer.Interval=2000;
this.m_SimulationTimer.Enabled=true;
}
}
void TriggerSimulatedPluck(object sender, ElapsedEventArgs e)
{
this.m_SimulationTimer.Enabled = false;
this.m_SimulationTimer.Dispose();
this.m_AutoPluck = true;
}
void AutoPluck()
{
System.Random random = new System.Random();
GameObject mainCamera = GameObject.FindWithTag ("MainCamera");
MouseOrbit mo = null;
float applyForce = 0.0f;
float slope = 0.00028648399272739457f;
float y_int = 0.2908366193449838f;
Vector3 vTorque = Vector3.zero;
int simulateId = PlayerPrefs.GetInt("SimulatePlayer" + this.m_Players[this.m_PlayerIndex].name);
int seed = (5 * ((int)(SimulationOptions.Pro) - simulateId));
int xSeed = 0;
int ySeed = 0;
int zSeed = 0;
int sign = random.Next(1, 1000)%2;
int range = random.Next(1, 1000)%seed;
int myValue = 0;
this.m_SimulationTimer.Enabled = false;
this.m_SimulationTimer.Dispose();
if(mainCamera)
{
mo = mainCamera.GetComponent<MouseOrbit>();
mo.IsManualMove = false;
}
this.m_AutoPluck = false;
if(simulateId >= 1)
{
float distance = Vector3.Distance(this.m_Players[this.m_PlayerIndex].transform.position,
this.m_SimulateToObject.transform.position);
if(simulateId != (int)(SimulationOptions.Pro))
{
myValue = random.Next(1, 6);
seed = (int)(myValue * ((int)(SimulationOptions.Pro) - simulateId));
sign = random.Next(1, 2);
range = random.Next(1, seed);
if(random.Next(1, 1000)%3 == 0)
{
distance += (sign == 1 ? range : -range);
}
}
vTorque.x = (float)(random.Next(1, 90));
vTorque.y = (float)(random.Next(1, 90));
vTorque.z = (float)(random.Next(1, 90));
applyForce = (slope * distance) + y_int;
this.m_Dispatcher.pluckObject(applyForce, vTorque);
}
}
void determineTurnOutcome()
{
int number = -1;
bool canActivePlayerContinue = false;
bool isAutoReward = false;
bool didElinimatePlayer = false;
foreach(GameObject nextObject in this.m_Players)
{
PlayerCollisionDispatcher nextDispatcher = nextObject.GetComponent<PlayerCollisionDispatcher>();
if(nextObject.activeSelf && !nextDispatcher.isGameOver && !nextDispatcher.isActive)
{
if(nextDispatcher.currentScore == nextDispatcher.targetScore)
{
nextDispatcher.totalScore = nextDispatcher.targetScore;
int.TryParse(nextDispatcher.name, out number);
nextDispatcher.targetScore++;
if(nextDispatcher.totalScore >= 13 || nextDispatcher.targetScore > 13)
{
nextDispatcher.totalScore = 13;
nextDispatcher.targetScore = 13;
nextDispatcher.isKiller = true;
this.setMaterial(nextDispatcher.renderer, "killers", nextDispatcher.name);
}
else
{
this.setMaterial(nextDispatcher.renderer, "numbers", nextDispatcher.name);
}
}
else if(nextDispatcher.didKillerCollide && (nextDispatcher.didLeaveBoard || nextDispatcher.didLeaveBounds))
{
this.setMaterial(nextDispatcher.renderer, "eliminated", nextDispatcher.name);
nextDispatcher.isGameOver = true;
didElinimatePlayer = true;
}
else if(nextDispatcher.didPlayerCollide && (nextDispatcher.didLeaveBoard || nextDispatcher.didLeaveBounds))
{
if(int.TryParse(nextDispatcher.name, out number))
{
nextDispatcher.targetScore = 1;
nextDispatcher.totalScore = 0;
}
}
else if(nextDispatcher.didEnterMud)
{
this.setMaterial(nextDispatcher.renderer, "mudd", nextDispatcher.name);
nextDispatcher.isKiller = false;
}
else if(nextDispatcher.isInMud && !nextDispatcher.didEnterMud)
{
isAutoReward = true;
}
else
{
this.setMaterial(nextDispatcher.renderer, "numbers", nextDispatcher.name);
}
}
nextDispatcher.transferStates();
}
if(this.m_Dispatcher.isKiller && !didElinimatePlayer)
{
this.setMaterial(this.m_Dispatcher.renderer, "numbers", this.m_Dispatcher.name);
this.m_Dispatcher.totalScore = 0;
this.m_Dispatcher.targetScore = 1;
this.m_Dispatcher.isKiller = false;
}
else if(this.m_Dispatcher.didEnterMud)
{
this.setMaterial(this.m_Dispatcher.renderer, "mud", this.m_Dispatcher.name);
}
else if(this.m_Dispatcher.currentScore == this.m_Dispatcher.targetScore || isAutoReward)
{
this.m_Dispatcher.totalScore = this.m_Dispatcher.targetScore;
canActivePlayerContinue = true;
this.m_Dispatcher.consecutivePops++;
int.TryParse(this.m_Dispatcher.name, out number);
this.m_Dispatcher.targetScore++;
this.setMaterial(this.m_Dispatcher.renderer, "numbers", this.m_Dispatcher.name);
}
else
{
this.setMaterial(this.m_Dispatcher.renderer, "numbers", this.m_Dispatcher.name);
}
this.isWinnerAnnounced();
if(!this.m_IsGameOver && !canActivePlayerContinue)
{
this.m_Dispatcher.endTurn();
this.startNextPlayer();
}
else if(canActivePlayerContinue)
{
this.m_Dispatcher.transferStates();
this.m_Dispatcher.isActive = true;
this.m_Dispatcher.didObjectMove = false;
this.m_Dispatcher.didObjectStop = false;
if(this.m_IsSimulating >= 1)
{
this.StartSimulation();
}
}
this.m_ForceValue = 0.0f;
}
void isWinnerAnnounced()
{
StringBuilder sb = new StringBuilder();
int totalPlayers = 0;
string winner = string.Empty;
int number = -1;
int totalPlayersInMud = 0;
foreach(GameObject nextObject in this.m_Players)
{
PlayerCollisionDispatcher nextDispatcher = nextObject.GetComponent<PlayerCollisionDispatcher>();
if(!nextDispatcher.isGameOver)
{
totalPlayers++;
winner = nextObject.name;
}
if(nextDispatcher.isInMud)
{
totalPlayersInMud++;
}
}
if(totalPlayers == 1)
{
if(winner != string.Empty && int.TryParse(winner, out number))
{
sb.AppendFormat("Congratulations Player {0}", number);
PlayerPrefs.SetString("WinningPlayer", sb.ToString());
}
else
{
PlayerPrefs.SetString("WinningPlayer", "Congratulations");
}
this.m_IsGameOver = true;
}
else if(totalPlayersInMud == this.m_Players.Count)
{
PlayerPrefs.SetString("WinningPlayer", "All players are stuck in the mud!");
this.m_IsGameOver = true;
}
}
void setMaterial(Renderer renderer, string state, string playerId)
{
StringBuilder sbNextImage = new StringBuilder();
sbNextImage.AppendFormat("Materials/playerObjects/{0}/{1}", state, playerId);
Material newMat = Resources.Load(sbNextImage.ToString(), typeof(Material)) as Material;
if(newMat)
{
renderer.material = newMat;
}
else
{
Debug.Log("FAILED to set material: " + sbNextImage.ToString());
}
}
void setAnnouncement(string text)
{
this.m_IsAnnouncement = true;
this.m_AnnouncementHeight = (int)(Screen.height * 0.5);
this.m_AnnouncementText = text;
}
void OnGUI() {
GUIStyle labelStyle = GUI.skin.label;
int number = -1;
StringBuilder scoreDetails = new StringBuilder();
StringBuilder turnDetails = new StringBuilder();
float x = 0;
float y = 0;
float w = 64.0f;
float h = 32.0f;
float alpha = 1.0f;
if(this.m_IsAnnouncement)
{
this.displayAnnouncement();
}
labelStyle.normal.textColor = new Color(1.0f, 1.0f, 1.0f, alpha);
Texture2D texture = new Texture2D(32, 32, TextureFormat.ARGB32, false);
for(int i = 0; i < 32; i++)
{
for(int j = 0; j < 32; j++)
{
texture.SetPixel(i, j, new Color(0.0f, 0.0f, 0.0f, 0.25f));
}
}
texture.Apply();
labelStyle.normal.background = texture;
if(this.m_DoShowScore)
{
foreach(GameObject nextObject in this.m_Players)
{
PlayerCollisionDispatcher nextDispatcher = nextObject.GetComponent<PlayerCollisionDispatcher>();
int.TryParse(nextDispatcher.name, out number);
if(nextDispatcher.isGameOver)
{
scoreDetails.AppendFormat("\tPlayer {0}: Game Over\n", number);
}
else if(nextDispatcher.didEnterMud)
{
scoreDetails.AppendFormat("\tPlayer {0}: In The Mudd\n", number);
}
else if(nextDispatcher.isKiller)
{
scoreDetails.AppendFormat("\tPlayer {0}: Killer\n", number);
}
else
{
scoreDetails.AppendFormat("\tPlayer {0}: {1}\n", number, nextDispatcher.totalScore);
}
}
GUI.Label (new Rect (0, 0, 225, 100), scoreDetails.ToString());
}
w = 64.0f;
h = 32.0f;
x = Screen.width - w;
y = Screen.height - h;
if(GUI.Button (new Rect (x, y, w, h), "Menu"))
{
audioPlayer.PlayAudio("Audio/Click");
this.m_IsMenuShowing = !this.m_IsMenuShowing;
}
if(this.m_IsMenuShowing)
{
w = (64.0f * this.m_MenuText.Length);
h = 32.0f;
x = Screen.width - w - 64.0f;
y = Screen.height - h;
int selOption = GUI.Toolbar(new Rect(x, y, w, h), this.m_MenuOption, this.m_MenuText);
if(selOption != this.m_MenuOption)
{
audioPlayer.PlayAudio("Audio/Click");
this.m_MenuOption = -1;
this.m_IsMenuShowing = !this.m_IsMenuShowing;
switch(selOption)
{
case (int)(MenuOptions.ArialViewOption): //arial
this.m_ArialCamera.SetActive(!this.m_ArialCamera.activeSelf);
break;
case (int)(MenuOptions.VolumeOption): //mute
int muteVolume = PlayerPrefs.GetInt("MuteVolume");
muteVolume = (muteVolume + 1)%2;
PlayerPrefs.SetInt("MuteVolume", muteVolume);
if(muteVolume == 0)
{
this.m_MenuText[(int)(MenuOptions.VolumeOption)] = "Mute";
}
else
{
this.m_MenuText[(int)(MenuOptions.VolumeOption)] = "Volume";
}
break;
case (int)(MenuOptions.PauseOption): //pause
if(Time.timeScale == 0.0f)
{
this.setAnnouncement("Continuing Game Play");
Time.timeScale = this.m_Speed;
this.m_MenuText[(int)(MenuOptions.PauseOption)] = "Pause";
}
else
{
this.setAnnouncement("Game Is Paused");
Time.timeScale = 0.0f;
this.m_MenuText[(int)(MenuOptions.PauseOption)] = "Play";
}
break;
case (int)(MenuOptions.ScoresOption): //scores
this.m_DoShowScore = !this.m_DoShowScore;
break;
case (int)(MenuOptions.RestartOption): //restart
Time.timeScale = this.m_Speed;
this.restartGame();
break;
case (int)(MenuOptions.QuitOption): //quit
Application.LoadLevel("Opening Screen");
break;
default:
break;
}
}
}
if(this.m_ArialCamera.activeSelf)
{
x = Screen.width * 0.7f - 10.0f;
y = 0;
w = 10.0f;
h = Screen.height * 0.3f;
this.m_ArialView.z = GUI.VerticalSlider (new Rect(x, y, w, h), this.m_ArialView.z, 1.0f, 0.0f);
x = Screen.width * 0.7f;
y = Screen.height * 0.3f;
w = Screen.width * 0.3f;
h = 10.0f;
this.m_ArialView.x = GUI.HorizontalSlider (new Rect(x, y, w, h), this.m_ArialView.x, 1.0f, 0.0f);
x = Screen.width * 0.7f;
y = Screen.height * 0.3f + 12.0f;
w = Screen.width * 0.3f;
h = 10.0f;
this.m_ArialView.y = GUI.HorizontalSlider (new Rect(x, y, w, h), this.m_ArialView.y, 1.0f, 0.0f);
}
int.TryParse(this.m_Players[this.m_PlayerIndex].name, out number);
turnDetails.AppendFormat("\tPlayer {0}'s Turn\n", number);
turnDetails.AppendFormat("\tNext Goal: {0}\n", this.m_Dispatcher.targetScore);
GUI.Label (new Rect (0, Screen.height - 100, 225, 100), turnDetails.ToString());
if(!this.m_Dispatcher.didObjectMove && m_IsSimulating == 0)
{
x = 250.0f;
y = Screen.height - 190.0f;
w = 30.0f;
h = 150.0f;
this.m_ForceValue = GUI.VerticalSlider (new Rect(x, y, w, h), m_ForceValue, 1.0f, 0.0f);
x = 250.0f;
y = Screen.height - 30.0f;
w = 100.0f;
h = 30.0f;
if(GUI.Button (new Rect(x, y, w, h), "Pluck!"))
{
System.Random random = new System.Random();
Vector3 vTorque = Vector3.zero;
int xSeed = 0;
int ySeed = 0;
int zSeed = 0;
xSeed = (random.Next(1, 45));
ySeed = (random.Next(1, 45));
zSeed = (random.Next(1, 45));
vTorque = new Vector3(xSeed, ySeed, zSeed);
this.m_Dispatcher.pluckObject(this.m_ForceValue, vTorque);
}
}
}
void displayAnnouncement()
{
float x = 0;
float y = 0;
float w = 0;
float h = 0;
float alpha = 1.0f;
GUIStyle announcementStyle = null;
GUIStyle labelStyle = null;
announcementStyle = new GUIStyle();
labelStyle = GUI.skin.label;
labelStyle.normal.textColor = new Color(1.0f, 1.0f, 1.0f, alpha);
x = (int)(Screen.width * 0.25);
y = (int)m_AnnouncementHeight;
w = (int)(Screen.width * 0.5);
h = 100;
alpha = (float)m_AnnouncementHeight/(float)(Screen.height * 0.5);
announcementStyle.fontSize = 32;
announcementStyle.alignment = TextAnchor.MiddleCenter;
announcementStyle.fontStyle = FontStyle.BoldAndItalic;
announcementStyle.normal.textColor = new Color(1.0f, 1.0f, 1.0f, alpha);
GUI.Label (new Rect (x, y, w, h), this.m_AnnouncementText, announcementStyle);
if(Time.timeScale != 0.0f)
{
if((this.m_AnnouncementHeight + h) <= 0)
{
this.m_IsAnnouncement = false;
this.m_AnnouncementHeight = (int)(Screen.height * 0.5);
}
else
{
this.m_AnnouncementHeight -= 1;
}
}
}
}
-----------
I believe I have narrowed the freezing down. Simulated testing results is leading me to believe that my problem is inside the OnGUI() method. I have commented that method out all together, and my app is operating smoothly. I'll figure this out, unless someone beats me to the root cause and solution.
I solved it...
My initial suspicions were correct: the problem did lie within the OnGUI() method. I moved the following source code to the Start() method. It made sense, since I'm only building a transparent background texture once.:
Texture2D texture = new Texture2D(32, 32, TextureFormat.ARGB32, false);
for(int i = 0; i < 32; i++)
{
for(int j = 0; j < 32; j++)
{
texture.SetPixel(i, j, new Color(0.0f, 0.0f, 0.0f, 0.25f));
}
}
texture.Apply();