I am trying to create a Processing animation using mass points and springs. I am able to define the mass points, and they work as expected. However when I try to create a spring going between the two mass points the script fails and I am told that "MassPoint is not defined". I am confused because I have defined MassPoint and am using it to create the two points that I already have. Is there a different way that I need to declare it within the Spring class?
MassPoint mp1 = new MassPoint(50, 50, 1.0, PI, 3);
MassPoint mp2 = new MassPoint(60, 60, 0, PI, 3);
Spring s1 = new Spring(mp1,mp2,30,1)
// Setup the Processing Canvas
void setup(){
size(screen.width, screen.height);
strokeWeight(1);
stroke(#000000);
frameRate( 15 );
background(background_color);
fill(#FFFFFF,alpha);
}
// Main draw loop
void draw(){
background(background_color);
mp1.move();
mp2.move();
console.log(mp1.xPos)
}
class MassPoint {
int xPos,yPos,mass;
float speed,angle;
MassPoint (int x, int y, float s, float a, int m) {
xPos = x;
yPos = y;
speed = s;
angle = a;
mass = m;
}
void move(){
xPos += sin(angle) * speed
yPos -= cos(angle) * speed
point(xPos,yPos)
}
}
class Spring {
float length,strength;
MassPoint mp1, mp2;
Spring (MassPoint mp1, MassPoint mp2, float l, float s) {
xPos1 = mp1.xPos;
yPos1 = mp1.yPos;
xPos2 = mp2.xPos;
yPos2 = mp2.yPos;
length = l;
strength = s;
}
}
Are you using an earlier version of Processing before 2.0? Maybe in early versions you were required to declare classes before using them, though it's no longer the case. To verify this, move all class declarations to the top of the file.
Trying the code in both 2.1.1 and 3.3 gives the error "Change screen.width and screen.height to displayWidth and displayHeight", which suggested an older version. See information about these changes here. Also, the call console.log() is not defined, use println() instead.
Below is my version of the code tested in Processing 2.1.1. No gravity or damping, but shows interesting spring behavior.
MassPoint mpS = new MassPoint(100, 100, 0, PI, 20);
MassPoint mp0 = new MassPoint(100, 100, 0, PI, 20);
MassPoint mp1 = new MassPoint(50, 100, 0, PI, 10);
MassPoint mp2 = new MassPoint(50, 150, 1, PI, 5);
Spring s1 = new Spring(mp0,mp1,50,0.0001);
Spring s2 = new Spring(mp1,mp2,50,0.0001);
int background_color = 64;
int alpha = 255;
// Setup the Processing Canvas
void setup(){
size(displayWidth, displayHeight);
strokeWeight(1);
stroke(#000000);
//frameRate( 15 );
background(background_color);
fill(#FFFFFF,alpha);
}
// Main draw loop
void draw(){
background(background_color);
// Spring 0 is static and cannot move
mp0.xPos = mpS.xPos;
mp0.yPos = mpS.yPos;
// Spring 1 and 2 can move
mp1.move();
mp2.move();
s1.move();
s2.move();
// Red when compressed, green when stretched
stroke( constrain(127-4*round(s1.springStretch),0,255), constrain(4*round(s1.springStretch)-127,0,255), 0 );
line(mp0.xPos, mp0.yPos, mp1.xPos, mp1.yPos);
stroke( constrain(127-4*round(s2.springStretch),0,255), constrain(4*round(s2.springStretch)-127,0,255), 0 );
line(mp1.xPos, mp1.yPos, mp2.xPos, mp2.yPos);
stroke(0);
fill(1);
ellipse(mp0.xPos, mp0.yPos, mp0.mass, mp0.mass);
ellipse(mp1.xPos, mp1.yPos, mp1.mass, mp1.mass);
ellipse(mp2.xPos, mp2.yPos, mp2.mass, mp2.mass);
//println(mp1.xPos);
}
class MassPoint {
float xPos,yPos,mass;
float xSpeed,ySpeed;
MassPoint (int x, int y, float s, float a, int m) {
xPos = x;
yPos = y;
xSpeed = (s * sin(a));
ySpeed = -(s * cos(a));
mass = m;
}
void move(){
xPos += xSpeed;
yPos += ySpeed;
point(xPos,yPos);
}
void applyForce( float fx, float fy )
{
float x = fx / mass;
float y = fy / mass;
xSpeed = xSpeed + x;
ySpeed = ySpeed + y;
xPos = xPos + x;
yPos = yPos + y;
}
}
class Spring {
float springLength, springStrength, springStretch;
MassPoint mp1, mp2;
Spring (MassPoint mp1, MassPoint mp2, float l, float s) {
this.mp1 = mp1;
this.mp2 = mp2;
springLength = l;
springStrength = s;
springStretch = 0;
}
void move(){
float xDelta = mp2.xPos - mp1.xPos;
float yDelta = mp2.yPos - mp1.yPos;
float dist = sqrt( (xDelta*xDelta) + (yDelta*yDelta) );
springStretch = (dist-springLength);
float power = springStretch * springStrength;
mp1.applyForce( xDelta*power, yDelta*power );
mp2.applyForce( -xDelta*power, -yDelta*power );
}
}
Are you porting from JavaScript or something? that's a weird hybrid you have there. See if this helps.
MassPoint mp1 = new MassPoint(50, 50, 1.0, PI, 3);
MassPoint mp2 = new MassPoint(60, 60, 0, PI, 3);
Spring s1 = new Spring(mp1,mp2,30,1);
// Setup the Processing Canvas
void setup(){
size(600, 400);
strokeWeight(1);
stroke(#000000);
frameRate( 15 );
background(0);
fill(#FFFFFF);
}
// Main draw loop
void draw(){
background(0);
mp1.move();
mp2.move();
println(mp1.yPos);
}
class MassPoint {
int xPos,yPos,mass;
float speed,angle;
MassPoint (int x, int y, float s, float a, int m) {
xPos = x;
yPos = y;
speed = s;
angle = a;
mass = m;
}
void move(){
xPos += sin(angle) * speed;
yPos -= cos(angle) * speed;
point(xPos,yPos);
}
}
class Spring {
float length,strength;
float xPos1, yPos1, xPos2, yPos2;
MassPoint mp1, mp2;
Spring (MassPoint mp1, MassPoint mp2, float l, float s) {
xPos1 = mp1.xPos;
yPos1 = mp1.yPos;
xPos2 = mp2.xPos;
yPos2 = mp2.yPos;
length = l;
strength = s;
}
}
Related
i wanted to rotate object based on MPU-6050 sensor so i wrote this code for arduino.
#include <Wire.h>
const int MPU_addr = 0x68;
int16_t AcX, AcY, AcZ, Tmp, GyX, GyY, GyZ;
void setup() {
initMPU6050(); //MPU-6050 센서에 대한 초기 설정 함수
Serial.begin(115200); //Serial 통신 시작
calibAccelGyro(); //센서 보정
initDT(); //시간 간격에 대한 초기화 -> 현재 시각 저장
//즉, 드론이 전원이 ON 되면 그떄부터 측정 시작!
}
void loop() {
readAccelGyro(); //가속도, 자이로 센서 값 읽어드림
//SendDataToProcessing(); //프로세싱으로 값 전달
calcDT(); //측정 주기 시간 계산
calcAccelYPR();
static int cnt;
cnt++;
if(cnt%2 == 0)
SendDataToProcessing(); //위에 동일한 함수는 주석처리!
//측정 주기 시간이 짝수(2ms 단위로 하기 위해서)이면 프로세싱으로 보낸다.
}
void initMPU6050(){
Wire.begin(); //I2C 통신 시작 아림
Wire.beginTransmission(MPU_addr); //0x68번지 값을 가지는 MPU-6050과 I2C 통신
Wire.write(0x6B);
Wire.write(0); //잠자는 MPU-6050을 깨우고 있다.
Wire.endTransmission(true); //I2C 버스 제어권에서 손 놓음
}
void readAccelGyro(){
Wire.beginTransmission(MPU_addr); //0x68번지 값을 가지는 MPU-6050과 I2C 통신 시작
Wire.write(0x3B); //0x3B번지에 저장
Wire.endTransmission(false); //데이터 전송 후 재시작 메새지 전송(연결은 계속 지속)
Wire.requestFrom(MPU_addr, 14, true); //0x68 번지에 0x3B 부터 48까지 총 14바이트 저장
AcX = Wire.read() << 8 | Wire.read();
AcY = Wire.read() << 8 | Wire.read();
AcZ = Wire.read() << 8 | Wire.read();
Tmp = Wire.read() << 8 | Wire.read();
GyX = Wire.read() << 8 | Wire.read();
GyY = Wire.read() << 8 | Wire.read();
GyZ = Wire.read() << 8 | Wire.read();
}
float dt;
float accel_angle_x, accel_angle_y, accel_angle_z;
float gyro_angle_x, gyro_angle_y, gyro_angle_z;
float filtered_angle_x, filtered_angle_y, filtered_angle_z;
float baseAcX, baseAcY, baseAcZ; //가속도 평균값 저장 변수
float baseGyX, baseGyY, baseGyZ; //자이로 평균값 저장 변수
void SendDataToProcessing(){
Serial.print(accel_angle_x, 2);
Serial.print(F(","));
Serial.print(accel_angle_y, 2);
Serial.print(F(","));
Serial.print(accel_angle_z, 2);
Serial.println(F(""));
}
void calibAccelGyro(){
float sumAcX = 0, sumAcY = 0, sumAcZ = 0;
float sumGyX = 0, sumGyY = 0, sumGyZ = 0;
readAccelGyro(); //가속도 자이로 센서 읽어들임
//평균값 구하기
for(int i=0; i<10; i++){
readAccelGyro();
sumAcX += AcX; sumAcY += AcY; sumAcZ += AcZ;
sumGyX += GyX; sumGyY += GyY; sumGyZ += GyZ;
delay(100);
}
baseAcX = sumAcX / 10; baseAcY = sumAcY / 10; baseAcZ = sumAcZ / 10;
baseGyX = sumGyX / 10; baseGyY = sumGyY / 10; baseGyZ = sumGyZ / 10;
}
unsigned long t_now; //현재 측정 주기 시간
unsigned long t_prev; //이전 측정 주기 시간
void initDT(){
t_prev = millis();
}
void calcDT(){
t_now = millis();
dt = (t_now - t_prev) / 1000.0; //millis()로 얻은 값은 밀리초 단위이니까!!!!
t_prev = t_now;
}
void calcAccelYPR(){
float accel_x, accel_y, accel_z; //가속도 센서의 최종적인 보정값!!!
float accel_xz, accel_yz;
const float RADIANS_TO_DEGREES = 180/3.14159;
accel_x = AcX - baseAcX; // 가속도(직선) X축에 대한 현재 값 - 가속도 센서의 평균값
accel_y = AcY - baseAcY;
accel_z = AcZ + (16384 - baseAcZ);
//직석 +X축이 기울어진 각도 구함
accel_yz = sqrt(pow(accel_y, 2) + pow(accel_z, 2));
accel_angle_y = atan(-accel_x / accel_yz)*RADIANS_TO_DEGREES;
accel_xz = sqrt(pow(accel_x, 2) + pow(accel_z, 2));
accel_angle_x = atan(accel_y / accel_xz)*RADIANS_TO_DEGREES;
accel_angle_z = 0;
}
and this code for unity.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.IO.Ports;
public class rotate : MonoBehaviour
{
float x;
float y;
float z;
SerialPort ardu = new SerialPort("COM3", 115200);
// Start is called before the first frame update
void Start()
{
ardu.Open();
ardu.ReadTimeout = 10;
}
// Update is called once per frame
void FixedUpdate()
{
if (ardu.IsOpen)
{
string phrase = ardu.re
string[] words = phrase.Split(',');
x = float.Parse(words[0]);
y = float.Parse(words[1]);
z = float.Parse(words[2]);
Debug.Log(y);
transform.eulerAngles = new Vector3(x, z, y * -1);
}
else
{
Debug.Log("ohnonono");
}
}
}
it works just fine. but it has a delay and the gap between them increases over and over.
I think the problem is Arduino's loop and unity's update has a different time scale. but I don't know how to solve this.
there seem to be a bit missing after
string phrase = ardu.re
as there is no semicolon, and SerialPort does not have a .re getter.
I believe you are right in your suspicions, arduino can easily complete the request thousands of times per second, and unless you read all the results, they will just accumulate in SerialPorts input buffer.
Other than delaying the read on the arduino, you should read the serial buffer in full every time you read it, for example using ReadExisting(), or repeating ReadLine within a while loop, for as long as the returned string is not empty.
keep in mind that next thing you'll face is that some frames will not be fully accumulated in the read buffer when you check (there is a possibility that you'll catch a frame in the middle of it transmitting) so do a validity check (a simple length check after .Split) should do it, to handle such case
I need to use Bitmap class from System.Drawing.Bitmap, this is a function that works fine on windows Platform. But after I tried to run on Xamarin Forms, and installed nuget package System.Drawing, the program compiles correctly without errors.
But when running program I receive an error. Somehow seems to point to System.Drawing from windows, not the System.Drawing from the nuget package.
What I need to do is, get Photo from Camera and print it.
Below is the code to print. Problem is with "Bitmap" converter.
Tried several nuget packages, none worked:
System.Drawing.Common
Fast-Bitmap
Bitmap.Net
public byte[] PrintImage(byte[] PHOTO)
{
Bitmap bmp;
using (var ms = new MemoryStream(PHOTO))
{
bmp = new Bitmap(ms);
}
BitmapData data = GetBitmapData(bmp);
BitArray dots = data.Dots;
byte[] width = BitConverter.GetBytes(data.Width);
int offset = 0;
MemoryStream stream = new MemoryStream();
BinaryWriter bw = new BinaryWriter(stream);
// center command
bw.Write(27);
bw.Write('a');
bw.Write(1);
// print image
bw.Write((char)0x1B);
bw.Write('#');
bw.Write((char)0x1B);
bw.Write('3');
bw.Write((byte)24);
while (offset < data.Height)
{
bw.Write((char)0x1B);
bw.Write('*'); // bit-image mode
bw.Write((byte)33); // 24-dot double-density
bw.Write(width[0]); // width low byte
bw.Write(width[1]); // width high byte
for (int x = 0; x < data.Width; ++x)
{
for (int k = 0; k < 3; ++k)
{
byte slice = 0;
for (int b = 0; b < 8; ++b)
{
int y = (((offset / 8) + k) * 8) + b;
// Calculate the location of the pixel.
// It'll be at (y * width) + x.
int i = (y * data.Width) + x;
// If the image is shorter than 24 dots.
bool v = false;
if (i < dots.Length)
{
v = dots[i];
}
slice |= (byte)((v ? 1 : 0) << (7 - b));
}
bw.Write(slice);
}
}
offset += 24;
bw.Write((char)0x0A);
}
// Restore the line spacing to the default of 30 dots.
bw.Write((char)0x1B);
bw.Write('3');
bw.Write((byte)30);
bw.Flush();
byte[] bytes = stream.ToArray();
return bytes; // logo + Encoding.Default.GetString(bytes);
}
public BitmapData GetBitmapData(Bitmap bmp) // (string bmpFileName)
{
//using (var bitmap = (Bitmap)Bitmap.FromFile(bmpFileName))
using (var bitmap = bmp)
{
var threshold = 127;
var index = 0;
double multiplier = 570; // this depends on your printer
double scale = (double)(multiplier / (double)bitmap.Width);
int xheight = (int)(bitmap.Height * scale);
int xwidth = (int)(bitmap.Width * scale);
var dimensions = xwidth * xheight;
var dots = new BitArray(dimensions);
for (var y = 0; y < xheight; y++)
{
for (var x = 0; x < xwidth; x++)
{
var _x = (int)(x / scale);
var _y = (int)(y / scale);
var color = bitmap.GetPixel(_x, _y);
var luminance = (int)(color.R * 0.3 + color.G * 0.59 + color.B * 0.11);
dots[index] = (luminance < threshold);
index++;
}
}
return new BitmapData()
{
Dots = dots,
Height = (int)(bitmap.Height * scale),
Width = (int)(bitmap.Width * scale)
};
}
}
public class BitmapData
{
public BitArray Dots
{
get;
set;
}
public int Height
{
get;
set;
}
public int Width
{
get;
set;
}
}
Error occurs when function is called as:
byte[] _buffer = PrintImage(FOTO);
The error:
"Could not resolve type with token 01000119 from typeref (expected class 'System.Drawing.Bitmap' in assembly 'System.Drawing.Common, Version=4.0.1.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51')"
I'm generating points and mesh on run-time, the problem is, the generated mesh vertices appeared in the wrong position, even if I pass on the point's global position.
the mesh generating part is made in MakeMeshData();
I tired calculating with all my points with position instead of localPosition, as well as commenting out the parenting, still the same result .
https://imgur.com/a/YAlpXfh
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class NPG03_Corridor : MonoBehaviour
{
public Transform centerPoint;
public Transform startPoint;
public Transform endPoint;
public enum CORRIDORTYPE
{
LinearBezierCurves,
QuadraticBezierCurves,
CubicBezierCurve
}
public CORRIDORTYPE corridorType;
public List<Transform> centerLinePoints = new List<Transform>();
public List<Transform> corridorAllPoint = new List<Transform>();
List<Transform> rightPoints = new List<Transform>();
List<Transform> leftPoints = new List<Transform>();
public List<GameObject> listOfCorridorFloor = new List<GameObject>();
public Vector3[] corridorVertices;
public int[] corridorTrangle;
public float StartEndDistanceFromCenter = 15;
public float minStartEndDistanceFromCenter = 10;
public float maxStartEndDistanceFromCenter = 20;
public int controlDirection = 1;
public float minControlDistanceFromCenter = 10;
public float maxControlDistanceFromCenter = 30;
public int numberOfLinePoint = 15;
public int numberOfMesh;
public Vector3[] testVec = new Vector3[3];
int[] textInt = new int[3];
private void Start()
{
BasiceSetup();
PointsSetups();
MakeMeshData();
}
private void BasiceSetup()
{
numberOfMesh = (numberOfLinePoint - 1);
GameObject pointHolderObject = new GameObject();
GameObject centerPointObject = new GameObject();
GameObject startPointObject = new GameObject();
GameObject endPostionObject = new GameObject();
centerPoint = centerPointObject.transform;
startPoint = startPointObject.transform;
endPoint = endPostionObject.transform;
pointHolderObject.name = "Point Holder";
centerPointObject.name = "Center Point";
startPointObject.name = "Start Point";
endPostionObject.name = "End Point";
pointHolderObject.transform.parent = transform;
centerPointObject.transform.parent = pointHolderObject.transform;
startPointObject.transform.parent = pointHolderObject.transform;
endPostionObject.transform.parent = pointHolderObject.transform;
pointHolderObject.transform.localPosition = Vector3.zero;
pointHolderObject.transform.localRotation = Quaternion.Euler(Vector3.zero);
centerPointObject.transform.localPosition = Vector3.zero;
centerPointObject.transform.localRotation = Quaternion.Euler(Vector3.zero);
startPointObject.transform.localPosition = Vector3.zero;
startPointObject.transform.localRotation = Quaternion.Euler(new Vector3(0, 180, 0));
endPostionObject.transform.localPosition = Vector3.zero;
endPostionObject.transform.localRotation = Quaternion.Euler(Vector3.zero);
Vector3 newStartExitPostion = Vector3.forward * (Random.Range(minStartEndDistanceFromCenter, maxStartEndDistanceFromCenter));
startPointObject.transform.localPosition = -1 * newStartExitPostion;
endPostionObject.transform.localPosition = newStartExitPostion;
NPG01_ModulePoint centerPointScript = centerPointObject.AddComponent<NPG01_ModulePoint>();
NPG01_ModulePoint startPointScript = startPointObject.AddComponent<NPG01_ModulePoint>();
NPG01_ModulePoint endPointScript = endPostionObject.AddComponent<NPG01_ModulePoint>();
centerPointScript.updatePoint(NPG01_ModulePoint.POINTSTATE.CENTER);
startPointScript.updatePoint(NPG01_ModulePoint.POINTSTATE.CONNECTION);
endPointScript.updatePoint(NPG01_ModulePoint.POINTSTATE.CONNECTION);
}
private void PointsSetups()
{
GameObject curveHolder = new GameObject();
curveHolder.transform.parent = transform;
curveHolder.name = "Curve Holder";
curveHolder.transform.localPosition = Vector3.zero;
curveHolder.transform.localRotation = Quaternion.Euler(Vector3.zero);
switch (corridorType)
{
case CORRIDORTYPE.LinearBezierCurves:
for (int i = 0; i < numberOfLinePoint; i++)
{
GameObject point = new GameObject();
point.name = "Curve Point " + i.ToString();
point.transform.parent = curveHolder.transform;
point.transform.localPosition = Vector3.zero;
point.transform.localRotation = Quaternion.Euler(Vector3.zero);
NPG01_ModulePoint pointScript = point.AddComponent<NPG01_ModulePoint>();
pointScript.updatePoint(NPG01_ModulePoint.POINTSTATE.BEZIERCURVES);
centerLinePoints.Add(point.transform);
}
for (int i = 0; i < numberOfLinePoint; i++)
{
float t = (float)i / ((float)numberOfLinePoint - 1);
centerLinePoints[i].localPosition = LinearBezierCurves(startPoint.localPosition, endPoint.localPosition, t);
GameObject rightPoint = new GameObject();
GameObject leftPoint = new GameObject();
rightPoint.transform.parent = curveHolder.transform;
rightPoint.name = "Right " + i;
rightPoint.transform.localRotation = Quaternion.Euler(Vector3.zero);
rightPoint.transform.localPosition = centerLinePoints[i].localPosition + (Vector3.right * 3);
NPG01_ModulePoint rightPointScript = rightPoint.AddComponent<NPG01_ModulePoint>();
rightPointScript.updatePoint(NPG01_ModulePoint.POINTSTATE.BEZIERCURVES);
leftPoint.transform.parent = curveHolder.transform;
leftPoint.name = "Left " + i;
leftPoint.transform.localRotation = Quaternion.Euler(Vector3.zero);
leftPoint.transform.localPosition = centerLinePoints[i].localPosition + (-Vector3.right * 3);
NPG01_ModulePoint leftPointScript = leftPoint.AddComponent<NPG01_ModulePoint>();
leftPointScript.updatePoint(NPG01_ModulePoint.POINTSTATE.BEZIERCURVES);
rightPoints.Add(rightPoint.transform);
leftPoints.Add(leftPoint.transform);
}
for (int i = 0; i < numberOfLinePoint; i++)
{
corridorAllPoint.Add(centerLinePoints[i]);
corridorAllPoint.Add(leftPoints[i]);
corridorAllPoint.Add(rightPoints[i]);
}
break;
case CORRIDORTYPE.QuadraticBezierCurves:
int controlPointDirction = Random.Range(0, 9);
if (controlPointDirction % 2 == 0)
{
controlDirection = 1;
}
else
{
controlDirection = -1;
}
GameObject controlPointObject = new GameObject();
controlPointObject.name = "Control Point";
controlPointObject.transform.parent = curveHolder.transform;
controlPointObject.transform.localPosition = Vector3.right * (20 * controlDirection);
controlPointObject.transform.localPosition = new Vector3(controlPointObject.transform.localPosition.x,
controlPointObject.transform.localPosition.y,
0);
NPG01_ModulePoint controlPointScript = controlPointObject.AddComponent<NPG01_ModulePoint>();
controlPointScript.updatePoint(NPG01_ModulePoint.POINTSTATE.BEZIERCONTROLE);
for (int i = 0; i < numberOfLinePoint; i++)
{
GameObject point = new GameObject();
point.name = "Curve Point " + i.ToString();
point.transform.parent = curveHolder.transform;
point.transform.position = Vector3.zero;
point.transform.localPosition = Vector3.zero;
point.transform.localRotation = Quaternion.Euler(Vector3.zero);
centerLinePoints.Add(point.transform);
NPG01_ModulePoint pointScript = point.AddComponent<NPG01_ModulePoint>();
pointScript.updatePoint(NPG01_ModulePoint.POINTSTATE.BEZIERCURVES);
}
for (int i = 0; i < numberOfLinePoint; i++)
{
float t = (float)i / ((float)numberOfLinePoint - 1);
centerLinePoints[i].localPosition = QuadraticBezierCurves(startPoint.localPosition, endPoint.localPosition, controlPointObject.transform.localPosition, t);
GameObject rightPoint = new GameObject();
GameObject leftPoint = new GameObject();
rightPoint.transform.parent = curveHolder.transform;
rightPoint.name = "Right " + i;
rightPoint.transform.localPosition = centerLinePoints[i].localPosition + (Vector3.right * 3);
NPG01_ModulePoint rightPointScript = rightPoint.AddComponent<NPG01_ModulePoint>();
rightPointScript.updatePoint(NPG01_ModulePoint.POINTSTATE.BEZIERCURVES);
leftPoint.transform.parent = curveHolder.transform;
leftPoint.name = "Left " + i;
leftPoint.transform.position = Vector3.zero;
leftPoint.transform.localPosition = Vector3.zero;
leftPoint.transform.localPosition = centerLinePoints[i].localPosition + (-Vector3.right * 3);
NPG01_ModulePoint leftPointScript = leftPoint.AddComponent<NPG01_ModulePoint>();
leftPointScript.updatePoint(NPG01_ModulePoint.POINTSTATE.BEZIERCURVES);
}
for (int i = 0; i < numberOfLinePoint; i++)
{
corridorAllPoint.Add(centerLinePoints[i]);
corridorAllPoint.Add(leftPoints[i]);
corridorAllPoint.Add(rightPoints[i]);
}
break;
case CORRIDORTYPE.CubicBezierCurve:
break;
}
}
private void MakeMeshData()
{
//mr = GetComponent<MeshRenderer>();
//mf = GetComponent<MeshFilter>();
GameObject meshHolder = new GameObject();
meshHolder.name = "Mesh Holder";
meshHolder.transform.parent = transform;
meshHolder.transform.localPosition = Vector3.zero;
meshHolder.transform.localRotation = Quaternion.Euler(Vector3.zero);
for (int i = 0; i < numberOfLinePoint - 1; i++)
{
GameObject leftFloorPanel = new GameObject();
GameObject rightFloorPanel = new GameObject();
leftFloorPanel.name = "Left Floor " + i.ToString();
rightFloorPanel.name = "Right Floor " + i.ToString();
leftFloorPanel.transform.parent = meshHolder.transform;
leftFloorPanel.transform.position = Vector3.zero;
leftFloorPanel.transform.localPosition = Vector3.zero;
leftFloorPanel.transform.localRotation = Quaternion.Euler(Vector3.zero);
Vector3 leftFloorPanelPostion = centerLinePoints[i].localPosition;
leftFloorPanelPostion.x = (leftPoints[i].localPosition.x + centerLinePoints[i].localPosition.x) / 2;
leftFloorPanelPostion.z = (centerLinePoints[i + 1].localPosition.z + centerLinePoints[i].localPosition.z) / 2;
leftFloorPanel.transform.localPosition = leftFloorPanelPostion;
rightFloorPanel.transform.parent = meshHolder.transform;
rightFloorPanel.transform.localPosition = Vector3.zero;
rightFloorPanel.transform.localRotation = Quaternion.Euler(Vector3.zero);
Vector3 rightFloorPanelPostion = centerLinePoints[i].localPosition;
rightFloorPanelPostion.x = (rightPoints[i].localPosition.x + centerLinePoints[i].localPosition.x) / 2;
rightFloorPanelPostion.z = (centerLinePoints[i + 1].localPosition.z + centerLinePoints[i].localPosition.z) / 2;
rightFloorPanel.transform.localPosition = rightFloorPanelPostion;
listOfCorridorFloor.Add(leftFloorPanel);
listOfCorridorFloor.Add(rightFloorPanel);
// Debug.Log(leftFloorPanel.transform.position + " " + leftFloorPanel.transform.localPosition);
}
corridorVertices = new Vector3[listOfCorridorFloor.Count * 3];
corridorTrangle = new int[listOfCorridorFloor.Count * 3];
//listOfCorridorFloor[0].transform.parent = null;
//centerLinePoints[0].transform.parent = null;
//leftPoints[0].transform.parent = null;
//leftPoints[1].transform.parent = null;
testVec[0] = centerLinePoints[0].transform.position;
testVec[1] = leftPoints[0].transform.position;
testVec[2] = leftPoints[1].transform.position;
//testVec[3] = leftPoints[1].transform.position;
//testVec[4] = centerLinePoints[1].position;
//testVec[5] = centerLinePoints[0].position;
textInt[0] = 0;
textInt[1] = 1;
textInt[2] = 2;
//textInt[3] = 3;
//textInt[4] = 4;
//textInt[5] = 5;
listOfCorridorFloor[0].AddComponent<MeshFilter>();
listOfCorridorFloor[0].AddComponent<MeshRenderer>();
}
private void Update()
{
Mesh testmesh = listOfCorridorFloor[0].GetComponent<MeshFilter>().mesh;
testVec[0] = centerLinePoints[0].transform.position;
testVec[1] = leftPoints[0].transform.position;
testVec[2] = leftPoints[1].transform.position;
textInt[0] = 0;
textInt[1] = 1;
textInt[2] = 2;
//Debug.Log("point local: " + centerLinePoints[0].transform.localPosition);
//Debug.Log("point global : " + centerLinePoints[0].transform.position);
//Debug.Log("vertice " + testVec[0]);
testmesh.Clear();
testmesh.vertices = testVec;
testmesh.triangles = textInt;
}
Vector3 LinearBezierCurves(Vector3 _pointStart, Vector3 _pointEnd, float t)
{// P0 P1
//P(t) = P0 + t * (P1 – P0) = (1 - t) P0 + t * P1 , 0 < t < 1
Vector3 p = Vector3.zero;
p = _pointStart + t * (_pointEnd - _pointStart);
return p;
}
Vector3 QuadraticBezierCurves(Vector3 _pointStart, Vector3 _pointEnd, Vector3 _pointControl, float t)
{ // P0 P1 P2
// P(t) = (1-t)^2 * P0 + 2(1-t) t * P2 + t^2 * P1 , 0 < t < 1
// uu u2 tt
Vector3 p = Vector3.zero;
float u = 1 - t;
float tt = t * t;
float uu = u * u;
float u2 = u * 2;
p = uu * _pointStart;
p += u2 * t * _pointControl;
p += tt * _pointEnd;
return p;
}
Vector3 CubicBezierCurve(Vector3 _pointStart, Vector3 _pointEnd, Vector3 _pointControlOne, Vector3 _pointControlTwo, float t)
{ // P0 P1 P2 P3
//P(t) = (1-t)^3 * P0 + 3 (1-t)^2 * t * P2 +3(1-t) * t^2 * P3 + t^3 * P1 , 0 < t< 1
// uuu uu u
Vector3 p = Vector3.zero;
float u = 1 - t;
float uu = u * u;
float uuu = u * u * u;
float tt = t * t;
float ttt = t * t * t;
return p;
}
private void MakeMeshData(Vector3 meshPointOne, Vector3 meshPointTwo, Vector3 meshPointThree, int index)
{
corridorVertices[index - 3] = meshPointOne;
corridorVertices[index - 2] = meshPointTwo;
corridorVertices[index - 1] = meshPointThree;
corridorTrangle[index - 3] = index - 3;
corridorTrangle[index - 2] = index - 2;
corridorTrangle[index - 1] = index - 1;
}
//private void CreateMesh()
//{
// roomMesh.Clear();
// roomMesh.vertices = roomVertices;
// roomMesh.triangles = roomTrangle;
//}
}
The mesh is always expressed in relation to its root transform. In order to use global positions use Transform.TransformPoint (or transform.InverseTransformPoint) to convert them to local space, i.e. all points must be expressed relative to the center of the gameobejct that will be displaying the mesh.
What is the best way to draw a graph for the HoloLens in unity?
I am new to this platform and have no idea which packages will work and which dont, the graph gets data dynamically.
EDIT: I have tried LineRenderer but it seems very limited in version 5.4 of Unity
A possible Solution for drawing a 3D-Graph is using a particle system:
Simple Example for a Component Script for a particle system:
public class Graph: MonoBehaviour {
//Particle-Resolution of the Graph
[Range(10, 100)]
public int resolution = 10;
private int currentResolution;
private ParticleSystem.Particle[] points;
void Start()
{
currentResolution = resolution;
points = new ParticleSystem.Particle[resolution];
float increment = 1f / (resolution - 1);
for (int i = 0; i < resolution; i++)
{
float x = i * increment;
points[i].position = new Vector3(x, 0f, 0f);
points[i].startColor = new Color(0f, 0f, 0f);
points[i].startSize = 0.1f;
}
}
void Update()
{
if ((currentResolution != resolution) || (points == null))
{
CreatePoints();
}
FunctionDelegate f = functionDelegates[(int)function];
for (int i = 0; i < points.Length; i++)
{
Vector3 p = points[i].position;
p.y = Sine(p.x);
points[i].position = p;
Color c = points[i].GetCurrentColor(GetComponent<ParticleSystem>());
c.g = p.y;
c.r = 1f - p.y;
points[i].startColor = c;
}
GetComponent<ParticleSystem>().SetParticles(points, points.Length);
}
private static float Sine(float x)
{
return 0.5f + 0.5f * Mathf.Sin(2 * Mathf.PI * x + Time.timeSinceLevelLoad);
}
}
A good tutorial for drawing 2D/3D graphs (including this example) with a particle system from CatLikeCoding (Jasper Flick). Refer to: http://catlikecoding.com/unity/tutorials/graphs/. It's a bit outdated and you must use startSize/startColor instead the depreceated color/size-Properties in this case.
But i'have testet it with the hololens allready and it worked fine. Some experiments with the HoloToolkit shaders for a better performance are necessary if you have a big amount of particles :-)
If you have further questions: Just ask me.
I want to have an infinitely explorable map. The plan is to create categories of game tiles (roads, obstacles, buildings), and randomly choose a category of game tile to be added when the player approaches the edge of the existing set of tiles. Tiles will also be destroyed once the player is 2 grid squares away from that tile. Currently I am using a multidimensional array that requires a size initializer.
What I have so far:
public class GameManager : MonoBehaviour
{
private GameObject[,] tileArray;
public GameObject groundTile;
public GameObject player;
private int tileSize = 80;
private int nextFarX = 1;
private int nextFarZ = 1;
private int nextNearX = -1;
private int nextNearZ = -1;
private float padding = .1f;
private int arrayOffset;
private int arrayDimension;
// Use this for initialization
void Start ()
{
arrayDimension = 200;
arrayOffset = arrayDimension / 2;
tileArray = new GameObject[,];
this.AddCubeAt(0, 0);
}
// Update is called once per frame
void Update () {
var x = Convert.ToInt32(player.transform.position.x / tileSize);
var z = Convert.ToInt32(player.transform.position.z / tileSize);
for (int i = -1; i < 2; i++)
{
for (int j = -1; j < 2; j++)
{
var checkX = x + i;
var checkZ = z + j;
if (tileArray[checkX + arrayOffset, checkZ + arrayOffset] == null)
{
//player is less than 2 tiles away from this grid, add a tile
this.AddCubeAt(checkX, checkZ);
}
}
}
// feels like a hack, but it will remove tiles that are not touching the tile that the player occupies
for (int i = 0; i < 6; i++)
{
for (int j = 0; j < 6; j++)
{
if (i == 0 | i == 5 | j == 0 | j == 5)
{
if (tileArray[x + (i-2) + arrayOffset, z + (j-2) + arrayOffset] != null)
{
Destroy(tileArray[x + (i - 2) + arrayOffset, z + (j - 2) + arrayOffset]);
tileArray[x + (i - 2) + arrayOffset, z + (j - 2) + arrayOffset] = null;
}
}
}
}
}
private void AddCubeAt(int x, int z)
{
var pos = new Vector3(x * tileSize, 0, z * tileSize);
var rot = Quaternion.identity;
GameObject newCube = (GameObject)Instantiate(groundTile, pos, rot);
tileArray[x + arrayOffset, z + arrayOffset] = newCube;
}
}
What is a better way to approach this?
You should familiarize yourself with Graph Data Structure (not adjacency matrix implementation). It's much more appropriate for this task. And, I would solve this
Tiles will also be destroyed once the player is 2 grid squares away from that tile
in another way: Every time player changed his position I would start DFS on target depth (in your case it's 2) and remove found tiles.
Decided to go with a simple Dictionary and methods to query/update it:
private GameObject RetrieveTileAt(int x, int z)
{
string key = string.Format("{0}.{1}", x, z);
if (tileDictionary.ContainsKey(key))
{
return tileDictionary[key];
}
else
{
return null;
}
}
private void InsertTileAt(int x, int z, GameObject tile)
{
string key = string.Format("{0}.{1}", x, z);
tileDictionary[key] = tile;
}
It is not an infinitely sized grid, (int min + int max)squared, but it should be far more than I need.